diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java index f20257ce3144f3e3fbd1d52c0d878da62d8dc4fb..a439a0b7db36dcd248ecc5f690dbac5da2861088 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java @@ -455,7 +455,8 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { } else if (call == RError.SHOW_CALLER2) { Frame frame = Utils.getActualCurrentFrame(); if (frame != null && RArguments.isRFrame(frame)) { - frame = Utils.getCallerFrame(frame, FrameAccess.READ_ONLY); + RCaller parent = RArguments.getCall(frame); + frame = Utils.getCallerFrame(parent, FrameAccess.READ_ONLY); } return findCallerFromFrame(frame); } else { 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 ed489a3e28ac1dd64e86b4f372b20fe4b19a3c66..f004349cc8abf9fbaeb4f8a6c510b8b3f742de6d 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 @@ -68,7 +68,6 @@ import com.oracle.truffle.r.runtime.conn.NativeConnections.NativeRConnection; import com.oracle.truffle.r.runtime.conn.RConnection; import com.oracle.truffle.r.runtime.context.Engine.ParseException; import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RAttributesLayout; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -110,7 +109,6 @@ import com.oracle.truffle.r.runtime.ffi.CharSXPWrapper; import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; import com.oracle.truffle.r.runtime.gnur.SA_TYPE; import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; -import com.oracle.truffle.r.runtime.nmath.distr.Unif; import com.oracle.truffle.r.runtime.nodes.DuplicationHelper; import com.oracle.truffle.r.runtime.nodes.RNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; @@ -684,19 +682,7 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { @Override public Object TAG(Object e) { - if (e instanceof RPairList) { - return ((RPairList) e).getTag(); - } else if (e instanceof RArgsValuesAndNames) { - ArgumentsSignature signature = ((RArgsValuesAndNames) e).getSignature(); - if (signature.getLength() > 0 && signature.getName(0) != null) { - return signature.getName(0); - } - return RNull.instance; - } else { - guaranteeInstanceOf(e, RExternalPtr.class); - // at the moment, this can only be used to null out the pointer - return ((RExternalPtr) e).getTag(); - } + return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.TAG).call(e); } @Override @@ -1608,4 +1594,20 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_namesgets).call(x, y); } + @Override + public int Rf_copyMostAttrib(Object x, Object y) { + FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_copyMostAttrib).call(x, y); + return 0; + } + + @Override + public Object Rf_VectorToPairList(Object x) { + return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_VectorToPairList).call(x); + } + + @Override + public Object Rf_asCharacterFactor(Object x) { + return FFIUpCallRootNode.getCallTarget(RFFIUpCallTable.Rf_asCharacterFactor).call(x); + } + } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java index 8b5fc1e7b73848a4d471312f981c1bc9350174b9..d4287407b14c8166a7062551c212a8d296298b53 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/TracingUpCallsRFFIImpl.java @@ -878,4 +878,22 @@ final class TracingUpCallsRFFIImpl implements UpCallsRFFI { return delegate.Rf_namesgets(vec, val); } + @Override + public int Rf_copyMostAttrib(Object x, Object y) { + RFFIUtils.traceUpCall("Rf_copyMostAttrib", x, y); + return delegate.Rf_copyMostAttrib(x, y); + } + + @Override + public Object Rf_VectorToPairList(Object x) { + RFFIUtils.traceUpCall("Rf_VectorToPairlist", x); + return delegate.Rf_VectorToPairList(x); + } + + @Override + public Object Rf_asCharacterFactor(Object x) { + RFFIUtils.traceUpCall("Rf_asCharacterFactor", x); + return delegate.Rf_asCharacterFactor(x); + } + } 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 deleted file mode 100644 index 07d6a98681272787228e27e46d13c0f2a60d901f..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ATTRIB.java +++ /dev/null @@ -1,53 +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.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/AttributesAccessNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/AttributesAccessNodes.java new file mode 100644 index 0000000000000000000000000000000000000000..49276644184fddf03db94bec6cb3f64ed8c4e63c --- /dev/null +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/AttributesAccessNodes.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.ffi.impl.nodes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode; +import com.oracle.truffle.r.nodes.attributes.GetAttributesNode; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; +import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RAttributeStorage; +import com.oracle.truffle.r.runtime.data.RExternalPtr; +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.RStringVector; + +public final class AttributesAccessNodes { + + abstract static class ATTRIB extends FFIUpCallNode.Arg1 { + @Child private GetAttributesNode getAttributesNode; + + @Specialization + public Object doAttributable(RAttributable obj) { + if (getAttributesNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getAttributesNode = GetAttributesNode.create(); + } + 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"); + } + } + } + + abstract static class TAG extends FFIUpCallNode.Arg1 { + + @Specialization + public Object doPairlist(RPairList obj) { + return obj.getTag(); + } + + @Specialization + public Object doArgs(RArgsValuesAndNames obj) { + ArgumentsSignature signature = obj.getSignature(); + if (signature.getLength() > 0 && signature.getName(0) != null) { + return signature.getName(0); + } + return RNull.instance; + } + + @Specialization + public Object doExternalPtr(RExternalPtr obj) { + return obj.getTag(); + } + + @Specialization + public Object doList(RList obj, + @Cached("create()") GetNamesAttributeNode getNamesAttributeNode) { + RStringVector names = getNamesAttributeNode.getNames(obj); + if (names != null && names.getLength() > 0) { + return names.getDataAt(0); + } + return RNull.instance; + } + + @Fallback + @TruffleBoundary + public RNull doOthers(Object obj) { + throw RInternalError.unimplemented("TAG is not implemented for type " + obj.getClass().getSimpleName()); + } + } + + abstract static class CopyMostAttrib extends FFIUpCallNode.Arg2 { + + @Child protected CopyOfRegAttributesNode copyRegAttributes; + + @Specialization + public Object doList(RAttributeStorage x, RAttributeStorage y) { + if (copyRegAttributes == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + copyRegAttributes = CopyOfRegAttributesNode.create(); + } + copyRegAttributes.execute(x, y); + return null; + } + + @Fallback + @SuppressWarnings("unused") + public Void doOthers(Object x, Object y) { + throw RInternalError.unimplemented("Rf_copyMostAttrib only works with atrributables."); + } + } +} diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java new file mode 100644 index 0000000000000000000000000000000000000000..ad332c706566981cc979622af8111f525e3d1045 --- /dev/null +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceNodes.java @@ -0,0 +1,285 @@ +/* + * 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.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.r.nodes.attributes.CopyOfRegAttributesNode; +import com.oracle.truffle.r.nodes.attributes.GetAttributeNode; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; +import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode; +import com.oracle.truffle.r.nodes.helpers.RFactorNodes; +import com.oracle.truffle.r.nodes.unary.CastComplexNode; +import com.oracle.truffle.r.nodes.unary.CastDoubleNode; +import com.oracle.truffle.r.nodes.unary.CastExpressionNode; +import com.oracle.truffle.r.nodes.unary.CastIntegerNode; +import com.oracle.truffle.r.nodes.unary.CastListNode; +import com.oracle.truffle.r.nodes.unary.CastLogicalNode; +import com.oracle.truffle.r.nodes.unary.CastNode; +import com.oracle.truffle.r.nodes.unary.CastRawNode; +import com.oracle.truffle.r.nodes.unary.CastStringNode; +import com.oracle.truffle.r.nodes.unary.CastSymbolNode; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RDataFactory; +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.RShareable; +import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.RTypedValue; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; + +public final class CoerceNodes { + + abstract static class VectorToPairListNode extends FFIUpCallNode.Arg1 { + + @Child private CopyOfRegAttributesNode copyRegAttributesNode; + @Child private GetNamesAttributeNode getNamesAttributeNode; + + @Specialization + protected Object convert(RAbstractVector v) { + + RStringVector names = getNamesAttributeNode.getNames(v); + SEXPTYPE gnurType = SEXPTYPE.gnuRTypeForObject(v); + + RPairList head = null; + RPairList prev = null; + assert names == null || names.getLength() == v.getLength(); + for (int i = 0; i < v.getLength(); i++) { + Object element = v.getDataAtAsObject(i); + adjustSharing(v, element); + RPairList cur = RDataFactory.createPairList(element, RNull.instance, names != null ? names.getDataAt(i) : RNull.instance, gnurType); + + if (prev == null) { + assert head == null; + head = cur; + } else { + prev.setCdr(cur); + } + prev = cur; + } + if (head != null) { + // also copy regular attributes + copyRegAttributesNode.execute(v, head); + return head; + } + return RNull.instance; + } + + private static void adjustSharing(RAbstractVector origin, Object element) { + if (origin instanceof RShareable) { + int v = getSharingLevel((RShareable) origin); + if (element instanceof RShareable) { + RShareable r = (RShareable) element; + if (v == 2) { + // we play it safe: if the caller wants this instance to be shared, they may + // expect it to never become non-shared again, which could happen in FastR + r.makeSharedPermanent(); + } + if (v == 1 && r.isTemporary()) { + r.incRefCount(); + } + } + } + } + + public static VectorToPairListNode create() { + return CoerceNodesFactory.VectorToPairListNodeGen.create(); + } + + private static int getSharingLevel(RShareable r) { + return r.isTemporary() ? 0 : r.isShared() ? 2 : 1; + } + } + + abstract static class AsCharacterFactor extends FFIUpCallNode.Arg1 { + + @Child private InheritsCheckNode inheritsFactorNode = InheritsCheckNode.createFactor(); + @Child private GetAttributeNode getAttributeNode = GetAttributeNode.create(); + @Child private RFactorNodes.GetLevels getLevels = RFactorNodes.GetLevels.create(); + + @Specialization + protected Object doFactor(RAbstractIntVector o) { + if (!inheritsFactorNode.execute(o)) { + throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, "attempting to coerce non-factor"); + } + + RStringVector levels = getLevels.execute(o); + if (levels == null) { + throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, "malformed factor"); + } + + String[] data = new String[o.getLength()]; + boolean isComplete = true; + int nl = levels.getLength(); + for (int i = 0; i < o.getLength(); i++) { + assert !o.isComplete() || o.getDataAt(i) != RRuntime.INT_NA; + int idx = o.getDataAt(i); + if (idx == RRuntime.INT_NA) { + data[i] = RRuntime.STRING_NA; + isComplete = false; + } else if (idx >= 1 && idx <= nl) { + data[i] = levels.getDataAt(idx - 1); + } else { + throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, "malformed factor"); + } + } + + return RDataFactory.createStringVector(data, isComplete); + } + + public static AsCharacterFactor create() { + return CoerceNodesFactory.AsCharacterFactorNodeGen.create(); + } + + } + + /** + * Implements Rf_coerceVector. + */ + abstract static class CoerceVectorNode extends FFIUpCallNode.Arg2 { + + public static CoerceVectorNode create() { + return CoerceNodesFactory.CoerceVectorNodeGen.create(); + } + + @Specialization(guards = "value.isS4()") + Object doS4Object(@SuppressWarnings("unused") RTypedValue value, @SuppressWarnings("unused") int mode) { + throw RError.nyi(RError.NO_CALLER, "Rf_coerceVector for S4 objects."); + } + + // Note: caches should cover all valid possibilities + @Specialization(guards = {"!isS4Object(value)", "isNotList(value)", "isValidMode(mode)", "cachedMode == mode"}, limit = "99") + Object doCached(Object value, @SuppressWarnings("unused") int mode, + @Cached("mode") @SuppressWarnings("unused") int cachedMode, + @Cached("createCastNode(cachedMode)") CastNode castNode) { + return castNode.doCast(value); + } + + // Lists are coerced with only preserved names unlike other types + @Specialization(guards = {"!isS4Object(value)", "isValidMode(mode)", "cachedMode == mode"}, limit = "99") + Object doCached(RList value, @SuppressWarnings("unused") int mode, + @Cached("mode") @SuppressWarnings("unused") int cachedMode, + @Cached("createCastNodeForList(cachedMode)") CastNode castNode) { + return castNode.doCast(value); + } + + @Fallback + @TruffleBoundary + Object doFallback(Object value, Object mode) { + String type = value != null ? value.getClass().getSimpleName() : "null"; + throw RInternalError.unimplemented(String.format("Rf_coerceVector unimplemented for type %s or mode %s.", type, mode)); + } + + static boolean isS4Object(Object obj) { + return obj instanceof RTypedValue && ((RTypedValue) obj).isS4(); + } + + static boolean isNotList(Object obj) { + return !(obj instanceof RList); + } + + static boolean isValidMode(int mode) { + return mode >= SEXPTYPE.NILSXP.code && mode <= SEXPTYPE.RAWSXP.code; + } + + static CastNode createCastNode(int mode) { + return createCastNode(mode, false); + } + + static CastNode createCastNodeForList(int mode) { + return createCastNode(mode, true); + } + + private static CastNode createCastNode(int mode, boolean forList) { + SEXPTYPE type = SEXPTYPE.mapInt(mode); + boolean preserveDims = !forList; + boolean preserveAttrs = !forList; + switch (type) { + case SYMSXP: + return CastSymbolNode.createForRFFI(false, false, false); + case NILSXP: + return new CastNullNode(); + case LISTSXP: + throw RInternalError.unimplemented("Rf_coerceVector unimplemented for PairLists."); + case LANGSXP: + throw RInternalError.unimplemented("Rf_coerceVector unimplemented for RLanguage."); + case ENVSXP: + return new EnvironmentCast(); + case VECSXP: + return CastListNode.createForRFFI(true, forList, forList); + case EXPRSXP: + return CastExpressionNode.createForRFFI(); + case INTSXP: + return CastIntegerNode.createForRFFI(true, preserveDims, preserveAttrs); + case REALSXP: + return CastDoubleNode.createForRFFI(true, preserveDims, preserveAttrs); + case LGLSXP: + return CastLogicalNode.createForRFFI(true, preserveDims, preserveAttrs); + case STRSXP: + return CastStringNode.createForRFFI(true, preserveDims, preserveAttrs); + case CPLXSXP: + return CastComplexNode.createForRFFI(true, preserveDims, preserveAttrs); + case RAWSXP: + return CastRawNode.createForRFFI(true, preserveDims, preserveAttrs); + default: + throw RInternalError.unimplemented(String.format("Rf_coerceVector called with unimplemented mode %d (type %s).", mode, type)); + } + } + + private static final class CastNullNode extends CastNode { + @Override + @TruffleBoundary + public Object execute(Object value) { + if (value instanceof RList) { + throw RError.error(RError.NO_CALLER, Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, "list", "coerceVectorList"); + } else { + throw RError.error(RError.NO_CALLER, Message.CANNOT_COERCE, getTypeName(value), "NULL"); + } + } + + private static String getTypeName(Object val) { + Object value = RRuntime.convertScalarVectors(val); + if (value == null) { + return "null"; + } + return value instanceof RTypedValue ? ((RTypedValue) value).getRType().getName() : value.getClass().getSimpleName(); + } + } + + private static final class EnvironmentCast extends CastNode { + @Override + @TruffleBoundary + public Object execute(Object value) { + throw RError.error(RError.NO_CALLER, Message.ENVIRONMENTS_COERCE); + } + } + } +} diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java deleted file mode 100644 index 32da1b5c50147f250972a2dba8c2d3efa6f85a81..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/CoerceVectorNode.java +++ /dev/null @@ -1,167 +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.ffi.impl.nodes; - -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.r.nodes.unary.CastComplexNode; -import com.oracle.truffle.r.nodes.unary.CastDoubleNode; -import com.oracle.truffle.r.nodes.unary.CastExpressionNode; -import com.oracle.truffle.r.nodes.unary.CastIntegerNode; -import com.oracle.truffle.r.nodes.unary.CastListNode; -import com.oracle.truffle.r.nodes.unary.CastLogicalNode; -import com.oracle.truffle.r.nodes.unary.CastNode; -import com.oracle.truffle.r.nodes.unary.CastRawNode; -import com.oracle.truffle.r.nodes.unary.CastStringNode; -import com.oracle.truffle.r.nodes.unary.CastSymbolNode; -import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RError.Message; -import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RTypedValue; -import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; - -/** - * Implements Rf_coerceVector. - */ -public abstract class CoerceVectorNode extends FFIUpCallNode.Arg2 { - - public static CoerceVectorNode create() { - return CoerceVectorNodeGen.create(); - } - - @Specialization(guards = "value.isS4()") - Object doS4Object(@SuppressWarnings("unused") RTypedValue value, @SuppressWarnings("unused") int mode) { - throw RError.nyi(RError.NO_CALLER, "Rf_coerceVector for S4 objects."); - } - - // Note: caches should cover all valid possibilities - @Specialization(guards = {"!isS4Object(value)", "isNotList(value)", "isValidMode(mode)", "cachedMode == mode"}, limit = "99") - Object doCached(Object value, @SuppressWarnings("unused") int mode, - @Cached("mode") @SuppressWarnings("unused") int cachedMode, - @Cached("createCastNode(cachedMode)") CastNode castNode) { - return castNode.doCast(value); - } - - // Lists are coerced with only preserved names unlike other types - @Specialization(guards = {"!isS4Object(value)", "isValidMode(mode)", "cachedMode == mode"}, limit = "99") - Object doCached(RList value, @SuppressWarnings("unused") int mode, - @Cached("mode") @SuppressWarnings("unused") int cachedMode, - @Cached("createCastNodeForList(cachedMode)") CastNode castNode) { - return castNode.doCast(value); - } - - @Fallback - @TruffleBoundary - Object doFallback(Object value, Object mode) { - String type = value != null ? value.getClass().getSimpleName() : "null"; - throw RInternalError.unimplemented(String.format("Rf_coerceVector unimplemented for type %s or mode %s.", type, mode)); - } - - static boolean isS4Object(Object obj) { - return obj instanceof RTypedValue && ((RTypedValue) obj).isS4(); - } - - static boolean isNotList(Object obj) { - return !(obj instanceof RList); - } - - static boolean isValidMode(int mode) { - return mode >= SEXPTYPE.NILSXP.code && mode <= SEXPTYPE.RAWSXP.code; - } - - static CastNode createCastNode(int mode) { - return createCastNode(mode, false); - } - - static CastNode createCastNodeForList(int mode) { - return createCastNode(mode, true); - } - - private static CastNode createCastNode(int mode, boolean forList) { - SEXPTYPE type = SEXPTYPE.mapInt(mode); - boolean preserveDims = !forList; - boolean preserveAttrs = !forList; - switch (type) { - case SYMSXP: - return CastSymbolNode.createForRFFI(false, false, false); - case NILSXP: - return new CastNullNode(); - case LISTSXP: - throw RInternalError.unimplemented("Rf_coerceVector unimplemented for PairLists."); - case LANGSXP: - throw RInternalError.unimplemented("Rf_coerceVector unimplemented for RLanguage."); - case ENVSXP: - return new EnvironmentCast(); - case VECSXP: - return CastListNode.createForRFFI(true, forList, forList); - case EXPRSXP: - return CastExpressionNode.createForRFFI(); - case INTSXP: - return CastIntegerNode.createForRFFI(true, preserveDims, preserveAttrs); - case REALSXP: - return CastDoubleNode.createForRFFI(true, preserveDims, preserveAttrs); - case LGLSXP: - return CastLogicalNode.createForRFFI(true, preserveDims, preserveAttrs); - case STRSXP: - return CastStringNode.createForRFFI(true, preserveDims, preserveAttrs); - case CPLXSXP: - return CastComplexNode.createForRFFI(true, preserveDims, preserveAttrs); - case RAWSXP: - return CastRawNode.createForRFFI(true, preserveDims, preserveAttrs); - default: - throw RInternalError.unimplemented(String.format("Rf_coerceVector called with unimplemented mode %d (type %s).", mode, type)); - } - } - - private static final class CastNullNode extends CastNode { - @Override - @TruffleBoundary - public Object execute(Object value) { - if (value instanceof RList) { - throw RError.error(RError.NO_CALLER, Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, "list", "coerceVectorList"); - } else { - throw RError.error(RError.NO_CALLER, Message.CANNOT_COERCE, getTypeName(value), "NULL"); - } - } - - private static String getTypeName(Object val) { - Object value = RRuntime.convertScalarVectors(val); - if (value == null) { - return "null"; - } - return value instanceof RTypedValue ? ((RTypedValue) value).getRType().getName() : value.getClass().getSimpleName(); - } - } - - private static final class EnvironmentCast extends CastNode { - @Override - @TruffleBoundary - public Object execute(Object value) { - throw RError.error(RError.NO_CALLER, Message.ENVIRONMENTS_COERCE); - } - } -} 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 4470a37a76c32fce8da819194007efa910eedea4..de10716282dd189766cd122c954d30a2cca6e652 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 @@ -94,12 +94,12 @@ public final class FFIUpCallRootNode extends RootNode { } public static void register() { - FFIUpCallRootNode.add(RFFIUpCallTable.ATTRIB, ATTRIBNodeGen::create); + FFIUpCallRootNode.add(RFFIUpCallTable.ATTRIB, AttributesAccessNodesFactory.ATTRIBNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asReal, AsRealNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asLogical, AsLogicalNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asInteger, AsIntegerNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asChar, AsCharNodeGen::create); - FFIUpCallRootNode.add(RFFIUpCallTable.Rf_coerceVector, CoerceVectorNode::create); + FFIUpCallRootNode.add(RFFIUpCallTable.Rf_coerceVector, CoerceNodes.CoerceVectorNode::create); FFIUpCallRootNode.add(RFFIUpCallTable.CAR, CARNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallTable.CDR, CDRNodeGen::create); FFIUpCallRootNode.add(RFFIUpCallTable.CADR, CADRNodeGen::create); @@ -114,5 +114,9 @@ public final class FFIUpCallRootNode extends RootNode { FFIUpCallRootNode.add(RFFIUpCallTable.Rf_qunif, () -> RandFunction3_2NodeGen.create(new Unif.QUnif())); FFIUpCallRootNode.add(RFFIUpCallTable.Rf_punif, () -> RandFunction3_2NodeGen.create(new Unif.PUnif())); FFIUpCallRootNode.add(RFFIUpCallTable.Rf_namesgets, MiscNodesFactory.NamesGetsNodeGen::create); + FFIUpCallRootNode.add(RFFIUpCallTable.TAG, AttributesAccessNodesFactory.TAGNodeGen::create); + FFIUpCallRootNode.add(RFFIUpCallTable.Rf_copyMostAttrib, AttributesAccessNodesFactory.CopyMostAttribNodeGen::create); + FFIUpCallRootNode.add(RFFIUpCallTable.Rf_VectorToPairList, CoerceNodes.VectorToPairListNode::create); + FFIUpCallRootNode.add(RFFIUpCallTable.Rf_asCharacterFactor, CoerceNodes.AsCharacterFactor::create); } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java index bd0c3374713aabd8bfe24182e7de4ab285183b3c..3f675ef3eca28cb4df8dd056b4731c6127405d6e 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java @@ -22,14 +22,22 @@ */ package com.oracle.truffle.r.ffi.impl.nodes; +import java.util.Arrays; + +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.dsl.TypeSystemReference; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +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.RPairList; +import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypes; @@ -61,6 +69,11 @@ public final class ListAccessNodes { return sym; } + @Specialization + protected Object car(RList list) { + return list.getDataAt(0); + } + @Specialization protected Object car(@SuppressWarnings("unused") RNull nil) { return RNull.instance; @@ -68,7 +81,7 @@ public final class ListAccessNodes { @Fallback protected Object car(@SuppressWarnings("unused") Object obj) { - throw RInternalError.unimplemented("CAR only works on pair lists and language objects"); + throw RInternalError.unimplemented("CAR only works on pair lists, language objects, argument lists, and symbols"); } } @@ -90,9 +103,26 @@ public final class ListAccessNodes { return args.toPairlist().cdr(); } + @Specialization + protected Object cdr(RList list, + @Cached("create()") GetNamesAttributeNode getNamesNode, + @Cached("create()") SetNamesAttributeNode setNamesNode) { + if (list.getLength() == 1) { + return RNull.instance; + } + Object[] dataCopy = list.getDataWithoutCopying(); + RStringVector names = getNamesNode.getNames(list); + RList copy = RDataFactory.createList(Arrays.copyOfRange(dataCopy, 1, list.getLength())); + if (names != null) { + String[] dataWithoutCopying = names.getDataWithoutCopying(); + setNamesNode.setNames(copy, RDataFactory.createStringVector(Arrays.copyOfRange(dataWithoutCopying, 1, names.getLength()), true)); + } + return copy; + } + @Fallback protected Object cdr(@SuppressWarnings("unused") Object obj) { - throw RInternalError.unimplemented("CDR only works on pair lists and language objects"); + throw RInternalError.unimplemented("CDR only works on pair lists, language objects, and argument lists"); } } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java index 76c10d6ac9e1285218e7e2774872b3375cc1ac2a..6226535d30b75aa31f47e75d6d361b23f2eb8cb8 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java @@ -305,4 +305,9 @@ public interface StdUpCallsRFFI { Object Rf_namesgets(Object vec, Object val); + int Rf_copyMostAttrib(Object x, Object y); + + Object Rf_VectorToPairList(Object x); + + Object Rf_asCharacterFactor(Object x); } diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h index 44b8bf7102dac472baa11a2dbcc4d41c3aa2842f..3452fe945c59beacfd0054e3ab02dad68c8249db 100644 --- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h +++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h @@ -58,7 +58,7 @@ typedef SEXP (*call_Rf_coerceVector)(SEXP x, SEXPTYPE mode); typedef R_xlen_t (*call_Rf_any_duplicated)(SEXP x, Rboolean from_last); typedef SEXP (*call_Rf_duplicated)(SEXP x, Rboolean y); typedef SEXP (*call_Rf_applyClosure)(SEXP x, SEXP y, SEXP z, SEXP a, SEXP b); -typedef void (*call_Rf_copyMostAttrib)(SEXP x, SEXP y); +typedef int (*call_Rf_copyMostAttrib)(SEXP x, SEXP y); typedef void (*call_Rf_copyVector)(SEXP x, SEXP y); typedef int (*call_Rf_countContexts)(int x, int y); typedef Rboolean (*call_Rf_inherits)(SEXP x, const char * klass); diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h index f17d3f1c1952664e5635140c1d46dbd2461cf3a9..e414fb91e6d9dd51d3e716fd0e908e96c1b28055 100644 --- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h +++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h @@ -78,73 +78,76 @@ #define Rf_ScalarInteger_x 73 #define Rf_ScalarLogical_x 74 #define Rf_ScalarString_x 75 -#define Rf_allocArray_x 76 -#define Rf_allocMatrix_x 77 -#define Rf_allocVector_x 78 -#define Rf_any_duplicated_x 79 -#define Rf_asChar_x 80 -#define Rf_asInteger_x 81 -#define Rf_asLogical_x 82 -#define Rf_asReal_x 83 -#define Rf_classgets_x 84 -#define Rf_coerceVector_x 85 -#define Rf_cons_x 86 -#define Rf_copyListMatrix_x 87 -#define Rf_copyMatrix_x 88 -#define Rf_defineVar_x 89 -#define Rf_dunif_x 90 -#define Rf_duplicate_x 91 -#define Rf_error_x 92 -#define Rf_errorcall_x 93 -#define Rf_eval_x 94 -#define Rf_findFun_x 95 -#define Rf_findVar_x 96 -#define Rf_findVarInFrame_x 97 -#define Rf_findVarInFrame3_x 98 -#define Rf_getAttrib_x 99 -#define Rf_gsetVar_x 100 -#define Rf_inherits_x 101 -#define Rf_install_x 102 -#define Rf_installChar_x 103 -#define Rf_isNull_x 104 -#define Rf_isString_x 105 -#define Rf_lengthgets_x 106 -#define Rf_mkCharLenCE_x 107 -#define Rf_namesgets_x 108 -#define Rf_ncols_x 109 -#define Rf_nrows_x 110 -#define Rf_punif_x 111 -#define Rf_qunif_x 112 -#define Rf_runif_x 113 -#define Rf_setAttrib_x 114 -#define Rf_str2type_x 115 -#define Rf_warning_x 116 -#define Rf_warningcall_x 117 -#define Rprintf_x 118 -#define SETCADR_x 119 -#define SETCAR_x 120 -#define SETCDR_x 121 -#define SET_NAMED_FASTR_x 122 -#define SET_RDEBUG_x 123 -#define SET_RSTEP_x 124 -#define SET_S4_OBJECT_x 125 -#define SET_STRING_ELT_x 126 -#define SET_SYMVALUE_x 127 -#define SET_TAG_x 128 -#define SET_TYPEOF_FASTR_x 129 -#define SET_VECTOR_ELT_x 130 -#define STRING_ELT_x 131 -#define SYMVALUE_x 132 -#define TAG_x 133 -#define TYPEOF_x 134 -#define UNSET_S4_OBJECT_x 135 -#define VECTOR_ELT_x 136 -#define getConnectionClassString_x 137 -#define getOpenModeString_x 138 -#define getSummaryDescription_x 139 -#define isSeekable_x 140 -#define unif_rand_x 141 +#define Rf_VectorToPairList_x 76 +#define Rf_allocArray_x 77 +#define Rf_allocMatrix_x 78 +#define Rf_allocVector_x 79 +#define Rf_any_duplicated_x 80 +#define Rf_asChar_x 81 +#define Rf_asCharacterFactor_x 82 +#define Rf_asInteger_x 83 +#define Rf_asLogical_x 84 +#define Rf_asReal_x 85 +#define Rf_classgets_x 86 +#define Rf_coerceVector_x 87 +#define Rf_cons_x 88 +#define Rf_copyListMatrix_x 89 +#define Rf_copyMatrix_x 90 +#define Rf_copyMostAttrib_x 91 +#define Rf_defineVar_x 92 +#define Rf_dunif_x 93 +#define Rf_duplicate_x 94 +#define Rf_error_x 95 +#define Rf_errorcall_x 96 +#define Rf_eval_x 97 +#define Rf_findFun_x 98 +#define Rf_findVar_x 99 +#define Rf_findVarInFrame_x 100 +#define Rf_findVarInFrame3_x 101 +#define Rf_getAttrib_x 102 +#define Rf_gsetVar_x 103 +#define Rf_inherits_x 104 +#define Rf_install_x 105 +#define Rf_installChar_x 106 +#define Rf_isNull_x 107 +#define Rf_isString_x 108 +#define Rf_lengthgets_x 109 +#define Rf_mkCharLenCE_x 110 +#define Rf_namesgets_x 111 +#define Rf_ncols_x 112 +#define Rf_nrows_x 113 +#define Rf_punif_x 114 +#define Rf_qunif_x 115 +#define Rf_runif_x 116 +#define Rf_setAttrib_x 117 +#define Rf_str2type_x 118 +#define Rf_warning_x 119 +#define Rf_warningcall_x 120 +#define Rprintf_x 121 +#define SETCADR_x 122 +#define SETCAR_x 123 +#define SETCDR_x 124 +#define SET_NAMED_FASTR_x 125 +#define SET_RDEBUG_x 126 +#define SET_RSTEP_x 127 +#define SET_S4_OBJECT_x 128 +#define SET_STRING_ELT_x 129 +#define SET_SYMVALUE_x 130 +#define SET_TAG_x 131 +#define SET_TYPEOF_FASTR_x 132 +#define SET_VECTOR_ELT_x 133 +#define STRING_ELT_x 134 +#define SYMVALUE_x 135 +#define TAG_x 136 +#define TYPEOF_x 137 +#define UNSET_S4_OBJECT_x 138 +#define VECTOR_ELT_x 139 +#define getConnectionClassString_x 140 +#define getOpenModeString_x 141 +#define getSummaryDescription_x 142 +#define isSeekable_x 143 +#define unif_rand_x 144 -#define UPCALLS_TABLE_SIZE 142 +#define UPCALLS_TABLE_SIZE 145 #endif // RFFI_UPCALLSINDEX_H diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c index 87605b88e859b232b52c5273435005c89ddd3549..5dcff7874a0572fb6df31c8bfb4e9d27f2c7e1f2 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c @@ -105,6 +105,8 @@ static jmethodID Rf_coerceVectorMethodID; static jmethodID Rf_mkCharLenCEMethodID; static jmethodID Rf_asLogicalMethodID; static jmethodID Rf_PairToVectorListMethodID; +static jmethodID Rf_VectorToPairListMethodID; +static jmethodID Rf_asCharacterFactorMethodID; static jmethodID gnuRCodeForObjectMethodID; static jmethodID NAMED_MethodID; static jmethodID SET_TYPEOF_FASTR_MethodID; @@ -147,6 +149,7 @@ static jmethodID Rf_copyMatrixMethodID; static jmethodID Rf_nrowsMethodID; static jmethodID Rf_ncolsMethodID; static jmethodID Rf_namesgetsMethodID; +static jmethodID Rf_copyMostAttribMethodID; static jclass CharSXPWrapperClass; jclass JNIUpCallsRFFIImplClass; @@ -227,6 +230,8 @@ void init_internals(JNIEnv *env) { Rf_coerceVectorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_coerceVector", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0); Rf_asLogicalMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asLogical", "(Ljava/lang/Object;)I", 0); Rf_PairToVectorListMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_PairToVectorList", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); + Rf_VectorToPairListMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_VectorToPairList", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); + Rf_asCharacterFactorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_asCharacterFactor", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); NAMED_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "NAMED", "(Ljava/lang/Object;)I", 0); SET_TYPEOF_FASTR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_TYPEOF_FASTR", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0); SET_NAMED_FASTR_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "SET_NAMED_FASTR", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0); @@ -265,6 +270,7 @@ void init_internals(JNIEnv *env) { Rf_nrowsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_nrows", "(Ljava/lang/Object;)I", 0); Rf_ncolsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_ncols", "(Ljava/lang/Object;)I", 0); Rf_namesgetsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_namesgets", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0); + Rf_copyMostAttribMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_copyMostAttrib", "(Ljava/lang/Object;Ljava/lang/Object;)I", 0); // static JNI-specific methods JNIUpCallsRFFIImplClass = checkFindClass(env, "com/oracle/truffle/r/ffi/impl/jni/JNIUpCallsRFFIImpl"); @@ -446,7 +452,9 @@ SEXP Rf_applyClosure(SEXP x, SEXP y, SEXP z, SEXP a, SEXP b) { } void Rf_copyMostAttrib(SEXP x, SEXP y) { - unimplemented("Rf_copyMostAttrib"); + TRACE(TARGpp, x, y); + JNIEnv *thisenv = getEnv(); + (*thisenv)->CallIntMethod(thisenv, UpCallsRFFIObject, Rf_copyMostAttribMethodID, x, y); } void Rf_copyVector(SEXP x, SEXP y) { @@ -1186,13 +1194,17 @@ SEXP Rf_PairToVectorList(SEXP x){ } SEXP Rf_VectorToPairList(SEXP x){ - unimplemented("Rf_VectorToPairList"); - return NULL; + TRACE(TARGp, x); + JNIEnv *thisenv = getEnv(); + SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_VectorToPairListMethodID, x); + return checkRef(thisenv, result); } SEXP Rf_asCharacterFactor(SEXP x){ - unimplemented("Rf_VectorToPairList"); - return NULL; + TRACE(TARGp, x); + JNIEnv *thisenv = getEnv(); + SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_asCharacterFactorMethodID, x); + return checkRef(thisenv, result); } int Rf_asLogical(SEXP x){ diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h index 916a6d0a4be19b603150d698a09baca6a51243b6..767572ed9dcd0d6a4fa390d50702bfef2615f0b6 100644 --- a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h +++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h @@ -311,7 +311,7 @@ SEXP Rf_applyClosure(SEXP x, SEXP y, SEXP z, SEXP a, SEXP b) { } void Rf_copyMostAttrib(SEXP x, SEXP y) { - unimplemented("Rf_copyMostAttrib"); + ((call_Rf_copyMostAttrib) callbacks[Rf_copyMostAttrib_x])(x, y); } void Rf_copyVector(SEXP x, SEXP y) { @@ -763,12 +763,11 @@ SEXP Rf_PairToVectorList(SEXP x){ } SEXP Rf_VectorToPairList(SEXP x){ - return unimplemented("Rf_VectorToPairList"); + return checkRef(((call_Rf_VectorToPairList) callbacks[Rf_VectorToPairList_x])(x)); } SEXP Rf_asCharacterFactor(SEXP x){ - unimplemented("Rf_VectorToPairList"); - return NULL; + return checkRef(((call_Rf_asCharacterFactor) callbacks[Rf_asCharacterFactor_x])(x)); } int Rf_asLogical(SEXP x){ diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java index 39146e8235b4014f1139a75ad00cb489a2347732..c8bdd10f11b20611384f9ebe538b69db8e76fa49 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/APerm.java @@ -18,21 +18,25 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.access.vector.ExtractListElement; +import com.oracle.truffle.r.nodes.attributes.RemoveRegAttributesNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode; 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.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RIntVector; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -51,11 +55,12 @@ public abstract class APerm extends RBuiltinNode.Arg3 { @Child private SetDimNamesAttributeNode setDimNames; @Child private ExtractListElement extractListElement; + @Child private ReuseNonSharedNode reuseNonSharedNode; static { Casts casts = new Casts(APerm.class); casts.arg("a").mustNotBeNull(RError.Message.FIRST_ARG_MUST_BE_ARRAY); - casts.arg("perm").allowNull().mustBe(numericValue().or(stringValue()).or(complexValue())).mapIf(numericValue().or(complexValue()), asIntegerVectorClosure()); + casts.arg("perm").allowNull().mustBe(numericValue().or(stringValue()).or(complexValue())).mapIf(numericValue().or(complexValue()), asIntegerVectorClosure(true, true, false)); casts.arg("resize").mustBe(numericValue().or(logicalValue()), Message.INVALID_LOGICAL, "resize").asLogicalVector().findFirst(); } @@ -107,7 +112,30 @@ public abstract class APerm extends RBuiltinNode.Arg3 { return result; } - @Specialization + @Specialization(guards = "isIdentityPermutation(vector, permVector, getDimsNode)") + protected RAbstractVector doIdentity(RAbstractVector vector, @SuppressWarnings("unused") RAbstractIntVector permVector, @SuppressWarnings("unused") byte resize, + @Cached("create()") RemoveRegAttributesNode removeClassAttrNode, + @Cached("create()") GetDimAttributeNode getDimsNode) { + + if (reuseNonSharedNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + reuseNonSharedNode = insert(ReuseNonSharedNode.create()); + } + + int[] dim = getDimsNode.getDimensions(vector); + checkErrorConditions(dim); + + RVector<?> reused = reuseNonSharedNode.execute(vector); + + // we have to remove some attributes + // remove all regular attributes (including the class attribute) + removeClassAttrNode.execute(reused); + + // also ensures that we do not give a closure away + return reused; + } + + @Specialization(guards = "!isIdentityPermutation(vector, permVector, getDimsNode)") protected RAbstractVector aPerm(RAbstractVector vector, RAbstractIntVector permVector, byte resize, @Cached("create()") GetDimAttributeNode getDimsNode, @Cached("create()") SetDimAttributeNode setDimsNode, @@ -153,10 +181,26 @@ public abstract class APerm extends RBuiltinNode.Arg3 { return result; } + protected boolean isIdentityPermutation(RAbstractVector v, RAbstractIntVector permVector, GetDimAttributeNode getDimAttributeNode) { + int[] dimensions = getDimAttributeNode.getDimensions(v); + if (dimensions != null) { + int[] perm = getPermute(dimensions, permVector); + for (int i = 0; i < dimensions.length; i++) { + if (i != perm[i]) { + return false; + } + } + return true; + } + return false; + } + @Specialization protected RAbstractVector aPerm(RAbstractVector vector, RAbstractStringVector permVector, byte resize, + @Cached("createBinaryProfile()") ConditionProfile isIdentityProfile, @Cached("create()") GetDimAttributeNode getDimsNode, @Cached("create()") SetDimAttributeNode setDimsNode, + @Cached("create()") RemoveRegAttributesNode removeClassAttrNode, @Cached("create()") GetDimNamesAttributeNode getDimNamesNode) { RList dimNames = getDimNamesNode.getDimNames(vector); if (dimNames == null) { @@ -175,8 +219,13 @@ public abstract class APerm extends RBuiltinNode.Arg3 { // TODO: not found dimname error } + RIntVector permIntVector = RDataFactory.createIntVector(perm, true); + if (isIdentityProfile.profile(isIdentityPermutation(vector, permIntVector, getDimsNode))) { + return doIdentity(vector, permIntVector, resize, removeClassAttrNode, getDimsNode); + } + // Note: if this turns out to be slow, we can cache the permutation - return aPerm(vector, RDataFactory.createIntVector(perm, true), resize, getDimsNode, setDimsNode, getDimNamesNode); + return aPerm(vector, permIntVector, resize, getDimsNode, setDimsNode, getDimNamesNode); } private static int[] getReverse(int[] dim) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java index 794229c9aae8f269919166366dfcb42e346ef626..33b9f53eb2bcc6da41a102539f92b1e8d6ca6f2e 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java @@ -77,6 +77,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypes; import com.oracle.truffle.r.runtime.data.RVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.nodes.RBaseNode; import com.oracle.truffle.r.runtime.ops.na.NACheck; @@ -304,7 +305,7 @@ public abstract class Bind extends RBaseNode { } } if (firstDimNames != RNull.instance) { - RStringVector names = (RStringVector) firstDimNames; + RAbstractStringVector names = (RAbstractStringVector) firstDimNames; if (names != null && names.getLength() == dimLength) { firstDimResultNames = names; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java index a6e10e9ec1e2dca9b7b13a612b0706f55c51be26..7baf39bb7d472663a413ba1c8264c101bf0df70c 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java @@ -55,6 +55,7 @@ import com.oracle.truffle.r.nodes.function.PromiseNode.VarArgNode; import com.oracle.truffle.r.nodes.function.PromiseNode.VarArgsPromiseNode; import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.CallerFrameClosure; import com.oracle.truffle.r.runtime.HasSignature; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; @@ -159,29 +160,25 @@ public class FrameFunctions { if (RArguments.getDepth(frame) - actualFrame <= ITERATE_LEVELS) { Frame current = frame; for (int i = 0; i < ITERATE_LEVELS; i++) { - current = current == null ? null : RArguments.getCallerFrame(current); + current = current == null ? null : getCallerFrame(current); if (current != null && RArguments.getDepth(current) == actualFrame) { return current; } } - notifyRCallNodes(actualFrame, RArguments.getCall(frame)); } return Utils.getStackFrame(access, actualFrame); } } - @TruffleBoundary - private static void notifyRCallNodes(int actualFrame, RCaller caller) { - RCaller currentCaller = caller; - for (int i = 0; i < ITERATE_LEVELS; i++) { - if (currentCaller == null || currentCaller.getDepth() <= actualFrame) { - break; - } - if (currentCaller.isValidCaller() && !currentCaller.isPromise() && currentCaller.getSyntaxNode() instanceof RCallNode) { - ((RCallNode) currentCaller.getSyntaxNode()).setNeedsCallerFrame(); - } - currentCaller = currentCaller.getParent(); + private static Frame getCallerFrame(Frame current) { + Object callerFrame = RArguments.getCallerFrame(current); + if (callerFrame instanceof CallerFrameClosure) { + CallerFrameClosure closure = (CallerFrameClosure) callerFrame; + closure.setNeedsCallerFrame(); + return closure.getMaterializedCallerFrame(); } + assert callerFrame instanceof Frame; + return (Frame) callerFrame; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java index 3e5b3d2fb9bbfc7022715e181b1ca6b59e44ca68..e8547dc985cbad602368033b7b425c51b9b78a82 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java @@ -37,7 +37,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; @@ -257,8 +256,6 @@ public class GetFunctions { @Child private TypeFromModeNode typeFromMode = TypeFromModeNodeGen.create(); @Child private CallRFunctionCachedNode callCache = CallRFunctionCachedNodeGen.create(2); - @CompilationFinal private boolean needsCallerFrame; - static { Casts casts = new Casts(MGet.class); casts.arg("x").mustBe(stringValue()).asStringVector(); @@ -375,14 +372,12 @@ public class GetFunctions { } private Object call(VirtualFrame frame, RFunction ifnFunc, String x) { - if (!needsCallerFrame && ((RRootNode) ifnFunc.getRootNode()).containsDispatch()) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - needsCallerFrame = true; + if (((RRootNode) ifnFunc.getRootNode()).containsDispatch()) { + callCache.setNeedsCallerFrame(); } - MaterializedFrame callerFrame = needsCallerFrame ? frame.materialize() : null; FormalArguments formals = ((RRootNode) ifnFunc.getRootNode()).getFormalArguments(); RArgsValuesAndNames args = new RArgsValuesAndNames(new Object[]{x}, ArgumentsSignature.empty(1)); - return callCache.execute(frame, ifnFunc, RCaller.create(frame, RCallerHelper.createFromArguments(ifnFunc, args)), callerFrame, new Object[]{x}, formals.getSignature(), + return callCache.execute(frame, ifnFunc, RCaller.create(frame, RCallerHelper.createFromArguments(ifnFunc, args)), new Object[]{x}, formals.getSignature(), ifnFunc.getEnclosingFrame(), null); } @@ -400,5 +395,6 @@ public class GetFunctions { } return value; } + } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java index 965159a003e27909512544a134e49257fdb42e48..7163f0f9bdce97762ca7b848cc3bb87265f5e467 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java @@ -253,7 +253,7 @@ public class HiddenInternalFunctions { RSerialize.CallHook callHook = new RSerialize.CallHook() { @Override public Object eval(Object arg) { - return callCache.execute(SubstituteVirtualFrame.create(frame), envhook, RCaller.create(frame, getOriginalCall()), null, new Object[]{arg}, null); + return callCache.execute(SubstituteVirtualFrame.create(frame), envhook, RCaller.create(frame, getOriginalCall()), new Object[]{arg}, null); } }; String functionName = ReadVariableNode.getSlowPathEvaluationName(); @@ -385,7 +385,7 @@ public class HiddenInternalFunctions { RSerialize.CallHook callHook = new RSerialize.CallHook() { @Override public Object eval(Object arg) { - return callCache.execute(SubstituteVirtualFrame.create(frame), hook, RCaller.create(frame, getOriginalCall()), null, new Object[]{arg}, null); + return callCache.execute(SubstituteVirtualFrame.create(frame), hook, RCaller.create(frame, getOriginalCall()), new Object[]{arg}, null); } }; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java index eddadcd858b150cc4ee5544107aed1931bcb23dd..79ba2deff626e7d39f093471d4326bae64af5500 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MakeUnique.java @@ -27,12 +27,20 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RStringSequence; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.ops.na.NACheck; @@ -40,8 +48,9 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck; @RBuiltin(name = "make.unique", kind = INTERNAL, parameterNames = {"names", "sep"}, behavior = PURE) public abstract class MakeUnique extends RBuiltinNode.Arg2 { - private final ConditionProfile namesProfile = ConditionProfile.createBinaryProfile(); - private final ConditionProfile duplicatesProfile = ConditionProfile.createBinaryProfile(); + @Child private ReuseNonSharedNode reuseNonSharedNode; + + private final ConditionProfile trivialSizeProfile = ConditionProfile.createBinaryProfile(); private final NACheck dummyCheck = NACheck.create(); // never triggered (used for vector update) static { @@ -52,49 +61,74 @@ public abstract class MakeUnique extends RBuiltinNode.Arg2 { } @Specialization - protected RAbstractStringVector makeUnique(RAbstractStringVector names, String sep) { - if (namesProfile.profile(names.getLength() == 0 || names.getLength() == 1)) { + protected RAbstractStringVector makeUnique(String names, @SuppressWarnings("unused") String sep) { + // a single string cannot have duplicates + return RDataFactory.createStringVectorFromScalar(names); + } + + @Specialization + protected RAbstractStringVector makeUnique(RStringVector names, String sep) { + if (trivialSizeProfile.profile(names.getLength() == 0 || names.getLength() == 1)) { return names; - } else { - // TODO: perhaps for longer vectors there is a faster algorithm using hash maps, but - // then it would probably have to be put on the slow path even for cases when no - // duplicates actually exist - int[] duplicates = new int[names.getLength()]; - boolean duplicatesExist = false; - for (int i = 0; i < duplicates.length; i++) { - if (duplicates[i] > 0) { - // already processed - continue; - } - String current = names.getDataAt(i); - int duplicatesCount = 0; - for (int j = i + 1; j < duplicates.length; j++) { - if (current.equals(names.getDataAt(j))) { - duplicatesExist = true; - duplicates[j] = ++duplicatesCount; - } + } + if (reuseNonSharedNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + reuseNonSharedNode = insert(ReuseNonSharedNode.create()); + } + + RStringVector reused = (RStringVector) reuseNonSharedNode.execute(names); + return doLargeVector(reused, sep); + } + + @Specialization + protected RAbstractStringVector makeUnique(RStringSequence names, @SuppressWarnings("unused") String sep) { + // a string sequence cannot have duplicates if stride is not zero + if (names.getStride() != 0) { + return names; + } + throw RInternalError.unimplemented("make.unique for string sequence with zero stride is not implemented"); + } + + @TruffleBoundary + protected RStringVector doLargeVector(RStringVector names, String sep) { + HashMap<String, AtomicInteger> keys = new HashMap<>(names.getLength()); + boolean containsDuplicates = false; + boolean containsClashes = true; + for (int i = 0; i < names.getLength(); i++) { + AtomicInteger value = new AtomicInteger(0); + String element = names.getDataAt(i); + AtomicInteger prev = keys.put(element, value); + if (prev != null) { + containsDuplicates = true; + value.incrementAndGet(); + if (!containsClashes) { + int lastIndexOf = element.lastIndexOf(sep); + // If an element contains the separator string followed by a digit, we may + // encounter clashes. + containsClashes = lastIndexOf != -1 && lastIndexOf + 1 < element.length() && Character.isDigit(element.charAt(lastIndexOf + 1)); } } - if (duplicatesProfile.profile(!duplicatesExist)) { - return names; - } else { - RStringVector newNames = names.materialize(); - if (newNames.isShared()) { - newNames = (RStringVector) newNames.copy(); - } - // start with 1 as the first one is never the duplicate - for (int i = 1; i < duplicates.length; i++) { - if (duplicates[i] > 0) { - newNames.updateDataAt(i, concat(newNames.getDataAt(i), sep, duplicates[i]), dummyCheck); - } + } + if (containsDuplicates) { + for (int i = 0; i < names.getLength(); i++) { + AtomicInteger atomicInteger = keys.get(names.getDataAt(i)); + int curCnt = atomicInteger.getAndIncrement() - 1; + if (curCnt > 0) { + String updatedElement; + do { + updatedElement = names.getDataAt(i) + sep + curCnt; + + // The generated string may already be in the vector. + if (containsClashes && keys.containsKey(updatedElement)) { + curCnt = atomicInteger.getAndIncrement() - 1; + } else { + break; + } + } while (true); + names.updateDataAt(i, updatedElement, dummyCheck); } - return newNames; } } - } - - @TruffleBoundary - private static String concat(String s1, String sep, int index) { - return s1 + sep + index; + return names; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java index afaa35a46f4ee13c6dd42ce27f0755e5700d3660..55a76080cb08370639afb5555aaf5e0a806f9f3f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java @@ -31,6 +31,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.BranchProfile; @@ -45,8 +46,11 @@ import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RIntSequence; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RScalar; +import com.oracle.truffle.r.runtime.data.RStringSequence; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; @@ -101,14 +105,19 @@ public abstract class Paste extends RBuiltinNode.Arg3 { } @Specialization - protected RStringVector pasteListNullSep(VirtualFrame frame, RAbstractListVector values, String sep, @SuppressWarnings("unused") RNull collapse) { + protected RAbstractStringVector pasteListNullSep(VirtualFrame frame, RAbstractListVector values, String sep, @SuppressWarnings("unused") RNull collapse) { int length = lengthProfile.profile(values.getLength()); if (hasNonNullElements(values, length)) { - String[] result = pasteListElements(frame, values, sep, length); - if (result == ONE_EMPTY_STRING) { - return RDataFactory.createEmptyStringVector(); + int seqPos = isStringSequence(values, length); + if (seqPos != -1) { + return createStringSequence(values, length, seqPos, sep); } else { - return RDataFactory.createStringVector(result, RDataFactory.COMPLETE_VECTOR); + String[] result = pasteListElements(frame, values, sep, length); + if (result == ONE_EMPTY_STRING) { + return RDataFactory.createEmptyStringVector(); + } else { + return RDataFactory.createStringVector(result, RDataFactory.COMPLETE_VECTOR); + } } } else { return RDataFactory.createEmptyStringVector(); @@ -253,4 +262,46 @@ public abstract class Paste extends RBuiltinNode.Arg3 { } return asCharacterNode; } + + /** + * Tests for pattern = { scalar } intSequence { scalar }. + */ + private static int isStringSequence(RAbstractListVector values, int length) { + int i = 0; + // consume prefix + while (i < length && isScalar(values.getDataAt(i))) { + i++; + } + if (i < length && values.getDataAt(i) instanceof RIntSequence) { + // consume suffix + int j = i + 1; + while (j < length && isScalar(values.getDataAt(j))) { + j++; + } + if (j == length) { + return i; + } + } + return -1; + } + + private static boolean isScalar(Object dataAt) { + return dataAt instanceof RScalar || dataAt instanceof String || dataAt instanceof Double || dataAt instanceof Integer || dataAt instanceof Byte; + } + + @TruffleBoundary + private static RStringSequence createStringSequence(RAbstractListVector values, int length, int seqPos, String sep) { + assert isStringSequence(values, length) != -1; + + StringBuilder prefix = new StringBuilder(); + for (int i = 0; i < seqPos; i++) { + prefix.append(values.getDataAt(i)).append(sep); + } + RIntSequence seq = (RIntSequence) values.getDataAt(seqPos); + StringBuilder suffix = new StringBuilder(); + for (int i = seqPos + 1; i < length; i++) { + suffix.append(values.getDataAt(i)).append(sep); + } + return RDataFactory.createStringSequence(prefix.toString(), suffix.toString(), seq.getStart(), seq.getStride(), seq.getLength()); + } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java index 650ab72158da049cc6119b59bdd5d7a7f471fade..b0a0f0e3cbbeeeb74c422358e005a9f5a822f3a9 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java @@ -17,7 +17,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.SUBSTITUTE; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.BranchProfile; @@ -27,6 +26,7 @@ import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.function.CallMatcherNode; import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; +import com.oracle.truffle.r.nodes.function.GetCallerFrameNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode; import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode; @@ -41,7 +41,6 @@ import com.oracle.truffle.r.runtime.RArguments.S3Args; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.ReturnException; -import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -59,24 +58,11 @@ public abstract class S3DispatchFunctions { @Child private S3FunctionLookupNode methodLookup; @Child private CallMatcherNode callMatcher; - private final ConditionProfile callerFrameSlowPath = ConditionProfile.createBinaryProfile(); - private final ConditionProfile topLevelFrameProfile = ConditionProfile.createBinaryProfile(); - protected Helper(boolean nextMethod) { methodLookup = S3FunctionLookupNode.create(true, nextMethod); callMatcher = CallMatcherNode.create(false); } - protected MaterializedFrame getCallerFrame(VirtualFrame frame) { - MaterializedFrame funFrame = RArguments.getCallerFrame(frame); - if (callerFrameSlowPath.profile(funFrame == null)) { - funFrame = Utils.getCallerFrame(frame, FrameAccess.MATERIALIZE).materialize(); - RError.performanceWarning("slow caller frame access in UseMethod dispatch"); - } - // S3 method can be dispatched from top-level where there is no caller frame - return topLevelFrameProfile.profile(funFrame == null) ? frame.materialize() : funFrame; - } - protected Object dispatch(VirtualFrame frame, String generic, RStringVector type, String group, MaterializedFrame callerFrame, MaterializedFrame genericDefFrame, ArgumentsSignature suppliedSignature, Object[] suppliedArguments) { Result lookupResult = methodLookup.execute(frame, generic, type, group, callerFrame, genericDefFrame); @@ -97,6 +83,7 @@ public abstract class S3DispatchFunctions { @Child private ClassHierarchyNode classHierarchyNode = ClassHierarchyNode.createForDispatch(true); @Child private PromiseCheckHelperNode promiseCheckHelper; + @Child private GetCallerFrameNode getCallerFrameNode = new GetCallerFrameNode(); @Child private Helper helper = new Helper(false); private final BranchProfile firstArgMissing = BranchProfile.create(); @@ -118,7 +105,7 @@ public abstract class S3DispatchFunctions { } RStringVector type = dispatchedObject == null ? RDataFactory.createEmptyStringVector() : classHierarchyNode.execute(dispatchedObject); - MaterializedFrame callerFrame = helper.getCallerFrame(frame); + MaterializedFrame callerFrame = getCallerFrameNode.execute(frame); MaterializedFrame genericDefFrame = RArguments.getEnclosingFrame(frame); ArgumentsSignature suppliedSignature = RArguments.getSuppliedSignature(frame); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java index ea2f8107dc40567fefc4e7bff43368127a0524d7..3a89f202b0f44b142a66a6364591ffe1948487cd 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SysFunctions.java @@ -55,6 +55,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinPackages; import com.oracle.truffle.r.runtime.RArguments; +import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.REnvVars; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; @@ -146,8 +147,9 @@ public class SysFunctions { @TruffleBoundary private static void doCheckNSLoad(MaterializedFrame frame, RAbstractStringVector values, boolean setting) { - Frame caller = Utils.getCallerFrame(frame, FrameAccess.READ_ONLY); - RFunction func = RArguments.getFunction(caller); + RCaller caller = RArguments.getCall(frame); + Frame callerFrame = Utils.getCallerFrame(caller, FrameAccess.READ_ONLY); + RFunction func = RArguments.getFunction(callerFrame); if (func.toString().equals(LOADNAMESPACE)) { if (setting) { RContext.getInstance().setNamespaceName(values.getDataAt(0)); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java index 626821a38aa55082fb3aaa99c9751aa448a45d17..5483988770fdc65ac8914b97e0e5e77558197827 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Unlist.java @@ -35,6 +35,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.base.UnlistNodeGen.RecursiveLengthNodeGen; +import com.oracle.truffle.r.nodes.builtin.base.UnlistNodeGen.UnlistLengthNodeGen; import com.oracle.truffle.r.nodes.control.RLengthNode; import com.oracle.truffle.r.nodes.unary.PrecedenceNode; import com.oracle.truffle.r.nodes.unary.PrecedenceNodeGen; @@ -75,12 +76,37 @@ public abstract class Unlist extends RBuiltinNode.Arg3 { } @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create(); - @Child private RLengthNode lengthNode; + @Child private UnlistLength lengthNode; @Child private RecursiveLength recursiveLengthNode; @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create(); @Child private Node hasSizeNode; @Child private ForeignArray2R foreignArray2RNode; + @ImportStatic({Message.class, RRuntime.class, ForeignArray2R.class}) + @TypeSystemReference(RTypes.class) + protected abstract static class UnlistLength extends Node { + + public abstract int execute(Object vector); + + @Child private RLengthNode lengthNode; + + @Specialization + protected int getLength(@SuppressWarnings("unused") RLanguage l) { + // language object do not get expanded - as such their length for the purpose of unlist + // is 1 + return 1; + } + + @Fallback + protected int getLength(Object operand) { + if (lengthNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + lengthNode = insert(RLengthNode.create()); + } + return lengthNode.executeInteger(operand); + } + } + @ImportStatic({Message.class, RRuntime.class, ForeignArray2R.class}) @TypeSystemReference(RTypes.class) protected abstract static class RecursiveLength extends Node { @@ -216,13 +242,13 @@ public abstract class Unlist extends RBuiltinNode.Arg3 { private int getLength(Object operand) { initLengthNode(); - return lengthNode.executeInteger(operand); + return lengthNode.execute(operand); } private void initLengthNode() { if (lengthNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - lengthNode = insert(RLengthNode.create()); + lengthNode = insert(UnlistLengthNodeGen.create()); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java index 135fea29b3990a92cf73aa9ca525e24c8f2eb8b0..4e58a26827823130d05262542f7a91929bce0238 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateSlot.java @@ -106,7 +106,7 @@ public abstract class UpdateSlot extends RBuiltinNode.Arg3 { if (cached.profile(currentFunction == checkSlotAssignFunction)) { // TODO: technically, someone could override checkAtAssignment function and access // the caller, but it's rather unlikely - checkAtAssignmentCall.execute(frame, checkSlotAssignFunction, RCaller.createInvalid(frame), null, new Object[]{objClass, name, valClass}, SIGNATURE, + checkAtAssignmentCall.execute(frame, checkSlotAssignFunction, RCaller.createInvalid(frame), new Object[]{objClass, name, valClass}, SIGNATURE, checkSlotAssignFunction.getEnclosingFrame(), null); } else { // slow path diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java index 9bef765b6372169ec18ff6220aa0238e414ef12d..06ab7c3d948fc06a2985e605e2f33bb0f0e16cec 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/WriteTable.java @@ -31,10 +31,6 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.conn.RConnection; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RLogicalVector; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -162,7 +158,7 @@ public abstract class WriteTable extends RExternalBuiltinNode.Arg11 { // if (i % 1000 == 999) // R_CheckUserInterrupt(); if (!(rnames instanceof RNull)) { - tmp.append(encodeElement2((RStringVector) rnames, i, quoteRn, qmethod, cdec)).append(csep); + tmp.append(encodeElement2((RAbstractStringVector) rnames, i, quoteRn, qmethod, cdec)).append(csep); } for (int j = 0; j < nc; j++) { Object xjObj = x.getDataAtAsObject(j); @@ -214,8 +210,8 @@ public abstract class WriteTable extends RExternalBuiltinNode.Arg11 { if (indx < 0 || indx >= x.getLength()) { throw new IllegalArgumentException("index out of range"); } - if (x instanceof RStringVector) { - RStringVector sx = (RStringVector) x; + if (x instanceof RAbstractStringVector) { + RAbstractStringVector sx = (RAbstractStringVector) x; String p0 = /* translateChar */sx.getDataAt(indx); return encodeStringElement(p0, quote, qmethod); } @@ -246,16 +242,16 @@ public abstract class WriteTable extends RExternalBuiltinNode.Arg11 { } private static boolean isna(RAbstractContainer x, int indx) { - if (x instanceof RLogicalVector) { - return RRuntime.isNA(((RLogicalVector) x).getDataAt(indx)); - } else if (x instanceof RDoubleVector) { - return RRuntime.isNA(((RDoubleVector) x).getDataAt(indx)); - } else if (x instanceof RIntVector) { - return RRuntime.isNA(((RIntVector) x).getDataAt(indx)); - } else if (x instanceof RStringVector) { - return RRuntime.isNA(((RStringVector) x).getDataAt(indx)); - } else if (x instanceof RComplexVector) { - RComplexVector cvec = (RComplexVector) x; + if (x instanceof RAbstractLogicalVector) { + return RRuntime.isNA(((RAbstractLogicalVector) x).getDataAt(indx)); + } else if (x instanceof RAbstractDoubleVector) { + return RRuntime.isNA(((RAbstractDoubleVector) x).getDataAt(indx)); + } else if (x instanceof RAbstractIntVector) { + return RRuntime.isNA(((RAbstractIntVector) x).getDataAt(indx)); + } else if (x instanceof RAbstractStringVector) { + return RRuntime.isNA(((RAbstractStringVector) x).getDataAt(indx)); + } else if (x instanceof RAbstractComplexVector) { + RAbstractComplexVector cvec = (RAbstractComplexVector) x; RComplex c = cvec.getDataAt(indx); return c.isNA(); } else { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java index 0ce9148bd595ef13b9a3a6a175f26ab6590cea02..7ce6f47b092713c0e5503f85b28e24f883381c98 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java @@ -25,11 +25,13 @@ package com.oracle.truffle.r.nodes.access.vector; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.r.nodes.access.vector.CachedExtractVectorNodeFactory.ExtractDimNamesNodeGen; import com.oracle.truffle.r.nodes.access.vector.CachedExtractVectorNodeFactory.SetNamesNodeGen; import com.oracle.truffle.r.nodes.access.vector.PositionsCheckNode.PositionProfile; import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode; @@ -278,7 +280,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { private Object extract(int dimensionIndex, RAbstractStringVector vector, Object pos, PositionProfile profile) { if (extractDimNames == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - extractDimNames = insert(new ExtractDimNamesNode(numberOfDimensions)); + extractDimNames = insert(ExtractDimNamesNodeGen.create(numberOfDimensions)); } return extractDimNames.extract(dimensionIndex, vector, pos, profile); } @@ -498,24 +500,45 @@ final class CachedExtractVectorNode extends CachedVectorNode { } } - private static class ExtractDimNamesNode extends Node { + abstract static class ExtractDimNamesNode extends Node { - @Children private final CachedExtractVectorNode[] extractNodes; + protected final int limit; + + @Child protected ExtractVectorNode fallbackExtractNode; ExtractDimNamesNode(int dimensions) { - this.extractNodes = new CachedExtractVectorNode[dimensions]; + // Support at most 2 different kinds of cached extract nodes per dimension. + limit = dimensions * 2; } - public Object extract(int dimensionIndex, RAbstractStringVector vector, Object position, PositionProfile profile) { - Object[] positions = new Object[]{position}; + protected abstract Object execute(int dimensionIndex, RAbstractStringVector vector, Object position, PositionProfile profile); + + protected boolean isSupported(CachedExtractVectorNode cachedExtractNode, RAbstractStringVector vector, Object position) { + return cachedExtractNode.isSupported(vector, new Object[]{position}, RLogical.TRUE, RLogical.TRUE); + } + + protected CachedExtractVectorNode createCached(RAbstractStringVector vector, Object position) { + return new CachedExtractVectorNode(ElementAccessMode.SUBSET, vector, new Object[]{position}, RLogical.TRUE, RLogical.TRUE, true); + } + + @Specialization(limit = "limit", guards = {"dimensionIndex == cachedIndex", "isSupported(cachedExtractNode, vector, position)"}) + public Object extractDimNamesCached(int dimensionIndex, RAbstractStringVector vector, Object position, PositionProfile profile, + @Cached("createCached(vector, position)") CachedExtractVectorNode cachedExtractNode, + @SuppressWarnings("unused") @Cached("dimensionIndex") int cachedIndex) { PositionProfile[] profiles = new PositionProfile[]{profile}; - if (extractNodes[dimensionIndex] == null) { + CompilerAsserts.partialEvaluationConstant(dimensionIndex); + return cachedExtractNode.apply(vector, new Object[]{position}, profiles, RLogical.TRUE, RLogical.TRUE); + } + + @Specialization(replaces = "extractDimNamesCached") + public Object extract(int dimensionIndex, RAbstractStringVector vector, Object position, @SuppressWarnings("unused") PositionProfile profile) { + if (fallbackExtractNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - extractNodes[dimensionIndex] = insert(new CachedExtractVectorNode(ElementAccessMode.SUBSET, vector, positions, RLogical.TRUE, RLogical.TRUE, false)); + fallbackExtractNode = insert(ExtractVectorNode.createRecursive(ElementAccessMode.SUBSET)); } CompilerAsserts.partialEvaluationConstant(dimensionIndex); - assert extractNodes[dimensionIndex].isSupported(vector, positions, RLogical.TRUE, RLogical.TRUE); - return extractNodes[dimensionIndex].apply(vector, positions, profiles, RLogical.TRUE, RLogical.TRUE); + Object[] positions = new Object[]{position}; + return fallbackExtractNode.apply(vector, positions, RLogical.TRUE, RLogical.TRUE); } } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java index 7118f008d8b60b50368ebf25865099e9680f6e10..bfe2fa60ef92b7a2a3388bbf4bdd56cb3ffb923c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/CopyOfRegAttributesNode.java @@ -30,9 +30,10 @@ import com.oracle.truffle.api.object.Property; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RAttributeStorage; import com.oracle.truffle.r.runtime.data.RAttributesLayout; import com.oracle.truffle.r.runtime.data.RVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.nodes.RBaseNode; /** @@ -52,60 +53,60 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode { @Child private GetFixedAttributeNode namesAttrGetter = GetFixedAttributeNode.createNames(); @Child private GetFixedAttributeNode classAttrGetter = GetFixedAttributeNode.createClass(); - public abstract void execute(RAbstractVector source, RVector<?> target); + public abstract void execute(RAttributable source, RAttributable target); public static CopyOfRegAttributesNode create() { return CopyOfRegAttributesNodeGen.create(); } @Specialization(guards = "source.getAttributes() == null") - protected void copyNoAttributes(@SuppressWarnings("unused") RAbstractVector source, @SuppressWarnings("unused") RVector<?> target) { + protected void copyNoAttributes(@SuppressWarnings("unused") RAttributeStorage source, @SuppressWarnings("unused") RAttributeStorage target) { // nothing to do } - protected static final boolean emptyAttributes(RAbstractVector source) { + protected static final boolean emptyAttributes(RAttributeStorage source) { DynamicObject attributes = source.getAttributes(); return attributes == null || attributes.isEmpty(); } @Specialization(guards = "emptyAttributes(source)", replaces = "copyNoAttributes") - protected void copyEmptyAttributes(@SuppressWarnings("unused") RAbstractVector source, @SuppressWarnings("unused") RVector<?> target) { + protected void copyEmptyAttributes(@SuppressWarnings("unused") RAttributeStorage source, @SuppressWarnings("unused") RAttributeStorage target) { // nothing to do } - protected final boolean onlyDimAttribute(RAbstractVector source) { + protected final boolean onlyDimAttribute(RAttributeStorage source) { DynamicObject attributes = source.getAttributes(); return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && dimAttrGetter.execute(attributes) != null; } @Specialization(guards = "onlyDimAttribute(source)") - protected void copyDimOnly(@SuppressWarnings("unused") RAbstractVector source, @SuppressWarnings("unused") RVector<?> target) { + protected void copyDimOnly(@SuppressWarnings("unused") RAttributeStorage source, @SuppressWarnings("unused") RAttributeStorage target) { // nothing to do } - protected final boolean onlyNamesAttribute(RAbstractVector source) { + protected final boolean onlyNamesAttribute(RAttributeStorage source) { DynamicObject attributes = source.getAttributes(); return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && namesAttrGetter.execute(attributes) != null; } @Specialization(guards = "onlyNamesAttribute(source)") - protected void copyNamesOnly(@SuppressWarnings("unused") RAbstractVector source, @SuppressWarnings("unused") RVector<?> target) { + protected void copyNamesOnly(@SuppressWarnings("unused") RAttributeStorage source, @SuppressWarnings("unused") RAttributeStorage target) { // nothing to do } - protected final boolean onlyClassAttribute(RAbstractVector source) { + protected final boolean onlyClassAttribute(RAttributeStorage source) { DynamicObject attributes = source.getAttributes(); return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && classAttrGetter.execute(attributes) != null; } @Specialization(guards = "onlyClassAttribute(source)") - protected void copyClassOnly(RAbstractVector source, RVector<?> target) { + protected void copyClassOnly(RAttributeStorage source, RVector<?> target) { Object classAttr = classAttrGetter.execute(source.getAttributes()); target.initAttributes(RAttributesLayout.createClass(classAttr)); } @Specialization - protected void copyGeneric(RAbstractVector source, RVector<?> target) { + protected void copyGeneric(RAttributeStorage source, RAttributeStorage target) { DynamicObject orgAttributes = source.getAttributes(); if (orgAttributes != null) { Shape shape = orgAttributes.getShape(); @@ -120,4 +121,14 @@ public abstract class CopyOfRegAttributesNode extends RBaseNode { } } } + + @Specialization(guards = "!isAttributeStorage(source)") + @SuppressWarnings("unused") + protected void copyNothing(RAttributable source, RAttributable target) { + // do nothing, just pass + } + + protected static boolean isAttributeStorage(Object o) { + return o instanceof RAttributeStorage; + } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveRegAttributesNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveRegAttributesNode.java new file mode 100644 index 0000000000000000000000000000000000000000..d8e270b43dfe05a2c478d401644809f3c75f1422 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/RemoveRegAttributesNode.java @@ -0,0 +1,140 @@ +/* + * 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.List; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.api.object.Property; +import com.oracle.truffle.api.object.Shape; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.RemoveClassAttributeNode; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RAttributeStorage; + +/** + * Remove all regular attributes. This node is in particular useful if we reuse containers with + * attributes but the reusing builtin should actually return a fresh container with no regular + * attributes. + */ +public abstract class RemoveRegAttributesNode extends AttributeAccessNode { + + private final ConditionProfile sizeOneProfile = ConditionProfile.createBinaryProfile(); + + @Child private GetFixedAttributeNode dimAttrGetter = GetFixedAttributeNode.createDim(); + @Child private GetFixedAttributeNode namesAttrGetter = GetFixedAttributeNode.createNames(); + @Child private GetFixedAttributeNode classAttrGetter = GetFixedAttributeNode.createClass(); + @Child private RemoveClassAttributeNode removeClassAttributeNode; + + protected RemoveRegAttributesNode() { + } + + public static RemoveRegAttributesNode create() { + return RemoveRegAttributesNodeGen.create(); + } + + public abstract void execute(RAttributable attrs); + + @Specialization(guards = "source.getAttributes() == null") + protected void copyNoAttributes(@SuppressWarnings("unused") RAttributeStorage source) { + // nothing to do + } + + protected static final boolean emptyAttributes(RAttributeStorage source) { + DynamicObject attributes = source.getAttributes(); + return attributes == null || attributes.isEmpty(); + } + + @Specialization(guards = "emptyAttributes(source)", replaces = "copyNoAttributes") + protected void copyEmptyAttributes(@SuppressWarnings("unused") RAttributeStorage source) { + // nothing to do + } + + protected final boolean onlyDimAttribute(RAttributeStorage source) { + DynamicObject attributes = source.getAttributes(); + return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && dimAttrGetter.execute(attributes) != null; + } + + @Specialization(guards = "onlyDimAttribute(source)") + protected void copyDimOnly(@SuppressWarnings("unused") RAttributeStorage source) { + // nothing to do + } + + protected final boolean onlyNamesAttribute(RAttributeStorage source) { + DynamicObject attributes = source.getAttributes(); + return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && namesAttrGetter.execute(attributes) != null; + } + + @Specialization(guards = "onlyNamesAttribute(source)") + protected void copyNamesOnly(@SuppressWarnings("unused") RAttributeStorage source) { + // nothing to do + } + + protected final boolean onlyClassAttribute(RAttributeStorage source) { + DynamicObject attributes = source.getAttributes(); + return attributes != null && sizeOneProfile.profile(attributes.size() == 1) && classAttrGetter.execute(attributes) != null; + } + + @Specialization(guards = "onlyClassAttribute(source)") + protected void copyClassOnly(RAttributeStorage source) { + if (removeClassAttributeNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + removeClassAttributeNode = insert(RemoveClassAttributeNode.create()); + } + removeClassAttributeNode.execute(source); + } + + @Specialization + protected void removeGeneric(RAttributeStorage source) { + DynamicObject orgAttributes = source.getAttributes(); + assert orgAttributes != null; + Shape shape = orgAttributes.getShape(); + List<Property> properties = shape.getPropertyList(); + for (int i = 0; i < properties.size(); i++) { + Property p = properties.get(i); + String name = (String) p.getKey(); + if (name != RRuntime.DIM_ATTR_KEY && name != RRuntime.DIMNAMES_ATTR_KEY && name != RRuntime.NAMES_ATTR_KEY) { + removeAttrFallback(orgAttributes, name); + } + } + } + + @TruffleBoundary + protected void removeAttrFallback(DynamicObject attrs, String name) { + attrs.delete(name); + } + + @Specialization(guards = "!isAttributeStorage(source)") + @SuppressWarnings("unused") + protected void copyNothing(RAttributable source) { + // do nothing, just pass + } + + protected static boolean isAttributeStorage(RAttributable o) { + return o instanceof RAttributeStorage; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java index 88f0ec886749048b8b13f2d7ba6eb64f664ab8e2..fa01f31ea9879cd1422a07ccad89f66df1d9a40a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/CallMatcherNode.java @@ -16,6 +16,7 @@ import java.util.function.Supplier; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.NodeCost; @@ -32,6 +33,7 @@ import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RArguments.DispatchArgs; +import com.oracle.truffle.r.runtime.RArguments.S3Args; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RVisibility; @@ -263,8 +265,9 @@ public abstract class CallMatcherNode extends RBaseNode { String genFunctionName = functionName == null ? function.getName() : functionName; Supplier<RSyntaxElement> argsSupplier = RCallerHelper.createFromArguments(genFunctionName, preparePermutation, suppliedArguments, suppliedSignature); RCaller caller = genFunctionName == null ? RCaller.createInvalid(frame, parent) : RCaller.create(frame, parent, argsSupplier); + MaterializedFrame callerFrame = dispatchArgs instanceof S3Args ? ((S3Args) dispatchArgs).callEnv : null; try { - return call.execute(frame, cachedFunction, caller, null, reorderedArgs, matchedArgs.getSignature(), cachedFunction.getEnclosingFrame(), dispatchArgs); + return call.execute(frame, cachedFunction, caller, callerFrame, reorderedArgs, matchedArgs.getSignature(), cachedFunction.getEnclosingFrame(), dispatchArgs); } finally { visibility.executeAfterCall(frame, caller); } @@ -343,8 +346,9 @@ public abstract class CallMatcherNode extends RBaseNode { RCaller caller = genFunctionName == null ? RCaller.createInvalid(frame, parent) : RCaller.create(frame, RCallerHelper.createFromArguments(genFunctionName, new RArgsValuesAndNames(reorderedArgs.getArguments(), ArgumentsSignature.empty(reorderedArgs.getLength())))); + MaterializedFrame callerFrame = (dispatchArgs instanceof S3Args) ? ((S3Args) dispatchArgs).callEnv : null; try { - return call.execute(frame, function, caller, null, reorderedArgs.getArguments(), reorderedArgs.getSignature(), function.getEnclosingFrame(), dispatchArgs); + return call.execute(frame, function, caller, callerFrame, reorderedArgs.getArguments(), reorderedArgs.getSignature(), function.getEnclosingFrame(), dispatchArgs); } finally { visibility.executeAfterCall(frame, caller); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java index 226573d72f40586343af33015ea00f34d9b2e53b..bf283b26035874d27723ac6863c20439a148c5bd 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetCallerFrameNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.nodes.function; -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.Frame; @@ -30,6 +29,7 @@ import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.profiles.BranchProfile; +import com.oracle.truffle.r.runtime.CallerFrameClosure; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RError; @@ -38,7 +38,8 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode; public final class GetCallerFrameNode extends RBaseNode { - private final BranchProfile topLevelProfile = BranchProfile.create(); + private final BranchProfile frameAvailableProfile = BranchProfile.create(); + private final BranchProfile closureProfile = BranchProfile.create(); @CompilationFinal private boolean slowPathInitialized; @Override @@ -47,38 +48,46 @@ public final class GetCallerFrameNode extends RBaseNode { } public MaterializedFrame execute(Frame frame) { - MaterializedFrame funFrame = RArguments.getCallerFrame(frame); - if (funFrame == null) { - if (!slowPathInitialized) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - slowPathInitialized = true; - } - notifyCallers(RArguments.getCall(frame)); - if (slowPathInitialized) { - RError.performanceWarning("slow caller frame access"); - } - Frame callerFrame = Utils.getCallerFrame(frame, FrameAccess.MATERIALIZE); - if (callerFrame != null) { - return callerFrame.materialize(); - } else { - topLevelProfile.enter(); - // S3 method can be dispatched from top-level where there is no caller frame - return frame.materialize(); + Object callerFrameObject = RArguments.getCallerFrame(frame); + if (callerFrameObject instanceof MaterializedFrame) { + frameAvailableProfile.enter(); + return (MaterializedFrame) callerFrameObject; + } + if (callerFrameObject instanceof CallerFrameClosure) { + closureProfile.enter(); + CallerFrameClosure closure = (CallerFrameClosure) callerFrameObject; + RCaller parent = RArguments.getCall(frame); + MaterializedFrame slowPathFrame = notifyCallers(closure, parent); + if (slowPathFrame != null) { + return slowPathFrame; } } - return funFrame; + assert callerFrameObject == null; + + // S3 method can be dispatched from top-level where there is no caller frame + // Since RArguments does not allow to create arguments with a 'null' caller frame, this + // must be the top level case. + return frame.materialize(); } @TruffleBoundary - private void notifyCallers(RCaller call) { - RCaller current = call; - while (current != null && current.isPromise()) { - current = current.getParent(); + private static MaterializedFrame notifyCallers(CallerFrameClosure closure, RCaller parent) { + + // inform the responsible call node to create a caller frame + closure.setNeedsCallerFrame(); + + // if interpreted, we will have a materialized frame in the closure + MaterializedFrame materializedCallerFrame = closure.getMaterializedCallerFrame(); + if (materializedCallerFrame != null) { + return materializedCallerFrame; } - if (current != null && current.isValidCaller() && current.getSyntaxNode() instanceof RCallNode) { - if (!((RCallNode) current.getSyntaxNode()).setNeedsCallerFrame()) { - slowPathInitialized = false; - } + RError.performanceWarning("slow caller frame access"); + // for now, get it on the very slow path + Frame callerFrame = Utils.getCallerFrame(parent, FrameAccess.MATERIALIZE); + if (callerFrame != null) { + return callerFrame.materialize(); } + return null; } + } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java index b2d5ebe471e2af85b928e377576af4bf6ee3c6d8..c3a0a12254405c034ad0cbd1c12137c5ebe61d76 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java @@ -521,8 +521,40 @@ public abstract class PromiseNode extends RNode { } } - @ExplodeLoop private int evaluateArguments(VirtualFrame frame, Object[] evaluatedArgs) { + if (evaluatedArgs.length <= 32) { + return evaluateArgumentsExplode(frame, evaluatedArgs); + } + return evaluateArgumentsLoop(frame, evaluatedArgs); + } + + @ExplodeLoop + private int evaluateArgumentsExplode(VirtualFrame frame, Object[] evaluatedArgs) { + int size = 0; + boolean containsVarargs = false; + for (int i = 0; i < varargs.length; i++) { + Object argValue = varargs[i].execute(frame); + if (argsValueAndNamesProfile.profile(argValue instanceof RArgsValuesAndNames)) { + containsVarargs = true; + size += ((RArgsValuesAndNames) argValue).getLength(); + evaluatedArgs[i] = argValue; + } else { + size++; + evaluatedArgs[i] = promiseCheckHelper.checkEvaluate(frame, argValue); + } + if (evaluatedArgs[i] == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + throw RInternalError.shouldNotReachHere("evaluated argument must not be null"); + } + } + if (containsVarargProfile.profile(containsVarargs)) { + return size; + } else { + return -1; + } + } + + private int evaluateArgumentsLoop(VirtualFrame frame, Object[] evaluatedArgs) { int size = 0; boolean containsVarargs = false; for (int i = 0; i < varargs.length; i++) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java index 58a993f8712f6aac3c59d263b5e5aacc19866943..b44c463f465a08c5b3f99e4c3a0fa5af461edfaf 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java @@ -31,7 +31,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; -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.NodeChild; @@ -70,8 +69,7 @@ import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.interop.Foreign2R; -import com.oracle.truffle.r.runtime.interop.R2Foreign; +import com.oracle.truffle.r.runtime.CallerFrameClosure; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RArguments.S3Args; import com.oracle.truffle.r.runtime.RArguments.S3DefaultArguments; @@ -95,13 +93,14 @@ import com.oracle.truffle.r.runtime.data.REmpty; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; -import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RPromise.Closure; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; +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.RBaseNode; import com.oracle.truffle.r.runtime.nodes.RFastPathNode; @@ -154,14 +153,6 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS // needed for INTERNAL_GENERIC calls: @Child private FunctionDispatch internalDispatchCall; - private final Assumption needsNoCallerFrame = Truffle.getRuntime().createAssumption("no caller frame"); - - public boolean setNeedsCallerFrame() { - boolean value = !needsNoCallerFrame.isValid(); - needsNoCallerFrame.invalidate(); - return value; - } - protected RCaller createCaller(VirtualFrame frame, RFunction function) { if (explicitArgs == null) { return RCaller.create(frame, this); @@ -956,6 +947,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS private final RootCallTarget cachedTarget; private final FastPathFactory fastPathFactory; private final RVisibility fastPathVisibility; + private final boolean containsDispatch; DispatchedCallNode(RootCallTarget cachedTarget, RCallNode originalCall) { super(originalCall); @@ -965,9 +957,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS this.fastPath = fastPathFactory == null ? null : fastPathFactory.create(); this.fastPathVisibility = fastPathFactory == null ? null : fastPathFactory.getVisibility(); this.visibility = fastPathFactory == null ? null : SetVisibilityNode.create(); - if (root.containsDispatch()) { - originalCall.setNeedsCallerFrame(); - } + this.containsDispatch = root.containsDispatch(); } @Override @@ -990,14 +980,48 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS if (needsSplitting(cachedTarget)) { call.getCallNode().cloneCallTarget(); } + if (containsDispatch) { + call.setNeedsCallerFrame(); + } } - MaterializedFrame callerFrame = /* CompilerDirectives.inInterpreter() || */originalCall.needsNoCallerFrame.isValid() ? null : frame.materialize(); + MaterializedFrame callerFrame = s3Args != null ? s3Args.callEnv : null; + RCaller caller = originalCall.createCaller(frame, function); - return call.execute(frame, function, originalCall.createCaller(frame, function), callerFrame, orderedArguments.getArguments(), orderedArguments.getSignature(), - function.getEnclosingFrame(), s3Args); + return call.execute(frame, function, caller, callerFrame, orderedArguments.getArguments(), orderedArguments.getSignature(), function.getEnclosingFrame(), s3Args); } } + public static final class InvalidateNoCallerFrame extends CallerFrameClosure { + + private final Assumption needsNoCallerFrame; + private final MaterializedFrame frame; + + protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame) { + this.needsNoCallerFrame = needsNoCallerFrame; + this.frame = null; + } + + protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame, MaterializedFrame frame) { + this.needsNoCallerFrame = needsNoCallerFrame; + this.frame = frame; + } + + @Override + public boolean setNeedsCallerFrame() { + if (needsNoCallerFrame.isValid()) { + needsNoCallerFrame.invalidate(); + return true; + } + return false; + } + + @Override + public MaterializedFrame getMaterializedCallerFrame() { + return frame; + } + + } + @Override public RSyntaxElement getSyntaxLHS() { return getFunction() == null ? RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "FUN", true) : getFunction().asRSyntaxNode(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionBaseNode.java new file mode 100644 index 0000000000000000000000000000000000000000..10aee1f08cfcc1f2abd4849015d564442c39037e --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionBaseNode.java @@ -0,0 +1,121 @@ +/* + * 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.function.call; + +import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.runtime.CallerFrameClosure; + +public abstract class CallRFunctionBaseNode extends Node { + + protected final Assumption needsNoCallerFrame = Truffle.getRuntime().createAssumption("no caller frame"); + protected final CallerFrameClosure invalidateNoCallerFrame = new InvalidateNoCallerFrame(needsNoCallerFrame); + private static final CallerFrameClosure DUMMY = new DummyCallerFrameClosure(); + + public boolean setNeedsCallerFrame() { + boolean value = !needsNoCallerFrame.isValid(); + needsNoCallerFrame.invalidate(); + return value; + } + + private Object getCallerFrameClosure(MaterializedFrame callerFrame) { + if (CompilerDirectives.inInterpreter()) { + return new InvalidateNoCallerFrame(needsNoCallerFrame, callerFrame); + } + return invalidateNoCallerFrame; + } + + private Object getCallerFrameClosure(VirtualFrame callerFrame) { + if (CompilerDirectives.inInterpreter()) { + return new InvalidateNoCallerFrame(needsNoCallerFrame, callerFrame != null ? callerFrame.materialize() : null); + } + return invalidateNoCallerFrame; + } + + protected final Object getCallerFrameObject(VirtualFrame curFrame, MaterializedFrame callerFrame, boolean topLevel) { + if (needsNoCallerFrame.isValid()) { + return getCallerFrameClosure(callerFrame); + } else { + if (callerFrame != null) { + return callerFrame; + } else if (topLevel) { + return DUMMY; + } + return curFrame.materialize(); + } + } + + protected final Object getCallerFrameObject(VirtualFrame callerFrame) { + return needsNoCallerFrame.isValid() ? getCallerFrameClosure(callerFrame) : callerFrame.materialize(); + } + + private static final class DummyCallerFrameClosure extends CallerFrameClosure { + + @Override + public boolean setNeedsCallerFrame() { + return false; + } + + @Override + public MaterializedFrame getMaterializedCallerFrame() { + return null; + } + + } + + public static final class InvalidateNoCallerFrame extends CallerFrameClosure { + + private final Assumption needsNoCallerFrame; + private final MaterializedFrame frame; + + protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame) { + this.needsNoCallerFrame = needsNoCallerFrame; + this.frame = null; + } + + protected InvalidateNoCallerFrame(Assumption needsNoCallerFrame, MaterializedFrame frame) { + this.needsNoCallerFrame = needsNoCallerFrame; + this.frame = frame; + } + + @Override + public boolean setNeedsCallerFrame() { + if (needsNoCallerFrame.isValid()) { + needsNoCallerFrame.invalidate(); + return true; + } + return false; + } + + @Override + public MaterializedFrame getMaterializedCallerFrame() { + return frame; + } + + } + +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java index d319b9f8c05f15928c8e2d3def5fb1b8d14fc6b6..2f0010a56085aff14a2f76677eddb6bffa089ed4 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionCachedNode.java @@ -30,7 +30,6 @@ import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.IndirectCallNode; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; @@ -41,7 +40,7 @@ import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.data.RFunction; @NodeInfo(cost = NodeCost.NONE) -public abstract class CallRFunctionCachedNode extends Node { +public abstract class CallRFunctionCachedNode extends CallRFunctionBaseNode { @Child private SetVisibilityNode visibility = SetVisibilityNode.create(); @@ -51,14 +50,21 @@ public abstract class CallRFunctionCachedNode extends Node { this.cacheLimit = cacheLimit; } - public final Object execute(VirtualFrame frame, RFunction function, RCaller call, MaterializedFrame callerFrame, Object[] evaluatedArgs, DispatchArgs dispatchArgs) { - Object[] callArgs = RArguments.create(function, call, callerFrame, evaluatedArgs, dispatchArgs); + public final Object execute(VirtualFrame frame, RFunction function, RCaller call, Object[] evaluatedArgs, DispatchArgs dispatchArgs) { + Object[] callArgs = RArguments.create(function, call, getCallerFrameObject(frame), evaluatedArgs, dispatchArgs); + return execute(frame, function.getTarget(), callArgs, call); + } + + public final Object execute(VirtualFrame frame, RFunction function, RCaller call, Object[] evaluatedArgs, + ArgumentsSignature suppliedSignature, MaterializedFrame enclosingFrame, DispatchArgs dispatchArgs) { + Object[] callArgs = RArguments.create(function, call, getCallerFrameObject(frame), evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs); return execute(frame, function.getTarget(), callArgs, call); } public final Object execute(VirtualFrame frame, RFunction function, RCaller call, MaterializedFrame callerFrame, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, MaterializedFrame enclosingFrame, DispatchArgs dispatchArgs) { - Object[] callArgs = RArguments.create(function, call, callerFrame, evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs); + boolean topLevel = call == null || call.getDepth() == 0; + Object[] callArgs = RArguments.create(function, call, getCallerFrameObject(frame, callerFrame, topLevel), evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs); return execute(frame, function.getTarget(), callArgs, call); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java index ee1b587d0e3ccb584dd31d81d7bd75f9d612986d..5e92e7411b9f0abff7864fc5ea9b737c0dbf1ccb 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/call/CallRFunctionNode.java @@ -27,7 +27,6 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; @@ -38,7 +37,7 @@ import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.data.RFunction; @NodeInfo(cost = NodeCost.NONE) -public final class CallRFunctionNode extends Node { +public final class CallRFunctionNode extends CallRFunctionBaseNode { @Child private DirectCallNode callNode; @Child private SetVisibilityNode visibility = SetVisibilityNode.create(); @@ -51,9 +50,21 @@ public final class CallRFunctionNode extends Node { return new CallRFunctionNode(callTarget); } - public Object execute(VirtualFrame frame, RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, + public Object execute(VirtualFrame frame, RFunction function, RCaller caller, MaterializedFrame candidate, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, MaterializedFrame enclosingFrame, DispatchArgs dispatchArgs) { - Object[] callArgs = RArguments.create(function, caller, callerFrame, evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs); + + boolean topLevel = caller == null || caller.getDepth() == 0; + Object[] callArgs = RArguments.create(function, caller, getCallerFrameObject(frame, candidate, topLevel), evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs); + try { + return callNode.call(callArgs); + } finally { + visibility.executeAfterCall(frame, caller); + } + } + + public Object execute(VirtualFrame frame, RFunction function, RCaller caller, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, + MaterializedFrame enclosingFrame, DispatchArgs dispatchArgs) { + Object[] callArgs = RArguments.create(function, caller, getCallerFrameObject(frame), evaluatedArgs, suppliedSignature, enclosingFrame, dispatchArgs); try { return callNode.call(callArgs); } finally { @@ -66,11 +77,13 @@ public final class CallRFunctionNode extends Node { } public static Object executeSlowpath(RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, DispatchArgs dispatchArgs) { + assert callerFrame != null; Object[] callArgs = RArguments.create(function, caller, callerFrame, evaluatedArgs, suppliedSignature, function.getEnclosingFrame(), dispatchArgs); return executeSlowpath(function, caller, callerFrame, callArgs); } public static Object executeSlowpath(RFunction function, RCaller caller, MaterializedFrame callerFrame, Object[] evaluatedArgs, DispatchArgs dispatchArgs) { + assert callerFrame != null; Object[] callArgs = RArguments.create(function, caller, callerFrame, evaluatedArgs, dispatchArgs); return executeSlowpath(function, caller, callerFrame, callArgs); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java index 6a7d5fa17632485aa4bf2f7d75f8284435146ab3..28fe8a13b4c821b874880fe25407165efb736743 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java @@ -36,6 +36,8 @@ import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; /** * Contains helper nodes related to factors, special R class of {@link RAbstractIntVector}. Note: @@ -86,11 +88,11 @@ public final class RFactorNodes { Object attr = attrAccess.execute(factor.getAttributes()); // Convert scalars to vector if necessary - RVector<?> vec; + RAbstractVector vec; if (nonScalarLevels.profile(attr instanceof RVector)) { vec = (RVector<?>) attr; } else if (attr != null) { - vec = (RVector<?>) RRuntime.asAbstractVector(attr); // scalar to vector + vec = (RAbstractVector) RRuntime.asAbstractVector(attr); // scalar to vector } else { notVectorBranch.enter(); // N.B: when a factor is lacking the 'levels' attribute, GNU R uses range 1:14331272 @@ -100,14 +102,14 @@ public final class RFactorNodes { } // Convert to string vector if necessary - if (stringVectorLevels.profile(vec instanceof RStringVector)) { - return (RStringVector) vec; + if (stringVectorLevels.profile(vec instanceof RAbstractStringVector)) { + return ((RAbstractStringVector) vec).materialize(); } else { if (castString == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); castString = insert(CastStringNodeGen.create(false, false, false)); } - RStringVector slevels = (RStringVector) castString.executeString(vec); + RStringVector slevels = ((RAbstractStringVector) castString.executeString(vec)).materialize(); return RDataFactory.createStringVector(slevels.getDataWithoutCopying(), RDataFactory.COMPLETE_VECTOR); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java index a9912feba90ea092a00e3a2f725d2b12e3ab4aaf..1803e88efbfda4b92f6f6c4b95f1097ec6477f8b 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java @@ -131,7 +131,7 @@ abstract class LoadMethod extends RBaseNode { if (cached.profile(currentFunction == loadMethodFunction)) { // TODO: technically, someone could override loadMethod function and access the // caller, but it's rather unlikely - ret = (RFunction) loadMethodCall.execute(frame, loadMethodFunction, caller, null, new Object[]{fdef, fname, REnvironment.frameToEnvironment(frame.materialize())}, SIGNATURE, + ret = (RFunction) loadMethodCall.execute(frame, loadMethodFunction, caller, new Object[]{fdef, fname, REnvironment.frameToEnvironment(frame.materialize())}, SIGNATURE, loadMethodFunction.getEnclosingFrame(), null); } else { // slow path diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java index ebec5af6e485d4e7016ec3162bad1b624eaaeb59..ccdeba3324a6a9a8afe7cdc0d8bf40746d32054a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java @@ -33,7 +33,9 @@ import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RIntSequence; import com.oracle.truffle.r.runtime.data.RLanguage; +import com.oracle.truffle.r.runtime.data.RStringSequence; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; @@ -70,12 +72,26 @@ public abstract class CastStringNode extends CastStringBaseNode { return ret; } + protected boolean isIntSequence(RAbstractContainer c) { + return c instanceof RIntSequence; + } + @Specialization protected RStringVector doStringVector(RStringVector vector) { return vector; } @Specialization + protected RStringSequence doStringSequence(RStringSequence vector) { + return vector; + } + + @Specialization + protected RStringSequence doIntSequence(RIntSequence vector) { + return RDataFactory.createStringSequence("", "", vector.getStart(), vector.getStride(), vector.getLength()); + } + + @Specialization(guards = "!isIntSequence(operandIn)") protected RStringVector doAbstractContainer(RAbstractContainer operandIn, @Cached("createClassProfile()") ValueProfile operandProfile, @Cached("createBinaryProfile()") ConditionProfile isLanguageProfile) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/PrecedenceNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/PrecedenceNode.java index 4b8964a8834e3e73e9d8f2bf510c0b36efca0797..c0d2eab3b9722d69e76595be79f602093daf553d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/PrecedenceNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/PrecedenceNode.java @@ -55,6 +55,7 @@ import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RRawVector; import com.oracle.truffle.r.runtime.data.RS4Object; +import com.oracle.truffle.r.runtime.data.RStringSequence; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -157,6 +158,11 @@ public abstract class PrecedenceNode extends RBaseNode { return STRING_PRECEDENCE; } + @Specialization + protected int doString(RStringSequence val, boolean recursive) { + return STRING_PRECEDENCE; + } + @Specialization protected int doFunction(RFunction func, boolean recursive) { return LIST_PRECEDENCE; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/CallerFrameClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/CallerFrameClosure.java new file mode 100644 index 0000000000000000000000000000000000000000..10c963766c8cc8b6cd7d88249711c1263a2b60b2 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/CallerFrameClosure.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.runtime; + +import com.oracle.truffle.api.frame.MaterializedFrame; + +public abstract class CallerFrameClosure { + + /** + * Inform the call node to subsequently provide the caller frame. + */ + public abstract boolean setNeedsCallerFrame(); + + /** + * Retrieve the materialized caller frame if available (i.e. interpreter only). + */ + public abstract MaterializedFrame getMaterializedCallerFrame(); + +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java index 1f41cbf04d1065e45362ffe5744d36e0c2a93e65..3c6ffeaa58399b08bf11b16a0cd183b45ebdf039 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RArguments.java @@ -170,10 +170,10 @@ public final class RArguments { return frame.getArguments().length - INDEX_ARGUMENTS; } - public static Object[] create(RFunction function, RCaller call, MaterializedFrame callerFrame, Object[] evaluatedArgs, DispatchArgs dispatchArgs) { + public static Object[] create(RFunction function, RCaller call, Object callerFrameObject, Object[] evaluatedArgs, DispatchArgs dispatchArgs) { ArgumentsSignature formalSignature = ((HasSignature) function.getRootNode()).getSignature(); CompilerAsserts.neverPartOfCompilation(); - return create(function, call, callerFrame, evaluatedArgs, ArgumentsSignature.empty(formalSignature.getLength()), function.getEnclosingFrame(), dispatchArgs); + return create(function, call, callerFrameObject, evaluatedArgs, ArgumentsSignature.empty(formalSignature.getLength()), function.getEnclosingFrame(), dispatchArgs); } /** @@ -187,11 +187,12 @@ public final class RArguments { * function as well as additional information like the parent frame or supplied * signature. */ - public static Object[] create(RFunction function, RCaller call, MaterializedFrame callerFrame, Object[] evaluatedArgs, + public static Object[] create(RFunction function, RCaller call, Object callerFrameObject, Object[] evaluatedArgs, ArgumentsSignature suppliedSignature, MaterializedFrame enclosingFrame, DispatchArgs dispatchArgs) { assert suppliedSignature.getLength() == evaluatedArgs.length : "suppliedSignature should match the evaluatedArgs (see Java docs)."; assert evaluatedArgs != null : "RArguments.create evaluatedArgs is null"; assert call != null : "RArguments.create call is null"; + assert callerFrameObject != null : "RArguments.create callerFrameObject is null"; // Eventually we want to have this invariant // assert call != null || REnvironment.isGlobalEnvFrame(callerFrame); @@ -199,7 +200,7 @@ public final class RArguments { a[INDEX_ENVIRONMENT] = null; a[INDEX_FUNCTION] = function; a[INDEX_CALL] = call; - a[INDEX_CALLER_FRAME] = callerFrame; + a[INDEX_CALLER_FRAME] = callerFrameObject; a[INDEX_ENCLOSING_FRAME] = enclosingFrame; a[INDEX_DISPATCH_ARGS] = dispatchArgs; a[INDEX_IS_IRREGULAR] = false; @@ -226,9 +227,11 @@ public final class RArguments { return a; } - public static MaterializedFrame getCallerFrame(Frame frame) { + public static Object getCallerFrame(Frame frame) { Object[] args = frame.getArguments(); - return (MaterializedFrame) args[INDEX_CALLER_FRAME]; + // a 'null' caller frame is still allowed in case of environments + assert args[INDEX_CALLER_FRAME] != null || args[INDEX_ENVIRONMENT] != null; + return args[INDEX_CALLER_FRAME]; } public static DispatchArgs getDispatchArgs(Frame frame) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java index f44a3cfa50fda6a71b4f6d89a442bfbc7e241c2c..5dc6ed526481acc3228f4795854c88f5fa73af48 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java @@ -448,8 +448,8 @@ public final class Utils { * TODO Calls to this method should be validated with respect to whether promise evaluation is * in progress and replaced with use of {@code FrameDepthNode}. */ - public static Frame getCallerFrame(Frame frame, FrameAccess fa) { - RCaller parent = RArguments.getCall(frame); + public static Frame getCallerFrame(RCaller caller, FrameAccess fa) { + RCaller parent = caller; while (parent != null && parent.isPromise()) { parent = parent.getParent(); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java index 06f3c97902603be00b2dd49044ba68de9b30138f..619bc2a75a2caff43fd491cb19def9571921693b 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java @@ -297,6 +297,10 @@ public final class RDataFactory { return createStringVector(new String[]{RRuntime.STRING_NA}, false); } + public static RStringSequence createStringSequence(String prefix, String suffix, int start, int stride, int length) { + return traceDataCreated(new RStringSequence(prefix, suffix, start, stride, length)); + } + public static RComplexVector createEmptyComplexVector() { return createComplexVector(new double[0], true); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java new file mode 100644 index 0000000000000000000000000000000000000000..03c11fa316b416042f33958257930f2e024c2fee --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java @@ -0,0 +1,148 @@ +/* + * 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.runtime.data; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.data.closures.RClosures; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public class RStringSequence extends RSequence implements RAbstractStringVector { + + private final int start; + private final int stride; + private final String prefix; + private final String suffix; + + protected RStringSequence(String prefix, String suffix, int start, int stride, int length) { + super(length); + this.start = start; + this.stride = stride; + this.prefix = prefix != null ? prefix : ""; + this.suffix = suffix != null ? suffix : ""; + } + + private static void resizeData(String[] newData, String[] data, int oldDataLength, String fill) { + if (newData.length > oldDataLength) { + if (fill != null) { + for (int i = data.length; i < oldDataLength; i++) { + newData[i] = fill; + } + } else { + for (int i = oldDataLength, j = 0; i < newData.length; ++i, j = Utils.incMod(j, oldDataLength)) { + newData[i] = data[j]; + } + } + } + } + + @Override + public RStringVector copyResized(int size, boolean fillNA) { + String[] data = new String[size]; + populateVectorData(data); + resizeData(data, data, getLength(), fillNA ? RRuntime.STRING_NA : null); + return RDataFactory.createStringVector(data, !(fillNA && size > getLength())); + } + + @Override + public RVector<?> copyResizedWithDimensions(int[] newDimensions, boolean fillNA) { + int size = newDimensions[0] * newDimensions[1]; + String[] data = new String[size]; + populateVectorData(data); + resizeData(data, data, getLength(), fillNA ? RRuntime.STRING_NA : null); + return RDataFactory.createStringVector(data, !(fillNA && size > getLength()), newDimensions); + } + + @Override + public RDoubleVector createEmptySameType(int newLength, boolean newIsComplete) { + return RDataFactory.createDoubleVector(new double[newLength], newIsComplete); + } + + @Override + public String getDataAt(int index) { + assert index >= 0 && index < getLength(); + return prefix + (start + stride * index) + suffix; + } + + private void populateVectorData(String[] result) { + int current = start; + for (int i = 0; i < result.length && i < getLength(); i++) { + result[i] = prefix + current + suffix; + current += stride; + } + } + + @Override + public RStringVector materialize() { + return internalCreateVector(); + } + + public int getStart() { + return start; + } + + public int getEnd() { + return start + (getLength() - 1) * stride; + } + + public int getStride() { + return stride; + } + + @Override + public Object getStartObject() { + return prefix + start + suffix; + } + + @Override + public Object getStrideObject() { + return Integer.toString(stride); + } + + @Override + protected RStringVector internalCreateVector() { + return copyResized(getLength(), false); + } + + @Override + public RAbstractVector castSafe(RType type, ConditionProfile isNAProfile, boolean keepAttributes) { + switch (type) { + case Character: + return this; + case List: + return RClosures.createToListVector(this, keepAttributes); + default: + return null; + } + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return "[\"" + getStartObject() + "\" - \"" + prefix + getEnd() + suffix + "\"]"; + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java index ad2756524f8c0ca8b4ea1a7677fea16f55ab2c33..846193104cbe95021aa0b18859b180ce2e6c6235 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java @@ -37,6 +37,7 @@ import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.SuppressFBWarnings; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; 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 com.oracle.truffle.r.runtime.nodes.RBaseNode; import com.oracle.truffle.r.runtime.ops.na.NACheck; @@ -302,7 +303,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement throw invokingNode.error(RError.Message.DIMNAMES_DONT_MATCH_EXTENT, i + 1); } } else { - RStringVector dimVector = (RStringVector) dimObject; + RAbstractStringVector dimVector = (RAbstractStringVector) dimObject; if (dimVector == null) { newDimNames.updateDataAt(i, RNull.instance, null); } else if (dimVector.getLength() != dimensions[i]) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java index 1cc4294efa9d58eb83760855b4e1a146a83c62dd..1c9527d80690831ccb3b65296d0be34deb133d50 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RClosures.java @@ -31,6 +31,7 @@ import com.oracle.truffle.r.runtime.data.RIntSequence; import com.oracle.truffle.r.runtime.data.RIntVector; import com.oracle.truffle.r.runtime.data.RLogicalVector; import com.oracle.truffle.r.runtime.data.RRawVector; +import com.oracle.truffle.r.runtime.data.RStringSequence; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; @@ -225,6 +226,10 @@ public class RClosures { return new RStringToListVectorClosure(vector, keepAttributes); } + public static RAbstractListVector createToListVector(RStringSequence vector, boolean keepAttributes) { + return new RStringSequenceToListVectorClosure(vector, keepAttributes); + } + // Factor to vector public static RAbstractVector createFactorToVector(RAbstractIntVector factor, boolean withNames, RAbstractVector levels) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToListVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToListVectorClosure.java index f6ef8f334c63b9c3fde8cf8f676d23d21fb9352f..80ede7abf8eeed21598c3597dc9d817ccd629f58 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToListVectorClosure.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToListVectorClosure.java @@ -34,6 +34,7 @@ import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RLogicalVector; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RRawVector; +import com.oracle.truffle.r.runtime.data.RStringSequence; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; @@ -224,6 +225,26 @@ final class RStringToListVectorClosure extends RToListVectorClosure { } } +final class RStringSequenceToListVectorClosure extends RToListVectorClosure { + + private final RStringSequence vector; + + RStringSequenceToListVectorClosure(RStringSequence vector, boolean keepAttributes) { + super(keepAttributes); + this.vector = vector; + } + + @Override + public RStringSequence getVector() { + return vector; + } + + @Override + public String getDataAt(int index) { + return vector.getDataAt(index); + } +} + final class RRawToListVectorClosure extends RToListVectorClosure { private final RRawVector vector; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java index 146301963b7405eaf7e9c06776afcd32f287cfea..977cc6c1a7a9fabd532de93fb4957c0cd5e142f7 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/gnur/SEXPTYPE.java @@ -34,6 +34,7 @@ import com.oracle.truffle.r.runtime.data.RPromise.EagerPromise; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RRawVector; import com.oracle.truffle.r.runtime.data.RS4Object; +import com.oracle.truffle.r.runtime.data.RStringSequence; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RUnboundValue; @@ -57,7 +58,7 @@ public enum SEXPTYPE { INTSXP(13, RIntVector.class, RIntSequence.class, Integer.class), /* integer vectors */ REALSXP(14, RDoubleVector.class, RDoubleSequence.class, Double.class), /* real variables */ CPLXSXP(15, RComplexVector.class, RComplex.class), /* complex variables */ - STRSXP(16, RStringVector.class, String.class), /* string vectors */ + STRSXP(16, RStringVector.class, RStringSequence.class, String.class), /* string vectors */ DOTSXP(17, RArgsValuesAndNames.class), /* dot-dot-dot object */ ANYSXP(18), /* make "any" args work */ VECSXP(19, RList.class), /* generic vectors */ diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 5288c6fc4ac7f00ba3f6e2bf05cd1327feefb666..23aeeb5945798641fbd90e60e94ccec19d95c57e 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -6351,6 +6351,14 @@ complex(0) #argv <- list(1L);as.complex(argv[[1]]); [1] 1+0i +##com.oracle.truffle.r.test.builtins.TestBuiltin_asdataframe.testWithDimnames# +#{ v1 <- matrix(rep(1.1, 16), 4, 4, dimnames=list(c('a', 'b', 'c', 'd'), c('e', 'f', 'g', 'h'))); v0 <- matrix(rep(1.2, 16), 4, 4, dimnames=list(1L:4L, c('e', 'f', 'g', 'h'))); as.data.frame(v1); as.data.frame(v0) } + e f g h +1 1.2 1.2 1.2 1.2 +2 1.2 1.2 1.2 1.2 +3 1.2 1.2 1.2 1.2 +4 1.2 1.2 1.2 1.2 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_asdataframe.testasdataframe1# #argv <- structure(list(x = structure(c(3.5, 2, 1.7, 0.40625, 0.5, 0.882, 4, 2, 2, 4, 2, 3, 0.625, 0.5, 0.444444444444444, 0, 0, 0.333333333333333, 0.833333333333333, 1, 0.333333333333333, 0.5, 0.666666666666667, 0.666666666666667, 0.166666666666667, 0, 0.5), .Dim = c(3L, 9L), .Dimnames = list(c('q1.csv', 'q2.csv', 'q3.csv'), c('effsize', 'constraint', 'outdegree', 'indegree', 'efficiency', 'hierarchy', 'centralization', 'gden', 'ego.gden')))), .Names = 'x');do.call('as.data.frame', argv) effsize constraint outdegree indegree efficiency hierarchy @@ -34667,6 +34675,38 @@ Error in make.unique(1) : 'names' must be a character vector #{ make.unique(character()) } character(0) +##com.oracle.truffle.r.test.builtins.TestBuiltin_makeunique.testMakeUnique5# +#{ make.unique(paste0('a', 1:10)) } + [1] "a1" "a2" "a3" "a4" "a5" "a6" "a7" "a8" "a9" "a10" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_makeunique.testMakeUnique5# +#{ make.unique(rep('a', 10)) } + [1] "a" "a.1" "a.2" "a.3" "a.4" "a.5" "a.6" "a.7" "a.8" "a.9" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_makeunique.testMakeUnique6# +#{ make.unique(paste('a', 1:10, sep = '.')) } + [1] "a.1" "a.2" "a.3" "a.4" "a.5" "a.6" "a.7" "a.8" "a.9" "a.10" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_makeunique.testMakeUnique6# +#{ make.unique(paste0('a', 1:10)) } + [1] "a1" "a2" "a3" "a4" "a5" "a6" "a7" "a8" "a9" "a10" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_makeunique.testMakeUnique7# +#{ make.unique(c('a', 'a', 'a.2', 'a'), sep = '.') } +[1] "a" "a.1" "a.2" "a.3" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_makeunique.testMakeUnique7# +#{ make.unique(c('a.1', 'a.2', 'a', 'a'), sep = '.') } +[1] "a.1" "a.2" "a" "a.3" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_makeunique.testMakeUnique7# +#{ make.unique(c('a.2', 'a.2', 'a', 'a', 'a'), sep = '.') } +[1] "a.2" "a.2.1" "a" "a.1" "a.3" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_makeunique.testMakeUnique7# +#{ make.unique(c('a.2', 'a.2', 'a.3', 'a.3', 'a', 'a', 'a'), sep = '.') } +[1] "a.2" "a.2.1" "a.3" "a.3.1" "a" "a.1" "a.4" + ##com.oracle.truffle.r.test.builtins.TestBuiltin_makeunique.testmakeunique1# #argv <- list(c('A', 'B', 'C', 'D', 'E', 'F'), '.'); .Internal(make.unique(argv[[1]], argv[[2]])) [1] "A" "B" "C" "D" "E" "F" @@ -72372,6 +72412,12 @@ a.b a a.b a2 a3 "1" "2" "3" +##com.oracle.truffle.r.test.builtins.TestBuiltin_unlist.testUnlist# +#{ unlist(list(quote(for(i in seq(1)) print(i))), recursive=F) } +[[1]] +for (i in seq(1)) print(i) + + ##com.oracle.truffle.r.test.builtins.TestBuiltin_unlist.testUnlist# #{ x <- list("a", c("b", "c"), list("d", list("e"))) ; unlist(x) } [1] "a" "b" "c" "d" "e" diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asdataframe.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asdataframe.java index 477c36e02f7447cea98b3c6d66c5501a337b5813..ed681dbc29804f4f272d4561df777e5787915c90 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asdataframe.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asdataframe.java @@ -4,7 +4,7 @@ * http://www.gnu.org/licenses/gpl-2.0.html * * Copyright (c) 2014, Purdue University - * Copyright (c) 2014, 2016, Oracle and/or its affiliates + * Copyright (c) 2014, 2017, Oracle and/or its affiliates * * All rights reserved. */ @@ -22,5 +22,11 @@ public class TestBuiltin_asdataframe extends TestBase { public void testasdataframe1() { assertEval("argv <- structure(list(x = structure(c(3.5, 2, 1.7, 0.40625, 0.5, 0.882, 4, 2, 2, 4, 2, 3, 0.625, 0.5, 0.444444444444444, 0, 0, 0.333333333333333, 0.833333333333333, 1, 0.333333333333333, 0.5, 0.666666666666667, 0.666666666666667, 0.166666666666667, 0, 0.5), .Dim = c(3L, 9L), .Dimnames = list(c('q1.csv', 'q2.csv', 'q3.csv'), c('effsize', 'constraint', 'outdegree', 'indegree', 'efficiency', 'hierarchy', 'centralization', 'gden', 'ego.gden')))), .Names = 'x');" + "do.call('as.data.frame', argv)"); + + } + + @Test + public void testWithDimnames() { + assertEval("{ v1 <- matrix(rep(1.1, 16), 4, 4, dimnames=list(c('a', 'b', 'c', 'd'), c('e', 'f', 'g', 'h'))); v0 <- matrix(rep(1.2, 16), 4, 4, dimnames=list(1L:4L, c('e', 'f', 'g', 'h'))); as.data.frame(v1); as.data.frame(v0) }"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_makeunique.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_makeunique.java index db726d9db92d7e40ed5f7b2dce447fbd9a5ff9d8..a6263d3959e3fe2a2ffea6d0c2385e9a6cb3377d 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_makeunique.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_makeunique.java @@ -4,7 +4,7 @@ * http://www.gnu.org/licenses/gpl-2.0.html * * Copyright (c) 2012-2014, Purdue University - * Copyright (c) 2013, 2016, Oracle and/or its affiliates + * Copyright (c) 2013, 2017, Oracle and/or its affiliates * * All rights reserved. */ @@ -37,6 +37,28 @@ public class TestBuiltin_makeunique extends TestBase { assertEval("argv <- list(character(0), '.'); .Internal(make.unique(argv[[1]], argv[[2]]))"); } + @Test + public void testMakeUnique5() { + assertEval("{ make.unique(rep('a', 10)) }"); + assertEval("{ make.unique(paste0('a', 1:10)) }"); + } + + @Test + public void testMakeUnique6() { + // test string sequences + assertEval("{ make.unique(paste0('a', 1:10)) }"); + assertEval("{ make.unique(paste('a', 1:10, sep = '.')) }"); + } + + @Test + public void testMakeUnique7() { + // test clashes + assertEval("{ make.unique(c('a', 'a', 'a.2', 'a'), sep = '.') }"); + assertEval("{ make.unique(c('a.1', 'a.2', 'a', 'a'), sep = '.') }"); + assertEval("{ make.unique(c('a.2', 'a.2', 'a', 'a', 'a'), sep = '.') }"); + assertEval("{ make.unique(c('a.2', 'a.2', 'a.3', 'a.3', 'a', 'a', 'a'), sep = '.') }"); + } + @Test public void testMakeUnique() { assertEval("{ make.unique(\"a\") }"); @@ -54,6 +76,6 @@ public class TestBuiltin_makeunique extends TestBase { assertEval("{ .Internal(make.unique(c(\"7\", \"42\"), character())) }"); assertEval("{ .Internal(make.unique(c(\"7\", \"42\"), c(\".\", \".\"))) }"); assertEval("{ .Internal(make.unique(c(\"7\", \"42\"), NULL)) }"); - } + } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_unlist.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_unlist.java index 7beb5839d2c2f90561a96c652fe6e333d68da693..ea57dc309ce7add318414dc3c97e44faaea48977 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_unlist.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_unlist.java @@ -338,6 +338,8 @@ public class TestBuiltin_unlist extends TestBase { assertEval("{ x <- list(1,list(2,3),4) ; z <- list(x,x) ; u <- list(z,z) ; u[[c(2,2,3)]] <- 6 ; unlist(u) }"); assertEval("{ x<-quote(f(1,2)); y<-function(z) 42; l<-list(x, y, NULL); y<-unlist(l); c(length(y), typeof(y)) }"); + + assertEval("{ unlist(list(quote(for(i in seq(1)) print(i))), recursive=F) }"); } @Test