diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ActiveBindingMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ActiveBindingMR.java index 7ea156016dc9d6352903d006d7200915237019de..5aa08ac4faab867795d867b1cb21b8cafabef269 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ActiveBindingMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ActiveBindingMR.java @@ -60,6 +60,13 @@ public class ActiveBindingMR { } } + @Resolve(message = "KEY_INFO") + public abstract static class ActiveBindingKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object idx) { + return 0; + } + } + @CanResolve public abstract static class ActiveBindingCheck extends Node { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ListMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ListMR.java new file mode 100644 index 0000000000000000000000000000000000000000..5dad942ddc4384657e394bcbaa4d3ce48f0734a6 --- /dev/null +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ListMR.java @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2016, 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.engine.interop; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.CanResolve; +import com.oracle.truffle.api.interop.KeyInfo; +import com.oracle.truffle.api.interop.KeyInfo.Builder; +import com.oracle.truffle.api.interop.MessageResolution; +import com.oracle.truffle.api.interop.Resolve; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnknownIdentifierException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.engine.interop.ListMRFactory.ListKeyInfoImplNodeGen; +import com.oracle.truffle.r.engine.interop.ListMRFactory.ListReadImplNodeGen; +import com.oracle.truffle.r.engine.interop.ListMRFactory.ListWriteImplNodeGen; +import com.oracle.truffle.r.ffi.impl.interop.NativePointer; +import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; +import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode; +import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; +import com.oracle.truffle.r.nodes.control.RLengthNode; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RList; +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.RPairList; +import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.RTruffleObject; +import com.oracle.truffle.r.runtime.interop.Foreign2R; +import com.oracle.truffle.r.runtime.interop.Foreign2RNodeGen; +import com.oracle.truffle.r.runtime.interop.R2Foreign; +import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen; + +public class ListMR { + + @MessageResolution(receiverType = RList.class) + public static class RListMR extends ListMR { + @Resolve(message = "IS_BOXED") + public abstract static class RListIsBoxedNode extends Node { + protected Object access(RList receiver) { + return isBoxed(receiver); + } + } + + @Resolve(message = "HAS_SIZE") + public abstract static class RListHasSizeNode extends Node { + protected Object access(RList receiver) { + return hasSize(receiver); + } + } + + @Resolve(message = "GET_SIZE") + public abstract static class RListGetSizeNode extends Node { + @Child private RLengthNode lengthNode = RLengthNode.create(); + + protected Object access(VirtualFrame frame, RList receiver) { + return getSize(frame, receiver, lengthNode); + } + } + + @Resolve(message = "IS_NULL") + public abstract static class RListIsNullNode extends Node { + protected Object access(RList receiver) { + return isNull(receiver); + } + } + + @Resolve(message = "READ") + public abstract static class RListReadNode extends Node { + @Child private ListReadImplNode read = ListReadImplNodeGen.create(); + + protected Object access(VirtualFrame frame, RList receiver, Object identifier) { + return read.execute(frame, receiver, identifier); + } + } + + @Resolve(message = "WRITE") + public abstract static class RListWriteNode extends Node { + @Child private ListWriteImplNode writeNode = ListWriteImplNodeGen.create(); + + protected Object access(VirtualFrame frame, RList receiver, Object identifier, Object valueObj) { + return writeNode.execute(frame, receiver, identifier, valueObj); + } + } + + @Resolve(message = "KEYS") + public abstract static class RListKeysNode extends Node { + @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); + + protected Object access(RList receiver) { + return listKeys(receiver, getNamesNode); + } + } + + @Resolve(message = "KEY_INFO") + public abstract static class RListKeyInfoNode extends Node { + @Child private ListKeyInfoImplNode keyInfoNode = ListKeyInfoImplNodeGen.create(); + + protected Object access(VirtualFrame frame, TruffleObject receiver, Object idx) { + return keyInfoNode.execute(frame, receiver, idx); + } + } + + @Resolve(message = "TO_NATIVE") + public abstract static class RListToNativeNode extends Node { + protected Object access(RTruffleObject receiver) { + return toNativePointer(receiver); + } + } + + @CanResolve + public abstract static class RListCheck extends Node { + + protected static boolean test(TruffleObject receiver) { + return receiver instanceof RList; + } + } + } + + @MessageResolution(receiverType = RPairList.class) + public static class RPairListMR { + @Resolve(message = "IS_BOXED") + public abstract static class RPairListIsBoxedNode extends Node { + protected Object access(RPairList receiver) { + return isBoxed(receiver); + } + } + + @Resolve(message = "HAS_SIZE") + public abstract static class RPairListHasSizeNode extends Node { + protected Object access(RPairList receiver) { + return hasSize(receiver); + } + } + + @Resolve(message = "GET_SIZE") + public abstract static class RPairListGetSizeNode extends Node { + @Child private RLengthNode lengthNode = RLengthNode.create(); + + protected Object access(VirtualFrame frame, RPairList receiver) { + return getSize(frame, receiver, lengthNode); + } + } + + @Resolve(message = "IS_NULL") + public abstract static class RPairListIsNullNode extends Node { + protected Object access(RPairList receiver) { + return isNull(receiver); + } + } + + @Resolve(message = "IS_EXECUTABLE") + public abstract static class RPairListIsExecutableNode extends Node { + protected Object access(@SuppressWarnings("unused") RPairList receiver) { + return false; + } + } + + @Resolve(message = "READ") + public abstract static class RPairListReadNode extends Node { + @Child private ListReadImplNode read = ListReadImplNodeGen.create(); + + protected Object access(VirtualFrame frame, RPairList receiver, Object identifier) { + return read.execute(frame, receiver, identifier); + } + } + + @Resolve(message = "WRITE") + public abstract static class RPairListWriteNode extends Node { + @Child private ListWriteImplNode writeNode = ListWriteImplNodeGen.create(); + + protected Object access(VirtualFrame frame, RPairList receiver, Object identifier, Object valueObj) { + return writeNode.execute(frame, receiver, identifier, valueObj); + } + } + + @Resolve(message = "KEYS") + public abstract static class RPairListKeysNode extends Node { + @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); + + protected Object access(RPairList receiver) { + return listKeys(receiver, getNamesNode); + } + } + + @Resolve(message = "KEY_INFO") + public abstract static class RPairListKeyInfoNode extends Node { + @Child private ListKeyInfoImplNode keyInfoNode = ListKeyInfoImplNodeGen.create(); + + protected Object access(VirtualFrame frame, TruffleObject receiver, Object idx) { + return keyInfoNode.execute(frame, receiver, idx); + } + } + + @Resolve(message = "TO_NATIVE") + public abstract static class RPairListToNativeNode extends Node { + protected Object access(RPairList receiver) { + return toNativePointer(receiver); + } + } + + @CanResolve + public abstract static class RPairListCheck extends Node { + protected static boolean test(TruffleObject receiver) { + return receiver instanceof RPairList; + } + } + } + + abstract static class ListReadImplNode extends Node { + @Child private ExtractVectorNode extract; + @Child private R2Foreign r2Foreign; + + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + protected abstract Object execute(VirtualFrame frame, TruffleObject receiver, Object idx); + + @Specialization + protected Object read(VirtualFrame frame, TruffleObject receiver, int idx, + @Cached("createKeyInfoNode()") ListKeyInfoImplNode keyInfo) { + int info = keyInfo.execute(frame, receiver, idx); + if (unknownIdentifier.profile(!KeyInfo.isExisting(info))) { + throw UnknownIdentifierException.raise("" + idx); + } + initExtractNode(); + // idx + 1 R is indexing from 1 + Object value = extract.apply(frame, receiver, new Object[]{idx + 1}, RLogical.valueOf(false), RMissing.instance); + initR2ForeignNode(); + return r2Foreign.execute(value); + } + + @Specialization + protected Object read(VirtualFrame frame, TruffleObject receiver, String field, + @Cached("createKeyInfoNode()") ListKeyInfoImplNode keyInfo) { + // reading by an unknown name returns null, + // reading by an unknown index returns subscript out of bounds; + // let's be consistent at this place, the name should be known to the caller anyway + int info = keyInfo.execute(frame, receiver, field); + if (unknownIdentifier.profile(!KeyInfo.isExisting(info))) { + throw UnknownIdentifierException.raise("" + field); + } + initExtractNode(); + Object value = extract.applyAccessField(frame, receiver, field); + initR2ForeignNode(); + return r2Foreign.execute(value); + } + + @Fallback + protected Object read(VirtualFrame frame, TruffleObject receiver, Object field) { + throw UnknownIdentifierException.raise("" + field); + } + + protected ListKeyInfoImplNode createKeyInfoNode() { + return ListKeyInfoImplNodeGen.create(); + } + + private void initR2ForeignNode() { + if (r2Foreign == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + r2Foreign = insert(R2ForeignNodeGen.create()); + } + } + + private void initExtractNode() { + if (extract == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + extract = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true)); + } + } + } + + abstract static class ListWriteImplNode extends Node { + @Child private ReplaceVectorNode replace; + @Child private Foreign2R foreign2R; + + protected abstract Object execute(VirtualFrame frame, TruffleObject receiver, Object identifier, Object valueObj); + + @Specialization + protected Object write(VirtualFrame frame, TruffleObject receiver, int idx, Object valueObj) { + // idx + 1 R is indexing from 1 + return write(frame, receiver, new Object[]{idx + 1}, valueObj); + } + + @Specialization + protected Object write(VirtualFrame frame, TruffleObject receiver, String field, Object valueObj) { + return write(frame, receiver, new Object[]{field}, valueObj); + } + + private Object write(VirtualFrame frame, TruffleObject receiver, Object[] positions, Object valueObj) { + if (foreign2R == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + foreign2R = insert(Foreign2RNodeGen.create()); + } + Object value = foreign2R.execute(valueObj); + if (replace == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + replace = insert(ReplaceVectorNode.create(ElementAccessMode.SUBSCRIPT, true)); + } + return replace.apply(frame, receiver, positions, value); + } + + @Fallback + protected Object write(VirtualFrame frame, TruffleObject receiver, Object field, Object object) { + throw UnknownIdentifierException.raise("" + field); + } + } + + abstract static class ListKeyInfoImplNode extends Node { + @Child private ExtractVectorNode extractNode; + + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + abstract int execute(VirtualFrame frame, TruffleObject receiver, Object idx); + + @Specialization + protected int keyInfo(VirtualFrame frame, TruffleObject receiver, int idx, + @Cached("createLengthNode()") RLengthNode lenghtNode) { + return keyInfo(frame, receiver, (double) idx, lenghtNode); + } + + @Specialization + protected int keyInfo(VirtualFrame frame, TruffleObject receiver, double idx, + @Cached("createLengthNode()") RLengthNode lengthNode) { + + int length = lengthNode.executeInteger(frame, receiver); + if (unknownIdentifier.profile(idx < 0 || idx >= length)) { + return 0; + } + initExtractNode(); + return buildKeys(extractNode.apply(frame, receiver, new Object[]{idx + 1}, RLogical.valueOf(false), RMissing.instance)); + } + + @Specialization + protected int keyInfo(VirtualFrame frame, TruffleObject receiver, String identifier, + @Cached("createNamesNode()") GetNamesAttributeNode namesNode) { + RStringVector names = namesNode.getNames(receiver); + boolean exists = false; + for (int i = 0; i < names.getLength(); i++) { + if (identifier.equals(names.getDataAt(i))) { + exists = true; + break; + } + } + if (unknownIdentifier.profile(!exists)) { + return 0; + } + initExtractNode(); + return buildKeys(extractNode.applyAccessField(frame, receiver, identifier)); + } + + protected RLengthNode createLengthNode() { + return RLengthNode.create(); + } + + protected GetNamesAttributeNode createNamesNode() { + return GetNamesAttributeNode.create(); + } + + private int buildKeys(Object value) { + Builder builder = KeyInfo.newBuilder(); + builder.setReadable(true).setWritable(true).setInvocable(value instanceof RFunction); + return builder.build(); + } + + private void initExtractNode() { + if (extractNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + extractNode = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true)); + } + } + + @Fallback + protected int access(VirtualFrame frame, TruffleObject receiver, Object field) { + return 0; + } + } + + private static boolean isBoxed(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + + private static boolean isNull(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + + private static boolean hasSize(@SuppressWarnings("unused") TruffleObject receiver) { + return true; + } + + private static Object getSize(VirtualFrame frame, TruffleObject receiver, RLengthNode lengthNode) { + return lengthNode.executeInteger(frame, receiver); + } + + private static Object listKeys(TruffleObject receiver, GetNamesAttributeNode getNamesNode) { + RStringVector names = getNamesNode.getNames(receiver); + return names != null ? names : RNull.instance; + } + + private static Object toNativePointer(RTruffleObject receiver) { + return new NativePointer(receiver); + } +} diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RAbstractVectorAccessFactory.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RAbstractVectorAccessFactory.java index 8453af22c21ab96832e32b20759ab70f81d90a5f..250948d7ab3689d80b5a4533ed5029e61a303922 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RAbstractVectorAccessFactory.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RAbstractVectorAccessFactory.java @@ -23,24 +23,40 @@ package com.oracle.truffle.r.engine.interop; import com.oracle.truffle.api.CallTarget; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.ForeignAccess.Factory26; +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.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.engine.TruffleRLanguageImpl; -import com.oracle.truffle.r.engine.interop.RAbstractVectorAccessFactoryFactory.VectorReadNodeGen; +import com.oracle.truffle.r.engine.interop.RAbstractVectorAccessFactoryFactory.VectorKeyInfoImplNodeGen; +import com.oracle.truffle.r.engine.interop.RAbstractVectorAccessFactoryFactory.VectorKeyInfoRootNodeGen; +import com.oracle.truffle.r.engine.interop.RAbstractVectorAccessFactoryFactory.VectorReadImplNodeGen; +import com.oracle.truffle.r.engine.interop.RAbstractVectorAccessFactoryFactory.VectorWriteImplNodeGen; import com.oracle.truffle.r.ffi.impl.interop.NativePointer; import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode; +import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode; import com.oracle.truffle.r.nodes.control.RLengthNode; import com.oracle.truffle.r.runtime.data.RLogical; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.interop.Foreign2R; +import com.oracle.truffle.r.runtime.interop.Foreign2RNodeGen; +import com.oracle.truffle.r.runtime.interop.R2Foreign; +import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; +import java.util.List; abstract class InteropRootNode extends RootNode { InteropRootNode() { @@ -65,34 +81,151 @@ public final class RAbstractVectorAccessFactory implements Factory26 { } } - abstract static class VectorReadNode extends InteropRootNode { + abstract static class VectorReadImplNode extends InteropRootNode { - @CompilationFinal private boolean lengthAccess = false; - @Child private ExtractVectorNode extract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true); - @Child private RLengthNode lengthNode = RLengthNode.create(); + @Child private ExtractVectorNode extract; + @Child private R2Foreign r2Foreign; + + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + @Override + public final Object execute(VirtualFrame frame) { + Object indentifier = ForeignAccess.getArguments(frame).get(0); + Object receiver = ForeignAccess.getReceiver(frame); + return execute(frame, receiver, indentifier); + } + + protected abstract Object execute(VirtualFrame frame, Object reciever, Object indentifier); + + @Specialization + protected Object readIndexed(VirtualFrame frame, Object receiver, int idx, + @Cached("createKeyInfoNode()") VectorKeyInfoImplNode keyInfo) { + int info = keyInfo.execute(frame, receiver, idx); + if (unknownIdentifier.profile(!KeyInfo.isExisting(info))) { + throw UnknownIdentifierException.raise("" + idx); + } + return read(frame, receiver, new Object[]{idx + 1}); + } + + @Specialization + protected Object readIndexed(VirtualFrame frame, Object receiver, long idx, + @Cached("createKeyInfoNode()") VectorKeyInfoImplNode keyInfo) { + int info = keyInfo.execute(frame, receiver, idx); + if (unknownIdentifier.profile(!KeyInfo.isExisting(info))) { + throw UnknownIdentifierException.raise("" + idx); + } + return read(frame, receiver, new Object[]{idx + 1}); + } + + private Object read(VirtualFrame frame, Object receiver, Object[] positions) { + if (extract == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + extract = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true)); + } + Object value = extract.apply(frame, receiver, positions, RLogical.TRUE, RLogical.TRUE); + if (r2Foreign == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + r2Foreign = insert(R2ForeignNodeGen.create()); + } + return r2Foreign.execute(value); + } + + @Fallback + protected Object read(VirtualFrame frame, Object receiver, Object indentifier) { + throw UnknownIdentifierException.raise("" + indentifier); + } + + protected VectorKeyInfoImplNode createKeyInfoNode() { + return VectorKeyInfoImplNodeGen.create(); + } + } + + abstract static class VectorWriteImplNode extends InteropRootNode { + @Child private ReplaceVectorNode replace; + @Child private Foreign2R foreign2R; + + @Override + public final Object execute(VirtualFrame frame) { + List<Object> arguments = ForeignAccess.getArguments(frame); + Object receiver = ForeignAccess.getReceiver(frame); + return execute(frame, receiver, arguments.get(0), arguments.get(1)); + } + + protected abstract Object execute(VirtualFrame frame, Object receiver, Object identifier, Object valueObj); + + @Specialization + protected Object write(VirtualFrame frame, TruffleObject receiver, int idx, Object valueObj) { + // idx + 1 R is indexing from 1 + return write(frame, receiver, new Object[]{idx + 1}, valueObj); + } + + @Specialization + protected Object write(VirtualFrame frame, TruffleObject receiver, long idx, Object valueObj) { + // idx + 1 R is indexing from 1 + return write(frame, receiver, new Object[]{idx + 1}, valueObj); + } + + private Object write(VirtualFrame frame, TruffleObject receiver, Object[] positions, Object valueObj) { + if (foreign2R == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + foreign2R = insert(Foreign2RNodeGen.create()); + } + Object value = foreign2R.execute(valueObj); + if (replace == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + replace = insert(ReplaceVectorNode.create(ElementAccessMode.SUBSCRIPT, true)); + } + return replace.apply(frame, receiver, positions, value); + } + + @Fallback + protected Object write(VirtualFrame frame, Object receiver, Object field, Object object) { + throw UnknownIdentifierException.raise("" + field); + } + } + + abstract static class VectorKeyInfoRootNode extends InteropRootNode { + @Child VectorKeyInfoImplNode keyInfoNode = VectorKeyInfoImplNodeGen.create(); @Override public final Object execute(VirtualFrame frame) { - Object label = ForeignAccess.getArguments(frame).get(0); + Object indentifier = ForeignAccess.getArguments(frame).get(0); Object receiver = ForeignAccess.getReceiver(frame); - return execute(frame, receiver, label); + return execute(frame, receiver, indentifier); } - protected abstract Object execute(VirtualFrame frame, Object reciever, Object label); + protected abstract int execute(VirtualFrame frame, Object reciever, Object indentifier); @Specialization - protected Object readIndexed(VirtualFrame frame, Object receiver, int label) { - return extract.apply(frame, receiver, new Object[]{label + 1}, RLogical.TRUE, RLogical.TRUE); + protected int keyInfo(VirtualFrame frame, Object receiver, Object indentifier) { + return keyInfoNode.execute(frame, receiver, indentifier); } + } + + abstract static class VectorKeyInfoImplNode extends Node { + @Child private RLengthNode lengthNode = RLengthNode.create(); + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + protected abstract int execute(VirtualFrame frame, Object reciever, Object indentifier); @Specialization - protected Object readIndexed(VirtualFrame frame, Object receiver, long label) { - return extract.apply(frame, receiver, new Object[]{label + 1}, RLogical.TRUE, RLogical.TRUE); + protected int keyInfo(VirtualFrame frame, Object receiver, int idx) { + return keyInfo(frame, receiver, (long) idx); } @Specialization - protected Object readProperty(VirtualFrame frame, Object receiver, String label) { - return extract.applyAccessField(frame, receiver, label); + protected int keyInfo(VirtualFrame frame, Object receiver, long idx) { + if (unknownIdentifier.profile(idx < 0 || idx >= lengthNode.executeInteger(frame, receiver))) { + return 0; + } + KeyInfo.Builder builder = KeyInfo.newBuilder(); + builder.setReadable(true).setWritable(true); + return builder.build(); + } + + @Fallback + protected int keyInfo(VirtualFrame frame, Object receiver, Object label) { + return 0; } } @@ -108,7 +241,12 @@ public final class RAbstractVectorAccessFactory implements Factory26 { @Override public CallTarget accessIsExecutable() { - return null; + return Truffle.getRuntime().createCallTarget(new InteropRootNode() { + @Override + public Object execute(VirtualFrame frame) { + return false; + } + }); } @Override @@ -150,12 +288,12 @@ public final class RAbstractVectorAccessFactory implements Factory26 { @Override public CallTarget accessRead() { - return Truffle.getRuntime().createCallTarget(VectorReadNodeGen.create()); + return Truffle.getRuntime().createCallTarget(VectorReadImplNodeGen.create()); } @Override public CallTarget accessWrite() { - return null; + return Truffle.getRuntime().createCallTarget(VectorWriteImplNodeGen.create()); } @Override @@ -185,7 +323,7 @@ public final class RAbstractVectorAccessFactory implements Factory26 { @Override public CallTarget accessKeyInfo() { - return null; + return Truffle.getRuntime().createCallTarget(VectorKeyInfoRootNodeGen.create()); } @Override diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java index c62c3b20335d81ad01044fb019e7a0433ef9c43f..ff96aa902a84ef0490a935e174bc89025075646f 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java @@ -22,12 +22,25 @@ */ package com.oracle.truffle.r.engine.interop; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.CanResolve; +import com.oracle.truffle.api.interop.KeyInfo; import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.engine.interop.RArgsValuesAndNamesMRFactory.RArgsValuesAndNamesKeyInfoImplNodeGen; +import com.oracle.truffle.r.engine.interop.RArgsValuesAndNamesMRFactory.RArgsValuesAndNamesReadImplNodeGen; +import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.interop.R2Foreign; +import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen; @MessageResolution(receiverType = RArgsValuesAndNames.class) public class RArgsValuesAndNamesMR { @@ -61,8 +74,26 @@ public class RArgsValuesAndNamesMR { @Resolve(message = "READ") public abstract static class RArgsValuesAndNamesReadNode extends Node { - protected Object access(RArgsValuesAndNames receiver, int index) { - return receiver.getArgument(index); + @Child RArgsValuesAndNamesReadImplNode readNode = RArgsValuesAndNamesReadImplNodeGen.create(); + + protected Object access(RArgsValuesAndNames receiver, Object identifier) { + return readNode.execute(receiver, identifier); + } + } + + @Resolve(message = "KEYS") + public abstract static class RArgsValuesAndNamesKeysNode extends Node { + protected Object access(RArgsValuesAndNames receiver) { + return RDataFactory.createStringVector(receiver.getSignature().getNames(), RDataFactory.COMPLETE_VECTOR); + } + } + + @Resolve(message = "KEY_INFO") + public abstract static class RArgsValuesAndNamesKeyInfoNode extends Node { + @Child private RArgsValuesAndNamesKeyInfoImplNode keyInfoNode = RArgsValuesAndNamesKeyInfoImplNodeGen.create(); + + protected Object access(VirtualFrame frame, RArgsValuesAndNames receiver, Object obj) { + return keyInfoNode.execute(frame, receiver, obj); } } @@ -73,4 +104,88 @@ public class RArgsValuesAndNamesMR { return receiver instanceof RArgsValuesAndNames; } } + + abstract static class RArgsValuesAndNamesReadImplNode extends Node { + @Child private R2Foreign r2Foreign = R2ForeignNodeGen.create(); + + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + abstract Object execute(RArgsValuesAndNames receiver, Object identifier); + + @Specialization + protected Object access(RArgsValuesAndNames receiver, int index) { + if (unknownIdentifier.profile(index < 0 || index >= receiver.getLength())) { + throw UnknownIdentifierException.raise("" + index); + } + Object value = receiver.getArgument(index); + return r2Foreign.execute(value); + } + + @Specialization + protected Object access(RArgsValuesAndNames receiver, String identifier) { + ArgumentsSignature sig = receiver.getSignature(); + String[] names = sig.getNames(); + int idx = -1; + for (int i = 0; i < names.length; i++) { + if (names[i].equals(identifier)) { + idx = i; + break; + } + } + if (unknownIdentifier.profile(idx < 0)) { + throw UnknownIdentifierException.raise("" + identifier); + } + + Object value = receiver.getArgument(idx); + return r2Foreign.execute(value); + } + + @Fallback + protected Object access(RArgsValuesAndNames receiver, Object identifier) { + throw UnknownIdentifierException.raise("" + identifier); + } + } + + abstract static class RArgsValuesAndNamesKeyInfoImplNode extends Node { + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + abstract Object execute(VirtualFrame frame, RArgsValuesAndNames receiver, Object idx); + + @Specialization + protected Object access(VirtualFrame frame, RArgsValuesAndNames receiver, int idx) { + if (unknownIdentifier.profile(idx < 0 || idx >= receiver.getLength())) { + return 0; + } + return createKeyInfo(receiver, idx); + } + + @Specialization + protected Object access(VirtualFrame frame, RArgsValuesAndNames receiver, String identifier) { + ArgumentsSignature sig = receiver.getSignature(); + String[] names = sig.getNames(); + int idx = -1; + for (int i = 0; i < names.length; i++) { + if (names[i].equals(identifier)) { + idx = i; + break; + } + } + if (unknownIdentifier.profile(idx < 0)) { + return 0; + } + + return createKeyInfo(receiver, idx); + } + + private Object createKeyInfo(RArgsValuesAndNames receiver, int idx) { + KeyInfo.Builder builder = KeyInfo.newBuilder(); + builder.setReadable(true).setInvocable(receiver.getArgument(idx) instanceof RFunction); + return builder.build(); + } + + @Fallback + protected Object access(VirtualFrame frame, RArgsValuesAndNames receiver, Object field) { + return 0; + } + } } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RConnectionMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RConnectionMR.java index 992891c4e563339f39c186cd79e98e47c97e9cfb..0d364d7041d352aa363b02bde22df019039f5fd5 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RConnectionMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RConnectionMR.java @@ -24,12 +24,42 @@ package com.oracle.truffle.r.engine.interop; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.MessageResolution; +import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.runtime.conn.RConnection; @MessageResolution(receiverType = RConnection.class) public class RConnectionMR { + + @Resolve(message = "IS_BOXED") + public abstract static class RConnectionIsBoxedNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "HAS_SIZE") + public abstract static class RConnectionHasSizeNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "IS_NULL") + public abstract static class RConnectionIsNullNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "KEY_INFO") + public abstract static class RConnectionKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @CanResolve public abstract static class RConnection extends Node { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RContextMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RContextMR.java index 012f9f218142dc1f61bc59cddd5dcc3c76ee3d3e..67d3201bba8025c38568cbd99b25073aab8c346d 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RContextMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RContextMR.java @@ -24,12 +24,42 @@ package com.oracle.truffle.r.engine.interop; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.MessageResolution; +import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.runtime.context.RContext; @MessageResolution(receiverType = RContext.class) public class RContextMR { + + @Resolve(message = "IS_BOXED") + public abstract static class RContextIsBoxedNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "HAS_SIZE") + public abstract static class RContextHasSizeNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "IS_NULL") + public abstract static class RContextIsNullNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "KEY_INFO") + public abstract static class RContextKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @CanResolve public abstract static class RContext extends Node { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RDoubleMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RDoubleMR.java index 6deaaf78d26dc2a016a0b473875678ca63f474b0..a31821ee84c8304b6eeca61eeb4ec853b8db7313 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RDoubleMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RDoubleMR.java @@ -59,6 +59,13 @@ public class RDoubleMR { } } + @Resolve(message = "KEY_INFO") + public abstract static class RDoubleKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @CanResolve public abstract static class RDoubleCheck extends Node { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REmptyMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REmptyMR.java index 13497b553c6fdadbd9f2bbbee94adeeee267b694..6537ae621cede6fffa8aa3ae882caf957c59dd1f 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REmptyMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REmptyMR.java @@ -53,6 +53,13 @@ public class REmptyMR { } } + @Resolve(message = "KEY_INFO") + public abstract static class REmptyKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @CanResolve public abstract static class REmptyCheck extends Node { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java index 66a2aa3b62a0a1c36e58b0aa749e7634591b1743..7f57be4a7640a9904f58b1b003663248052ef927 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java @@ -22,21 +22,36 @@ */ package com.oracle.truffle.r.engine.interop; -import static com.oracle.truffle.r.engine.interop.Utils.javaToRPrimitive; - +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.KeyInfo; import com.oracle.truffle.api.interop.KeyInfo.Builder; +import com.oracle.truffle.api.interop.Message; import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; 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.nodes.Node; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.engine.interop.REnvironmentMRFactory.REnvironmentKeyInfoImplNodeGen; +import com.oracle.truffle.r.engine.interop.REnvironmentMRFactory.REnvironmentReadImplNodeGen; +import com.oracle.truffle.r.engine.interop.REnvironmentMRFactory.REnvironmentWriteImplNodeGen; import com.oracle.truffle.r.ffi.impl.interop.NativePointer; import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode; import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode; +import com.oracle.truffle.r.runtime.data.RDouble; +import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.interop.Foreign2R; +import com.oracle.truffle.r.runtime.interop.Foreign2RNodeGen; +import com.oracle.truffle.r.runtime.interop.R2Foreign; +import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen; @MessageResolution(receiverType = REnvironment.class) public class REnvironmentMR { @@ -58,7 +73,7 @@ public class REnvironmentMR { @Resolve(message = "HAS_SIZE") public abstract static class REnvironmentHasSizeNode extends Node { protected Object access(@SuppressWarnings("unused") REnvironment receiver) { - return true; + return false; } } @@ -71,20 +86,19 @@ public class REnvironmentMR { @Resolve(message = "READ") public abstract static class REnvironmentReadNode extends Node { - @Child private ExtractVectorNode extract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true); + @Child private REnvironmentReadImplNode readNode = REnvironmentReadImplNodeGen.create(); - protected Object access(VirtualFrame frame, REnvironment receiver, String field) { - return extract.applyAccessField(frame, receiver, field); + protected Object access(VirtualFrame frame, REnvironment receiver, Object identifier) { + return readNode.execute(frame, receiver, identifier); } } @Resolve(message = "WRITE") public abstract static class REnvironmentWriteNode extends Node { - @Child private ReplaceVectorNode extract = ReplaceVectorNode.create(ElementAccessMode.SUBSCRIPT, true); + @Child private REnvironmentWriteImplNode writeNode = REnvironmentWriteImplNodeGen.create(); - protected Object access(VirtualFrame frame, REnvironment receiver, String field, Object valueObj) { - Object value = javaToRPrimitive(valueObj); - return extract.apply(frame, receiver, new Object[]{field}, value); + protected Object access(VirtualFrame frame, REnvironment receiver, Object field, Object valueObj) { + return writeNode.execute(frame, receiver, field, valueObj); } } @@ -98,8 +112,116 @@ public class REnvironmentMR { @Resolve(message = "KEY_INFO") public abstract static class REnvironmentKeyInfoNode extends Node { + @Child private REnvironmentKeyInfoImplNode keyInfoNode = REnvironmentKeyInfoImplNodeGen.create(); + + protected Object access(REnvironment receiver, Object obj) { + return keyInfoNode.execute(receiver, obj); + } + } + + @CanResolve + public abstract static class REnvironmentCheck extends Node { + + protected static boolean test(TruffleObject receiver) { + return receiver instanceof REnvironment; + } + } + + abstract static class REnvironmentReadImplNode extends Node { + @Child private ExtractVectorNode extract; + @Child private R2Foreign r2Foreign; + + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + protected abstract Object execute(VirtualFrame frame, TruffleObject receiver, Object identifier); + + @Specialization + protected Object access(VirtualFrame frame, REnvironment receiver, String identifier, + @Cached("createKeyInfoNode()") REnvironmentKeyInfoImplNode keyInfo) { + int info = keyInfo.execute(receiver, identifier); + if (unknownIdentifier.profile(!KeyInfo.isExisting(info))) { + throw UnknownIdentifierException.raise("" + identifier); + } + + initExtractNode(); + Object value = extract.applyAccessField(frame, receiver, identifier); + initR2ForeignNode(); + return r2Foreign.execute(value); + } + + @Fallback + protected Object access(VirtualFrame frame, TruffleObject receiver, Object identifier) { + throw UnknownIdentifierException.raise("" + identifier); + } + + protected REnvironmentKeyInfoImplNode createKeyInfoNode() { + return REnvironmentKeyInfoImplNodeGen.create(); + } + + private void initR2ForeignNode() { + if (r2Foreign == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + r2Foreign = insert(R2ForeignNodeGen.create()); + } + } - protected Object access(REnvironment receiver, String identifier) { + private void initExtractNode() { + if (extract == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + extract = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true)); + } + } + } + + abstract static class REnvironmentWriteImplNode extends Node { + @Child private Foreign2R foreign2R; + @Child private ReplaceVectorNode replace; + + private final ConditionProfile roIdentifier = ConditionProfile.createBinaryProfile(); + + protected abstract Object execute(VirtualFrame frame, TruffleObject receiver, Object identifier, Object valueObj); + + @Specialization + protected Object access(VirtualFrame frame, REnvironment receiver, String identifier, Object valueObj, + @Cached("createKeyInfoNode()") REnvironmentKeyInfoImplNode keyInfo) { + + int info = keyInfo.execute(receiver, identifier); + if (KeyInfo.isExisting(info)) { + if (roIdentifier.profile(!KeyInfo.isWritable(info))) { + // TODO - this is a bit weird - should be Message.WRITE and identifier + throw UnsupportedMessageException.raise(Message.WRITE); + } + } else if (receiver.isLocked()) { + throw UnsupportedMessageException.raise(Message.WRITE); + } + if (foreign2R == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + foreign2R = insert(Foreign2RNodeGen.create()); + } + Object value = foreign2R.execute(valueObj); + if (replace == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + replace = insert(ReplaceVectorNode.create(ElementAccessMode.SUBSCRIPT, true)); + } + return replace.apply(frame, receiver, new Object[]{identifier}, value); + } + + @Fallback + protected Object access(VirtualFrame frame, TruffleObject receiver, Object identifier, Object valueObj) { + throw UnknownIdentifierException.raise("" + identifier); + } + + protected REnvironmentKeyInfoImplNode createKeyInfoNode() { + return REnvironmentKeyInfoImplNodeGen.create(); + } + } + + abstract static class REnvironmentKeyInfoImplNode extends Node { + + protected abstract int execute(REnvironment receiver, Object identifier); + + @Specialization + protected int access(REnvironment receiver, String identifier) { Object val = receiver.get(identifier); if (val == null) { return 0; @@ -109,15 +231,13 @@ public class REnvironmentMR { if (!receiver.isLocked() && !receiver.bindingIsLocked(identifier)) { builder.setWritable(true); } + builder.setInvocable(val instanceof RFunction); return builder.build(); } - } - - @CanResolve - public abstract static class REnvironmentCheck extends Node { - protected static boolean test(TruffleObject receiver) { - return receiver instanceof REnvironment; + @Fallback + protected int access(REnvironment receiver, Object identifier) { + return 0; } } } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RExternalPtrMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RExternalPtrMR.java index 2ccac47016908c9d99126ad1307aedc1c368c1e5..d180a32a9046410c7cd08f22b4ab105d8de64c18 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RExternalPtrMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RExternalPtrMR.java @@ -24,12 +24,41 @@ package com.oracle.truffle.r.engine.interop; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.MessageResolution; +import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.runtime.data.RExternalPtr; @MessageResolution(receiverType = RExternalPtr.class) public class RExternalPtrMR { + @Resolve(message = "IS_BOXED") + public abstract static class RExternalPtrIsBoxedNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "HAS_SIZE") + public abstract static class RExternalPtrHasSizeNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "IS_NULL") + public abstract static class RExternalPtrIsNullNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "KEY_INFO") + public abstract static class RExternalPtrKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @CanResolve public abstract static class RExternalPtrCheck extends Node { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java index 6b21deed0d9c5348e19b5c75349a48434e000216..3fd10f6ef50db12c670ffa5c10e750ecd2d7ffd8 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java @@ -47,6 +47,7 @@ import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTruffleObject; import com.oracle.truffle.r.runtime.data.RUnboundValue; +import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.env.frame.ActiveBinding; @@ -108,8 +109,8 @@ public final class RForeignAccessFactoryImpl implements RForeignAccessFactory { return RMissingMRForeign.ACCESS; } else if (obj instanceof REmpty) { return REmptyMRForeign.ACCESS; - } else if (obj instanceof RAbstractVector) { - return ForeignAccess.create(RAbstractVector.class, new RAbstractVectorAccessFactory()); + } else if (obj instanceof RAbstractAtomicVector) { + return ForeignAccess.create(RAbstractAtomicVector.class, new RAbstractVectorAccessFactory()); } else { ForeignAccess access = FFI_RForeignAccessFactoryImpl.getForeignAccess(obj); if (access != null) { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RFunctionMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RFunctionMR.java index 027ad9d9dd1f50fd87fa712acfdc1dc20166c2e7..0d6afa91c24e34b9813494e73606d156be01086c 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RFunctionMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RFunctionMR.java @@ -41,9 +41,42 @@ import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; import com.oracle.truffle.r.runtime.env.frame.RFrameSlot; +import com.oracle.truffle.r.runtime.interop.Foreign2R; +import com.oracle.truffle.r.runtime.interop.Foreign2RNodeGen; +import com.oracle.truffle.r.runtime.interop.R2Foreign; +import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen; @MessageResolution(receiverType = RFunction.class) public class RFunctionMR { + + @Resolve(message = "IS_BOXED") + public abstract static class RFunctionIsBoxedNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "HAS_SIZE") + public abstract static class RFunctionHasSizeNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "IS_NULL") + public abstract static class RFunctionIsNullNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "KEY_INFO") + public abstract static class RFunctionKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @Resolve(message = "IS_EXECUTABLE") public abstract static class RFunctionIsExecutabledNode extends Node { protected Object access(@SuppressWarnings("unused") RFunction receiver) { @@ -60,6 +93,9 @@ public class RFunctionMR { @Resolve(message = "EXECUTE") public abstract static class RFunctionExecuteNode extends Node { + @Child private Foreign2R foreign2R = Foreign2RNodeGen.create(); + @Child private R2Foreign r2Foreign = R2ForeignNodeGen.create(); + private static final FrameDescriptor emptyFrameDescriptor = FrameSlotChangeMonitor.initializeFunctionFrameDescriptor("<interop>", new FrameDescriptor("R interop frame")); private static final RFrameSlot argsIdentifier = RFrameSlot.createTemp(false); private static final FrameSlot slot = FrameSlotChangeMonitor.findOrAddFrameSlot(emptyFrameDescriptor, argsIdentifier, FrameSlotKind.Object); @@ -74,10 +110,15 @@ public class RFunctionMR { Object[] dummyFrameArgs = RArguments.createUnitialized(); VirtualFrame dummyFrame = Truffle.getRuntime().createVirtualFrame(dummyFrameArgs, emptyFrameDescriptor); - RArgsValuesAndNames actualArgs = new RArgsValuesAndNames(arguments, ArgumentsSignature.empty(arguments.length)); + Object[] convertedArguments = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + convertedArguments[i] = foreign2R.execute(arguments[i]); + } + RArgsValuesAndNames actualArgs = new RArgsValuesAndNames(convertedArguments, ArgumentsSignature.empty(arguments.length)); try { FrameSlotChangeMonitor.setObject(dummyFrame, slot, actualArgs); - return call.execute(dummyFrame, receiver); + Object value = call.execute(dummyFrame, receiver); + return r2Foreign.execute(value); } finally { FrameSlotChangeMonitor.setObject(dummyFrame, slot, null); } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RIntegerMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RIntegerMR.java index edd489b79917ad82d76521e1a2eada4d65b44077..498b95efac7e6914ba5a96755a01cc495a5fa7a2 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RIntegerMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RIntegerMR.java @@ -52,9 +52,16 @@ public class RIntegerMR { } } + @Resolve(message = "KEY_INFO") + public abstract static class RIntegerKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @Resolve(message = "UNBOX") public abstract static class RIntegerUnboxNode extends Node { - protected double access(RInteger receiver) { + protected int access(RInteger receiver) { return receiver.getValue(); } } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RInteropScalarMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RInteropScalarMR.java index 0ae18bbe9de7a97cf20fc6b8b4e97198d3c8b119..798ab8277caded8b647a63aa5af2377f3e0c41c0 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RInteropScalarMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RInteropScalarMR.java @@ -76,6 +76,13 @@ public class RInteropScalarMR { } } + @Resolve(message = "KEY_INFO") + public abstract static class RInteropScalarKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @CanResolve public abstract static class RInteropScalarCheck extends Node { protected static boolean test(TruffleObject receiver) { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RLanguageMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RLanguageMR.java index c0c338cfb7ec3716e457b23fe35a561d69d11684..353ac3daebfe9b9c1a4e8c4699a7b05cee0c4682 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RLanguageMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RLanguageMR.java @@ -22,20 +22,27 @@ */ package com.oracle.truffle.r.engine.interop; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.CanResolve; -import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.KeyInfo; import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.ffi.impl.interop.NativePointer; import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RLogical; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.interop.R2Foreign; +import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen; @MessageResolution(receiverType = RLanguage.class) public class RLanguageMR { @@ -54,6 +61,13 @@ public class RLanguageMR { } } + @Resolve(message = "GET_SIZE") + public abstract static class RLanguageGetSizeNode extends Node { + protected Object access(@SuppressWarnings("unused") RLanguage receiver) { + return receiver.getLength(); + } + } + @Resolve(message = "IS_NULL") public abstract static class RLanguageIsNullNode extends Node { protected Object access(@SuppressWarnings("unused") RLanguage receiver) { @@ -70,44 +84,93 @@ public class RLanguageMR { @Resolve(message = "READ") public abstract static class RLanguageReadNode extends Node { - @Child private ExtractVectorNode extract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true); + @Child private ReadNode readNode = RLanguageMRFactory.ReadNodeGen.create(); - protected Object access(VirtualFrame frame, RLanguage receiver, int label) { - return extract.apply(frame, receiver, new Object[]{label + 1}, RLogical.TRUE, RLogical.TRUE); + protected Object access(VirtualFrame frame, RLanguage receiver, Object identifier) { + return readNode.execute(frame, receiver, identifier); } } - @Resolve(message = "WRITE") - public abstract static class RLanguageWriteNode extends Node { + @Resolve(message = "KEY_INFO") + public abstract static class RLanguageNode extends Node { + @Node.Child private KeyInfoNode keyInfoNode = RLanguageMRFactory.KeyInfoNodeGen.create(); - @SuppressWarnings("unused") - protected Object access(RLanguage receiver, int label, Object valueObj) { - throw UnsupportedMessageException.raise(Message.WRITE); + protected Object access(VirtualFrame frame, RLanguage receiver, Object obj) { + return keyInfoNode.execute(receiver, obj); } } - @Resolve(message = "KEYS") - public abstract static class RLanguageKeysNode extends Node { + @CanResolve + public abstract static class RLanguageCheck extends Node { - protected Object access(@SuppressWarnings("unused") RLanguage receiver) { - return RNull.instance; + protected static boolean test(TruffleObject receiver) { + return receiver instanceof RLanguage; } } - @Resolve(message = "KEY_INFO") - public abstract static class RLanguageKeyInfoNode extends Node { + abstract static class ReadNode extends Node { + @Child private ExtractVectorNode extract; + @Child private R2Foreign r2Foreign; + + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + abstract Object execute(VirtualFrame frame, RLanguage receiver, Object identifier); + + @Specialization + protected Object access(VirtualFrame frame, RLanguage receiver, int idx, + @Cached("createKeyInfoNode()") KeyInfoNode keyInfo) { + + int info = keyInfo.execute(receiver, idx); + if (unknownIdentifier.profile(!KeyInfo.isExisting(info))) { + throw UnknownIdentifierException.raise("" + idx); + } + + if (extract == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + extract = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true)); + } + Object value = extract.apply(frame, receiver, new Object[]{idx + 1}, RLogical.TRUE, RLogical.TRUE); + if (value == null) { + return RNull.instance; + } + + if (r2Foreign == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + r2Foreign = insert(R2ForeignNodeGen.create()); + } + return r2Foreign.execute(value); + } - @SuppressWarnings("unused") - protected Object access(VirtualFrame frame, RLanguage receiver, String identifier) { - return 0; + @Fallback + protected Object access(VirtualFrame frame, RLanguage receiver, Object identifier) { + throw UnknownIdentifierException.raise("" + identifier); + } + + protected static KeyInfoNode createKeyInfoNode() { + return RLanguageMRFactory.KeyInfoNodeGen.create(); } } - @CanResolve - public abstract static class RLanguageCheck extends Node { + abstract static class KeyInfoNode extends Node { + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); - protected static boolean test(TruffleObject receiver) { - return receiver instanceof RLanguage; + abstract int execute(RLanguage receiver, Object identifier); + + @Specialization + protected int access(RLanguage receiver, int idx) { + if (unknownIdentifier.profile(idx < 0 || idx >= receiver.getLength())) { + return 0; + } + + KeyInfo.Builder builder = KeyInfo.newBuilder(); + builder.setReadable(true); + // TODO what about writeble/invocable/... + return builder.build(); + } + + @Fallback + protected int access(RLanguage receiver, Object identifier) { + return 0; } } } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RListMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RListMR.java deleted file mode 100644 index 2501226929587783cc413eba72957ac64508654d..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RListMR.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2016, 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.engine.interop; - -import static com.oracle.truffle.r.engine.interop.Utils.javaToRPrimitive; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.interop.CanResolve; -import com.oracle.truffle.api.interop.KeyInfo; -import com.oracle.truffle.api.interop.KeyInfo.Builder; -import com.oracle.truffle.api.interop.MessageResolution; -import com.oracle.truffle.api.interop.Resolve; -import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.ConditionProfile; -import com.oracle.truffle.r.ffi.impl.interop.NativePointer; -import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; -import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode; -import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode; -import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; -import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RStringVector; - -@MessageResolution(receiverType = RList.class) -public class RListMR { - - @Resolve(message = "IS_BOXED") - public abstract static class RListIsBoxedNode extends Node { - protected Object access(@SuppressWarnings("unused") RList receiver) { - return false; - } - } - - @Resolve(message = "HAS_SIZE") - public abstract static class RListHasSizeNode extends Node { - protected Object access(@SuppressWarnings("unused") RList receiver) { - return true; - } - } - - @Resolve(message = "IS_NULL") - public abstract static class RListIsNullNode extends Node { - protected Object access(@SuppressWarnings("unused") RList receiver) { - return false; - } - } - - @Resolve(message = "READ") - public abstract static class RListReadNode extends Node { - @Child private ExtractVectorNode extract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true); - - protected Object access(VirtualFrame frame, RList receiver, String field) { - return extract.applyAccessField(frame, receiver, field); - } - } - - @Resolve(message = "WRITE") - public abstract static class RListWriteNode extends Node { - @Child private ReplaceVectorNode replace = ReplaceVectorNode.create(ElementAccessMode.SUBSCRIPT, true); - - protected Object access(VirtualFrame frame, RList receiver, String field, Object valueObj) { - Object value = javaToRPrimitive(valueObj); - return replace.apply(frame, receiver, new Object[]{field}, value); - } - } - - @Resolve(message = "KEYS") - public abstract static class RListKeysNode extends Node { - @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); - - protected Object access(RList receiver) { - RStringVector names = getNamesNode.getNames(receiver); - return names != null ? names : RNull.instance; - } - } - - @Resolve(message = "KEY_INFO") - public abstract static class RListKeyInfoNode extends Node { - @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); - @Child private ExtractVectorNode extractNode; - - private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); - - protected Object access(VirtualFrame frame, RList receiver, String identifier) { - RStringVector names = getNamesNode.getNames(receiver); - boolean exists = false; - for (int i = 0; i < names.getLength(); i++) { - if (identifier.equals(names.getDataAt(i))) { - exists = true; - break; - } - } - if (unknownIdentifier.profile(!exists)) { - return 0; - } - - Builder builder = KeyInfo.newBuilder(); - builder.setReadable(true).setWritable(true); - if (extractNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - extractNode = insert(ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true)); - } - Object value = extractNode.applyAccessField(frame, receiver, identifier); - builder.setInvocable(value instanceof RFunction); - return builder.build(); - } - } - - @Resolve(message = "TO_NATIVE") - public abstract static class RListToNativeNode extends Node { - protected Object access(RList receiver) { - return new NativePointer(receiver); - } - } - - @CanResolve - public abstract static class RListCheck extends Node { - - protected static boolean test(TruffleObject receiver) { - return receiver instanceof RList; - } - } -} diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RMissingMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RMissingMR.java index 6b776976b902216cd2c335d642e651c217408eea..22ed9437334387647a0af54e855179b0ed06aec1 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RMissingMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RMissingMR.java @@ -53,6 +53,13 @@ public class RMissingMR { } } + @Resolve(message = "KEY_INFO") + public abstract static class RMissingKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @CanResolve public abstract static class RMissingCheck extends Node { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RNullMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RNullMR.java index dcbe27c3bcbc55cbe103d4d101747c795c957817..92aa246996cb3100f2eae689e52df2536ee8fb27 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RNullMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RNullMR.java @@ -58,6 +58,13 @@ public class RNullMR { } } + @Resolve(message = "KEY_INFO") + public abstract static class RNullKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @Resolve(message = "TO_NATIVE") public abstract static class RNullToNativeNode extends Node { protected Object access(@SuppressWarnings("unused") RNull receiver) { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPairListMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPairListMR.java deleted file mode 100644 index aed400fc084ff2f0029eaaf462b8d79bf48b96d1..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPairListMR.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2016, 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.engine.interop; - -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.interop.CanResolve; -import com.oracle.truffle.api.interop.MessageResolution; -import com.oracle.truffle.api.interop.Resolve; -import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.ffi.impl.interop.NativePointer; -import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; -import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode; -import com.oracle.truffle.r.nodes.control.RLengthNode; -import com.oracle.truffle.r.runtime.data.RLogical; -import com.oracle.truffle.r.runtime.data.RMissing; -import com.oracle.truffle.r.runtime.data.RPairList; - -@MessageResolution(receiverType = RPairList.class) -public class RPairListMR { - @Resolve(message = "IS_BOXED") - public abstract static class RPairListIsBoxedNode extends Node { - protected Object access(@SuppressWarnings("unused") RPairList receiver) { - return false; - } - } - - @Resolve(message = "HAS_SIZE") - public abstract static class RPairListHasSizeNode extends Node { - protected Object access(@SuppressWarnings("unused") RPairList receiver) { - return true; - } - } - - @Resolve(message = "IS_NULL") - public abstract static class RPairListIsNullNode extends Node { - protected Object access(@SuppressWarnings("unused") RPairList receiver) { - return false; - } - } - - @Resolve(message = "GET_SIZE") - public abstract static class RVectorGetSizeNode extends Node { - @Child private RLengthNode lengthNode = RLengthNode.create(); - - protected Object access(VirtualFrame frame, RPairList receiver) { - return lengthNode.executeInteger(frame, receiver); - } - } - - @Resolve(message = "READ") - public abstract static class RPairListReadNode extends Node { - @Child private ExtractVectorNode extract = ExtractVectorNode.create(ElementAccessMode.SUBSCRIPT, true); - - protected Object access(VirtualFrame frame, RPairList receiver, Integer index) { - return extract.apply(frame, receiver, new Object[]{index}, RLogical.valueOf(false), RMissing.instance); - } - } - - @Resolve(message = "TO_NATIVE") - public abstract static class RPairListToNativeNode extends Node { - protected Object access(RPairList receiver) { - return new NativePointer(receiver); - } - } - - @CanResolve - public abstract static class RPairListCheck extends Node { - - protected static boolean test(TruffleObject receiver) { - return receiver instanceof RPairList; - } - } -} diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java index fc12c99c4c2c594a6c37042e634ebb678d18e814..16c7115a4dcb2497a2fb2e90c8b6c95a668c1f31 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java @@ -23,6 +23,8 @@ package com.oracle.truffle.r.engine.interop; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.CanResolve; import com.oracle.truffle.api.interop.KeyInfo; import com.oracle.truffle.api.interop.MessageResolution; @@ -31,6 +33,9 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.engine.interop.RPromiseMRFactory.RPromiseKeyInfoImplNodeGen; +import com.oracle.truffle.r.engine.interop.RPromiseMRFactory.RPromiseReadImplNodeGen; +import com.oracle.truffle.r.engine.interop.RPromiseMRFactory.RPromiseWriteImplNodeGen; import com.oracle.truffle.r.ffi.impl.interop.NativePointer; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.runtime.RRuntime; @@ -61,31 +66,62 @@ public class RPromiseMR { @Resolve(message = "READ") public abstract static class RPromiseReadNode extends Node { + @Child RPromiseReadImplNode readNode = RPromiseReadImplNodeGen.create(); @TruffleBoundary protected Object access(RPromise receiver, String field) { - if (PROP_EXPR.equals(field)) { - return RDataFactory.createLanguage(receiver.getRep()); - } - if (PROP_IS_EVALUATED.equals(field)) { - return RRuntime.asLogical(receiver.isEvaluated()); - } - if (PROP_VALUE.equals(field)) { - // only read value if evaluated - if (receiver.isEvaluated()) { - return receiver.getValue(); - } - return RNull.instance; - } - throw UnknownIdentifierException.raise(field); + return readNode.execute(receiver, receiver); } } @Resolve(message = "WRITE") public abstract static class RPromiseWriteNode extends Node { + @Child RPromiseWriteImplNode writeNode = RPromiseWriteImplNodeGen.create(); protected Object access(RPromise receiver, String field, Object valueObj) { - if (PROP_IS_EVALUATED.equals(field)) { + return writeNode.execute(receiver, valueObj, valueObj); + } + } + + @Resolve(message = "KEYS") + public abstract static class RPromiseKeysNode extends Node { + + protected Object access(@SuppressWarnings("unused") RPromise receiver) { + return RDataFactory.createStringVector(new String[]{PROP_VALUE, PROP_IS_EVALUATED, PROP_EXPR}, true); + } + } + + @Resolve(message = "KEY_INFO") + public abstract static class RPromiseKeyInfoNode extends Node { + @Child RPromiseKeyInfoImplNode keyInfoNode = RPromiseKeyInfoImplNodeGen.create(); + + protected Object access(RPromise receiver, String identifier) { + return keyInfoNode.execute(receiver, identifier); + } + } + + @Resolve(message = "TO_NATIVE") + public abstract static class RPromiseToNativeNode extends Node { + protected Object access(RPromise receiver) { + return new NativePointer(receiver); + } + } + + @CanResolve + public abstract static class RPromiseCheck extends Node { + + protected static boolean test(TruffleObject receiver) { + return receiver instanceof RPromise; + } + } + + abstract static class RPromiseWriteImplNode extends Node { + + protected abstract Object execute(RPromise receiver, Object identifier, Object valueObj); + + @Specialization + protected Object access(RPromise receiver, String identifier, Object valueObj) { + if (PROP_IS_EVALUATED.equals(identifier)) { if (!(valueObj instanceof Boolean)) { throw UnsupportedTypeException.raise(new Object[]{valueObj}); } @@ -98,21 +134,48 @@ public class RPromiseMR { } return RRuntime.asLogical(receiver.isEvaluated()); } - throw UnknownIdentifierException.raise(field); + throw UnknownIdentifierException.raise(identifier); + } + + @Fallback + protected Object access(RPromise receiver, Object identifier, Object valueObj) { + throw UnknownIdentifierException.raise("" + identifier); } } - @Resolve(message = "KEYS") - public abstract static class RPromiseKeysNode extends Node { + abstract static class RPromiseReadImplNode extends Node { - protected Object access(@SuppressWarnings("unused") RPromise receiver) { - return RDataFactory.createStringVector(new String[]{PROP_VALUE, PROP_IS_EVALUATED, PROP_EXPR}, true); + protected abstract Object execute(RPromise receiver, Object identifier); + + @Specialization + protected Object access(@SuppressWarnings("unused") RPromise receiver, String identifier) { + if (PROP_EXPR.equals(identifier)) { + return RDataFactory.createLanguage(receiver.getRep()); + } + if (PROP_IS_EVALUATED.equals(identifier)) { + return RRuntime.asLogical(receiver.isEvaluated()); + } + if (PROP_VALUE.equals(identifier)) { + // only read value if evaluated + if (receiver.isEvaluated()) { + return receiver.getValue(); + } + return RNull.instance; + } + throw UnknownIdentifierException.raise(identifier); + } + + @Fallback + protected Object access(RPromise receiver, Object identifier) { + throw UnknownIdentifierException.raise("" + identifier); } } - @Resolve(message = "KEY_INFO") - public abstract static class RPromiseKeyInfoNode extends Node { + abstract static class RPromiseKeyInfoImplNode extends Node { + + protected abstract Object execute(RPromise receiver, Object identifier); + @Specialization protected Object access(@SuppressWarnings("unused") RPromise receiver, String identifier) { if (PROP_EXPR.equals(identifier) || PROP_VALUE.equals(identifier)) { return KeyInfo.newBuilder().setReadable(true).build(); @@ -122,20 +185,10 @@ public class RPromiseMR { return 0; } } - } - - @Resolve(message = "TO_NATIVE") - public abstract static class RPromiseToNativeNode extends Node { - protected Object access(RPromise receiver) { - return new NativePointer(receiver); - } - } - @CanResolve - public abstract static class RPromiseCheck extends Node { - - protected static boolean test(TruffleObject receiver) { - return receiver instanceof RPromise; + @Fallback + protected Object access(RPromise receiver, Object identifier) { + return 0; } } } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RS4ObjectMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RS4ObjectMR.java index 084b6d390d0d88da68bb959c763d3f235c81782d..0f7c7346fd652a5d815418533c056444f1983215 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RS4ObjectMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RS4ObjectMR.java @@ -22,17 +22,38 @@ */ package com.oracle.truffle.r.engine.interop; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.CanResolve; +import com.oracle.truffle.api.interop.KeyInfo; +import com.oracle.truffle.api.interop.KeyInfo.Builder; +import com.oracle.truffle.api.interop.Message; import com.oracle.truffle.api.interop.MessageResolution; import com.oracle.truffle.api.interop.Resolve; 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.nodes.Node; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.engine.interop.RS4ObjectMRFactory.RS4ObjectKeyInfoImplNodeGen; +import com.oracle.truffle.r.engine.interop.RS4ObjectMRFactory.RS4ObjectReadImplNodeGen; +import com.oracle.truffle.r.engine.interop.RS4ObjectMRFactory.RS4ObjectWriteImplNodeGen; import com.oracle.truffle.r.nodes.attributes.ArrayAttributeNode; import com.oracle.truffle.r.nodes.attributes.GetAttributeNode; import com.oracle.truffle.r.nodes.attributes.SetAttributeNode; import com.oracle.truffle.r.runtime.data.RAttributesLayout.RAttribute; import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RS4Object; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.interop.Foreign2R; +import com.oracle.truffle.r.runtime.interop.Foreign2RNodeGen; +import com.oracle.truffle.r.runtime.interop.R2Foreign; +import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen; @MessageResolution(receiverType = RS4Object.class) public class RS4ObjectMR { @@ -60,21 +81,19 @@ public class RS4ObjectMR { @Resolve(message = "READ") public abstract static class RS4ObjectReadNode extends Node { - @Child private GetAttributeNode getAttributeNode = GetAttributeNode.create(); + @Child private RS4ObjectReadImplNode readNode = RS4ObjectReadImplNodeGen.create(); - protected Object access(RS4Object receiver, String field) { - return getAttributeNode.execute(receiver, field); + protected Object access(RS4Object receiver, Object identifier) { + return readNode.execute(receiver, identifier); } } @Resolve(message = "WRITE") public abstract static class RS4ObjectWriteNode extends Node { - @Child private SetAttributeNode setAttributeNode = SetAttributeNode.create(); + @Child private RS4ObjectWriteImplNode writeNode = RS4ObjectWriteImplNodeGen.create(); - protected Object access(RS4Object receiver, String field, Object valueObj) { - Object value = Utils.javaToRPrimitive(valueObj); - setAttributeNode.execute(receiver, field, value); - return value; + protected Object access(RS4Object receiver, Object identifier, Object valueObj) { + return writeNode.execute(receiver, identifier, valueObj); } } @@ -83,13 +102,26 @@ public class RS4ObjectMR { @Child private ArrayAttributeNode arrayAttrAccess = ArrayAttributeNode.create(); protected Object access(RS4Object receiver) { - RAttribute[] attributes = arrayAttrAccess.execute(receiver.getAttributes()); - String[] data = new String[attributes.length]; - for (int i = 0; i < data.length; i++) { - data[i] = attributes[i].getName(); - } - return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR); + return getKeys(receiver, arrayAttrAccess); + } + } + + @Resolve(message = "KEY_INFO") + public abstract static class RS4ObjectNode extends Node { + @Node.Child private RS4ObjectKeyInfoImplNode keyInfoNode = RS4ObjectKeyInfoImplNodeGen.create(); + + protected Object access(VirtualFrame frame, RS4Object receiver, Object obj) { + return keyInfoNode.execute(receiver, obj); + } + } + + private static RAbstractStringVector getKeys(RS4Object s4, ArrayAttributeNode arrayAttrAccess) { + RAttribute[] attributes = arrayAttrAccess.execute(s4.getAttributes()); + String[] data = new String[attributes.length]; + for (int i = 0; i < data.length; i++) { + data[i] = attributes[i].getName(); } + return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR); } @CanResolve @@ -98,4 +130,138 @@ public class RS4ObjectMR { return receiver instanceof RS4Object; } } + + abstract static class RS4ObjectReadImplNode extends Node { + @Child private GetAttributeNode getAttributeNode; + @Child private R2Foreign r2Foreign; + + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + abstract Object execute(RS4Object receiver, Object identifier); + + @Specialization + protected Object access(RS4Object receiver, String identifier, + @Cached("createKeyInfoNode()") RS4ObjectKeyInfoImplNode keyInfo) { + int info = keyInfo.execute(receiver, identifier); + if (unknownIdentifier.profile(!KeyInfo.isExisting(info))) { + throw UnknownIdentifierException.raise("" + identifier); + } + + if (getAttributeNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getAttributeNode = insert(GetAttributeNode.create()); + } + Object value = getAttributeNode.execute(receiver, identifier); + if (value == null) { + return RNull.instance; + } + + if (r2Foreign == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + r2Foreign = insert(R2ForeignNodeGen.create()); + } + return r2Foreign.execute(value); + } + + @Fallback + protected Object access(RS4Object receiver, Object identifier) { + throw UnknownIdentifierException.raise("" + identifier); + } + + protected static ArrayAttributeNode createArrayAttributeNode() { + return ArrayAttributeNode.create(); + } + + protected static RS4ObjectKeyInfoImplNode createKeyInfoNode() { + return RS4ObjectKeyInfoImplNodeGen.create(); + } + } + + abstract static class RS4ObjectWriteImplNode extends Node { + @Child private SetAttributeNode setAttributeNode; + @Child private Foreign2R foreign2R; + + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + abstract Object execute(RS4Object receiver, Object identifier, Object valueObj); + + @Specialization + protected Object access(RS4Object receiver, String identifier, Object valueObj, + @Cached("createKeyInfoNode()") RS4ObjectKeyInfoImplNode keyInfo) { + int info = keyInfo.execute(receiver, identifier); + if (unknownIdentifier.profile(!KeyInfo.isExisting(info))) { + throw UnknownIdentifierException.raise("" + identifier); + } + + if (!KeyInfo.isWritable(info)) { + throw UnsupportedMessageException.raise(Message.WRITE); + } + + if (foreign2R == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + foreign2R = insert(Foreign2RNodeGen.create()); + } + Object value = foreign2R.execute(valueObj); + if (setAttributeNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + setAttributeNode = insert(SetAttributeNode.create()); + } + setAttributeNode.execute(receiver, identifier, value); + return valueObj; + } + + @Fallback + protected Object access(RS4Object receiver, Object identifier, Object valueObj) { + throw UnknownIdentifierException.raise("" + identifier); + } + + protected static RS4ObjectKeyInfoImplNode createKeyInfoNode() { + return RS4ObjectKeyInfoImplNodeGen.create(); + } + } + + abstract static class RS4ObjectKeyInfoImplNode extends Node { + @Child private GetAttributeNode getAttributeNode; + + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + abstract int execute(RS4Object receiver, Object idx); + + @Specialization + protected int access(RS4Object receiver, String identifier, + @Cached("createArrayAttributeNode()") ArrayAttributeNode arrayAttrAccess) { + int idx = getAttrIndex(receiver, identifier, arrayAttrAccess); + if (unknownIdentifier.profile(idx < 0)) { + return 0; + } + + if (getAttributeNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getAttributeNode = insert(GetAttributeNode.create()); + } + Builder builder = KeyInfo.newBuilder(); + builder.setReadable(true).setWritable(!identifier.equals("class")); + builder.setInvocable(getAttributeNode.execute(receiver, identifier) instanceof RFunction); + return builder.build(); + } + + protected static ArrayAttributeNode createArrayAttributeNode() { + return ArrayAttributeNode.create(); + } + + @Fallback + protected int access(RS4Object receiver, Object field) { + return 0; + } + } + + private static int getAttrIndex(RS4Object receiver, String identifier, ArrayAttributeNode arrayAttrAccess) { + RAttribute[] attributes = arrayAttrAccess.execute(receiver.getAttributes()); + for (int i = 0; i < attributes.length; i++) { + if (attributes[i].getName().equals(identifier)) { + return i; + } + } + return -1; + } } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java index 3c00139f868ba1148f9f7d281eb70956feb519d9..f175339f0953f8a87e4ba5f9d50c0c4568119a77 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RSymbolMR.java @@ -33,6 +33,34 @@ import com.oracle.truffle.r.runtime.data.RSymbol; @MessageResolution(receiverType = RSymbol.class) public class RSymbolMR { + @Resolve(message = "IS_BOXED") + public abstract static class RSymbolIsBoxedNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "HAS_SIZE") + public abstract static class RSymbolHasSizeNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "IS_NULL") + public abstract static class RSymbolIsNullNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver) { + return false; + } + } + + @Resolve(message = "KEY_INFO") + public abstract static class RSymbolKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @Resolve(message = "TO_NATIVE") public abstract static class RSymbolToNativeNode extends Node { protected Object access(RSymbol receiver) { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RUnboundValueMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RUnboundValueMR.java index f8c1e15d8bf90e750ba2049d64eae63b10f2fea0..c2d60fa3a6da3b023cd43db7b6e8b83e34d10a37 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RUnboundValueMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RUnboundValueMR.java @@ -52,6 +52,13 @@ public class RUnboundValueMR { } } + @Resolve(message = "KEY_INFO") + public abstract static class RUnboundValueKeyInfoNode extends Node { + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, @SuppressWarnings("unused") Object identifier) { + return 0; + } + } + @CanResolve public abstract static class RUnboundValueCheck extends Node { diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/AbstractMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/AbstractMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c53520bccbbf856cdd5ae2f7cfaabcf039f6a44f --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/AbstractMRTest.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.InteropException; +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.r.ffi.impl.interop.NativePointer; +import java.util.HashSet; +import java.util.Set; +import org.junit.Assert; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +abstract class AbstractMRTest { + + /** + * Create TruffleObject-s to be rudimentary tested for IS_NULL, IS_BOXED/UNBOX, IS_EXECUTABLE, + * IS_POINTER, HAS_SIZE/GET_SIZE/KEYS behavior. + * + * @return + * @throws Exception + */ + protected abstract TruffleObject[] createTruffleObjects() throws Exception; + + /** + * Create a test TruffleObject having size == 0. + */ + protected abstract TruffleObject createEmptyTruffleObject() throws Exception; + + protected String[] getKeys() { + return null; + } + + protected boolean isNull(TruffleObject obj) { + return false; + } + + protected boolean isExecutable(TruffleObject obj) { + return false; + } + + protected boolean isPointer(TruffleObject obj) { + return false; + } + + protected boolean isBoxed(TruffleObject obj) { + return false; + } + + protected boolean hasSize(TruffleObject obj) { + return false; + } + + protected int getSize(TruffleObject obj) { + throw new UnsupportedOperationException("override if hasSize returns true"); + } + + protected Object getUnboxed(TruffleObject obj) { + throw new UnsupportedOperationException("override if isBoxed returns true"); + } + + @Test + public void testIsNull() throws Exception { + for (TruffleObject obj : createTruffleObjects()) { + assertEquals(isNull(obj), ForeignAccess.sendIsNull(Message.IS_NULL.createNode(), obj)); + } + } + + @Test + public void testIsExecutable() throws Exception { + for (TruffleObject obj : createTruffleObjects()) { + assertEquals(isExecutable(obj), ForeignAccess.sendIsExecutable(Message.IS_EXECUTABLE.createNode(), obj)); + } + } + + @Test + public void testIsPointer() throws Exception { + for (TruffleObject obj : createTruffleObjects()) { + assertEquals(isPointer(obj), ForeignAccess.sendIsPointer(Message.IS_POINTER.createNode(), obj)); + } + } + + @Test + public void testNativePointer() throws Exception { + for (TruffleObject obj : createTruffleObjects()) { + try { + assertTrue(ForeignAccess.sendToNative(Message.TO_NATIVE.createNode(), obj) instanceof NativePointer); + } catch (UnsupportedMessageException unsupportedMessageException) { + } + } + } + + @Test + public void testSize() throws Exception { + for (TruffleObject obj : createTruffleObjects()) { + boolean hasSize = ForeignAccess.sendHasSize(Message.HAS_SIZE.createNode(), obj); + assertEquals("" + obj.getClass() + " " + obj, hasSize(obj), hasSize); + if (hasSize) { + assertEquals(getSize(obj), ForeignAccess.sendGetSize(Message.GET_SIZE.createNode(), obj)); + } else { + assertInteropException(() -> ForeignAccess.sendGetSize(Message.GET_SIZE.createNode(), obj), UnsupportedMessageException.class); + } + } + } + + @Test + public void testBoxed() throws Exception { + for (TruffleObject obj : createTruffleObjects()) { + boolean isBoxed = ForeignAccess.sendIsBoxed(Message.IS_BOXED.createNode(), obj); + assertEquals(isBoxed(obj), isBoxed); + if (isBoxed) { + assertEquals(getUnboxed(obj), ForeignAccess.sendUnbox(Message.UNBOX.createNode(), obj)); + } + // else { + // assertInteropException(() -> ForeignAccess.sendUnbox(Message.UNBOX.createNode(), + // obj), UnsupportedMessageException.class); + // } + } + } + + @Test + public void testKeys() throws Exception { + String[] keys = getKeys(); + if (keys == null) { + return; + } + for (TruffleObject obj : createTruffleObjects()) { + TruffleObject keysObj = ForeignAccess.sendKeys(Message.KEYS.createNode(), obj); + int size = (int) ForeignAccess.sendGetSize(Message.GET_SIZE.createNode(), keysObj); + assertEquals(keys.length, size); + + Set<Object> set = new HashSet<>(); + for (int i = 0; i < size; i++) { + set.add(ForeignAccess.sendRead(Message.READ.createNode(), keysObj, i)); + } + for (String key : keys) { + assertTrue(set.contains(key)); + } + } + } + + @Test + public void testEmpty() throws Exception { + + TruffleObject obj = createEmptyTruffleObject(); + if (obj != null) { + if (hasSize(obj)) { + int size = (int) ForeignAccess.sendGetSize(Message.GET_SIZE.createNode(), obj); + assertEquals(0, size); + } + + TruffleObject keys = null; + try { + keys = ForeignAccess.sendKeys(Message.KEYS.createNode(), obj); + } catch (UnsupportedMessageException ex) { + } + if (keys != null) { + boolean keysHasSize = ForeignAccess.sendHasSize(Message.HAS_SIZE.createNode(), keys); + if (keysHasSize) { + int keysSize = (int) ForeignAccess.sendGetSize(Message.GET_SIZE.createNode(), keys); + assertEquals(0, keysSize); + } + } + } + } + + protected interface ForeignCall { + void call() throws Exception; + } + + protected void assertInteropException(ForeignCall c, Class<? extends InteropException> expectedClazz) { + boolean ie = false; + try { + c.call(); + } catch (InteropException ex) { + if (expectedClazz != null && ex.getClass() != expectedClazz) { + Assert.fail(expectedClazz + " was expected but got instead: " + ex); + } + ie = true; + } catch (Exception ex) { + if (expectedClazz != null && ex.getClass() != expectedClazz) { + Assert.fail(expectedClazz + " was expected but got instead: " + ex); + } else { + Assert.fail("InteropException was expected but got insteat: " + ex); + } + } + assertTrue(ie); + } + +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/ActiveBindingMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/ActiveBindingMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2d750d368ec1afa3abf1d5ea5b9c3385fa43bb27 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/ActiveBindingMRTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.env.frame.ActiveBinding; + +public class ActiveBindingMRTest extends AbstractMRTest { + + @Override + protected boolean isBoxed(TruffleObject obj) { + return true; + } + + @Override + protected Object getUnboxed(TruffleObject obj) { + return ((ActiveBinding) obj).readValue(); + } + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + PolyglotEngine engine = PolyglotEngine.newBuilder().build(); + Source src = Source.newBuilder("f=function() {}").mimeType("text/x-r").name("test.R").build(); + PolyglotEngine.Value result = engine.eval(src); + RFunction fn = result.as(RFunction.class); + return new TruffleObject[]{new ActiveBinding(RType.Any, fn)}; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; + } +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/ListMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/ListMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9486402b6da24bc7fc821c33be2b9fc71edc3ffa --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/ListMRTest.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.ForeignAccess; +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.UnsupportedTypeException; +import com.oracle.truffle.api.interop.java.JavaInterop; + +import org.junit.Test; + +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.ffi.impl.interop.NativePointer; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RPairList; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class ListMRTest extends AbstractMRTest { + + private String testValues = "i=1L, d=2.1, b=TRUE, fn=function() {}, n=NULL, 4"; + private final PolyglotEngine engine; + + public ListMRTest() { + engine = PolyglotEngine.newBuilder().build(); + } + + @Test + public void testNativePointer() throws UnsupportedMessageException, UnknownIdentifierException, UnsupportedTypeException { + assertTrue(ForeignAccess.sendToNative(Message.TO_NATIVE.createNode(), create("list", testValues)) instanceof NativePointer); + assertTrue(ForeignAccess.sendToNative(Message.TO_NATIVE.createNode(), create("pairlist", testValues)) instanceof NativePointer); + } + + @Test + public void testKeysReadWrite() throws UnsupportedMessageException, UnknownIdentifierException, UnsupportedTypeException { + testKeysReadWrite("list"); + testKeysReadWrite("pairlist"); + } + + private void testKeysReadWrite(String createFun) throws UnsupportedMessageException, UnknownIdentifierException, UnsupportedTypeException { + + RAbstractContainer l = create(createFun, testValues); + + assertEquals(1, ForeignAccess.sendRead(Message.READ.createNode(), l, "i")); + assertEquals(2.1, ForeignAccess.sendRead(Message.READ.createNode(), l, "d")); + assertEquals(true, ForeignAccess.sendRead(Message.READ.createNode(), l, "b")); + assertTrue(ForeignAccess.sendRead(Message.READ.createNode(), l, "n") instanceof RNull); + + assertEquals(1, ForeignAccess.sendRead(Message.READ.createNode(), l, 0)); + assertEquals(2.1, ForeignAccess.sendRead(Message.READ.createNode(), l, 1)); + assertEquals(true, ForeignAccess.sendRead(Message.READ.createNode(), l, 2)); + assertTrue(ForeignAccess.sendRead(Message.READ.createNode(), l, 4) instanceof RNull); + + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), l, -1), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), l, 0f), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), l, 4d), UnknownIdentifierException.class); + + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), l, "nnnoooonnne"), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), l, 100), UnknownIdentifierException.class); + + TruffleObject obj = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), l, "d", 123.1); + assertEquals(123.1, ForeignAccess.sendRead(Message.READ.createNode(), obj, "d")); + + obj = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), l, 2, false); + RAbstractContainer returnedList = JavaInterop.asJavaObject(RAbstractContainer.class, obj); + assertEquals((byte) 0, returnedList.getDataAtAsObject(2)); + assertEquals(false, ForeignAccess.sendRead(Message.READ.createNode(), obj, "b")); + + obj = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), l, "newnew", "nneeww"); + assertEquals("nneeww", ForeignAccess.sendRead(Message.READ.createNode(), obj, "newnew")); + + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), l, 0f, false), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), l, 0d, false), UnknownIdentifierException.class); + } + + @Test + public void testKeysInfo() { + testKeysInfo("list"); + testKeysInfo("pairlist"); + } + + public void testKeysInfo(String createFun) { + + RAbstractContainer l = create(createFun, testValues); + + int info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, "nnoonnee"); + assertFalse(KeyInfo.isExisting(info)); + assertFalse(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, "d"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, "fn"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertTrue(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, -1); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, l.getLength()); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, 1f); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, 0); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, 1d); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + } + + private RAbstractContainer create(String createFun, String values) { + Source src = Source.newBuilder(createFun + "(" + values + ")").mimeType("text/x-r").name("test.R").build(); + PolyglotEngine.Value result = engine.eval(src); + return result.as(RAbstractContainer.class); + } + + @Override + protected String[] getKeys() { + return new String[]{"i", "d", "b", "fn", "n", ""}; + } + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + return new TruffleObject[]{create("list", testValues), create("pairlist", testValues)}; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + // cant have an emtpy pair list + return create("list", ""); + } + + @Override + protected boolean hasSize(TruffleObject arg0) { + return true; + } + + @Override + protected int getSize(TruffleObject obj) { + return obj instanceof RList ? ((RList) obj).getLength() : ((RPairList) obj).getLength(); + } + +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RArgsValuesAndNamesMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RArgsValuesAndNamesMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a7e3eb84811fe0017b4ef7af701aa29ecc300d4d --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RArgsValuesAndNamesMRTest.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.ForeignAccess; +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.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +public class RArgsValuesAndNamesMRTest extends AbstractMRTest { + + @Test + public void testReadWriteIdx() throws Exception { + TruffleObject args = createTruffleObjects()[0]; + + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), args, 1f), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), args, 1d), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), args, -1), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), args, 100), UnknownIdentifierException.class); + + assertEquals("abc", ForeignAccess.sendRead(Message.READ.createNode(), args, 0)); + assertEquals(123, ForeignAccess.sendRead(Message.READ.createNode(), args, 1)); + assertEquals(1.1, ForeignAccess.sendRead(Message.READ.createNode(), args, 2)); + assertEquals(true, ForeignAccess.sendRead(Message.READ.createNode(), args, 3)); + assertTrue(ForeignAccess.sendRead(Message.READ.createNode(), args, 4) instanceof RFunction); + assertTrue(ForeignAccess.sendRead(Message.READ.createNode(), args, 5) instanceof RNull); + + TruffleObject emptyargs = RArgsValuesAndNames.EMPTY; + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), emptyargs, 0), UnknownIdentifierException.class); + + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), args, 0, 321), UnsupportedMessageException.class); + } + + @Test + public void testReadWriteName() throws Exception { + TruffleObject args = createTruffleObjects()[0]; + + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), args, "nnnnooooonnnneee"), UnknownIdentifierException.class); + + assertEquals("abc", ForeignAccess.sendRead(Message.READ.createNode(), args, "s")); + assertEquals(123, ForeignAccess.sendRead(Message.READ.createNode(), args, "i")); + assertEquals(1.1, ForeignAccess.sendRead(Message.READ.createNode(), args, "d")); + assertEquals(true, ForeignAccess.sendRead(Message.READ.createNode(), args, "b")); + assertTrue(ForeignAccess.sendRead(Message.READ.createNode(), args, "fn") instanceof RFunction); + assertTrue(ForeignAccess.sendRead(Message.READ.createNode(), args, "n") instanceof RNull); + + TruffleObject emptyargs = RArgsValuesAndNames.EMPTY; + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), emptyargs, "s"), UnknownIdentifierException.class); + + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), args, "s", "aaa"), UnsupportedMessageException.class); + } + + @Test + public void testKeysInfo() throws Exception { + TruffleObject e = createTruffleObjects()[0]; + int info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "nnoonnee"); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, 1f); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, 0); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "s"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "b"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "fn"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertTrue(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "n"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + } + + private String[] names = {"s", "i", "d", "b", "fn", "n"}; + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + PolyglotEngine engine = PolyglotEngine.newBuilder().build(); + Source src = Source.newBuilder("f=function() {}").mimeType("text/x-r").name("test.R").build(); + PolyglotEngine.Value result = engine.eval(src); + RFunction fn = result.as(RFunction.class); + Object[] values = {"abc", 123, 1.1, RRuntime.asLogical(true), fn, RNull.instance}; + return new TruffleObject[]{new RArgsValuesAndNames(values, ArgumentsSignature.get(names))}; + } + + @Override + protected String[] getKeys() { + return names; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return RArgsValuesAndNames.EMPTY; + } + + @Override + protected boolean hasSize(TruffleObject obj) { + return true; + } + + @Override + protected int getSize(TruffleObject obj) { + return ((RArgsValuesAndNames) obj).getLength(); + } + +} diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/Utils.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RDoubleMRTest.java similarity index 50% rename from com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/Utils.java rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RDoubleMRTest.java index 6d044539546c64e6d2b97ca0d994e6c2db852bc1..887f384fbb2b4b1c578934ca3717de357a6bf08f 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/Utils.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RDoubleMRTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -20,26 +20,30 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.r.engine.interop; +package com.oracle.truffle.r.test.engine.interop; -import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.r.runtime.data.RDouble; -class Utils { - static Object javaToRPrimitive(Object valueObj) { - Object value = valueObj; - if (value instanceof Short) { - value = (int) ((Short) value).shortValue(); - } else if (value instanceof Float) { - float floatValue = ((Float) value).floatValue(); - value = new Double(floatValue); - } else if (value instanceof Boolean) { - boolean booleanValue = ((Boolean) value).booleanValue(); - value = booleanValue ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; - } else if (value instanceof Character) { - value = (int) ((Character) value).charValue(); - } else if (value instanceof Byte) { - value = (int) ((Byte) value).byteValue(); - } - return value; +public class RDoubleMRTest extends AbstractMRTest { + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + return new TruffleObject[]{RDouble.valueOf(1.1)}; + } + + @Override + protected boolean isBoxed(TruffleObject obj) { + return true; + } + + @Override + protected Object getUnboxed(TruffleObject obj) { + return ((RDouble) obj).getValue(); + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/REmptyMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/REmptyMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1ec6184661511c474fd2d3944a65e3e2254971c3 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/REmptyMRTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.r.runtime.data.REmpty; + +public class REmptyMRTest extends AbstractMRTest { + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + return new TruffleObject[]{REmpty.instance}; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; + } +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/REnvironmentMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/REnvironmentMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..33ff1c3fea8760a3e3a6ff1ae0e6ded6f60e33e2 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/REnvironmentMRTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.ForeignAccess; +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 org.junit.Test; + +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.env.REnvironment; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class REnvironmentMRTest extends AbstractMRTest { + + @Test + public void testReadWrite() throws Exception { + REnvironment e = (REnvironment) createTruffleObjects()[0]; + + assertEquals("aaa", ForeignAccess.sendRead(Message.READ.createNode(), e, "s")); + assertEquals(123, ForeignAccess.sendRead(Message.READ.createNode(), e, "i")); + assertEquals(123.1, ForeignAccess.sendRead(Message.READ.createNode(), e, "d")); + assertEquals(true, ForeignAccess.sendRead(Message.READ.createNode(), e, "b")); + + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), e, "nnnoooonnne"), UnknownIdentifierException.class); + + TruffleObject obj = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), e, "s", "abc"); + Object value = ForeignAccess.sendRead(Message.READ.createNode(), obj, "s"); + assertEquals("abc", value); + + obj = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), e, "b", false); + REnvironment env = JavaInterop.asJavaObject(REnvironment.class, obj); + assertEquals((byte) 0, env.get("b")); + value = ForeignAccess.sendRead(Message.READ.createNode(), obj, "b"); + assertEquals(false, value); + + obj = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), e, "i", (short) 1234); + value = ForeignAccess.sendRead(Message.READ.createNode(), obj, "i"); + assertTrue(value instanceof Integer); + assertEquals(1234, value); + + obj = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), e, "newnew", "nneeww"); + value = ForeignAccess.sendRead(Message.READ.createNode(), obj, "newnew"); + assertEquals("nneeww", value); + + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), e, "l", 667), UnsupportedMessageException.class); + + e.lock(true); + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), e, "newnew2", "nneeww"), UnsupportedMessageException.class); + e.lock(false); + + // can't read/write via index + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), e, 0), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), e, 1f), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), e, 1, 321), UnknownIdentifierException.class); + } + + @Test + public void testKeysInfo() throws Exception { + TruffleObject e = createTruffleObjects()[0]; + int info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "nnoonnee"); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, 0); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, 1f); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "s"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "b"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "fn"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertTrue(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "n"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), e, "l"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + } + + protected TruffleObject[] createTruffleObjects() throws Exception { + PolyglotEngine engine = PolyglotEngine.newBuilder().build(); + Source src = Source.newBuilder("e <- new.env(); e$s <- 'aaa'; e$i <- 123L; e$d <- 123.1; e$b <- TRUE; e$fn <- function() {}; e$n <- NULL; e$l <- 666; lockBinding('l', e); e").mimeType( + "text/x-r").name("test.R").build(); + return new TruffleObject[]{engine.eval(src).as(REnvironment.class)}; + } + + @Override + protected String[] getKeys() { + return new String[]{"s", "i", "d", "b", "fn", "n", "l"}; + } + + protected TruffleObject createEmptyTruffleObject() throws Exception { + PolyglotEngine engine = PolyglotEngine.newBuilder().build(); + Source src = Source.newBuilder("new.env()").mimeType("text/x-r").name("test.R").build(); + return engine.eval(src).as(REnvironment.class); + } + +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RFunctionMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RFunctionMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..03c5a908b7d16155168ccb025558a4f9e0e7eaa0 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RFunctionMRTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 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.engine.interop; + +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.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.data.RFunction; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +public class RFunctionMRTest extends AbstractMRTest { + + @Test + public void testExecute() throws UnsupportedTypeException, ArityException, UnsupportedMessageException { + RFunction f = create("function() {}"); + assertTrue(ForeignAccess.sendIsExecutable(Message.IS_EXECUTABLE.createNode(), f)); + + TruffleObject result = (TruffleObject) ForeignAccess.sendExecute(Message.createExecute(0).createNode(), f); + assertTrue(ForeignAccess.sendIsNull(Message.IS_NULL.createNode(), result)); + + f = create("function() {1L}"); + assertEquals(1, ForeignAccess.sendExecute(Message.createExecute(0).createNode(), f)); + + f = create("function() {1}"); + assertEquals(1.0, ForeignAccess.sendExecute(Message.createExecute(0).createNode(), f)); + + f = create("function() {TRUE}"); + assertEquals(true, ForeignAccess.sendExecute(Message.createExecute(0).createNode(), f)); + + f = create("function(a) {a}"); + assertEquals("abc", ForeignAccess.sendExecute(Message.createExecute(1).createNode(), f, "abc")); + + f = create("function(a) { is.logical(a) }"); + assertEquals(true, ForeignAccess.sendExecute(Message.createExecute(1).createNode(), f, true)); + + f = create("function(a) { as.external.short(a) }"); + assertTrue(ForeignAccess.sendExecute(Message.createExecute(1).createNode(), f, 123) instanceof Short); + + } + + @Override + protected TruffleObject[] createTruffleObjects() { + return new TruffleObject[]{create("function() {}")}; + } + + private RFunction create(String fun) { + PolyglotEngine engine = PolyglotEngine.newBuilder().build(); + Source src = Source.newBuilder(fun).mimeType("text/x-r").name("test.R").build(); + PolyglotEngine.Value result = engine.eval(src); + return result.as(RFunction.class); + } + + @Override + protected boolean isExecutable(TruffleObject obj) { + return true; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; + } +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RIntegerMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RIntegerMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b44b1e1505ac661845551f16366558ff23957003 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RIntegerMRTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.r.runtime.data.RInteger; + +public class RIntegerMRTest extends AbstractMRTest { + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + return new TruffleObject[]{RInteger.valueOf(123)}; + } + + @Override + protected boolean isBoxed(TruffleObject obj) { + return true; + } + + @Override + protected Object getUnboxed(TruffleObject obj) { + return ((RInteger) obj).getValue(); + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; + } +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RInteropScalarMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RInteropScalarMRTest.java index eba1e8a9b35af3772e1c0b914a182eeb7b10f7ee..fbbcd375cc9765f0ccca69862527eacc5a4cc9d0 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RInteropScalarMRTest.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RInteropScalarMRTest.java @@ -31,36 +31,55 @@ import org.junit.Test; 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.source.Source; -import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.data.RInteropScalar; +import org.junit.Assert; -public class RInteropScalarMRTest { +public class RInteropScalarMRTest extends AbstractMRTest { @Test - public void testRInteroptScalar() throws UnsupportedMessageException { - testRIS("toByte", "" + Byte.MAX_VALUE, Byte.class); - testRIS("toChar", "'a'", Character.class); - testRIS("toFloat", "" + Float.MAX_VALUE, Float.class); - testRIS("toLong", "" + Long.MAX_VALUE, Long.class); - testRIS("toShort", "" + Short.MAX_VALUE, Short.class); + public void testRInteroptScalar() throws Exception { + for (TruffleObject obj : createTruffleObjects()) { + RInteropScalar is = (RInteropScalar) obj; + testRIS(obj, is.getJavaType()); + } } - private static void testRIS(String toInteropScalarBuiltin, String value, Class<?> unboxedType) throws UnsupportedMessageException { - TruffleObject l = createRInteroptScalarTO(toInteropScalarBuiltin, value); + private static void testRIS(TruffleObject obj, Class<?> unboxedType) throws Exception { + assertFalse(ForeignAccess.sendIsNull(Message.IS_NULL.createNode(), obj)); + assertFalse(ForeignAccess.sendHasSize(Message.HAS_SIZE.createNode(), obj)); - assertFalse(ForeignAccess.sendIsNull(Message.IS_NULL.createNode(), l)); - assertFalse(ForeignAccess.sendHasSize(Message.HAS_SIZE.createNode(), l)); + assertTrue(ForeignAccess.sendIsBoxed(Message.IS_BOXED.createNode(), obj)); + Object ub = ForeignAccess.sendUnbox(Message.UNBOX.createNode(), obj); + assertEquals(unboxedType, ub.getClass().getField("TYPE").get(null)); + } + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + return new TruffleObject[]{RInteropScalar.RInteropByte.valueOf(Byte.MAX_VALUE), + RInteropScalar.RInteropChar.valueOf('a'), + RInteropScalar.RInteropFloat.valueOf(Float.MAX_VALUE), + RInteropScalar.RInteropLong.valueOf(Long.MAX_VALUE), + RInteropScalar.RInteropShort.valueOf(Short.MAX_VALUE)}; + } + + @Override + protected boolean isBoxed(TruffleObject arg0) { + return true; + } - assertTrue(ForeignAccess.sendIsBoxed(Message.IS_BOXED.createNode(), l)); - Object ub = ForeignAccess.sendUnbox(Message.UNBOX.createNode(), l); - assertEquals(unboxedType, ub.getClass()); + @Override + protected Object getUnboxed(TruffleObject obj) { + RInteropScalar is = (RInteropScalar) obj; + try { + return is.getClass().getDeclaredMethod("getValue").invoke(is); + } catch (Exception ex) { + Assert.fail("can't read interop scalar value " + ex); + } + return null; } - private static TruffleObject createRInteroptScalarTO(String toInteropScalarBuiltin, String value) { - PolyglotEngine engine = PolyglotEngine.newBuilder().build(); - Source src = Source.newBuilder(".fastr.interop." + toInteropScalarBuiltin + "(" + value + ")").mimeType("text/x-r").name("test.R").build(); - PolyglotEngine.Value result = engine.eval(src); - return result.as(TruffleObject.class); + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RLanguageMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RLanguageMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..66a7eac2592032c1d8a85dc93d0ea12f381ec54f --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RLanguageMRTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.ForeignAccess; +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.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.data.RLanguage; +import org.junit.Assert; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +public class RLanguageMRTest extends AbstractMRTest { + + @Test + public void testKeysInfo() throws Exception { + RLanguage rl = (RLanguage) createTruffleObjects()[0]; + int info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), rl, "nnoonnee"); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), rl, 1f); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), rl, rl.getLength()); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), rl, 0); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), rl, 1); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), rl, 2); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + } + + @Test + public void testReadWrite() throws Exception { + RLanguage rl = (RLanguage) createTruffleObjects()[0]; + + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), rl, "nnnoooonnne"), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), rl, rl.getLength()), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), rl, 0d), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), rl, 0f), UnknownIdentifierException.class); + + // TODO add some meaningfull read tests + Assert.assertNotNull(ForeignAccess.sendRead(Message.READ.createNode(), rl, 0)); + + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), rl, "aaa", "abc"), UnsupportedMessageException.class); + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), rl, 0, "abc"), UnsupportedMessageException.class); + + } + + @Override + protected TruffleObject[] createTruffleObjects() { + PolyglotEngine engine = PolyglotEngine.newBuilder().build(); + // TODO any simpler way to create a RLanguage ? + String srcTxt = "ne <- new.env(); delayedAssign('x', 1 + 2, assign.env = ne); substitute(x, ne)"; + Source src = Source.newBuilder(srcTxt).mimeType("text/x-r").name("test.R").build(); + PolyglotEngine.Value result = engine.eval(src); + return new TruffleObject[]{result.as(RLanguage.class)}; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; + } + + @Override + protected boolean hasSize(TruffleObject obj) { + return true; + } + + @Override + protected int getSize(TruffleObject obj) { + return ((RLanguage) obj).getLength(); + } + +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RListMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RListMRTest.java deleted file mode 100644 index f083bd862435f28e05e067ce9ff667382bef0025..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RListMRTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 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.engine.interop; - -import com.oracle.truffle.api.interop.ForeignAccess; -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.UnsupportedTypeException; - -import org.junit.Test; - -import com.oracle.truffle.api.source.Source; -import com.oracle.truffle.api.vm.PolyglotEngine; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class RListMRTest { - - @Test - public void testKeysReadWrite() throws UnsupportedMessageException, UnknownIdentifierException, UnsupportedTypeException { - TruffleObject l = createRListTruffleObject("n1=1L, n2=2L, 3, 4"); - - TruffleObject keys = ForeignAccess.sendKeys(Message.KEYS.createNode(), l); - assertEquals("n1", ForeignAccess.sendRead(Message.READ.createNode(), keys, 0)); - assertEquals("n2", ForeignAccess.sendRead(Message.READ.createNode(), keys, 1)); - assertEquals("", ForeignAccess.sendRead(Message.READ.createNode(), keys, 2)); - assertEquals("", ForeignAccess.sendRead(Message.READ.createNode(), keys, 3)); - - assertEquals(4, ForeignAccess.sendGetSize(Message.GET_SIZE.createNode(), keys)); - assertEquals(1, ForeignAccess.sendRead(Message.READ.createNode(), l, "n1")); - assertEquals(2, ForeignAccess.sendRead(Message.READ.createNode(), l, "n2")); - - // TODO fails - should this return NULL as in l[""] or 3 as in l$"" - // ElementAccessMode.FIELD_SUBSCRIPT vs .SUBSCRIPT doesn't seem to have any effect - // assertEquals(3, ForeignAccess.sendRead(Message.READ.createNode(), l, "")); - - // TODO - more tests for NA, ... ? - - l = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), l, "n2", 123); - assertEquals(123, ForeignAccess.sendRead(Message.READ.createNode(), l, "n2")); - } - - @Test - public void testKeysInfo() { - TruffleObject l = createRListTruffleObject("n1=1, n2=2"); - int info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, "nnoonnee"); - assertFalse(KeyInfo.isExisting(info)); - assertFalse(KeyInfo.isReadable(info)); - assertFalse(KeyInfo.isWritable(info)); - assertFalse(KeyInfo.isInvocable(info)); - assertFalse(KeyInfo.isInternal(info)); - - info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, "n2"); - assertTrue(KeyInfo.isExisting(info)); - assertTrue(KeyInfo.isReadable(info)); - assertTrue(KeyInfo.isWritable(info)); - assertFalse(KeyInfo.isInvocable(info)); - assertFalse(KeyInfo.isInternal(info)); - - l = createRListTruffleObject("f=function() {}"); - info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), l, "f"); - assertTrue(KeyInfo.isExisting(info)); - assertTrue(KeyInfo.isReadable(info)); - assertTrue(KeyInfo.isWritable(info)); - assertTrue(KeyInfo.isInvocable(info)); - assertFalse(KeyInfo.isInternal(info)); - } - - private static TruffleObject createRListTruffleObject(String values) { - PolyglotEngine engine = PolyglotEngine.newBuilder().build(); - Source src = Source.newBuilder("list(" + values + ")").mimeType("text/x-r").name("test.R").build(); - PolyglotEngine.Value result = engine.eval(src); - return result.as(TruffleObject.class); - } -} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RMissingMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RMissingMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c0a39b78a89784dc48f690c0547d928f831a693f --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RMissingMRTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.r.runtime.data.RMissing; + +public class RMissingMRTest extends AbstractMRTest { + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + return new TruffleObject[]{RMissing.instance}; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; + } +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RNullMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RNullMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c9c943090466aa6330051dcad113c8b61c947d45 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RNullMRTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.TruffleObject; + +import com.oracle.truffle.r.runtime.data.RNull; + +public class RNullMRTest extends AbstractMRTest { + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + return new TruffleObject[]{RNull.instance}; + } + + @Override + protected boolean isNull(TruffleObject obj) { + return true; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; + } +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RS4ObjectMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RS4ObjectMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..233ec91a21f9c078cbf2c6bab016204bff283c1e --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RS4ObjectMRTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.ForeignAccess; +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.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.data.RS4Object; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +public class RS4ObjectMRTest extends AbstractMRTest { + + public RS4ObjectMRTest() { + } + + @Test + public void testKeysInfo() throws Exception { + TruffleObject s4 = createTruffleObjects()[0]; + int info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), s4, "nnoonnee"); + assertFalse(KeyInfo.isExisting(info)); + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), s4, 0); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), s4, 1f); + assertFalse(KeyInfo.isExisting(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), s4, "s"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), s4, "b"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), s4, "fn"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertTrue(KeyInfo.isWritable(info)); + assertTrue(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + + info = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), s4, "class"); + assertTrue(KeyInfo.isExisting(info)); + assertTrue(KeyInfo.isReadable(info)); + assertFalse(KeyInfo.isWritable(info)); + assertFalse(KeyInfo.isInvocable(info)); + assertFalse(KeyInfo.isInternal(info)); + } + + @Test + public void testReadWrite() throws Exception { + TruffleObject s4 = createTruffleObjects()[0]; + + assertEquals("aaa", ForeignAccess.sendRead(Message.READ.createNode(), s4, "s")); + assertEquals(123, ForeignAccess.sendRead(Message.READ.createNode(), s4, "i")); + assertEquals(1.1, ForeignAccess.sendRead(Message.READ.createNode(), s4, "d")); + assertEquals(true, ForeignAccess.sendRead(Message.READ.createNode(), s4, "b")); + + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), s4, "nnnoooonnne"), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), s4, 0), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), s4, 1d), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), s4, 1f), UnknownIdentifierException.class); + + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), s4, "class", "cantchangeclass"), UnsupportedMessageException.class); + // TODO this should fail !!! + // assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), s4, "i", + // "cant write string into int slot"), UnsupportedMessageException.class); + + ForeignAccess.sendWrite(Message.WRITE.createNode(), s4, "s", "abc"); + Object value = ForeignAccess.sendRead(Message.READ.createNode(), s4, "s"); + assertEquals("abc", value); + + ForeignAccess.sendWrite(Message.WRITE.createNode(), s4, "b", false); + value = ForeignAccess.sendRead(Message.READ.createNode(), s4, "b"); + assertEquals(false, value); + + ForeignAccess.sendWrite(Message.WRITE.createNode(), s4, "i", (short) 1234); + value = ForeignAccess.sendRead(Message.READ.createNode(), s4, "i"); + assertTrue(value instanceof Integer); + assertEquals(1234, value); + + } + + @Override + protected TruffleObject[] createTruffleObjects() { + PolyglotEngine engine = PolyglotEngine.newBuilder().build(); + String srcTxt = "setClass('test', representation(s = 'character', d = 'numeric', i = 'integer', b = 'logical', fn = 'function'));" + + "new('test', s = 'aaa', d = 1.1, i=123L, b = TRUE, fn = function() {})"; + Source src = Source.newBuilder(srcTxt).mimeType("text/x-r").name("test.R").build(); + PolyglotEngine.Value result = engine.eval(src); + RS4Object s4 = result.as(RS4Object.class); + return new TruffleObject[]{s4}; + } + + @Override + protected String[] getKeys() { + return new String[]{"s", "d", "i", "b", "fn", "class"}; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; + } +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RUboundValueMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RUboundValueMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..baa61ec385903879fc2583e334d6a9e19c63eeeb --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/RUboundValueMRTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.r.runtime.data.RUnboundValue; + +public class RUboundValueMRTest extends AbstractMRTest { + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + return new TruffleObject[]{RUnboundValue.instance}; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return null; + } + +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/VectorMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/VectorMRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8547a34982335c092fbf7751da6a2775e20bde57 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/VectorMRTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 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.engine.interop; + +import com.oracle.truffle.api.interop.ForeignAccess; +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 org.junit.Test; + +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class VectorMRTest extends AbstractMRTest { + + private final PolyglotEngine engine; + + public VectorMRTest() { + engine = PolyglotEngine.newBuilder().build(); + } + + @Test + public void testReadWrite() throws Exception { + final TruffleObject vi = create("1L:10L"); + assertEquals(3, ForeignAccess.sendRead(Message.READ.createNode(), vi, 2)); + assertEquals(3, ForeignAccess.sendRead(Message.READ.createNode(), vi, 2L)); + + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), vi, "a"), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), vi, 100), UnknownIdentifierException.class); + assertInteropException(() -> ForeignAccess.sendWrite(Message.WRITE.createNode(), vi, "s", "abc"), UnknownIdentifierException.class); + + TruffleObject vd = create("1.1:10.1"); + assertEquals(1.1, ForeignAccess.sendRead(Message.READ.createNode(), vd, 0)); + + TruffleObject vb = create("c(TRUE, FALSE, TRUE)"); + assertEquals(true, ForeignAccess.sendRead(Message.READ.createNode(), vb, 0)); + + TruffleObject nvi = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), vi, 0, 123); + RAbstractIntVector returnedVec = JavaInterop.asJavaObject(RAbstractIntVector.class, nvi); + assertEquals(123, returnedVec.getDataAt(0)); + assertEquals(123, ForeignAccess.sendRead(Message.READ.createNode(), nvi, 0)); + + assertEquals(10, ForeignAccess.sendGetSize(Message.GET_SIZE.createNode(), nvi)); + nvi = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), nvi, 100, 321); + assertEquals(101, ForeignAccess.sendGetSize(Message.GET_SIZE.createNode(), nvi)); + assertEquals(321, ForeignAccess.sendRead(Message.READ.createNode(), nvi, 100)); + + nvi = (TruffleObject) ForeignAccess.sendWrite(Message.WRITE.createNode(), nvi, 0, "abc"); + RAbstractVector vec = JavaInterop.asJavaObject(RAbstractVector.class, nvi); + assertTrue(vec instanceof RAbstractStringVector); + assertEquals("abc", ForeignAccess.sendRead(Message.READ.createNode(), nvi, 0)); + + } + + @Test + public void testKeyInfo() throws Exception { + TruffleObject v = create("c(TRUE, FALSE, TRUE)"); + assertInteropException(() -> ForeignAccess.sendKeys(Message.KEYS.createNode(), v), UnsupportedMessageException.class); + + int keyInfo = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), v, 0); + assertTrue(KeyInfo.isExisting(keyInfo)); + assertTrue(KeyInfo.isReadable(keyInfo)); + assertTrue(KeyInfo.isWritable(keyInfo)); + assertFalse(KeyInfo.isInvocable(keyInfo)); + assertFalse(KeyInfo.isInternal(keyInfo)); + + keyInfo = ForeignAccess.sendKeyInfo(Message.KEY_INFO.createNode(), v, 100); + assertFalse(KeyInfo.isExisting(keyInfo)); + } + + @Override + protected TruffleObject[] createTruffleObjects() throws Exception { + return new TruffleObject[]{create("1:10"), create("as.numeric()")}; + } + + @Override + protected TruffleObject createEmptyTruffleObject() throws Exception { + return create("as.numeric()"); + } + + @Override + protected boolean isBoxed(TruffleObject obj) { + return ((RAbstractVector) obj).getLength() == 1; + } + + @Override + protected boolean hasSize(TruffleObject obj) { + return true; + } + + @Override + protected int getSize(TruffleObject obj) { + return ((RAbstractVector) obj).getLength(); + } + + private TruffleObject create(String createTxt) throws Exception { + Source src = Source.newBuilder(createTxt).mimeType("text/x-r").name("test.R").build(); + return engine.eval(src).as(RAbstractVector.class); + } + +} diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py index 6634237a98c549da9b3dc3ef7509bf14d2f51092..ef0a29387f7aa8f5dfc73e2d1bc0757c50587c15 100644 --- a/mx.fastr/mx_fastr.py +++ b/mx.fastr/mx_fastr.py @@ -313,7 +313,7 @@ def _test_subpackage(name): return '.'.join((_test_package(), name)) def _simple_generated_unit_tests(): - return map(_test_subpackage, ['engine.shell', 'library.base', 'library.grid', 'library.fastrGrid', 'library.methods', 'library.stats', 'library.utils', 'library.fastr', 'builtins', 'functions', 'parser', 'rffi', 'rng', 'runtime.data', 'S4']) + return map(_test_subpackage, ['engine.shell', 'engine.interop', 'library.base', 'library.grid', 'library.fastrGrid', 'library.methods', 'library.stats', 'library.utils', 'library.fastr', 'builtins', 'functions', 'parser', 'rffi', 'rng', 'runtime.data', 'S4']) def _simple_unit_tests(): return _simple_generated_unit_tests() + [_test_subpackage('tck')]