diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java index 62a3e4bb2b873db16ebc06b620aced31690a5563..5ff5d597cf36b3956e332061d0db965f6e28ce95 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java @@ -51,13 +51,15 @@ import com.oracle.truffle.r.nodes.RASTBuilder; import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.access.ConstantNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinPackages; -import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNode; +import com.oracle.truffle.r.nodes.builtin.base.printer.ValuePrinterNode; import com.oracle.truffle.r.nodes.control.BreakException; import com.oracle.truffle.r.nodes.control.NextException; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; +import com.oracle.truffle.r.nodes.function.CallMatcherNode.CallMatcherGenericNode; import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation; -import com.oracle.truffle.r.runtime.JumpToTopLevelException; +import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.FastROptions; +import com.oracle.truffle.r.runtime.JumpToTopLevelException; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RError; @@ -66,8 +68,8 @@ import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RParserFactory; import com.oracle.truffle.r.runtime.RProfile; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE; import com.oracle.truffle.r.runtime.RSource; +import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE; import com.oracle.truffle.r.runtime.ReturnException; import com.oracle.truffle.r.runtime.SubstituteVirtualFrame; import com.oracle.truffle.r.runtime.ThreadTimings; @@ -76,6 +78,7 @@ import com.oracle.truffle.r.runtime.Utils.DebugExitException; import com.oracle.truffle.r.runtime.VirtualEvalFrame; import com.oracle.truffle.r.runtime.context.Engine; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RFunction; @@ -84,6 +87,7 @@ 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.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.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -381,7 +385,7 @@ final class REngine implements Engine, Engine.Timings { @Override @TruffleBoundary - public Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, Object... args) { + public Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, RStringVector names, Object... args) { assert frame == null || caller != null; MaterializedFrame actualFrame = frame; if (actualFrame == null) { @@ -393,7 +397,17 @@ final class REngine implements Engine, Engine.Timings { actualFrame = current.materialize(); } } - Object[] rArgs = RArguments.create(func, caller == null ? RArguments.getCall(actualFrame) : caller, actualFrame, args, null); + RArgsValuesAndNames reorderedArgs = CallMatcherGenericNode.reorderArguments(args, func, + names == null ? ArgumentsSignature.empty(args.length) : ArgumentsSignature.get(names.getDataWithoutCopying()), false, + RError.NO_CALLER); + Object[] newArgs = reorderedArgs.getArguments(); + for (int i = 0; i < newArgs.length; i++) { + Object arg = newArgs[i]; + if (arg instanceof RPromise) { + newArgs[i] = PromiseHelperNode.evaluateSlowPath(null, (RPromise) arg); + } + } + Object[] rArgs = RArguments.create(func, caller == null ? RArguments.getCall(actualFrame) : caller, actualFrame, newArgs, null); return func.getTarget().call(rArgs); } @@ -570,7 +584,7 @@ final class REngine implements Engine, Engine.Timings { result = RRuntime.asAbstractVector(result); // this supports printing of non-R values (via toString for now) if (result instanceof RTypedValue) { - return PrettyPrinterNode.prettyPrintDefault(result); + return ValuePrinterNode.prettyPrint(result); } else if (result == null) { return "[external object (null)]"; } else if (result instanceof TruffleObject) { 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 29700d0b926722999fa95f84fde571c2ebeb4468..4939a7e6690cc8f6a80366fc5950fe72ea08dc0a 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 @@ -366,14 +366,14 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { @Override public Object callback(RFunction f, Object[] args) { - boolean gd = DebugHandling.globalDisable(true); + boolean gd = RContext.getInstance().stateInstrumentation.setDebugGloballyDisabled(true); try { - return RContext.getEngine().evalFunction(f, null, null, args); + return RContext.getEngine().evalFunction(f, null, null, null, args); } catch (ReturnException ex) { // cannot throw return exceptions further up. return ex.getResult(); } finally { - DebugHandling.globalDisable(gd); + RContext.getInstance().stateInstrumentation.setDebugGloballyDisabled(gd); } } @@ -646,7 +646,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { @Override public boolean enableDebug(RFunction func, boolean once) { - return DebugHandling.enableDebug(func, "", RNull.instance, once); + return DebugHandling.enableDebug(func, "", RNull.instance, once, false); } @Override diff --git a/com.oracle.truffle.r.native/gnur/Makefile.gnur b/com.oracle.truffle.r.native/gnur/Makefile.gnur index 76eb523030ffa5275c1111b968117073b6311ec0..238eb6c3e5a21fa21ec597b8d78257f57b055d68 100644 --- a/com.oracle.truffle.r.native/gnur/Makefile.gnur +++ b/com.oracle.truffle.r.native/gnur/Makefile.gnur @@ -116,7 +116,7 @@ endif $(GNUR_HOME)/Makefile: ed $(GNUR_HOME)/src/extra/xz/Makefile.in < patchXzMakefile - (cd $(GNUR_HOME); ./configure --with-x=no --without-recommended-packages $(GNUR_CONFIG_FLAGS) > gnur_configure.log 2>&1) + (cd $(GNUR_HOME); ./configure --with-x=no --without-recommended-packages --enable-memory-profiling $(GNUR_CONFIG_FLAGS) > gnur_configure.log 2>&1) build: $(GNUR_HOME)/bin/R diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java index 90def9d1d66e671944f5d9db7dbce3a4ab77cf64..8e8df708cc2813a6e1311a8115502b8328734c75 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java @@ -69,6 +69,7 @@ import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypes; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; @RBuiltin(name = "as.vector", kind = INTERNAL, parameterNames = {"x", "mode"}) public abstract class AsVector extends RBuiltinNode { @@ -207,12 +208,20 @@ public abstract class AsVector extends RBuiltinNode { } @Specialization(guards = "modeIsPairList(mode)") + @TruffleBoundary protected Object asVectorPairList(RList x, @SuppressWarnings("unused") String mode) { // TODO implement non-empty element list conversion; this is a placeholder for type test if (x.getLength() == 0) { return RNull.instance; } else { - throw RError.nyi(RError.SHOW_CALLER, "non-empty lists"); + Object list = RNull.instance; + RStringVector names = x.getNames(); + for (int i = x.getLength() - 1; i >= 0; i--) { + Object name = names == null ? RNull.instance : RDataFactory.createSymbolInterned(names.getDataAt(i)); + Object data = x.getDataAt(i); + list = RDataFactory.createPairList(data, list, name); + } + return list; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index baa600759e5a7f148c1d9195bdd6bad536a4f611..87d627da486027bc7e0850cc681e71bc99b6fb8f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -581,6 +581,9 @@ public class BasePackage extends RBuiltinPackage { add(TraceFunctions.PrimTrace.class, TraceFunctionsFactory.PrimTraceNodeGen::create); add(TraceFunctions.PrimUnTrace.class, TraceFunctionsFactory.PrimUnTraceNodeGen::create); add(TraceFunctions.TraceOnOff.class, TraceFunctionsFactory.TraceOnOffNodeGen::create); + add(TraceFunctions.Tracemem.class, TraceFunctionsFactory.TracememNodeGen::create); + add(TraceFunctions.Retracemem.class, TraceFunctionsFactory.RetracememNodeGen::create); + add(TraceFunctions.Untracemem.class, TraceFunctionsFactory.UntracememNodeGen::create); add(Transpose.class, TransposeNodeGen::create); add(TrigExpFunctions.Acos.class, TrigExpFunctionsFactory.AcosNodeGen::create); add(TrigExpFunctions.Acosh.class, TrigExpFunctionsFactory.AcoshNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java index ce364a8e0471b9ab7be948c354bace2715bd96b7..1c7d8acffacd364516e4f6b1a9bce4bb91e0a347 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Complex.java @@ -22,62 +22,54 @@ */ package com.oracle.truffle.r.nodes.builtin.base; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.defaultValue; import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.LoopConditionProfile; import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; import com.oracle.truffle.r.runtime.RBuiltin; -import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RComplexVector; import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.ops.na.NACheck; @RBuiltin(name = "complex", kind = INTERNAL, parameterNames = {"length.out", "real", "imaginary"}) public abstract class Complex extends RBuiltinNode { - private static final RDoubleVector ZERO = RDataFactory.createDoubleVectorFromScalar(0.0); - @Override protected void createCasts(CastBuilder casts) { - casts.toInteger(0); - } - - @SuppressWarnings("unused") - @Specialization(guards = "resultEmpty(lengthOut, realAbsVec, imaginaryAbsVec)") - protected RComplexVector complexEmpty(int lengthOut, RAbstractDoubleVector realAbsVec, RAbstractDoubleVector imaginaryAbsVec) { - return RDataFactory.createEmptyComplexVector(); + casts.arg("length.out").asIntegerVector().findFirst(0); + casts.arg("real").map(defaultValue(RDataFactory.createEmptyDoubleVector())).asDoubleVector(); + casts.arg("imaginary").map(defaultValue(RDataFactory.createEmptyDoubleVector())).asDoubleVector(); } - @Specialization(guards = "!resultEmpty(lengthOut, realAbsVec, imaginaryAbsVec)") - protected RComplexVector complex(int lengthOut, RAbstractDoubleVector realAbsVec, RAbstractDoubleVector imaginaryAbsVec) { - RDoubleVector real = checkLength(realAbsVec); - RDoubleVector imaginary = checkLength(imaginaryAbsVec); - int realLength = real.getLength(); - int imaginaryLength = imaginary.getLength(); - int length = Math.max(Math.max(realLength, imaginaryLength), lengthOut); - boolean complete = RDataFactory.COMPLETE_VECTOR; + @Specialization + protected RComplexVector complex(int lengthOut, RAbstractDoubleVector real, RAbstractDoubleVector imaginary, // + @Cached("create()") NACheck realNA, // + @Cached("create()") NACheck imaginaryNA, // + @Cached("create()") VectorLengthProfile realLengthProfile, // + @Cached("create()") VectorLengthProfile imaginaryLengthProfile, // + @Cached("create()") VectorLengthProfile lengthProfile, // + @Cached("createCountingProfile()") LoopConditionProfile loopProfile) { + int realLength = realLengthProfile.profile(real.getLength()); + int imaginaryLength = imaginaryLengthProfile.profile(imaginary.getLength()); + int length = lengthProfile.profile(Math.max(Math.max(lengthOut, realLength), imaginaryLength)); double[] data = new double[length << 1]; - for (int i = 0; i < data.length; i += 2) { - data[i] = real.getDataAt((i >> 1) % realLength); - data[i + 1] = imaginary.getDataAt((i >> 1) % imaginaryLength); - if (RRuntime.isNA(data[i]) || RRuntime.isNA(data[i + 1])) { - complete = RDataFactory.INCOMPLETE_VECTOR; - } - } - return RDataFactory.createComplexVector(data, complete); - } - - private static RDoubleVector checkLength(RAbstractDoubleVector v) { - if (v.getLength() == 0) { - return ZERO; - } else { - return v.materialize(); + realNA.enable(real); + imaginaryNA.enable(imaginary); + loopProfile.profileCounted(length); + for (int i = 0; loopProfile.inject(i < data.length); i += 2) { + double realValue = realLength == 0 ? 0 : real.getDataAt((i >> 1) % realLength); + double imaginaryValue = imaginaryLength == 0 ? 0 : imaginary.getDataAt((i >> 1) % imaginaryLength); + data[i] = realValue; + data[i + 1] = imaginaryValue; + realNA.check(realValue); + imaginaryNA.check(imaginaryValue); } - } - - protected static boolean resultEmpty(int lengthOut, RAbstractDoubleVector realAbsVec, RAbstractDoubleVector imaginaryAbsVec) { - return lengthOut == 0 && realAbsVec.getLength() == 0 && imaginaryAbsVec.getLength() == 0; + return RDataFactory.createComplexVector(data, realNA.neverSeenNA() && imaginaryNA.neverSeenNA()); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java index 02acf9fe42d316abed1979ff6a69697d981cabb2..306d58f0e1a6e0b312e129a47f5ab7faf76033ad 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DebugFunctions.java @@ -47,7 +47,7 @@ public class DebugFunctions { protected void doDebug(RFunction fun, Object text, Object condition, boolean once) throws RError { // GnuR does not generate an error for builtins, but debug (obviously) has no effect if (!fun.isBuiltin()) { - if (!DebugHandling.enableDebug(fun, text, condition, once)) { + if (!DebugHandling.enableDebug(fun, text, condition, once, false)) { throw RError.error(this, RError.Message.GENERIC, "failed to attach debug handler (not instrumented?)"); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java index cbf5f639747597685c6fce213ad7f1661bcb94ac..58a270898eb117dd079565f80757abdce5344b30 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NChar.java @@ -22,8 +22,10 @@ */ package com.oracle.truffle.r.nodes.builtin.base; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asIntegerVector; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asStringVector; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; @@ -34,11 +36,9 @@ import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode; import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.CastStringNodeGen; -import com.oracle.truffle.r.nodes.unary.ConversionFailedException; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RIntVector; @@ -70,11 +70,7 @@ public abstract class NChar extends RBuiltinNode { CompilerDirectives.transferToInterpreterAndInvalidate(); convertString = insert(CastStringNodeGen.create(false, false, false, false)); } - try { - return (String) convertString.executeString(content); - } catch (ConversionFailedException e) { - throw RError.error(this, RError.Message.TYPE_EXPECTED, RType.Character.getName()); - } + return (String) convertString.executeString(content); } @SuppressWarnings("unused") diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java index 69a5311f651d88637f52e3a560c49693531a713f..08378721add61691818828c4ca4ce5ea436999ba 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/NZChar.java @@ -29,11 +29,8 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.CastStringNodeGen; -import com.oracle.truffle.r.nodes.unary.ConversionFailedException; import com.oracle.truffle.r.runtime.RBuiltin; -import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RLogicalVector; import com.oracle.truffle.r.runtime.data.RNull; @@ -49,11 +46,7 @@ public abstract class NZChar extends RBuiltinNode { CompilerDirectives.transferToInterpreterAndInvalidate(); convertString = insert(CastStringNodeGen.create(false, true, false, false)); } - try { - return (String) convertString.execute(content); - } catch (ConversionFailedException e) { - throw RError.error(this, RError.Message.TYPE_EXPECTED, RType.Character.getName()); - } + return (String) convertString.execute(content); } private static byte isNonZeroLength(String s) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java deleted file mode 100644 index fd9176181cbeff8b626880e1ab6c876a2b9c62ca..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java +++ /dev/null @@ -1,1869 +0,0 @@ -/* - * Copyright (c) 2013, 2016, 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.builtin.base; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.api.TruffleLanguage; -import com.oracle.truffle.api.dsl.NodeChild; -import com.oracle.truffle.api.dsl.NodeChildren; -import com.oracle.truffle.api.dsl.NodeField; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; -import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.IndirectCallNode; -import com.oracle.truffle.api.nodes.RootNode; -import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.nodes.RRootNode; -import com.oracle.truffle.r.nodes.access.ConstantNode; -import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNodeGen.PrettyPrinterSingleListElementNodeGen; -import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNodeGen.PrettyPrinterSingleVectorElementNodeGen; -import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNodeGen.PrintDimNodeGen; -import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNodeGen.PrintVector2DimNodeGen; -import com.oracle.truffle.r.nodes.builtin.base.PrettyPrinterNodeGen.PrintVectorMultiDimNodeGen; -import com.oracle.truffle.r.nodes.function.FormalArguments; -import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode; -import com.oracle.truffle.r.nodes.helpers.RFactorNodes; -import com.oracle.truffle.r.nodes.unary.CastStringNode; -import com.oracle.truffle.r.nodes.unary.CastStringNodeGen; -import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RArguments; -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.conn.SocketConnections; -import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.data.RAttributable; -import com.oracle.truffle.r.runtime.data.RAttributeProfiles; -import com.oracle.truffle.r.runtime.data.RAttributes; -import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute; -import com.oracle.truffle.r.runtime.data.RBuiltinDescriptor; -import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RDouble; -import com.oracle.truffle.r.runtime.data.RExpression; -import com.oracle.truffle.r.runtime.data.RExternalPtr; -import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RLanguage; -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.RPairList; -import com.oracle.truffle.r.runtime.data.RPromise; -import com.oracle.truffle.r.runtime.data.RRaw; -import com.oracle.truffle.r.runtime.data.RS4Object; -import com.oracle.truffle.r.runtime.data.RString; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.RSymbol; -import com.oracle.truffle.r.runtime.data.RVector; -import com.oracle.truffle.r.runtime.data.closures.RClosures; -import com.oracle.truffle.r.runtime.data.closures.RFactorToStringVectorClosure; -import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -import com.oracle.truffle.r.runtime.env.REnvironment; -import com.oracle.truffle.r.runtime.nodes.RNode; -import com.oracle.truffle.r.runtime.ops.na.NACheck; - -@SuppressWarnings("unused") -@NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "listElementName", type = RNode.class), @NodeChild(value = "quote", type = RNode.class), - @NodeChild(value = "right", type = RNode.class)}) -@NodeField(name = "printingAttributes", type = boolean.class) -public abstract class PrettyPrinterNode extends RNode { - - @Override - public abstract Object execute(VirtualFrame frame); - - public abstract Object executeString(int o, Object listElementName, byte quote, byte right); - - public abstract Object executeString(double o, Object listElementName, byte quote, byte right); - - public abstract Object executeString(byte o, Object listElementName, byte quote, byte right); - - public abstract Object executeString(Object o, Object listElementName, byte quote, byte right); - - @Child private PrettyPrinterNode attributePrettyPrinter; - @Child private PrettyPrinterNode recursivePrettyPrinter; - @Child private PrettyPrinterSingleListElementNode singleListElementPrettyPrinter; - @Child private PrettyPrinterSingleVectorElementNode singleVectorElementPrettyPrinter; - @Child private PrintVectorMultiDimNode multiDimPrinter; - - @Child private NumericalFunctions.Re re = NumericalFunctionsFactory.ReNodeGen.create(null); - @Child private NumericalFunctions.Im im = NumericalFunctionsFactory.ImNodeGen.create(null); - - @Child private IndirectCallNode indirectCall = Truffle.getRuntime().createIndirectCallNode(); - - private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); - - protected abstract boolean isPrintingAttributes(); - - private static final FrameAccess FRAME_ACCESS = FrameAccess.NONE; - - private String prettyPrintAttribute(Object o) { - if (attributePrettyPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - attributePrettyPrinter = insert(PrettyPrinterNodeGen.create(null, null, null, null, true)); - } - return (String) attributePrettyPrinter.executeString(o, null, RRuntime.LOGICAL_TRUE, RRuntime.LOGICAL_FALSE); - } - - private String prettyPrintRecursive(Object o, Object listElementName, byte quote, byte right) { - if (recursivePrettyPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - recursivePrettyPrinter = insert(PrettyPrinterNodeGen.create(null, null, null, null, isPrintingAttributes())); - } - return (String) recursivePrettyPrinter.executeString(o, listElementName, quote, right); - } - - private String prettyPrintSingleListElement(Object o, Object listElementName, byte quote, byte right) { - if (singleListElementPrettyPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - singleListElementPrettyPrinter = insert(PrettyPrinterSingleListElementNodeGen.create(null, null, null, null)); - } - return (String) singleListElementPrettyPrinter.executeString(o, listElementName, quote, right); - } - - private String prettyPrintSingleVectorElement(Object o, byte isQuoted) { - if (singleVectorElementPrettyPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - singleVectorElementPrettyPrinter = insert(PrettyPrinterSingleVectorElementNodeGen.create(null, null)); - } - return (String) singleVectorElementPrettyPrinter.executeString(o, isQuoted); - } - - private String printVectorMultiDim(RAbstractVector vector, boolean isListOrStringVector, boolean isComplexOrRawVector, byte quote) { - if (multiDimPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - multiDimPrinter = insert(PrintVectorMultiDimNodeGen.create(null, null, null, null)); - } - StringBuilder sb = new StringBuilder(); - sb.append((String) multiDimPrinter.executeString(vector, RRuntime.asLogical(isListOrStringVector), RRuntime.asLogical(isComplexOrRawVector), quote)); - RAttributes attributes = vector.getAttributes(); - if (attributes != null) { - sb.append(printAttributes(vector, attributes)); - } - return builderToString(sb); - } - - @TruffleBoundary - @Specialization - protected String prettyPrint(RNull operand, Object listElementName, byte quote, byte right) { - return "NULL"; - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVector(byte operand, Object listElementName, byte quote, byte right) { - return concat("[1] ", prettyPrint(operand)); - } - - public static String prettyPrint(byte operand, int width) { - StringBuilder sb = new StringBuilder(); - String valStr = RRuntime.logicalToString(operand); - return spaces(sb, width - valStr.length()).append(valStr).toString(); - } - - public static String prettyPrint(byte operand) { - return RRuntime.logicalToString(operand); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVector(int operand, Object listElementName, byte quote, byte right) { - return concat("[1] ", prettyPrint(operand)); - } - - public static String prettyPrint(int operand) { - return RRuntime.intToString(operand); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVector(double operand, Object listElementName, byte quote, byte right) { - return concat("[1] ", prettyPrint(operand)); - } - - public static String prettyPrint(double operand) { - return doubleToStringPrintFormat(operand, calcRoundFactor(operand, 10000000)); - } - - public static String prettyPrint(double operand, double roundFactor, int digitsBehindDot) { - return doubleToStringPrintFormat(operand, roundFactor, digitsBehindDot); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVector(RComplex operand, Object listElementName, byte quote, byte right) { - return concat("[1] ", prettyPrint(operand)); - } - - public static String prettyPrint(RComplex operand) { - double rfactor = calcRoundFactor(operand.getRealPart(), 10000000); - double ifactor = calcRoundFactor(operand.getImaginaryPart(), 10000000); - return operand.toString(doubleToStringPrintFormat(operand.getRealPart(), rfactor), doubleToStringPrintFormat(operand.getImaginaryPart(), ifactor)); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVector(String operand, Object listElementName, byte quote, byte right) { - if (RRuntime.fromLogical(quote)) { - return concat("[1] ", prettyPrint(operand)); - } - return concat("[1] ", operand); - } - - public static String prettyPrint(String operand) { - return RRuntime.quoteString(operand, false); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVector(RRaw operand, Object listElementName, byte quote, byte right) { - return concat("[1] ", prettyPrint(operand)); - } - - public static String prettyPrint(RRaw operand) { - return operand.toString(); - } - - @TruffleBoundary - @Specialization - protected String prettyPrint(RFunction operand, Object listElementName, byte quote, byte right) { - return prettyPrintFunction(operand, listElementName, quote, right, true); - } - - public String prettyPrintFunction(RFunction operand, Object listElementName, byte quote, byte right, boolean useSource) { - String string; - if (operand.isBuiltin()) { - RBuiltinDescriptor rBuiltin = operand.getRBuiltin(); - RRootNode node = (RRootNode) operand.getTarget().getRootNode(); - FormalArguments formals = node.getFormalArguments(); - StringBuffer sb = new StringBuffer(); - sb.append("function ("); - ArgumentsSignature signature = formals.getSignature(); - for (int i = 0; i < signature.getLength(); i++) { - RNode defaultArg = formals.getDefaultArgument(i); - sb.append(signature.getName(i)); - if (defaultArg != null) { - sb.append(" = "); - Object value = ((ConstantNode) defaultArg).getValue(); - String printValue = prettyPrintRecursive(value, listElementName, quote, right); - // remove the "[1] " - sb.append(printValue.substring(4)); - } - if (i != signature.getLength() - 1) { - sb.append(", "); - } - } - sb.append(") .Primitive(\""); - sb.append(rBuiltin.getName()); - sb.append("\")"); - string = sb.toString(); - } else { - String source = ((RRootNode) operand.getTarget().getRootNode()).getSourceCode(); - if (source == null || !useSource) { - source = RDeparse.deparse(operand); - } - REnvironment env = RArguments.getEnvironment(operand.getEnclosingFrame()); - if (env != null && env.isNamespaceEnv()) { - source += "\n" + env.getPrintName(); - } - string = source; - } - return printValueAndAttributes(string, operand, false); - } - - @TruffleBoundary - @Specialization - protected String prettyPrint(REnvironment operand, Object listElementName, byte quote, byte right) { - return printValueAndAttributes(operand.toString(), operand, false); - } - - @TruffleBoundary - @Specialization - protected String prettyPrint(RExpression expr, Object listElementName, byte quote, byte right) { - StringBuilder builder = new StringBuilder(); - builder.append("expression("); - RList exprs = expr.getList(); - RStringVector names = (RStringVector) expr.getAttr(attrProfiles, RRuntime.NAMES_ATTR_KEY); - for (int i = 0; i < exprs.getLength(); i++) { - if (i != 0) { - builder.append(", "); - } - if (names != null && names.getDataAt(i) != null) { - builder.append(names.getDataAt(i)); - builder.append(" = "); - } - builder.append(prettyPrintSingleVectorElement(exprs.getDataAt(i), quote)); - } - builder.append(')'); - return builderToString(builder); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintSymbol(RSymbol operand, Object listElementName, byte quote, byte right) { - return printValueAndAttributes(operand.getName(), operand, false); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintExternalPtr(RExternalPtr operand, Object listElementName, byte quote, byte right) { - return printValueAndAttributes(String.format("<pointer: %#x>", operand.getAddr()), operand, false); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintPromise(RPromise promise, Object listElementName, byte quote, byte right) { - if (promise.isEvaluated()) { - return prettyPrintRecursive(promise.getValue(), listElementName, quote, right); - } else { - return prettyPrintPromise(promise); - } - } - - @TruffleBoundary - @Specialization - protected String prettyPrintLanguage(RLanguage language, Object listElementName, byte quote, byte right) { - return printValueAndAttributes(prettyPrintLanguageInternal(language), language, true); - } - - private static String prettyPrintLanguageInternal(RLanguage language) { - return RDeparse.deparse(language, 60, false, 0, -1); - } - - private static String prettyPrintPromise(RPromise promise) { - RNode node = (RNode) promise.getRep(); - SourceSection ss = node.asRSyntaxNode().getSourceSection(); - if (ss == null) { - return "<no source available>"; - } else { - return ss.getCode(); - } - } - - @TruffleBoundary - @Specialization - protected String prettyPrintPairList(RPairList pairList, Object listElementName, byte quote, byte right) { - StringBuilder sb = new StringBuilder(); - int i = 1; - Object plObject = pairList; - RPairList pl = pairList; - while (!RPairList.isNull(plObject)) { - if (!pl.isNullTag()) { - sb.append('$'); - sb.append(pl.getTag()); - } else { - sb.append("[["); - sb.append(Integer.toString(i)); - sb.append("]]"); - } - sb.append('\n'); - if (!RPairList.isNull(pl.car())) { - sb.append(prettyPrintRecursive(pl.car(), listElementName, quote, right)); - sb.append('\n'); - } - plObject = pl.cdr(); - if (!RPairList.isNull(plObject)) { - pl = (RPairList) plObject; - sb.append('\n'); - } - i++; - } - return sb.toString(); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintMissing(RMissing missing, Object listElementName, byte quote, byte right) { - return ""; - } - - @TruffleBoundary - @Specialization - protected String prettyPringS4(RS4Object o, Object listElementName, byte quote, byte right) { - StringBuilder sb = new StringBuilder(); - sb.append("<S4 Type Object>"); - for (RAttribute attr : o.getAttributes()) { - printAttribute(sb, attr); - } - return sb.toString(); - } - - private static String getStringFromObj(Object o, String msg) { - if (o instanceof String) { - return (String) o; - } else if (o instanceof RStringVector && ((RStringVector) o).getLength() == 1) { - return ((RStringVector) o).getDataAt(0); - } else { - throw RError.error(RError.SHOW_CALLER2, RError.Message.GENERIC, msg); - } - } - - private String printAttributes(RAbstractVector vector, RAttributes attributes) { - StringBuilder builder = new StringBuilder(); - for (RAttribute attr : attributes) { - if (attr.getName().equals(RRuntime.NAMES_ATTR_KEY) && !vector.hasDimensions()) { - // names attribute already printed - continue; - } - if (attr.getName().equals(RRuntime.DIM_ATTR_KEY) || attr.getName().equals(RRuntime.DIMNAMES_ATTR_KEY)) { - // dim and dimnames attributes never gets printed - continue; - } - printAttribute(builder, attr); - } - return builderToString(builder); - } - - /** - * Encapsulates the printing of the value and attributes for {@link RAttributable} types. - * - * @param ignoreNames TODO - */ - private String printValueAndAttributes(String value, RAttributable object, boolean ignoreNames) { - RAttributes attributes = object.getAttributes(); - if (attributes == null) { - return value; - } else { - StringBuilder builder = new StringBuilder(value); - for (RAttribute attr : attributes) { - if (ignoreNames && attr.getName().equals(RRuntime.NAMES_ATTR_KEY)) { - continue; - } - printAttribute(builder, attr); - } - return builderToString(builder); - } - } - - private void printAttribute(StringBuilder builder, RAttribute attr) { - builder.append("\n"); - builder.append(concat("attr(,\"", attr.getName(), "\")\n")); - builder.append(prettyPrintAttribute(attr.getValue())); - } - - private static int getMaxPrintLength() { - int maxPrint = RRuntime.asInteger(RContext.getInstance().stateROptions.getValue("max.print")); - return RRuntime.isNA(maxPrint) ? -1 : maxPrint; - } - - private String printVector(RAbstractVector vector, String[] values, boolean isStringVector, boolean isRawVector) { - assert vector.getLength() == values.length; - int maxPrint = getMaxPrintLength(); - if (values.length == 0) { - String result = concat(RRuntime.classToString(vector.getElementClass()), "(0)"); - if (vector.getNames(attrProfiles) != null) { - result = concat("named ", result); - } - return result; - } else { - boolean printNamesHeader = ((!vector.hasDimensions() || (vector.getDimensions().length == 1 && vector.getDimNames(attrProfiles) != null)) && vector.getNames(attrProfiles) != null); - RStringVector names = printNamesHeader ? vector.getNames(attrProfiles) : null; - int maxWidth = 0; - for (String s : values) { - maxWidth = Math.max(maxWidth, s.length()); - } - if (printNamesHeader) { - for (int i = 0; i < names.getLength(); i++) { - String s = names.getDataAt(i); - if (RRuntime.isNA(s)) { - s = RRuntime.NA_HEADER; - } - maxWidth = Math.max(maxWidth, s.length()); - } - } - int columnWidth = maxWidth + 1; // There is a blank before each column. - int leftWidth = 0; - int maxPositionLength = 0; - if (!printNamesHeader) { - maxPositionLength = intString(vector.getLength()).length(); - leftWidth = maxPositionLength + 2; // There is [] around the number. - } - int forColumns = (int) RContext.getInstance().stateROptions.getValue("width") - leftWidth; - int numberOfColumns = Math.max(1, forColumns / columnWidth); - - int index = 0; - StringBuilder builder = new StringBuilder(); - StringBuilder headerBuilder = null; - if (printNamesHeader) { - headerBuilder = new StringBuilder(); - } - while (index < vector.getLength()) { - if (!printNamesHeader) { - int position = index + 1; - String positionString = intString(position); - appendSpaces(builder, maxPositionLength - positionString.length()); - builder.append("[").append(positionString).append("]"); - } - for (int j = 0; j < numberOfColumns && index < vector.getLength(); j++) { - String valueString = values[index]; - if (!printNamesHeader) { - builder.append(' '); - // for some reason vectors of strings are printed differently - if (isStringVector) { - builder.append(valueString); - appendSpaces(builder, (columnWidth - 1) - valueString.length()); - } else { - appendSpaces(builder, (columnWidth - 1) - valueString.length()); - builder.append(valueString); - } - } else { - int actualColumnWidth = columnWidth; - if (j == 0) { - actualColumnWidth--; - } - // for some reason vectors of raw values are printed differently - if (!isRawVector) { - appendSpaces(builder, actualColumnWidth - valueString.length()); - } - builder.append(valueString); - if (isRawVector) { - builder.append(' '); - } - String headerString = names.getDataAt(index); - if (RRuntime.isNA(headerString)) { - headerString = RRuntime.NA_HEADER; - } - appendSpaces(headerBuilder, actualColumnWidth - headerString.length()); - headerBuilder.append(headerString); - } - index++; - if (index == maxPrint) { - break; - } - } - builder.append('\n'); - if (printNamesHeader) { - headerBuilder.append('\n'); - headerBuilder.append(builderToString(builder)); - builder = new StringBuilder(); - } - if (index == maxPrint) { - break; - } - } - StringBuilder resultBuilder = printNamesHeader ? headerBuilder : builder; - resultBuilder.deleteCharAt(resultBuilder.length() - 1); - if (index == maxPrint) { - resultBuilder.append("\n [ reached getOption(\"max.print\") -- omitted "); - resultBuilder.append(vector.getLength() - maxPrint); - resultBuilder.append(" entries ]"); - } - if (!(vector instanceof RFactorToStringVectorClosure)) { - // it's a bit of a hack, but factors are meant to be printed using the S3 function - // anyway - the idea is to suppress attribute printing for factors nested in lists - RAttributes attributes = vector.getAttributes(); - if (attributes != null) { - resultBuilder.append(printAttributes(vector, attributes)); - } - } - return builderToString(resultBuilder); - } - } - - private static void appendSpaces(StringBuilder builder, int spaces) { - for (int k = 0; k < spaces; k++) { - builder.append(' '); - } - } - - protected static String padColHeader(int r, int dataColWidth, RAbstractVector vector, boolean isListOrStringVector, RAttributeProfiles attrProfiles) { - RList dimNames = vector.getDimNames(attrProfiles); - StringBuilder sb = new StringBuilder(); - int wdiff; - if (dimNames == null || dimNames.getDataAt(1) == RNull.instance) { - String rs = intString(r); - wdiff = dataColWidth - (rs.length() + 3); // 3: [,] - if (!isListOrStringVector && wdiff > 0) { - spaces(sb, wdiff); - } - sb.append("[,").append(rs).append(']'); - } else { - String dimId; - if (dimNames.getDataAt(1) instanceof String) { - assert r == 1; - dimId = (String) dimNames.getDataAt(1); - } else { - RStringVector dimNamesVector = (RStringVector) dimNames.getDataAt(1); - dimId = dimNamesVector.getDataAt(r - 1); - } - if (RRuntime.isNA(dimId)) { - dimId = RRuntime.NA_HEADER; - } - wdiff = dataColWidth - dimId.length(); - if (!isListOrStringVector && wdiff > 0) { - spaces(sb, wdiff); - } - sb.append(dimId); - } - if (isListOrStringVector && wdiff > 0) { - spaces(sb, wdiff); - } - return builderToString(sb); - } - - protected static boolean rowHeaderUsesIndices(RList dimNames) { - return dimNames == null || dimNames.getDataAt(0) == RNull.instance; - } - - protected static String rowHeader(int c, RAbstractVector vector, RAttributeProfiles attrProfiles) { - RList dimNames = vector.getDimNames(attrProfiles); - if (rowHeaderUsesIndices(dimNames)) { - return concat("[", intString(c), ",]"); - } else { - RAbstractStringVector dimNamesVector = (RAbstractStringVector) getDimNamesAt(dimNames, 1); - String dimId = dimNamesVector.getDataAt(c - 1); - if (RRuntime.isNA(dimId)) { - dimId = RRuntime.NA_HEADER; - } - return dimId; - } - } - - public static StringBuilder spaces(StringBuilder sb, int s) { - if (s > 0) { - appendSpaces(sb, s); - } - return sb; - } - - private static String getDimId(RAbstractVector vector, int dimLevel, int dimInd, RAttributeProfiles attrProfiles) { - String dimId; - RList dimNames = vector.getDimNames(attrProfiles); - if (dimNames == null || getDimNamesAt(dimNames, dimLevel) == RNull.instance) { - dimId = intString(dimInd + 1); - } else { - RAbstractStringVector dimNamesVector = (RAbstractStringVector) getDimNamesAt(dimNames, dimLevel); - dimId = dimNamesVector.getDataAt(dimInd); - } - return dimId; - } - - private static Object getDimNamesAt(RList dimNames, int dimLevel) { - Object result = dimNames.getDataAt(dimLevel - 1); - if (result instanceof String) { - return RString.valueOf((String) result); - } - return result; - } - - private static double calcRoundFactor(double input, long maxFactor) { - if (Double.isNaN(input) || Double.isInfinite(input) || input == 0.0) { - return maxFactor * 10; - } - double data = input; - double factor = 1; - if (Math.abs(data) > 1000000000000L) { - while (Math.abs(data) > 10000000L) { - data = data / 10; - factor /= 10; - } - } else if ((int) data != 0) { - while (Math.abs(data) < maxFactor / 10) { - data = data * 10; - factor *= 10; - } - } else { - long current = maxFactor / 10; - while (Math.abs(data) < 1 && current > 1) { - data = data * 10; - current = current * 10; - } - return current; - } - return factor; - } - - private static String doubleToStringPrintFormat(double input, double roundFactor, int digitsBehindDot) { - double data = input; - if (digitsBehindDot == -1) { - // processing a single double value or a complex value; use rounding instead of - // digitsBehindDot (which is in this case invalid) to determine precision - if (!Double.isNaN(data) && !Double.isInfinite(data)) { - if (roundFactor < 1) { - double inverse = 1 / roundFactor; - data = Math.round(data / inverse) * inverse; - } else { - data = Math.round(data * roundFactor) / roundFactor; - } - } - } - return RRuntime.doubleToString(data, digitsBehindDot); - } - - private static String doubleToStringPrintFormat(double input, double roundFactor) { - return doubleToStringPrintFormat(input, roundFactor, -1); - } - - private String prettyPrintList0(RList operand, Object listElementName, byte quote, byte right) { - int length = operand.getLength(); - if (length == 0) { - String result = "list()"; - if (operand.getNames(attrProfiles) != null) { - result = concat("named ", result); - } - return result; - } else { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (isPrintingAttributes() && operand.elementNamePrefix != null) { - sb.append(operand.elementNamePrefix); - } - Object name = operand.getNameAt(i); - if (listElementName != null) { - name = concat(RRuntime.toString(listElementName), RRuntime.toString(name)); - } - sb.append(name).append('\n'); - Object value = operand.getDataAt(i); - sb.append(prettyPrintSingleListElement(value, name, quote, right)).append("\n\n"); - } - sb.deleteCharAt(sb.length() - 1); - RAttributes attributes = operand.getAttributes(); - if (attributes != null) { - sb.append(printAttributes(operand, attributes)); - } - return builderToString(sb); - } - } - - public static String prettyPrint(RList operand) { - return concat("List,", intString(operand.getLength())); - } - - public static String prettyPrint(RAbstractVector operand) { - return concat(RRuntime.classToStringCap(operand.getElementClass()), ",", intString(operand.getLength())); - } - - @TruffleBoundary - @Specialization(guards = "twoDimsOrMore(operand)") - protected String prettyPrintM(RList operand, Object listElementName, byte quote, byte right) { - return printVectorMultiDim(operand, true, false, quote); - } - - @TruffleBoundary - @Specialization(guards = "twoDimsOrMore(operand)") - protected String prettyPrintM(RAbstractStringVector operand, Object listElementName, byte quote, byte right) { - return printVectorMultiDim(operand, right == RRuntime.LOGICAL_FALSE, false, quote); - } - - @TruffleBoundary - @Specialization(guards = "twoDimsOrMore(operand)") - protected String prettyPrintM(RAbstractComplexVector operand, Object listElementName, byte quote, byte right) { - return printVectorMultiDim(operand, false, true, quote); - } - - @TruffleBoundary - @Specialization(guards = "twoDimsOrMore(operand)") - protected String prettyPrintM(RAbstractRawVector operand, Object listElementName, byte quote, byte right) { - return printVectorMultiDim(operand, false, true, quote); - } - - @TruffleBoundary - @Specialization(guards = "twoDimsOrMore(operand)") - protected String prettyPrintM(RAbstractDoubleVector operand, Object listElementName, byte quote, byte right) { - return printVectorMultiDim(operand, false, false, quote); - } - - @TruffleBoundary - @Specialization(guards = "twoDimsOrMore(operand)") - protected String prettyPrintM(RAbstractIntVector operand, Object listElementName, byte quote, byte right) { - return printVectorMultiDim(operand, false, false, quote); - } - - @TruffleBoundary - @Specialization(guards = "twoDimsOrMore(operand)") - protected String prettyPrintM(RAbstractLogicalVector operand, Object listElementName, byte quote, byte right) { - return printVectorMultiDim(operand, false, false, quote); - } - - @TruffleBoundary - @Specialization(guards = "!twoDimsOrMore(operand)") - protected String prettyPrint(RList operand, Object listElementName, byte quote, byte right) { - return prettyPrintList0(operand, listElementName, quote, right); - } - - private static double getMaxRoundFactor(RAbstractDoubleVector operand) { - double maxRoundFactor = 0; - for (int i = 0; i < operand.getLength(); i++) { - double data = operand.getDataAt(i); - double roundFactor = calcRoundFactor(data, 10000000); - if (roundFactor > maxRoundFactor) { - maxRoundFactor = roundFactor; - } - } - return maxRoundFactor; - } - - private static int getMaxDigitsBehindDot(double maxRoundFactor) { - int maxDigitsBehindDot = 0; - for (double j = 1; j < maxRoundFactor; j *= 10) { - maxDigitsBehindDot++; - } - return maxDigitsBehindDot; - } - - @TruffleBoundary - @Specialization(guards = "!twoDimsOrMore(operand)") - protected String prettyPrint(RAbstractDoubleVector operand, Object listElementName, byte quote, byte right) { - int length = operand.getLength(); - String[] values = new String[length]; - double maxRoundFactor = getMaxRoundFactor(operand); - int maxDigitsBehindDot = getMaxDigitsBehindDot(maxRoundFactor); - for (int i = 0; i < length; i++) { - double data = operand.getDataAt(i); - values[i] = prettyPrint(data, maxRoundFactor, maxDigitsBehindDot); - } - padTrailingDecimalPointAndZeroesIfRequired(values); - return printVector(operand, values, false, false); - } - - @TruffleBoundary - @Specialization(guards = "!twoDimsOrMore(operand)") - protected String prettyPrint(RAbstractIntVector operand, Object listElementName, byte quote, byte right) { - int length = operand.getLength(); - String[] values = new String[length]; - for (int i = 0; i < length; i++) { - int data = operand.getDataAt(i); - values[i] = prettyPrint(data); - } - return printVector(operand, values, false, false); - } - - @TruffleBoundary - @Specialization(guards = "!twoDimsOrMore(operand)") - protected String prettyPrint(RAbstractStringVector operand, Object listElementName, byte quote, byte right) { - int length = operand.getLength(); - String[] values = new String[length]; - for (int i = 0; i < length; i++) { - String data = operand.getDataAt(i); - if (RRuntime.fromLogical(quote)) { - values[i] = prettyPrint(data); - } else { - if (RRuntime.isNA(data)) { - values[i] = RRuntime.NA_HEADER; - } else { - values[i] = data; - } - } - } - return printVector(operand, values, true, false); - } - - @TruffleBoundary - @Specialization(guards = "!twoDimsOrMore(operand)") - protected String prettyPrint(RAbstractLogicalVector operand, Object listElementName, byte quote, byte right) { - int length = operand.getLength(); - String[] values = new String[length]; - for (int i = 0; i < length; i++) { - byte data = operand.getDataAt(i); - values[i] = prettyPrint(data); - } - return printVector(operand, values, false, false); - } - - @TruffleBoundary - @Specialization(guards = "!twoDimsOrMore(operand)") - protected String prettyPrint(RAbstractRawVector operand, Object listElementName, byte quote, byte right) { - int length = operand.getLength(); - String[] values = new String[length]; - for (int i = 0; i < length; i++) { - RRaw data = operand.getDataAt(i); - values[i] = prettyPrint(data); - } - return printVector(operand, values, false, true); - } - - @TruffleBoundary - @Specialization(guards = "!twoDimsOrMore(operand)") - protected String prettyPrint(RAbstractComplexVector operand, Object listElementName, byte quote, byte right) { - - RAbstractDoubleVector realParts = (RAbstractDoubleVector) re.calculateUnboxed(operand); - RAbstractDoubleVector imaginaryParts = (RAbstractDoubleVector) im.calculateUnboxed(operand); - - int length = operand.getLength(); - String[] realValues = new String[length]; - String[] imaginaryValues = new String[length]; - for (int i = 0; i < length; i++) { - realValues[i] = prettyPrint(realParts.getDataAt(i)); - imaginaryValues[i] = prettyPrint(imaginaryParts.getDataAt(i)); - } - padTrailingDecimalPointAndZeroesIfRequired(realValues); - padTrailingDecimalPointAndZeroesIfRequired(imaginaryValues); - removeLeadingMinus(imaginaryValues); - rightJustify(imaginaryValues); - - String[] values = new String[length]; - for (int i = 0; i < length; i++) { - values[i] = operand.getDataAt(i).isNA() ? "NA" : concat(realValues[i], imaginaryParts.getDataAt(i) < 0.0 ? "-" : "+", imaginaryValues[i], "i"); - } - return printVector(operand, values, false, false); - } - - protected static boolean twoDimsOrMore(RAbstractContainer v) { - return v.hasDimensions() && v.getDimensions().length > 1; - } - - protected static boolean isLengthOne(RAbstractIntVector v) { - return v.getLength() == 1; - } - - private static String builderToString(StringBuilder sb) { - return sb.toString(); - } - - private static String builderToSubstring(StringBuilder sb, int start, int end) { - return sb.substring(start, end); - } - - private static String intString(int x) { - return Integer.toString(x); - } - - private static String stringFormat(String format, Object arg) { - return String.format(format, arg); - } - - private static String concat(String... ss) { - StringBuilder sb = new StringBuilder(); - for (String s : ss) { - sb.append(s); - } - return builderToString(sb); - } - - private static String substring(String s, int start) { - return s.substring(start); - } - - private static int requiresDecimalPointsAndTrailingZeroes(String[] values, int[] decimalPointOffsets, int[] lenAfterPoint) { - boolean foundWithDecimalPoint = false; - boolean foundWithoutDecimalPoint = false; - boolean inequalLenAfterPoint = false; - int maxLenAfterPoint = -1; - for (int i = 0; i < values.length; i++) { - String v = values[i]; - decimalPointOffsets[i] = v.indexOf('.'); - if (decimalPointOffsets[i] == -1) { - foundWithoutDecimalPoint = true; - lenAfterPoint[i] = 0; - } else { - foundWithDecimalPoint = true; - int lap = substring(v, decimalPointOffsets[i] + 1).length(); - lenAfterPoint[i] = lap; - if (lap > maxLenAfterPoint) { - if (maxLenAfterPoint == -1) { - inequalLenAfterPoint = true; - } - maxLenAfterPoint = lap; - } - } - } - return (foundWithDecimalPoint && foundWithoutDecimalPoint) || inequalLenAfterPoint ? maxLenAfterPoint : -1; - } - - public static void padTrailingDecimalPointAndZeroesIfRequired(String[] values) { - int[] decimalPointOffsets = new int[values.length]; - int[] lenAfterPoint = new int[values.length]; - int maxLenAfterPoint = requiresDecimalPointsAndTrailingZeroes(values, decimalPointOffsets, lenAfterPoint); - if (maxLenAfterPoint == -1) { - return; - } - - for (int i = 0; i < values.length; i++) { - String v = values[i]; - if (RRuntime.isNA(v) || "NaN".equals(v)) { - continue; - } - if (decimalPointOffsets[i] == -1) { - v = concat(v, "."); - } - if (lenAfterPoint[i] < maxLenAfterPoint) { - values[i] = concat(v, stringFormat(concat("%0", intString(maxLenAfterPoint - lenAfterPoint[i]), "d"), 0)); - } - } - } - - private static void rightJustify(String[] values) { - int maxLen = 0; - boolean inequalLengths = false; - int lastLen = 0; - for (int i = 0; i < values.length; i++) { - String v = values[i]; - if (RRuntime.isNA(v)) { - // do not use NA for deciding alignment - continue; - } - int l = v.length(); - maxLen = Math.max(maxLen, l); - inequalLengths = lastLen != 0 && lastLen != l; - lastLen = l; - } - if (!inequalLengths) { - return; - } - for (int i = 0; i < values.length; i++) { - String v = values[i]; - int l = v.length(); - if (l < maxLen) { - int d = maxLen - l; - if (d == 1) { - values[i] = concat(" ", v); - } else { - values[i] = concat(stringFormat(concat("%", intString(d), "s"), " "), v); - } - } - } - } - - private static void removeLeadingMinus(String[] values) { - for (int i = 0; i < values.length; i++) { - String v = values[i]; - if (v.charAt(0) == '-') { - values[i] = substring(v, 1); - } - } - } - - public static String prettyPrintDefault(Object value) { - return (String) Truffle.getRuntime().createCallTarget(new RootNode(TruffleLanguage.class, null, null) { - - @Child PrettyPrinterNode node = PrettyPrinterNodeGen.create(null, null, null, null, false); - - @Override - public Object execute(VirtualFrame frame) { - return node.executeString(frame.getArguments()[0], null, RRuntime.LOGICAL_FALSE, RRuntime.LOGICAL_FALSE); - } - }).call(value); - } - - @NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "listElementName", type = RNode.class), @NodeChild(value = "quote", type = RNode.class), - @NodeChild(value = "right", type = RNode.class)}) - abstract static class PrettyPrinterSingleListElementNode extends RNode { - - @Child private PrettyPrinterNode prettyPrinter; - @Child private CastStringNode castStringNode; - - private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); - - private final NACheck naCheck = NACheck.create(); - - private void initCast(Object listElementName) { - if (prettyPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - prettyPrinter = insert(PrettyPrinterNodeGen.create(null, null, null, null, false)); - } - } - - private void initCast() { - if (castStringNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - castStringNode = insert(CastStringNodeGen.create(false, false, false, false)); - } - } - - private String prettyPrintSingleElement(byte o, Object listElementName, byte quote, byte right) { - initCast(listElementName); - return (String) prettyPrinter.executeString(o, listElementName, quote, right); - } - - private String prettyPrintSingleElement(int o, Object listElementName, byte quote, byte right) { - initCast(listElementName); - return (String) prettyPrinter.executeString(o, listElementName, quote, right); - } - - private String prettyPrintSingleElement(double o, Object listElementName, byte quote, byte right) { - initCast(listElementName); - return (String) prettyPrinter.executeString(o, listElementName, quote, right); - } - - private String prettyPrintSingleElement(Object o, Object listElementName, byte quote, byte right) { - initCast(listElementName); - return (String) prettyPrinter.executeString(o, listElementName, quote, right); - } - - public abstract Object executeString(int o, Object listElementName, byte quote, byte right); - - public abstract Object executeString(double o, Object listElementName, byte quote, byte right); - - public abstract Object executeString(byte o, Object listElementName, byte quote, byte right); - - public abstract Object executeString(Object o, Object listElementName, byte quote, byte right); - - @Specialization - protected String prettyPrintListElement(SocketConnections.RSocketConnection operand, Object listElementName, byte quote, byte right) { - // TODO; fixing this properly would likely require overhaul of the whole - // formatting/printing infrastructure, which does not seem worth it at this point - return "SOCKET CONNECTION"; - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(RNull operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(byte operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(int operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(double operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(RComplex operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(String operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(RRaw operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization(guards = "!isFactor(operand)") - protected String prettyPrintListElement(RAbstractVector operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(RSymbol operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(RLanguage operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(REnvironment operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(RFunction operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintListElement(RExternalPtr operand, Object listElementName, byte quote, byte right) { - return prettyPrintSingleElement(operand, listElementName, quote, right); - } - - @Child InheritsCheckNode factorInheritsCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR); - @Child RFactorNodes.GetLevels getFactorLevels; - - protected boolean isFactor(Object o) { - return this.factorInheritsCheck.execute(o); - } - - // TODO: this should be handled by an S3 function - @Specialization(guards = "isFactor(factor)") - protected String prettyPrintListElement(RAbstractIntVector factor, Object listElementName, byte quote, byte right) { - if (getFactorLevels == null) { - CompilerDirectives.transferToInterpreter(); - getFactorLevels = insert(new RFactorNodes.GetLevels()); - } - - RVector vec = getFactorLevels.execute(factor); - String[] strings; - if (vec == null) { - strings = new String[0]; - } else { - initCast(); - strings = new String[vec.getLength()]; - for (int i = 0; i < vec.getLength(); i++) { - strings[i] = (String) castStringNode.executeString(vec.getDataAtAsObject(i)); - } - } - return formatLevelStrings(factor, listElementName, right, vec, strings); - } - - @TruffleBoundary - private String formatLevelStrings(RAbstractIntVector operand, Object listElementName, byte right, RVector vec, String[] strings) { - StringBuilder sb = new StringBuilder(prettyPrintSingleElement(RClosures.createFactorToVector(operand, true, attrProfiles), listElementName, RRuntime.LOGICAL_FALSE, right)); - sb.append("\nLevels:"); - if (vec != null) { - for (int i = 0; i < vec.getLength(); i++) { - sb.append(" "); - sb.append(strings[i]); - } - } - return sb.toString(); - } - } - - @NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "isQuoted", type = RNode.class)}) - abstract static class PrettyPrinterSingleVectorElementNode extends RNode { - - @Child private PrettyPrinterSingleVectorElementNode recursivePrettyPrinter; - - private String prettyPrintRecursive(Object o, byte isQuoted) { - if (recursivePrettyPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - recursivePrettyPrinter = insert(PrettyPrinterSingleVectorElementNodeGen.create(null, null)); - } - return (String) recursivePrettyPrinter.executeString(o, isQuoted); - } - - public abstract Object executeString(Object o, byte isQuoted); - - @TruffleBoundary - @Specialization - protected String prettyPrintVectorElement(RNull operand, byte isQuoted) { - return "NULL"; - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVectorElement(byte operand, byte isQuoted) { - return prettyPrint(operand); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVectorElement(int operand, byte isQuoted) { - return prettyPrint(operand); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVectorElement(double operand, byte isQuoted) { - return prettyPrint(operand); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVectorElement(RComplex operand, byte isQuoted) { - return prettyPrint(operand); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVectorElement(String operand, byte isQuoted) { - if (RRuntime.fromLogical(isQuoted)) { - return prettyPrint(operand); - } - return operand; - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVectorElement(RRaw operand, byte isQuoted) { - return prettyPrint(operand); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVectorElement(RList operand, byte isQuoted) { - return prettyPrint(operand); - } - - @TruffleBoundary - @Specialization(guards = {"operand.getLength() != 1", "!isVectorList(operand)"}) - protected String prettyPrintVectorElement(RAbstractVector operand, byte isQuoted) { - return prettyPrint(operand); - } - - @TruffleBoundary - @Specialization(guards = {"operand.getLength() == 1", "!isVectorList(operand)"}) - protected String prettyPrintVectorElementLengthOne(RAbstractVector operand, byte isQuoted) { - return prettyPrintRecursive(operand.getDataAtAsObject(0), isQuoted); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVectorElement(RLanguage operand, byte isQuoted) { - return prettyPrintLanguageInternal(operand); - } - - @TruffleBoundary - @Specialization - protected String prettyPrintVectorElement(RSymbol operand, byte isQuoted) { - return operand.getName(); - } - - protected static boolean isVectorList(RAbstractVector v) { - return v instanceof RList; - } - - protected static boolean isLengthOne(RAbstractVector v) { - return v.getLength() == 1; - } - } - - @NodeChildren({@NodeChild(value = "vector", type = RNode.class), @NodeChild(value = "isListOrStringVector", type = RNode.class), @NodeChild(value = "isComplexOrRawVector", type = RNode.class), - @NodeChild(value = "isQuoted", type = RNode.class)}) - abstract static class PrintVectorMultiDimNode extends RNode { - - @Child private PrintVector2DimNode vector2DimPrinter; - @Child private PrintDimNode dimPrinter; - - private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); - - private String printVector2Dim(RAbstractVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) { - if (vector2DimPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - vector2DimPrinter = insert(PrintVector2DimNodeGen.create(null, null, null, null, null, null)); - } - return (String) vector2DimPrinter.executeString(vector, dimensions, offset, isListOrStringVector, isComplexOrRawVector, isQuoted); - } - - private String printDim(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, int currentDimLevel, int arrayBase, int accDimensions, String header, byte isQuoted) { - if (dimPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - dimPrinter = insert(PrintDimNodeGen.create(null, null, null, null, null, null, null, null)); - } - return (String) dimPrinter.executeString(vector, isListOrStringVector, isComplexOrRawVector, currentDimLevel, arrayBase, accDimensions, header, isQuoted); - } - - public abstract Object executeString(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted); - - @TruffleBoundary - @Specialization - protected String printVectorMultiDim(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) { - int[] dimensions = vector.getDimensions(); - RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, RDataFactory.COMPLETE_VECTOR); - assert dimensions != null; - int numDimensions = dimensions.length; - assert numDimensions > 1; - if (numDimensions == 2) { - return printVector2Dim(vector, dimensionsVector, 0, isListOrStringVector, isComplexOrRawVector, isQuoted); - } else { - int dimSize = dimensions[numDimensions - 1]; - if (dimSize == 0) { - return ""; - } - StringBuilder sb = new StringBuilder(); - if (numDimensions == 3) { - int matrixSize = dimensions[0] * dimensions[1]; - for (int dimInd = 0; dimInd < dimSize; dimInd++) { - // Checkstyle: stop - sb.append(", , "); - // Checkstyle: resume - sb.append(getDimId(vector, numDimensions, dimInd, attrProfiles)); - sb.append("\n\n"); - sb.append(printVector2Dim(vector, dimensionsVector, dimInd * matrixSize, isListOrStringVector, isComplexOrRawVector, isQuoted)); - sb.append("\n"); - if (dimInd < (dimSize - 1) && vector.getLength() > 0 || vector.getLength() == 0) { - sb.append("\n"); - } - } - } else { - int accDimensions = vector.getLength() / dimSize; - for (int dimInd = 0; dimInd < dimSize; dimInd++) { - int arrayBase = accDimensions * dimInd; - String dimId = getDimId(vector, numDimensions, dimInd, attrProfiles); - String innerDims = printDim(vector, isListOrStringVector, isComplexOrRawVector, numDimensions - 1, arrayBase, accDimensions, dimId, isQuoted); - if (innerDims == null) { - return ""; - } else { - sb.append(innerDims); - } - } - } - if (vector.getLength() == 0) { - // remove last line break - return builderToSubstring(sb, 0, sb.length() - 1); - } else { - return builderToString(sb); - } - } - } - } - - @NodeChildren({@NodeChild(value = "vector", type = RNode.class), @NodeChild(value = "dimensions", type = RNode.class), @NodeChild(value = "offset", type = RNode.class), - @NodeChild(value = "isListOrStringVector", type = RNode.class), @NodeChild(value = "isComplexOrRawVector", type = RNode.class), @NodeChild(value = "isQuoted", type = RNode.class)}) - abstract static class PrintVector2DimNode extends RNode { - - @Child private PrettyPrinterSingleVectorElementNode singleVectorElementPrettyPrinter; - - private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); - - private String prettyPrintSingleVectorElement(Object o, byte isQuoted) { - if (singleVectorElementPrettyPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - singleVectorElementPrettyPrinter = insert(PrettyPrinterSingleVectorElementNodeGen.create(null, null)); - } - return (String) singleVectorElementPrettyPrinter.executeString(o, isQuoted); - } - - public abstract Object executeString(RAbstractVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted); - - private static String getDimId(RList dimNames, int dimension, int ind, byte isComplexOrRawVector) { - StringBuilder sb = new StringBuilder(); - if (dimNames == null || dimNames.getDataAt(dimension) == RNull.instance) { - String rs = intString(ind); - sb.append("["); - if (dimension == 1) { - // columns - sb.append(','); - } - sb.append(rs); - if (dimension == 0) { - // rows - sb.append(','); - } - sb.append(']'); - } else { - RStringVector dimNamesVector = (RStringVector) dimNames.getDataAt(dimension); - String dimId = dimNamesVector.getDataAt(ind - 1); - if (dimension == 1 && isComplexOrRawVector == RRuntime.LOGICAL_TRUE && dimId.length() == 1) { - sb.append(' '); - } - sb.append(dimId); - } - return builderToString(sb); - } - - @TruffleBoundary - @Specialization(guards = "vector.getLength() == 0") - protected String printVector2DimEmpty(RAbstractVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) { - int nrow = dimensions.getDataAt(0); - int ncol = dimensions.getDataAt(1); - - if (nrow == 0 && ncol == 0) { - if (dimensions.getLength() == 2) { - return "<0 x 0 matrix>"; - } else { - return ""; - } - } - - StringBuilder sb = new StringBuilder(); - RList dimNames = vector.getDimNames(attrProfiles); - if (ncol > 0) { - sb.append(" "); - for (int c = 1; c <= ncol; c++) { - sb.append(getDimId(dimNames, 1, c, isComplexOrRawVector)); - if (c < ncol) { - sb.append(' '); - } - } - } - if (nrow > 0) { - sb.append('\n'); - for (int r = 1; r <= nrow; r++) { - sb.append(getDimId(dimNames, 0, r, isComplexOrRawVector)); - if (r < nrow) { - sb.append('\n'); - } - } - } - return builderToString(sb); - } - - @TruffleBoundary - @Specialization(guards = "vector.getLength() != 0") - protected String printVector2Dim(RAbstractDoubleVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) { - int nrow = dimensions.getDataAt(0); - int ncol = dimensions.getDataAt(1); - - // prepare data (relevant for column widths) - String[] dataStrings = new String[nrow * ncol]; - int[] dataColWidths = new int[ncol]; - RList dimNames = vector.getDimNames(attrProfiles); - RStringVector columnDimNames = null; - if (dimNames != null && dimNames.getDataAt(1) != RNull.instance) { - columnDimNames = (RStringVector) dimNames.getDataAt(1); - } - double[] maxRoundFactors = new double[ncol]; - int[] maxDigitsBehindDot = new int[ncol]; - for (int c = 0; c < ncol; c++) { - maxRoundFactors[c] = 0; - for (int r = 0; r < nrow; r++) { - int index = c * nrow + r; - double data = vector.getDataAt(index + offset); - double roundFactor = calcRoundFactor(data, 10000000); - if (roundFactor > maxRoundFactors[c]) { - maxRoundFactors[c] = roundFactor; - } - } - maxDigitsBehindDot[c] = getMaxDigitsBehindDot(maxRoundFactors[c]); - } - int rowHeaderWidth = 0; - for (int c = 0; c < ncol; c++) { - for (int r = 0; r < nrow; r++) { - int index = c * nrow + r; - dataStrings[index] = prettyPrint(vector.getDataAt(index + offset), maxRoundFactors[c], maxDigitsBehindDot[c]); - maintainColumnData(dataColWidths, columnDimNames, c, dataStrings[index]); - rowHeaderWidth = Math.max(rowHeaderWidth, rowHeader(r + 1, vector, attrProfiles).length()); - } - } - - // probably add trailing decimal points and zeroes - // iterate over columns - for (int c = 0; c < ncol; c++) { - postProcessDoubleColumn(dataStrings, nrow, ncol, c); - // final adjustment of column width - boolean hasNegative = false; - for (int r = 0; r < nrow; r++) { - // do not count minus signs - String data = dataStrings[c * nrow + r]; - boolean isNegative = data.charAt(0) == '-'; - hasNegative = hasNegative || isNegative; - int l = isNegative ? data.length() - 1 : data.length(); - if (l > dataColWidths[c]) { - dataColWidths[c] = l; - } - } - if (hasNegative) { - dataColWidths[c] = -dataColWidths[c]; - } - } - - return formatResult(vector, nrow, ncol, dataStrings, dataColWidths, rowHeaderWidth, isListOrStringVector == RRuntime.LOGICAL_TRUE); - } - - @TruffleBoundary - @Specialization(guards = "vector.getLength() != 0") - protected String printVector2Dim(RAbstractComplexVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) { - int nrow = dimensions.getDataAt(0); - int ncol = dimensions.getDataAt(1); - - // prepare data (relevant for column widths) - String[] reStrings = new String[nrow * ncol]; - String[] imStrings = new String[nrow * ncol]; - String[] siStrings = new String[nrow * ncol]; - int[] dataColWidths = new int[ncol]; - RList dimNames = vector.getDimNames(attrProfiles); - RStringVector columnDimNames = null; - if (dimNames != null && dimNames.getDataAt(1) != RNull.instance) { - columnDimNames = (RStringVector) dimNames.getDataAt(1); - } - int rowHeaderWidth = 0; - for (int r = 0; r < nrow; r++) { - for (int c = 0; c < ncol; c++) { - int index = c * nrow + r; - reStrings[index] = prettyPrintSingleVectorElement(vector.getDataAt(index + offset).getRealPart(), isQuoted); - imStrings[index] = prettyPrintSingleVectorElement(vector.getDataAt(index + offset).getImaginaryPart(), isQuoted); - siStrings[index] = vector.getDataAt(index + offset).getImaginaryPart() < 0.0 ? "-" : "+"; - // "" because column width is computed later - maintainColumnData(dataColWidths, columnDimNames, c, ""); - } - rowHeaderWidth = Math.max(rowHeaderWidth, rowHeader(r + 1, vector, attrProfiles).length()); - } - - // adjust formatting - // iterate over columns - for (int c = 0; c < ncol; c++) { - postProcessComplexColumn(reStrings, imStrings, nrow, ncol, c); - } - - String[] dataStrings = new String[nrow * ncol]; - for (int i = 0; i < dataStrings.length; i++) { - dataStrings[i] = vector.getDataAt(i).isNA() ? "NA" : concat(reStrings[i], siStrings[i], imStrings[i], "i"); - } - - // final adjustment of column width - for (int c = 0; c < ncol; c++) { - for (int r = 0; r < nrow; r++) { - // do not count minus signs - String data = dataStrings[c * nrow + r]; - int l = data.charAt(0) == '-' ? data.length() - 1 : data.length(); - if (l > dataColWidths[c]) { - dataColWidths[c] = l; - } - } - } - - return formatResult(vector, nrow, ncol, dataStrings, dataColWidths, rowHeaderWidth, isListOrStringVector == RRuntime.LOGICAL_TRUE); - } - - @TruffleBoundary - @Specialization(guards = {"vector.getLength() != 0", "notDoubleOrComplex(vector)"}) - protected String printVector2Dim(RAbstractVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) { - int nrow = dimensions.getDataAt(0); - int ncol = dimensions.getDataAt(1); - - // prepare data (relevant for column widths) - String[] dataStrings = new String[nrow * ncol]; - int[] dataColWidths = new int[ncol]; - RList dimNames = vector.getDimNames(attrProfiles); - RStringVector columnDimNames = null; - if (dimNames != null && dimNames.getDataAt(1) != RNull.instance) { - if (dimNames.getDataAt(1) instanceof String) { - columnDimNames = RDataFactory.createStringVector((String) dimNames.getDataAt(1)); - } else { - columnDimNames = (RStringVector) dimNames.getDataAt(1); - } - } - int rowHeaderWidth = 0; - for (int r = 0; r < nrow; r++) { - for (int c = 0; c < ncol; c++) { - int index = c * nrow + r; - dataStrings[index] = prettyPrintSingleVectorElement(vector.getDataAtAsObject(index + offset), isQuoted); - maintainColumnData(dataColWidths, columnDimNames, c, dataStrings[index]); - } - rowHeaderWidth = Math.max(rowHeaderWidth, rowHeader(r + 1, vector, attrProfiles).length()); - } - - return formatResult(vector, nrow, ncol, dataStrings, dataColWidths, rowHeaderWidth, isListOrStringVector == RRuntime.LOGICAL_TRUE); - } - - protected boolean notDoubleOrComplex(RAbstractVector vector) { - return vector.getElementClass() != RDouble.class && vector.getElementClass() != RComplex.class; - } - - private static void postProcessDoubleColumn(String[] dataStrings, int nrow, int ncol, int col) { - // create and populate array with column data - String[] columnData = new String[nrow]; - for (int r = 0; r < nrow; r++) { - columnData[r] = dataStrings[col * nrow + r]; - } - padTrailingDecimalPointAndZeroesIfRequired(columnData); - // put possibly changed data back - for (int r = 0; r < nrow; r++) { - dataStrings[col * nrow + r] = columnData[r]; - } - } - - private static void postProcessComplexColumn(String[] re, String[] im, int nrow, int ncol, int col) { - // create and populate arrays with column data - String[] cre = new String[nrow]; - String[] cim = new String[nrow]; - for (int r = 0; r < nrow; r++) { - cre[r] = re[col * nrow + r]; - cim[r] = im[col * nrow + r]; - } - - padTrailingDecimalPointAndZeroesIfRequired(cre); - padTrailingDecimalPointAndZeroesIfRequired(cim); - removeLeadingMinus(cim); - rightJustify(cre); - rightJustify(cim); - - // put possibly changed data back - for (int r = 0; r < nrow; r++) { - re[col * nrow + r] = cre[r]; - im[col * nrow + r] = cim[r]; - } - } - - private static void maintainColumnData(int[] dataColWidths, RStringVector columnDimNames, int c, String data) { - // do not count minus signs - int dataLength = !data.equals("") && data.charAt(0) == '-' ? data.length() - 1 : data.length(); - if (dataLength > dataColWidths[c]) { - dataColWidths[c] = dataLength; - } - if (columnDimNames != null) { - String columnName = columnDimNames.getDataAt(c); - if (RRuntime.isNA(columnName)) { - columnName = RRuntime.NA_HEADER; - } - if (columnName.length() > dataColWidths[c]) { - dataColWidths[c] = columnName.length(); - } - } - } - - private String formatResult(RAbstractVector vector, int nrow, int ncol, String[] dataStrings, int[] dataColWidths, int rowHeaderWidth, boolean isListOrStringVector) { - boolean isComplexVector = vector.getElementClass() == RComplex.class; - boolean isDoubleVector = vector.getElementClass() == RDouble.class; - String rowFormat = concat("%", intString(rowHeaderWidth), "s"); - - StringBuilder b = new StringBuilder(); - - int colInd = 0; - while (true) { - int totalWidth = rowHeaderWidth + 1; - int startColInd = colInd; - for (; colInd < dataColWidths.length; colInd++) { - boolean hasNegative = dataColWidths[colInd] < 0; - totalWidth += Math.abs(dataColWidths[colInd]) + ((isDoubleVector || isComplexVector) && hasNegative ? 2 : 1); - if (totalWidth > (int) RContext.getInstance().stateROptions.getValue("name")) { - if (colInd == startColInd) { - // the first column is already too wide but needs to be printed - // nevertheless - colInd++; - } - break; - } - } - - // column header - spaces(b, rowHeaderWidth + 1); - for (int c = startColInd + 1; c <= colInd; c++) { - boolean hasNegative = dataColWidths[c - 1] < 0; - // header of the first column needs extra padding if this column has negative - // numbers - int padding = Math.abs(dataColWidths[c - 1]) + ((isDoubleVector || isComplexVector) && hasNegative ? 1 : 0); - b.append(padColHeader(c, padding, vector, isListOrStringVector, attrProfiles)); - if (c < colInd) { - b.append(" "); - } - } - b.append('\n'); - - boolean indexRowHeaders = rowHeaderUsesIndices(vector.getDimNames(attrProfiles)); - - // rows - for (int r = 1; r <= nrow; r++) { - String headerString = rowHeader(r, vector, attrProfiles); - if (indexRowHeaders) { - spaces(b, rowHeaderWidth - headerString.length()); - b.append(headerString).append(' '); - } else { - b.append(headerString); - spaces(b, rowHeaderWidth - headerString.length() + 1); - } - for (int c = startColInd + 1; c <= colInd; c++) { - String dataString = dataStrings[(c - 1) * nrow + (r - 1)]; - boolean hasNegative = dataColWidths[c - 1] < 0; - int padding = Math.abs(dataColWidths[c - 1]) + ((isDoubleVector || isComplexVector) && hasNegative ? 1 : 0); - if (isListOrStringVector || (isComplexVector && !RRuntime.STRING_NA.equals(dataString))) { - // list elements are left-justified, and so are complex matrix elements - // that are not NA - b.append(dataString); - spaces(b, padColHeader(c, padding, vector, isListOrStringVector, attrProfiles).length() - dataString.length()); - } else { - // vector elements are right-justified, and so are NAs in complex - // matrices - String cellFormat = concat("%", intString(padColHeader(c, padding, vector, isListOrStringVector, attrProfiles).length()), "s"); - b.append(stringFormat(cellFormat, dataString)); - } - if (c < colInd) { - b.append(' '); - } - } - if (r < nrow) { - b.append('\n'); - } - } - if (colInd < dataColWidths.length) { - b.append('\n'); - } else { - break; - } - } - return builderToString(b); - } - } - - @NodeChildren({@NodeChild(value = "vector", type = RNode.class), @NodeChild(value = "isListOrStringVector", type = RNode.class), @NodeChild(value = "isComplexOrRawVector", type = RNode.class), - @NodeChild(value = "currentDimLevel", type = RNode.class), @NodeChild(value = "arrayBase", type = RNode.class), @NodeChild(value = "accDimensions", type = RNode.class), - @NodeChild(value = "header", type = RNode.class), @NodeChild(value = "isQuoted", type = RNode.class)}) - abstract static class PrintDimNode extends RNode { - - public abstract Object executeString(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, int currentDimLevel, int arrayBase, int accDimensions, - String header, byte isQuoted); - - @Child private PrintVector2DimNode vector2DimPrinter; - @Child private PrintDimNode dimPrinter; - - private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); - - private String printVector2Dim(RAbstractVector vector, RIntVector dimensions, int offset, byte isListOrStringVector, byte isComplexOrRawVector, byte isQuoted) { - if (vector2DimPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - vector2DimPrinter = insert(PrintVector2DimNodeGen.create(null, null, null, null, null, null)); - } - return (String) vector2DimPrinter.executeString(vector, dimensions, offset, isListOrStringVector, isComplexOrRawVector, isQuoted); - } - - private String printDimRecursive(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, int currentDimLevel, int arrayBase, int accDimensions, String header, - byte isQuoted) { - if (dimPrinter == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - dimPrinter = insert(PrintDimNodeGen.create(null, null, null, null, null, null, null, null)); - } - return (String) dimPrinter.executeString(vector, isListOrStringVector, isComplexOrRawVector, currentDimLevel, arrayBase, accDimensions, header, isQuoted); - } - - @TruffleBoundary - @Specialization - protected String printDim(RAbstractVector vector, byte isListOrStringVector, byte isComplexOrRawVector, int currentDimLevel, int arrayBase, int accDimensions, String header, byte isQuoted) { - int[] dimensions = vector.getDimensions(); - RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, RDataFactory.COMPLETE_VECTOR); - StringBuilder sb = new StringBuilder(); - int dimSize = dimensions[currentDimLevel - 1]; - if (dimSize == 0) { - return null; - } - if (currentDimLevel == 3) { - int matrixSize = dimensions[0] * dimensions[1]; - for (int dimInd = 0; dimInd < dimSize; dimInd++) { - // Checkstyle: stop - sb.append(", , "); - // Checkstyle: resume - sb.append(getDimId(vector, currentDimLevel, dimInd, attrProfiles)); - sb.append(", "); - sb.append(header); - sb.append("\n\n"); - sb.append(printVector2Dim(vector, dimensionsVector, arrayBase + (dimInd * matrixSize), isListOrStringVector, isComplexOrRawVector, isQuoted)); - sb.append("\n"); - if ((arrayBase + (dimInd * matrixSize) + matrixSize) < vector.getLength() || vector.getLength() == 0) { - sb.append("\n"); - } - } - } else { - int newAccDimensions = accDimensions / dimSize; - for (int dimInd = 0; dimInd < dimSize; dimInd++) { - int newArrayBase = arrayBase + newAccDimensions * dimInd; - String dimId = getDimId(vector, currentDimLevel, dimInd, attrProfiles); - String innerDims = printDimRecursive(vector, isListOrStringVector, isComplexOrRawVector, currentDimLevel - 1, newArrayBase, newAccDimensions, concat(dimId, ", ", header), - isQuoted); - if (innerDims == null) { - return null; - } else { - sb.append(innerDims); - } - } - return builderToString(sb); - } - return builderToString(sb); - } - } -} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java index 760c12d79b473e2988b281d135c54b5822a35f83..4b209c83fe3888acb7056aac0a3b70d79999a9d8 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java @@ -80,7 +80,7 @@ public class PrintFunctions { @Cached("createShowFunction(frame)") RFunction showFunction) { if (noOpt) { // S4 should only be called in case noOpt is true - RContext.getEngine().evalFunction(showFunction, null, null, o); + RContext.getEngine().evalFunction(showFunction, null, null, null, o); } else { printDefault(showFunction, digits, quote, naPrint, printGap, right, max, useSource, noOpt); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java index d8981ee372263777514a391e9597abcf9e7c23cc..fe4860d7a7b3cc5b35a79c475f1f03a8dc6e73c7 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Quit.java @@ -51,7 +51,7 @@ public abstract class Quit extends RBuiltinNode { @Specialization @TruffleBoundary protected Object doQuit(RAbstractStringVector saveArg, final int status, final byte runLastIn) { - if (RContext.getInstance().isInBrowser()) { + if (RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser()) { RError.warning(this, RError.Message.BROWSER_QUIT); return RNull.instance; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java index 9cd64c59070f6381542bbb808e9b9f1421f867fd..6e4e54843c564b6ab411d24c895a1113c8372c26 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java @@ -24,14 +24,13 @@ import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.attributes.AttributeAccess; import com.oracle.truffle.r.nodes.attributes.AttributeAccessNodeGen; +import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.objects.CollectGenericArgumentsNode; import com.oracle.truffle.r.nodes.objects.CollectGenericArgumentsNodeGen; import com.oracle.truffle.r.nodes.objects.DispatchGeneric; import com.oracle.truffle.r.nodes.objects.DispatchGenericNodeGen; -import com.oracle.truffle.r.nodes.unary.CastIntegerScalarNode; -import com.oracle.truffle.r.nodes.unary.CastStringScalarNode; -import com.oracle.truffle.r.nodes.unary.CastStringScalarNodeGen; +import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RCaller; @@ -58,14 +57,22 @@ public abstract class StandardGeneric extends RBuiltinNode { @Child private AttributeAccess genericAttrAccess; @Child private FrameFunctions.SysFunction sysFunction; - @Child private CastStringScalarNode castStringScalar = CastStringScalarNodeGen.create(); @Child private LocalReadVariableNode readMTableFirst = LocalReadVariableNode.create(RRuntime.DOT_ALL_MTABLE, true); @Child private LocalReadVariableNode readSigLength = LocalReadVariableNode.create(RRuntime.DOT_SIG_LENGTH, true); @Child private LocalReadVariableNode readSigARgs = LocalReadVariableNode.create(RRuntime.DOT_SIG_ARGS, true); - @Child private CastIntegerScalarNode castIntScalar = CastIntegerScalarNode.create(); @Child private CollectGenericArgumentsNode collectArgumentsNode; @Child private DispatchGeneric dispatchGeneric = DispatchGenericNodeGen.create(); + @Child private CastNode castIntScalar; + @Child private CastNode castStringScalar; + { + CastBuilder builder = new CastBuilder(); + builder.arg(0).asIntegerVector().findFirst(RRuntime.INT_NA); + builder.arg(1).asStringVector().findFirst(RRuntime.STRING_NA); + castIntScalar = builder.getCasts()[0]; + castStringScalar = builder.getCasts()[1]; + } + private final BranchProfile noGenFunFound = BranchProfile.create(); private final ConditionProfile sameNamesProfile = ConditionProfile.createBinaryProfile(); @@ -81,10 +88,10 @@ public abstract class StandardGeneric extends RBuiltinNode { // and this slow path should not be executed again REnvironment methodsEnv = REnvironment.getRegisteredNamespace("methods"); RFunction currentFunction = ReadVariableNode.lookupFunction(".getMethodsTable", methodsEnv.getFrame(), true); - mtable = (REnvironment) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), fdef); + mtable = (REnvironment) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), null, fdef); } RList sigArgs = (RList) readSigARgs.execute(null, fnFrame); - int sigLength = castIntScalar.executeInt(readSigLength.execute(null, fnFrame)); + int sigLength = (int) castIntScalar.execute(readSigLength.execute(null, fnFrame)); if (sigLength > sigArgs.getLength()) { throw RError.error(this, RError.Message.GENERIC, "'.SigArgs' is shorter than '.SigLength' says it should be"); } @@ -118,7 +125,7 @@ public abstract class StandardGeneric extends RBuiltinNode { noGenFunFound.enter(); return null; } - String gen = castStringScalar.executeString(genObj); + String gen = (String) castStringScalar.execute(genObj); if (sameNamesProfile.profile(gen == fname)) { return stdGenericInternal(frame, fVec, fn); } else { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java index 341a599ab3100966d00a8cae5e0d361e6d1cf630..c724cfb934de63b4aedf83776edd6eff31a02133 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TraceFunctions.java @@ -22,23 +22,41 @@ */ package com.oracle.truffle.r.nodes.builtin.base; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; + +import java.io.IOException; +import java.util.HashSet; + import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen; import com.oracle.truffle.r.nodes.builtin.helpers.TraceHandling; +import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RBuiltinKind; +import com.oracle.truffle.r.runtime.RCaller; 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.RType; import com.oracle.truffle.r.runtime.RVisibility; +import com.oracle.truffle.r.runtime.conn.StdConnections; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.MemoryTracer; import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; public class TraceFunctions { @@ -111,4 +129,128 @@ public class TraceFunctions { return RRuntime.asLogical(RContext.getInstance().stateInstrumentation.getTracingState()); } } + + public abstract static class TracememBase extends RBuiltinNode { + static { + MemoryTracer.setListener(new TracememBase.TracememListener()); + } + + protected static HashSet<Object> getTracedObjects() { + return RContext.getInstance().getInstrumentationState().getTracemem().getTracedObjects(); + } + + protected static String formatHashCode(Object x) { + return String.format("<0x%x>", x.hashCode()); + } + + protected static void startTracing(Object x) { + getTracedObjects().add(x); + MemoryTracer.reportEvents(); + } + + protected static void printToStdout(String msg) { + try { + StdConnections.getStdout().writeString(msg, true); + } catch (IOException ex) { + throw RError.error(RError.NO_CALLER, RError.Message.GENERIC, ex.getMessage()); + } + } + + @TruffleBoundary + protected static String getStackTrace() { + final StringBuffer result = new StringBuffer(); + Truffle.getRuntime().iterateFrames(frame -> { + Frame unwrapped = RArguments.unwrap(frame.getFrame(FrameAccess.READ_ONLY, true)); + if (RArguments.isRFrame(unwrapped)) { + RCaller call = RArguments.getCall(unwrapped); + if (call != null && call.isValidCaller()) { + result.append(RContext.getRRuntimeASTAccess().getCallerSource(call)); + result.append(' '); + } + } + return null; + }); + return result.toString(); + } + + private static final class TracememListener implements MemoryTracer.Listener { + @Override + public void reportCopying(RAbstractVector src, RAbstractVector dest) { + if (getTracedObjects().contains(src)) { + printToStdout(String.format("tracemem[0x%x -> 0x%x]: %s", src.hashCode(), dest.hashCode(), getStackTrace())); + } + } + } + } + + /** + * Note: tracemem does not support scalars: these are stored in frame directly not wrapped in a + * vector class. When these are manipulated as 'vectors', they are wrapped temporarily, such + * temporary vector wrappers cannot be traced however. + */ + @RBuiltin(name = "tracemem", kind = RBuiltinKind.PRIMITIVE, parameterNames = "x") + public abstract static class Tracemem extends TracememBase { + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("x").mustBe(nullValue().not(), Message.TRACEMEM_NOT_NULL); + } + + @Specialization + protected String execute(Object x) { + startTracing(x); + return formatHashCode(x); + } + } + + /** + * {@code retracemem} differences from {@code tracemem} are that it fails silently when R is not + * build with memory tracing support or x is NULL and it has additional parameter with an + * unclear meaning. + */ + @RBuiltin(name = "retracemem", kind = RBuiltinKind.PRIMITIVE, visibility = RVisibility.CUSTOM, parameterNames = {"x", "previous"}) + public abstract static class Retracemem extends TracememBase { + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("previous").defaultError(Message.INVALID_ARGUMENT, "previous").mustBe(stringValue().or(missingValue())); + } + + @Specialization + protected Object execute(Object x, @SuppressWarnings("unused") RNull previous) { + return getResult(x); + } + + @Specialization + protected Object execute(Object x, @SuppressWarnings("unused") RMissing previous) { + return getResult(x); + } + + @Specialization + protected Object execute(Object x, String previous) { + Object result = getResult(x); + if (x != null && x != RNull.instance) { + startTracing(x); + printToStdout(String.format("tracemem[%s -> 0x%x]: %s", previous, x.hashCode(), getStackTrace())); + } + return result; + } + + private static Object getResult(Object x) { + if (!isRNull(x) && getTracedObjects().contains(x)) { + RContext.getInstance().setVisible(true); + return formatHashCode(x); + } else { + RContext.getInstance().setVisible(false); + return RNull.instance; + } + } + } + + @RBuiltin(name = "untracemem", kind = RBuiltinKind.PRIMITIVE, visibility = RVisibility.OFF, parameterNames = "x") + public abstract static class Untracemem extends TracememBase { + @Specialization + protected RNull execute(Object x) { + getTracedObjects().remove(x); + return RNull.instance; + } + } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java index d91d4a8fbbe67167fb4ef437b99865e6abca9fe0..8c67c523f28176fe28445d8b3b5cd24ab0d73260 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateDimNames.java @@ -163,7 +163,7 @@ public abstract class UpdateDimNames extends RBuiltinNode { RList resDimNames = newDimNames; if (newDimNamesLength < dimensions.length) { // resize the array and fill the missing entries with NULL-s - resDimNames = resDimNames.copyResized(dimensions.length, true); + resDimNames = (RList) resDimNames.copyResized(dimensions.length, true); resDimNames.setAttributes(newDimNames); for (int i = newDimNamesLength; i < dimensions.length; i++) { resDimNames.updateDataAt(i, RNull.instance, null); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java index d192337e3792cb3a2d984f9081c02eaf12713e9d..317ce79c47937da8c3668727093dd086aeb21372 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateNames.java @@ -72,7 +72,7 @@ public abstract class UpdateNames extends RBuiltinNode { } RAbstractContainer result = (RAbstractContainer) container.getNonShared(); if (stringVector.getLength() < result.getLength()) { - stringVector = stringVector.copyResized(result.getLength(), true); + stringVector = (RStringVector) stringVector.copyResized(result.getLength(), true); } else if (stringVector.getLength() > result.getLength()) { throw RError.error(this, Message.NAMES_LONGER, stringVector.getLength(), result.getLength()); } else if (stringVector == container) { 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 34b82ecb414147552844b3dee4600d72809f2c5b..31d5719ff049de145a5bffefc6dd648a4c6b5fec 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 @@ -107,7 +107,7 @@ public abstract class UpdateSlot extends RBuiltinNode { checkAtAssignmentCall.call(frame, args); } else { // slow path - RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), objClass, name, valClass); + RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, getOriginalCall()), null, objClass, name, valClass); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java index 6d314f2c96ab4922cae488b2172ca3cfe206a09f..fac8867b5f7d166621ab0b1438eb78eb4d568577 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Vector.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.nodes.builtin.base; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement; import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -45,7 +46,7 @@ public abstract class Vector extends RBuiltinNode { @Override protected void createCasts(CastBuilder casts) { - casts.convertToInteger(1); + casts.arg("length").asIntegerVector().mustBe(singleElement()).findFirst(); } protected RType modeToType(String mode) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java index 3e2a6aaa8deccf201689df416f80212bce615034..d66b1be427541de72840a0cabaccb3aeb4b72115 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Xtfrm.java @@ -52,6 +52,6 @@ public abstract class Xtfrm extends RBuiltinNode { getNode = insert(GetNodeGen.create(null)); } RFunction func = (RFunction) getNode.execute(frame, "xtfrm.default", RArguments.getEnvironment(frame), RType.Function.getName(), true); - return RContext.getEngine().evalFunction(func, null, null, x); + return RContext.getEngine().evalFunction(func, null, null, null, x); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java index ad3a084a0509bca41911f3b84dbcb649a000d033..e3c6e354648afc064ce811405de7837b8ecf98aa 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/S4ObjectPrinter.java @@ -60,7 +60,7 @@ final class S4ObjectPrinter implements ValuePrinter<RS4Object> { static void printS4(PrintContext printCtx, Object o) { Frame frame = com.oracle.truffle.r.runtime.Utils.getActualCurrentFrame(); - RContext.getEngine().evalFunction(createShowFunction(frame), null, null, o); + RContext.getEngine().evalFunction(createShowFunction(frame), null, null, null, o); // The show function prints an additional new line character. The following attribute // instructs the ValuePrinter.println method not to print the new line since it was // already printed. diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java index 5020e439eb0315feca814e87cfa54aa8fe1ef7bc..d124cf1fcf353ea953fba02552e7f63f02f3d5d2 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java @@ -25,7 +25,11 @@ package com.oracle.truffle.r.nodes.builtin.base.printer; import java.io.IOException; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode; import com.oracle.truffle.r.nodes.builtin.base.Inherits; import com.oracle.truffle.r.nodes.builtin.base.InheritsNodeGen; @@ -130,4 +134,17 @@ public abstract class ValuePrinterNode extends RBaseNode { private static void prettyPrint(Object o, PrintContext printCtx) throws IOException { ValuePrinters.INSTANCE.println(o, printCtx); } + + public static String prettyPrint(final Object value) { + return (String) Truffle.getRuntime().createCallTarget(new RootNode(TruffleLanguage.class, null, null) { + + @Child ValuePrinterNode valuePrinterNode = ValuePrinterNodeGen.create(); + + @Override + public Object execute(VirtualFrame frame) { + return valuePrinterNode.prettyPrint(value, AnyVectorToStringVectorWriter::new); + } + }).call(value); + } + } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java index 684450a20e1db09768ac470155812eee1bd3f76a..72afb897490df85bbbd3f7e4e8e2a2047a74b4ea 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRIdentity.java @@ -29,7 +29,7 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RBuiltin; -@RBuiltin(aliases = "fastr.identity", name = ".fastr.identity", kind = PRIMITIVE, parameterNames = {""}) +@RBuiltin(name = ".fastr.identity", kind = PRIMITIVE, parameterNames = {""}) public abstract class FastRIdentity extends RBuiltinNode { @Specialization @TruffleBoundary diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java index 8f8d110389efc85db52d5646f675f56affa90ae1..ebbf9c234093fb3b997aa08ed58417a696e61447 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRRefCountInfo.java @@ -35,7 +35,7 @@ import com.oracle.truffle.r.runtime.data.RShareable; * returns -1 for non-shareable, 0 for private, 1 for temp, 2 for shared and SHARED_PERMANENT_VAL * for permanent shared */ -@RBuiltin(aliases = "fastr.refcountinfo", name = ".fastr.refcountinfo", kind = PRIMITIVE, parameterNames = {""}) +@RBuiltin(name = ".fastr.refcountinfo", kind = PRIMITIVE, parameterNames = {""}) public abstract class FastRRefCountInfo extends RBuiltinNode { @Specialization protected int refcount(Object x) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java index d88a058041e5dc99e68ddf349047e9aa9e70747e..6f4d154672217f2e9c6283836df8b593987500af 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java @@ -36,18 +36,25 @@ import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.ConsoleHandler; import com.oracle.truffle.r.runtime.context.Engine.ParseException; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RIntVector; 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.env.REnvironment; +import com.oracle.truffle.r.runtime.instrument.InstrumentationState.BrowserState; import com.oracle.truffle.r.runtime.nodes.RNode; /** * The interactive component of the {@code browser} function. * - * TODO GnuR does not allow quit() from the browser. This really needs to be checked in the quit - * builtin somehow. + * This is called in two ways: + * <ol> + * <li>implicitly when a function has had {@code debug} called</li> + * <li>explicitly by a call in the source code. N.B. in this case we must enable debugging + * (instrumentation) because a {@code n} command must stop at the next statement.</li> + * </ol> + * */ public abstract class BrowserInteractNode extends RNode { @@ -56,18 +63,19 @@ public abstract class BrowserInteractNode extends RNode { public static final int CONTINUE = 2; public static final int FINISH = 3; - private static String lastEmptyLineCommand = "n"; - @Specialization protected int interact(VirtualFrame frame) { CompilerDirectives.transferToInterpreter(); MaterializedFrame mFrame = frame.materialize(); ConsoleHandler ch = RContext.getInstance().getConsoleHandler(); + BrowserState browserState = RContext.getInstance().stateInstrumentation.getBrowserState(); String savedPrompt = ch.getPrompt(); ch.setPrompt(browserPrompt(RArguments.getDepth(frame))); + RFunction caller = RArguments.getFunction(frame); + boolean callerIsDebugged = DebugHandling.isDebugged(caller); int exitMode = NEXT; try { - RContext.getInstance().setInBrowser(true); + browserState.setInBrowser(true); LW: while (true) { String input = ch.readLine(); if (input != null) { @@ -76,7 +84,7 @@ public abstract class BrowserInteractNode extends RNode { if (input == null || input.length() == 0) { byte browserNLdisabledVec = RRuntime.asLogicalObject(RContext.getInstance().stateROptions.getValue("browserNLdisabled")); if (!RRuntime.fromLogical(browserNLdisabledVec)) { - input = lastEmptyLineCommand; + input = browserState.lastEmptyLineCommand(); } } switch (input) { @@ -86,11 +94,17 @@ public abstract class BrowserInteractNode extends RNode { break LW; case "n": exitMode = NEXT; - lastEmptyLineCommand = "n"; + if (!callerIsDebugged) { + DebugHandling.enableDebug(caller, "", "", true, true); + } + browserState.setLastEmptyLineCommand("n"); break LW; case "s": exitMode = STEP; - lastEmptyLineCommand = "s"; + if (!callerIsDebugged) { + DebugHandling.enableDebug(caller, "", "", true, true); + } + browserState.setLastEmptyLineCommand("s"); break LW; case "f": exitMode = FINISH; @@ -128,7 +142,7 @@ public abstract class BrowserInteractNode extends RNode { } } finally { ch.setPrompt(savedPrompt); - RContext.getInstance().setInBrowser(false); + browserState.setInBrowser(false); } return exitMode; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java index 76c6e1167e48c003fdb5ee32c9fb597514912321..799fa83b5bd2f153efc32738aee19ed16c462890 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java @@ -100,19 +100,15 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNodeVisitor; */ public class DebugHandling { - /** - * This flag is used to (temporarily) disable all debugging across calls that are used - * internally in the implementation. - */ - private static boolean globalDisable; - /** * Attach the DebugHandling instrument to the FunctionStatementsNode and all syntactic nodes. + * + * @param implicit TODO */ - public static boolean enableDebug(RFunction func, Object text, Object condition, boolean once) { + public static boolean enableDebug(RFunction func, Object text, Object condition, boolean once, boolean implicit) { FunctionStatementsEventListener fbr = getFunctionStatementsEventListener(func); if (fbr == null) { - attachDebugHandler(func, text, condition, once); + attachDebugHandler(func, text, condition, once, implicit); } else { fbr.enable(); } @@ -142,25 +138,12 @@ public class DebugHandling { return (FunctionStatementsEventListener) RContext.getInstance().stateInstrumentation.getDebugListener(fdn.getSourceSection()); } - /** - * Disables/enables debugging globally. Intended to be used for short period, typically while - * executing functions used internally by the implementation. - * - * @param disable {@code true} to disable, {@code false} to enable. - * @return the current value (default {@code false}. - */ - public static boolean globalDisable(boolean disable) { - boolean current = globalDisable; - globalDisable = disable; - return current; + private static void attachDebugHandler(RFunction func, Object text, Object condition, boolean once, boolean implicit) { + attachDebugHandler(RInstrumentation.getFunctionDefinitionNode(func), text, condition, once, implicit); } - private static void attachDebugHandler(RFunction func, Object text, Object condition, boolean once) { - attachDebugHandler(RInstrumentation.getFunctionDefinitionNode(func), text, condition, once); - } - - private static FunctionStatementsEventListener attachDebugHandler(FunctionDefinitionNode fdn, Object text, Object condition, boolean once) { - FunctionStatementsEventListener fser = new FunctionStatementsEventListener(fdn, text, condition, once); + private static FunctionStatementsEventListener attachDebugHandler(FunctionDefinitionNode fdn, Object text, Object condition, boolean once, boolean implicit) { + FunctionStatementsEventListener fser = new FunctionStatementsEventListener(fdn, text, condition, once, implicit); // First attach the main listener on the START_FUNCTION Instrumenter instrumenter = RInstrumentation.getInstrumenter(); SourceSectionFilter.Builder functionBuilder = RInstrumentation.createFunctionFilter(fdn, StandardTags.RootTag.class); @@ -189,7 +172,7 @@ public class DebugHandling { FunctionStatementsEventListener fser = getFunctionStatementsEventListener(fdn); if (fser == null) { // attach a "once" listener - fser = attachDebugHandler(fdn, null, null, true); + fser = attachDebugHandler(fdn, null, null, true, false); } else { if (fser.disabled()) { fser.enable(); @@ -221,7 +204,7 @@ public class DebugHandling { } boolean disabled() { - return disabled || globalDisable; + return disabled || RContext.getInstance().stateInstrumentation.debugGloballyDisabled(); } void disable() { @@ -314,6 +297,11 @@ public class DebugHandling { * handler established temporarily for step-into. */ private final boolean once; + /** + * Denotes that this was installed by an explicit call to {@code browser()} on an otherwise + * undebugged function. {@code assert once == true}. + */ + private final boolean implicit; /** * Records whether a permanent handler was (temporarily) enabled for a step-into. * @@ -321,11 +309,12 @@ public class DebugHandling { private boolean enabledForStepInto; private boolean continuing; - FunctionStatementsEventListener(FunctionDefinitionNode functionDefinitionNode, Object text, Object condition, boolean once) { + FunctionStatementsEventListener(FunctionDefinitionNode functionDefinitionNode, Object text, Object condition, boolean once, boolean implicit) { super(functionDefinitionNode, text, condition); RContext.getInstance().stateInstrumentation.putDebugListener(functionDefinitionNode.getSourceSection(), this); statementListener = new StatementEventListener(functionDefinitionNode, text, condition); this.once = once; + this.implicit = implicit; } StatementEventListener getStatementListener() { @@ -415,8 +404,10 @@ public class DebugHandling { } private void returnCleanup(VirtualFrame frame) { - print("exiting from: ", false); - printCall(frame); + if (!implicit) { + print("exiting from: ", false); + printCall(frame); + } if (once || enabledForStepInto) { disable(); } else if (continuing) { @@ -559,7 +550,7 @@ public class DebugHandling { @Override public void onEnter(EventContext context, VirtualFrame frame) { - if (!globalDisable) { + if (!RContext.getInstance().stateInstrumentation.debugGloballyDisabled()) { FunctionDefinitionNode fdn = (FunctionDefinitionNode) context.getInstrumentedNode().getRootNode(); ensureSingleStep(fdn); functionStatementsEventListener.clearStepInstrument(); diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java index 95814c609349b8e2114f5314a6e5c4bca4518a33..777b8e0e05be525d5a074cf03e726f00ac77707a 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java @@ -35,11 +35,10 @@ public class CastStringNodeGenSampler extends CastNodeSampler<CastStringNodeGen> @Override public TypeExpr resultTypes(TypeExpr inputType) { TypeExpr rt = super.resultTypes(inputType); - if (castNode.isEmptyVectorConvertedToNull()) { + if (castNode.convertEmptyVectorToNull()) { return rt.or(TypeExpr.union(RNull.class)); } else { return rt; } } - } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java index 81fec609976bd179e5c43f6c9a39c3ed30c1ad7d..887a6d7609e140f0d12ee908f7aebdc91ad88f31 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/AccessSlotNode.java @@ -79,7 +79,7 @@ public abstract class AccessSlotNode extends RNode { // TODO: any way to cache it or use a mechanism similar to overrides? REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods"); RFunction dataPart = getDataPartFunction(methodsNamespace); - return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), object); + return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), null, object); } else if (name == RRuntime.NAMES_ATTR_KEY && object instanceof RAbstractVector) { assert false; // RS4Object can never be a vector? return RNull.instance; @@ -137,7 +137,7 @@ public abstract class AccessSlotNode extends RNode { // TODO: any way to cache it or use a mechanism similar to overrides? REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods"); RFunction dataPart = getDataPartFunction(methodsNamespace); - return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), object); + return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), null, object); } // this is really a fallback specialization but @Fallback does not work here (because of the diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java index 5a751ab1ec34382631eabd8fad06bf13c27c47e3..1055b68104d67594963fe2adf41a7c0bf37bdfe2 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/UpdateSlotNode.java @@ -68,7 +68,8 @@ public abstract class UpdateSlotNode extends RNode { REnvironment methodsNamespace = REnvironment.getRegisteredNamespace("methods"); Object f = methodsNamespace.findFunction("setDataPart"); RFunction dataPart = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(f); - return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), object, prepareValue(value), + return RContext.getEngine().evalFunction(dataPart, methodsNamespace.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), null, object, + prepareValue(value), RRuntime.LOGICAL_TRUE); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java index 66ac8ced4bcd2759534d469d1ee878725afa55aa..908e71262a44a928adcade80d4287a953fc8215a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java @@ -43,7 +43,6 @@ import com.oracle.truffle.r.nodes.unary.CastLogicalBaseNode; import com.oracle.truffle.r.nodes.unary.CastLogicalBaseNodeGen; import com.oracle.truffle.r.nodes.unary.CastLogicalNode; import com.oracle.truffle.r.nodes.unary.CastLogicalNodeGen; -import com.oracle.truffle.r.nodes.unary.CastLogicalScalarNode; import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.nodes.unary.CastStringBaseNode; import com.oracle.truffle.r.nodes.unary.CastStringBaseNodeGen; @@ -53,7 +52,6 @@ import com.oracle.truffle.r.nodes.unary.CastToAttributableNodeGen; import com.oracle.truffle.r.nodes.unary.CastToVectorNodeGen; import com.oracle.truffle.r.nodes.unary.ChainedCastNode; import com.oracle.truffle.r.nodes.unary.ConditionalMapNodeGen; -import com.oracle.truffle.r.nodes.unary.ConvertIntNodeGen; import com.oracle.truffle.r.nodes.unary.FilterNodeGen; import com.oracle.truffle.r.nodes.unary.FindFirstNodeGen; import com.oracle.truffle.r.nodes.unary.FirstBooleanNodeGen; @@ -162,10 +160,6 @@ public final class CastBuilder { return insert(index, FirstIntNode.createWithWarning(RError.Message.FIRST_ELEMENT_USED, name, intNa)); } - public CastBuilder convertToInteger(int index) { - return insert(index, ConvertIntNodeGen.create()); - } - public CastBuilder firstIntegerWithError(int index, RError.Message error, String name) { insert(index, CastIntegerNodeGen.create(false, false, false)); return insert(index, FirstIntNode.createWithError(error, name)); @@ -184,7 +178,8 @@ public final class CastBuilder { } public CastBuilder firstLogical(int index) { - return insert(index, CastLogicalScalarNode.create()); + arg(index).asLogicalVector().findFirst(RRuntime.LOGICAL_NA); + return this; } public InitialPhaseBuilder<Object> arg(int argumentIndex, String argumentName) { @@ -387,7 +382,7 @@ public final class CastBuilder { @Override public <T, R extends T> TypePredicateArgumentFilter<T, R> nullValue() { - return TypePredicateArgumentFilter.fromLambda(x -> x == RNull.instance || x == null); + return new TypePredicateArgumentFilter<>(x -> x == RNull.instance || x == null, true); } @Override 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 d0be229b8ae28d07c86c50eef7b72d1af1308919..01b3e47c819e48bb4e9cc597456c04ccdd18dbb9 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 @@ -246,18 +246,18 @@ public abstract class CallMatcherNode extends RBaseNode { // Note: see CallMatcherNode#specialize for details on suppliedSignature/Arguments // this unrolls all varargs instances in suppliedArgs into a flat array of arguments - RArgsValuesAndNames preparedArguments = prepareSuppliedArgument(preparePermutation, suppliedArguments, suppliedSignature); + Object[] preparedArguments = prepareSuppliedArgument(preparePermutation, suppliedArguments); // This is then matched to formal signature: the result is non-flat array of // arguments possibly containing varargs -- something that argument matching for a // direct function call would create would this be a direct function call - RArgsValuesAndNames matchedArgs = ArgumentMatcher.matchArgumentsEvaluated(permutation, preparedArguments.getArguments(), null, formals); + RArgsValuesAndNames matchedArgs = ArgumentMatcher.matchArgumentsEvaluated(permutation, preparedArguments, null, formals); Object[] reorderedArgs = matchedArgs.getArguments(); evaluatePromises(frame, cachedFunction, reorderedArgs, formals.getSignature().getVarArgIndex()); if (call != null) { RCaller parent = RArguments.getCall(frame).getParent(); String genFunctionName = functionName == null ? function.getName() : functionName; - Supplier<RSyntaxNode> argsSupplier = RCallerHelper.createFromArguments(genFunctionName, preparedArguments); + Supplier<RSyntaxNode> argsSupplier = RCallerHelper.createFromArguments(genFunctionName, preparePermutation, suppliedArguments, suppliedSignature); RCaller caller = genFunctionName == null ? RCaller.createInvalid(frame, parent) : RCaller.create(frame, parent, argsSupplier); Object[] arguments = prepareArguments(reorderedArgs, matchedArgs.getSignature(), cachedFunction, dispatchArgs, caller); return call.call(frame, arguments); @@ -311,27 +311,24 @@ public abstract class CallMatcherNode extends RBaseNode { } @ExplodeLoop - private static RArgsValuesAndNames prepareSuppliedArgument(long[] preparePermutation, Object[] arguments, ArgumentsSignature suppliedSignature) { + private static Object[] prepareSuppliedArgument(long[] preparePermutation, Object[] arguments) { Object[] values = new Object[preparePermutation.length]; - String[] names = new String[preparePermutation.length]; for (int i = 0; i < values.length; i++) { long source = preparePermutation[i]; - if (!ArgumentsSignature.isVarArgsIndex(source)) { - values[i] = arguments[(int) source]; - names[i] = suppliedSignature.getName((int) source); - } else { + if (ArgumentsSignature.isVarArgsIndex(source)) { int varArgsIdx = ArgumentsSignature.extractVarArgsIndex(source); int argsIdx = ArgumentsSignature.extractVarArgsArgumentIndex(source); RArgsValuesAndNames varargs = (RArgsValuesAndNames) arguments[varArgsIdx]; values[i] = varargs.getArguments()[argsIdx]; - names[i] = varargs.getSignature().getName(argsIdx); + } else { + values[i] = arguments[(int) source]; } } - return new RArgsValuesAndNames(values, ArgumentsSignature.get(names)); + return values; } } - private static final class CallMatcherGenericNode extends CallMatcherNode { + public static final class CallMatcherGenericNode extends CallMatcherNode { CallMatcherGenericNode(boolean forNextMethod, boolean argsAreEvaluated) { super(forNextMethod, argsAreEvaluated); @@ -339,12 +336,9 @@ public abstract class CallMatcherNode extends RBaseNode { @Child private IndirectCallNode call = Truffle.getRuntime().createIndirectCallNode(); - private final ConditionProfile hasVarArgsProfile = ConditionProfile.createBinaryProfile(); - private final ConditionProfile hasUnmatchedProfile = ConditionProfile.createBinaryProfile(); - @Override public Object execute(VirtualFrame frame, ArgumentsSignature suppliedSignature, Object[] suppliedArguments, RFunction function, String functionName, DispatchArgs dispatchArgs) { - RArgsValuesAndNames reorderedArgs = reorderArguments(suppliedArguments, function, suppliedSignature); + RArgsValuesAndNames reorderedArgs = reorderArguments(suppliedArguments, function, suppliedSignature, forNextMethod, this); evaluatePromises(frame, function, reorderedArgs.getArguments(), reorderedArgs.getSignature().getVarArgIndex()); RCaller parent = RArguments.getCall(frame).getParent(); @@ -368,7 +362,7 @@ public abstract class CallMatcherNode extends RBaseNode { } @TruffleBoundary - protected RArgsValuesAndNames reorderArguments(Object[] args, RFunction function, ArgumentsSignature paramSignature) { + public static RArgsValuesAndNames reorderArguments(Object[] args, RFunction function, ArgumentsSignature paramSignature, boolean forNextMethod, RBaseNode callingNode) { assert paramSignature.getLength() == args.length; int argCount = args.length; @@ -378,10 +372,10 @@ public abstract class CallMatcherNode extends RBaseNode { boolean hasUnmatched = false; for (int fi = 0; fi < argCount; fi++) { Object arg = args[fi]; - if (hasVarArgsProfile.profile(arg instanceof RArgsValuesAndNames)) { + if (arg instanceof RArgsValuesAndNames) { hasVarArgs = true; argListSize += ((RArgsValuesAndNames) arg).getLength() - 1; - } else if (hasUnmatchedProfile.profile(paramSignature.isUnmatched(fi))) { + } else if (paramSignature.isUnmatched(fi)) { hasUnmatched = true; argListSize--; } @@ -429,7 +423,7 @@ public abstract class CallMatcherNode extends RBaseNode { RArgsValuesAndNames evaledArgs = new RArgsValuesAndNames(argValues, signature); // ...to match them against the chosen function's formal arguments - RArgsValuesAndNames evaluated = ArgumentMatcher.matchArgumentsEvaluated((RRootNode) function.getRootNode(), evaledArgs, null, forNextMethod, this); + RArgsValuesAndNames evaluated = ArgumentMatcher.matchArgumentsEvaluated((RRootNode) function.getRootNode(), evaledArgs, null, forNextMethod, callingNode); return evaluated; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java index a680de8e2b195b3c1980f4cb0be923b10fb9081d..a680b84ceb4391222b721c5e3898fec41614a7be 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java @@ -185,7 +185,8 @@ abstract class S4Class extends RBaseNode { // the assumption here is that the R function can only return either a String or // RStringVector s4Extends = (RStringVector) castToVector.execute( - RContext.getEngine().evalFunction(sExtendsForS3Function, methodsEnv.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), classAttr)); + RContext.getEngine().evalFunction(sExtendsForS3Function, methodsEnv.getFrame(), RCaller.create(Utils.getActualCurrentFrame(), RASTUtils.getOriginalCall(this)), null, + classAttr)); RContext.getInstance().putS4Extends(classAttr, s4Extends); } return s4Extends; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java index 13b9a157c77574f6ee21f603f8d72fa7281aebad..af7f0639df7fd2f1dc27484dbcd0017a644bce79 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallerHelper.java @@ -51,7 +51,7 @@ public final class RCallerHelper { * S3/S4 dispatch), and that can then be used to retrieve correct syntax nodes. * * @param arguments array with arguments and corresponding names. This method strips any - * {@code RMissing} arguments and unrolls all varargs withint arguments array. + * {@code RMissing} arguments and unrolls all varargs within the arguments array. */ public static Supplier<RSyntaxNode> createFromArguments(RFunction function, RArgsValuesAndNames arguments) { return createFromArgumentsInternal(function, arguments); @@ -105,17 +105,50 @@ public final class RCallerHelper { } return syntaxNode; } + }; + } - private RSyntaxNode getArgumentNode(Object arg) { - if (arg instanceof RPromise) { - RPromise p = (RPromise) arg; - return p.getRep().asRSyntaxNode(); - } else if (!(arg instanceof RMissing)) { - return ConstantNode.create(arg); + private static RSyntaxNode getArgumentNode(Object arg) { + if (arg instanceof RPromise) { + RPromise p = (RPromise) arg; + return p.getRep().asRSyntaxNode(); + } else if (!(arg instanceof RMissing)) { + return ConstantNode.create(arg); + } + return null; + } + + /** + * This method calculates the signature of the permuted arguments lazily. + */ + public static Supplier<RSyntaxNode> createFromArguments(String function, long[] preparePermutation, Object[] suppliedArguments, ArgumentsSignature suppliedSignature) { + return new Supplier<RSyntaxNode>() { + + RSyntaxNode syntaxNode = null; + + @Override + public RSyntaxNode get() { + if (syntaxNode == null) { + Object[] values = new Object[preparePermutation.length]; + String[] names = new String[preparePermutation.length]; + for (int i = 0; i < values.length; i++) { + long source = preparePermutation[i]; + if (!ArgumentsSignature.isVarArgsIndex(source)) { + values[i] = suppliedArguments[(int) source]; + names[i] = suppliedSignature.getName((int) source); + } else { + int varArgsIdx = ArgumentsSignature.extractVarArgsIndex(source); + int argsIdx = ArgumentsSignature.extractVarArgsArgumentIndex(source); + RArgsValuesAndNames varargs = (RArgsValuesAndNames) suppliedArguments[varArgsIdx]; + values[i] = varargs.getArguments()[argsIdx]; + names[i] = varargs.getSignature().getName(argsIdx); + } + } + RArgsValuesAndNames arguments = new RArgsValuesAndNames(values, ArgumentsSignature.get(names)); + syntaxNode = createFromArguments(function, arguments).get(); } - return null; + return syntaxNode; } - }; } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java index b54a2b7daf74a520f530cb33fb92f9dcf08e85e0..ea78fd31ab168ccb3dd5c1bde48c717af525b335 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java @@ -23,6 +23,7 @@ package com.oracle.truffle.r.nodes.function; import com.oracle.truffle.api.profiles.BranchProfile; +import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RS4Object; @@ -38,6 +39,7 @@ public abstract class WrapArgumentBaseNode extends RNode { @Child protected RNode operand; + private final ValueProfile argumentValueProfile; private final BranchProfile everSeenVector; private final BranchProfile everSeenLanguage; private final BranchProfile everSeenFunction; @@ -49,6 +51,7 @@ public abstract class WrapArgumentBaseNode extends RNode { protected WrapArgumentBaseNode(RNode operand, boolean initProfiles) { this.operand = operand; if (initProfiles) { + argumentValueProfile = ValueProfile.createClassProfile(); everSeenVector = BranchProfile.create(); everSeenLanguage = BranchProfile.create(); everSeenFunction = BranchProfile.create(); @@ -56,6 +59,7 @@ public abstract class WrapArgumentBaseNode extends RNode { shareable = BranchProfile.create(); nonShareable = BranchProfile.create(); } else { + argumentValueProfile = null; everSeenVector = null; everSeenLanguage = null; everSeenFunction = null; @@ -65,7 +69,8 @@ public abstract class WrapArgumentBaseNode extends RNode { } } - protected RShareable getShareable(Object result) { + protected RShareable getShareable(Object initialResult) { + Object result = argumentValueProfile.profile(initialResult); if (result instanceof RVector) { everSeenVector.enter(); return (RVector) result; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java index 116526a385172cdcded48933ec097afb5218560d..8f9367277fe9c26aa4414ea4a1e78344cbfbfb60 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java @@ -74,7 +74,7 @@ public abstract class DispatchGeneric extends RBaseNode { CompilerDirectives.transferToInterpreterAndInvalidate(); REnvironment methodsEnv = REnvironment.getRegisteredNamespace("methods"); RFunction currentFunction = ReadVariableNode.lookupFunction(".InheritForDispatch", methodsEnv.getFrame(), true); - method = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, RASTUtils.getOriginalCall(this)), classes, fdef, mtable); + method = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, RASTUtils.getOriginalCall(this)), null, classes, fdef, mtable); } method = loadMethod.executeRFunction(frame, method, fname); Object ret = executeMethod.executeObject(frame, method, fname); 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 d4cfc8497ec4751b17cc0654c1149a1a8b5194ca..72a4c84ab2dcfdc2f42b28b3d0a4a3ed09b55855 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 @@ -135,7 +135,7 @@ abstract class LoadMethod extends RBaseNode { ret = (RFunction) loadMethodCall.call(frame, args); } else { // slow path - ret = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), caller, fdef, fname, REnvironment.frameToEnvironment(frame.materialize())); + ret = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), caller, null, fdef, fname, REnvironment.frameToEnvironment(frame.materialize())); } } else { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java index bc94284a06417fc4261627bda80c3edcacce48f8..9f8baf3851fb8e0f2ea5d8c9ec82a81c04e5bc9c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java @@ -12,15 +12,14 @@ */ package com.oracle.truffle.r.nodes.objects; -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.access.AccessSlotNode; import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen; import com.oracle.truffle.r.nodes.attributes.AttributeAccess; import com.oracle.truffle.r.nodes.attributes.AttributeAccessNodeGen; +import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; -import com.oracle.truffle.r.nodes.unary.CastLogicalScalarNode; -import com.oracle.truffle.r.nodes.unary.CastStringScalarNode; +import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.nodes.unary.DuplicateNode; import com.oracle.truffle.r.nodes.unary.DuplicateNodeGen; import com.oracle.truffle.r.runtime.RError; @@ -36,22 +35,26 @@ public abstract class NewObject extends RExternalBuiltinNode.Arg1 { @Child private AccessSlotNode accessSlotVirtual = AccessSlotNodeGen.create(true, null, null); @Child private AccessSlotNode accessSlotClassName = AccessSlotNodeGen.create(true, null, null); @Child private AccessSlotNode accessSlotPrototypeName = AccessSlotNodeGen.create(true, null, null); - @Child private CastStringScalarNode castStringScalar; - @Child private CastLogicalScalarNode castLogicalScalar = CastLogicalScalarNode.create(); @Child private DuplicateNode duplicate = DuplicateNodeGen.create(true); @Child private AttributeAccess pckgAttrAccess = AttributeAccessNodeGen.create(RRuntime.PCKG_ATTR_KEY); + @Child private CastNode castStringScalar; + @Child private CastNode castLogicalScalar; + { + CastBuilder builder = new CastBuilder(); + builder.arg(0).asStringVector().findFirst(RRuntime.STRING_NA); + builder.arg(1).asLogicalVector().findFirst(RRuntime.LOGICAL_NA); + castStringScalar = builder.getCasts()[0]; + castLogicalScalar = builder.getCasts()[1]; + } + @Specialization(guards = "!isNull(classDef)") protected Object doNewObject(Object classDef) { Object e = accessSlotVirtual.executeAccess(classDef, RRuntime.S_VIRTUAL); - if (castLogicalScalar.executeByte(e) != RRuntime.LOGICAL_FALSE) { - if (castStringScalar == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - castStringScalar = insert(CastStringScalarNode.create()); - } + if (((byte) castLogicalScalar.execute(e)) != RRuntime.LOGICAL_FALSE) { e = accessSlotClassName.executeAccess(classDef, RRuntime.S_CLASSNAME); - throw RError.error(this, RError.Message.OBJECT_FROM_VIRTUAL, castStringScalar.executeString(e)); + throw RError.error(this, RError.Message.OBJECT_FROM_VIRTUAL, castStringScalar.execute(e)); } e = accessSlotClassName.executeAccess(classDef, RRuntime.S_CLASSNAME); Object prototype = accessSlotPrototypeName.executeAccess(classDef, RRuntime.S_PROTOTYPE); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java index 4590f6475ff18b5620d80e531d2701f094114497..9f401aa09158f569c14c17be0220dbd234d13d1e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastBaseNode.java @@ -22,19 +22,24 @@ */ package com.oracle.truffle.r.nodes.unary; -import com.oracle.truffle.api.dsl.NodeField; -import com.oracle.truffle.api.dsl.NodeFields; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.NullProfile; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.env.REnvironment; -@NodeFields({@NodeField(name = "preserveNames", type = boolean.class), @NodeField(name = "dimensionsPreservation", type = boolean.class), @NodeField(name = "attrPreservation", type = boolean.class)}) public abstract class CastBaseNode extends CastNode { private final BranchProfile listCoercionErrorBranch = BranchProfile.create(); @@ -43,11 +48,29 @@ public abstract class CastBaseNode extends CastNode { private final NullProfile hasNamesProfile = NullProfile.create(); private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); - protected abstract boolean isPreserveNames(); + private final boolean preserveNames; + private final boolean preserveDimensions; + private final boolean preserveAttributes; - protected abstract boolean isDimensionsPreservation(); + protected CastBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + this.preserveNames = preserveNames; + this.preserveDimensions = preserveDimensions; + this.preserveAttributes = preserveAttributes; + } + + public boolean preserveNames() { + return preserveNames; + } - protected abstract boolean isAttrPreservation(); + public boolean preserveDimensions() { + return preserveDimensions; + } + + public boolean preserveAttributes() { + return preserveAttributes; + } + + protected abstract RType getTargetType(); protected RError throwCannotCoerceListError(String type) { listCoercionErrorBranch.enter(); @@ -55,7 +78,7 @@ public abstract class CastBaseNode extends CastNode { } protected int[] getPreservedDimensions(RAbstractContainer operand) { - if (isDimensionsPreservation()) { + if (preserveDimensions()) { return hasDimensionsProfile.profile(operand.getDimensions()); } else { return null; @@ -63,7 +86,7 @@ public abstract class CastBaseNode extends CastNode { } protected RStringVector getPreservedNames(RAbstractContainer operand) { - if (isPreserveNames()) { + if (preserveNames()) { return hasNamesProfile.profile(operand.getNames(attrProfiles)); } else { return null; @@ -71,11 +94,26 @@ public abstract class CastBaseNode extends CastNode { } protected void preserveDimensionNames(RAbstractContainer operand, RVector ret) { - if (isDimensionsPreservation()) { + if (preserveDimensions()) { RList dimNames = operand.getDimNames(attrProfiles); if (hasDimNamesProfile.profile(dimNames != null)) { ret.setDimNames((RList) dimNames.copy()); } } } + + @Fallback + @TruffleBoundary + protected Object doOther(Object value) { + Object mappedValue = RRuntime.asAbstractVector(value); + if (mappedValue instanceof REnvironment) { + throw RError.error(RError.SHOW_CALLER, RError.Message.ENVIRONMENTS_COERCE); + } else if (mappedValue instanceof RTypedValue) { + throw RError.error(RError.SHOW_CALLER, RError.Message.CANNOT_COERCE, ((RTypedValue) mappedValue).getRType().getName(), getTargetType().getName()); + } else if (mappedValue instanceof TruffleObject) { + throw RError.error(RError.SHOW_CALLER, RError.Message.CANNOT_COERCE, "truffleobject", getTargetType().getName()); + } else { + throw RInternalError.shouldNotReachHere("unexpected value of type " + (mappedValue == null ? "null" : mappedValue.getClass())); + } + } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java index b781b66977c8d4a3fb2fb183bcbe63fd51cd6723..2e6fae29105ba85c5233d5ed27c7ec804b8173a1 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastComplexNode.java @@ -24,14 +24,13 @@ package com.oracle.truffle.r.nodes.unary; import java.util.function.IntFunction; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RComplexVector; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -60,6 +59,15 @@ public abstract class CastComplexNode extends CastBaseNode { public abstract Object executeComplex(Object o); + protected CastComplexNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + @Override + protected final RType getTargetType() { + return RType.Complex; + } + @Specialization protected RNull doNull(@SuppressWarnings("unused") RNull operand) { return RNull.instance; @@ -121,7 +129,7 @@ public abstract class CastComplexNode extends CastBaseNode { } RComplexVector ret = RDataFactory.createComplexVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; @@ -174,7 +182,7 @@ public abstract class CastComplexNode extends CastBaseNode { } RComplexVector ret = RDataFactory.createComplexVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; @@ -190,12 +198,6 @@ public abstract class CastComplexNode extends CastBaseNode { return createResultVector(operand, index -> RDataFactory.createComplex(operand.getDataAt(index).getValue(), 0)); } - @Fallback - @TruffleBoundary - protected int doOther(Object operand) { - throw new ConversionFailedException(operand.getClass().getName()); - } - public static CastComplexNode create() { return CastComplexNodeGen.create(true, true, true); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java index 159da03c48d96ea984e285b89d44b3ce3a7ed9ea..c4377e38e2f9e050931b613a7f2e815cb8fb1bac 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleBaseNode.java @@ -22,14 +22,13 @@ */ package com.oracle.truffle.r.nodes.unary; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; @@ -38,9 +37,18 @@ import com.oracle.truffle.r.runtime.ops.na.NAProfile; public abstract class CastDoubleBaseNode extends CastBaseNode { - private final NACheck naCheck = NACheck.create(); - private final NAProfile naProfile = NAProfile.create(); - private final BranchProfile warningBranch = BranchProfile.create(); + protected final NACheck naCheck = NACheck.create(); + protected final NAProfile naProfile = NAProfile.create(); + protected final BranchProfile warningBranch = BranchProfile.create(); + + protected CastDoubleBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + @Override + protected final RType getTargetType() { + return RType.Double; + } public abstract Object executeDouble(int o); @@ -101,11 +109,4 @@ public abstract class CastDoubleBaseNode extends CastBaseNode { protected double doRaw(RRaw operand) { return RRuntime.raw2double(operand); } - - @Fallback - @TruffleBoundary - protected double doOther(Object operand) { - throw new ConversionFailedException(operand.getClass().getName()); - } - } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java index ae8e7d86ba191c6f14f165743912026249fd0e6a..47459c84f748ba2d2c43a1eaeb17820d77e69ecb 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastDoubleNode.java @@ -27,7 +27,6 @@ import java.util.function.IntToDoubleFunction; 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.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; @@ -42,21 +41,19 @@ import com.oracle.truffle.r.runtime.data.RStringVector; 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.RAbstractVector; -import com.oracle.truffle.r.runtime.ops.na.NACheck; -import com.oracle.truffle.r.runtime.ops.na.NAProfile; public abstract class CastDoubleNode extends CastDoubleBaseNode { - private final NACheck naCheck = NACheck.create(); - private final NAProfile naProfile = NAProfile.create(); - private final BranchProfile warningBranch = BranchProfile.create(); + protected CastDoubleNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } @Child private CastDoubleNode recursiveCastDouble; private Object castDoubleRecursive(Object o) { if (recursiveCastDouble == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveCastDouble = insert(CastDoubleNodeGen.create(isPreserveNames(), isDimensionsPreservation(), isAttrPreservation())); + recursiveCastDouble = insert(CastDoubleNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes())); } return recursiveCastDouble.executeDouble(o); } @@ -64,7 +61,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode { private RDoubleVector createResultVector(RAbstractVector operand, double[] ddata) { RDoubleVector ret = RDataFactory.createDoubleVector(ddata, naCheck.neverSeenNA(), getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; @@ -81,7 +78,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode { } RDoubleVector ret = RDataFactory.createDoubleVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; @@ -127,7 +124,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode { } RDoubleVector ret = RDataFactory.createDoubleVector(ddata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; @@ -201,7 +198,7 @@ public abstract class CastDoubleNode extends CastDoubleBaseNode { } } RDoubleVector ret = RDataFactory.createDoubleVector(result, !seenNA); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(list); } return ret; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java index cd73b7847f815970da3903c065779659dc8c2e8f..10e7fe8bfe7acb9b5388f997afb9859a29b56e53 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastExpressionNode.java @@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.unary; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RExpression; @@ -39,6 +40,15 @@ public abstract class CastExpressionNode extends CastBaseNode { public abstract Object executeExpression(Object o); + protected CastExpressionNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + @Override + protected final RType getTargetType() { + return RType.Expression; + } + @Specialization protected RExpression doNull(@SuppressWarnings("unused") RNull value) { return create(RNull.instance); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java index 9445804d02df77dbe1d82a72a041bd8228b8b446..5e3b5b5aa16d0650fcd6cd5a22389a84cb0d50e3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerBaseNode.java @@ -29,12 +29,11 @@ import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; -import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.ops.na.NACheck; public abstract class CastIntegerBaseNode extends CastBaseNode { @@ -44,10 +43,19 @@ public abstract class CastIntegerBaseNode extends CastBaseNode { @Child private CastIntegerNode recursiveCastInteger; + protected CastIntegerBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + @Override + protected final RType getTargetType() { + return RType.Integer; + } + protected Object castIntegerRecursive(Object o) { if (recursiveCastInteger == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveCastInteger = insert(CastIntegerNodeGen.create(isPreserveNames(), isDimensionsPreservation(), isAttrPreservation())); + recursiveCastInteger = insert(CastIntegerNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes())); } return recursiveCastInteger.executeInt(o); } @@ -109,14 +117,4 @@ public abstract class CastIntegerBaseNode extends CastBaseNode { protected int doRaw(RRaw operand) { return RRuntime.raw2int(operand); } - - @Specialization - protected Object doEnvironment(@SuppressWarnings("unused") REnvironment value) { - throw RError.error(RError.SHOW_CALLER, RError.Message.ENVIRONMENTS_COERCE); - } - - @Specialization - protected Object doFunction(@SuppressWarnings("unused") RFunction value) { - throw RError.error(RError.SHOW_CALLER, RError.Message.CLOSURE_COERCE); - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java index f9b782dc101aee43469ef62cc1a73e0acd8a81d0..60d21ca021724d29ff2cf57c4277b96bf3088208 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerNode.java @@ -22,9 +22,7 @@ */ package com.oracle.truffle.r.nodes.unary; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RError; @@ -50,6 +48,10 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode { private final NAProfile naProfile = NAProfile.create(); + protected CastIntegerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + public abstract Object executeInt(int o); public abstract Object executeInt(double o); @@ -58,8 +60,6 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode { public abstract Object executeInt(Object o); - @Child private CastIntegerNode recursiveCastInteger; - @Specialization protected RAbstractIntVector doIntVector(RAbstractIntVector operand) { return operand; @@ -74,7 +74,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode { private RIntVector createResultVector(RAbstractVector operand, int[] idata) { RIntVector ret = RDataFactory.createIntVector(idata, naCheck.neverSeenNA(), getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; @@ -96,7 +96,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode { } RIntVector ret = RDataFactory.createIntVector(idata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; @@ -152,7 +152,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode { } RIntVector ret = RDataFactory.createIntVector(idata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; @@ -190,8 +190,8 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode { int value = (Integer) castEntry; result[i] = value; seenNA = seenNA || RRuntime.isNA(value); - } else if (castEntry instanceof RIntVector) { - RIntVector intVector = (RIntVector) castEntry; + } else if (castEntry instanceof RAbstractIntVector) { + RAbstractIntVector intVector = (RAbstractIntVector) castEntry; if (intVector.getLength() == 1) { int value = intVector.getDataAt(0); result[i] = value; @@ -208,7 +208,7 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode { } } RIntVector ret = RDataFactory.createIntVector(result, !seenNA); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(list); } return ret; @@ -224,12 +224,6 @@ public abstract class CastIntegerNode extends CastIntegerBaseNode { return arg instanceof RIntVector; } - @Fallback - @TruffleBoundary - protected int doOther(Object operand) { - throw new ConversionFailedException(operand.getClass().getName()); - } - public static CastIntegerNode create() { return CastIntegerNodeGen.create(true, true, true); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerScalarNode.java deleted file mode 100644 index dc7525c99bc4d225c1f6ab9deabafedb7dbb07ea..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastIntegerScalarNode.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2015, 2016, 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.unary; - -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; - -public abstract class CastIntegerScalarNode extends CastIntegerBaseNode { - - public abstract int executeInt(Object o); - - @Specialization(guards = "operand.getLength() > 0") - protected int doLogicalVector(RLogicalVector operand) { - return (int) castIntegerRecursive(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected int doIntVector(RAbstractIntVector operand) { - return (int) castIntegerRecursive(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected int doDoubleVector(RAbstractDoubleVector operand) { - return (int) castIntegerRecursive(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected int doStringVector(RStringVector operand) { - return (int) castIntegerRecursive(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected int doComplexVector(RComplexVector operand) { - return (int) castIntegerRecursive(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected int doRawVectorDims(RRawVector operand) { - return (int) castIntegerRecursive(operand.getDataAt(0)); - } - - @Fallback - protected int castInt(@SuppressWarnings("unused") Object o) { - // for non-atomic structures and vectors of length 0 - return RRuntime.INT_NA; - } - - public static CastIntegerScalarNode create() { - return CastIntegerScalarNodeGen.create(false, false, false); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java index ba4330cc0849dc3ad0093651103740e1cb806bd5..8a67bbad26382d5854dc1d232ea40b558f2bbd9f 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java @@ -27,6 +27,7 @@ import java.util.Iterator; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RAttributes; import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute; @@ -45,10 +46,17 @@ import com.oracle.truffle.r.runtime.env.REnvironment; public abstract class CastListNode extends CastBaseNode { - @Child private CastListNode castListRecursive; - public abstract RList executeList(Object o); + protected CastListNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + @Override + protected final RType getTargetType() { + return RType.List; + } + @Specialization protected RList doNull(@SuppressWarnings("unused") RNull operand) { return RDataFactory.createList(); @@ -72,7 +80,7 @@ public abstract class CastListNode extends CastBaseNode { } RList ret = RDataFactory.createList(data, getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java index 1de63001a8fab2521cd1070037313452976d13c2..03ea9e3eb653978486ba62171af92fc0b7b962b2 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalBaseNode.java @@ -22,9 +22,9 @@ */ package com.oracle.truffle.r.nodes.unary; -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.ops.na.NACheck; @@ -33,14 +33,13 @@ public abstract class CastLogicalBaseNode extends CastBaseNode { protected final NACheck naCheck = NACheck.create(); - @Child private CastLogicalNode recursiveCastLogical; + protected CastLogicalBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } - protected Object castLogicalRecursive(Object o) { - if (recursiveCastLogical == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveCastLogical = insert(CastLogicalNodeGen.create(isPreserveNames(), isDimensionsPreservation(), isAttrPreservation())); - } - return recursiveCastLogical.execute(o); + @Override + protected final RType getTargetType() { + return RType.Logical; } @Specialization diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java index 90fc83be7044eb76e719e4fee206e137914ec1d5..b7eac7f903810077889f3957e746be082c3a64c6 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java @@ -24,8 +24,7 @@ package com.oracle.truffle.r.nodes.unary; import java.util.Arrays; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode; import com.oracle.truffle.r.runtime.RRuntime; @@ -47,6 +46,29 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode { private final NAProfile naProfile = NAProfile.create(); + @Child private CastLogicalNode recursiveCastLogical; + @Child private InheritsCheckNode inheritsFactorCheck; + + protected CastLogicalNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + protected Object castLogicalRecursive(Object o) { + if (recursiveCastLogical == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + recursiveCastLogical = insert(CastLogicalNodeGen.create(preserveNames(), preserveDimensions(), preserveAttributes())); + } + return recursiveCastLogical.execute(o); + } + + protected boolean isFactor(Object o) { + if (inheritsFactorCheck == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + inheritsFactorCheck = insert(new InheritsCheckNode(RRuntime.CLASS_FACTOR)); + } + return inheritsFactorCheck.execute(o); + } + @Specialization protected RNull doNull(@SuppressWarnings("unused") RNull operand) { return RNull.instance; @@ -68,7 +90,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode { } RLogicalVector ret = RDataFactory.createLogicalVector(bdata, !seenNA, getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; @@ -84,6 +106,13 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode { return createResultVector(operand, index -> naCheck.convertIntToLogical(operand.getDataAt(index))); } + @Specialization(guards = "isFactor(factor)") + protected RLogicalVector asLogical(RAbstractIntVector factor) { + byte[] data = new byte[factor.getLength()]; + Arrays.fill(data, RRuntime.LOGICAL_NA); + return RDataFactory.createLogicalVector(data, RDataFactory.INCOMPLETE_VECTOR); + } + @Specialization protected RLogicalVector doDoubleVector(RAbstractDoubleVector operand) { return createResultVector(operand, index -> naCheck.convertDoubleToLogical(operand.getDataAt(index))); @@ -138,7 +167,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode { } } RLogicalVector ret = RDataFactory.createLogicalVector(result, !seenNA); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(list); } return ret; @@ -154,26 +183,7 @@ public abstract class CastLogicalNode extends CastLogicalBaseNode { return missing; } - @Specialization(guards = "isFactor(factor)") - protected RLogicalVector asLogical(RAbstractIntVector factor) { - byte[] data = new byte[factor.getLength()]; - Arrays.fill(data, RRuntime.LOGICAL_NA); - return RDataFactory.createLogicalVector(data, RDataFactory.INCOMPLETE_VECTOR); - } - - @Fallback - @TruffleBoundary - protected int doOther(Object operand) { - throw new ConversionFailedException(operand.getClass().getName()); - } - public static CastLogicalNode createNonPreserving() { return CastLogicalNodeGen.create(false, false, false); } - - @Child private InheritsCheckNode inheritsFactorCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR); - - protected boolean isFactor(Object o) { - return inheritsFactorCheck.execute(o); - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalScalarNode.java deleted file mode 100644 index 71513232170913e47071ab77b61cb01e99424db4..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalScalarNode.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2015, 2016, 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.unary; - -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; - -public abstract class CastLogicalScalarNode extends CastLogicalBaseNode { - - public abstract byte executeByte(Object o); - - @Specialization(guards = "operand.getLength() > 0") - protected byte doLogicalVector(RLogicalVector operand) { - return (byte) castLogicalRecursive(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected byte doIntVector(RAbstractIntVector operand) { - return (byte) castLogicalRecursive(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected byte doDoubleVector(RAbstractDoubleVector operand) { - return (byte) castLogicalRecursive(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected byte doStringVector(RStringVector operand) { - return (byte) castLogicalRecursive(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected byte doComplexVector(RComplexVector operand) { - return (byte) castLogicalRecursive(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected byte doRawVectorDims(RRawVector operand) { - return (byte) castLogicalRecursive(operand.getDataAt(0)); - } - - @Fallback - protected byte castLogical(@SuppressWarnings("unused") Object o) { - // for non-atomic structures and vectors of length 0 - return RRuntime.LOGICAL_NA; - } - - public static CastLogicalScalarNode create() { - return CastLogicalScalarNodeGen.create(false, false, false); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java index 120d4232b83f602a30aea46bc8f485cffd7893f6..c4216503fa42031bb450494e4ca88ffeb4c3fad3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastRawNode.java @@ -22,14 +22,13 @@ */ package com.oracle.truffle.r.nodes.unary; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RComplexVector; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -49,6 +48,15 @@ public abstract class CastRawNode extends CastBaseNode { private final NACheck naCheck = NACheck.create(); private final BranchProfile warningBranch = BranchProfile.create(); + protected CastRawNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + @Override + protected final RType getTargetType() { + return RType.Raw; + } + public abstract Object executeRaw(int o); public abstract Object executeRaw(double o); @@ -130,7 +138,7 @@ public abstract class CastRawNode extends CastBaseNode { private RRawVector createResultVector(RAbstractVector operand, byte[] bdata) { RRawVector ret = RDataFactory.createRawVector(bdata, getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; @@ -271,12 +279,6 @@ public abstract class CastRawNode extends CastBaseNode { return operand; } - @Fallback - @TruffleBoundary - protected int doOther(Object operand) { - throw new ConversionFailedException(operand.getClass().getName()); - } - public static CastRawNode createNonPreserving() { return CastRawNodeGen.create(false, false, false); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java index 290505762224c50a33ae3632f8a3bec7132e8d2e..9c2b21f546c2cebbf1f14bdb329233844cea2a06 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java @@ -23,6 +23,7 @@ package com.oracle.truffle.r.nodes.unary; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RRaw; @@ -30,6 +31,15 @@ public abstract class CastStringBaseNode extends CastBaseNode { @Child private ToStringNode toString = ToStringNodeGen.create(); + protected CastStringBaseNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + @Override + protected final RType getTargetType() { + return RType.Character; + } + @Specialization protected String doString(String value) { return value; 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 2ad538134cc4987e3f8cc813c10750804f6b2270..9a258c8124fc2ca1f264a0f054dc899b0c89acb0 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 @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.nodes.unary; -import com.oracle.truffle.api.dsl.NodeField; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -33,9 +32,19 @@ import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -@NodeField(name = "emptyVectorConvertedToNull", type = boolean.class) public abstract class CastStringNode extends CastStringBaseNode { + private final boolean convertEmptyVectorToNull; + + protected CastStringNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean convertEmptyVectorToNull) { + super(preserveNames, preserveDimensions, preserveAttributes); + this.convertEmptyVectorToNull = convertEmptyVectorToNull; + } + + public boolean convertEmptyVectorToNull() { + return convertEmptyVectorToNull; + } + public abstract Object executeString(int o); public abstract Object executeString(double o); @@ -44,8 +53,6 @@ public abstract class CastStringNode extends CastStringBaseNode { public abstract Object executeString(Object o); - public abstract boolean isEmptyVectorConvertedToNull(); - @Specialization protected RNull doNull(@SuppressWarnings("unused") RNull operand) { return RNull.instance; @@ -53,7 +60,7 @@ public abstract class CastStringNode extends CastStringBaseNode { @Specialization(guards = "vector.getLength() == 0") protected Object doEmptyVector(@SuppressWarnings("unused") RAbstractVector vector) { - return isEmptyVectorConvertedToNull() ? RNull.instance : RDataFactory.createStringVector(0); + return convertEmptyVectorToNull ? RNull.instance : RDataFactory.createStringVector(0); } @Specialization(guards = "vector.getLength() != 0") @@ -75,7 +82,7 @@ public abstract class CastStringNode extends CastStringBaseNode { } RStringVector ret = RDataFactory.createStringVector(sdata, operand.isComplete(), getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); - if (isAttrPreservation()) { + if (preserveAttributes()) { ret.copyRegAttributesFrom(operand); } return ret; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringScalarNode.java deleted file mode 100644 index 7a5f961d4fc921bbc5d9c065ab8ae0033650dd5a..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringScalarNode.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2015, 2016, 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.unary; - -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; - -public abstract class CastStringScalarNode extends CastStringBaseNode { - - public abstract String executeString(Object o); - - @Specialization(guards = "operand.getLength() > 0") - protected String doLogicalVector(RLogicalVector operand) { - return toString(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected String doIntVector(RAbstractIntVector operand) { - return toString(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected String doDoubleVector(RAbstractDoubleVector operand) { - return toString(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected String doStringVector(RStringVector operand) { - return toString(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected String doComplexVector(RComplexVector operand) { - return toString(operand.getDataAt(0)); - } - - @Specialization(guards = "operand.getLength() > 0") - protected String doRawVectorDims(RRawVector operand) { - return toString(operand.getDataAt(0)); - } - - @Fallback - protected String castLogical(@SuppressWarnings("unused") Object o) { - // for non-atomic structures, vectors of length 0, and NULL - return RRuntime.STRING_NA; - } - - public static CastStringScalarNode create() { - return CastStringScalarNodeGen.create(false, false, false); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java index cfd853bfe0b4af5e6e92c4bdf56edb34b6204928..c567944d82dd273656521a82d5dbe8af7d79426c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java @@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.unary; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RDoubleVector; import com.oracle.truffle.r.runtime.data.RIntVector; @@ -37,6 +38,15 @@ public abstract class CastSymbolNode extends CastBaseNode { @Child private ToStringNode toString = ToStringNodeGen.create(); + protected CastSymbolNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + @Override + protected final RType getTargetType() { + return RType.Symbol; + } + public abstract Object executeSymbol(Object o); private String toString(Object value) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java index 89199ea9571e54514ddce53b7972f094ccc74b8d..769ee3d5558aa4b64476b6a7476e3e90c4c7d0a5 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToAttributableNode.java @@ -23,6 +23,7 @@ package com.oracle.truffle.r.nodes.unary; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RNull; @@ -35,6 +36,15 @@ public abstract class CastToAttributableNode extends CastBaseNode { public abstract Object executeObject(Object value); + protected CastToAttributableNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + @Override + protected final RType getTargetType() { + return RType.Any; + } + @Specialization @SuppressWarnings("unused") protected RNull cast(RNull rnull) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java index 607e59d5c87ebb86ee7d06e551286a4647599100..7bd1fd595cbb70500660a57c559305252bb520e1 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastToContainerNode.java @@ -23,6 +23,7 @@ package com.oracle.truffle.r.nodes.unary; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RLanguage; @@ -35,6 +36,15 @@ public abstract class CastToContainerNode extends CastBaseNode { public abstract Object executeObject(Object value); + protected CastToContainerNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { + super(preserveNames, preserveDimensions, preserveAttributes); + } + + @Override + protected final RType getTargetType() { + return RType.Any; + } + @Specialization @SuppressWarnings("unused") protected RNull castNull(RNull rnull) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConversionFailedException.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConversionFailedException.java deleted file mode 100644 index 364e2787010541ac8bf8e6da672bcae02a7c5919..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConversionFailedException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2013, 2016, 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.unary; - -/** Thrown by a convert node. Indicates that a parent node must rewrite itself. */ -public final class ConversionFailedException extends RuntimeException { - - private static final long serialVersionUID = 1L; - - ConversionFailedException(String message) { - super(message); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertInt.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertInt.java deleted file mode 100644 index dbfb7f96d877a673ba19d553cf4776e7e531c4b2..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertInt.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2013, 2016, 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.unary; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; - -public abstract class ConvertInt extends CastNode { - - @Child private ConvertInt convertIntRecursive; - - public abstract int executeInteger(Object operand); - - private int convertIntRecursive(Object operand) { - if (convertIntRecursive == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - convertIntRecursive = insert(ConvertIntNodeGen.create()); - } - return executeInteger(operand); - } - - @Specialization - protected int doInt(int operand) { - return operand; - } - - @Specialization - protected int doDouble(double operand) { - return (int) operand; - } - - @Specialization - protected int doLogical(byte operand) { - return RRuntime.logical2int(operand); - } - - @Specialization(guards = "operand.getLength() == 1") - protected int doLogical(RAbstractContainer operand) { - return convertIntRecursive(operand.getDataAtAsObject(0)); - } - - @Fallback - @TruffleBoundary - protected int doOther(Object operand) { - throw new ConversionFailedException(operand.getClass().getName()); - } -} diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java index de33418f4c6c31fd5e0d0a6c671d783a7b3ebb6c..731cbc5ac2557d606af6fd9b8002b45447355926 100644 --- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java +++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java @@ -279,7 +279,7 @@ public class CallRFFIHelper { public static Object R_do_MAKE_CLASS(String clazz) { RFunction getClass = (RFunction) RContext.getRRuntimeASTAccess().forcePromise(REnvironment.getRegisteredNamespace("methods").get("getClass")); - return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), clazz); + return RContext.getEngine().evalFunction(getClass, null, RCaller.createInvalid(null), null, clazz); } public static Object Rf_findVar(Object symbolArg, Object envArg) { @@ -894,31 +894,6 @@ public class CallRFFIHelper { return result; } - private static Object convertPairList(RPairList list) { - try { - if (list.getType() == SEXPTYPE.LANGSXP) { - RPairList pl = list; - Map<String, Object> constants = new HashMap<>(); - String deparse = RDeparse.deparseDeserialize(constants, pl); - Source source = RSource.fromTextInternal(deparse, RSource.Internal.PAIRLIST_DEPARSE); - RExpression expr = RContext.getEngine().parse(constants, source); - assert expr.getLength() == 1; - Object result = expr.getDataAt(0); - RAttributes attrs = pl.getAttributes(); - if (result instanceof RAttributable) { - RAttributes.copyAttributes((RAttributable) result, attrs); - } - return result; - - } else { - throw RInternalError.shouldNotReachHere(); - } - } catch (Throwable x) { - throw RInternalError.shouldNotReachHere(); - } - - } - @TruffleBoundary public static Object Rf_eval(Object expr, Object env) { if (RFFIUtils.traceEnabled()) { @@ -929,11 +904,20 @@ public class CallRFFIHelper { if (expr instanceof RPromise) { result = RContext.getRRuntimeASTAccess().forcePromise(expr); } else if (expr instanceof RExpression) { - result = RContext.getEngine().eval((RExpression) expr, (REnvironment) env, RCaller.createInvalid(null)); + result = RContext.getEngine().eval((RExpression) expr, (REnvironment) env, topLevel); } else if (expr instanceof RLanguage) { - result = RContext.getEngine().eval((RLanguage) expr, (REnvironment) env, RCaller.createInvalid(null)); + result = RContext.getEngine().eval((RLanguage) expr, (REnvironment) env, topLevel); } else if (expr instanceof RPairList) { - result = Rf_eval(convertPairList((RPairList) expr), env); + RPairList l = (RPairList) expr; + RFunction f = (RFunction) l.car(); + Object args = l.cdr(); + if (args == RNull.instance) { + result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), topLevel, null, new Object[0]); + } else { + RList argsList = ((RPairList) args).toRList(); + result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), topLevel, argsList.getNames(), argsList.getDataNonShared()); + } + } else { // just return value result = expr; @@ -1008,7 +992,7 @@ public class CallRFFIHelper { RFFIUtils.traceUpCall("R_computeIdentical", x, y, flags); } RFunction indenticalBuiltin = RContext.lookupBuiltin("identical"); - Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))), + Object res = RContext.getEngine().evalFunction(indenticalBuiltin, null, null, null, x, y, RRuntime.asLogical((!((flags & 1) == 0))), RRuntime.asLogical((!((flags & 2) == 0))), RRuntime.asLogical((!((flags & 4) == 0))), RRuntime.asLogical((!((flags & 8) == 0))), RRuntime.asLogical((!((flags & 16) == 0)))); return (int) res; } @@ -1276,12 +1260,12 @@ public class CallRFFIHelper { } RCaller currentCaller = RArguments.getCall(frame); while (currentCaller != null) { - if (!currentCaller.isPromise()) { + if (!currentCaller.isPromise() && currentCaller.isValidCaller()) { break; } currentCaller = currentCaller.getParent(); } - return currentCaller == null ? RNull.instance : currentCaller; + return currentCaller == null || currentCaller == topLevel ? RNull.instance : currentCaller; } public static Object R_getParentFunctionContext(Object c) { @@ -1291,30 +1275,11 @@ public class CallRFFIHelper { RCaller currentCaller = guaranteeInstanceOf(c, RCaller.class); while (true) { currentCaller = currentCaller.getParent(); - if (currentCaller == null || !currentCaller.isPromise()) { + if (currentCaller == null || (!currentCaller.isPromise() && currentCaller.isValidCaller())) { break; } } - return currentCaller == null ? RNull.instance : currentCaller; - } - - public static Object R_getFunctionContext(int depth) { - if (RFFIUtils.traceEnabled()) { - RFFIUtils.traceUpCall("getFunctionContext", depth); - } - Frame frame = Utils.getActualCurrentFrame(); - RCaller currentCaller = RArguments.getCall(frame); - int currentDepth = 0; - while (currentCaller != null) { - if (!currentCaller.isPromise()) { - currentDepth++; - if (currentDepth >= depth) { - break; - } - } - currentCaller = currentCaller.getParent(); - } - return currentCaller == null ? RNull.instance : currentCaller; + return currentCaller == null || currentCaller == topLevel ? RNull.instance : currentCaller; } public static Object R_getContextEnv(Object c) { @@ -1419,7 +1384,6 @@ public class CallRFFIHelper { } public static int R_insideBrowser() { - return RContext.getInstance().isInBrowser() ? 1 : 0; + return RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser() ? 1 : 0; } - } diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java index 168618a998bd8e666fe27f37136eaf78372965a4..da24f27db4ab82bba8840d97541dffae4e408e88 100644 --- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java +++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java @@ -22,6 +22,8 @@ */ package com.oracle.truffle.r.runtime.ffi.jnr; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.r.runtime.RPlatform; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.RContext.ContextState; @@ -90,111 +92,122 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI { return this; } - private BaseRFFI baseRFFI; + @CompilationFinal private BaseRFFI baseRFFI; @Override public BaseRFFI getBaseRFFI() { if (baseRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); baseRFFI = new JNR_Base(); } return baseRFFI; } - private LapackRFFI lapackRFFI; + @CompilationFinal private LapackRFFI lapackRFFI; @Override public LapackRFFI getLapackRFFI() { if (lapackRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); lapackRFFI = new JNR_Lapack(); } return lapackRFFI; } - private RApplRFFI rApplRFFI; + @CompilationFinal private RApplRFFI rApplRFFI; @Override public RApplRFFI getRApplRFFI() { if (rApplRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); rApplRFFI = new JNR_RAppl(); } return rApplRFFI; } - private StatsRFFI statsRFFI; + @CompilationFinal private StatsRFFI statsRFFI; @Override public StatsRFFI getStatsRFFI() { if (statsRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); statsRFFI = new JNR_Stats(); } return statsRFFI; } - private ToolsRFFI toolsRFFI; + @CompilationFinal private ToolsRFFI toolsRFFI; @Override public ToolsRFFI getToolsRFFI() { if (toolsRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); toolsRFFI = new Generic_Tools(); } return toolsRFFI; } - private GridRFFI gridRFFI; + @CompilationFinal private GridRFFI gridRFFI; @Override public GridRFFI getGridRFFI() { if (gridRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); gridRFFI = new Generic_Grid(); } return gridRFFI; } - private UserRngRFFI userRngRFFI; + @CompilationFinal private UserRngRFFI userRngRFFI; @Override public UserRngRFFI getUserRngRFFI() { if (userRngRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); userRngRFFI = new JNR_UserRng(); } return userRngRFFI; } - private CRFFI cRFFI; + @CompilationFinal private CRFFI cRFFI; @Override public CRFFI getCRFFI() { if (cRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); cRFFI = new CRFFI_JNR_Invoke(); } return cRFFI; } - private CallRFFI callRFFI; + @CompilationFinal private CallRFFI callRFFI; @Override public CallRFFI getCallRFFI() { if (callRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); callRFFI = new JNI_CallRFFI(); } return callRFFI; } - private ZipRFFI zipRFFI; + @CompilationFinal private ZipRFFI zipRFFI; @Override public ZipRFFI getZipRFFI() { if (zipRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); zipRFFI = new JNR_Zip(); } return zipRFFI; } - private PCRERFFI pcreRFFI; + @CompilationFinal private PCRERFFI pcreRFFI; @Override public PCRERFFI getPCRERFFI() { if (pcreRFFI == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); pcreRFFI = new JNR_PCRE(); } return pcreRFFI; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java index 1c9a2d4d54a118b253be02e4587f821dfa9e5719..50a18c02504f470cbfb08d67dc5d3fba23b240de 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java @@ -596,7 +596,10 @@ public class RDeparse { append("list(").appendListContents(obj).append(')'); } } else if (value instanceof RAbstractVector) { - appendVector((RAbstractVector) value); + RAbstractVector obj = (RAbstractVector) value; + try (C c = withAttributes(obj)) { + appendVector((RAbstractVector) value); + } } else if (value instanceof RNull) { append("NULL"); } else if (value instanceof RFunction) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java index a90d09540304fac64402f98e4bafbb04709ba768..15777101afe3c9342eaab71f1313a9f15dda53ae 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java @@ -270,6 +270,7 @@ public final class RError extends RuntimeException { EMPTY_WHAT("empty 'what' specified"), LINE_ELEMENTS("line %d did not have %d elements"), ITEMS_NOT_MULTIPLE("number of items read is not a multiple of the number of columns"), + TRACEMEM_NOT_NULL("cannot trace NULL"), // below: GNU R gives also expression for the argument NOT_FUNCTION("'%s' is not a function, character or symbol"), NON_CHARACTER("non-character argument"), diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java index 911a09d8291a12e6d029ee2120a74c3b58f83c0a..84afa3b4041e4ac89f860278200c93ab1d4af85c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java @@ -340,7 +340,7 @@ public class RErrorHandling { errorcallDfltWithCall(fromCall(call), Message.GENERIC, msg); } else { RFunction hf = (RFunction) h; - RContext.getEngine().evalFunction(hf, null, null, cond); + RContext.getEngine().evalFunction(hf, null, null, null, cond); } } else { throw gotoExitingHandler(cond, call, entry); @@ -503,7 +503,7 @@ public class RErrorHandling { evaluatedArgs[i] = RMissing.instance; } } - RContext.getEngine().evalFunction(errorFunction, null, null, evaluatedArgs); + RContext.getEngine().evalFunction(errorFunction, null, null, null, evaluatedArgs); } else if (errorExpr instanceof RLanguage || errorExpr instanceof RExpression) { if (errorExpr instanceof RLanguage) { RContext.getEngine().eval((RLanguage) errorExpr, materializedFrame); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java index 3c826891dd099b8bcfe4952440c971abc1bb4f13..85fbeff658a1db99fd8f16bc4364379305ee7993 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java @@ -445,7 +445,7 @@ public class RSerialize { * only used in a warning message in the unlikely event that the namespace * cannot be found. */ - Object r = RContext.getEngine().evalFunction(contextState.getDotDotFindNamespace(), null, null, s, ""); + Object r = RContext.getEngine().evalFunction(contextState.getDotDotFindNamespace(), null, null, null, s, ""); return checkResult(addReadRef(r)); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java index e8363e5a00435d101d9e1a99987924ec2a96fb2b..f6c0f60ed573f8ce488923a6dcb895dc1b938963 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java @@ -35,6 +35,7 @@ import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RLanguage; +import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.nodes.RNode; @@ -167,9 +168,10 @@ public interface Engine { * case the current frame is used). In many cases {@code frame} may not represent the current * call stack, for example many S4-related evaluations set {@code frame} to the {@code methods} * namespace, but the current stack is not empty. So when {@code frame} is not {@code null} a - * {@code caller} should be passed to maintain the call stack correctly. + * {@code caller} should be passed to maintain the call stack correctly. {@code names} string + * vector describing (optional) argument names */ - Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, Object... args); + Object evalFunction(RFunction func, MaterializedFrame frame, RCaller caller, RStringVector names, Object... args); /** * Checks for the existence of (startup/shutdown) function {@code name} and, if present, invokes diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java index ec21c2f7e22ddbd63241af45c167c0eb31bfcef4..8e011cfa039c2d2d87b63e33897271cfbb7f0a80 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java @@ -293,11 +293,6 @@ public final class RContext extends ExecutionContext implements TruffleObject { private boolean nullS4Object = false; - /** - * This used to prevent a "quit" from the browser (as per GnuR). - */ - private boolean inBrowser = false; - private boolean active; private PrimitiveMethodsInfo primitiveMethodsInfo; @@ -623,14 +618,6 @@ public final class RContext extends ExecutionContext implements TruffleObject { nullS4Object = on; } - public boolean isInBrowser() { - return inBrowser; - } - - public void setInBrowser(boolean on) { - inBrowser = on; - } - public boolean allowPrimitiveMethods() { return allowPrimitiveMethods; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java new file mode 100644 index 0000000000000000000000000000000000000000..05b5db6c2ab0659d63d734052b21dd3216ae1553 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016, 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.Assumption; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +/** + * Helper for tracing memory related events. All implementors of {@link RAbstractVector} are + * expected to report to {@link MemoryTracer} and others can listen to them through {@link Listener} + * interface. Use method {@link #reportEvents()} to start the tracing. + */ +public final class MemoryTracer { + private static Listener listener; + private static final Assumption noMemoryTracingAssumption = Truffle.getRuntime().createAssumption(); + + private MemoryTracer() { + // only static methods + } + + /** + * Sets the listener of memory tracing events. For the time being there can only be one + * listener. This can be extended to an array should we need more listeners. + */ + public static void setListener(Listener newListener) { + listener = newListener; + } + + /** + * After calling this method memory related events will be reported to the listener. This + * invalidates global assumption and should be used with caution. + */ + public static void reportEvents() { + noMemoryTracingAssumption.invalidate(); + } + + /** + * Reports copy event to the listener. If there are no traced objects, this should turn into + * no-op. TODO might be worth interposing on a change in {@code tracingState} to turn off the + * collection. + */ + public static void reportCopying(RAbstractVector source, RAbstractVector dest) { + if (!noMemoryTracingAssumption.isValid() && listener != null && RContext.getInstance().stateInstrumentation.getTracingState()) { + listener.reportCopying(source, dest); + } + } + + public interface Listener { + void reportCopying(RAbstractVector source, RAbstractVector dest); + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java index a3d7858c77f15957b42b902e19e6a6d2a4707d1d..1bfe70252de40c3162543da9ef30c416b27154b2 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java @@ -67,7 +67,9 @@ public final class RComplex extends RScalarVector implements RAbstractComplexVec @Override public RComplexVector materialize() { - return RDataFactory.createComplexVectorFromScalar(this); + RComplexVector result = RDataFactory.createComplexVectorFromScalar(this); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java index 530b0796a9308505f41a7194f8b702ffb35b88f7..e94bd445cc3b6d629053f86da551dbab6deea2bf 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java @@ -198,7 +198,7 @@ public final class RComplexVector extends RVector implements RAbstractComplexVec } @Override - public RComplexVector copyResized(int size, boolean fillNA) { + protected RComplexVector internalCopyResized(int size, boolean fillNA) { boolean isComplete = isComplete() && ((data.length >= size) || !fillNA); return RDataFactory.createComplexVector(copyResizedData(size, fillNA), isComplete); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java index b31722d76e5a1b49c4774fc3ed16079908c5b775..096356c36aaf5031ea8b85166e820cfbd7d960b5 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java @@ -89,7 +89,9 @@ public final class RDouble extends RScalarVector implements RAbstractDoubleVecto @Override public RDoubleVector materialize() { - return RDataFactory.createDoubleVectorFromScalar(getValue()); + RDoubleVector result = RDataFactory.createDoubleVectorFromScalar(getValue()); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java index a3be26975816e8a310f72bf77f809fdd84c72146..c542875fa7f26d8e6b64219f65df90db26b6db82 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java @@ -211,7 +211,7 @@ public final class RDoubleVector extends RVector implements RAbstractDoubleVecto } @Override - public RDoubleVector copyResized(int size, boolean fillNA) { + protected RDoubleVector internalCopyResized(int size, boolean fillNA) { boolean isComplete = isComplete() && ((data.length >= size) || !fillNA); return RDataFactory.createDoubleVector(copyResizedData(size, fillNA), isComplete); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java index 6a672cdbace2b30459625d2caa289cce155ffd4d..74e182b9cee2de064c08e037eea0ad49440e66dd 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java @@ -208,7 +208,7 @@ public final class RIntVector extends RVector implements RAbstractIntVector { } @Override - public RIntVector copyResized(int size, boolean fillNA) { + protected RIntVector internalCopyResized(int size, boolean fillNA) { boolean isComplete = isComplete() && ((data.length >= size) || !fillNA); return RDataFactory.createIntVector(copyResizedData(size, fillNA), isComplete); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java index 0df0f556e1b7226069b7e983910c8cbabaf6e25d..075d9ee51126ff8bd297ebffb5b11bed48055b13 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java @@ -87,7 +87,9 @@ public final class RInteger extends RScalarVector implements RAbstractIntVector @Override public RIntVector materialize() { - return RDataFactory.createIntVectorFromScalar(value); + RIntVector result = RDataFactory.createIntVectorFromScalar(value); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java index cb0496f25de6cc7d472d396e7a04a1736a142b25..c97e5a73d88d9290e5597a439ec0b73d82d13a7e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java @@ -72,7 +72,7 @@ public final class RList extends RListBase { } @Override - public RList copyResized(int size, boolean fillNA) { + protected RList internalCopyResized(int size, boolean fillNA) { return RDataFactory.createList(copyResizedData(size, fillNA)); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java index 65f0ad784fd53bec3301152b834b74c3e4efc5b2..05d0e6d1b1d642a39fc13b620d15a3727a3c130d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java @@ -93,7 +93,9 @@ public final class RLogical extends RScalarVector implements RAbstractLogicalVec @Override public RLogicalVector materialize() { - return RDataFactory.createLogicalVectorFromScalar(value); + RLogicalVector result = RDataFactory.createLogicalVectorFromScalar(value); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java index 4d3068841936b172d547b8cad3a69073785ff11d..a492093eb77cf75441f3b9218fb7b370fb9fe891 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java @@ -169,7 +169,7 @@ public final class RLogicalVector extends RVector implements RAbstractLogicalVec } @Override - public RLogicalVector copyResized(int size, boolean fillNA) { + protected RLogicalVector internalCopyResized(int size, boolean fillNA) { boolean isComplete = isComplete() && ((data.length >= size) || !fillNA); return RDataFactory.createLogicalVector(copyResizedData(size, fillNA), isComplete); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java index bb93e20a576774f9b6697cdc6b0e47f6b5467417..d843cacfb937a8518c91151e91e7e33b3c553076 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java @@ -64,7 +64,9 @@ public final class RRaw extends RScalarVector implements RAbstractRawVector { @Override public RRawVector materialize() { - return RDataFactory.createRawVector(new byte[]{value}); + RRawVector result = RDataFactory.createRawVector(new byte[]{value}); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java index fdadc7cd66a1a41c9d046a33e0872ce52827e0a7..01ef62b132ffb705df18b6646b7ca419a06e3da9 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java @@ -187,7 +187,7 @@ public final class RRawVector extends RVector implements RAbstractRawVector { } @Override - public RRawVector copyResized(int size, boolean fillNA) { + protected RRawVector internalCopyResized(int size, boolean fillNA) { return RDataFactory.createRawVector(copyResizedData(size, fillNA)); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java index 6d7ddced925c96d8bebedfbb4b98892d18dba52f..6e4a7ca5d9590b16c937b8bb62608c6f25ef8cd7 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java @@ -142,22 +142,30 @@ public abstract class RScalarVector extends RScalar implements RAbstractVector { @Override public RVector copyResized(int size, boolean fillNA) { - return materialize().copyResized(size, fillNA); + RVector result = materialize().copyResized(size, fillNA); + MemoryTracer.reportCopying(this, result); + return result; } @Override public RAbstractVector copyWithNewDimensions(int[] newDimensions) { - return materialize().copyWithNewDimensions(newDimensions); + RAbstractVector result = materialize().copyWithNewDimensions(newDimensions); + MemoryTracer.reportCopying(this, result); + return result; } @Override public RVector copyResizedWithDimensions(int[] newDimensions, boolean fillNA) { - return materialize().copyResizedWithDimensions(newDimensions, fillNA); + RVector result = materialize().copyResizedWithDimensions(newDimensions, fillNA); + MemoryTracer.reportCopying(this, result); + return result; } @Override public RAbstractVector copyDropAttributes() { - return materialize().copyDropAttributes(); + RVector result = materialize().copyDropAttributes(); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java index df3204230ada99193b5ba8a0003154bd26105c0f..3dcc48a783d72896755c68f58238721596a0d86c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java @@ -80,7 +80,9 @@ public abstract class RSequence implements RAbstractVector { } public final RVector createVector() { - return internalCreateVector(); + RVector result = internalCreateVector(); + MemoryTracer.reportCopying(this, result); + return result; } protected abstract RVector internalCreateVector(); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java index 03edef949b3c7b03135e912ab175d2079c023b25..764f4c4b4ba2c88556989eb83461fdf4b8409bc5 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java @@ -73,7 +73,9 @@ public final class RString extends RScalarVector implements RAbstractStringVecto @Override public RStringVector materialize() { - return RDataFactory.createStringVector(new String[]{getValue()}, isComplete()); + RStringVector result = RDataFactory.createStringVector(new String[]{getValue()}, isComplete()); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java index 85a263b13b224a23a06cfcbb5bdc50eec83f417e..53f6667432c8ca54341247372fbab98b5a38f82f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java @@ -190,7 +190,7 @@ public final class RStringVector extends RVector implements RAbstractStringVecto } @Override - public RStringVector copyResized(int size, boolean fillNA) { + protected RStringVector internalCopyResized(int size, boolean fillNA) { boolean isComplete = isComplete() && ((data.length >= size) || !fillNA); return RDataFactory.createStringVector(copyResizedData(size, fillNA ? RRuntime.STRING_NA : null), isComplete); } 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 2c7e3e715317addc7183cab2c3f8b6ac78bb4cd0..159addc3e228b3bda6e2e3bbcc9e9504544c5987 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 @@ -410,7 +410,7 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare RList resDimNames = newDimNames; if (newDimNamesLength < dimensions.length) { // resize the array and fill the missing entries with NULL-s - resDimNames = resDimNames.copyResized(dimensions.length, true); + resDimNames = (RList) resDimNames.copyResized(dimensions.length, true); resDimNames.setAttributes(newDimNames); for (int i = newDimNamesLength; i < dimensions.length; i++) { resDimNames.updateDataAt(i, RNull.instance, null); @@ -547,9 +547,11 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare } } + // public interface *copy* methods are final and delegate to *internalCopyAndReport* methods + @Override public final RVector copy() { - RVector result = internalCopy(); + RVector result = internalCopyAndReport(); setAttributes(result); incCopyCount(); result.setTypedValueInfo(getTypedValueInfo()); @@ -558,21 +560,55 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare @Override public final RVector copyDropAttributes() { - return internalCopy(); + RVector result = internalCopyAndReport(); + return result; } @Override - public RVector deepCopy() { - RVector result = internalDeepCopy(); + public final RVector deepCopy() { + RVector result = internalDeepCopyAndReport(); setAttributes(result); return result; } + @Override + public final RVector copyResized(int size, boolean fillNA) { + return internalCopyResizedAndReport(size, fillNA); + } + + // *internalCopyAndReport* methods do just the copy and report it to MemoryTracer. These should + // be used if additional logic in public interface *copy* method is not desired. + + protected final RVector internalCopyAndReport() { + RVector result = internalCopy(); + MemoryTracer.reportCopying(this, result); + return result; + } + + protected final RVector internalDeepCopyAndReport() { + RVector result = internalDeepCopy(); + MemoryTracer.reportCopying(this, result); + return result; + } + + protected final RVector internalCopyResizedAndReport(int size, boolean fillNA) { + RVector result = internalCopyResized(size, fillNA); + MemoryTracer.reportCopying(this, result); + return result; + } + + // *internalCopy* methods should only be overridden, but never invoked from anywhere but + // *internalCopyAndReport* + + protected abstract RVector internalCopyResized(int size, boolean fillNA); + // to be overridden by recursive structures protected RVector internalDeepCopy() { return internalCopy(); } + protected abstract RVector internalCopy(); + @Override public RVector copyResizedWithDimensions(int[] newDimensions, boolean fillNA) { // TODO support for higher dimensions @@ -588,8 +624,6 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare protected abstract String getDataAtAsString(int index); - protected abstract RVector internalCopy(); - protected abstract boolean internalVerify(); /** diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java index a0a74fcdcb3df189eb2397dee4f99d42ed18306d..0fe0baccfc90e7e0bb0b1a374322b1d431b37cc2 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.runtime.data.closures; +import com.oracle.truffle.r.runtime.data.MemoryTracer; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RAttributes; import com.oracle.truffle.r.runtime.data.RList; @@ -127,12 +128,16 @@ abstract class RToVectorClosure implements RAbstractVector { @Override public final RAbstractVector copy() { - return vector.copy(); + RAbstractVector result = vector.copy(); + MemoryTracer.reportCopying(this, result); + return result; } @Override public final RVector copyResized(int size, boolean fillNA) { - return vector.copyResized(size, fillNA); + RVector result = vector.copyResized(size, fillNA); + MemoryTracer.reportCopying(this, result); + return result; } @Override @@ -146,7 +151,9 @@ abstract class RToVectorClosure implements RAbstractVector { @Override public final RAbstractVector copyDropAttributes() { - return vector.copyDropAttributes(); + RAbstractVector result = vector.copyDropAttributes(); + MemoryTracer.reportCopying(this, result); + return result; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java index b0f2d25be47dfeb42fb3d7d4cc7eaadea0f5fcc7..a2ae57288b474717f66033b2bacd43a882e5e899 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java @@ -24,8 +24,12 @@ package com.oracle.truffle.r.runtime.data.model; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.MemoryTracer; import com.oracle.truffle.r.runtime.data.RVector; +/** + * When implementing, make sure to invoke related {@link MemoryTracer} methods. + */ public interface RAbstractVector extends RAbstractContainer { /** @@ -76,5 +80,4 @@ public interface RAbstractVector extends RAbstractContainer { void setComplete(boolean complete); void setNA(Object store, int index); - } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java index e34c048fda5393653330a81013f66d3907276fec..694ac019f0eed1aa25cfcede1df14b03bd45d1aa 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.runtime.ffi; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.RContext.ContextState; @@ -36,7 +37,7 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextState; */ public abstract class RFFIFactory { - protected static RFFI theRFFI; + @CompilationFinal protected static RFFI theRFFI; public static void setRFFIFactory(RFFIFactory factory) { RFFIContextStateFactory.registerFactory(factory); @@ -52,7 +53,7 @@ public abstract class RFFIFactory { * Initialize the factory instance. This method will be called immediately after the factory * instance is created allowing any additional initialization that could not be done in the * constructor. - * + * * @param runtime {@code true} if the initialization is being done at runtime. An AOT system may * call this twice, once with {@code false} whern an image is being bilt and once * when starting up. diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java index 87b3341dae1bdc444b1f3e64b7657a8835905597..09f5a10046d079cd9b7697e1d51e4fb172fb4556 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java @@ -23,6 +23,7 @@ package com.oracle.truffle.r.runtime.instrument; import java.io.PrintWriter; +import java.util.HashSet; import java.util.WeakHashMap; import com.oracle.truffle.api.instrumentation.EventBinding; @@ -52,27 +53,60 @@ public final class InstrumentationState implements RContext.ContextState { */ private final WeakHashMap<SourceSection, ExecutionEventListener> debugListenerMap = new WeakHashMap<>(); + /** + * The {@link Instrumenter} associated with this {@link RContext}. Never {@code null}. + */ private final Instrumenter instrumenter; + /** + * The {@link Profiler}, if any, associated with this {@link RContext}. + */ private Profiler profiler; + /** + * The {@link RprofState} state, if any, associated with this {@link RContext}. + */ private final RprofState rprofState; + private final TracememContext tracememContext; + + /** + * State used by the {@code tracemem} built-in. + */ + public static final class TracememContext { + private HashSet<Object> tracedObjects; + + public HashSet<Object> getTracedObjects() { + if (tracedObjects == null) { + tracedObjects = new HashSet<>(); + } + return tracedObjects; + } + } + + /** + * The {@link BrowserState} state, if any, associated with this {@link RContext}. + */ + private final BrowserState browserState; + + /** + * Whether debugging is globally disabled in this {@link RContext}. Used to (temporarily) + * disable all debugging across calls that are used internally in the implementation. + * + */ + private boolean debugGloballyDisabled; + /** * State used by {@code Rprof}. * */ - public static class RprofState { + public static final class RprofState { private PrintWriter out; private Thread profileThread; private ExecutionEventListener statementListener; private long intervalInMillis; private boolean lineProfiling; - public static RprofState newContext(@SuppressWarnings("unused") RContext context) { - return new RprofState(); - } - public void initialize(PrintWriter outA, Thread profileThreadA, ExecutionEventListener statementListenerA, long intervalInMillisA, boolean lineProfilingA) { this.out = outA; @@ -104,9 +138,32 @@ public final class InstrumentationState implements RContext.ContextState { } + public static class BrowserState { + private boolean inBrowser; + private String lastEmptyLineCommand = "n"; + + public void setInBrowser(boolean state) { + this.inBrowser = state; + } + + public boolean inBrowser() { + return inBrowser; + } + + public void setLastEmptyLineCommand(String s) { + lastEmptyLineCommand = s; + } + + public String lastEmptyLineCommand() { + return lastEmptyLineCommand; + } + } + private InstrumentationState(Instrumenter instrumenter) { this.instrumenter = instrumenter; this.rprofState = new RprofState(); + this.tracememContext = new TracememContext(); + this.browserState = new BrowserState(); } public void putTraceBinding(SourceSection ss, EventBinding<?> binding) { @@ -158,6 +215,24 @@ public final class InstrumentationState implements RContext.ContextState { return rprofState; } + public TracememContext getTracemem() { + return tracememContext; + } + + public BrowserState getBrowserState() { + return browserState; + } + + public boolean setDebugGloballyDisabled(boolean state) { + boolean current = debugGloballyDisabled; + this.debugGloballyDisabled = state; + return current; + } + + public boolean debugGloballyDisabled() { + return debugGloballyDisabled; + } + public static InstrumentationState newContext(@SuppressWarnings("unused") RContext context, Instrumenter instrumenter) { return new InstrumentationState(instrumenter); } diff --git a/com.oracle.truffle.r.test.cran/r/install.cran.packages.R b/com.oracle.truffle.r.test.cran/r/install.cran.packages.R index 21cd5a3d1eb5117ade53b4aa7b5dad141bee04f9..097eab15f6bf8feeb4576609efce8337a4fd018b 100644 --- a/com.oracle.truffle.r.test.cran/r/install.cran.packages.R +++ b/com.oracle.truffle.r.test.cran/r/install.cran.packages.R @@ -331,8 +331,27 @@ check.installed.pkgs <- function() { # requested set of candidate packages # sets global variables avail.pkgs and toinstall.pkgs, the latter being # of the same type as avail.pkgs but containing only those packages to install +# returns a vector of package names to install/test get.pkgs <- function() { - avail.pkgs <<- available.packages(contriburl=contriburl, type="source") + my.warning <- function(war) { + if (!quiet) { + cat("Fatal error:", war$message, "\n") + } + quit(save="no", status=100) + } + tryCatch({ + avail.pkgs <<- available.packages(contriburl=contriburl, type="source") + }, warning=my.warning) + + # Owing to a FastR bug, we may not invoke the handler above, but + # if length(avail.pkgs) == 0, that also means it failed + if (length(avail.pkgs) == 0) { + if (!quiet) { + print("Fatal error: no packages found in repo") + } + quit(save="no", status=100) + } + avail.pkgs.rownames <<- rownames(avail.pkgs) # get/create the blacklist blacklist <- get.blacklist() @@ -371,7 +390,29 @@ get.pkgs <- function() { } matched.avail.pkgs <- apply(avail.pkgs, 1, match.fun) toinstall.pkgs <<-avail.pkgs[matched.avail.pkgs, , drop=F] - toinstall.pkgs + + if (!is.na(random.count)) { + # install random.count packages taken at random from toinstall.pkgs + test.avail.pkgnames <- rownames(toinstall.pkgs) + rands <- sample(1:length(test.avail.pkgnames)) + test.pkgnames <- character(random.count) + for (i in (1:random.count)) { + test.pkgnames[[i]] <- test.avail.pkgnames[[rands[[i]]]] + } + } else { + test.pkgnames <- rownames(toinstall.pkgs) + if (!is.na(count.daily)) { + # extract count from index given by yday + npkgs <- length(test.pkgnames) + yday <- as.POSIXlt(Sys.Date())$yday + chunk <- as.integer(npkgs / count.daily) + start <- (yday %% chunk) * count.daily + end <- ifelse(start + count.daily > npkgs, npkgs, start + count.daily - 1) + test.pkgnames <- test.pkgnames[start:end] + } + } + + test.pkgnames } # Serially install the packages in pkgnames. @@ -476,36 +517,15 @@ get.blacklist <- function() { # performs the installation, or logs what it would install if dry.run = T do.it <- function() { - get.pkgs() + test.pkgnames <- get.pkgs() if (list.versions) { - for (i in (1:length(rownames(toinstall.pkgs)))) { - pkg <- toinstall.pkgs[i, ] + for (pkgname in test.pkgnames) { + pkg <- toinstall.pkgs[pkgname, ] cat(pkg["Package"], pkg["Version"], paste0(contriburl, "/", pkg["Version"], ".tar.gz"), "\n", sep=",") } } - if (!is.na(random.count)) { - # install random.count packages taken at random from toinstall.pkgs - test.avail.pkgnames <- rownames(toinstall.pkgs) - rands <- sample(1:length(test.avail.pkgnames)) - test.pkgnames <- character(random.count) - for (i in (1:random.count)) { - test.pkgnames[[i]] <- test.avail.pkgnames[[rands[[i]]]] - } - } else { - test.pkgnames <- rownames(toinstall.pkgs) - if (!is.na(count.daily)) { - # extract count from index given by yday - npkgs <- length(test.pkgnames) - yday <- as.POSIXlt(Sys.Date())$yday - chunk <- as.integer(npkgs / count.daily) - start <- (yday %% chunk) * count.daily - end <- ifelse(start + count.daily > npkgs, npkgs, start + count.daily - 1) - test.pkgnames <- test.pkgnames[start:end] - } - } - if (install) { cat("BEGIN package installation\n") install.pkgs(test.pkgnames) 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 8bca99d985bc4f7cde543a0edf8814d21ddfa77a..cce7e0ea8f6adac97096e5d2ed610d0dd411bf97 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 @@ -9890,6 +9890,11 @@ $names z 1 42 +##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine +#{ x<-c(a=42); y<-c(b=7); z<-c(x,y); w<-names(z); w[[1]]<-"c"; z } + a b +42 7 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine #{ x<-c(y=1); c(x, 42) } y @@ -13214,6 +13219,11 @@ logical(0) #{ complex(3) } [1] 0+0i 0+0i 0+0i +##com.oracle.truffle.r.test.builtins.TestBuiltin_complex.testComplex +#{ complex(3, 3, new.env()) } +Error in complex(3, 3, new.env()) : + environments cannot be coerced to other types + ##com.oracle.truffle.r.test.builtins.TestBuiltin_complex.testComplex #{ complex(3, c(1,2), c(4,5,6)) } [1] 1+4i 2+5i 1+6i @@ -13226,6 +13236,15 @@ logical(0) #{ complex(3, c(1,2,3), c(4,5,6)) } [1] 1+4i 2+5i 3+6i +##com.oracle.truffle.r.test.builtins.TestBuiltin_complex.testComplex +#{ complex(3, new.env()) } +Error in complex(3, new.env()) : + environments cannot be coerced to other types + +##com.oracle.truffle.r.test.builtins.TestBuiltin_complex.testComplex +#{ complex(new.env()) } +Error in complex(new.env()) : invalid length + ##com.oracle.truffle.r.test.builtins.TestBuiltin_complex.testComplex #{ complex(real=1,imag=2) } [1] 1+2i @@ -15238,6 +15257,10 @@ a[a <- TRUE] #{ k <- 2 ; deparse(k) } [1] "2" +##com.oracle.truffle.r.test.builtins.TestBuiltin_deparse.testDeparse +#{ x<-c(a=42, b=7); deparse(x) } +[1] "structure(c(42, 7), .Names = c(\"a\", \"b\"))" + ##com.oracle.truffle.r.test.builtins.TestBuiltin_deparse.testDeparse #{ x<-expression(1); deparse(x) } [1] "expression(1)" @@ -36745,6 +36768,21 @@ integer(0) #argv <- structure(list(pkgname = 'stats4', event = 'onLoad'), .Names = c('pkgname', 'event'));do.call('packageEvent', argv) [1] "UserHook::stats4::onLoad" +##com.oracle.truffle.r.test.builtins.TestBuiltin_pairlist.testPairList +#{ x<-7; y<-c(foo=42); z<-pairlist(x, y); list(z, typeof(z)) } +[[1]] +[[1]][[1]] +[1] 7 + +[[1]][[2]] +foo + 42 + + +[[2]] +[1] "pairlist" + + ##com.oracle.truffle.r.test.builtins.TestBuiltin_pairlist.testpairlist1 #argv <- list();do.call('pairlist', argv) NULL @@ -40693,14 +40731,6 @@ logical(0) [145] NA 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [163] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -##com.oracle.truffle.r.test.builtins.TestBuiltin_retracemem.testretracemem1 -#argv <- list(FALSE, FALSE);retracemem(argv[[1]],argv[[2]]); -Error in retracemem(argv[[1]], argv[[2]]) : invalid 'previous' argument - -##com.oracle.truffle.r.test.builtins.TestBuiltin_retracemem.testretracemem2 -#argv <- list(structure(3.14159265358979, class = structure('3.14159265358979', class = 'testit')), structure(3.14159265358979, class = structure('3.14159265358979', class = 'testit')));retracemem(argv[[1]],argv[[2]]); -Error in retracemem(argv[[1]], argv[[2]]) : invalid 'previous' argument - ##com.oracle.truffle.r.test.builtins.TestBuiltin_rev.testRev #{ rev(1:3) } [1] 3 2 1 @@ -48848,6 +48878,39 @@ character(0) #argv <- structure(list(x = c('na', NA, 'banana')), .Names = 'x');do.call('toupper', argv) [1] "NA" NA "BANANA" +##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.argumentErrors +#retracemem(NULL) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.argumentErrors +#retracemem(c(1,10,100), 1:10) +Error in retracemem(c(1, 10, 100), 1:10) : invalid 'previous' argument + +##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.argumentErrors +#tracemem(NULL) +Error in tracemem(NULL) : cannot trace NULL + +##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.list +#v <- list(1,10,100); tracemem(v); x <- v; x[[1]]<-42; +[1] "<0x112db18>" +tracemem[0x112db18 -> 0x1699c30]: + +##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.retracemem +#v <- c(1,10,100); tracemem(v); x <- v[-1]; retracemem(x, retracemem(v)); u <- x; u[[1]] <- 42; +[1] "<0x17f8b18>" +tracemem[<0x17f8b18> -> 0x251dd78]: +tracemem[0x251dd78 -> 0x251ddb0]: + +##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.vectors +#v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; untracemem(v); y[[2]] <- 84 +[1] "<0x1b8eb18>" +tracemem[0x1b8eb18 -> 0x20fabe8]: + +##com.oracle.truffle.r.test.builtins.TestBuiltin_tracemem.vectors +#v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; y[[2]] <- 84 +[1] "<0x24b2b18>" +tracemem[0x24b2b18 -> 0x2a1ebe8]: +tracemem[0x24b2b18 -> 0x2a1ea80]: + ##com.oracle.truffle.r.test.builtins.TestBuiltin_trigamma.testtrigamma1 #argv <- list(structure(c(9.16602362697115, 1.16602362697115, 3.16602362697115, 6.16602362697115, 6.16602362697115, 2.16602362697115, 8.16602362697115, 1.16602362697115, 7.16602362697115, 19.1660236269712, 2.16602362697115), .Names = c('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11')));trigamma(argv[[1]]); 1 2 3 4 5 6 7 @@ -106806,31 +106869,31 @@ a b c d e [1] "123" ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions -#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { { f<-function(x) fastr.refcountinfo(x); f(c(1,2)) } } +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { { f<-function(x) .fastr.refcountinfo(x); f(c(1,2)) } } [1] 1 ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions -#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2 } else { { f<-function(x) { y<-x; fastr.refcountinfo(y) }; f(c(1,2)) } } +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2 } else { { f<-function(x) { y<-x; .fastr.refcountinfo(y) }; f(c(1,2)) } } [1] 2 ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions -#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2 } else { { x<-c(1,2); f<-function(x) fastr.refcountinfo(x); f(x) } } +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2 } else { { x<-c(1,2); f<-function(x) .fastr.refcountinfo(x); f(x) } } [1] 2 ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions -#if (length(grep("FastR", R.Version()$version.string)) != 1) { FALSE } else { { f<-function(y) { x<-y; xi1<-fastr.identity(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }; f(c(1,2)) } } +#if (length(grep("FastR", R.Version()$version.string)) != 1) { FALSE } else { { f<-function(y) { x<-y; xi1<-.fastr.identity(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }; f(c(1,2)) } } [1] FALSE ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions -#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { f<-function(x) { xi1<-fastr.identity(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }; f(c(1,2)) } } +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { f<-function(x) { xi1<-.fastr.identity(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }; f(c(1,2)) } } [1] TRUE ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions -#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { x<-rep(1, 100); xi1<-fastr.identity(x); f<-function(x) { x }; f(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 } } +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { x<-rep(1, 100); xi1<-.fastr.identity(x); f<-function(x) { x }; f(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 } } [1] TRUE ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions -#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { x<-rep(1, 100); xi1<-fastr.identity(x); f<-function(x) { y<-x; y }; f(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 } } +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { x<-rep(1, 100); xi1<-.fastr.identity(x); f<-function(x) { y<-x; y }; f(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 } } [1] TRUE ##com.oracle.truffle.r.test.library.stats.TestFitting.testLm diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java index b002045656a8214a91587222a65aedb82e056adf..257566d7e83fdf6d15a746ff079664c03fdd5138 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java @@ -22,6 +22,7 @@ import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.HashMap; import java.util.Map.Entry; import java.util.SortedMap; import java.util.TreeMap; @@ -68,6 +69,7 @@ public class TestBase { IgnoreWarningContext, // the warning context is ignored MayIgnoreErrorContext, MayIgnoreWarningContext, + ContainsReferences, // replaces references in form of 0xbcdef1 for numbers IgnoreWhitespace; } @@ -353,6 +355,11 @@ public class TestBase { */ private static final boolean FULL_COMPARE_ERRORS = false; + /** + * To implement {@link Output#ContainsReferences}. + **/ + private static final Pattern REFERENCE_PATTERN = Pattern.compile("(?<id>(0x[0-9abcdefx]+))"); + /** * Test a given string with R source against expected output. This is (currently) an exact * match, so any warnings or errors will cause a failure until FastR matches GnuR in that @@ -459,6 +466,7 @@ public class TestBase { boolean mayContainError = TestTrait.contains(traits, Output.MayIgnoreErrorContext); boolean ambiguousError = TestTrait.contains(traits, Output.IgnoreErrorMessage); boolean ignoreWhitespace = TestTrait.contains(traits, Output.IgnoreWhitespace); + boolean containsReferences = TestTrait.contains(traits, Output.ContainsReferences); boolean nonSharedContext = TestTrait.contains(traits, Context.NonShared); boolean longTimeout = TestTrait.contains(traits, Context.LongTimeout); @@ -477,7 +485,7 @@ public class TestBase { result = result.replaceAll("\\s+", ""); } - CheckResult checkResult = checkResult(whiteLists, input, expected, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError); + CheckResult checkResult = checkResult(whiteLists, input, expected, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError, containsReferences); result = checkResult.result; expected = checkResult.expected; @@ -539,14 +547,18 @@ public class TestBase { } private CheckResult checkResult(WhiteList[] whiteLists, String input, String originalExpected, String originalResult, boolean containsWarning, boolean mayContainWarning, boolean containsError, - boolean mayContainError, boolean ambiguousError) { + boolean mayContainError, boolean ambiguousError, boolean convertReferences) { boolean ok; String result = originalResult; String expected = originalExpected; + if (convertReferences) { + result = convertReferencesInOutput(result); + expected = convertReferencesInOutput(expected); + } if (input.equals("c(1i,1i,1i)/(-(1/0))")) { System.console(); } - if (expected.equals(result) || searchWhiteLists(whiteLists, input, expected, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError)) { + if (expected.equals(result) || searchWhiteLists(whiteLists, input, expected, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError, convertReferences)) { ok = true; if (containsError && !ambiguousError) { System.out.println("unexpected correct error message: " + getTestContext()); @@ -575,8 +587,23 @@ public class TestBase { return new CheckResult(ok, result, expected); } + private static String convertReferencesInOutput(String result) { + Matcher matcher = REFERENCE_PATTERN.matcher(result); + HashMap<String, Integer> idsMap = new HashMap<>(); + int currentId = 1; + while (matcher.find()) { + if (idsMap.putIfAbsent(matcher.group("id"), currentId) == null) { + currentId++; + } + } + for (Entry<String, Integer> item : idsMap.entrySet()) { + result = result.replace(item.getKey(), item.getValue().toString()); + } + return result; + } + private boolean searchWhiteLists(WhiteList[] whiteLists, String input, String expected, String result, boolean containsWarning, boolean mayContainWarning, boolean containsError, - boolean mayContainError, boolean ambiguousError) { + boolean mayContainError, boolean ambiguousError, boolean convertReferences) { if (whiteLists == null) { return false; } @@ -584,13 +611,13 @@ public class TestBase { WhiteList.Results wlr = list.get(input); if (wlr != null) { // Sanity check that "expected" matches the entry in the WhiteList - CheckResult checkedResult = checkResult(null, input, wlr.expected, expected, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError); + CheckResult checkedResult = checkResult(null, input, wlr.expected, expected, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError, convertReferences); if (!checkedResult.ok) { System.out.println("expected output does not match: " + wlr.expected + " vs. " + expected); return false; } // Substitute the FastR output and try to match that - CheckResult fastRResult = checkResult(null, input, wlr.fastR, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError); + CheckResult fastRResult = checkResult(null, input, wlr.fastR, result, containsWarning, mayContainWarning, containsError, mayContainError, ambiguousError, convertReferences); if (fastRResult.ok) { list.markUsed(input); return true; diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java index b3fe43da16d732f65ee0fda8883c1163fb5ac5fd..b972661904eccb4e49daa0755387d353cb8a4cef 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java @@ -541,6 +541,9 @@ public class TestBuiltin_c extends TestBase { assertEval("{ setClass(\"foo\", representation(d=\"numeric\")); x<-new(\"foo\", d=42); y<-c(x, 7); y[[1]] }"); assertEval("{ typeof(c(as.symbol(\"foo\"), 42)) }"); + + // names vector created by combine cannot be temporary + assertEval("{ x<-c(a=42); y<-c(b=7); z<-c(x,y); w<-names(z); w[[1]]<-\"c\"; z }"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_complex.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_complex.java index 166495ab7772c50e59904a86b027f24455ac6a93..9698cfdb0b5fe5ac45effa9dbb8fc9bd044df5b3 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_complex.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_complex.java @@ -24,13 +24,12 @@ public class TestBuiltin_complex extends TestBase { @Test public void testcomplex2() { - assertEval(Ignored.Unknown, "argv <- list(FALSE, FALSE, numeric(0)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))"); + assertEval("argv <- list(FALSE, FALSE, numeric(0)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))"); } @Test public void testcomplex3() { - assertEval(Ignored.Unknown, - "argv <- list(0L, 1:10, c(1, 1.4142135623731, 1.73205080756888, 2, 2.23606797749979, 2.44948974278318, 2.64575131106459, 2.82842712474619, 3, 3.16227766016838)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))"); + assertEval("argv <- list(0L, 1:10, c(1, 1.4142135623731, 1.73205080756888, 2, 2.23606797749979, 2.44948974278318, 2.64575131106459, 2.82842712474619, 3, 3.16227766016838)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))"); } @Test @@ -50,7 +49,7 @@ public class TestBuiltin_complex extends TestBase { @Test public void testcomplex7() { - assertEval(Ignored.Unknown, "argv <- list(0L, NULL, numeric(0)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))"); + assertEval("argv <- list(0L, NULL, numeric(0)); .Internal(complex(argv[[1]], argv[[2]], argv[[3]]))"); } @Test @@ -58,6 +57,9 @@ public class TestBuiltin_complex extends TestBase { assertEval("{ complex(real=1,imaginary=2) }"); assertEval("{ complex(real=1,imag=2) }"); assertEval("{ complex(3) }"); + assertEval(Output.IgnoreErrorMessage, "{ complex(new.env()) }"); + assertEval("{ complex(3, new.env()) }"); + assertEval("{ complex(3, 3, new.env()) }"); assertEval("{ complex(3, c(1,2,3), c(4,5,6)) }"); assertEval("{ complex(3, c(1,2,3), c(4,5)) }"); assertEval("{ complex(3, c(1,2), c(4,5,6)) }"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java index 8a8b2d5ef5f58711e052ff74d34266dc699895e1..1ad6c86052ab6784676a60143e735538dfdbbf4e 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_deparse.java @@ -319,6 +319,8 @@ public class TestBuiltin_deparse extends TestBase { assertEval("unserialize(serialize(quote(!(a <- TRUE)), NULL))"); assertEval("unserialize(serialize(quote(a[a <- TRUE]), NULL))"); + + assertEval("{ x<-c(a=42, b=7); deparse(x) }"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pairlist.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pairlist.java index bcf662251692789948b05cf944e737d65507f520..5c44cfe13b3b3ffc5126d1bea67ea46041fb5854 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pairlist.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_pairlist.java @@ -22,4 +22,10 @@ public class TestBuiltin_pairlist extends TestBase { public void testpairlist1() { assertEval("argv <- list();do.call('pairlist', argv)"); } + + @Test + public void testPairList() { + assertEval("{ x<-7; y<-c(foo=42); z<-pairlist(x, y); list(z, typeof(z)) }"); + } + } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_retracemem.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_retracemem.java deleted file mode 100644 index ae260d0e65b227cb5ccdee90bea38ccda0e052c8..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_retracemem.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This material is distributed under the GNU General Public License - * Version 2. You may review the terms of this license at - * http://www.gnu.org/licenses/gpl-2.0.html - * - * Copyright (c) 2014, Purdue University - * Copyright (c) 2014, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.test.builtins; - -import org.junit.Test; - -import com.oracle.truffle.r.test.TestBase; - -// Checkstyle: stop line length check -public class TestBuiltin_retracemem extends TestBase { - - @Test - public void testretracemem1() { - assertEval(Ignored.Unknown, "argv <- list(FALSE, FALSE);retracemem(argv[[1]],argv[[2]]);"); - } - - @Test - public void testretracemem2() { - assertEval(Ignored.Unknown, - "argv <- list(structure(3.14159265358979, class = structure('3.14159265358979', class = 'testit')), structure(3.14159265358979, class = structure('3.14159265358979', class = 'testit')));retracemem(argv[[1]],argv[[2]]);"); - } -} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tracemem.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tracemem.java new file mode 100644 index 0000000000000000000000000000000000000000..7b4e4e6f413c56d80610c894335b45f40983ee96 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tracemem.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.truffle.r.test.builtins; + +import org.junit.Test; + +import com.oracle.truffle.r.test.TestBase; + +/** + * Tests tracemem and related builtins. + */ +public class TestBuiltin_tracemem extends TestBase { + @Test + public void argumentErrors() { + assertEval("tracemem(NULL)"); + assertEval("retracemem(NULL)"); + assertEval("retracemem(c(1,10,100), 1:10)"); + } + + @Test + public void vectors() { + assertEval(Output.ContainsReferences, "v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; y[[2]] <- 84"); + assertEval(Output.ContainsReferences, "v <- c(1,10,100); tracemem(v); x <- v; y <- v; x[[1]]<-42; untracemem(v); y[[2]] <- 84"); + } + + @Test + public void list() { + assertEval(Output.ContainsReferences, "v <- list(1,10,100); tracemem(v); x <- v; x[[1]]<-42;"); + } + + @Test + public void retracemem() { + // intended semantics of retracemem is not clear, this tests what is definitely intended: + // retracemem starts tracing of its first argument + assertEval(Output.ContainsReferences, "v <- c(1,10,100); tracemem(v); x <- v[-1]; retracemem(x, retracemem(v)); u <- x; u[[1]] <- 42;"); + } +} diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestStateTrans.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestStateTrans.java index ff68983f3f4a650650aac0055063dec408774959..d0dbbf9a5d425c504f77a51f7f00f71ff6384156 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestStateTrans.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestStateTrans.java @@ -31,14 +31,14 @@ public class TestStateTrans extends TestBase { @Test public void testTransitions() { - assertEvalFastR("{ f<-function(x) fastr.refcountinfo(x); f(c(1,2)) }", "1"); - assertEvalFastR("{ f<-function(x) { y<-x; fastr.refcountinfo(y) }; f(c(1,2)) }", "2"); - assertEvalFastR("{ x<-c(1,2); f<-function(x) fastr.refcountinfo(x); f(x) }", "2"); - assertEvalFastR("{ f<-function(x) { xi1<-fastr.identity(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }; f(c(1,2)) }", "TRUE"); - assertEvalFastR("{ f<-function(y) { x<-y; xi1<-fastr.identity(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }; f(c(1,2)) }", "FALSE"); + assertEvalFastR("{ f<-function(x) .fastr.refcountinfo(x); f(c(1,2)) }", "1"); + assertEvalFastR("{ f<-function(x) { y<-x; .fastr.refcountinfo(y) }; f(c(1,2)) }", "2"); + assertEvalFastR("{ x<-c(1,2); f<-function(x) .fastr.refcountinfo(x); f(x) }", "2"); + assertEvalFastR("{ f<-function(x) { xi1<-.fastr.identity(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }; f(c(1,2)) }", "TRUE"); + assertEvalFastR("{ f<-function(y) { x<-y; xi1<-.fastr.identity(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }; f(c(1,2)) }", "FALSE"); // after returning from read-only functions, vector should be modifiable without // creating a copy - assertEvalFastR("{ x<-rep(1, 100); xi1<-fastr.identity(x); f<-function(x) { x }; f(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }", "TRUE"); - assertEvalFastR("{ x<-rep(1, 100); xi1<-fastr.identity(x); f<-function(x) { y<-x; y }; f(x); x[1]<-7; xi2<-fastr.identity(x); xi1 == xi2 }", "TRUE"); + assertEvalFastR("{ x<-rep(1, 100); xi1<-.fastr.identity(x); f<-function(x) { x }; f(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }", "TRUE"); + assertEvalFastR("{ x<-rep(1, 100); xi1<-.fastr.identity(x); f<-function(x) { y<-x; y }; f(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 }", "TRUE"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RBuiltinCheck.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RBuiltinCheck.java index 2ce13c5c6a2a97403a8dfae84a64514e047f9e53..f34dc91c6beab8cfd78f4583140f10292d7622d7 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RBuiltinCheck.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RBuiltinCheck.java @@ -28,10 +28,10 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; import java.util.function.BiPredicate; import java.util.function.Function; import java.util.regex.Matcher; @@ -44,6 +44,7 @@ import com.oracle.truffle.r.nodes.builtin.base.BasePackage; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RBuiltinKind; import com.oracle.truffle.r.runtime.RVisibility; +import com.oracle.truffle.r.test.TestBase.Ignored; /** * Utility to analyze builtins implemented in FastR vs. builtins available in GNU R. The GNU R @@ -62,6 +63,7 @@ import com.oracle.truffle.r.runtime.RVisibility; public final class RBuiltinCheck { private static final String DEFAULT_NAMESC = "com.oracle.truffle.r.native/gnur/R-3.2.4/src/main/names.c"; + private static final String BUILTIN_TEST_PATH = "com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_%s.java"; // old-style code annotation to get rid of javadoc error. /** @@ -170,7 +172,7 @@ public final class RBuiltinCheck { return; // so that gnur can be final } - Set<String> both = new HashSet<>(fastr.keySet()); + Set<String> both = new TreeSet<>(fastr.keySet()); both.retainAll(gnur.keySet()); Set<String> fastrOnly = keysWithout(fastr, both); @@ -181,14 +183,14 @@ public final class RBuiltinCheck { both.removeAll(descriptorsDiff.keySet()); // Print the results - printOutput(show, both, descriptorsDiff, fastrOnly, gnurOnly); + printOutput(suitePath, show, both, descriptorsDiff, fastrOnly, gnurOnly); } - private static void printOutput(EnumSet<FilterOption> show, Set<String> both, Map<String, BuiltinTuple> descriptorsDiff, Set<String> fastrOnly, Set<String> gnurOnly) { + private static void printOutput(String suitePath, EnumSet<FilterOption> show, Set<String> both, Map<String, BuiltinTuple> descriptorsDiff, Set<String> fastrOnly, Set<String> gnurOnly) { String prefix = ""; if (show.contains(FilterOption.BOTH)) { prefix = printHeader(prefix, show, "Builtins in both GNU R and FastR with matching descriptors: " + both.size()); - both.stream().forEach(System.out::println); + both.stream().forEach(b -> printBuiltinWithTest(b, suitePath)); } if (show.contains(FilterOption.BOTH_DIFF)) { @@ -220,6 +222,24 @@ public final class RBuiltinCheck { } } + private static void printBuiltinWithTest(String builtin, String suitePath) { + String name = builtin.replace(".", ""); + name = name.replace("<-", "assign"); + try { + String content = Files.lines(Paths.get(suitePath, String.format(BUILTIN_TEST_PATH, name))).collect(Collectors.joining("\n")); + int tests = content.split("assertEval").length - 1; + int ignoredTests = content.split(Ignored.class.getSimpleName()).length - 1; + if (tests > 0) { + String testDetails = String.format("%3d%% (%d/%d)", (tests - ignoredTests) * 100 / tests, tests - ignoredTests, tests); + System.out.printf("%-15s %s%n", builtin, testDetails); + return; + } + } catch (IOException e) { + // nothing to do + } + System.out.printf("%-20s (no tests found)%n", builtin); + } + private static String formatTableCell(String format, BuiltinTuple tuple, Function<BuiltinInfo, Object> selector, BiPredicate<BuiltinInfo, BuiltinInfo> cmp) { String result = String.format(format, selector.apply(tuple.fastr), selector.apply(tuple.gnur)); if (!cmp.test(tuple.fastr, tuple.gnur)) { @@ -235,19 +255,18 @@ public final class RBuiltinCheck { if (show.size() > 1) { System.out.println(prefix + header); } - return "\n\n"; } private static Set<String> keysWithout(Map<String, BuiltinInfo> map, Set<String> both) { - Set<String> mapOnly = new HashSet<>(map.keySet()); + Set<String> mapOnly = new TreeSet<>(map.keySet()); mapOnly.removeAll(both); return mapOnly; } private static Map<String, BuiltinInfo> extractFastRBuiltins() { BasePackage base = new BasePackage(); - HashMap<String, BuiltinInfo> result = new HashMap<>(); + Map<String, BuiltinInfo> result = new TreeMap<>(); for (Map.Entry<String, RBuiltinFactory> builtin : base.getBuiltins().entrySet()) { Class<?> clazz = builtin.getValue().getBuiltinNodeClass(); RBuiltin annotation = clazz.getAnnotation(RBuiltin.class); @@ -264,7 +283,7 @@ public final class RBuiltinCheck { private static Map<String, BuiltinInfo> extractGnuRBuiltins(String suiteDir) throws IOException { String content = Files.lines(Paths.get(suiteDir, DEFAULT_NAMESC)).collect(Collectors.joining("\n")); Matcher matcher = Pattern.compile(FUNTAB_REGEXP).matcher(content); - HashMap<String, BuiltinInfo> result = new HashMap<>(); + Map<String, BuiltinInfo> result = new TreeMap<>(); while (matcher.find()) { // normalize eval to three digits, e.g. '2' to '002' String eval = String.format("%1$3s", matcher.group("eval")).replace(' ', '0'); diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index 573f4ba7708d8c65544061cb755aada2ce29520a..64a55c761c15eabae7c9761e45cb00f34680dfbf 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -572,7 +572,6 @@ com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_reg com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java,purdue.copyright com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java,purdue.copyright com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_repint.java,purdue.copyright -com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_retracemem.java,purdue.copyright com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rev.java,purdue.copyright com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_round.java,purdue.copyright com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_row.java,purdue.copyright diff --git a/mx.fastr/mx_fastr_pkgs.py b/mx.fastr/mx_fastr_pkgs.py index eca0d4bf72f6bef420844c839831b5429417da48..334b4c3e9a4b935b38cb3e0ec3e621c681c5be02 100644 --- a/mx.fastr/mx_fastr_pkgs.py +++ b/mx.fastr/mx_fastr_pkgs.py @@ -133,7 +133,11 @@ def pkgtest(args): _log_step('BEGIN', 'install/test', 'FastR') # Currently installpkgs does not set a return code (in install.cran.packages.R) - mx_fastr._installpkgs(stacktrace_args + install_args, nonZeroIsFatal=False, env=env, out=out, err=out) + rc = mx_fastr._installpkgs(stacktrace_args + install_args, nonZeroIsFatal=False, env=env, out=out, err=out) + if rc == 100: + # fatal error connecting to package repo + mx.abort(rc) + rc = 0 for status in out.install_status.itervalues(): if not status: @@ -186,7 +190,7 @@ def _get_test_outputs(suite, pkg_name, test_info): test_info[pkg_name] = TestStatus() for f in files: ext = os.path.splitext(f)[1] - if ext == '.R' or ext == '.prev': + if f == 'test_time' or ext == '.R' or ext == '.prev': continue # suppress .pdf's for now (we can't compare them) if ext == '.pdf': @@ -265,26 +269,37 @@ def _set_test_status(fastr_test_info): gnur_outputs = gnur_test_status.testfile_outputs fastr_outputs = fastr_test_status.testfile_outputs if _failed_outputs(gnur_outputs): + # What this likely means is that some native package is not + # installed on the system so GNUR can't run the tests. + # Ideally this never happens. print "{0}: GnuR test had .fail outputs".format(pkg) - continue if _failed_outputs(fastr_outputs): + # In addition to the similar comment for GNU R, this can happen + # if, say, the JVM crashes (possible with native code packages) print "{0}: FastR test had .fail outputs".format(pkg) fastr_test_status.status = "FAILED" - continue - + # Now for each successful GNU R output we compare content (assuming FastR didn't fail) for gnur_test_output_relpath, gnur_testfile_status in gnur_outputs.iteritems(): + # Can't compare if either GNUR or FastR failed + if gnur_testfile_status.status == "FAILED": + break + if not gnur_test_output_relpath in fastr_outputs: + # FastR crashed on this test fastr_test_status.status = "FAILED" print "{0}: FastR is missing output file: {1}".format(pkg, gnur_test_output_relpath) break + fastr_testfile_status = fastr_outputs[gnur_test_output_relpath] + if fastr_testfile_status.status == "FAILED": + break + gnur_content = None with open(gnur_testfile_status.abspath) as f: gnur_content = f.readlines() fastr_content = None - fastr_testfile_status = fastr_outputs[gnur_test_output_relpath] with open(fastr_testfile_status.abspath) as f: fastr_content = f.readlines() @@ -295,11 +310,27 @@ def _set_test_status(fastr_test_info): break if result != 0: fastr_test_status.status = "FAILED" + fastr_testfile_status.status = "FAILED" print "{0}: FastR output mismatch: {1}".format(pkg, gnur_test_output_relpath) break # we started out as UNKNOWN if not (fastr_test_status.status == "INDETERMINATE" or fastr_test_status.status == "FAILED"): fastr_test_status.status = "OK" + + # write out a file with the test status for each output (that exists) + with open(join(_pkg_testdir('fastr', pkg), 'testfile_status'), 'w') as f: + for fastr_relpath, fastr_testfile_status in fastr_outputs.iteritems(): + if fastr_testfile_status.status == "FAILED": + relpath = fastr_relpath + ".fail" + else: + relpath = fastr_relpath + + if os.path.exists(join(_pkg_testdir('fastr', pkg), relpath)): + f.write(relpath) + f.write(' ') + f.write(fastr_testfile_status.status) + f.write('\n') + print 'END checking ' + pkg def _find_start(content):