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 9744d89ebda248d647be26c292d7a621fa0cf48e..8c6219e025259da327baa3ef5e0c2db103981188 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 @@ -47,7 +47,6 @@ import com.oracle.truffle.r.nodes.control.IfNode; import com.oracle.truffle.r.nodes.control.ReplacementNode; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; -import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java index 30a134642b932dbd8197084dfad5f5562ecdf335..04c66c9f1e98f0a38d1966e699a4142dfe2392ad 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java @@ -242,7 +242,7 @@ public class RCommand { } else if (cause instanceof ExitException) { // usually from quit vm.dispose(); - System.exit(((ExitException) cause).getStatus()); + Utils.systemExit(((ExitException) cause).getStatus()); } else { RInternalError.reportErrorAndConsoleLog(cause, consoleHandler, 0); // We continue the repl even though the system may be broken @@ -262,7 +262,7 @@ public class RCommand { } catch (Throwable e) { if (e.getCause() instanceof ExitException) { // normal quit, but with exit code based on lastStatus - System.exit(lastStatus); + Utils.systemExit(lastStatus); } throw RInternalError.shouldNotReachHere(e); } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java index 5b4d80c96f3f3d8b085cf7f2a706ebb056a7eba9..b952a0da7a3b74f43725f163a7221b7d57d48379 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/ObjectSize.java @@ -22,199 +22,56 @@ */ package com.oracle.truffle.r.library.utils; -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.library.utils.ObjectSizeNodeGen.RecursiveObjectSizeNodeGen; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; -import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; -import com.oracle.truffle.r.runtime.data.RAttributable; -import com.oracle.truffle.r.runtime.data.RAttributes; -import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute; -import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RDoubleSequence; -import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RExpression; +import com.oracle.truffle.r.runtime.data.RObjectSize; import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RIntSequence; -import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RLanguage; -import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RLogicalVector; import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RPairList; -import com.oracle.truffle.r.runtime.data.RRaw; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.RTypedValue; -/* - * Similarly to GNU R's version, this is very approximate - * (e.g. overhead related to Java object headers is not included) - * and is only (semi) accurate for atomic vectors. +/** + * Similarly to GNU R's version, this is approximate and based, for {@link RTypedValue} instances on + * {@link RObjectSize#getObjectSize}. As per GNU R the AST size for a closure is included. TODO AST + * size not included owing to problems sizing it automatically. */ +@SuppressWarnings("unused") public abstract class ObjectSize extends RExternalBuiltinNode.Arg1 { - protected abstract int executeInt(Object o); - - @Child RecursiveObjectSize recursiveObjectSize; - - protected int recursiveObjectSize(Object o) { - if (recursiveObjectSize == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveObjectSize = insert(RecursiveObjectSizeNodeGen.create()); - } - return recursiveObjectSize.executeInt(o); - } - - @Specialization - protected int objectSize(@SuppressWarnings("unused") RNull o) { - return 64; // pointer? - } - - @Specialization - protected int objectSize(@SuppressWarnings("unused") int o) { - return 32; - } - - @Specialization - protected int objectSize(@SuppressWarnings("unused") double o) { - return 64; - } - - @Specialization - protected int objectSize(@SuppressWarnings("unused") byte o) { - return 8; - } - - @Specialization - protected int objectSize(String o) { - return o.length() * 16; - } - - @Specialization - protected int objectSize(@SuppressWarnings("unused") RRaw o) { - return 8; - } - - @Specialization - protected int objectSize(@SuppressWarnings("unused") RComplex o) { - return 128; - } - - @Specialization - protected int objectSize(RIntSequence o) { - int res = 96; // int length + int start + int stride - return res + attrSize(o); - } - - @Specialization - protected int objectSize(RDoubleSequence o) { - int res = 160; // int length + double start + double stride - return res + attrSize(o); - } - - @Specialization - protected int objectSize(RIntVector o) { - return o.getLength() * 32 + attrSize(o); - } - - @Specialization - protected int objectSize(RDoubleVector o) { - return o.getLength() * 64 + attrSize(o); - } - - @Specialization - protected int objectSize(RStringVector o) { - int res = 0; - for (int i = 0; i < o.getLength(); i++) { - res += o.getLength() * 16; - } - return res + attrSize(o); - } - - @Specialization - protected int objectSize(RLogicalVector o) { - return o.getLength() * 8 + attrSize(o); - } - - @Specialization - protected int objectSize(RComplexVector o) { - return o.getLength() * 128 + attrSize(o); - } - - @Specialization - protected int objectSize(RRawVector o) { - return o.getLength() * 8 + attrSize(o); - } - - @Specialization - @TruffleBoundary - protected int objectSize(RList o) { - int res = 0; - for (int i = 0; i < o.getLength(); i++) { - res += recursiveObjectSize(o.getDataAt(i)); - } - return res + attrSize(o); - } - - @Specialization - @TruffleBoundary - protected int objectSize(RPairList o) { - RPairList list = o; - Object car = list.car(); - int res = 0; - while (true) { - res += recursiveObjectSize(car); - Object cdr = list.cdr(); - if (cdr == RNull.instance) { - break; + private static class MyIgnoreObjectHandler implements RObjectSize.IgnoreObjectHandler { + @Override + public boolean ignore(Object rootObject, Object obj) { + if (obj == RNull.instance) { + return true; } else { - list = (RPairList) cdr; - car = list.car(); + return false; } } - return res + attrSize(o); - } - @Specialization - protected int objectSize(@SuppressWarnings("unused") RFunction o) { - return 256; // arbitrary, but does it really matter? } + private static final MyIgnoreObjectHandler ignoreObjectHandler = new MyIgnoreObjectHandler(); + @Specialization - protected int objectSize(@SuppressWarnings("unused") RLanguage o) { - return 256; // arbitrary, but does it really matter? + protected int objectSize(int o) { + return RObjectSize.INT_SIZE; } @Specialization - protected int objectSize(@SuppressWarnings("unused") RExpression o) { - return 256; // arbitrary, but does it really matter? + protected int objectSize(double o) { + return RObjectSize.DOUBLE_SIZE; } - protected int attrSize(RAttributable o) { - return o.getAttributes() == null ? 0 : attrSizeInternal(o.getAttributes()); + @Specialization + protected int objectSize(byte o) { + return RObjectSize.BYTE_SIZE; } + @Fallback @TruffleBoundary - protected int attrSizeInternal(RAttributes attributes) { - int size = 0; - for (RAttribute attr : attributes) { - size += attr.getName().length() * 16; - size += recursiveObjectSize(attr.getValue()); - } - return size; - } - - protected abstract static class RecursiveObjectSize extends TruffleBoundaryNode { - - protected abstract int executeInt(Object o); - - @Child ObjectSize objectSize = ObjectSizeNodeGen.create(); - - @Specialization - protected int objectSize(Object o) { - return objectSize.executeInt(o); - } + protected int objectSize(Object o) { + return (int) RObjectSize.getObjectSize(o, ignoreObjectHandler); } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java index d03f663b1151eaae9a39bdecede4f62e9996a80e..db38227316cc29e6eec6064ae342363e887c6018 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java @@ -50,12 +50,36 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSource; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RObjectSize; +import com.oracle.truffle.r.runtime.data.RTypedValue; +import com.oracle.truffle.r.runtime.data.MemoryCopyTracer; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.instrument.InstrumentationState.RprofState; +import com.oracle.truffle.r.runtime.instrument.InstrumentationState.RprofState.MemoryQuad; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; -public abstract class Rprof extends RExternalBuiltinNode.Arg8 { +/** + * Implements the {@code Rprof} external. + * + * The output is basically a sequence of call stacks, output at each sample interval, with entries + * in the stack identified by quoted function names. If memory profiling, the stack is preceded by a + * auad of numbers {@code :smallv:bigv:nodes:duplicate_counter:} allocated in the interval. If line + * profiling is enabled source files are listed as + * + * <pre> + * #File N: path + * </pre> + * + * and then the {@code N} is used in line number references of the form {@code N#L},which precede + * the function name. + * + */ +public abstract class Rprof extends RExternalBuiltinNode.Arg8 implements RDataFactory.Listener, MemoryCopyTracer.Listener { + + private RprofState profState; @SuppressWarnings("unused") @Specialization @@ -64,13 +88,13 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 { if (!RContext.getInstance().isInitial()) { throw RError.error(this, RError.Message.GENERIC, "profiling not supported in created contexts"); } - RprofState profState = RContext.getInstance().stateInstrumentation.getRprof(); + profState = RContext.getInstance().stateInstrumentation.getRprof(); String filename = filenameVec.getDataAt(0); if (filename.length() == 0) { // disable endProfiling(); } else { - // enable + // enable after ending any previous session if (profState.out() != null) { endProfiling(); } @@ -79,18 +103,21 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 { boolean gcProfiling = RRuntime.fromLogical(gcProfilingL); try { PrintWriter out = new PrintWriter(new FileWriter(filename, append)); - if (memProfiling) { - RError.warning(this, RError.Message.GENERIC, "Rprof: memory profiling not supported"); - } if (gcProfiling) { RError.warning(this, RError.Message.GENERIC, "Rprof: gc profiling not supported"); } + if (memProfiling) { + RDataFactory.addListener(this); + RDataFactory.setAllocationTracing(true); + MemoryCopyTracer.addListener(this); + MemoryCopyTracer.setTracingState(true); + } // interval is in seconds, we convert to millis long intervalInMillis = (long) (1E3 * intervalD); StatementListener statementListener = new StatementListener(); ProfileThread profileThread = new ProfileThread(intervalInMillis, statementListener); profileThread.setDaemon(true); - profState.initialize(out, profileThread, statementListener, intervalInMillis, RRuntime.fromLogical(lineProfilingL)); + profState.initialize(out, profileThread, statementListener, intervalInMillis, RRuntime.fromLogical(lineProfilingL), memProfiling); profileThread.start(); } catch (IOException ex) { throw RError.error(this, RError.Message.GENERIC, String.format("Rprof: cannot open profile file '%s'", filename)); @@ -99,13 +126,37 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 { return RNull.instance; } - private static void endProfiling() { - RprofState profState = RContext.getInstance().stateInstrumentation.getRprof(); + @Override + @TruffleBoundary + public void reportAllocation(RTypedValue data) { + long size = RObjectSize.getObjectSize(data, Rprofmem.myIgnoreObjectHandler); + if (data instanceof RAbstractVector) { + if (size >= Rprofmem.LARGE_VECTOR) { + profState.memoryQuad().largeV += size; + } else { + profState.memoryQuad().smallV += size; + } + } else { + profState.memoryQuad().nodes += size; + } + + } + + @Override + @TruffleBoundary + public void reportCopying(RAbstractVector source, RAbstractVector dest) { + profState.memoryQuad().copied += RObjectSize.getObjectSize(source, Rprofmem.myIgnoreObjectHandler); + } + + private void endProfiling() { ProfileThread profileThread = (ProfileThread) profState.profileThread(); profileThread.running = false; HashMap<String, Integer> fileMap = null; PrintWriter out = profState.out(); StatementListener statementListener = (StatementListener) profState.statementListener(); + if (profState.memoryProfiling()) { + out.print("memory profiling: "); + } if (profState.lineProfiling()) { out.print("line profiling: "); } @@ -124,7 +175,12 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 { } } } + int index = 0; for (ArrayList<RSyntaxNode> intervalStack : statementListener.intervalStacks) { + if (profState.memoryProfiling()) { + MemoryQuad mq = statementListener.intervalMemory.get(index); + out.printf(":%d:%d:%d:%d:", mq.largeV, mq.smallV, mq.nodes, mq.copied); + } for (RSyntaxNode node : intervalStack) { RootNode rootNode = node.asRNode().getRootNode(); if (rootNode instanceof FunctionDefinitionNode) { @@ -139,8 +195,15 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 { } } out.println(); + index++; } out.close(); + profState.setOut(null); + if (profState.memoryProfiling()) { + RDataFactory.setAllocationTracing(false); + MemoryCopyTracer.setTracingState(false); + } + } private static String getPath(RSyntaxNode node) { @@ -177,8 +240,9 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 { * Emulates a sampling timer by checking when the sample interval rolls over and at that point * collects the stack of functions. */ - private static final class StatementListener implements ExecutionEventListener { + private final class StatementListener implements ExecutionEventListener { private ArrayList<ArrayList<RSyntaxNode>> intervalStacks = new ArrayList<>(); + private ArrayList<MemoryQuad> intervalMemory = new ArrayList<>(); private volatile boolean newInterval; private StatementListener() { @@ -200,12 +264,16 @@ public abstract class Rprof extends RExternalBuiltinNode.Arg8 { stack.add((RSyntaxNode) context.getInstrumentedNode()); collectStack(stack); intervalStacks.add(stack); + if (profState.memoryProfiling()) { + intervalMemory.add(profState.memoryQuad().copyAndClear()); + } + newInterval = false; } } @TruffleBoundary - private static void collectStack(final ArrayList<RSyntaxNode> stack) { + private void collectStack(final ArrayList<RSyntaxNode> stack) { Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() { @Override diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprofmem.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprofmem.java new file mode 100644 index 0000000000000000000000000000000000000000..5fa5c672e50bcf65325c39085cb018110c0dc822 --- /dev/null +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprofmem.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016, 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.library.utils; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +import com.oracle.truffle.r.runtime.RArguments; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RTypedValue; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RObjectSize; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.instrument.InstrumentationState.RprofmemState; + +public abstract class Rprofmem extends RExternalBuiltinNode.Arg3 implements RDataFactory.Listener { + + private RprofmemState profmemState; + + @Specialization + @TruffleBoundary + public Object doRprofmem(RAbstractStringVector filenameVec, byte appendL, RAbstractDoubleVector thresholdVec) { + if (!RContext.getInstance().isInitial()) { + throw RError.error(this, RError.Message.GENERIC, "profiling not supported in created contexts"); + } + String filename = filenameVec.getDataAt(0); + if (filename.length() == 0) { + // disable + endProfiling(); + } else { + // enable after ending any previous session + profmemState = RContext.getInstance().stateInstrumentation.getRprofmem(); + if (profmemState.out() != null) { + endProfiling(); + } + boolean append = RRuntime.fromLogical(appendL); + try { + PrintWriter out = new PrintWriter(new FileWriter(filename, append)); + profmemState.initialize(out, thresholdVec.getDataAt(0)); + RDataFactory.addListener(this); + RDataFactory.setAllocationTracing(true); + } catch (IOException ex) { + throw RError.error(this, RError.Message.GENERIC, String.format("Rprofmem: cannot open profile file '%s'", filename)); + } + } + return RNull.instance; + } + + private void endProfiling() { + if (profmemState != null) { + RDataFactory.setAllocationTracing(false); + profmemState.out().flush(); + profmemState.out().close(); + profmemState.setOut(null); + } + } + + private static final int PAGE_SIZE = 2000; + static final int LARGE_VECTOR = 128; + + /** + * We ignore nested {@link RTypedValue} instances as these will have been counted already. We + * also ignore {@link Node} instances, except in {@link RFunction} objects. + */ + private static class MyIgnoreObjectHandler implements RObjectSize.IgnoreObjectHandler { + @Override + public boolean ignore(Object rootObject, Object obj) { + if (obj == RNull.instance) { + return true; + } else { + Class<?> klass = obj.getClass(); + if (RTypedValue.class.isAssignableFrom(klass)) { + return true; + } else { + return false; + } + } + } + + } + + static final RObjectSize.IgnoreObjectHandler myIgnoreObjectHandler = new MyIgnoreObjectHandler(); + + @Override + @TruffleBoundary + public void reportAllocation(RTypedValue data) { + // We could do some in memory buffering + // TODO write out full stack + Frame frame = Utils.getActualCurrentFrame(); + if (frame == null) { + // not an R evaluation, some internal use + return; + } + RFunction func = RArguments.getFunction(frame); + if (func == null) { + return; + } + String name = func.getRootNode().getName(); + + long size = RObjectSize.getObjectSize(data, myIgnoreObjectHandler); + if (data instanceof RAbstractVector && size >= LARGE_VECTOR) { + profmemState.out().printf("%d: %s\n", size, name); + } else { + int pageCount = profmemState.pageCount(); + long pcs = pageCount + size; + if (pcs > PAGE_SIZE) { + profmemState.out().printf("new page: %s\n", name); + profmemState.setPageCount((int) (pcs - PAGE_SIZE)); + } else { + profmemState.setPageCount((int) pcs); + } + } + + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java index 70e3f59befe6762be709e18a834ab931dee2261f..905fb5e0d0e90b19380f9fc56fe0ee2f68a8d9fc 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AllNames.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.nodes.builtin.base; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; 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 1b9d8c311222962e25d0bd5c7565c90cf4ea1b92..8170e1d1b19f680b8335398e890fe242f5ef98cb 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 @@ -574,8 +574,8 @@ public class BasePackage extends RBuiltinPackage { add(Tabulate.class, TabulateNodeGen::create); add(TempDir.class, TempDirNodeGen::create); add(TempFile.class, TempFileNodeGen::create); - add(ToLowerOrUpper.ToLower.class, ToLowerOrUpper::createToLower); - add(ToLowerOrUpper.ToUpper.class, ToLowerOrUpper::createToUpper); + add(ToLowerOrUpper.ToLower.class, ToLowerOrUpperFactory.ToLowerNodeGen::create); + add(ToLowerOrUpper.ToUpper.class, ToLowerOrUpperFactory.ToUpperNodeGen::create); add(Traceback.class, TracebackNodeGen::create); add(TraceFunctions.PrimTrace.class, TraceFunctionsFactory.PrimTraceNodeGen::create); add(TraceFunctions.PrimUnTrace.class, TraceFunctionsFactory.PrimUnTraceNodeGen::create); @@ -624,8 +624,8 @@ public class BasePackage extends RBuiltinPackage { add(Vector.class, VectorNodeGen::create); add(Warning.class, WarningNodeGen::create); add(WhichFunctions.Which.class, WhichFunctionsFactory.WhichNodeGen::create); - add(WhichFunctions.WhichMax.class, WhichFunctionsFactory.WhichMaxNodeGen::create); - add(WhichFunctions.WhichMin.class, WhichFunctionsFactory.WhichMinNodeGen::create); + add(WhichFunctions.WhichMax.class, WhichFunctions.WhichMax::create); + add(WhichFunctions.WhichMin.class, WhichFunctions.WhichMin::create); add(Xtfrm.class, XtfrmNodeGen::create); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java index fcad0d222e6f7ac43fafc9bdd51bfecb6ee0119e..aa454c0002d8a29000c90055b468fb1ee87c8f77 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java @@ -362,7 +362,7 @@ public abstract class Combine extends RBuiltinNode { case LOGICAL_PRECEDENCE: return CastLogicalNodeGen.create(true, false, false); case STRING_PRECEDENCE: - return CastStringNodeGen.create(true, false, false, false); + return CastStringNodeGen.create(true, false, false); case RAW_PRECEDENCE: return CastRawNodeGen.create(true, false, false); case EXPRESSION_PRECEDENCE: diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java index 177768859206b1c9efe5fd9e697239ff55fffd5c..bd48e8980243abb1d75214c3cc5b599653657019 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Crossprod.java @@ -52,7 +52,7 @@ public abstract class Crossprod extends RBuiltinNode { return matMult.executeObject(op1, op2); } - private Object transpose(Object value) { + private Object transpose(RAbstractVector value) { if (transpose == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); transpose = insert(TransposeNodeGen.create(null)); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java index 9d902b5d481e52d677b754eee866fc0df6b3bf84..33546b1db6d04b2303b66e91a9fca9b7f9e497f7 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java @@ -741,7 +741,7 @@ public class FileFunctions { private CastStringNode initCastStringNode() { if (castStringNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castStringNode = insert(CastStringNodeGen.create(false, false, false, false)); + castStringNode = insert(CastStringNodeGen.create(false, false, false)); } return castStringNode; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java index c929d73972986ea4b0ac31e5336b72524325dac2..fa762a0a2f9e0fa7a67d30cc5a43595aaac4c592 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FormatC.java @@ -35,7 +35,7 @@ public abstract class FormatC extends RBuiltinNode { private RStringVector castStringVector(Object o) { if (castStringNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castStringNode = insert(CastStringNodeGen.create(true, true, true, false)); + castStringNode = insert(CastStringNodeGen.create(true, true, true)); } return (RStringVector) ((RStringVector) castStringNode.executeString(o)).copyDropAttributes(); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java index 81d4ba97e495193b6a14d90228fa3747042825ba..19d0acc4b7f43f8d331e226fccf24349f207d157 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java @@ -56,7 +56,6 @@ 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.builtins.RBuiltin; -import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RFunction; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java index cf527e00fb408b7a65f378b1031ff47245ac7122..bbb1f2bc9bffa1cc9b8065a6ac566e44bb48c950 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Match.java @@ -80,7 +80,7 @@ public abstract class Match extends RBuiltinNode { private RAbstractStringVector castString(RAbstractVector operand) { if (castString == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castString = insert(CastStringNodeGen.create(false, false, false, false)); + castString = insert(CastStringNodeGen.create(false, false, false)); } return (RAbstractStringVector) castString.execute(operand); } 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 7d4a5f2d108673a2310e1f2f826caf4e48faf24f..2400bc8fe76c7070f0f6fd940073e6772e22f7af 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 @@ -45,7 +45,7 @@ public abstract class NZChar extends RBuiltinNode { private String coerceContent(Object content) { if (convertString == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - convertString = insert(CastStringNodeGen.create(false, false, false, false)); + convertString = insert(CastStringNodeGen.create(false, false, false)); } return (String) convertString.execute(content); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java index a64a2900dbbed90e93852da8d52b9ade8aaee138..78b39957ba995d6bbf24687ff2a1f96a8f0cb11f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PMinMax.java @@ -118,7 +118,7 @@ public abstract class PMinMax extends RBuiltinNode { private CastNode getStringCastNode() { if (castString == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castString = insert(CastStringNodeGen.create(true, true, true, false)); + castString = insert(CastStringNodeGen.create(true, true, true)); } return castString; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java index 4f61514f592b76207e3b56bf3f37b2172a344b72..10550c3ed5be05f2679fb47d7740b92f74fa5c80 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Parse.java @@ -113,7 +113,7 @@ public abstract class Parse extends RBuiltinNode { if (castStringNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); castVectorNode = insert(CastToVectorNodeGen.create(false)); - castStringNode = insert(CastStringNodeGen.create(false, false, false, false)); + castStringNode = insert(CastStringNodeGen.create(false, false, false)); } return (RStringVector) castStringNode.executeString(castVectorNode.execute(s)); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java index 1935e7272540a4e7347a3ee11bd22f38799e49db..699b9fe4219a49ab2dd8e3b8977e5dacf4125e7f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Paste.java @@ -40,9 +40,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RSequence; import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; @RBuiltin(name = "paste", kind = INTERNAL, parameterNames = {"", "sep", "collapse"}, behavior = PURE) @@ -71,7 +69,7 @@ public abstract class Paste extends RBuiltinNode { private RStringVector castCharacterVector(Object o) { if (castCharacterNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castCharacterNode = insert(CastStringNodeGen.create(false, false, false, false)); + castCharacterNode = insert(CastStringNodeGen.create(false, false, false)); } Object ret = castCharacterNode.executeString(o); if (ret instanceof String) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java index db9729cdf6736b4720305df90f902393d8cb17e4..fdcad6132cc24b5119b071873ca097ca83765435 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Primitive.java @@ -22,14 +22,19 @@ */ 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.nodes.builtin.CastBuilder.Predef.stringValue; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; -import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.BranchProfile; +import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.builtins.RBuiltinKind; import com.oracle.truffle.r.runtime.context.RContext; @@ -37,24 +42,34 @@ import com.oracle.truffle.r.runtime.data.RFunction; @RBuiltin(name = ".Primitive", kind = PRIMITIVE, parameterNames = "name", behavior = PURE) public abstract class Primitive extends RBuiltinNode { + private final BranchProfile errorProfile = BranchProfile.create(); - // TODO: implement inline caching + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("name").defaultError(Message.STRING_ARGUMENT_REQUIRED).mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst(); + } + + @Specialization(guards = "name == cachedName") + protected RFunction primitiveCached(@SuppressWarnings("unused") String name, + @Cached("name") @SuppressWarnings("unused") String cachedName, + @Cached("lookup(name)") RFunction function) { + return function; + } - @Specialization + @Specialization(contains = "primitiveCached") protected RFunction primitive(String name) { + RFunction function = lookup(name); + return function; + } + + @TruffleBoundary + protected RFunction lookup(String name) { RFunction function = RContext.lookupBuiltin(name); if (function == null || function.getRBuiltin() != null && function.getRBuiltin().getKind() != RBuiltinKind.PRIMITIVE) { errorProfile.enter(); throw RError.error(this, RError.Message.NO_SUCH_PRIMITIVE, name); } - - // .Primitive function is validated return function; } - - @Fallback - protected RFunction primitive(@SuppressWarnings("unused") Object name) { - throw RError.error(this, RError.Message.STRING_ARGUMENT_REQUIRED); - } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java index 304af5f57e8333b6ea11b5a962f98d9607d0ca77..049375ae56f6834addf7f3827751016107526c6f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Scan.java @@ -12,7 +12,16 @@ package com.oracle.truffle.r.nodes.builtin.base; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.charAt0; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.constant; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.length; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lengthLte; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.lt; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean; import static com.oracle.truffle.r.runtime.builtins.RBehavior.IO; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; @@ -30,7 +39,6 @@ import com.oracle.truffle.r.nodes.unary.CastToVectorNodeGen; 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.builtins.RBehavior; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.conn.RConnection; import com.oracle.truffle.r.runtime.conn.StdConnections; @@ -45,14 +53,11 @@ import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RString; import com.oracle.truffle.r.runtime.data.RVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.ops.na.NACheck; -import com.sun.org.apache.bcel.internal.generic.INSTANCEOF; -@SuppressWarnings("unused") @RBuiltin(name = "scan", kind = INTERNAL, parameterNames = {"file", "what", "nmax", "sep", "dec", "quote", "skip", "nlines", "na.strings", "flush", "fill", "strip.white", "quiet", "blank.lines.skip", "multi.line", "comment.char", "allowEscapes", "encoding", "skipNull"}, behavior = IO) public abstract class Scan extends RBuiltinNode { @@ -74,6 +79,7 @@ public abstract class Scan extends RBuiltinNode { return ((RAbstractVector) castVector.execute(value)).materialize(); } + @SuppressWarnings("unused") private static class LocalData { RAbstractStringVector naStrings = null; boolean quiet = false; @@ -181,7 +187,6 @@ public abstract class Scan extends RBuiltinNode { // TODO: quite a few more things happen in GNU R around connections data.con = file; - Object result = RNull.instance; data.save = 0; try (RConnection openConn = data.con.forceOpen("r")) { @@ -199,14 +204,6 @@ public abstract class Scan extends RBuiltinNode { } } - private static int firstElementOrNA(RAbstractIntVector nmaxVec) { - return nmaxVec.getLength() == 0 ? RRuntime.INT_NA : nmaxVec.getDataAt(0); - } - - private static byte firstElementOrNA(RAbstractLogicalVector flushVec) { - return flushVec.getLength() == 0 ? RRuntime.LOGICAL_NA : flushVec.getDataAt(0); - } - private static int getFirstQuoteInd(String str, char sepChar) { int quoteInd = str.indexOf(sepChar); if (quoteInd >= 0) { @@ -320,7 +317,8 @@ public abstract class Scan extends RBuiltinNode { } } - private RVector scanFrame(RList what, int maxRecords, int maxLines, boolean flush, boolean fill, boolean stripWhite, boolean blSkip, boolean multiLine, LocalData data) throws IOException { + private RVector scanFrame(RList what, int maxRecords, int maxLines, boolean flush, boolean fill, @SuppressWarnings("unused") boolean stripWhite, boolean blSkip, boolean multiLine, LocalData data) + throws IOException { int nc = what.getLength(); if (nc == 0) { @@ -442,7 +440,8 @@ public abstract class Scan extends RBuiltinNode { } @TruffleBoundary - private RVector scanVector(RAbstractVector what, int maxItems, int maxLines, boolean flush, boolean stripWhite, boolean blSkip, LocalData data) throws IOException { + private RVector scanVector(RAbstractVector what, int maxItems, int maxLines, @SuppressWarnings("unused") boolean flush, @SuppressWarnings("unused") boolean stripWhite, boolean blSkip, + LocalData data) throws IOException { int blockSize = maxItems > 0 ? maxItems : SCAN_BLOCKSIZE; RVector vec = what.createEmptySameType(blockSize, RDataFactory.COMPLETE_VECTOR); naCheck.enable(true); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java index f7fe84aa1e73285af79cd08a77842cf3f4f1eb9d..6124f541a90c1eeefcf644560379ea0a185ed8ba 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java @@ -15,16 +15,21 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; +import java.util.function.BiFunction; + +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.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.CastBuilder; +import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.builtin.base.ToLowerOrUpper.StringMapNode; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; -import com.oracle.truffle.r.runtime.data.RAttributeProfiles; -import com.oracle.truffle.r.runtime.data.RDataFactory; 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.RAbstractStringVector; @@ -32,52 +37,43 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; @RBuiltin(name = "strtrim", kind = INTERNAL, parameterNames = {"x", "width"}, behavior = PURE) public abstract class Strtrim extends RBuiltinNode { - private RAttributeProfiles attrProfiles = RAttributeProfiles.create(); - @Override protected void createCasts(CastBuilder casts) { - casts.toInteger(1); + casts.arg("x").mustBe(Predef.stringValue(), Message.REQUIRES_CHAR_VECTOR, "strtrim()").asStringVector(true, true, true); + casts.arg("width").asIntegerVector(); } @Specialization - protected RStringVector srtrim(RAbstractStringVector x, RAbstractIntVector width) { + protected RStringVector srtrim(RAbstractStringVector x, RAbstractIntVector width, + @Cached("create()") StringMapNode mapNode, + @Cached("createBinaryProfile()") ConditionProfile fitsProfile) { int len = x.getLength(); int nw = width.getLength(); if (nw == 0 || nw < len && (len % nw != 0)) { + CompilerDirectives.transferToInterpreter(); throw RError.error(this, RError.Message.INVALID_ARGUMENT, "width"); } for (int i = 0; i < nw; i++) { - int widthi = width.getDataAt(i); - if (widthi == RRuntime.INT_NA || widthi < 0) { + assert RRuntime.INT_NA < 0; // check for NA folded into < 0 + if (width.getDataAt(i) < 0) { + CompilerDirectives.transferToInterpreter(); throw RError.error(this, RError.Message.INVALID_ARGUMENT, "width"); } } - String[] data = new String[len]; - boolean complete = RDataFactory.COMPLETE_VECTOR; - for (int i = 0; i < len; i++) { - String element = x.getDataAt(i); - if (RRuntime.isNA(element)) { - data[i] = element; - complete = RDataFactory.INCOMPLETE_VECTOR; - continue; - } + BiFunction<String, Integer, String> function = (element, i) -> { // TODO multibyte character handling int w = width.getDataAt(i % nw); - if (w > element.length()) { - data[i] = element; + if (fitsProfile.profile(w >= element.length())) { + return element; } else { - data[i] = element.substring(0, w); + return substring(element, w); } - } - RStringVector result = RDataFactory.createStringVector(data, complete); - result.copyAttributesFrom(attrProfiles, x); - return result; + }; + return mapNode.apply(x, function); } - @SuppressWarnings("unused") - @Fallback @TruffleBoundary - RStringVector strtrim(Object x, Object width) { - throw RError.error(this, RError.Message.REQUIRES_CHAR_VECTOR, "strtrim()"); + private static String substring(String element, int w) { + return element.substring(0, w); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java index d12bcadb18d22e87bd27a4b3046fe3b117c3aeb4..4010f36ea20ed08601c93d5b0f72456d7b58d100 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ToLowerOrUpper.java @@ -22,73 +22,122 @@ */ package com.oracle.truffle.r.nodes.builtin.base; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; +import java.util.function.BiFunction; +import java.util.function.Function; + import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.LoopConditionProfile; import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode; +import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNodeGen; +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.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; -import com.oracle.truffle.r.runtime.nodes.RNode; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; import com.oracle.truffle.r.runtime.ops.na.NACheck; -import com.oracle.truffle.r.runtime.ops.na.NAProfile; -public abstract class ToLowerOrUpper extends RBuiltinNode { +public abstract class ToLowerOrUpper { - @RBuiltin(name = "tolower", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE) - public static final class ToLower { - } + public static final class StringMapNode extends RBaseNode { - @RBuiltin(name = "toupper", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE) - public static final class ToUpper { - } + private final VectorLengthProfile lengthProfile = VectorLengthProfile.create(); + private final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile(); + private final NACheck na = NACheck.create(); + private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); - public static ToLowerOrUpper createToLower(RNode[] arguments) { - return ToLowerOrUpperNodeGen.create(true, arguments); - } + @Child private CopyOfRegAttributesNode copyAttributes = CopyOfRegAttributesNodeGen.create(); - public static ToLowerOrUpper createToUpper(RNode[] arguments) { - return ToLowerOrUpperNodeGen.create(false, arguments); - } + private StringMapNode() { + // nothing to do + } - private final boolean lower; + public static StringMapNode create() { + return new StringMapNode(); + } - public ToLowerOrUpper(boolean lower) { - this.lower = lower; - } + private String elementFunction(String value, int i, BiFunction<String, Integer, String> function) { + return na.check(value) ? RRuntime.STRING_NA : function.apply(value, i); + } + + public String apply(String value, BiFunction<String, Integer, String> function) { + na.enable(value); + return elementFunction(value, 0, function); + } - @TruffleBoundary - private String processElement(String value) { - return lower ? value.toLowerCase() : value.toUpperCase(); + public RStringVector apply(RAbstractStringVector vector, BiFunction<String, Integer, String> function) { + na.enable(vector); + int length = lengthProfile.profile(vector.getLength()); + String[] stringVector = new String[length]; + loopProfile.profileCounted(length); + for (int i = 0; loopProfile.inject(i < length); i++) { + String value = vector.getDataAt(i); + stringVector[i] = elementFunction(value, i, function); + } + RStringVector result = RDataFactory.createStringVector(stringVector, vector.isComplete(), vector.getDimensions(), vector.getNames(attrProfiles)); + copyAttributes.execute(vector, result); + return result; + } } - @Specialization - protected String toLower(String value, // - @Cached("create()") NAProfile na) { - return na.isNA(value) ? RRuntime.STRING_NA : processElement(value); + @RBuiltin(name = "tolower", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE) + public abstract static class ToLower extends RBuiltinNode { + + @Child private StringMapNode mapNode = StringMapNode.create(); + + @Override + protected void createCasts(CastBuilder casts) { + casts.arg(0, "x").mustBe(stringValue()).asStringVector(true, true, true); + } + + @TruffleBoundary + private static String processElement(String value, int i) { + return value.toLowerCase(); + } + + @Specialization + protected String toLower(String value) { + return mapNode.apply(value, ToLower::processElement); + } + + @Specialization + protected RStringVector toLower(RAbstractStringVector vector) { + return mapNode.apply(vector, ToLower::processElement); + } } - @Specialization - protected RStringVector toLower(RAbstractStringVector vector, // - @Cached("createCountingProfile()") LoopConditionProfile loopProfile, // - @Cached("create()") NACheck na, // - @Cached("create()") CopyOfRegAttributesNode copyAttributes) { - na.enable(vector); - String[] stringVector = new String[vector.getLength()]; - loopProfile.profileCounted(vector.getLength()); - for (int i = 0; loopProfile.inject(i < vector.getLength()); i++) { - String value = vector.getDataAt(i); - stringVector[i] = na.check(value) ? RRuntime.STRING_NA : processElement(value); + @RBuiltin(name = "toupper", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE) + public abstract static class ToUpper extends RBuiltinNode { + + @Child private StringMapNode mapNode = StringMapNode.create(); + + @Override + protected void createCasts(CastBuilder casts) { + casts.arg(0, "x").mustBe(stringValue()).asStringVector(true, true, true); + } + + @TruffleBoundary + private static String processElement(String value, int i) { + return value.toUpperCase(); + } + + @Specialization + protected String toLower(String value) { + return mapNode.apply(value, ToUpper::processElement); + } + + @Specialization + protected RStringVector toLower(RAbstractStringVector vector) { + return mapNode.apply(vector, ToUpper::processElement); } - RStringVector result = RDataFactory.createStringVector(stringVector, vector.isComplete(), vector.getDimensions()); - copyAttributes.execute(vector, result); - return result; } } 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 d294b653a4db4d9fc01226325f0dca790b9db417..13c44d60cfdd6e5a75207c2b9d794f8507b106a1 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 @@ -54,7 +54,7 @@ import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.builtins.RBuiltin; 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.MemoryCopyTracer; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; @@ -79,7 +79,7 @@ public class TraceFunctions { public abstract static class PrimTrace extends Helper { @Specialization - protected RNull primUnTrace(VirtualFrame frame, RAbstractStringVector funcName) { + protected RNull primTrace(VirtualFrame frame, RAbstractStringVector funcName) { return primTrace((RFunction) getFunction(frame, funcName.getDataAt(0))); } @@ -118,10 +118,12 @@ public class TraceFunctions { @Specialization @TruffleBoundary protected byte traceOnOff(byte state) { + /* TODO GnuR appears to accept ANY value as an argument */ boolean prevState = RContext.getInstance().stateInstrumentation.getTracingState(); boolean newState = RRuntime.fromLogical(state); if (newState != prevState) { RContext.getInstance().stateInstrumentation.setTracingState(newState); + MemoryCopyTracer.setTracingState(newState); } return RRuntime.asLogical(prevState); } @@ -135,7 +137,7 @@ public class TraceFunctions { public abstract static class TracememBase extends RBuiltinNode { static { - MemoryTracer.setListener(new TracememBase.TracememListener()); + MemoryCopyTracer.addListener(new TracememBase.TracememListener()); } protected static HashSet<Object> getTracedObjects() { @@ -147,8 +149,16 @@ public class TraceFunctions { } protected static void startTracing(Object x) { + /* + * There is no explicit command to enable tracing, it is implicit in the call to + * tracemem. However, it can be disabled by tracingState(F), so we can't unilaterally + * turn on tracing here. + */ getTracedObjects().add(x); - MemoryTracer.reportEvents(); + boolean tracingState = RContext.getInstance().stateInstrumentation.getTracingState(); + if (tracingState) { + MemoryCopyTracer.setTracingState(true); + } } protected static void printToStdout(String msg) { @@ -176,7 +186,7 @@ public class TraceFunctions { return result.toString(); } - private static final class TracememListener implements MemoryTracer.Listener { + private static final class TracememListener implements MemoryCopyTracer.Listener { @Override public void reportCopying(RAbstractVector src, RAbstractVector dest) { if (getTracedObjects().contains(src)) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java index c1a394c20d9e60501af8df2d9a4d7e1e24272140..e9088eeb636daa0ba882e7913ceef4134f86132b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java @@ -13,88 +13,86 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; -import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.SUBSTITUTE; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; +import java.util.function.BiFunction; +import java.util.function.Function; + +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.api.profiles.LoopConditionProfile; import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode; import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNodeGen; import com.oracle.truffle.r.nodes.attributes.InitAttributesNode; import com.oracle.truffle.r.nodes.attributes.PutAttributeNode; import com.oracle.truffle.r.nodes.attributes.PutAttributeNodeGen; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; +import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; 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.RAbstractListVector; +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.nodes.RNode; -@RBuiltin(name = "t.default", kind = SUBSTITUTE, parameterNames = {"x"}, behavior = PURE) -// TODO INTERNAL +@RBuiltin(name = "t.default", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE) public abstract class Transpose extends RBuiltinNode { private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); private final BranchProfile hasDimNamesProfile = BranchProfile.create(); private final ConditionProfile isMatrixProfile = ConditionProfile.createBinaryProfile(); + private final VectorLengthProfile lengthProfile = VectorLengthProfile.create(); + private final LoopConditionProfile loopProfile = LoopConditionProfile.createCountingProfile(); + @Child private CopyOfRegAttributesNode copyRegAttributes = CopyOfRegAttributesNodeGen.create(); @Child private InitAttributesNode initAttributes = InitAttributesNode.create(); @Child private PutAttributeNode putDimensions = PutAttributeNodeGen.createDim(); @Child private PutAttributeNode putDimNames = PutAttributeNodeGen.createDimNames(); - public abstract Object execute(Object o); - - @Specialization - protected RNull transpose(RNull value) { - return value; - } - - @Specialization - protected int transpose(int value) { - return value; - } - - @Specialization - protected double transpose(double value) { - return value; - } - - @Specialization - protected byte transpose(byte value) { - return value; - } - - @Specialization(guards = "isEmpty2D(vector)") - protected RAbstractVector transpose(RAbstractVector vector) { - int[] dim = vector.getDimensions(); - return vector.copyWithNewDimensions(new int[]{dim[1], dim[0]}); - } + public abstract Object execute(RAbstractVector o); @FunctionalInterface - private interface InnerLoop<T extends RAbstractVector> { - RVector apply(T vector, int firstDim); + private interface WriteArray<T extends RAbstractVector, A> { + void apply(A array, T vector, int i, int j); } - protected <T extends RAbstractVector> RVector transposeInternal(T vector, InnerLoop<T> innerLoop) { + protected <T extends RAbstractVector, A> RVector transposeInternal(T vector, Function<Integer, A> createArray, WriteArray<T, A> writeArray, BiFunction<A, Boolean, RVector> createResult) { + int length = lengthProfile.profile(vector.getLength()); int firstDim; int secondDim; if (isMatrixProfile.profile(vector.isMatrix())) { firstDim = vector.getDimensions()[0]; secondDim = vector.getDimensions()[1]; } else { - firstDim = vector.getLength(); + firstDim = length; secondDim = 1; } - RNode.reportWork(this, vector.getLength()); + RNode.reportWork(this, length); - RVector r = innerLoop.apply(vector, firstDim); + A array = createArray.apply(length); + int j = 0; + loopProfile.profileCounted(length); + for (int i = 0; loopProfile.inject(i < length); i++, j += firstDim) { + if (j > (length - 1)) { + j -= (length - 1); + } + writeArray.apply(array, vector, i, j); + } + RVector r = createResult.apply(array, vector.isComplete()); // copy attributes copyRegAttributes.execute(vector, r); // set new dimensions @@ -113,61 +111,47 @@ public abstract class Transpose extends RBuiltinNode { return r; } - private static RVector innerLoopInt(RAbstractIntVector vector, int firstDim) { - int[] result = new int[vector.getLength()]; - int j = 0; - for (int i = 0; i < result.length; i++, j += firstDim) { - if (j > (result.length - 1)) { - j -= (result.length - 1); - } - result[i] = vector.getDataAt(j); - } - return RDataFactory.createIntVector(result, vector.isComplete()); + @Specialization + protected RVector transpose(RAbstractIntVector x) { + return transposeInternal(x, l -> new int[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createIntVector); } - private static RVector innerLoopDouble(RAbstractDoubleVector vector, int firstDim) { - double[] result = new double[vector.getLength()]; - int j = 0; - for (int i = 0; i < result.length; i++, j += firstDim) { - if (j > (result.length - 1)) { - j -= (result.length - 1); - } - result[i] = vector.getDataAt(j); - } - return RDataFactory.createDoubleVector(result, vector.isComplete()); + @Specialization + protected RVector transpose(RAbstractLogicalVector x) { + return transposeInternal(x, l -> new byte[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createLogicalVector); } - private static RVector innerLoopString(RAbstractStringVector vector, int firstDim) { - String[] result = new String[vector.getLength()]; - int j = 0; - for (int i = 0; i < result.length; i++, j += firstDim) { - if (j > (result.length - 1)) { - j -= (result.length - 1); - } - result[i] = vector.getDataAt(j); - } - return RDataFactory.createStringVector(result, vector.isComplete()); + @Specialization + protected RVector transpose(RAbstractDoubleVector x) { + return transposeInternal(x, l -> new double[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createDoubleVector); } - @Specialization(guards = "!isEmpty2D(vector)") - protected RVector transpose(RAbstractIntVector vector) { - return transposeInternal(vector, Transpose::innerLoopInt); + @Specialization + protected RVector transpose(RAbstractComplexVector x) { + return transposeInternal(x, l -> new double[l * 2], (a, v, i, j) -> { + RComplex d = v.getDataAt(j); + a[i * 2] = d.getRealPart(); + a[i * 2 + 1] = d.getImaginaryPart(); + }, RDataFactory::createComplexVector); } - @Specialization(guards = "!isEmpty2D(vector)") - protected RVector transpose(RAbstractDoubleVector vector) { - return transposeInternal(vector, Transpose::innerLoopDouble); + @Specialization + protected RVector transpose(RAbstractStringVector x) { + return transposeInternal(x, l -> new String[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createStringVector); } - @Specialization(guards = "!isEmpty2D(vector)") - protected RVector transpose(RAbstractStringVector vector) { - return transposeInternal(vector, Transpose::innerLoopString); + @Specialization + protected RVector transpose(RAbstractListVector x) { + return transposeInternal(x, l -> new Object[l], (a, v, i, j) -> a[i] = v.getDataAt(j), (a, c) -> RDataFactory.createList(a)); } - protected static boolean isEmpty2D(RAbstractVector vector) { - if (!vector.hasDimensions()) { - return false; - } - return vector.getDimensions().length == 2 && vector.getLength() == 0; + @Specialization + protected RVector transpose(RAbstractRawVector x) { + return transposeInternal(x, l -> new byte[l], (a, v, i, j) -> a[i] = v.getRawDataAt(j), (a, c) -> RDataFactory.createRawVector(a)); + } + + @Fallback + protected RVector transpose(@SuppressWarnings("unused") Object x) { + throw RError.error(RError.SHOW_CALLER, Message.ARGUMENT_NOT_MATRIX); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java index 25207ed80eabb2649f34aff15ec6b84215f3dc85..bba597a2585760808ef85fadaae692cb3156482f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateClass.java @@ -67,7 +67,7 @@ public abstract class UpdateClass extends RBuiltinNode { private void initCastStringNode() { if (castStringNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castStringNode = insert(CastStringNodeGen.create(false, false, false, false)); + castStringNode = insert(CastStringNodeGen.create(false, false, false)); } } 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 c1949bd51d41c8ce87e9beb8f4718d69b63c677a..9b49702aa2fcc30d926f3fde4b21f6213c0cc8ba 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 @@ -61,7 +61,7 @@ public abstract class UpdateDimNames extends RBuiltinNode { private Object castString(Object o) { if (castStringNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castStringNode = insert(CastStringNodeGen.create(true, true, true, false)); + castStringNode = insert(CastStringNodeGen.create(true, true, true)); } return castStringNode.execute(o); } 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 4d92e592fb6e56ef7f5c4a7150d58add79cbb3ea..fd9b979a7964a6a0b0532c753bfff0a6e8d5c3f4 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 @@ -48,7 +48,7 @@ public abstract class UpdateNames extends RBuiltinNode { private Object castString(Object o) { if (castStringNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castStringNode = insert(CastStringNodeGen.create(false, false, false, false)); + castStringNode = insert(CastStringNodeGen.create(false, false, false)); } return castStringNode.executeString(o); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java index 963fb48e49d9bc006ffb8007ca700d4a03560932..f05261a585f42113af69f41576f5a2897eddc6df 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateOldClass.java @@ -59,7 +59,7 @@ public abstract class UpdateOldClass extends RBuiltinNode { private void initCastStringNode() { if (castStringNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castStringNode = insert(CastStringNodeGen.create(false, false, false, false)); + castStringNode = insert(CastStringNodeGen.create(false, false, false)); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java index 3d608da7397fb8e2c95b3bb9214288837354361c..b878565580cb566b94d9b2728004d11527840110 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VApply.java @@ -126,7 +126,7 @@ public abstract class VApply extends RBuiltinNode { private Object castString(Object operand, boolean preserveAllAttr) { if (castString == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castString = insert(CastStringNodeGen.create(true, preserveAllAttr, preserveAllAttr, false)); + castString = insert(CastStringNodeGen.create(true, preserveAllAttr, preserveAllAttr)); } return castString.execute(operand); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java index 249cee47c1bb624b7831a854d95cf177a698e389..6ee52996d3b615a84c3bc978430ab84f9962f23d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Warning.java @@ -47,7 +47,7 @@ public abstract class Warning extends RBuiltinNode { private Object castString(Object operand) { if (castString == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castString = insert(CastStringNodeGen.create(false, false, false, false)); + castString = insert(CastStringNodeGen.create(false, false, false)); } return castString.execute(operand); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java index ffa0cc5c29b71e409b06dadc9080542cfd02c7cb..17662ce966d830026fbd35be2cfbb5ba69a8f6b2 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WhichFunctions.java @@ -22,23 +22,28 @@ */ package com.oracle.truffle.r.nodes.builtin.base; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; -import java.util.ArrayList; - -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.ConditionProfile; +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.builtin.base.WhichFunctionsFactory.WhichMinMaxNodeGen; +import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RIntVector; +import com.oracle.truffle.r.runtime.data.RNull; 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.RAbstractLogicalVector; +import com.oracle.truffle.r.runtime.nodes.RNode; import com.oracle.truffle.r.runtime.ops.na.NACheck; /** @@ -49,94 +54,125 @@ public class WhichFunctions { @RBuiltin(name = "which", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE) public abstract static class Which extends RBuiltinNode { - private final NACheck naCheck = NACheck.create(); - private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("x").mustBe(logicalValue()).asLogicalVector(); + } - @Specialization(guards = "!hasNames(x)") - @TruffleBoundary - protected RIntVector which(RAbstractLogicalVector x) { - ArrayList<Integer> w = new ArrayList<>(); - for (int i = 0; i < x.getLength(); i++) { + @Specialization + protected RIntVector which(RAbstractLogicalVector x, + @Cached("create()") VectorLengthProfile lengthProfile, + @Cached("createCountingProfile()") LoopConditionProfile loopProfile, + @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile, + @Cached("create()") RAttributeProfiles attrProfiles, + @Cached("create()") NACheck naCheck) { + int length = lengthProfile.profile(x.getLength()); + loopProfile.profileCounted(length); + // determine the length of the result + int resultLength = 0; + for (int i = 0; loopProfile.inject(i < length); i++) { if (x.getDataAt(i) == RRuntime.LOGICAL_TRUE) { - w.add(i); + resultLength++; } } - int[] result = new int[w.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = w.get(i) + 1; - } - return RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR); - } - - @Specialization(guards = "hasNames(x)") - @TruffleBoundary - protected RIntVector whichNames(RAbstractLogicalVector x) { - ArrayList<Integer> w = new ArrayList<>(); - ArrayList<String> n = new ArrayList<>(); - RStringVector oldNames = x.getNames(attrProfiles); - naCheck.enable(oldNames); - for (int i = 0; i < x.getLength(); i++) { + // collect result indexes + int[] result = new int[resultLength]; + int pos = 0; + for (int i = 0; loopProfile.inject(i < length); i++) { if (x.getDataAt(i) == RRuntime.LOGICAL_TRUE) { - w.add(i); - String s = oldNames.getDataAt(i); - naCheck.check(s); - n.add(s); + result[pos++] = i + 1; } } - int[] result = new int[w.size()]; - for (int i = 0; i < result.length; i++) { - result[i] = w.get(i) + 1; + RStringVector names = x.getNames(attrProfiles); + if (hasNamesProfile.profile(names != null)) { + // collect result names + String[] resultNames = new String[resultLength]; + naCheck.enable(names); + pos = 0; + for (int i = 0; i < x.getLength(); i++) { + if (x.getDataAt(i) == RRuntime.LOGICAL_TRUE) { + String name = names.getDataAt(i); + naCheck.check(name); + resultNames[pos++] = name; + } + } + return RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR, RDataFactory.createStringVector(resultNames, naCheck.neverSeenNA())); + } else { + return RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR); } - String[] names = new String[n.size()]; - return RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR, RDataFactory.createStringVector(n.toArray(names), naCheck.neverSeenNA())); - } - - protected boolean hasNames(RAbstractLogicalVector x) { - return x.getNames(attrProfiles) != null; } } @RBuiltin(name = "which.max", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE) - public abstract static class WhichMax extends RBuiltinNode { - - @Override - protected void createCasts(CastBuilder casts) { - casts.toDouble(0); + public abstract static class WhichMax { + private WhichMax() { + // private } - @Specialization - protected int which(RAbstractDoubleVector x) { - double max = x.getDataAt(0); - int maxIndex = 0; - for (int i = 0; i < x.getLength(); i++) { - if (x.getDataAt(i) > max) { - max = x.getDataAt(i); - maxIndex = i; - } - } - return maxIndex + 1; + public static WhichMinMax create(RNode[] arguments) { + return WhichMinMaxNodeGen.create(true, arguments); } } @RBuiltin(name = "which.min", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE) - public abstract static class WhichMin extends RBuiltinNode { + public abstract static class WhichMin { + private WhichMin() { + // private + } + + public static WhichMinMax create(RNode[] arguments) { + return WhichMinMaxNodeGen.create(false, arguments); + } + } + + public abstract static class WhichMinMax extends RBuiltinNode { + + private final boolean isMax; + + protected WhichMinMax(boolean isMax) { + this.isMax = isMax; + } @Override protected void createCasts(CastBuilder casts) { - casts.toDouble(0); + casts.arg(0, "x").asDoubleVector(true, false, false); } @Specialization - protected int which(RAbstractDoubleVector x) { - double minimum = x.getDataAt(0); - int minIndex = 0; - for (int i = 0; i < x.getLength(); i++) { - if (x.getDataAt(i) < minimum) { - minimum = x.getDataAt(i); - minIndex = i; + protected RIntVector which(RAbstractDoubleVector x, + @Cached("create()") VectorLengthProfile lengthProfile, + @Cached("createCountingProfile()") LoopConditionProfile loopProfile, + @Cached("createBinaryProfile()") ConditionProfile isNaNProfile, + @Cached("createBinaryProfile()") ConditionProfile hasNamesProfile, + @Cached("create()") RAttributeProfiles attrProfiles) { + int length = lengthProfile.profile(x.getLength()); + loopProfile.profileCounted(length); + double extreme = Double.NaN; + int extremeIndex = -1; + for (int i = 0; loopProfile.inject(i < length); i++) { + double d = x.getDataAt(i); + // inverted comparison to pass when extreme is NaN + if (!Double.isNaN(d) && (isMax ? !(d <= extreme) : !(d >= extreme))) { + extreme = x.getDataAt(i); + extremeIndex = i; } } - return minIndex + 1; + if (isNaNProfile.profile(extremeIndex == -1)) { + return RDataFactory.createEmptyIntVector(); + } + RStringVector names = x.getNames(attrProfiles); + if (hasNamesProfile.profile(names != null)) { + // collect result names + RStringVector resultNames = RDataFactory.createStringVectorFromScalar(names.getDataAt(extremeIndex)); + return RDataFactory.createIntVector(new int[]{extremeIndex + 1}, true, resultNames); + } else { + return RDataFactory.createIntVectorFromScalar(extremeIndex + 1); + } + } + + @Specialization + protected RIntVector which(@SuppressWarnings("unused") RNull x) { + return RDataFactory.createEmptyIntVector(); } } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java index 582337c61d1c2c1eff10889bcbff2597c3761af0..624b0baa010ced6e4ec76b6d3e99758a2bff94c1 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java @@ -66,6 +66,7 @@ import com.oracle.truffle.r.library.utils.Download; import com.oracle.truffle.r.library.utils.MenuNodeGen; import com.oracle.truffle.r.library.utils.ObjectSizeNodeGen; import com.oracle.truffle.r.library.utils.RprofNodeGen; +import com.oracle.truffle.r.library.utils.RprofmemNodeGen; import com.oracle.truffle.r.library.utils.TypeConvertNodeGen; import com.oracle.truffle.r.library.utils.WriteTable; import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; @@ -576,8 +577,9 @@ public class ForeignFunctions { return getExternalModelBuiltinNode("termsform"); case "Rprof": return RprofNodeGen.create(); - case "unzip": case "Rprofmem": + return RprofmemNodeGen.create(); + case "unzip": case "addhistory": case "loadhistory": case "savehistory": diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java index 457b1c404ba589315ba895b2bb3173381b463041..b75899478f34a0c3723eae0c6498afa13336a72e 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java @@ -157,9 +157,9 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { /* * F Format: use "F" format WHENEVER we use not more space than 'E' and still satisfy * 'R_print.digits' {but as if nsmall==0 !} - * + * * E Format has the form [S]X[.XXX]E+XX[X] - * + * * This is indicated by setting *e to non-zero (usually 1) If the additional exponent digit * is required *e is set to 2 */ @@ -247,7 +247,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { * for a number x , determine sgn = 1_{x < 0} {0/1} kpower = Exponent of 10; nsig = * min(R_print.digits, #{significant digits of alpha}) roundingwidens = 1 if rounding causes * x to increase in width, 0 otherwise - * + * * where |x| = alpha * 10^kpower and 1 <= alpha < 10 */ double alpha; @@ -382,8 +382,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { buff = snprintf(NB, fmt, x); } } else { /* e = 0 */ - StringBuilder sb = new StringBuilder("#.#"); - DecimalFormat df = new DecimalFormat(sb.toString()); + DecimalFormat df = new DecimalFormat("#.#"); df.setRoundingMode(RoundingMode.HALF_EVEN); df.setDecimalSeparatorAlwaysShown(false); df.setMinimumFractionDigits(d); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java index 81a02f918888202c7f9cbc30d4b5758a129e9664..ae7d75ffc1eff9aaa109ff114b61611e4fff620b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRContext.java @@ -181,23 +181,30 @@ public class FastRContext { @TruffleBoundary protected Object eval(RAbstractStringVector exprs, int pc, String kind, RAbstractStringVector args) { RContext.ContextKind contextKind = RContext.ContextKind.valueOf(kind); + Object[] results = new Object[pc]; - // separate threads that run in parallel; invoking thread waits for completion - RContext.EvalThread[] threads = new RContext.EvalThread[pc]; - for (int i = 0; i < pc; i++) { + if (pc == 1) { ContextInfo info = createContextInfo(contextKind, args); - threads[i] = new RContext.EvalThread(info, RSource.fromTextInternal(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL)); - } - for (int i = 0; i < pc; i++) { - threads[i].start(); - } - try { + PolyglotEngine vm = info.createVM(); + results[0] = RContext.EvalThread.run(vm, info, RSource.fromTextInternal(exprs.getDataAt(0), RSource.Internal.CONTEXT_EVAL)); + } else { + // separate threads that run in parallel; invoking thread waits for completion + RContext.EvalThread[] threads = new RContext.EvalThread[pc]; for (int i = 0; i < pc; i++) { - threads[i].join(); - results[i] = threads[i].getEvalResult(); + ContextInfo info = createContextInfo(contextKind, args); + threads[i] = new RContext.EvalThread(info, RSource.fromTextInternal(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL)); + } + for (int i = 0; i < pc; i++) { + threads[i].start(); + } + try { + for (int i = 0; i < pc; i++) { + threads[i].join(); + results[i] = threads[i].getEvalResult(); + } + } catch (InterruptedException ex) { + throw RError.error(this, RError.Message.GENERIC, "error finishing eval thread"); } - } catch (InterruptedException ex) { - throw RError.error(this, RError.Message.GENERIC, "error finishing eval thread"); } return RDataFactory.createList(results); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java index 1dda3508749ac98bfd666025679dccd78199226e..550f3efb3191bf745599764bd3fc6b9f598b0d80 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java @@ -22,6 +22,8 @@ */ package com.oracle.truffle.r.nodes.builtin.fastr; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; import static com.oracle.truffle.r.runtime.RVisibility.OFF; import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; @@ -33,6 +35,7 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; @@ -41,10 +44,10 @@ import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; -import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSource; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RTypedValue; @@ -55,8 +58,8 @@ public class FastRInterop { @Override protected void createCasts(CastBuilder casts) { - casts.firstStringWithError(0, Message.INVALID_ARGUMENT, "mimeType"); - casts.firstStringWithError(1, Message.INVALID_ARGUMENT, "source"); + casts.arg("mimeType").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst(); + casts.arg("source").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst(); } protected CallTarget parse(String mimeType, String source) { @@ -77,9 +80,9 @@ public class FastRInterop { @SuppressWarnings("unused") @Specialization(guards = {"cachedMimeType != null", "cachedMimeType.equals(mimeType)", "cachedSource != null", "cachedSource.equals(source)"}) - protected Object evalCached(VirtualFrame frame, String mimeType, String source, // - @Cached("mimeType") String cachedMimeType, // - @Cached("source") String cachedSource, // + protected Object evalCached(VirtualFrame frame, String mimeType, String source, + @Cached("mimeType") String cachedMimeType, + @Cached("source") String cachedSource, @Cached("createCall(mimeType, source)") DirectCallNode call) { return call.call(frame, EMPTY_OBJECT_ARRAY); } @@ -98,31 +101,49 @@ public class FastRInterop { @RBuiltin(name = ".fastr.interop.export", visibility = OFF, kind = PRIMITIVE, parameterNames = {"name", "value"}, behavior = COMPLEX) public abstract static class Export extends RBuiltinNode { - @Specialization + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("name").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst(); + casts.boxPrimitive(1); + } + + @Specialization(guards = "!isRMissing(value)") @TruffleBoundary - protected Object exportSymbol(Object name, RTypedValue value) { - String stringName = RRuntime.asString(name); - if (stringName == null) { + protected Object exportSymbol(String name, RTypedValue value) { + if (name == null) { throw RError.error(this, RError.Message.INVALID_ARG_TYPE, "name"); } - RContext.getInstance().getExportedSymbols().put(stringName, value); + RContext.getInstance().getExportedSymbols().put(name, value); return RNull.instance; } + + @Specialization + @TruffleBoundary + protected Object exportSymbol(@SuppressWarnings("unused") String name, @SuppressWarnings("unused") RMissing value) { + throw RError.error(this, Message.ARGUMENT_MISSING, "value"); + } + + @Fallback + @TruffleBoundary + protected Object exportSymbol(@SuppressWarnings("unused") Object name, @SuppressWarnings("unused") Object value) { + throw RError.error(this, Message.GENERIC, "only R language objects can be exported"); + } } @RBuiltin(name = ".fastr.interop.import", visibility = OFF, kind = PRIMITIVE, parameterNames = {"name"}, behavior = COMPLEX) public abstract static class Import extends RBuiltinNode { + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("name").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst(); + } + @Specialization @TruffleBoundary - protected Object importSymbol(Object name) { - String stringName = RRuntime.asString(name); - if (stringName == null) { - throw RError.error(this, RError.Message.INVALID_ARG_TYPE, "name"); - } - Object object = RContext.getInstance().getEnv().importSymbol(stringName); + protected Object importSymbol(String name) { + Object object = RContext.getInstance().getEnv().importSymbol(name); if (object == null) { - throw RError.error(this, RError.Message.NO_IMPORT_OBJECT, stringName); + throw RError.error(this, RError.Message.NO_IMPORT_OBJECT, name); } return object; } diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java index a7835b6c048720307b08440201cdf3df53c1bcc9..681a49131af2005f5d4f01561a6c8388dd4fad56 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/CastBuilderTest.java @@ -22,14 +22,14 @@ */ package com.oracle.truffle.r.nodes.builtin; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.elementAt; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asStringVector; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asLogicalVector; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asStringVector; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.chain; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.complexValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.constant; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.defaultValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.elementAt; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.equalTo; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.findFirst; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte; @@ -69,8 +69,6 @@ import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNodeGen; import com.oracle.truffle.r.nodes.builtin.ArgumentFilter.ArgumentTypeFilter; import com.oracle.truffle.r.nodes.builtin.ArgumentFilter.ArgumentValueFilter; import com.oracle.truffle.r.nodes.builtin.CastBuilder.InitialPhaseBuilder; -import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; -import com.oracle.truffle.r.nodes.builtin.base.IsNA; import com.oracle.truffle.r.nodes.casts.ArgumentFilterSampler; import com.oracle.truffle.r.nodes.casts.CastNodeSampler; import com.oracle.truffle.r.nodes.casts.PredefFiltersSamplers; @@ -85,7 +83,6 @@ import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RIntVector; import com.oracle.truffle.r.runtime.data.RInteger; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RLogical; @@ -634,7 +631,7 @@ public class CastBuilderTest { } } - private String argType(Object arg) { + private static String argType(Object arg) { return arg.getClass().getSimpleName(); } diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastNodeSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastNodeSampler.java index f90d1ec73c701252e434c56b4e9a4e3e4b6703dd..0e64e2c2cd775661cf03bad5498dce8dcaecad4a 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastNodeSampler.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastNodeSampler.java @@ -23,11 +23,6 @@ package com.oracle.truffle.r.nodes.casts; import java.lang.reflect.Constructor; -import java.lang.reflect.Type; -import java.util.Collections; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; import com.oracle.truffle.r.nodes.unary.CastNode; diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastUtils.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastUtils.java index 9981b36e9248af9aa982861c06f101a588f6aef0..a59861970ff7893d9ee0e84082e813a27e9d793f 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastUtils.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/CastUtils.java @@ -52,8 +52,6 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -import sun.java2d.xr.XRCompositeManager; - public class CastUtils { public static final class Cast { diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TestCasts.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TestCasts.java index 05d7c3b1e78cd10130300c569de72aa7be04bf51..494f5e2116c721d4c45615faa7f51a370d209f15 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TestCasts.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/TestCasts.java @@ -45,9 +45,6 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.scalarLogica import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; -import java.io.IOException; -import java.io.OutputStream; - import org.junit.Test; import com.oracle.truffle.api.CompilerAsserts; diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ValuePredicateArgumentFilterSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ValuePredicateArgumentFilterSampler.java index cf17d773155e154ea3d74f9b6bee05caf07661b0..1b29123007f6ee8a4fc2d0ddef798fc84de3efdc 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ValuePredicateArgumentFilterSampler.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ValuePredicateArgumentFilterSampler.java @@ -30,7 +30,6 @@ import java.util.stream.Collectors; import com.oracle.truffle.r.nodes.builtin.ValuePredicateArgumentFilter; import com.oracle.truffle.r.nodes.casts.ArgumentFilterSampler.ArgumentValueFilterSampler; -import com.sun.source.doctree.AttributeTree.ValueKind; public class ValuePredicateArgumentFilterSampler<T> extends ValuePredicateArgumentFilter<T> implements ArgumentValueFilterSampler<T> { diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/VectorPredicateArgumentFilterSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/VectorPredicateArgumentFilterSampler.java index 33f3ebe0ea4419c7efe1973399f1bead927710af..92f4853c4918c6be5ecaa85499177ff6292459b1 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/VectorPredicateArgumentFilterSampler.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/VectorPredicateArgumentFilterSampler.java @@ -28,7 +28,6 @@ import java.util.List; import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.Stream; import com.oracle.truffle.r.nodes.builtin.VectorPredicateArgumentFilter; import com.oracle.truffle.r.nodes.casts.ArgumentFilterSampler.ArgumentValueFilterSampler; diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FilterNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FilterNodeGenSampler.java index 047ced6cff65c7bf52f15672ccd52189a42737da..bfdbdd71f798d6f2b8c4530c5911014aee10cfc5 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FilterNodeGenSampler.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FilterNodeGenSampler.java @@ -24,7 +24,6 @@ package com.oracle.truffle.r.nodes.unary; import com.oracle.truffle.r.nodes.casts.ArgumentFilterSampler; import com.oracle.truffle.r.nodes.casts.CastNodeSampler; -import com.oracle.truffle.r.nodes.casts.CastUtils; import com.oracle.truffle.r.nodes.casts.Samples; import com.oracle.truffle.r.nodes.casts.TypeExpr; diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java index 3fa48e1f4a8e503607ae54d9135563aa65e32f56..0b92ad8b7dcc6f93b0e971727b1b71ea6bad8ebb 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/FindFirstNodeGenSampler.java @@ -24,9 +24,7 @@ package com.oracle.truffle.r.nodes.unary; import java.lang.reflect.Type; import java.util.HashSet; -import java.util.Optional; import java.util.Set; -import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -36,7 +34,6 @@ import com.oracle.truffle.r.nodes.casts.Samples; import com.oracle.truffle.r.nodes.casts.TypeExpr; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; public class FindFirstNodeGenSampler extends CastNodeSampler<FindFirstNodeGen> { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java index 46ab6dc79f9f12af5c770c05d4dd1f2f2a07cfe9..1441a1741586f7b8c1495521281adfb2dabccba5 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java @@ -102,7 +102,7 @@ public class ReadVariadicComponentNode extends RSourceSectionNode implements RSy @Override public String getIdentifier() { - return getPrintForm(); + return getPrintForm().intern(); } @Override diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java index 6d813c4a45aa5e8d837aa4b520e374ca167f0980..245067ec8469059f34357adc436ef56abbfef8a0 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java @@ -70,7 +70,7 @@ public abstract class CastTypeNode extends BinaryNode { public static CastNode createCast(RType type, boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { switch (type) { case Character: - return CastStringNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, false); + return CastStringNodeGen.create(preserveNames, preserveDimensions, preserveAttributes); case Complex: return CastComplexNodeGen.create(preserveNames, preserveDimensions, preserveAttributes); case Double: 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 5816dfbcff6f1139789451fa644d7f4a5ac59797..564660b681f2661cfb9902918ce9f6fd945b3422 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 @@ -131,7 +131,11 @@ public final class CastBuilder { } public CastBuilder toCharacter(int index) { - return insert(index, CastStringNodeGen.create(false, false, false, false)); + return insert(index, CastStringNodeGen.create(false, false, false)); + } + + public CastBuilder toCharacter(int index, boolean preserveNames, boolean dimensionsPreservation, boolean attrPreservation) { + return insert(index, CastStringNodeGen.create(preserveNames, dimensionsPreservation, attrPreservation)); } public CastBuilder toComplex(int index) { @@ -710,7 +714,7 @@ public final class CastBuilder { } public static <T> Function<ArgCastBuilder<T, ?>, CastNode> asStringVector() { - return phaseBuilder -> CastStringNodeGen.create(false, false, false, false); + return phaseBuilder -> CastStringNodeGen.create(false, false, false); } public static <T> Function<ArgCastBuilder<T, ?>, CastNode> asComplexVector() { @@ -722,7 +726,7 @@ public final class CastBuilder { } public static <T> Function<ArgCastBuilder<T, ?>, CastNode> asStringVector(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { - return phaseBuilder -> CastStringNodeGen.create(preserveNames, preserveDimensions, preserveAttributes, false); + return phaseBuilder -> CastStringNodeGen.create(preserveNames, preserveDimensions, preserveAttributes); } public static <T> Function<ArgCastBuilder<T, ?>, CastNode> asLogical() { @@ -1388,6 +1392,11 @@ public final class CastBuilder { return state().factory.newCoercedPhaseBuilder(this, Byte.class); } + default CoercedPhaseBuilder<RAbstractStringVector, String> asStringVector(boolean preserveNames, boolean dimensionsPreservation, boolean attrPreservation) { + state().castBuilder().toCharacter(state().index(), preserveNames, dimensionsPreservation, attrPreservation); + return state().factory.newCoercedPhaseBuilder(this, String.class); + } + default CoercedPhaseBuilder<RAbstractStringVector, String> asStringVector() { state().castBuilder().toCharacter(state().index()); return state().factory.newCoercedPhaseBuilder(this, String.class); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java index 2c468c42b1bbd4b6c25dfb88ff3952db68b03e5c..cf65a15c602e85f5eccf5e005c31402e5c68ff30 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/helpers/RFactorNodes.java @@ -101,7 +101,7 @@ public final class RFactorNodes { } else { if (castString == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - castString = insert(CastStringNodeGen.create(false, false, false, false)); + castString = insert(CastStringNodeGen.create(false, false, false)); } RStringVector slevels = (RStringVector) castString.executeString(vec); return RDataFactory.createStringVector(slevels.getDataWithoutCopying(), RDataFactory.COMPLETE_VECTOR); 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 ec36ae7b6365f9ec9d374abef3e71a26db3c0132..d416956e4a2689e6f5f1098a9b7a4de604697d56 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 @@ -30,19 +30,11 @@ import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; public abstract class CastStringNode extends CastStringBaseNode { - private final boolean convertEmptyVectorToNull; - - protected CastStringNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes, boolean convertEmptyVectorToNull) { + protected CastStringNode(boolean preserveNames, boolean preserveDimensions, boolean preserveAttributes) { super(preserveNames, preserveDimensions, preserveAttributes); - this.convertEmptyVectorToNull = convertEmptyVectorToNull; - } - - public boolean convertEmptyVectorToNull() { - return convertEmptyVectorToNull; } public abstract Object executeString(int o); @@ -58,11 +50,6 @@ public abstract class CastStringNode extends CastStringBaseNode { return RNull.instance; } - @Specialization(guards = "vector.getLength() == 0") - protected Object doEmptyVector(@SuppressWarnings("unused") RAbstractVector vector) { - return convertEmptyVectorToNull ? RNull.instance : RDataFactory.createStringVector(0); - } - private RStringVector vectorCopy(RAbstractContainer operand, String[] data) { RStringVector ret = RDataFactory.createStringVector(data, operand.isComplete(), getPreservedDimensions(operand), getPreservedNames(operand)); preserveDimensionNames(operand, ret); @@ -72,7 +59,7 @@ public abstract class CastStringNode extends CastStringBaseNode { return ret; } - @Specialization(guards = "vector.getLength() != 0") + @Specialization protected RStringVector doStringVector(RStringVector vector) { if (preserveAttributes() && preserveDimensions() && preserveNames()) { return vector; @@ -81,7 +68,7 @@ public abstract class CastStringNode extends CastStringBaseNode { } } - @Specialization(guards = "operand.getLength() != 0") + @Specialization protected RStringVector doIntVector(RAbstractContainer operand) { String[] sdata = new String[operand.getLength()]; // conversions to character will not introduce new NAs @@ -102,10 +89,10 @@ public abstract class CastStringNode extends CastStringBaseNode { } public static CastStringNode create() { - return CastStringNodeGen.create(true, true, true, false); + return CastStringNodeGen.create(true, true, true); } public static CastStringNode createNonPreserving() { - return CastStringNodeGen.create(false, false, false, false); + return CastStringNodeGen.create(false, false, false); } } 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 d644738e48811feaa3e60840a01274d4506c88bf..a44b8ff62a92abd152f40e7db3f18345c91508fa 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 @@ -23,8 +23,6 @@ package com.oracle.truffle.r.runtime.ffi.jnr; import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; import java.util.function.Function; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -35,17 +33,16 @@ import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RCleanUp; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.REnvVars; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RErrorHandling; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.RSrcref; import com.oracle.truffle.r.runtime.RSource; +import com.oracle.truffle.r.runtime.RSrcref; +import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; -import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE; import com.oracle.truffle.r.runtime.context.Engine.ParseException; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RAttributable; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java index 8733ab397016e835599532c18d617f86ab877e7b..486c4b98687d8b2f54e026a3d432d2ecdb9cd7c0 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java @@ -169,6 +169,18 @@ public final class Utils { throw new ExitException(2); } + /** + * This the real, final, non-overrideable, exit of the entire R system. TODO well, modulo how + * quit() is interpreted when R is started implicitly from a Polyglot shell that is running + * other languages. + * + * @param status + */ + public static void systemExit(int status) { + RPerfStats.report(); + System.exit(status); + } + private static String userHome; private static String userHome() { 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 c21d8b5555efa5960fd7a0b924d696a7a711cad9..bbc30f71a915fe474e2bb4cb8d801c723a2aeb89 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 @@ -199,35 +199,44 @@ public final class RContext extends ExecutionContext implements TruffleObject { throw new RInternalError(e1, "error while initializing eval thread"); } try { - try { - PolyglotEngine.Value resultValue = vm.eval(source); - evalResult = createEvalResult(resultValue); - } catch (ParseException e) { - e.report(info.getConsoleHandler()); - evalResult = createErrorResult(e.getMessage()); - } catch (IOException e) { - Throwable cause = e.getCause(); - if (cause instanceof ExitException) { - // termination, treat this as "success" - ExitException exitException = (ExitException) cause; - evalResult = RDataFactory.createList(new Object[]{exitException.getStatus()}); - } else { - // some internal error - RInternalError.reportErrorAndConsoleLog(cause, info.getConsoleHandler(), info.getId()); - evalResult = createErrorResult(cause.getClass().getSimpleName()); - } - } + evalResult = run(vm, info, source); } finally { vm.dispose(); threads.remove(info.getId()); } } + /** + * Convenience method for {@code .fastr.context.eval} in same thread. + */ + public static RList run(PolyglotEngine vm, ContextInfo info, Source source) { + RList evalResult; + try { + PolyglotEngine.Value resultValue = vm.eval(source); + evalResult = createEvalResult(resultValue); + } catch (ParseException e) { + e.report(info.getConsoleHandler()); + evalResult = createErrorResult(e.getMessage()); + } catch (IOException e) { + Throwable cause = e.getCause(); + if (cause instanceof ExitException) { + // termination, treat this as "success" + ExitException exitException = (ExitException) cause; + evalResult = RDataFactory.createList(new Object[]{exitException.getStatus()}); + } else { + // some internal error + RInternalError.reportErrorAndConsoleLog(cause, info.getConsoleHandler(), info.getId()); + evalResult = createErrorResult(cause.getClass().getSimpleName()); + } + } + return evalResult; + } + /** * The result is an {@link RList} contain the value, plus an "error" attribute if the * evaluation resulted in an error. */ - public static RList createEvalResult(PolyglotEngine.Value resultValue) throws IOException { + private static RList createEvalResult(PolyglotEngine.Value resultValue) throws IOException { Object result = resultValue.get(); Object listResult = result; String error = null; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/AgentObjectSizeFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/AgentObjectSizeFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..7e303054edb4f818d2153f011bac4e37a0baebff --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/AgentObjectSizeFactory.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2016, 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 java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.management.ManagementFactory; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +import javax.tools.ToolProvider; + +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.data.RObjectSize.IgnoreObjectHandler; +import com.oracle.truffle.r.runtime.data.RObjectSize.TypeCustomizer; + +/** + * Uses an instrumentation agent to get an accurate estimate of an objects size, plus reflection to + * aggregate the size of object-valued fields. Sharing is not handled in the general case, although + * some special cases are handed, such as the fact that {@link RNull} is a singleton. + * + * In order to satisfy the requirements of the Java instrumentation API, we have to load the agent + * from a jar file. The creation and loading is all orchestrated by this class. + */ +public class AgentObjectSizeFactory extends ObjectSizeFactory { + + private Map<Class<?>, ArrayList<Field>> objectFieldsMap = new HashMap<>(); + private static Map<Class<?>, TypeCustomizer> customizerMap = new HashMap<>(); // system wide + + public AgentObjectSizeFactory() { + if (!ObjSizeAgent.isInitialized()) { + try { + createAgentJar(); + } catch (Exception ex) { + // not available + Utils.rSuicide("failed to load ObjSizeAgent: " + ex.getMessage()); + } + } + } + + /** + * Adds the class file bytes for a given class to a JAR stream. + */ + static void add(JarOutputStream jar, Class<?> c) throws IOException { + String name = c.getName(); + String classAsPath = name.replace('.', '/') + ".class"; + jar.putNextEntry(new JarEntry(classAsPath)); + + InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath); + + int nRead; + byte[] buf = new byte[1024]; + while ((nRead = stream.read(buf, 0, buf.length)) != -1) { + jar.write(buf, 0, nRead); + } + + jar.closeEntry(); + } + + protected void createAgentJar() throws Exception { + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + Attributes mainAttrs = manifest.getMainAttributes(); + mainAttrs.putValue("Agent-Class", ObjSizeAgent.class.getName()); + mainAttrs.putValue("Premain-Class", ObjSizeAgent.class.getName()); + + Path jar = Files.createTempFile("myagent", ".jar"); + try { + JarOutputStream jarStream = new JarOutputStream(new FileOutputStream(jar.toFile()), manifest); + add(jarStream, ObjSizeAgent.class); + jarStream.close(); + + loadAgent(jar); + } finally { + Files.deleteIfExists(jar); + } + } + + public static void loadAgent(Path agent) throws Exception { + String vmName = ManagementFactory.getRuntimeMXBean().getName(); + int p = vmName.indexOf('@'); + String pid = vmName.substring(0, p); + ClassLoader cl = ToolProvider.getSystemToolClassLoader(); + Class<?> c = Class.forName("com.sun.tools.attach.VirtualMachine", true, cl); + Method attach = c.getDeclaredMethod("attach", String.class); + Method loadAgent = c.getDeclaredMethod("loadAgent", String.class, String.class); + Object vm = attach.invoke(null, pid); + loadAgent.invoke(vm, agent.toString(), ""); + } + + @Override + public long getObjectSize(Object obj, IgnoreObjectHandler ignoreObjectHandler) { + return getObjectSize(obj, obj, ignoreObjectHandler); + } + + private long getObjectSize(Object rootObj, Object obj, IgnoreObjectHandler ignoreObjectHandler) { + try { + long basicSize = ObjSizeAgent.objectSize(obj); + long size = basicSize; + Class<?> klass = obj.getClass(); + if (klass.isArray() && !klass.getComponentType().isPrimitive()) { + for (int i = 0; i < Array.getLength(obj); i++) { + Object elem = Array.get(obj, i); + if (elem == null || isNa(elem)) { + continue; + } else { + size += getObjectSize(rootObj, elem, ignoreObjectHandler); + } + } + } else { + ArrayList<Field> objectFields = objectFieldsMap.get(klass); + if (objectFields == null) { + objectFields = new ArrayList<>(); + findObjectFields(obj.getClass(), objectFields); + objectFieldsMap.put(klass, objectFields); + } + for (Field objectField : objectFields) { + Object fieldObj = objectField.get(obj); + if (fieldObj == null || ignoreObjectHandler.ignore(rootObj, fieldObj)) { + continue; + } else { + TypeCustomizer typeCustomizer = getCustomizer(fieldObj.getClass()); + if (typeCustomizer == null) { + size += getObjectSize(rootObj, fieldObj, ignoreObjectHandler); + } else { + size += typeCustomizer.getObjectSize(fieldObj); + } + } + } + } + return size; + } catch (Throwable t) { + throw RInternalError.shouldNotReachHere(t); + } + + } + + private static boolean isNa(Object elem) { + String typeName = elem.getClass().getSimpleName(); + switch (typeName) { + case "Integer": + return RRuntime.isNA((int) elem); + case "Double": + return RRuntime.isNA((double) elem); + case "String": + return RRuntime.isNA((String) elem); + default: + return false; + } + } + + /** + * Walks the superclass hierarchy of {@code klass} and accumulates all object-valued fields in + * {@code objectFields}. + */ + private static void findObjectFields(Class<?> klass, ArrayList<Field> objectFields) { + if (klass != Object.class) { + findObjectFields(klass.getSuperclass(), objectFields); + Field[] fields = klass.getDeclaredFields(); + for (Field field : fields) { + Class<?> fieldClass = field.getType(); + if (fieldClass.isPrimitive()) { + continue; + } + int modifiers = field.getModifiers(); + if (Modifier.isStatic(modifiers)) { + continue; + } + // check for special case of an completely ignored type + if (getCustomizer(fieldClass) == RObjectSize.IGNORE) { + continue; + } + field.setAccessible(true); + objectFields.add(field); + } + } + } + + private static TypeCustomizer getCustomizer(Class<?> objClass) { + for (Map.Entry<Class<?>, TypeCustomizer> entry : customizerMap.entrySet()) { + if (entry.getKey().isAssignableFrom(objClass)) { + return entry.getValue(); + } + } + return null; + + } + + @Override + public void registerTypeCustomizer(Class<?> klass, TypeCustomizer typeCustomizer) { + customizerMap.put(klass, typeCustomizer); + } + +} 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/MemoryCopyTracer.java similarity index 56% rename from com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryTracer.java rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/MemoryCopyTracer.java index 05b5db6c2ab0659d63d734052b21dd3216ae1553..f6e7cabae776ea3598ae3034f6ee4da2ee799ca1 100644 --- 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/MemoryCopyTracer.java @@ -23,48 +23,56 @@ 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 java.util.Deque; +import java.util.concurrent.ConcurrentLinkedDeque; + +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.utilities.CyclicAssumption; 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. + * Helper for tracing memory copying events, as used by the {@code tracemem} bultin. All + * implementors of {@link RAbstractVector} are expected to report to {@link MemoryCopyTracer} and + * others can listen to them through {@link Listener} interface. Use method + * {@link #setTracingState(boolean)} to enable/disable the tracing. */ -public final class MemoryTracer { - private static Listener listener; - private static final Assumption noMemoryTracingAssumption = Truffle.getRuntime().createAssumption(); +public final class MemoryCopyTracer { + private static Deque<Listener> listeners = new ConcurrentLinkedDeque<>(); + @CompilationFinal private static boolean enabled; + + private static final CyclicAssumption noMemoryCopyTracingAssumption = new CyclicAssumption("data copying"); - private MemoryTracer() { + private MemoryCopyTracer() { // 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. + * Adds a listener of memory copying events. */ - public static void setListener(Listener newListener) { - listener = newListener; + public static void addListener(Listener listener) { + listeners.addLast(listener); } /** * 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(); + public static void setTracingState(boolean newState) { + if (enabled != newState) { + noMemoryCopyTracingAssumption.invalidate(); + enabled = newState; + } } /** * 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. + * no-op. */ public static void reportCopying(RAbstractVector source, RAbstractVector dest) { - if (!noMemoryTracingAssumption.isValid() && listener != null && RContext.getInstance().stateInstrumentation.getTracingState()) { - listener.reportCopying(source, dest); + if (enabled) { + for (Listener listener : listeners) { + listener.reportCopying(source, dest); + } } } diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/ObjSizeAgent.java similarity index 50% rename from com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java rename to com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/ObjSizeAgent.java index 777b8e0e05be525d5a074cf03e726f00ac77707a..b6756248470bea75bf369bfd2859bd071c11de48 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/unary/CastStringNodeGenSampler.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/ObjSizeAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -20,25 +20,33 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.truffle.r.nodes.unary; +package com.oracle.truffle.r.runtime.data; -import com.oracle.truffle.r.nodes.casts.CastNodeSampler; -import com.oracle.truffle.r.nodes.casts.TypeExpr; -import com.oracle.truffle.r.runtime.data.RNull; +import java.lang.instrument.Instrumentation; -public class CastStringNodeGenSampler extends CastNodeSampler<CastStringNodeGen> { +/** + * This is agent class for object sizing. It has to be separate as it is loaded from a jar file. + * This implements the basic call to the JVM for the "struct" part of the object. + * {@link AgentObjectSizeFactory} handles the recursive sizing based on the field/array types. + * + */ +public class ObjSizeAgent { + private static Instrumentation instrumentation; + + public static void premain(@SuppressWarnings("unused") String agentArgs, Instrumentation inst) { + instrumentation = inst; + } - public CastStringNodeGenSampler(CastStringNodeGen castNode) { - super(castNode); + public static void agentmain(@SuppressWarnings("unused") String agentArgs, Instrumentation inst) { + instrumentation = inst; } - @Override - public TypeExpr resultTypes(TypeExpr inputType) { - TypeExpr rt = super.resultTypes(inputType); - if (castNode.convertEmptyVectorToNull()) { - return rt.or(TypeExpr.union(RNull.class)); - } else { - return rt; - } + public static long objectSize(Object obj) { + return instrumentation.getObjectSize(obj); } + + static boolean isInitialized() { + return instrumentation != null; + } + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/ObjectSizeFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/ObjectSizeFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..18a0cb472db916172c7386ab5e62fb9334a0552f --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/ObjectSizeFactory.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, 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.r.runtime.data.RObjectSize.IgnoreObjectHandler; +import com.oracle.truffle.r.runtime.data.RObjectSize.TypeCustomizer; + +public abstract class ObjectSizeFactory { + + static { + final String prop = System.getProperty("fastr.objectsize.factory.class", "com.oracle.truffle.r.runtime.data.AgentObjectSizeFactory"); + try { + theInstance = (ObjectSizeFactory) Class.forName(prop).newInstance(); + } catch (Exception ex) { + // CheckStyle: stop system..print check + System.err.println("Failed to instantiate class: " + prop); + } + } + + private static ObjectSizeFactory theInstance; + + public static ObjectSizeFactory getInstance() { + return theInstance; + } + + /** + * See {@link RObjectSize#getObjectSize}. + */ + public abstract long getObjectSize(Object obj, IgnoreObjectHandler ignoreObjectHandler); + + public abstract void registerTypeCustomizer(Class<?> klass, TypeCustomizer typeCustomizer); + +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/OutputAgentObjectSizeFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/OutputAgentObjectSizeFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..4d7279743c01e4518d20124db73a4676a5c65a0a --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/OutputAgentObjectSizeFactory.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, 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 java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; + +import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.data.RObjectSize.IgnoreObjectHandler; + +/** + * A debugging tool, logs all calls to {@link #getObjectSize(Object, IgnoreObjectHandler)} to a + * file. + * + */ +public class OutputAgentObjectSizeFactory extends AgentObjectSizeFactory { + + private PrintWriter printWriter; + + public OutputAgentObjectSizeFactory() { + try { + printWriter = new PrintWriter(new FileWriter(Utils.getLogPath("fastr_objectsize.log").toString())); + } catch (IOException ex) { + Utils.rSuicide(ex.getMessage()); + } + + } + + @Override + public long getObjectSize(Object obj, IgnoreObjectHandler ignoreObjectHandler) { + long size = super.getObjectSize(obj, ignoreObjectHandler); + printWriter.printf("%s: %d\n", obj.getClass().getSimpleName(), (int) size); + printWriter.flush(); + return size; + } +} 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 1bfe70252de40c3162543da9ef30c416b27154b2..430be1e43025c645c81ffbb1c59aa6f756c8bee6 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 @@ -68,7 +68,7 @@ public final class RComplex extends RScalarVector implements RAbstractComplexVec @Override public RComplexVector materialize() { RComplexVector result = RDataFactory.createComplexVectorFromScalar(this); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java index 6131402db4e6ecb0b06453b5f497cb289ce5314e..dad4afd45a6e0e52823f4e946f459dd9a5514e1e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java @@ -23,8 +23,10 @@ package com.oracle.truffle.r.runtime.data; import java.util.Arrays; +import java.util.Deque; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.atomic.AtomicInteger; import com.oracle.truffle.api.Assumption; @@ -32,7 +34,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.frame.MaterializedFrame; -import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.api.utilities.CyclicAssumption; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RInternalError; @@ -49,11 +51,6 @@ import com.oracle.truffle.r.runtime.nodes.RNode; public final class RDataFactory { - /** - * Profile for creation tracing; must precede following declarations. - */ - private static final ConditionProfile statsProfile = ConditionProfile.createBinaryProfile(); - public static final boolean INCOMPLETE_VECTOR = false; public static final boolean COMPLETE_VECTOR = true; @@ -498,24 +495,79 @@ public final class RDataFactory { return traceDataCreated(new RExternalPtr(value, tag, RNull.instance)); } - @CompilationFinal private static PerfHandler stats; + /* + * Support for collecting information on allocations in this class. Rprofmem/Rprof register a + * listener when active which, when memory profiling is enabled, is called with the object being + * allocated. Owing to the use of the Assumption, there should be no overhead when disabled. + */ + + private static Deque<Listener> listeners = new ConcurrentLinkedDeque<>(); + @CompilationFinal private static boolean enabled; + private static final CyclicAssumption noAllocationTracingAssumption = new CyclicAssumption("data allocation"); + + public static void setAllocationTracing(boolean newState) { + if (enabled != newState) { + noAllocationTracingAssumption.invalidate(); + enabled = newState; + } + } private static <T> T traceDataCreated(T data) { - if (statsProfile.profile(stats != null)) { - stats.record(data); + if (enabled) { + for (Listener listener : listeners) { + listener.reportAllocation((RTypedValue) data); + } } return data; } + public interface Listener { + /** + * Invoked when an instance of an {@link RTypedValue} is created. Note that the initial + * state of the complex objects, i.e., those with additional {@code Object} subclass fields, + * which may also be {@link RTypedValue} instances is undefined other than by inspection. A + * listener that computes the "size" of an object must take into account that + * {@link RTypedValue} instances passed to a {@code createXXX} method will already have been + * reported, but other data such as {@code int[]} instances for array dimensions will not. + */ + void reportAllocation(RTypedValue data); + } + + /** + * 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 addListener(Listener listener) { + listeners.addLast(listener); + } + + /* + * (Legacy) support for R:PerfStats option. This does produce more information than Rprofmem + * regarding the types and length of the objects being allocated, but it does not record where + * in R the allocation took place. + */ static { RPerfStats.register(new PerfHandler()); } - private static class PerfHandler implements RPerfStats.Handler { + private static class PerfHandler implements RPerfStats.Handler, Listener { private static Map<Class<?>, RPerfStats.Histogram> histMap; + @Override + public void initialize(String optionData) { + histMap = new HashMap<>(); + addListener(this); + setAllocationTracing(true); + } + + @Override + public String getName() { + return "datafactory"; + } + + @Override @TruffleBoundary - void record(Object data) { + public void reportAllocation(RTypedValue data) { Class<?> klass = data.getClass(); boolean isBounded = data instanceof RAbstractVector; RPerfStats.Histogram hist = histMap.get(klass); @@ -527,17 +579,6 @@ public final class RDataFactory { hist.inc(length); } - @Override - public void initialize(String optionData) { - stats = this; - histMap = new HashMap<>(); - } - - @Override - public String getName() { - return "datafactory"; - } - @Override public void report() { RPerfStats.out().println("Scalar types"); @@ -558,5 +599,6 @@ public final class RDataFactory { } RPerfStats.out().println(); } + } } 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 096356c36aaf5031ea8b85166e820cfbd7d960b5..2caf812292e1c4270b619fe81165d7e1066aa7b2 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 @@ -90,7 +90,7 @@ public final class RDouble extends RScalarVector implements RAbstractDoubleVecto @Override public RDoubleVector materialize() { RDoubleVector result = RDataFactory.createDoubleVectorFromScalar(getValue()); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } 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 075d9ee51126ff8bd297ebffb5b11bed48055b13..33ba1ebd83bac82664770babb137ec2908cf5148 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 @@ -88,7 +88,7 @@ public final class RInteger extends RScalarVector implements RAbstractIntVector @Override public RIntVector materialize() { RIntVector result = RDataFactory.createIntVectorFromScalar(value); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } 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 05d0e6d1b1d642a39fc13b620d15a3727a3c130d..44e432804a569f815eeb52fe6b9533d3f79c97a4 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 @@ -94,7 +94,7 @@ public final class RLogical extends RScalarVector implements RAbstractLogicalVec @Override public RLogicalVector materialize() { RLogicalVector result = RDataFactory.createLogicalVectorFromScalar(value); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObjectSize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObjectSize.java new file mode 100644 index 0000000000000000000000000000000000000000..14b70ab39912d6a656926780f59ffe37d48e3daa --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RObjectSize.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016, 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.CallTarget; +import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.runtime.RCaller; +import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor; +import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; + +/** + * Support for the sizing of the objects that flow through the interpreter, i.e., mostly + * {@link RTypedValue}, but also including scalar types like {@code String} and dimension data for + * arrays, i.e., {@code int[]}. + * + * The actually implementation is controlled by {@link ObjectSizeFactory} to finesse problems with + * Java VMs that do not support reflection. + * + * Owing to the (implementation) complexity of some of the types, two levels of customization are + * provided: + * <ol> + * <li>A completely custom sizing implementation can be provided for a specific type. This effects + * all sizing computations.</li> + * <li>In any given call to {@link #getObjectSize} an instance of {@IgnoreObjectHandler} can passed. + * This allows some additional dynamic control over certain fields depending of the context of the + * call. For example, when tracking the incremental memory allocation via {@link RDataFactory}, we + * do not want to (double) count fields of type {@link RTypedValue}. However, when computing the + * total size of the object, e.g. for the {@code utils::object.size} builtin, we do want to count + * them.</li> + * </ol> + * + */ +public class RObjectSize { + public static final int INT_SIZE = 32; + public static final int DOUBLE_SIZE = 64; + public static final int BYTE_SIZE = 8; + + public interface TypeCustomizer { + /** + * Allows complete control over sizing of a type registered with + * {@link #registerTypeCustomizer}. + */ + long getObjectSize(Object obj); + } + + public interface IgnoreObjectHandler { + /** + * Controls which fields of an object passed to {@link #getObjectSize} will be ignored. + * {@code rootObject} is the initiating object and {@code obj} is some field of that object + * or one of its components. The return value should be {@code true} if {@code obj} should + * be ignored. + */ + boolean ignore(Object rootObject, Object obj); + } + + /** + * Returns an estimate of the size of the this object, including the size of any object-valued + * fields, recursively. Evidently this is a snapshot and the size can change as, e.g., + * attributes are added/removed. + * + * If called immediately after creation by {@link RDataFactory}, with an + * {@link IgnoreObjectHandler} that ignores objects created separately and, it provides an + * approximation of the incremental memory usage of the system. + * + * @param ignoreObjectHandler An object that is called to decide whether to include the + * contribution a field of this object (and its sub-objects) in the result. Passing + * {@code null} includes everything. N.B. {@code obj} is typed as {@code Object} only + * to allow scalar typed such as {@code String} to be passed. + * + */ + public static long getObjectSize(Object obj, IgnoreObjectHandler ignoreObjectHandler) { + return (int) ObjectSizeFactory.getInstance().getObjectSize(obj, ignoreObjectHandler); + } + + /** + * Register a {@link TypeCustomizer} for {@code klass} and its subclasses. I.e. and object + * {@code obj} is customized iff {@code klass.isAssignableFrom(obj.getClass())}. + */ + public static void registerTypeCustomizer(Class<?> klass, TypeCustomizer typeCustomizer) { + ObjectSizeFactory.getInstance().registerTypeCustomizer(klass, typeCustomizer); + } + + /** + * This denotes a special customizer that completely ignores instances of the type and its + * subclasses. It allows a more efficient implementation as the type can be suppressed + * completely from the computation at the time fields of a containing type are analyzed. + */ + public static final TypeCustomizer IGNORE = new TypeCustomizer() { + + @Override + public long getObjectSize(Object obj) { + return 0; + } + + }; + + // TODO construct proper customizers for some of these. + static { + registerTypeCustomizer(Frame.class, IGNORE); + registerTypeCustomizer(FrameDescriptor.class, IGNORE); + registerTypeCustomizer(Node.class, IGNORE); + registerTypeCustomizer(CallTarget.class, IGNORE); + registerTypeCustomizer(RBuiltinDescriptor.class, IGNORE); + registerTypeCustomizer(RPromise.Closure.class, IGNORE); + registerTypeCustomizer(Assumption.class, IGNORE); + registerTypeCustomizer(RCaller.class, IGNORE); + registerTypeCustomizer(SEXPTYPE.class, IGNORE); + } + +} 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 d843cacfb937a8518c91151e91e7e33b3c553076..a18f274d43736e0c7e9936de1eaa8d6adf0aa544 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 @@ -65,7 +65,7 @@ public final class RRaw extends RScalarVector implements RAbstractRawVector { @Override public RRawVector materialize() { RRawVector result = RDataFactory.createRawVector(new byte[]{value}); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } 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 6e4a7ca5d9590b16c937b8bb62608c6f25ef8cd7..e12aed17f8fbb58a7789401701ae49a288788850 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 @@ -143,28 +143,28 @@ public abstract class RScalarVector extends RScalar implements RAbstractVector { @Override public RVector copyResized(int size, boolean fillNA) { RVector result = materialize().copyResized(size, fillNA); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } @Override public RAbstractVector copyWithNewDimensions(int[] newDimensions) { RAbstractVector result = materialize().copyWithNewDimensions(newDimensions); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } @Override public RVector copyResizedWithDimensions(int[] newDimensions, boolean fillNA) { RVector result = materialize().copyResizedWithDimensions(newDimensions, fillNA); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } @Override public RAbstractVector copyDropAttributes() { RVector result = materialize().copyDropAttributes(); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } 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 3dcc48a783d72896755c68f58238721596a0d86c..75a022269b5c8b5057b02859a0d6f750d412e76b 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 @@ -81,7 +81,7 @@ public abstract class RSequence implements RAbstractVector { public final RVector createVector() { RVector result = internalCreateVector(); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } 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 764f4c4b4ba2c88556989eb83461fdf4b8409bc5..af3281e0c19f749edcdbd5f3ab44ed4562315ce6 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 @@ -74,7 +74,7 @@ public final class RString extends RScalarVector implements RAbstractStringVecto @Override public RStringVector materialize() { RStringVector result = RDataFactory.createStringVector(new String[]{getValue()}, isComplete()); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } 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 159addc3e228b3bda6e2e3bbcc9e9504544c5987..a75b54fdb4bd80a721e5dfb173f611368db7cb62 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 @@ -581,19 +581,19 @@ public abstract class RVector extends RSharingAttributeStorage implements RShare protected final RVector internalCopyAndReport() { RVector result = internalCopy(); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } protected final RVector internalDeepCopyAndReport() { RVector result = internalDeepCopy(); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } protected final RVector internalCopyResizedAndReport(int size, boolean fillNA) { RVector result = internalCopyResized(size, fillNA); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } 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 0fe0baccfc90e7e0bb0b1a374322b1d431b37cc2..99383ff1a2bf7e9f9c5afd5ed0158a00ffb02835 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,7 +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.MemoryCopyTracer; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RAttributes; import com.oracle.truffle.r.runtime.data.RList; @@ -129,14 +129,14 @@ abstract class RToVectorClosure implements RAbstractVector { @Override public final RAbstractVector copy() { RAbstractVector result = vector.copy(); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } @Override public final RVector copyResized(int size, boolean fillNA) { RVector result = vector.copyResized(size, fillNA); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } @@ -152,7 +152,7 @@ abstract class RToVectorClosure implements RAbstractVector { @Override public final RAbstractVector copyDropAttributes() { RAbstractVector result = vector.copyDropAttributes(); - MemoryTracer.reportCopying(this, result); + MemoryCopyTracer.reportCopying(this, result); return result; } 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 a2ae57288b474717f66033b2bacd43a882e5e899..a9b3eebf0606c05d5a434500e994a5ab907cc38c 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,11 +24,11 @@ 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.MemoryCopyTracer; import com.oracle.truffle.r.runtime.data.RVector; /** - * When implementing, make sure to invoke related {@link MemoryTracer} methods. + * When implementing, make sure to invoke related {@link MemoryCopyTracer} methods. */ public interface RAbstractVector extends RAbstractContainer { 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 09f5a10046d079cd9b7697e1d51e4fb172fb4556..0b601ce31970ad98c9347a687fc8de366dbcef6c 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 @@ -68,6 +68,11 @@ public final class InstrumentationState implements RContext.ContextState { */ private final RprofState rprofState; + /** + * The {@link RprofmemState} state, if any, associated with this {@link RContext}. + */ + private final RprofmemState rprofmemState; + private final TracememContext tracememContext; /** @@ -96,32 +101,72 @@ public final class InstrumentationState implements RContext.ContextState { */ private boolean debugGloballyDisabled; + private abstract static class RprofAdapter { + protected PrintWriter out; + + /** + * Return current output or {@code null} if not profiling. + */ + public PrintWriter out() { + return out; + } + + public void setOut(PrintWriter out) { + this.out = out; + } + } + /** * State used by {@code Rprof}. * */ - public static final class RprofState { - private PrintWriter out; + public static final class RprofState extends RprofAdapter { private Thread profileThread; private ExecutionEventListener statementListener; private long intervalInMillis; private boolean lineProfiling; + private MemoryQuad memoryQuad; + + public static final class MemoryQuad { + public long smallV; + public long largeV; + public long nodes; + public long copied; + + public MemoryQuad copyAndClear() { + MemoryQuad result = new MemoryQuad(); + result.copied = copied; + result.largeV = largeV; + result.smallV = smallV; + result.nodes = nodes; + copied = 0; + largeV = 0; + smallV = 0; + nodes = 0; + return result; + } + } public void initialize(PrintWriter outA, Thread profileThreadA, ExecutionEventListener statementListenerA, long intervalInMillisA, - boolean lineProfilingA) { + boolean lineProfilingA, boolean memoryProfilingA) { this.out = outA; this.profileThread = profileThreadA; this.statementListener = statementListenerA; this.intervalInMillis = intervalInMillisA; this.lineProfiling = lineProfilingA; + this.memoryQuad = memoryProfilingA ? new MemoryQuad() : null; } public boolean lineProfiling() { return lineProfiling; } - public PrintWriter out() { - return out; + public boolean memoryProfiling() { + return memoryQuad != null; + } + + public MemoryQuad memoryQuad() { + return memoryQuad; } public long intervalInMillis() { @@ -138,6 +183,28 @@ public final class InstrumentationState implements RContext.ContextState { } + public static final class RprofmemState extends RprofAdapter { + private double threshold; + private int pageCount; + + public void initialize(PrintWriter outA, double thresholdA) { + this.out = outA; + this.threshold = thresholdA; + } + + public double threshold() { + return threshold; + } + + public int pageCount() { + return pageCount; + } + + public void setPageCount(int pageCount) { + this.pageCount = pageCount; + } + } + public static class BrowserState { private boolean inBrowser; private String lastEmptyLineCommand = "n"; @@ -162,6 +229,7 @@ public final class InstrumentationState implements RContext.ContextState { private InstrumentationState(Instrumenter instrumenter) { this.instrumenter = instrumenter; this.rprofState = new RprofState(); + this.rprofmemState = new RprofmemState(); this.tracememContext = new TracememContext(); this.browserState = new BrowserState(); } @@ -215,6 +283,10 @@ public final class InstrumentationState implements RContext.ContextState { return rprofState; } + public RprofmemState getRprofmem() { + return rprofmemState; + } + public TracememContext getTracemem() { return tracememContext; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxLookup.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxLookup.java index 705968c91b77d672bdbac6ee8212c7130ac7a259..ac2cfe029130c6db14079f91223bc1a623d59354 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxLookup.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxLookup.java @@ -29,6 +29,9 @@ import com.oracle.truffle.api.source.SourceSection; */ public interface RSyntaxLookup extends RSyntaxElement { + /** + * @return The identifier that this lookup represents - this needs to be an interned string. + */ String getIdentifier(); boolean isFunctionLookup(); 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 373fefd48255861cdcdae7e0480e801ac6c8a825..01e3fcd48ae14532a5137cb0329f0b4184b4e46e 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 @@ -1101,6 +1101,26 @@ character(0) #argv <- list(structure(list(sec = c(0, 0, 0, 0, 0), min = c(0L, 0L, 0L, 0L, 0L), hour = c(0L, 0L, 0L, 0L, 0L), mday = 22:26, mon = c(3L, 3L, 3L, 3L, 3L), year = c(108L, 108L, 108L, 108L, 108L), wday = 2:6, yday = 112:116, isdst = c(-1L, -1L, -1L, -1L, -1L)), .Names = c('sec', 'min', 'hour', 'mday', 'mon', 'year', 'wday', 'yday', 'isdst'), class = c('POSIXlt', 'POSIXt'), tzone = 'GMT')); .Internal(POSIXlt2Date(argv[[1]])) [1] "2008-04-22" "2008-04-23" "2008-04-24" "2008-04-25" "2008-04-26" +##com.oracle.truffle.r.test.builtins.TestBuiltin_Primitive.testPrimitive1 +#.Primitive('any') +function (..., na.rm = FALSE) .Primitive("any") + +##com.oracle.truffle.r.test.builtins.TestBuiltin_Primitive.testPrimitive1 +#.Primitive('complex') +Error in .Primitive("complex") : no such primitive function + +##com.oracle.truffle.r.test.builtins.TestBuiltin_Primitive.testPrimitive1 +#.Primitive('foo') +Error in .Primitive("foo") : no such primitive function + +##com.oracle.truffle.r.test.builtins.TestBuiltin_Primitive.testPrimitive1 +#.Primitive(1) +Error in .Primitive(1) : string argument required + +##com.oracle.truffle.r.test.builtins.TestBuiltin_Primitive.testPrimitive1 +#.Primitive(c('c', 'b')) +Error in .Primitive(c("c", "b")) : string argument required + ##com.oracle.truffle.r.test.builtins.TestBuiltin_Primitive.testPrimitive1 #argv <- list('c');.Primitive(argv[[1]]); function (..., recursive = FALSE) .Primitive("c") @@ -45976,6 +45996,16 @@ character(0) #argv <- list(character(0), 8L); .Internal(strtoi(argv[[1]], argv[[2]])) integer(0) +##com.oracle.truffle.r.test.builtins.TestBuiltin_strtrim.teststrtrim +#v <- c('a', 'fooooo', 'bbbbbb', 'cccccccccc', 'dd', NA); names(v) <- as.character(1:6); strtrim(v, c(2, 5)) + 1 2 3 4 5 6 + "a" "foooo" "bb" "ccccc" "dd" NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_strtrim.teststrtrim +#v <- c('a', 'fooooo', 'bbbbbb', 'cccccccccc', 'dd', NA); names(v) <- as.character(1:6); strtrim(v, c(2L, 5L)) + 1 2 3 4 5 6 + "a" "foooo" "bb" "ccccc" "dd" NA + ##com.oracle.truffle.r.test.builtins.TestBuiltin_strtrim.teststrtrim1 #argv <- list(c('\'time\'', '\'status\''), 128); .Internal(strtrim(argv[[1]], argv[[2]])) [1] "'time'" "'status'" @@ -48022,6 +48052,39 @@ integer(0) #{ u <- function() sys.parents() ; f <- function(x) x ; g <- function(y) f(y) ; h <- function(z=u()) g(z) ; h() } [1] 0 1 2 1 +##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTranspose +#t(1) + [,1] +[1,] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTranspose +#t(TRUE) + [,1] +[1,] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTranspose +#t(as.raw(c(1,2,3,4))) + [,1] [,2] [,3] [,4] +[1,] 01 02 03 04 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTranspose +#t(new.env()) +Error in t.default(new.env()) : argument is not a matrix + +##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTranspose +#v <- as.complex(1:50); dim(v) <- c(5,10); dimnames(v) <- list(as.character(40:44), as.character(10:19)); t(v) + 40 41 42 43 44 +10 1+0i 2+0i 3+0i 4+0i 5+0i +11 6+0i 7+0i 8+0i 9+0i 10+0i +12 11+0i 12+0i 13+0i 14+0i 15+0i +13 16+0i 17+0i 18+0i 19+0i 20+0i +14 21+0i 22+0i 23+0i 24+0i 25+0i +15 26+0i 27+0i 28+0i 29+0i 30+0i +16 31+0i 32+0i 33+0i 34+0i 35+0i +17 36+0i 37+0i 38+0i 39+0i 40+0i +18 41+0i 42+0i 43+0i 44+0i 45+0i +19 46+0i 47+0i 48+0i 49+0i 50+0i + ##com.oracle.truffle.r.test.builtins.TestBuiltin_t.testTranspose #{ m <- double() ; dim(m) <- c(0,4) ; t(m) } @@ -107105,26 +107168,38 @@ a b c d a b c d e 1 2 3 4 5 -##com.oracle.truffle.r.test.library.fastr.TestInteropEval.testInteropEval +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropEval #if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { .fastr.interop.eval('application/x-r', '1') } [1] 1 -##com.oracle.truffle.r.test.library.fastr.TestInteropEval.testInteropEval +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropEval #if (length(grep("FastR", R.Version()$version.string)) != 1) { 16 } else { .fastr.interop.eval('application/x-r', '14 + 2') } [1] 16 -##com.oracle.truffle.r.test.library.fastr.TestInteropEval.testInteropEval +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropEval #if (length(grep("FastR", R.Version()$version.string)) != 1) { 1L } else { .fastr.interop.eval('application/x-r', '1L') } [1] 1 -##com.oracle.truffle.r.test.library.fastr.TestInteropEval.testInteropEval +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropEval #if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { .fastr.interop.eval('application/x-r', 'TRUE') } [1] TRUE -##com.oracle.truffle.r.test.library.fastr.TestInteropEval.testInteropEval +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropEval #if (length(grep("FastR", R.Version()$version.string)) != 1) { as.character(123) } else { .fastr.interop.eval('application/x-r', 'as.character(123)') } [1] "123" +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropExport +#if (length(grep("FastR", R.Version()$version.string)) != 1) { invisible() } else { .fastr.interop.export('foo', 'foo') } + +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropExport +#if (length(grep("FastR", R.Version()$version.string)) != 1) { invisible() } else { .fastr.interop.export('foo', 14 + 2) } + +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropExport +#if (length(grep("FastR", R.Version()$version.string)) != 1) { invisible() } else { .fastr.interop.export('foo', 1:100) } + +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropExport +#if (length(grep("FastR", R.Version()$version.string)) != 1) { invisible() } else { .fastr.interop.export('foo', new.env()) } + ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions #if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { { f<-function(x) .fastr.refcountinfo(x); f(c(1,2)) } } [1] 1 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_Primitive.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_Primitive.java index dd1cb83bac27a21d515b2dbc9d66231d545b9f4b..0a5be54776f6d0366f142b7175f1fc4fb3284c57 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_Primitive.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_Primitive.java @@ -19,6 +19,13 @@ public class TestBuiltin_Primitive extends TestBase { @Test public void testPrimitive1() { - assertEval(Ignored.Unknown, "argv <- list('c');.Primitive(argv[[1]]);"); + // our c() primitive is missing an argument + assertEval(Ignored.ImplementationError, "argv <- list('c');.Primitive(argv[[1]]);"); + + assertEval(".Primitive(c('c', 'b'))"); + assertEval(".Primitive('any')"); + assertEval(".Primitive('foo')"); + assertEval(".Primitive('complex')"); + assertEval(".Primitive(1)"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_strtrim.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_strtrim.java index 6c566f53a4cd418c70b1f9cf22aeb9019ebc992c..00fc2dc52149e953dff0057469a515912a4decb2 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_strtrim.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_strtrim.java @@ -51,4 +51,10 @@ public class TestBuiltin_strtrim extends TestBase { public void teststrtrim8() { assertEval("argv <- list(character(0), 40L); .Internal(strtrim(argv[[1]], argv[[2]]))"); } + + @Test + public void teststrtrim() { + assertEval("v <- c('a', 'fooooo', 'bbbbbb', 'cccccccccc', 'dd', NA); names(v) <- as.character(1:6); strtrim(v, c(2L, 5L))"); + assertEval("v <- c('a', 'fooooo', 'bbbbbb', 'cccccccccc', 'dd', NA); names(v) <- as.character(1:6); strtrim(v, c(2, 5))"); + } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java index 3d851f24c7e6da980f8521ef2ff438e066cf4420..693cde32eb6e252583908b569377a1a8b142a8c2 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_t.java @@ -40,5 +40,11 @@ public class TestBuiltin_t extends TestBase { assertEval("{ t(t(matrix(1:4, nrow=2))) }"); assertEval("{ x<-matrix(1:2, ncol=2, dimnames=list(\"a\", c(\"b\", \"c\"))); t(x) }"); + + assertEval("t(new.env())"); + assertEval("v <- as.complex(1:50); dim(v) <- c(5,10); dimnames(v) <- list(as.character(40:44), as.character(10:19)); t(v)"); + assertEval("t(1)"); + assertEval("t(TRUE)"); + assertEval("t(as.raw(c(1,2,3,4)))"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tolower.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tolower.java index 8b0588b2bdd7b3dbe88f9dcc5db85d1dbc65c20f..f216fb17383d13f45e41e65f7a756002c2cc96a6 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tolower.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_tolower.java @@ -39,7 +39,7 @@ public class TestBuiltin_tolower extends TestBase { @Test public void testtolower5() { - assertEval(Ignored.Unimplemented, "argv <- list(structure('base', .Names = 'Priority')); .Internal(tolower(argv[[1]]))"); + assertEval("argv <- list(structure('base', .Names = 'Priority')); .Internal(tolower(argv[[1]]))"); } @Test @@ -57,8 +57,9 @@ public class TestBuiltin_tolower extends TestBase { assertEval("{ tolower(c(\"Hello\",\"ByE\")) }"); assertEval("{ tolower(c()) }"); + // double-to-string conversion problem assertEval(Ignored.OutputFormatting, "{ tolower(1E100) }"); - assertEval(Ignored.Unimplemented, "{ tolower(c(a=\"HI\", \"HELlo\")) }"); + assertEval("{ tolower(c(a=\"HI\", \"HELlo\")) }"); assertEval("{ tolower(NA) }"); assertEval("tolower(c('NA', 'na'))"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_toupper.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_toupper.java index d00b82523eba4d16051e8f3682407f4e391229be..a6a2008deac27591833cea3559e7b408bbcffd1f 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_toupper.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_toupper.java @@ -34,8 +34,7 @@ public class TestBuiltin_toupper extends TestBase { @Test public void testtoupper4() { - assertEval(Ignored.Unimplemented, - "argv <- list(structure(c('BasicClasses', 'Classes', 'Documentation', 'environment-class', 'GenericFunctions', 'language-class', 'LinearMethodsList-class', 'MethodDefinition-class', 'MethodWithNext-class', 'Methods', 'MethodsList-class', 'callNextMethod', 'ObjectsWithPackage-class', 'S3Part', 'S4groupGeneric', 'SClassExtension-class', 'StructureClasses', 'TraceClasses', 'as', 'callGeneric', 'canCoerce', 'cbind2', 'className', 'classRepresentation-class', 'classesToAM', 'dotsMethods', 'evalSource', 'findClass', 'findMethods', 'fixPre1.8', 'genericFunction-class', 'getClass', 'getMethod', 'getPackageName', 'hasArg', 'implicitGeneric', 'inheritedSlotNames', 'initialize-methods', 'is', 'isSealedMethod', 'LocalReferenceClasses', 'method.skeleton', 'new', 'nonStructure-class', 'promptClass', 'promptMethods', 'ReferenceClasses', 'representation', 'selectSuperClasses', 'setClass', 'setClassUnion', 'setGeneric', 'setLoadActions', 'setMethod', 'setOldClass', 'makeClassRepresentation', 'show', 'showMethods', 'signature-class', 'slot', 'envRefClass-class', 'testInheritedMethods', 'validObject', '.BasicFunsList'), .Names = c('/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/BasicClasses.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/Classes.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/Documentation.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/EnvironmentClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/GenericFunctions.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/LanguageClasses.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/LinearMethodsList-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/MethodDefinition-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/MethodWithNext-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/Methods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/MethodsList-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/NextMethod.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/ObjectsWithPackage-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/S3Part.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/S4groupGeneric.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/SClassExtension-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/StructureClasses.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/TraceClasses.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/as.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/callGeneric.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/canCoerce.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/cbind2.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/className.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/classRepresentation-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/classesToAM.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/dotsMethods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/evalSource.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/findClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/findMethods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/fixPrevious.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/genericFunction-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/getClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/getMethod.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/getPackageName.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/hasArg.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/implicitGeneric.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/inheritedSlotNames.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/initialize-methods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/is.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/isSealedMethod.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/localRefClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/method.skeleton.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/new.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/nonStructure-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/promptClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/promptMethods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/refClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/representation.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/selectSuperClasses.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setClassUnion.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setGeneric.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setLoadActions.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setMethod.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setOldClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setSClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/show.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/showMethods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/signature-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/slot.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/stdRefClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/testInheritedMethods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/validObject.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/zBasicFunsList.tex'))); .Internal(toupper(argv[[1]]))"); + assertEval("argv <- list(structure(c('BasicClasses', 'Classes', 'Documentation', 'environment-class', 'GenericFunctions', 'language-class', 'LinearMethodsList-class', 'MethodDefinition-class', 'MethodWithNext-class', 'Methods', 'MethodsList-class', 'callNextMethod', 'ObjectsWithPackage-class', 'S3Part', 'S4groupGeneric', 'SClassExtension-class', 'StructureClasses', 'TraceClasses', 'as', 'callGeneric', 'canCoerce', 'cbind2', 'className', 'classRepresentation-class', 'classesToAM', 'dotsMethods', 'evalSource', 'findClass', 'findMethods', 'fixPre1.8', 'genericFunction-class', 'getClass', 'getMethod', 'getPackageName', 'hasArg', 'implicitGeneric', 'inheritedSlotNames', 'initialize-methods', 'is', 'isSealedMethod', 'LocalReferenceClasses', 'method.skeleton', 'new', 'nonStructure-class', 'promptClass', 'promptMethods', 'ReferenceClasses', 'representation', 'selectSuperClasses', 'setClass', 'setClassUnion', 'setGeneric', 'setLoadActions', 'setMethod', 'setOldClass', 'makeClassRepresentation', 'show', 'showMethods', 'signature-class', 'slot', 'envRefClass-class', 'testInheritedMethods', 'validObject', '.BasicFunsList'), .Names = c('/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/BasicClasses.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/Classes.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/Documentation.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/EnvironmentClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/GenericFunctions.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/LanguageClasses.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/LinearMethodsList-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/MethodDefinition-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/MethodWithNext-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/Methods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/MethodsList-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/NextMethod.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/ObjectsWithPackage-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/S3Part.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/S4groupGeneric.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/SClassExtension-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/StructureClasses.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/TraceClasses.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/as.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/callGeneric.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/canCoerce.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/cbind2.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/className.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/classRepresentation-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/classesToAM.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/dotsMethods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/evalSource.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/findClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/findMethods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/fixPrevious.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/genericFunction-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/getClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/getMethod.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/getPackageName.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/hasArg.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/implicitGeneric.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/inheritedSlotNames.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/initialize-methods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/is.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/isSealedMethod.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/localRefClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/method.skeleton.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/new.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/nonStructure-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/promptClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/promptMethods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/refClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/representation.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/selectSuperClasses.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setClassUnion.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setGeneric.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setLoadActions.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setMethod.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setOldClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/setSClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/show.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/showMethods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/signature-class.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/slot.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/stdRefClass.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/testInheritedMethods.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/validObject.tex', '/home/lzhao/tmp/RtmpZy1R7l/ltx5573594f0cc9/zBasicFunsList.tex'))); .Internal(toupper(argv[[1]]))"); } @Test @@ -51,6 +50,6 @@ public class TestBuiltin_toupper extends TestBase { assertEval(Ignored.OutputFormatting, "{ toupper(1E100) }"); assertEval("{ m <- matrix(\"hi\") ; toupper(m) }"); - assertEval(Ignored.Unimplemented, "{ toupper(c(a=\"hi\", \"hello\")) }"); + assertEval("{ toupper(c(a=\"hi\", \"hello\")) }"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_whichmax.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_whichmax.java index 2fe9d80df244312a224515e494fa1fc7ced6783c..ddf4c669f82f8a705cacddb8ba2f8b227097aad2 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_whichmax.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_whichmax.java @@ -24,7 +24,7 @@ public class TestBuiltin_whichmax extends TestBase { @Test public void testwhichmax2() { - assertEval(Ignored.Unknown, "argv <- list(structure(c(TRUE, FALSE), .Names = c('d', 'I(as.numeric(d)^2)'))); .Internal(which.max(argv[[1]]))"); + assertEval("argv <- list(structure(c(TRUE, FALSE), .Names = c('d', 'I(as.numeric(d)^2)'))); .Internal(which.max(argv[[1]]))"); } @Test @@ -34,23 +34,22 @@ public class TestBuiltin_whichmax extends TestBase { @Test public void testwhichmax4() { - assertEval(Ignored.Unknown, - "argv <- list(structure(c(NA, 87, 82, 75, 63, 50, 43, 32, 35, 60, 54, 55, 36, 39, NA, NA, 69, 57, 57, 51, 45, 37, 46, 39, 36, 24, 32, 23, 25, 32, NA, 32, 59, 74, 75, 60, 71, 61, 71, 57, 71, 68, 79, 73, 76, 71, 67, 75, 79, 62, 63, 57, 60, 49, 48, 52, 57, 62, 61, 66, 71, 62, 61, 57, 72, 83, 71, 78, 79, 71, 62, 74, 76, 64, 62, 57, 80, 73, 69, 69, 71, 64, 69, 62, 63, 46, 56, 44, 44, 52, 38, 46, 36, 49, 35, 44, 59, 65, 65, 56, 66, 53, 61, 52, 51, 48, 54, 49, 49, 61, NA, NA, 68, 44, 40, 27, 28, 25, 24, 24), .Tsp = c(1945, 1974.75, 4), class = 'ts')); .Internal(which.max(argv[[1]]))"); + assertEval("argv <- list(structure(c(NA, 87, 82, 75, 63, 50, 43, 32, 35, 60, 54, 55, 36, 39, NA, NA, 69, 57, 57, 51, 45, 37, 46, 39, 36, 24, 32, 23, 25, 32, NA, 32, 59, 74, 75, 60, 71, 61, 71, 57, 71, 68, 79, 73, 76, 71, 67, 75, 79, 62, 63, 57, 60, 49, 48, 52, 57, 62, 61, 66, 71, 62, 61, 57, 72, 83, 71, 78, 79, 71, 62, 74, 76, 64, 62, 57, 80, 73, 69, 69, 71, 64, 69, 62, 63, 46, 56, 44, 44, 52, 38, 46, 36, 49, 35, 44, 59, 65, 65, 56, 66, 53, 61, 52, 51, 48, 54, 49, 49, 61, NA, NA, 68, 44, 40, 27, 28, 25, 24, 24), .Tsp = c(1945, 1974.75, 4), class = 'ts')); .Internal(which.max(argv[[1]]))"); } @Test public void testwhichmax5() { - assertEval(Ignored.Unknown, "argv <- list(NULL); .Internal(which.max(argv[[1]]))"); + assertEval("argv <- list(NULL); .Internal(which.max(argv[[1]]))"); } @Test public void testwhichmax6() { - assertEval(Ignored.Unknown, "argv <- list(list()); .Internal(which.max(argv[[1]]))"); + assertEval("argv <- list(list()); .Internal(which.max(argv[[1]]))"); } @Test public void testwhichmax8() { - assertEval(Ignored.Unknown, "argv <- structure(list(x = c(NA, NA)), .Names = 'x');do.call('which.max', argv)"); + assertEval("argv <- structure(list(x = c(NA, NA)), .Names = 'x');do.call('which.max', argv)"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_whichmin.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_whichmin.java index c68a12f92aeb6613580324898e4074e1212331ef..8dbadd6a6face7e01fb9f1830fe277a4b5186edd 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_whichmin.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_whichmin.java @@ -19,41 +19,37 @@ public class TestBuiltin_whichmin extends TestBase { @Test public void testwhichmin1() { - assertEval(Ignored.Unknown, - "argv <- list(structure(c(345595, 172795, 69115, 34555, 23035, 11515, 5755, 2875, 1147, 571, 379, 187, 91, 27, 11, 3, 1, 3, 4.42857142857143, 4.73716632443532, 4.86858316221766, 4.95619438740589, 4.97809719370294, 4.98904859685147, 4.99452429842574, 4.99780971937029, 4.99890485968515, 4.99945242984257, 4.99978097193703, 4.99989048596851, 4.99994524298426, 4.9999780971937, 4.99998904859685), .Names = c('1 sec', '2 secs', '5 secs', '10 secs', '15 secs', '30 secs', '1 min', '2 mins', '5 mins', '10 mins', '15 mins', '30 mins', '1 hour', '3 hours', '6 hours', '12 hours', '1 DSTday', '2 DSTdays', '1 week', 'halfmonth', '1 month', '3 months', '6 months', '1 year', '2 years', '5 years', '10 years', '20 years', '50 years', '100 years', '200 years', '500 years', '1000 years'))); .Internal(which.min(argv[[1]]))"); + assertEval("argv <- list(structure(c(345595, 172795, 69115, 34555, 23035, 11515, 5755, 2875, 1147, 571, 379, 187, 91, 27, 11, 3, 1, 3, 4.42857142857143, 4.73716632443532, 4.86858316221766, 4.95619438740589, 4.97809719370294, 4.98904859685147, 4.99452429842574, 4.99780971937029, 4.99890485968515, 4.99945242984257, 4.99978097193703, 4.99989048596851, 4.99994524298426, 4.9999780971937, 4.99998904859685), .Names = c('1 sec', '2 secs', '5 secs', '10 secs', '15 secs', '30 secs', '1 min', '2 mins', '5 mins', '10 mins', '15 mins', '30 mins', '1 hour', '3 hours', '6 hours', '12 hours', '1 DSTday', '2 DSTdays', '1 week', 'halfmonth', '1 month', '3 months', '6 months', '1 year', '2 years', '5 years', '10 years', '20 years', '50 years', '100 years', '200 years', '500 years', '1000 years'))); .Internal(which.min(argv[[1]]))"); } @Test public void testwhichmin2() { - assertEval(Ignored.Unknown, - "argv <- list(structure(c(295, 145, 55, 25, 15, 5, 0, 2.5, 4, 4.5, 4.66666666666667, 4.83333333333333, 4.91666666666667, 4.97222222222222, 4.98611111111111, 4.99305555555556, 4.99652777777778, 4.99826388888889, 4.99950396825397, 4.99977184576774, 4.99988592288387, 4.99996197429462, 4.99998098714731, 4.99999049357366, 4.99999524678683, 4.99999809871473, 4.99999904935737, 4.99999952467868, 4.99999980987147, 4.99999990493574, 4.99999995246787, 4.99999998098715, 4.99999999049357), .Names = c('1 sec', '2 secs', '5 secs', '10 secs', '15 secs', '30 secs', '1 min', '2 mins', '5 mins', '10 mins', '15 mins', '30 mins', '1 hour', '3 hours', '6 hours', '12 hours', '1 DSTday', '2 DSTdays', '1 week', 'halfmonth', '1 month', '3 months', '6 months', '1 year', '2 years', '5 years', '10 years', '20 years', '50 years', '100 years', '200 years', '500 years', '1000 years'))); .Internal(which.min(argv[[1]]))"); + assertEval("argv <- list(structure(c(295, 145, 55, 25, 15, 5, 0, 2.5, 4, 4.5, 4.66666666666667, 4.83333333333333, 4.91666666666667, 4.97222222222222, 4.98611111111111, 4.99305555555556, 4.99652777777778, 4.99826388888889, 4.99950396825397, 4.99977184576774, 4.99988592288387, 4.99996197429462, 4.99998098714731, 4.99999049357366, 4.99999524678683, 4.99999809871473, 4.99999904935737, 4.99999952467868, 4.99999980987147, 4.99999990493574, 4.99999995246787, 4.99999998098715, 4.99999999049357), .Names = c('1 sec', '2 secs', '5 secs', '10 secs', '15 secs', '30 secs', '1 min', '2 mins', '5 mins', '10 mins', '15 mins', '30 mins', '1 hour', '3 hours', '6 hours', '12 hours', '1 DSTday', '2 DSTdays', '1 week', 'halfmonth', '1 month', '3 months', '6 months', '1 year', '2 years', '5 years', '10 years', '20 years', '50 years', '100 years', '200 years', '500 years', '1000 years'))); .Internal(which.min(argv[[1]]))"); } @Test public void testwhichmin3() { - assertEval(Ignored.Unknown, "argv <- list(NULL); .Internal(which.min(argv[[1]]))"); + assertEval("argv <- list(NULL); .Internal(which.min(argv[[1]]))"); } @Test public void testwhichmin4() { - assertEval(Ignored.Unknown, "argv <- list(list()); .Internal(which.min(argv[[1]]))"); + assertEval("argv <- list(list()); .Internal(which.min(argv[[1]]))"); } @Test public void testwhichmin5() { - assertEval(Ignored.Unknown, - "argv <- list(c(NA, 0.951840581382975, 0.805577027554469, 0.663985017923499, 0.53717416750558, 0.496765449963868, 0.472038350505409, 0.463306413812878, 0.485896454097402, 0.520777596351646, 0.524391122960607, 0.492063804965834, 0.513821989320989, 0.521702559081969, 0.533525525673351)); .Internal(which.min(argv[[1]]))"); + assertEval("argv <- list(c(NA, 0.951840581382975, 0.805577027554469, 0.663985017923499, 0.53717416750558, 0.496765449963868, 0.472038350505409, 0.463306413812878, 0.485896454097402, 0.520777596351646, 0.524391122960607, 0.492063804965834, 0.513821989320989, 0.521702559081969, 0.533525525673351)); .Internal(which.min(argv[[1]]))"); } @Test public void testwhichmin6() { - assertEval(Ignored.Unknown, - "argv <- list(structure(c(NA, 87, 82, 75, 63, 50, 43, 32, 35, 60, 54, 55, 36, 39, NA, NA, 69, 57, 57, 51, 45, 37, 46, 39, 36, 24, 32, 23, 25, 32, NA, 32, 59, 74, 75, 60, 71, 61, 71, 57, 71, 68, 79, 73, 76, 71, 67, 75, 79, 62, 63, 57, 60, 49, 48, 52, 57, 62, 61, 66, 71, 62, 61, 57, 72, 83, 71, 78, 79, 71, 62, 74, 76, 64, 62, 57, 80, 73, 69, 69, 71, 64, 69, 62, 63, 46, 56, 44, 44, 52, 38, 46, 36, 49, 35, 44, 59, 65, 65, 56, 66, 53, 61, 52, 51, 48, 54, 49, 49, 61, NA, NA, 68, 44, 40, 27, 28, 25, 24, 24), .Tsp = c(1945, 1974.75, 4), class = 'ts')); .Internal(which.min(argv[[1]]))"); + assertEval("argv <- list(structure(c(NA, 87, 82, 75, 63, 50, 43, 32, 35, 60, 54, 55, 36, 39, NA, NA, 69, 57, 57, 51, 45, 37, 46, 39, 36, 24, 32, 23, 25, 32, NA, 32, 59, 74, 75, 60, 71, 61, 71, 57, 71, 68, 79, 73, 76, 71, 67, 75, 79, 62, 63, 57, 60, 49, 48, 52, 57, 62, 61, 66, 71, 62, 61, 57, 72, 83, 71, 78, 79, 71, 62, 74, 76, 64, 62, 57, 80, 73, 69, 69, 71, 64, 69, 62, 63, 46, 56, 44, 44, 52, 38, 46, 36, 49, 35, 44, 59, 65, 65, 56, 66, 53, 61, 52, 51, 48, 54, 49, 49, 61, NA, NA, 68, 44, 40, 27, 28, 25, 24, 24), .Tsp = c(1945, 1974.75, 4), class = 'ts')); .Internal(which.min(argv[[1]]))"); } @Test public void testwhichmin8() { - assertEval(Ignored.Unknown, "argv <- structure(list(x = c(NA, NA, Inf)), .Names = 'x');do.call('which.min', argv)"); + assertEval("argv <- structure(list(x = c(NA, NA, Inf)), .Names = 'x');do.call('which.min', argv)"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInteropEval.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java similarity index 79% rename from com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInteropEval.java rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java index f866e6f2e6f40e52d0b39934bb32c6aeef5dc77e..0f8ad2f8dd8531ed611b23c3a89d9173f3f1d0fe 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInteropEval.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java @@ -26,7 +26,7 @@ import org.junit.Test; import com.oracle.truffle.r.test.TestBase; -public class TestInteropEval extends TestBase { +public class TestInterop extends TestBase { @Test public void testInteropEval() { @@ -36,4 +36,12 @@ public class TestInteropEval extends TestBase { assertEvalFastR(".fastr.interop.eval('application/x-r', 'TRUE')", "TRUE"); assertEvalFastR(".fastr.interop.eval('application/x-r', 'as.character(123)')", "as.character(123)"); } + + @Test + public void testInteropExport() { + assertEvalFastR(".fastr.interop.export('foo', 14 + 2)", "invisible()"); + assertEvalFastR(".fastr.interop.export('foo', 'foo')", "invisible()"); + assertEvalFastR(".fastr.interop.export('foo', 1:100)", "invisible()"); + assertEvalFastR(".fastr.interop.export('foo', new.env())", "invisible()"); + } }