diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java index 7e0bd5d9b1e11a0454d723c67e43b2dc9cb1b1ef..00481e026856f6cc6b9301012ba2cae90fe29538 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java @@ -264,7 +264,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { @Override public Object ATTRIB(Object obj) { if (obj instanceof RAttributable) { - return ((RAttributable) obj).getAttributes(); + return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.ATTRIB).call(obj); } return RNull.instance; } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ATTRIB.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ATTRIB.java new file mode 100644 index 0000000000000000000000000000000000000000..07d6a98681272787228e27e46d13c0f2a60d901f --- /dev/null +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ATTRIB.java @@ -0,0 +1,53 @@ +/* + * 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.ffi.impl.nodes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.attributes.GetAttributesNode; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RNull; + +public abstract class ATTRIB extends FFIUpCallNode.Arg1 { + @Child private GetAttributesNode getAttributesNode = GetAttributesNode.create(); + + @Specialization + public Object doAttributable(RAttributable obj) { + return getAttributesNode.execute(obj); + } + + @Fallback + public RNull doOthers(Object obj) { + if (obj == RNull.instance || RRuntime.isForeignObject(obj)) { + return RNull.instance; + } else { + CompilerDirectives.transferToInterpreter(); + String type = obj == null ? "null" : obj.getClass().getSimpleName(); + throw RError.error(RError.NO_CALLER, Message.GENERIC, "object of type '" + type + "' cannot be attributed"); + } + } +} diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java index fe43cc4cc16ba62f81ab84404cc1e2d7d14efeb6..a3bd560c96916a5e325b4b4ed02a458e5c6e9eb0 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/FFIUpCallRootNode.java @@ -90,6 +90,7 @@ public final class FFIUpCallRootNode extends RootNode { } public static void register() { + FFIUpCallRootNode.add(RFFIUpCallTable.ATTRIB, ATTRIBNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asReal, AsRealNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asLogical, AsLogicalNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asInteger, AsIntegerNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java index 42325e9757f5c0822e37f34d38c0c357e9efbdaa..3e2489c23cab0c3661c4ab8e883a8dc5628b0f47 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java @@ -35,6 +35,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.attributes.GetAttributeNode; +import com.oracle.truffle.r.nodes.attributes.GetAttributesNode; import com.oracle.truffle.r.nodes.attributes.IterableAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetRowNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; @@ -47,11 +48,9 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RAttributesLayout; -import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; @RBuiltin(name = "attr", kind = PRIMITIVE, parameterNames = {"x", "which", "exact"}, behavior = PURE) public abstract class Attr extends RBuiltinNode.Arg3 { @@ -124,7 +123,7 @@ public abstract class Attr extends RBuiltinNode.Arg3 { if (attributes == null) { return RNull.instance; } else { - return getFullRowNames(getRowNamesNode.getRowNames(container)); + return GetAttributesNode.getFullRowNames(getRowNamesNode.getRowNames(container)); } } @@ -143,20 +142,6 @@ public abstract class Attr extends RBuiltinNode.Arg3 { } } - public static Object getFullRowNames(Object a) { - if (a == RNull.instance) { - return RNull.instance; - } else { - if (a instanceof RAbstractIntVector) { - RAbstractIntVector rowNames = (RAbstractIntVector) a; - if (rowNames.getLength() == 2 && RRuntime.isNA(rowNames.getDataAt(0))) { - return RDataFactory.createIntSequence(1, 1, Math.abs(rowNames.getDataAt(1))); - } - } - return a; - } - } - protected static boolean isRowNamesAttr(String name) { return name.equals(RRuntime.ROWNAMES_ATTR_KEY); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java index 5f3aee4e78d586e8754665ea9e0e3f6a480975a3..668410e59d03995caaafbb39e9b82a80fccc571f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attributes.java @@ -25,109 +25,44 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; -import java.util.Arrays; - import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.object.DynamicObject; -import com.oracle.truffle.api.profiles.BranchProfile; -import com.oracle.truffle.api.profiles.ConditionProfile; -import com.oracle.truffle.r.nodes.attributes.ArrayAttributeNode; -import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode; +import com.oracle.truffle.r.nodes.attributes.GetAttributesNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RAttributable; -import com.oracle.truffle.r.runtime.data.RAttributesLayout; -import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RLanguage; -import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -import com.oracle.truffle.r.runtime.env.REnvironment; @RBuiltin(name = "attributes", kind = PRIMITIVE, parameterNames = {"obj"}, behavior = PURE) public abstract class Attributes extends RBuiltinNode.Arg1 { - private final BranchProfile rownamesBranch = BranchProfile.create(); - @Child private ArrayAttributeNode arrayAttrAccess = ArrayAttributeNode.create(); - @Child private SetNamesAttributeNode setNamesNode = SetNamesAttributeNode.create(); + @Child private GetAttributesNode getAttributesNode = GetAttributesNode.create(); static { Casts.noCasts(Attributes.class); } @Specialization - protected Object attributesNull(RAbstractContainer container, - @Cached("createBinaryProfile()") ConditionProfile hasAttributesProfile) { - if (hasAttributesProfile.profile(hasAttributes(container))) { - return createResult(container, container instanceof RLanguage); - } else { - return RNull.instance; - } + protected Object attributesNull(RAbstractContainer container) { + return getAttributesNode.execute(container); } /** - * Unusual cases that it is not worth specializing on as they are not performance-centric, - * basically any type that is not an {@link RAbstractContainer} but is {@link RAttributable}, - * e.g. {@link REnvironment}. + * Unusual cases that it is not worth specializing on as they are not performance-centric. */ @Fallback @TruffleBoundary protected Object attributes(Object object) { if (object instanceof RAttributable) { - if (!hasAttributes((RAttributable) object)) { - return RNull.instance; - } else { - return createResult((RAttributable) object, false); - } + return getAttributesNode.execute((RAttributable) object); } else if (object == RNull.instance || RRuntime.isForeignObject(object)) { return RNull.instance; } else { throw RError.nyi(this, "object cannot be attributed"); } } - - /** - * {@code language} objects behave differently regarding "names"; they don't get included. - */ - private Object createResult(RAttributable attributable, boolean ignoreNames) { - DynamicObject attributes = attributable.getAttributes(); - int size = attributes.size(); - String[] names = new String[size]; - Object[] values = new Object[size]; - int z = 0; - for (RAttributesLayout.RAttribute attr : arrayAttrAccess.execute(attributes)) { - String name = attr.getName(); - if (ignoreNames && name.equals(RRuntime.NAMES_ATTR_KEY)) { - continue; - } - names[z] = name; - if (name.equals(RRuntime.ROWNAMES_ATTR_KEY)) { - rownamesBranch.enter(); - values[z] = Attr.getFullRowNames(attr.getValue()); - } else { - values[z] = attr.getValue(); - } - z++; - } - if (ignoreNames && z != names.length) { - if (z == 0) { - return RNull.instance; - } else { - names = Arrays.copyOfRange(names, 0, names.length - 1); - values = Arrays.copyOfRange(values, 0, values.length - 1); - } - } - RList result = RDataFactory.createList(values); - setNamesNode.setNames(result, RDataFactory.createStringVector(names, true)); - return result; - } - - private static boolean hasAttributes(RAttributable attributable) { - return attributable.getAttributes() != null && !attributable.getAttributes().isEmpty(); - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributesNode.java new file mode 100644 index 0000000000000000000000000000000000000000..1b2ff7d4ac84c82df65563975ed47c450165da2a --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/GetAttributesNode.java @@ -0,0 +1,141 @@ +/* + * 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.nodes.attributes; + +import java.util.Arrays; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.api.profiles.BranchProfile; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RAttributesLayout; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RLanguage; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; + +/** + * Transforms the attributes from {@link DynamicObject} into {@link RList}. + */ +public abstract class GetAttributesNode extends RBaseNode { + + private final BranchProfile rownamesBranch = BranchProfile.create(); + @Child private ArrayAttributeNode arrayAttrAccess = ArrayAttributeNode.create(); + @Child private SetNamesAttributeNode setNamesNode = SetNamesAttributeNode.create(); + + public static GetAttributesNode create() { + return GetAttributesNodeGen.create(); + } + + public abstract Object execute(RAttributable attributable); + + @Specialization + protected Object attributesNull(RAbstractContainer container, + @Cached("createBinaryProfile()") ConditionProfile hasAttributesProfile) { + if (hasAttributesProfile.profile(hasAttributes(container))) { + return createResult(container, container instanceof RLanguage); + } else { + return RNull.instance; + } + } + + /** + * Unusual cases that it is not worth specializing on as they are not performance-centric, + * basically any type that is not an {@link RAbstractContainer} but is {@link RAttributable}, + * e.g. {@link REnvironment}. + */ + @Fallback + @TruffleBoundary + protected Object attributes(RAttributable object) { + if (hasAttributes(object)) { + return createResult(object, false); + } else { + return RNull.instance; + } + } + + public static Object getFullRowNames(Object a) { + if (a == RNull.instance) { + return RNull.instance; + } else { + if (a instanceof RAbstractIntVector) { + RAbstractIntVector rowNames = (RAbstractIntVector) a; + if (rowNames.getLength() == 2 && RRuntime.isNA(rowNames.getDataAt(0))) { + return RDataFactory.createIntSequence(1, 1, Math.abs(rowNames.getDataAt(1))); + } + } + return a; + } + } + + /** + * {@code language} objects behave differently regarding "names"; they don't get included. + */ + private Object createResult(RAttributable attributable, boolean ignoreNames) { + DynamicObject attributes = attributable.getAttributes(); + int size = attributes.size(); + String[] names = new String[size]; + Object[] values = new Object[size]; + int z = 0; + for (RAttributesLayout.RAttribute attr : arrayAttrAccess.execute(attributes)) { + String name = attr.getName(); + if (ignoreNames && name.equals(RRuntime.NAMES_ATTR_KEY)) { + continue; + } + names[z] = name; + if (name.equals(RRuntime.ROWNAMES_ATTR_KEY)) { + rownamesBranch.enter(); + values[z] = getFullRowNames(attr.getValue()); + } else { + values[z] = attr.getValue(); + } + z++; + } + if (ignoreNames && z != names.length) { + if (z == 0) { + return RNull.instance; + } else { + names = Arrays.copyOfRange(names, 0, names.length - 1); + values = Arrays.copyOfRange(values, 0, values.length - 1); + } + } + RList result = RDataFactory.createList(values); + setNamesNode.setNames(result, RDataFactory.createStringVector(names, true)); + return result; + } + + private static boolean hasAttributes(RAttributable attributable) { + return attributable.getAttributes() != null && !attributable.getAttributes().isEmpty(); + } +}