diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index 94ed95a323a79511e84ffc81b2a865a7a16a9db0..8548fd442c15ecd31ca37bedcb274c3f4eeb39d7 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -64,7 +64,6 @@ import com.oracle.truffle.r.runtime.RCmdOptions.RCmdOption;
 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.RInternalSourceDescriptions;
 import com.oracle.truffle.r.runtime.RParserFactory;
 import com.oracle.truffle.r.runtime.RProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
@@ -209,7 +208,7 @@ final class REngine implements Engine, Engine.Timings {
             }
             // Should this print the result?
             try {
-                parseAndEval(RSource.fromText(call, RInternalSourceDescriptions.STARTUP_SHUTDOWN), globalFrame, false);
+                parseAndEval(RSource.fromTextInternal(call, RSource.Internal.STARTUP_SHUTDOWN), globalFrame, false);
             } catch (ParseException e) {
                 throw new RInternalError(e, "error while parsing startup function");
             }
@@ -242,7 +241,7 @@ final class REngine implements Engine, Engine.Timings {
         try {
             Object lastValue = RNull.instance;
             for (RSyntaxNode node : list) {
-                RootCallTarget callTarget = doMakeCallTarget(node.asRNode(), RInternalSourceDescriptions.REPL_WRAPPER, printResult, true);
+                RootCallTarget callTarget = doMakeCallTarget(node.asRNode(), RSource.Internal.REPL_WRAPPER.string, printResult, true);
                 lastValue = callTarget.call(frame);
             }
             return lastValue;
@@ -300,7 +299,7 @@ final class REngine implements Engine, Engine.Timings {
         @SuppressWarnings("unchecked") @Child private FindContextNode<RContext> findContext = (FindContextNode<RContext>) TruffleRLanguage.INSTANCE.actuallyCreateFindContextNode();
 
         PolyglotEngineRootNode(List<RSyntaxNode> statements) {
-            super(TruffleRLanguage.class, SourceSection.createUnavailable("repl", RInternalSourceDescriptions.REPL_WRAPPER), new FrameDescriptor());
+            super(TruffleRLanguage.class, SourceSection.createUnavailable("repl", RSource.Internal.REPL_WRAPPER.string), new FrameDescriptor());
             this.statements = statements;
         }
 
@@ -317,7 +316,7 @@ final class REngine implements Engine, Engine.Timings {
             try {
                 Object lastValue = RNull.instance;
                 for (RSyntaxNode node : statements) {
-                    RootCallTarget callTarget = doMakeCallTarget(node.asRNode(), RInternalSourceDescriptions.REPL_WRAPPER, true, true);
+                    RootCallTarget callTarget = doMakeCallTarget(node.asRNode(), RSource.Internal.REPL_WRAPPER.string, true, true);
                     lastValue = callTarget.call(newContext.stateREnvironment.getGlobalFrame());
                 }
                 return lastValue;
@@ -376,7 +375,7 @@ final class REngine implements Engine, Engine.Timings {
         if (n instanceof ConstantNode) {
             return ((ConstantNode) n).getValue();
         }
-        RootCallTarget callTarget = doMakeCallTarget(n, EVAL_FUNCTION_NAME, false, false);
+        RootCallTarget callTarget = doMakeCallTarget(n, RSource.Internal.EVAL_WRAPPER.string, false, false);
         return callTarget.call(frame);
     }
 
@@ -402,7 +401,7 @@ final class REngine implements Engine, Engine.Timings {
         // we need to copy the node, otherwise it (and its children) will specialized to a specific
         // frame descriptor and will fail on subsequent re-executions
         RSyntaxNode n = RContext.getASTBuilder().process(exprRep);
-        RootCallTarget callTarget = doMakeCallTarget(n.asRNode(), EVAL_FUNCTION_NAME, false, false);
+        RootCallTarget callTarget = doMakeCallTarget(n.asRNode(), RSource.Internal.EVAL_WRAPPER.string, false, false);
         return evalTarget(callTarget, caller, envir);
     }
 
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 f530a95f4a555018d359fb57490f8f1daef8c891..1cc9f5502c982708473f2bfa859f3c34486382a9 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
@@ -447,7 +447,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
 
     @Override
     public void setFunctionName(RootNode node, String name) {
-        ((FunctionDefinitionNode) node).setDescription(name);
+        ((FunctionDefinitionNode) node).setName(name);
     }
 
     @Override
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java
index 3dca9591b06ab35ffaa1a8af64fc0bf1e73f400f..0c5cdcd86f9305b26df4fac1ccff5bb2c7ba34c0 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java
@@ -27,7 +27,7 @@ import java.io.IOException;
 import java.io.PrintWriter;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.r.runtime.RInternalSourceDescriptions;
+import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.Utils;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -115,7 +115,7 @@ class JLineConsoleHandler implements ConsoleHandler {
 
     @Override
     public String getInputDescription() {
-        return RInternalSourceDescriptions.SHELL_INPUT;
+        return RSource.Internal.SHELL_INPUT.string;
     }
 
     @Override
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 318e42ae6647257c8346cf2e7db592a8ea043f49..3911f4468da9e666304337ef8daead8ddaa8ec5c 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
@@ -52,7 +52,6 @@ import com.oracle.truffle.r.nodes.builtin.base.Quit;
 import com.oracle.truffle.r.runtime.BrowserQuitException;
 import com.oracle.truffle.r.runtime.RCmdOptions;
 import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.RInternalSourceDescriptions;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.Utils;
@@ -139,7 +138,7 @@ public class RCommand {
             if (!options.getBoolean(SLAVE)) {
                 options.setValue(NO_SAVE, true);
             }
-            consoleHandler = new StringConsoleHandler(exprs, System.out, RInternalSourceDescriptions.EXPRESSION_INPUT);
+            consoleHandler = new StringConsoleHandler(exprs, System.out, RSource.Internal.EXPRESSION_INPUT.string);
         } else {
             /*
              * GnuR behavior differs from the manual entry for {@code interactive} in that {@code
@@ -172,8 +171,8 @@ public class RCommand {
         return ContextInfo.create(options, ContextKind.SHARE_NOTHING, null, consoleHandler);
     }
 
-    private static final Source GET_ECHO = RSource.fromText("invisible(getOption('echo'))", RInternalSourceDescriptions.GET_ECHO);
-    private static final Source QUIT_EOF = RSource.fromText("quit(\"default\", 0L, TRUE)", RInternalSourceDescriptions.QUIT_EOF);
+    private static final Source GET_ECHO = RSource.fromTextInternal("invisible(getOption('echo'))", RSource.Internal.GET_ECHO);
+    private static final Source QUIT_EOF = RSource.fromTextInternal("quit(\"default\", 0L, TRUE)", RSource.Internal.QUIT_EOF);
 
     /**
      * The read-eval-print loop, which can take input from a console, command line expression or a
@@ -187,7 +186,7 @@ public class RCommand {
      * exiting. So,in either case, we never return.
      */
     static void readEvalPrint(ContextInfo info) {
-        PolyglotEngine vm = info.apply(PolyglotEngine.newBuilder()).build();
+        PolyglotEngine vm = info.createVM();
         ConsoleHandler consoleHandler = info.getConsoleHandler();
         try {
             // console.println("initialize time: " + (System.currentTimeMillis() - start));
@@ -207,7 +206,7 @@ public class RCommand {
 
                     String continuePrompt = getContinuePrompt();
                     StringBuffer sb = new StringBuffer(input);
-                    Source source = RSource.fromText(sb.toString(), RInternalSourceDescriptions.SHELL_INPUT);
+                    Source source = RSource.fromTextInternal(sb.toString(), RSource.Internal.SHELL_INPUT);
                     while (true) {
                         /*
                          * N.B. As of Truffle rev 371045b1312d412bafa29882e6c3f7bfe6c0f8f1, only
@@ -225,7 +224,7 @@ public class RCommand {
                                 throw new EOFException();
                             }
                             sb.append(additionalInput);
-                            source = RSource.fromText(sb.toString(), RInternalSourceDescriptions.SHELL_INPUT);
+                            source = RSource.fromTextInternal(sb.toString(), RSource.Internal.SHELL_INPUT);
                             // The only continuation in the while loop
                             continue;
                         } catch (ParseException e) {
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
new file mode 100644
index 0000000000000000000000000000000000000000..d03f663b1151eaae9a39bdecede4f62e9996a80e
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/Rprof.java
@@ -0,0 +1,236 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.function.Function;
+
+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.frame.VirtualFrame;
+import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
+import com.oracle.truffle.api.instrumentation.EventContext;
+import com.oracle.truffle.api.instrumentation.ExecutionEventListener;
+import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
+import com.oracle.truffle.api.instrumentation.StandardTags;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode;
+import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
+import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation;
+import com.oracle.truffle.r.runtime.RArguments;
+import com.oracle.truffle.r.runtime.RCaller;
+import com.oracle.truffle.r.runtime.RError;
+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.RNull;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.instrument.InstrumentationState.RprofState;
+import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
+
+public abstract class Rprof extends RExternalBuiltinNode.Arg8 {
+
+    @SuppressWarnings("unused")
+    @Specialization
+    public Object doRprof(RAbstractStringVector filenameVec, byte appendL, double intervalD, byte memProfilingL,
+                    byte gcProfilingL, byte lineProfilingL, int numFiles, int bufSize) {
+        if (!RContext.getInstance().isInitial()) {
+            throw RError.error(this, RError.Message.GENERIC, "profiling not supported in created contexts");
+        }
+        RprofState profState = RContext.getInstance().stateInstrumentation.getRprof();
+        String filename = filenameVec.getDataAt(0);
+        if (filename.length() == 0) {
+            // disable
+            endProfiling();
+        } else {
+            // enable
+            if (profState.out() != null) {
+                endProfiling();
+            }
+            boolean append = RRuntime.fromLogical(appendL);
+            boolean memProfiling = RRuntime.fromLogical(memProfilingL);
+            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");
+                }
+                // 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));
+                profileThread.start();
+            } catch (IOException ex) {
+                throw RError.error(this, RError.Message.GENERIC, String.format("Rprof: cannot open profile file '%s'", filename));
+            }
+        }
+        return RNull.instance;
+    }
+
+    private static void endProfiling() {
+        RprofState profState = RContext.getInstance().stateInstrumentation.getRprof();
+        ProfileThread profileThread = (ProfileThread) profState.profileThread();
+        profileThread.running = false;
+        HashMap<String, Integer> fileMap = null;
+        PrintWriter out = profState.out();
+        StatementListener statementListener = (StatementListener) profState.statementListener();
+        if (profState.lineProfiling()) {
+            out.print("line profiling: ");
+        }
+        out.printf("sample.interval=%d\n", profState.intervalInMillis() * 1000);
+        if (profState.lineProfiling()) {
+            // scan stacks to find files
+            fileMap = new HashMap<>();
+            int fileIndex = 0;
+            for (ArrayList<RSyntaxNode> intervalStack : statementListener.intervalStacks) {
+                for (RSyntaxNode node : intervalStack) {
+                    String path = getPath(node);
+                    if (path != null && fileMap.get(path) == null) {
+                        fileMap.put(path, ++fileIndex);
+                        out.printf("#File %d: %s\n", fileIndex, path);
+                    }
+                }
+            }
+        }
+        for (ArrayList<RSyntaxNode> intervalStack : statementListener.intervalStacks) {
+            for (RSyntaxNode node : intervalStack) {
+                RootNode rootNode = node.asRNode().getRootNode();
+                if (rootNode instanceof FunctionDefinitionNode) {
+                    String name = rootNode.getName();
+                    if (profState.lineProfiling()) {
+                        Integer fileIndex = fileMap.get(getPath(node));
+                        if (fileIndex != null) {
+                            out.printf("%d#%d ", fileIndex, node.getSourceSection().getStartLine());
+                        }
+                    }
+                    out.printf("\"%s\" ", name);
+                }
+            }
+            out.println();
+        }
+        out.close();
+    }
+
+    private static String getPath(RSyntaxNode node) {
+        Source source = node.getSourceSection().getSource();
+        String path = RSource.getPath(source);
+        return path;
+    }
+
+    private static final class ProfileThread extends Thread {
+        private final long interval;
+        private final StatementListener statementListener;
+        private volatile boolean running = true;
+
+        private ProfileThread(long interval, StatementListener statementListener) {
+            this.interval = interval;
+            this.statementListener = statementListener;
+        }
+
+        @Override
+        public void run() {
+            while (running) {
+                try {
+                    Thread.sleep(interval);
+                    statementListener.intervalElapsed();
+                } catch (InterruptedException ex) {
+
+                }
+            }
+        }
+
+    }
+
+    /**
+     * 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 ArrayList<ArrayList<RSyntaxNode>> intervalStacks = new ArrayList<>();
+        private volatile boolean newInterval;
+
+        private StatementListener() {
+            SourceSectionFilter.Builder builder = SourceSectionFilter.newBuilder();
+            builder.tagIs(StandardTags.StatementTag.class);
+            SourceSectionFilter filter = builder.build();
+            RInstrumentation.getInstrumenter().attachListener(filter, this);
+        }
+
+        private void intervalElapsed() {
+            newInterval = true;
+        }
+
+        @Override
+        public void onEnter(EventContext context, VirtualFrame frame) {
+            if (newInterval) {
+                /* context tells here we are now, frame provides callers. */
+                final ArrayList<RSyntaxNode> stack = new ArrayList<>();
+                stack.add((RSyntaxNode) context.getInstrumentedNode());
+                collectStack(stack);
+                intervalStacks.add(stack);
+                newInterval = false;
+            }
+        }
+
+        @TruffleBoundary
+        private static void collectStack(final ArrayList<RSyntaxNode> stack) {
+            Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() {
+
+                @Override
+                public Object apply(Frame f) {
+                    RCaller call = RArguments.getCall(f);
+                    if (call != null && call.isValidCaller()) {
+                        while (call.isPromise()) {
+                            call = call.getParent();
+                        }
+                        RSyntaxNode syntaxNode = call.getSyntaxNode();
+                        stack.add(syntaxNode);
+                    }
+                    return null;
+                }
+
+            });
+        }
+
+        @Override
+        public void onReturnValue(EventContext context, VirtualFrame frame, Object result) {
+        }
+
+        @Override
+        public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) {
+        }
+
+    }
+}
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 fad9160130ca1186ab100605899d2220ea87fe66..d0e3a8c0b290f4475b190a19221974a6ec1ebd32 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
@@ -44,14 +44,12 @@ import com.oracle.truffle.r.nodes.builtin.base.foreign.DotC;
 import com.oracle.truffle.r.nodes.builtin.base.foreign.DotCNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.foreign.ForeignFunctions;
 import com.oracle.truffle.r.nodes.builtin.base.foreign.ForeignFunctionsFactory;
-import com.oracle.truffle.r.nodes.builtin.fastr.FastRCallCounting;
-import com.oracle.truffle.r.nodes.builtin.fastr.FastRCallCountingFactory;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRContext;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRContextFactory;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRDebug;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRDebugNodeGen;
-import com.oracle.truffle.r.nodes.builtin.fastr.FastRFunctionTimer;
-import com.oracle.truffle.r.nodes.builtin.fastr.FastRFunctionTimerFactory;
+import com.oracle.truffle.r.nodes.builtin.fastr.FastRFunctionProfiler;
+import com.oracle.truffle.r.nodes.builtin.fastr.FastRFunctionProfilerFactory;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRIdentity;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRIdentityNodeGen;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRInspect;
@@ -277,8 +275,6 @@ public class BasePackage extends RBuiltinPackage {
         add(WithVisible.class, WithVisibleNodeGen::create);
         add(Exists.class, ExistsNodeGen::create);
         add(Expression.class, ExpressionNodeGen::create);
-        add(FastRCallCounting.CreateCallCounter.class, FastRCallCountingFactory.CreateCallCounterNodeGen::create);
-        add(FastRCallCounting.GetCallCounter.class, FastRCallCountingFactory.GetCallCounterNodeGen::create);
         add(FastRContext.CloseChannel.class, FastRContextFactory.CloseChannelNodeGen::create);
         add(FastRContext.Create.class, FastRContextFactory.CreateNodeGen::create);
         add(FastRContext.CreateChannel.class, FastRContextFactory.CreateChannelNodeGen::create);
@@ -293,8 +289,10 @@ public class BasePackage extends RBuiltinPackage {
         add(FastRContext.Join.class, FastRContextFactory.JoinNodeGen::create);
         add(FastrDqrls.class, FastrDqrlsNodeGen::create);
         add(FastRDebug.class, FastRDebugNodeGen::create);
-        add(FastRFunctionTimer.CreateFunctionTimer.class, FastRFunctionTimerFactory.CreateFunctionTimerNodeGen::create);
-        add(FastRFunctionTimer.GetFunctionTimer.class, FastRFunctionTimerFactory.GetFunctionTimerNodeGen::create);
+        add(FastRFunctionProfiler.Create.class, FastRFunctionProfilerFactory.CreateNodeGen::create);
+        add(FastRFunctionProfiler.Get.class, FastRFunctionProfilerFactory.GetNodeGen::create);
+        add(FastRFunctionProfiler.Reset.class, FastRFunctionProfilerFactory.ResetNodeGen::create);
+        add(FastRFunctionProfiler.Clear.class, FastRFunctionProfilerFactory.ClearNodeGen::create);
         add(FastRIdentity.class, FastRIdentityNodeGen::create);
         add(FastRInspect.class, FastRInspectNodeGen::create);
         add(FastRInterop.Eval.class, FastRInteropFactory.EvalNodeGen::create);
@@ -526,6 +524,7 @@ public class BasePackage extends RBuiltinPackage {
         add(Row.class, RowNodeGen::create);
         add(RowMeans.class, RowMeansNodeGen::create);
         add(RowSums.class, RowSumsNodeGen::create);
+        add(RowsumFunctions.Rowsum.class, RowsumFunctionsFactory.RowsumNodeGen::create);
         add(S3DispatchFunctions.NextMethod.class, S3DispatchFunctionsFactory.NextMethodNodeGen::create);
         add(S3DispatchFunctions.UseMethod.class, S3DispatchFunctionsFactory.UseMethodNodeGen::create);
         add(Sample.class, SampleNodeGen::create);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
index 4bb4174be7632353f08c124180ef9ed97e6c638a..3c8f0d6b5588e442fa9d75712ccfb47e63032a3e 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java
@@ -62,7 +62,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 @RBuiltin(name = "lapply", kind = INTERNAL, parameterNames = {"X", "FUN"}, splitCaller = true)
 public abstract class Lapply extends RBuiltinNode {
 
-    private static final Source CALL_SOURCE = RSource.fromText("FUN(X[[i]], ...)", "lapply");
+    private static final Source CALL_SOURCE = RSource.fromTextInternal("FUN(X[[i]], ...)", RSource.Internal.LAPPLY);
 
     private final RAttributeProfiles attrProfiles = RAttributeProfiles.create();
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4d26ee3a7562e968f577cd5fdd594e879ac1cdb
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java
@@ -0,0 +1,144 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
+ * Copyright (c) 1997-2015,  The R Core Team
+ * Copyright (c) 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+
+package com.oracle.truffle.r.nodes.builtin.base;
+
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean;
+
+import java.util.HashMap;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.runtime.RBuiltin;
+import com.oracle.truffle.r.runtime.RBuiltinKind;
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RIntVector;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
+import com.oracle.truffle.r.runtime.ops.na.NACheck;
+
+// Translated from main/unique.c
+
+// TODO rowsum_df
+public class RowsumFunctions {
+
+    @RBuiltin(name = "rowsum_matrix", kind = RBuiltinKind.INTERNAL, parameterNames = {"x", "g", "uniqueg", "snarm", "rn"})
+    public abstract static class Rowsum extends RBuiltinNode {
+
+        private final ConditionProfile typeProfile = ConditionProfile.createBinaryProfile();
+        private final NACheck na = NACheck.create();
+
+        @Override
+        protected void createCasts(CastBuilder casts) {
+            casts.arg("x").mustBe(integerValue().or(doubleValue()), RError.Message.ROWSUM_NON_NUMERIC);
+
+            casts.arg("g").asVector();
+
+            casts.arg("uniqueg").asVector();
+
+            casts.arg("snarm").asLogicalVector().findFirst().notNA(RError.Message.INVALID_LOGICAL).map(toBoolean());
+
+            casts.arg("rn").mustBe(stringValue(), RError.Message.ROWSUM_NAMES_NOT_CHAR).asStringVector();
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected Object rowsum(RAbstractVector xv, RAbstractVector g, RAbstractVector uniqueg, boolean narm, RAbstractStringVector rn) {
+            int p = xv.isMatrix() ? xv.getDimensions()[1] : 1;
+            int n = g.getLength();
+            int ng = uniqueg.getLength();
+            HashMap<Object, Integer> table = new HashMap<>();
+            for (int i = 0; i < ng; i++) {
+                // uniqueg has no duplicates (by definition)
+                table.put(uniqueg.getDataAtAsObject(i), i);
+            }
+            int[] matches = new int[n];
+            for (int i = 0; i < n; i++) {
+                Integer hi = table.get(g.getDataAtAsObject(i));
+                matches[i] = xv == null ? 0 : hi + 1;
+            }
+            int offset = 0;
+            int offsetg = 0;
+
+            boolean isInt = xv instanceof RIntVector;
+            RVector result;
+            na.enable(xv);
+            boolean complete = xv.isComplete();
+
+            if (typeProfile.profile(isInt)) {
+                RIntVector xi = (RIntVector) xv;
+                int[] ansi = new int[ng * p];
+                for (int i = 0; i < p; i++) {
+                    for (int j = 0; j < n; j++) {
+                        int midx = matches[j] - 1 + offsetg;
+                        int itmp = ansi[midx];
+                        if (na.check(xi.getDataAt(j + offset))) {
+                            if (!narm) {
+                                ansi[midx] = RRuntime.INT_NA;
+                                complete = RDataFactory.INCOMPLETE_VECTOR;
+                            }
+                        } else if (!na.check(itmp)) {
+                            long dtmp = itmp;
+                            int jtmp = xi.getDataAt(j + offset);
+                            dtmp += jtmp;
+                            if (dtmp < Integer.MIN_VALUE || dtmp > Integer.MAX_VALUE) {
+                                itmp = RRuntime.INT_NA;
+                                complete = RDataFactory.INCOMPLETE_VECTOR;
+                            } else {
+                                itmp += jtmp;
+                            }
+                            ansi[midx] = itmp;
+                        }
+                    }
+                    offset += n;
+                    offsetg += ng;
+                }
+                result = RDataFactory.createIntVector(ansi, complete, new int[]{ng, p});
+            } else {
+                RDoubleVector xd = (RDoubleVector) xv;
+                double[] ansd = new double[ng * p];
+                for (int i = 0; i < p; i++) {
+                    for (int j = 0; j < n; j++) {
+                        int midx = matches[j] - 1 + offsetg;
+                        double dtmp = xd.getDataAt(j + offset);
+                        if (!narm || !Double.isNaN(dtmp)) {
+                            ansd[midx] += dtmp;
+                        }
+                    }
+                    offset += n;
+                    offsetg += ng;
+                }
+                result = RDataFactory.createDoubleVector(ansd, complete, new int[]{ng, p});
+            }
+            Object[] dimNamesData = new Object[2];
+            dimNamesData[0] = rn;
+            RList dn2 = xv.materialize().getDimNames();
+            if (dn2 != null && dn2.getLength() >= 2 && dn2.getDataAt(1) != RNull.instance) {
+                dimNamesData[1] = dn2.getDataAt(1);
+            }
+            RList dimNames = RDataFactory.createList(dimNamesData);
+            result.setDimNames(dimNames);
+            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 45ded5c9169373e32d0615ac29f2fa4c9e7c9df0..341a599ab3100966d00a8cae5e0d361e6d1cf630 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
@@ -97,10 +97,10 @@ public class TraceFunctions {
         @Specialization
         @TruffleBoundary
         protected byte traceOnOff(byte state) {
-            boolean prevState = RContext.getInstance().stateTraceHandling.getTracingState();
+            boolean prevState = RContext.getInstance().stateInstrumentation.getTracingState();
             boolean newState = RRuntime.fromLogical(state);
             if (newState != prevState) {
-                RContext.getInstance().stateTraceHandling.setTracingState(newState);
+                RContext.getInstance().stateInstrumentation.setTracingState(newState);
             }
             return RRuntime.asLogical(prevState);
         }
@@ -108,7 +108,7 @@ public class TraceFunctions {
         @Specialization
         @TruffleBoundary
         protected byte traceOnOff(@SuppressWarnings("unused") RNull state) {
-            return RRuntime.asLogical(RContext.getInstance().stateTraceHandling.getTracingState());
+            return RRuntime.asLogical(RContext.getInstance().stateInstrumentation.getTracingState());
         }
     }
 }
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 63d2a6dc06af300cad8e5583b7514ddf202b7619..c0ec1fa2a2ba4fc2c375c0cb89e8c5648c292a52 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
@@ -60,6 +60,7 @@ import com.oracle.truffle.r.library.utils.CountFields;
 import com.oracle.truffle.r.library.utils.Crc64NodeGen;
 import com.oracle.truffle.r.library.utils.Download;
 import com.oracle.truffle.r.library.utils.MenuNodeGen;
+import com.oracle.truffle.r.library.utils.RprofNodeGen;
 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;
@@ -568,8 +569,9 @@ public class ForeignFunctions {
                     return new Download();
                 case "termsform":
                     return getExternalModelBuiltinNode("termsform");
-                case "unzip":
                 case "Rprof":
+                    return RprofNodeGen.create();
+                case "unzip":
                 case "Rprofmem":
                 case "addhistory":
                 case "loadhistory":
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRCallCounting.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRCallCounting.java
deleted file mode 100644
index 4039faa429afd3aafb46e1409bba4c31c8469d4f..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRCallCounting.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.builtin.fastr;
-
-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.nodes.builtin.RBuiltinNode;
-import com.oracle.truffle.r.nodes.instrumentation.REntryCounters;
-import com.oracle.truffle.r.runtime.RBuiltin;
-import com.oracle.truffle.r.runtime.RBuiltinKind;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RVisibility;
-import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.data.RNull;
-
-public class FastRCallCounting {
-
-    @RBuiltin(name = ".fastr.createcc", visibility = RVisibility.OFF, kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func"})
-    public abstract static class CreateCallCounter extends RBuiltinNode {
-        @Specialization
-        @TruffleBoundary
-        protected RNull createCallCounter(RFunction function) {
-            if (!function.isBuiltin()) {
-                REntryCounters.FunctionListener.installCounter(function);
-            }
-            return RNull.instance;
-        }
-
-        @SuppressWarnings("unused")
-        @Fallback
-        protected Object fallback(Object a1) {
-            throw RError.error(this, RError.Message.INVALID_ARGUMENT, "func");
-        }
-    }
-
-    @RBuiltin(name = ".fastr.getcc", visibility = RVisibility.OFF, kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func"})
-    public abstract static class GetCallCounter extends RBuiltinNode {
-        @Specialization
-        @TruffleBoundary
-        protected Object getCallCount(RFunction function) {
-            if (!function.isBuiltin()) {
-                int entryCount = REntryCounters.FunctionListener.findCounter(function).getEnterCount();
-                if (entryCount < 0) {
-                    throw RError.error(this, RError.Message.GENERIC, "no associated counter");
-                } else {
-                    return entryCount;
-                }
-            }
-            return RNull.instance;
-        }
-
-        @SuppressWarnings("unused")
-        @Fallback
-        protected Object fallback(Object a1) {
-            throw RError.error(this, RError.Message.INVALID_ARGUMENT, "func");
-        }
-    }
-}
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 78ba86e8c541e7816d4d5a8d5dff8179932eb958..b267e8713b6998709e7626fa3859e821d76bde3a 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
@@ -38,7 +38,6 @@ import com.oracle.truffle.r.runtime.RCmdOptions;
 import com.oracle.truffle.r.runtime.RCmdOptions.Client;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.RInternalSourceDescriptions;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.RVisibility;
@@ -123,7 +122,7 @@ public class FastRContext {
             RContext.EvalThread[] threads = new RContext.EvalThread[contexts.getLength()];
             for (int i = 0; i < threads.length; i++) {
                 ContextInfo info = checkContext(contexts.getDataAt(i), this);
-                threads[i] = new RContext.EvalThread(info, RSource.fromText(exprs.getDataAt(i % threads.length), RInternalSourceDescriptions.CONTEXT_EVAL));
+                threads[i] = new RContext.EvalThread(info, RSource.fromTextInternal(exprs.getDataAt(i % threads.length), RSource.Internal.CONTEXT_EVAL));
             }
             for (int i = 0; i < threads.length; i++) {
                 threads[i].start();
@@ -187,7 +186,7 @@ public class FastRContext {
                 RContext.EvalThread[] threads = new RContext.EvalThread[contexts.getLength()];
                 for (int i = 0; i < threads.length; i++) {
                     ContextInfo info = checkContext(contexts.getDataAt(i), this);
-                    threads[i] = new RContext.EvalThread(info, RSource.fromText(exprs.getDataAt(i % threads.length), RInternalSourceDescriptions.CONTEXT_EVAL));
+                    threads[i] = new RContext.EvalThread(info, RSource.fromTextInternal(exprs.getDataAt(i % threads.length), RSource.Internal.CONTEXT_EVAL));
                 }
                 for (int i = 0; i < threads.length; i++) {
                     threads[i].start();
@@ -203,9 +202,9 @@ public class FastRContext {
             } else {
                 for (int i = 0; i < contexts.getLength(); i++) {
                     ContextInfo info = checkContext(contexts.getDataAt(i), this);
-                    PolyglotEngine vm = info.apply(PolyglotEngine.newBuilder()).build();
+                    PolyglotEngine vm = info.createVM();
                     try {
-                        Source source = RSource.fromText(exprs.getDataAt(i % exprs.getLength()), RInternalSourceDescriptions.CONTEXT_EVAL);
+                        Source source = RSource.fromTextInternal(exprs.getDataAt(i % exprs.getLength()), RSource.Internal.CONTEXT_EVAL);
                         PolyglotEngine.Value resultValue = vm.eval(source);
                         results[i] = RContext.EvalThread.createEvalResult(resultValue);
                     } catch (ParseException e) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionProfiler.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionProfiler.java
new file mode 100644
index 0000000000000000000000000000000000000000..977de8fc70a5c51aefd9b21f23c0ab68316a6c81
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionProfiler.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.fastr;
+
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue;
+
+import java.util.ArrayList;
+
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
+import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.nodes.builtin.CastBuilder;
+import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.nodes.instrumentation.RFunctionProfiler;
+import com.oracle.truffle.r.runtime.RBuiltin;
+import com.oracle.truffle.r.runtime.RBuiltinKind;
+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.RVisibility;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RDoubleVector;
+import com.oracle.truffle.r.runtime.data.RFunction;
+import com.oracle.truffle.r.runtime.data.RList;
+import com.oracle.truffle.r.runtime.data.RMissing;
+import com.oracle.truffle.r.runtime.data.RNull;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
+import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
+import com.oracle.truffle.tools.Profiler;
+
+public class FastRFunctionProfiler {
+
+    @RBuiltin(name = ".fastr.profiler.create", visibility = RVisibility.OFF, kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func", "mode"})
+    public abstract static class Create extends RBuiltinNode {
+        private static final int COUNTING = 1;
+        private static final int TIMING = 2;
+
+        @Override
+        public Object[] getDefaultParameterValues() {
+            return new Object[]{RMissing.instance, "counting"};
+        }
+
+        @Override
+        protected void createCasts(CastBuilder casts) {
+            casts.arg("func").mustBe(instanceOf(RFunction.class).or(missingValue()));
+
+            casts.arg("mode").mustBe(stringValue()).asStringVector();
+        }
+
+        private int checkMode(RAbstractStringVector modeVec) {
+            int result = 0;
+            for (int i = 0; i < modeVec.getLength(); i++) {
+                String mode = modeVec.getDataAt(i);
+                switch (mode) {
+                    case "counting":
+                        result |= COUNTING;
+                        break;
+                    case "timing":
+                        result |= TIMING;
+                        break;
+                    default:
+                        throw RError.error(this, RError.Message.GENERIC, "invalid 'mode', one of 'count, timning' expected");
+                }
+            }
+            return result;
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected RNull createFunctionProfiler(RFunction function, RAbstractStringVector modeVec) {
+            int mode = checkMode(modeVec);
+            if (!function.isBuiltin()) {
+                RFunctionProfiler.installTimer(function, (mode & COUNTING) != 0, (mode & TIMING) != 0);
+            } else {
+                throw RError.error(this, RError.Message.GENERIC, "cannot profile builtin functions");
+            }
+            return RNull.instance;
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected RNull createFunctionProfiler(@SuppressWarnings("unused") RMissing value, RAbstractStringVector modeVec) {
+            int mode = checkMode(modeVec);
+            RFunctionProfiler.installTimer(null, (mode & COUNTING) != 0, (mode & TIMING) != 0);
+            return RNull.instance;
+        }
+
+    }
+
+    @RBuiltin(name = ".fastr.profiler.get", kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func", "threshold", "scale"})
+    public abstract static class Get extends RBuiltinNode {
+
+        private static final RStringVector COLNAMES = RDataFactory.createStringVector(new String[]{"Invocations", "TotalTime", "SelfTime"}, RDataFactory.COMPLETE_VECTOR);
+        private static final RStringVector ROWNAMES = RDataFactory.createStringVector(new String[]{"Combined", "Interpreted", "Compiled"}, RDataFactory.COMPLETE_VECTOR);
+        private static final int NCOLS = 3;
+        private static final int NROWS = 3;
+
+        @Override
+        protected void createCasts(CastBuilder casts) {
+            casts.arg("func").mustBe(instanceOf(RFunction.class).or(missingValue()));
+
+            casts.arg("threshold").mustBe(integerValue().or(doubleValue())).asDoubleVector();
+
+            casts.arg("scale").mustBe(stringValue()).asStringVector();
+        }
+
+        @Override
+        public Object[] getDefaultParameterValues() {
+            return new Object[]{RMissing.instance, 0.0, "nanos"};
+        }
+
+        private void checkScale(String s) throws RError {
+            if (!(s.equals("nanos") || s.equals("millis") || s.equals("micros") || s.equals("secs"))) {
+                throw RError.error(this, RError.Message.GENERIC, "invalid scale: one of 'nanos, micros, millis, secs' expected");
+            }
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected Object get(@SuppressWarnings("unused") RMissing value, RAbstractDoubleVector thresholdVec, RAbstractStringVector scaleVec) {
+            String scale = scaleVec.getDataAt(0);
+            checkScale(scale);
+            double threshold = thresholdVec.getDataAt(0);
+            Profiler.Counter[] counters = RFunctionProfiler.getCounters();
+            if (counters == null) {
+                throw RError.error(this, RError.Message.GENERIC, "profiling not enabled");
+            }
+            ArrayList<RDoubleVector> dataList = new ArrayList<>();
+            ArrayList<String> nameList = new ArrayList<>();
+            for (int i = 0; i < counters.length; i++) {
+                Profiler.Counter counter = counters[i];
+                if (threshold > 0.0) {
+                    long time = counter.getTotalTime(Profiler.Counter.TimeKind.INTERPRETED_AND_COMPILED);
+                    if (time <= threshold) {
+                        continue;
+                    }
+                }
+                dataList.add(getFunctionMatrix(counter, scale));
+                nameList.add(counter.getName());
+            }
+            Object[] data = new Object[dataList.size()];
+            String[] names = new String[nameList.size()];
+            return RDataFactory.createList(dataList.toArray(data), RDataFactory.createStringVector(nameList.toArray(names), RDataFactory.COMPLETE_VECTOR));
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected Object get(RFunction function, @SuppressWarnings("unused") RAbstractDoubleVector threshold, RAbstractStringVector scaleVec) {
+            String scale = scaleVec.getDataAt(0);
+            checkScale(scale);
+            if (!function.isBuiltin()) {
+                Profiler.Counter counter = RFunctionProfiler.getCounter(function);
+                if (counter == null) {
+                    throw RError.error(this, RError.Message.GENERIC, "profiling not enabled");
+                } else {
+                    return getFunctionMatrix(counter, scale);
+                }
+            } else {
+                throw RError.error(this, RError.Message.GENERIC, "cannot profile builtin functions");
+            }
+        }
+
+        private static RDoubleVector getFunctionMatrix(Profiler.Counter counter, String scale) {
+            double[] data = new double[NROWS * NCOLS];
+            boolean isTiming = RFunctionProfiler.isTiming();
+            boolean complete = isTiming ? RDataFactory.COMPLETE_VECTOR : RDataFactory.INCOMPLETE_VECTOR;
+            for (int r = 0; r < NROWS; r++) {
+                Profiler.Counter.TimeKind timeKind = Profiler.Counter.TimeKind.values()[r];
+                for (int c = 0; c < NCOLS; c++) {
+                    int index = c * NROWS + r;
+                    double value = 0.0;
+                    switch (c) {
+                        case 0:
+                            value = counter.getInvocations(timeKind);
+                            break;
+                        case 1:
+                            value = isTiming ? counter.getTotalTime(timeKind) : RRuntime.DOUBLE_NA;
+                            break;
+                        case 2:
+                            value = isTiming ? counter.getSelfTime(timeKind) : RRuntime.DOUBLE_NA;
+                    }
+                    data[index] = c == 0 ? value : scaledTime(scale, value);
+                }
+            }
+            RDoubleVector result = RDataFactory.createDoubleVector(data, complete, new int[]{3, 3});
+            Object[] dimNamesData = new Object[2];
+            dimNamesData[0] = ROWNAMES;
+            dimNamesData[1] = COLNAMES;
+            RList dimNames = RDataFactory.createList(dimNamesData);
+            result.setDimNames(dimNames);
+            return result;
+        }
+
+        private static double scaledTime(String scale, double time) {
+            if (RRuntime.isNA(time)) {
+                return time;
+            }
+            switch (scale) {
+                case "nanos":
+                    return time;
+                case "micros":
+                    return time / 1000.0;
+                case "millis":
+                    return time / 1000000.0;
+                case "secs":
+                    return time / 1000000000.0;
+                default:
+                    throw RInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    @RBuiltin(name = ".fastr.profiler.reset", kind = RBuiltinKind.PRIMITIVE, parameterNames = {}, visibility = RVisibility.OFF)
+    public abstract static class Reset extends RBuiltinNode {
+        @Specialization
+        @TruffleBoundary
+        protected Object reset() {
+            RFunctionProfiler.reset();
+            return RNull.instance;
+        }
+    }
+
+    @RBuiltin(name = ".fastr.profiler.clear", kind = RBuiltinKind.PRIMITIVE, parameterNames = {}, visibility = RVisibility.OFF)
+    public abstract static class Clear extends RBuiltinNode {
+        @Specialization
+        @TruffleBoundary
+        protected Object clear() {
+            RFunctionProfiler.clear();
+            return RNull.instance;
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionTimer.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionTimer.java
deleted file mode 100644
index 1a967545babb8328c37243b0ba4d3f4370188406..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRFunctionTimer.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.builtin.fastr;
-
-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.nodes.builtin.RBuiltinNode;
-import com.oracle.truffle.r.nodes.instrumentation.RNodeTimer;
-import com.oracle.truffle.r.runtime.RBuiltin;
-import com.oracle.truffle.r.runtime.RBuiltinKind;
-import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RVisibility;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
-import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.data.RMissing;
-import com.oracle.truffle.r.runtime.data.RNull;
-import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
-
-public class FastRFunctionTimer {
-
-    @RBuiltin(name = ".fastr.createtimer", visibility = RVisibility.OFF, kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func"})
-    public abstract static class CreateFunctionTimer extends RBuiltinNode {
-        @Specialization
-        @TruffleBoundary
-        protected RNull createFunctionTimer(RFunction function) {
-            if (!function.isBuiltin()) {
-                RNodeTimer.StatementListener.installTimer(function);
-            }
-            return RNull.instance;
-        }
-
-        @SuppressWarnings("unused")
-        @Fallback
-        protected Object fallback(Object a1) {
-            throw RError.error(this, RError.Message.INVALID_ARGUMENT, "func");
-        }
-    }
-
-    @RBuiltin(name = ".fastr.gettimer", kind = RBuiltinKind.PRIMITIVE, parameterNames = {"func", "scale"})
-    public abstract static class GetFunctionTimer extends RBuiltinNode {
-        @Override
-        public Object[] getDefaultParameterValues() {
-            return new Object[]{RMissing.instance, "nanos"};
-        }
-
-        @Specialization
-        @TruffleBoundary
-        protected Object getFunctionTimer(RFunction function, RAbstractStringVector scale) {
-            if (!function.isBuiltin()) {
-                long timeInfo = RNodeTimer.StatementListener.findTimer(function);
-                if (timeInfo < 0) {
-                    throw RError.error(this, RError.Message.GENERIC, "no associated timer");
-                } else {
-                    double timeVal = timeInfo;
-                    switch (scale.getDataAt(0)) {
-                        case "nanos":
-                            break;
-                        case "micros":
-                            timeVal = timeVal / 1000.0;
-                            break;
-                        case "millis":
-                            timeVal = timeVal / 1000000.0;
-                            break;
-                        case "secs":
-                            timeVal = timeVal / 1000000000.0;
-                            break;
-                        default:
-                            throw RError.error(this, RError.Message.GENERIC, "invalid scale: one of 'nanos, micros, millis, secs' expected");
-                    }
-                    return RDataFactory.createDoubleVectorFromScalar(timeVal);
-                }
-            }
-            return RNull.instance;
-        }
-
-        @SuppressWarnings("unused")
-        @Fallback
-        protected Object fallback(Object a1, Object a2) {
-            throw RError.error(this, RError.Message.INVALID_ARGUMENT, "func");
-        }
-    }
-}
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 b8d8a8ead92a39ac7b850f4f4a5e1a8c68921384..06daa8d3da89d6e579c97fd7240d2b04f651bc36 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
@@ -35,7 +35,6 @@ import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.RVisibility;
-import com.oracle.truffle.r.runtime.context.Engine;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RTypedValue;
@@ -47,7 +46,7 @@ public class FastRInterop {
         @Specialization
         @TruffleBoundary
         protected Object interopEval(Object mimeType, Object source) {
-            Source sourceObject = RSource.fromText(RRuntime.asString(source), Engine.EVAL_FUNCTION_NAME, RRuntime.asString(mimeType));
+            Source sourceObject = RSource.fromTextInternal(RRuntime.asString(source), RSource.Internal.EVAL_WRAPPER, RRuntime.asString(mimeType));
 
             CallTarget callTarget;
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
index 7626ff551b9040dbb647d68a5786b3ab193f2228..5534c5b861619ba884e708bda29cf06c25493237 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java
@@ -57,7 +57,6 @@ public abstract class BrowserInteractNode extends RNode {
     public static final int CONTINUE = 2;
     public static final int FINISH = 3;
 
-    private static final String BROWSER_SOURCE = "<browser_input>";
     private static String lastEmptyLineCommand = "n";
 
     /**
@@ -128,7 +127,7 @@ public abstract class BrowserInteractNode extends RNode {
 
                     default:
                         try {
-                            RContext.getEngine().parseAndEval(RSource.fromText(input, BROWSER_SOURCE), mFrame, true);
+                            RContext.getEngine().parseAndEval(RSource.fromTextInternal(input, RSource.Internal.BROWSER_INPUT), mFrame, true);
                         } catch (ReturnException e) {
                             exitMode = NEXT;
                             break LW;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java
index ad0d6d9ee5f4c5c26987732384ed6ef725f33c26..76c6e1167e48c003fdb5ee32c9fb597514912321 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java
@@ -24,7 +24,6 @@ package com.oracle.truffle.r.nodes.builtin.helpers;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.WeakHashMap;
 
 import com.oracle.truffle.api.Assumption;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
@@ -44,11 +43,10 @@ import com.oracle.truffle.r.nodes.control.AbstractLoopNode;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation;
 import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags;
-import com.oracle.truffle.r.runtime.FunctionUID;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RDeparse;
 import com.oracle.truffle.r.runtime.RError;
-import com.oracle.truffle.r.runtime.RInternalSourceDescriptions;
+import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.conn.StdConnections;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
 import com.oracle.truffle.r.runtime.context.RContext;
@@ -102,11 +100,6 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNodeVisitor;
  */
 public class DebugHandling {
 
-    /**
-     * Records all functions that have debug listeners installed.
-     */
-    private static final WeakHashMap<FunctionUID, FunctionStatementsEventListener> listenerMap = new WeakHashMap<>();
-
     /**
      * This flag is used to (temporarily) disable all debugging across calls that are used
      * internally in the implementation.
@@ -117,8 +110,7 @@ public class DebugHandling {
      * Attach the DebugHandling instrument to the FunctionStatementsNode and all syntactic nodes.
      */
     public static boolean enableDebug(RFunction func, Object text, Object condition, boolean once) {
-        FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode();
-        FunctionStatementsEventListener fbr = listenerMap.get(fdn.getUID());
+        FunctionStatementsEventListener fbr = getFunctionStatementsEventListener(func);
         if (fbr == null) {
             attachDebugHandler(func, text, condition, once);
         } else {
@@ -128,7 +120,7 @@ public class DebugHandling {
     }
 
     public static boolean undebug(RFunction func) {
-        FunctionStatementsEventListener fbr = listenerMap.get(((FunctionDefinitionNode) func.getRootNode()).getUID());
+        FunctionStatementsEventListener fbr = getFunctionStatementsEventListener(func);
         if (fbr == null) {
             return false;
         } else {
@@ -138,10 +130,18 @@ public class DebugHandling {
     }
 
     public static boolean isDebugged(RFunction func) {
-        FunctionStatementsEventListener fser = listenerMap.get(((FunctionDefinitionNode) func.getRootNode()).getUID());
+        FunctionStatementsEventListener fser = getFunctionStatementsEventListener(func);
         return fser != null && !fser.disabled();
     }
 
+    private static FunctionStatementsEventListener getFunctionStatementsEventListener(RFunction func) {
+        return (FunctionStatementsEventListener) RContext.getInstance().stateInstrumentation.getDebugListener(RInstrumentation.getSourceSection(func));
+    }
+
+    private static FunctionStatementsEventListener getFunctionStatementsEventListener(FunctionDefinitionNode fdn) {
+        return (FunctionStatementsEventListener) RContext.getInstance().stateInstrumentation.getDebugListener(fdn.getSourceSection());
+    }
+
     /**
      * Disables/enables debugging globally. Intended to be used for short period, typically while
      * executing functions used internally by the implementation.
@@ -186,7 +186,7 @@ public class DebugHandling {
     }
 
     private static void ensureSingleStep(FunctionDefinitionNode fdn) {
-        FunctionStatementsEventListener fser = listenerMap.get(fdn.getUID());
+        FunctionStatementsEventListener fser = getFunctionStatementsEventListener(fdn);
         if (fser == null) {
             // attach a "once" listener
             fser = attachDebugHandler(fdn, null, null, true);
@@ -262,7 +262,7 @@ public class DebugHandling {
                          * will everything get invalidated?
                          */
                         stepIntoInstrument = RInstrumentation.getInstrumenter().attachListener(SourceSectionFilter.newBuilder().tagIs(StandardTags.RootTag.class).build(),
-                                        new StepIntoInstrumentListener(listenerMap.get(functionDefinitionNode.getUID())));
+                                        new StepIntoInstrumentListener(getFunctionStatementsEventListener(functionDefinitionNode)));
                     }
                     break;
                 case BrowserInteractNode.CONTINUE:
@@ -275,7 +275,7 @@ public class DebugHandling {
                     AbstractLoopNode loopNode = inLoop(node);
                     if (loopNode != null) {
                         // Have to disable just the body of the loop
-                        FunctionStatementsEventListener fser = listenerMap.get(functionDefinitionNode.getUID());
+                        FunctionStatementsEventListener fser = getFunctionStatementsEventListener(functionDefinitionNode);
                         fser.setFinishing(loopNode);
                     } else {
                         doContinue();
@@ -285,7 +285,7 @@ public class DebugHandling {
         }
 
         private void doContinue() {
-            FunctionStatementsEventListener fser = listenerMap.get(functionDefinitionNode.getUID());
+            FunctionStatementsEventListener fser = getFunctionStatementsEventListener(functionDefinitionNode);
             fser.setContinuing();
         }
 
@@ -323,7 +323,7 @@ public class DebugHandling {
 
         FunctionStatementsEventListener(FunctionDefinitionNode functionDefinitionNode, Object text, Object condition, boolean once) {
             super(functionDefinitionNode, text, condition);
-            listenerMap.put(functionDefinitionNode.getUID(), this);
+            RContext.getInstance().stateInstrumentation.putDebugListener(functionDefinitionNode.getSourceSection(), this);
             statementListener = new StatementEventListener(functionDefinitionNode, text, condition);
             this.once = once;
         }
@@ -447,8 +447,8 @@ public class DebugHandling {
             consoleHandler.print("debug: ");
         } else {
             SourceSection source = ((RBaseNode) node).asRSyntaxNode().getSourceSection();
-            String path = source.getSource().getPath();
-            if (path == null || RInternalSourceDescriptions.isInternal(path)) {
+            String path = RSource.getPath(source.getSource());
+            if (path == null) {
                 path = "";
             }
             consoleHandler.print("debug at " + path + "#" + source.getStartLine() + ": ");
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java
index 1418ab39e90504bb45fd8867c7bec30ed9562d02..798fd225d0eb4101e79b8ed1b90b3722c0577653 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/TraceHandling.java
@@ -33,7 +33,6 @@ import com.oracle.truffle.api.instrumentation.ExecutionEventListener;
 import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
 import com.oracle.truffle.api.instrumentation.StandardTags;
 import com.oracle.truffle.api.utilities.CyclicAssumption;
-import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation;
 import com.oracle.truffle.r.runtime.FastROptions;
 import com.oracle.truffle.r.runtime.RArguments;
@@ -52,9 +51,8 @@ import com.oracle.truffle.r.runtime.data.RMissing;
 public class TraceHandling {
 
     public static void enableTrace(RFunction func) {
-        FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode();
         @SuppressWarnings("unchecked")
-        EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateTraceHandling.get(fdn.getUID());
+        EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateInstrumentation.getTraceBinding(RInstrumentation.getSourceSection(func));
         if (binding != null) {
             // only one
             binding.dispose();
@@ -63,17 +61,16 @@ public class TraceHandling {
     }
 
     public static void disableTrace(RFunction func) {
-        FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode();
         @SuppressWarnings("unchecked")
-        EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateTraceHandling.get(fdn.getUID());
+        EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateInstrumentation.getTraceBinding(RInstrumentation.getSourceSection(func));
         if (binding != null) {
             binding.dispose();
-            RContext.getInstance().stateTraceHandling.put(RInstrumentation.getFunctionDefinitionNode(func).getUID(), null);
+            RContext.getInstance().stateInstrumentation.putTraceBinding(RInstrumentation.getSourceSection(func), null);
         }
     }
 
     public static void setTracingState(boolean state) {
-        Object[] listeners = RContext.getInstance().stateTraceHandling.getListeners();
+        EventBinding<?>[] listeners = RContext.getInstance().stateInstrumentation.getTraceBindings();
         for (int i = 0; i < listeners.length; i++) {
             @SuppressWarnings("unchecked")
             EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) listeners[i];
@@ -97,9 +94,8 @@ public class TraceHandling {
     }
 
     public static boolean enableStatementTrace(RFunction func, RLanguage tracer, @SuppressWarnings("unused") Object exit, Object at, boolean print) {
-        FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode();
         @SuppressWarnings("unchecked")
-        EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateTraceHandling.get(fdn.getUID());
+        EventBinding<TraceEventListener> binding = (EventBinding<TraceEventListener>) RContext.getInstance().stateInstrumentation.getTraceBinding(RInstrumentation.getSourceSection(func));
         if (binding != null) {
             // only one allowed
             binding.dispose();
@@ -109,7 +105,7 @@ public class TraceHandling {
             TracerFunctionEntryEventListener listener = new TracerFunctionEntryEventListener(tracer, print);
             binding = RInstrumentation.getInstrumenter().attachListener(RInstrumentation.createFunctionStartFilter(func).build(), listener);
             setOutputHandler();
-            RContext.getInstance().stateTraceHandling.put(RInstrumentation.getFunctionDefinitionNode(func).getUID(), binding);
+            RContext.getInstance().stateInstrumentation.putTraceBinding(RInstrumentation.getSourceSection(func), binding);
         }
         return false;
     }
@@ -118,7 +114,7 @@ public class TraceHandling {
         PrimitiveFunctionEntryEventListener fser = new PrimitiveFunctionEntryEventListener();
         EventBinding<TraceEventListener> binding = RInstrumentation.getInstrumenter().attachListener(RInstrumentation.createFunctionStartFilter(func).build(), fser);
         setOutputHandler();
-        RContext.getInstance().stateTraceHandling.put(RInstrumentation.getFunctionDefinitionNode(func).getUID(), binding);
+        RContext.getInstance().stateInstrumentation.putTraceBinding(RInstrumentation.getSourceSection(func), binding);
     }
 
     private abstract static class TraceEventListener implements ExecutionEventListener {
diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/TestBase.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/TestBase.java
index c3e51b7541755b08a35328f31823bbe0e6b906c2..abd1f3fab05b824fbd86294ccaff489811b72ba1 100644
--- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/TestBase.java
+++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/TestBase.java
@@ -45,7 +45,7 @@ public class TestBase {
     }
 
     // clear out warnings (which are stored in shared base env)
-    private static final Source CLEAR_WARNINGS = RSource.fromText("assign('last.warning', NULL, envir = baseenv())", "<clear_warnings>");
+    private static final Source CLEAR_WARNINGS = RSource.fromTextInternal("assign('last.warning', NULL, envir = baseenv())", RSource.Internal.CLEAR_WARNINGS);
 
     @AfterClass
     public static void finishClass() throws IOException {
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ALONGFunctionUIDFactory.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ALONGFunctionUIDFactory.java
deleted file mode 100644
index f508505dfa5eb8ec196ebf574896c10b90ef6340..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ALONGFunctionUIDFactory.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.function;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-import com.oracle.truffle.r.runtime.FunctionUID;
-import com.oracle.truffle.r.runtime.instrument.FunctionUIDFactory;
-
-public class ALONGFunctionUIDFactory extends FunctionUIDFactory {
-
-    private static final AtomicLong ID = new AtomicLong();
-
-    private static final class ALongFunctionUID implements FunctionUID {
-
-        private final long uuid;
-
-        private ALongFunctionUID(long uuid) {
-            this.uuid = uuid;
-        }
-
-        @Override
-        public int compareTo(FunctionUID o) {
-            ALongFunctionUID oa = (ALongFunctionUID) o;
-            if (uuid == oa.uuid) {
-                return 0;
-            } else if (uuid < oa.uuid) {
-                return -1;
-            } else {
-                return 1;
-            }
-        }
-
-        @Override
-        public String toString() {
-            return Long.toString(uuid);
-        }
-    }
-
-    @Override
-    public FunctionUID createUID() {
-        return new ALongFunctionUID(ID.incrementAndGet());
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
index 0baca3d486265f3af9ba19fcb526589a42aa59ca..9e3d611808fd439720b539a5e27f79e9e7889082 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java
@@ -47,10 +47,8 @@ import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinFactory;
 import com.oracle.truffle.r.nodes.control.BreakException;
 import com.oracle.truffle.r.nodes.control.NextException;
-import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.BrowserQuitException;
-import com.oracle.truffle.r.runtime.FunctionUID;
 import com.oracle.truffle.r.runtime.RArguments;
 import com.oracle.truffle.r.runtime.RArguments.DispatchArgs;
 import com.oracle.truffle.r.runtime.RArguments.S3Args;
@@ -63,21 +61,19 @@ import com.oracle.truffle.r.runtime.RSerialize;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.Utils.DebugExitException;
-import com.oracle.truffle.r.runtime.WithFunctionUID;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RBuiltinDescriptor;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.env.frame.RFrameSlot;
-import com.oracle.truffle.r.runtime.instrument.FunctionUIDFactory;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxFunction;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 
-public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNode, WithFunctionUID, RSyntaxFunction {
+public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNode, RSyntaxFunction {
 
     @Child private RNode body; // typed as RNode to avoid custom instrument wrapper
     /**
@@ -88,12 +84,10 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
      * {@code f <- function}.
      * <li>The first several characters of the function definition for anonymous functions.
      * </ul>
-     * It can be updated later by calling {@link #setDescription}, which is useful for functions
-     * lazily loaded from packages, where at the point of definition any assignee variable is
-     * unknown.
+     * It can be updated later by calling {@link #setName}, which is useful for functions lazily
+     * loaded from packages, where at the point of definition any assignee variable is unknown.
      */
-    private String description;
-    private FunctionUID uuid;
+    private String name;
     private boolean instrumented = false;
     private SourceSection sourceSectionR;
     private final SourceSection[] argSourceSections;
@@ -133,12 +127,12 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
     private final ConditionProfile returnTopLevelProfile = ConditionProfile.createBinaryProfile();
 
     public static FunctionDefinitionNode create(SourceSection src, FrameDescriptor frameDesc, SourceSection[] argSourceSections, SaveArgumentsNode saveArguments, RSyntaxNode body,
-                    FormalArguments formals, String description, PostProcessArgumentsNode argPostProcess) {
-        return new FunctionDefinitionNode(src, frameDesc, argSourceSections, saveArguments, body, formals, description, argPostProcess, FunctionUIDFactory.get().createUID());
+                    FormalArguments formals, String name, PostProcessArgumentsNode argPostProcess) {
+        return new FunctionDefinitionNode(src, frameDesc, argSourceSections, saveArguments, body, formals, name, argPostProcess);
     }
 
     private FunctionDefinitionNode(SourceSection src, FrameDescriptor frameDesc, SourceSection[] argSourceSections, RNode saveArguments, RSyntaxNode body, FormalArguments formals,
-                    String description, PostProcessArgumentsNode argPostProcess, FunctionUID uuid) {
+                    String name, PostProcessArgumentsNode argPostProcess) {
         super(null, formals, frameDesc, RASTBuilder.createFunctionFastPath(body, formals.getSignature()));
         this.argSourceSections = argSourceSections;
         assert FrameSlotChangeMonitor.isValidFrameDescriptor(frameDesc);
@@ -146,13 +140,11 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
         this.sourceSectionR = src;
         this.saveArguments = saveArguments;
         this.body = body.asRNode();
-        this.description = description;
+        this.name = name;
         this.onExitSlot = FrameSlotNode.createInitialized(frameDesc, RFrameSlot.OnExit, false);
-        this.uuid = uuid;
         this.needsSplitting = needsAnyBuiltinSplitting();
         this.containsDispatch = containsAnyDispatch(body);
         this.argPostProcess = argPostProcess;
-        RInstrumentation.registerFunctionDefinition(this);
     }
 
     @Override
@@ -165,8 +157,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
             SourceSection source = argSourceSections == null ? getSourceSection() : argSourceSections[i];
             args.add(RCodeBuilder.argument(source, getFormalArguments().getSignature().getName(i), value == null ? null : builder.process(value.asRSyntaxNode())));
         }
-        RootCallTarget callTarget = RContext.getASTBuilder().rootFunction(getSourceSection(), args, builder.process(getBody()), description);
-        ((FunctionDefinitionNode) callTarget.getRootNode()).uuid = uuid;
+        RootCallTarget callTarget = RContext.getASTBuilder().rootFunction(getSourceSection(), args, builder.process(getBody()), name);
         return callTarget;
     }
 
@@ -236,11 +227,6 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
         return needsSplitting;
     }
 
-    @Override
-    public FunctionUID getUID() {
-        return uuid;
-    }
-
     public RSyntaxNode getBody() {
         return body.asRSyntaxNode();
     }
@@ -392,7 +378,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
 
     @Override
     public String getName() {
-        return description == null ? "<no source>" : description;
+        return name == null ? "<no source>" : name;
     }
 
     @Override
@@ -454,8 +440,8 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
         }
     }
 
-    public void setDescription(String name) {
-        this.description = name;
+    public void setName(String name) {
+        this.name = name;
     }
 
     public boolean getInstrumented() {
@@ -495,6 +481,6 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo
 
     @Override
     public String getSyntaxDebugName() {
-        return description;
+        return name;
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java
index 4cd2134a87d2f4a531b6019f1617f050e1c9c170..b4dd48549c46b868691e576d6a7e2864bd5f65c9 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java
@@ -134,6 +134,6 @@ public final class FunctionExpressionNode extends RSourceSectionNode implements
 
     @Override
     public String getSyntaxDebugName() {
-        return ((RRootNode) callTarget.getRootNode()).getDescription();
+        return ((RRootNode) callTarget.getRootNode()).getName();
     }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UUIDFunctionUIDFactory.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UUIDFunctionUIDFactory.java
deleted file mode 100644
index 3d3a4163f8cb8fb63f8b708b50f4f2cd93d20b84..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/UUIDFunctionUIDFactory.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.function;
-
-import java.util.UUID;
-
-import com.oracle.truffle.r.runtime.FunctionUID;
-import com.oracle.truffle.r.runtime.instrument.FunctionUIDFactory;
-
-public class UUIDFunctionUIDFactory extends FunctionUIDFactory {
-
-    private static final class UUIDFunctionUID implements FunctionUID {
-
-        private final UUID uuid;
-
-        private UUIDFunctionUID(UUID uuid) {
-            this.uuid = uuid;
-        }
-
-        @Override
-        public int compareTo(FunctionUID o) {
-            return uuid.compareTo(((UUIDFunctionUID) o).uuid);
-        }
-
-        @Override
-        public String toString() {
-            return uuid.toString();
-        }
-    }
-
-    @Override
-    public FunctionUID createUID() {
-        return new UUIDFunctionUID(UUID.randomUUID());
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/REntryCounters.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/REntryCounters.java
deleted file mode 100644
index 33343ce29eb227fb13acccd8deb64c2440d0f20c..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/REntryCounters.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.instrumentation;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.instrumentation.EventContext;
-import com.oracle.truffle.api.instrumentation.ExecutionEventListener;
-import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
-import com.oracle.truffle.api.instrumentation.StandardTags;
-import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
-import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation.FunctionIdentification;
-import com.oracle.truffle.r.runtime.FunctionUID;
-import com.oracle.truffle.r.runtime.RPerfStats;
-import com.oracle.truffle.r.runtime.data.RFunction;
-
-/**
- * Basic support for adding entry/exit counters to nodes. The {@link SourceSection} attribute is is
- * used to retrieve the counter associated with a node.
- *
- */
-public class REntryCounters {
-    public static final class Counter {
-        private final Object ident;
-        private int enterCount;
-        private int exitCount;
-
-        Counter(Object ident) {
-            this.ident = ident;
-        }
-
-        public int getEnterCount() {
-            return enterCount;
-        }
-
-        public int getExitCount() {
-            return exitCount;
-        }
-
-        public Object getIdent() {
-            return ident;
-        }
-    }
-
-    /**
-     * Listener that is independent of the kind of node and specific instance being counted.
-     */
-    private abstract static class BasicListener implements ExecutionEventListener {
-
-        private HashMap<SourceSection, Counter> counterMap = new HashMap<>();
-
-        private Counter getCounter(EventContext context) {
-            SourceSection ss = context.getInstrumentedSourceSection();
-            Counter counter = counterMap.get(ss);
-            if (counter == null) {
-                Object obj = counterCreated(context);
-                counter = new Counter(obj);
-                counterMap.put(ss, counter);
-            }
-            return counter;
-        }
-
-        protected Counter getCounter(SourceSection sourceSection) {
-            Counter counter = counterMap.get(sourceSection);
-            assert counter != null;
-            return counter;
-        }
-
-        protected Map<SourceSection, Counter> getCounterMap() {
-            return counterMap;
-        }
-
-        @Override
-        public void onEnter(EventContext context, VirtualFrame frame) {
-            getCounter(context).enterCount++;
-        }
-
-        @Override
-        public void onReturnValue(EventContext context, VirtualFrame frame, Object result) {
-            getCounter(context).exitCount++;
-        }
-
-        @Override
-        public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) {
-            getCounter(context).exitCount++;
-        }
-
-        protected abstract Object counterCreated(EventContext context);
-    }
-
-    /**
-     * A counter that is specialized for function entry, tagged with the {@link FunctionUID}.
-     */
-    public static class FunctionListener extends BasicListener {
-        private static final FunctionListener singleton = new FunctionListener();
-
-        static void installCounters() {
-            if (enabled()) {
-                SourceSectionFilter.Builder builder = SourceSectionFilter.newBuilder();
-                builder.tagIs(StandardTags.RootTag.class);
-                SourceSectionFilter filter = builder.build();
-                RInstrumentation.getInstrumenter().attachListener(filter, singleton);
-            }
-        }
-
-        public static void installCounter(RFunction func) {
-            RInstrumentation.getInstrumenter().attachListener(RInstrumentation.createFunctionStartFilter(func).build(), singleton);
-        }
-
-        public static Counter findCounter(RFunction func) {
-            FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode();
-            return singleton.getCounter(fdn.getBody().getSourceSection());
-        }
-
-        @Override
-        protected FunctionUID counterCreated(EventContext context) {
-            FunctionDefinitionNode fdn = (FunctionDefinitionNode) context.getInstrumentedNode().getRootNode();
-            return fdn.getUID();
-        }
-
-        static {
-            RPerfStats.register(new PerfHandler());
-        }
-
-        static boolean enabled() {
-            return RPerfStats.enabled(PerfHandler.NAME);
-        }
-
-        private static class PerfHandler implements RPerfStats.Handler {
-            private static class FunctionCount implements Comparable<FunctionCount> {
-                int count;
-                String name;
-
-                FunctionCount(int count, String name) {
-                    this.count = count;
-                    this.name = name;
-                }
-
-                @Override
-                public int compareTo(FunctionCount o) {
-                    if (count < o.count) {
-                        return 1;
-                    } else if (count > o.count) {
-                        return -1;
-                    } else {
-                        return name.compareTo(o.name);
-                    }
-                }
-            }
-
-            static final String NAME = "functioncounts";
-
-            @Override
-            public void initialize(String optionText) {
-            }
-
-            @Override
-            public String getName() {
-                return NAME;
-            }
-
-            /**
-             * R's anonymous function definitions don't help with reporting. We make an attempt to
-             * locate a function name in the global/package environments.
-             */
-            @Override
-            public void report() {
-                RPerfStats.out().println("R Function Entry Counts");
-                ArrayList<FunctionCount> results = new ArrayList<>();
-                for (Map.Entry<SourceSection, Counter> entry : FunctionListener.singleton.getCounterMap().entrySet()) {
-                    Counter counter = entry.getValue();
-                    FunctionIdentification fdi = RInstrumentation.getFunctionIdentification((FunctionUID) counter.getIdent());
-                    int count = counter.getEnterCount();
-                    if (count > 0) {
-                        results.add(new FunctionCount(count, fdi.name));
-                    }
-                }
-                FunctionCount[] sortedCounts = new FunctionCount[results.size()];
-                results.toArray(sortedCounts);
-                Arrays.sort(sortedCounts);
-                for (FunctionCount functionCount : sortedCounts) {
-                    RPerfStats.out().printf("%6d: %s%n", functionCount.count, functionCount.name);
-                }
-            }
-        }
-    }
-}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RFunctionProfiler.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RFunctionProfiler.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3158a4c3e13a058b87ed179d903eaec0db6c873
--- /dev/null
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RFunctionProfiler.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.instrumentation;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.source.SourceSection;
+import com.oracle.truffle.api.vm.PolyglotEngine;
+import com.oracle.truffle.r.runtime.RPerfStats;
+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.RFunction;
+import com.oracle.truffle.tools.Profiler;
+import com.oracle.truffle.tools.Profiler.Counter;
+import com.oracle.truffle.tools.Profiler.Counter.TimeKind;
+
+/**
+ * Interface to the Truffle {@link Profiler}.
+ */
+public class RFunctionProfiler {
+    static {
+        RPerfStats.register(new PerfHandler());
+    }
+
+    static boolean enabled() {
+        return RPerfStats.enabled(PerfHandler.NAME);
+    }
+
+    /**
+     * This is called on startup to support {@link RPerfStats}.
+     */
+    static void installTimers(RContext context) {
+        if (enabled()) {
+            enableTiming(context, true, true);
+        }
+    }
+
+    private static Profiler getProfiler(RContext context) {
+        PolyglotEngine vm = context.getVM();
+        Profiler profiler = Profiler.find(vm);
+        return profiler;
+    }
+
+    private static Profiler getProfiler() {
+        PolyglotEngine vm = RContext.getInstance().getVM();
+        Profiler profiler = Profiler.find(vm);
+        return profiler;
+    }
+
+    private static void enableTiming(RContext context, @SuppressWarnings("unused") boolean counting, boolean timing) {
+        Profiler profiler = getProfiler(context);
+        context.getInstrumentationState().setProfiler(profiler);
+        profiler.setTiming(timing);
+        profiler.setCollecting(true);
+    }
+
+    /**
+     * (Interactively) installs a timer for a specific function. Currently the {@link Profiler} does
+     * not support profiling limited to specific functions so this effectively enables everything.
+     * If {@code func} is {@code null} profile all functions. In principle profiling can be
+     * restricted to entry counting and timing but currently counting is always on.
+     *
+     */
+    public static void installTimer(@SuppressWarnings("unused") RFunction func, boolean counting, boolean timing) {
+        enableTiming(RContext.getInstance(), counting, timing);
+    }
+
+    public static Counter getCounter(RFunction func) {
+        Profiler profiler = getProfiler();
+        if (profiler.isCollecting()) {
+            String funcName = func.getTarget().getRootNode().getName();
+            Map<SourceSection, Counter> counters = profiler.getCounters();
+            for (Counter counter : counters.values()) {
+                if (counter.getName().equals(funcName)) {
+                    return counter;
+                }
+            }
+        }
+        return null;
+    }
+
+    public static void reset() {
+        Profiler profiler = getProfiler();
+        profiler.clearData();
+        profiler.setCollecting(false);
+    }
+
+    public static void clear() {
+        Profiler profiler = getProfiler();
+        profiler.clearData();
+    }
+
+    public static Counter[] getCounters() {
+        Profiler profiler = getProfiler();
+        if (profiler.isCollecting()) {
+            Map<SourceSection, Counter> counters = profiler.getCounters();
+            Counter[] result = new Counter[counters.size()];
+            counters.values().toArray(result);
+            return result;
+        } else {
+            return null;
+        }
+    }
+
+    public static boolean isTiming() {
+        Profiler profiler = getProfiler();
+        return profiler.isTiming();
+    }
+
+    private static class PerfHandler implements RPerfStats.Handler {
+        static final String NAME = "timing";
+        @SuppressWarnings("unused") private boolean stmts;
+        private int threshold;
+
+        @Override
+        public void initialize(String optionText) {
+            if (optionText.length() > 0) {
+                String[] subOptions = optionText.split(":");
+                for (String subOption : subOptions) {
+                    if (subOption.equals("stmts")) {
+                        Utils.warn("statement timing is not implemented");
+                        stmts = true;
+                    } else if (subOption.startsWith("threshold")) {
+                        threshold = Integer.parseInt(subOption.substring(subOption.indexOf('=') + 1)) * 1000;
+                    }
+                }
+            }
+        }
+
+        @Override
+        public String getName() {
+            return NAME;
+        }
+
+        private static class SortableCounter implements Comparable<SortableCounter> {
+            private Counter counter;
+
+            SortableCounter(Counter counter) {
+                this.counter = counter;
+            }
+
+            @Override
+            public int compareTo(SortableCounter other) {
+                long myTime = counter.getSelfTime(TimeKind.INTERPRETED_AND_COMPILED);
+                long otherTime = other.counter.getSelfTime(TimeKind.INTERPRETED_AND_COMPILED);
+                return myTime < otherTime ? 1 : (myTime > otherTime ? -1 : 0);
+            }
+
+        }
+
+        /**
+         * Report the statement timing information at the end of the run. The report is per function
+         * Functions that consumed less time than requested threshold (default 0) are not included
+         * in the report. The report is sorted by cumulative time.
+         */
+        @Override
+        public void report() {
+            Profiler profiler = RContext.getInstance().getInstrumentationState().getProfiler();
+            // profiler.printHistograms(RPerfStats.out());
+            Map<SourceSection, Counter> counters = profiler.getCounters();
+            long totalTime = 0;
+            SortableCounter[] sortedCounters = new SortableCounter[counters.size()];
+            int i = 0;
+            for (Counter counter : counters.values()) {
+                totalTime += counter.getSelfTime(TimeKind.INTERPRETED_AND_COMPILED);
+                sortedCounters[i++] = new SortableCounter(counter);
+            }
+            Arrays.sort(sortedCounters);
+            for (SortableCounter scounter : sortedCounters) {
+                long time = scounter.counter.getSelfTime(TimeKind.INTERPRETED_AND_COMPILED);
+                if (time > 0 && time > threshold) {
+                    SourceSection ss = scounter.counter.getSourceSection();
+                    Source source = ss.getSource();
+                    RPerfStats.out().println("==========");
+                    double thisPercent = percent(time, totalTime);
+                    RPerfStats.out().printf("%d ms (%.2f%%): %s, %s%n", time, thisPercent, scounter.counter.getName(), RSource.getOrigin(source));
+                }
+            }
+            System.console();
+        }
+
+        private static double percent(long a, long b) {
+            return ((double) a * 100) / b;
+        }
+
+    }
+}
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java
index e245408ffafb1d509b711c00fa2a663f7b75d4d8..c51da1dd105e9f7cda7fddaa74322a28564fa41c 100644
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java
+++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RInstrumentation.java
@@ -22,142 +22,38 @@
  */
 package com.oracle.truffle.r.nodes.instrumentation;
 
-import java.util.HashMap;
-import java.util.Map;
-
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.instrumentation.Instrumenter;
 import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
 import com.oracle.truffle.api.instrumentation.StandardTags;
-import com.oracle.truffle.api.nodes.RootNode;
-import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
 import com.oracle.truffle.r.runtime.FastROptions;
-import com.oracle.truffle.r.runtime.FunctionUID;
-import com.oracle.truffle.r.runtime.RPerfStats;
-import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.data.RPromise;
-import com.oracle.truffle.r.runtime.data.RStringVector;
-import com.oracle.truffle.r.runtime.env.REnvironment;
 
 /**
  * Handles the initialization of the (NEW) instrumentation system which sets up various instruments
- * depending on command line options.
+ * depending on command line options and provides utility methods for instrumentation-based tools.
  *
  */
 public class RInstrumentation {
 
-    /**
-     * Collects together all the relevant data for a function, keyed by the {@link FunctionUID},
-     * which is unique, for {@link RPerfStats} use.
-     */
-    private static Map<FunctionUID, FunctionData> functionMap;
-
-    /**
-     * Created lazily as needed.
-     */
-    static class FunctionIdentification {
-        public final Source source;
-        public final String name;
-        public final String origin;
-        public final FunctionDefinitionNode node;
-
-        FunctionIdentification(Source source, String name, String origin, FunctionDefinitionNode node) {
-            this.source = source;
-            this.name = name;
-            this.origin = origin;
-            this.node = node;
-        }
-    }
-
-    /**
-     * Created for every {@link FunctionDefinitionNode}. maybe could be lazier.
-     */
-    private static class FunctionData {
-        private final FunctionUID uid;
-        private final FunctionDefinitionNode fdn;
-        private FunctionIdentification ident;
-
-        FunctionData(FunctionUID uid, FunctionDefinitionNode fdn) {
-            this.uid = uid;
-            this.fdn = fdn;
-        }
-
-        private FunctionIdentification getIdentification() {
-            if (ident == null) {
-                SourceSection ss = fdn.getSourceSection();
-                /*
-                 * The default for "name" is the description associated with "fdn". If the function
-                 * was parsed from text this will be the variable name the function value was
-                 * assigned to, or the first 40 characters of the definition if anonymous.
-                 */
-                String idName = fdn.toString();
-                Source idSource = null;
-                String idOrigin = null;
-                if (ss.getSource() != null) {
-                    idSource = ss.getSource();
-                    String sourceName = idSource.getName();
-                    idOrigin = sourceName;
-                    if (sourceName.startsWith("<package:")) {
-                        // try to find the name in the package environments
-                        // format of sourceName is "<package"xxx deparse>"
-                        String functionName = findFunctionName(uid, sourceName.substring(1, sourceName.lastIndexOf(' ')));
-                        if (functionName != null) {
-                            idName = functionName;
-                        }
-                    } else {
-                        idOrigin = sourceName;
-                    }
-                } else {
-                    // One of the RSyntaxNode "unavailable"s.
-                    idOrigin = idName;
-                    idSource = RSource.fromText(idName, idName);
-                }
-                ident = new FunctionIdentification(idSource, idName, idOrigin, fdn);
-            }
-            return ident;
-
-        }
-    }
-
     /**
      * The function names that were requested to be used in implicit {@code debug(f)} calls, when
      * those functions are defined. Global to all contexts.
      */
     @CompilationFinal private static String[] debugFunctionNames;
 
-    /**
-     * Called back from {@link FunctionDefinitionNode} so that we can record the {@link FunctionUID}
-     * and use {@code fdn} as the canonical {@link FunctionDefinitionNode}.
-     *
-     * @param fdn
-     */
-    public static void registerFunctionDefinition(FunctionDefinitionNode fdn) {
-        // For PerfStats we need to record the info on fdn for the report
-        if (functionMap != null) {
-            FunctionUID uid = fdn.getUID();
-            FunctionData fd = functionMap.get(uid);
-            if (fd != null) {
-                // duplicate
-                return;
-            }
-            assert fd == null;
-            functionMap.put(uid, new FunctionData(uid, fdn));
-        }
-    }
-
-    static FunctionIdentification getFunctionIdentification(FunctionUID uid) {
-        return functionMap.get(uid).getIdentification();
-    }
-
     public static FunctionDefinitionNode getFunctionDefinitionNode(RFunction func) {
         assert !func.isBuiltin();
         return (FunctionDefinitionNode) func.getRootNode();
     }
 
+    public static SourceSection getSourceSection(RFunction func) {
+        return getFunctionDefinitionNode(func).getSourceSection();
+    }
+
     /**
      * Create a filter that matches all the statement nodes in {@code func}.
      */
@@ -183,7 +79,6 @@ public class RInstrumentation {
         builder.sourceIs(fdns.getSource());
         builder.rootSourceSectionEquals(fdns);
         return builder;
-
     }
 
     /**
@@ -201,22 +96,20 @@ public class RInstrumentation {
      * Activate the instrumentation system for {@code context}. Currently this simply checks for the
      * global (command-line) options for tracing and timing. They are applied to every context.
      */
-    public static void activate(@SuppressWarnings("unused") RContext context) {
+    public static void activate(RContext context) {
         String rdebugValue = FastROptions.Rdebug.getStringValue();
         if (rdebugValue != null) {
             debugFunctionNames = rdebugValue.split(",");
         }
-        if (REntryCounters.FunctionListener.enabled() || RNodeTimer.StatementListener.enabled()) {
-            functionMap = new HashMap<>();
-            REntryCounters.FunctionListener.installCounters();
-            RNodeTimer.StatementListener.installTimers();
+        if (RFunctionProfiler.enabled()) {
+            RFunctionProfiler.installTimers(context);
         }
         // Check for function tracing
         RContext.getRRuntimeASTAccess().traceAllFunctions();
     }
 
     public static Instrumenter getInstrumenter() {
-        return RContext.getInstance().getInstrumenter();
+        return RContext.getInstance().getInstrumentationState().getInstrumenter();
     }
 
     public static void checkDebugRequested(RFunction func) {
@@ -230,66 +123,4 @@ public class RInstrumentation {
         }
     }
 
-    private static Map<FunctionUID, String> functionNameMap;
-
-    /**
-     * Attempts to locate a name for an (assumed) builtin or global function. Returns {@code null}
-     * if not found.
-     */
-    private static String findFunctionName(FunctionUID uid, String packageName) {
-        if (functionNameMap == null) {
-            functionNameMap = new HashMap<>();
-        }
-        String name = functionNameMap.get(uid);
-        if (name == null) {
-            name = findFunctionInPackage(uid, packageName);
-        }
-        return name;
-    }
-
-    /**
-     * Try to find the function identified by uid in the given package. N.B. If we have the uid, the
-     * promise identifying the lazily loaded function must have been evaluated! So there is no need
-     * to evaluate any promises. N.B. For packages, we must use the namespace env as that contains
-     * public and private functions.
-     */
-    private static String findFunctionInPackage(FunctionUID uid, String packageName) {
-        if (packageName == null) {
-            return findFunctionInEnv(uid, REnvironment.globalEnv());
-        }
-        REnvironment env = REnvironment.lookupOnSearchPath(packageName);
-        env = env.getPackageNamespaceEnv();
-        return findFunctionInEnv(uid, env);
-    }
-
-    private static String findFunctionInEnv(FunctionUID uid, REnvironment env) {
-        // This is rather inefficient, but it doesn't matter
-        RStringVector names = env.ls(true, null, false);
-        for (int i = 0; i < names.getLength(); i++) {
-            String name = names.getDataAt(i);
-            Object val = env.get(name);
-            if (val instanceof RPromise) {
-                RPromise prVal = (RPromise) val;
-                if (prVal.isEvaluated()) {
-                    val = prVal.getValue();
-                } else {
-                    continue;
-                }
-            }
-            if (val instanceof RFunction) {
-                RFunction func = (RFunction) val;
-                RootNode rootNode = func.getRootNode();
-                if (rootNode instanceof FunctionDefinitionNode) {
-                    FunctionDefinitionNode fdn = (FunctionDefinitionNode) rootNode;
-                    if (fdn.getUID().equals(uid)) {
-                        functionNameMap.put(fdn.getUID(), name);
-                        return name;
-                    }
-                }
-            }
-        }
-        // Most likely a nested function, which is ok
-        // because they are not lazy and so have names from the parser.
-        return null;
-    }
 }
diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RNodeTimer.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RNodeTimer.java
deleted file mode 100644
index 84c3cb1927b446d10a3702acd33193a63d837293..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RNodeTimer.java
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.nodes.instrumentation;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.TreeMap;
-
-import com.oracle.truffle.api.frame.VirtualFrame;
-import com.oracle.truffle.api.instrumentation.EventContext;
-import com.oracle.truffle.api.instrumentation.ExecutionEventListener;
-import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
-import com.oracle.truffle.api.instrumentation.StandardTags;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.api.source.SourceSection;
-import com.oracle.truffle.r.nodes.control.BlockNode;
-import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
-import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation.FunctionIdentification;
-import com.oracle.truffle.r.runtime.FunctionUID;
-import com.oracle.truffle.r.runtime.RPerfStats;
-import com.oracle.truffle.r.runtime.data.RFunction;
-import com.oracle.truffle.r.runtime.nodes.RNode;
-import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
-import com.oracle.truffle.r.runtime.nodes.RSyntaxNodeVisitor;
-
-/**
- * Basic support for adding as timer to a node. Currently limited to "statement" timing.
- *
- * The instrument records the cumulative time spent executing this node during the process execution
- * using {@link System#nanoTime()}.
- *
- */
-public class RNodeTimer {
-
-    public static final class TimeInfo {
-        private final Object ident;
-        protected long enterTime;
-        protected long cumulativeTime;
-
-        TimeInfo(Object ident) {
-            this.ident = ident;
-        }
-
-        public long getTime() {
-            return cumulativeTime;
-        }
-
-        public Object getIdent() {
-            return ident;
-        }
-    }
-
-    private abstract static class BasicListener implements ExecutionEventListener {
-        private HashMap<SourceSection, TimeInfo> timeInfoMap = new HashMap<>();
-
-        private TimeInfo getTimeInfo(EventContext context) {
-            SourceSection ss = context.getInstrumentedSourceSection();
-            TimeInfo timeInfo = timeInfoMap.get(ss);
-            if (timeInfo == null) {
-                Object obj = timeInfoCreated(context);
-                timeInfo = new TimeInfo(obj);
-                timeInfoMap.put(ss, timeInfo);
-            }
-            return timeInfo;
-        }
-
-        protected TimeInfo getTimeInfo(SourceSection sourceSection) {
-            TimeInfo timeInfo = timeInfoMap.get(sourceSection);
-            assert timeInfo != null;
-            return timeInfo;
-        }
-
-        protected Map<SourceSection, TimeInfo> getTimeInfoMap() {
-            return timeInfoMap;
-        }
-
-        @Override
-        public void onEnter(EventContext context, VirtualFrame frame) {
-            getTimeInfo(context).enterTime = System.nanoTime();
-        }
-
-        @Override
-        public void onReturnValue(EventContext context, VirtualFrame frame, Object result) {
-            TimeInfo timeInfo = getTimeInfo(context);
-            timeInfo.cumulativeTime += System.nanoTime() - timeInfo.enterTime;
-        }
-
-        @Override
-        public void onReturnExceptional(EventContext context, VirtualFrame frame, Throwable exception) {
-            onReturnValue(context, frame, exception);
-        }
-
-        protected abstract Object timeInfoCreated(EventContext context);
-
-    }
-
-    public static class StatementListener extends BasicListener {
-        private static final StatementListener singleton = new StatementListener();
-
-        public static long findTimer(RFunction func) {
-            FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode();
-            FunctionUID uid = fdn.getUID();
-            long cumTime = 0;
-            for (Map.Entry<SourceSection, TimeInfo> entry : StatementListener.singleton.getTimeInfoMap().entrySet()) {
-                TimeInfo timeInfo = entry.getValue();
-                Node node = (Node) timeInfo.getIdent();
-                FunctionDefinitionNode entryFdn = (FunctionDefinitionNode) node.getRootNode();
-                FunctionUID entryUid = entryFdn.getUID();
-                if (entryUid.equals(uid)) {
-                    // statement in "func"
-                    cumTime += timeInfo.cumulativeTime;
-                }
-            }
-            return cumTime;
-        }
-
-        static void installTimers() {
-            if (enabled()) {
-                SourceSectionFilter.Builder builder = SourceSectionFilter.newBuilder();
-                builder.tagIs(StandardTags.StatementTag.class);
-                SourceSectionFilter filter = builder.build();
-                RInstrumentation.getInstrumenter().attachListener(filter, singleton);
-            }
-        }
-
-        public static void installTimer(RFunction func) {
-            RInstrumentation.getInstrumenter().attachListener(RInstrumentation.createFunctionStatementFilter(func).build(), singleton);
-        }
-
-        @Override
-        protected Node timeInfoCreated(EventContext context) {
-            return context.getInstrumentedNode();
-        }
-
-        // PerfStats support
-
-        static {
-            RPerfStats.register(new PerfHandler());
-        }
-
-        static boolean enabled() {
-            return RPerfStats.enabled(PerfHandler.NAME);
-        }
-
-        private static class TimingData implements Comparable<TimingData> {
-            long time;
-            FunctionUID functionUID;
-
-            TimingData(FunctionUID functionUID) {
-                this.functionUID = functionUID;
-            }
-
-            void addTime(long t) {
-                this.time += t;
-            }
-
-            @Override
-            public int compareTo(TimingData o) {
-                if (time < o.time) {
-                    return 1;
-                } else if (time > o.time) {
-                    return -1;
-                } else {
-                    return 0;
-                }
-            }
-        }
-
-        private static class PerfHandler implements RPerfStats.Handler {
-            static final String NAME = "timing";
-            private boolean stmts;
-            private int threshold;
-
-            @Override
-            public void initialize(String optionText) {
-                if (optionText.length() > 0) {
-                    String[] subOptions = optionText.split(":");
-                    for (String subOption : subOptions) {
-                        if (subOption.equals("stmts")) {
-                            stmts = true;
-                        } else if (subOption.startsWith("threshold")) {
-                            threshold = Integer.parseInt(subOption.substring(subOption.indexOf('=') + 1)) * 1000;
-                        }
-                    }
-                }
-            }
-
-            @Override
-            public String getName() {
-                return NAME;
-            }
-
-            /**
-             * Report the statement timing information at the end of the run. The report is per
-             * function {@link FunctionUID}, which uniquely defines a function in the face of call
-             * target splitting. Functions that consumed less time than requested threshold (default
-             * 0) are not included in the report. The report is sorted by cumulative time.
-             */
-            @Override
-            public void report() {
-                Map<FunctionUID, TimingData> functionMap = new TreeMap<>();
-
-                for (Map.Entry<SourceSection, TimeInfo> entry : StatementListener.singleton.getTimeInfoMap().entrySet()) {
-                    TimeInfo timeInfo = entry.getValue();
-                    Node node = (Node) timeInfo.getIdent();
-                    if (node.getRootNode() instanceof FunctionDefinitionNode) {
-                        FunctionDefinitionNode fdn = (FunctionDefinitionNode) node.getRootNode();
-                        FunctionUID uid = fdn.getUID();
-                        TimingData timingData = functionMap.get(uid);
-                        if (timingData == null) {
-                            timingData = new TimingData(uid);
-                            functionMap.put(uid, timingData);
-                        }
-                        timingData.addTime(millis(entry.getValue().cumulativeTime));
-                    }
-                }
-
-                Collection<TimingData> values = functionMap.values();
-                TimingData[] sortedData = new TimingData[values.size()];
-                values.toArray(sortedData);
-                Arrays.sort(sortedData);
-                long totalTime = 0;
-                for (TimingData t : sortedData) {
-                    totalTime += t.time;
-                }
-
-                RPerfStats.out().printf("Total (user) time %d ms%n", totalTime);
-                for (TimingData t : sortedData) {
-                    if (t.time > 0) {
-                        if (t.time > threshold) {
-                            FunctionIdentification fdi = RInstrumentation.getFunctionIdentification(t.functionUID);
-                            RPerfStats.out().println("==========");
-                            RPerfStats.out().printf("%d ms (%.2f%%): %s, %s%n", t.time, percent(t.time, totalTime), fdi.name, fdi.origin);
-                            if (stmts) {
-                                SourceSection ss = fdi.node.getSourceSection();
-                                if (ss == null) {
-                                    // wrapper
-                                    ss = fdi.node.getBody().getSourceSection();
-                                    if (ss == null) {
-                                        RPerfStats.out().println("no source available");
-                                    }
-                                } else {
-                                    long[] time = createLineTimes(fdi);
-                                    int startLine = ss.getStartLine();
-                                    int lastLine = ss.getEndLine();
-                                    for (int i = startLine; i <= lastLine; i++) {
-                                        RPerfStats.out().printf("%8dms: %s%n", time[i], fdi.source.getCode(i));
-                                    }
-
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        private static double percent(long a, long b) {
-            return ((double) a * 100) / b;
-        }
-
-        private abstract static class StatementVisitor implements RSyntaxNodeVisitor {
-            @SuppressWarnings("unused") protected final FunctionUID uid;
-
-            StatementVisitor(FunctionUID uid) {
-                this.uid = uid;
-            }
-
-            @Override
-            public boolean visit(RSyntaxNode node, int depth) {
-                if (node instanceof BlockNode) {
-                    BlockNode sequenceNode = (BlockNode) node;
-                    RNode[] block = sequenceNode.getSequence();
-                    for (int i = 0; i < block.length; i++) {
-                        RSyntaxNode n = block[i].unwrap().asRSyntaxNode();
-                        if (!callback(n)) {
-                            return false;
-                        }
-                    }
-                }
-                return true;
-            }
-
-            protected abstract boolean callback(RSyntaxNode node);
-
-        }
-
-        private static class LineTimesNodeVisitor extends StatementVisitor {
-            private final long[] times;
-
-            LineTimesNodeVisitor(FunctionUID uid, long[] time) {
-                super(uid);
-                this.times = time;
-            }
-
-            @Override
-            protected boolean callback(RSyntaxNode node) {
-                SourceSection ss = node.getSourceSection();
-                TimeInfo timeInfo = singleton.getTimeInfoMap().get(ss);
-                if (timeInfo != null) {
-                    assert ss.getStartLine() != 0;
-                    long stmtTime = millis(timeInfo.cumulativeTime);
-                    times[0] += stmtTime;
-                    times[ss.getStartLine()] += stmtTime;
-                } else {
-                    /*
-                     * This happens because default arguments are not visited during the AST probe
-                     * walk.
-                     */
-                }
-                return true;
-            }
-        }
-
-        private static long millis(long nanos) {
-            return nanos / 1000000;
-        }
-
-        private static long[] createLineTimes(FunctionIdentification fdi) {
-            /*
-             * Although only those lines occupied by the function will actually have entries in the
-             * array, addressing is easier if we allocate an array that is as long as the entire
-             * source. Since there is never a line 0, we use that to compute the total.
-             */
-            final long[] times = new long[fdi.source.getLineCount() + 1];
-            RSyntaxNode.accept(fdi.node.getBody().asNode(), 0, new LineTimesNodeVisitor(fdi.node.getUID(), times), false);
-            return times;
-        }
-    }
-}
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 12c94d8ddc1457fb26840b926a26fe0cdd0fcc74..dbc9d2dc9bfb59a5bfe699c5380a2b2e7f0fb694 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
@@ -30,7 +30,6 @@ import com.oracle.truffle.r.runtime.RCaller;
 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.RInternalSourceDescriptions;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.RType;
@@ -655,7 +654,7 @@ public class CallRFFIHelper {
         guarantee(symbolObj instanceof RSymbol);
         RSymbol symbol = (RSymbol) symbolObj;
         // Works but not remotely efficient
-        Source source = RSource.fromText("get(\"" + symbol.getName() + "\", mode=\"function\")", RInternalSourceDescriptions.RF_FINDFUN);
+        Source source = RSource.fromTextInternal("get(\"" + symbol.getName() + "\", mode=\"function\")", RSource.Internal.RF_FINDFUN);
         try {
             Object result = RContext.getEngine().parseAndEval(source, env.getFrame(), false);
             return result;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
index 911146cef4567a13f3ba111f4d933a9608fa392c..8d04af165f9ced86ced2791b37fc76261077f2eb 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java
@@ -39,7 +39,6 @@ public enum FastROptions {
     PrintErrorStacktracesToFile("Dumps Java and R stack traces to 'fastr_errors.log' for all errors", true),
     CheckResultCompleteness("Assert completeness of results vectors after evaluating unit tests and R shell commands", true),
     Debug("Debug=name1,name2,...; Turn on debugging output for 'name1', 'name2', etc.", null, true),
-    Instrument("Enable (Old) Instrumentation", false),
     TraceCalls("Trace all R function calls", false),
     TraceCallsToFile("TraceCalls output is sent to 'fastr_tracecalls.log'", false),
     TraceNativeCalls("Trace all native function calls (performed via .Call, .External, etc.)", false),
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FunctionUID.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FunctionUID.java
deleted file mode 100644
index 891850463405f5fc2871f9096fba8e106ca7d068..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FunctionUID.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, 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;
-
-/**
- * An abstract UID for a {@code FunctionDefinitionNode}, used by instrumentation code. There may be
- * many clones of a {@code FunctionDefinitionNode}, but they all share the same UID.
- */
-public interface FunctionUID extends Comparable<FunctionUID> {
-
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
index cbe8a8217396bef609da9399da5c9732b202ee60..0516ba9dac1739769d78185452ac6523eae330e3 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java
@@ -342,7 +342,7 @@ public class RDeparse {
         }
 
         public void fixupSources() {
-            Source source = RSource.fromText(sb.toString(), "deparse");
+            Source source = RSource.fromTextInternal(sb.toString(), RSource.Internal.DEPARSE);
             for (SourceSectionElement s : sources) {
                 s.element.setSourceSection(source.createSection(null, s.start, s.length));
             }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index 7df6df646122ce7708b1d47e5ebf37e5451f7091..c08fae1d96a9bd7baff6efe01ca89f47d1499ff9 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -676,7 +676,9 @@ public final class RError extends RuntimeException {
         QUIT_ASK("one of \"yes\", \"no\", \"ask\" or \"default\" expected."),
         QUIT_SAVE("unrecognized value of 'save'"),
         ENVIRONMENTS_COERCE("environments cannot be coerced to other types"),
-        CLOSURE_COERCE("cannot coerce type 'closure' to vector of type 'integer'");
+        CLOSURE_COERCE("cannot coerce type 'closure' to vector of type 'integer'"),
+        ROWSUM_NAMES_NOT_CHAR("row names are not character"),
+        ROWSUM_NON_NUMERIC("non-numeric matrix in rowsum(): this should not happen");
 
         public final String message;
         final boolean hasArgs;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalSourceDescriptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalSourceDescriptions.java
deleted file mode 100644
index 10d57d635a5195989d604f6a6ae3241b4bdf43bf..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalSourceDescriptions.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import com.oracle.truffle.api.source.Source;
-
-/**
- * Collection of strings that are used to indicate {@link Source} instances that have internal
- * descriptions.
- */
-public class RInternalSourceDescriptions {
-    private static final Set<String> set = new HashSet<>();
-
-    public static final String UNIT_TEST = add("<unit_test>");
-    public static final String SHELL_INPUT = add("<shell_input>");
-    public static final String EXPRESSION_INPUT = add("<expression_input>");
-    public static final String GET_ECHO = add("<get_echo>");
-    public static final String QUIT_EOF = add("<<quit_eof>>");
-    public static final String STARTUP_SHUTDOWN = add("<startup/shutdown>");
-    public static final String REPL_WRAPPER = add("<repl wrapper>");
-    public static final String NO_SOURCE = add("<no source>");
-    public static final String CONTEXT_EVAL = add("<context_eval>");
-    public static final String RF_FINDFUN = add("<Rf_findfun>");
-
-    private static String add(String s) {
-        set.add(s);
-        return s;
-    }
-
-    public static boolean isInternal(String s) {
-        return set.contains(s);
-    }
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
index 532564cb30eea0544f17cc2d848f4142c447e808..b930856972ac8930e17853a30b645baf8858c1ad 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java
@@ -310,7 +310,6 @@ public class RSerialize {
     }
 
     private static class Input extends Common {
-        private static final String UNKNOWN_PACKAGE_SOURCE_PREFIX = "<package:";
 
         protected final PInputStream stream;
         /**
@@ -860,7 +859,7 @@ public class RSerialize {
 
         private RExpression parse(Map<String, Object> constants, String deparseRaw) throws IOException {
             try {
-                Source source = RSource.fromText(deparseRaw, UNKNOWN_PACKAGE_SOURCE_PREFIX + packageName + " deparse>");
+                Source source = RSource.fromPackageTextInternal(deparseRaw, packageName);
                 return RContext.getEngine().parse(constants, source);
             } catch (Throwable ex) {
                 /*
@@ -893,7 +892,7 @@ public class RSerialize {
                 Source source;
                 String name;
                 if (sourcePath == null) {
-                    source = RSource.fromText(deparse, UNKNOWN_PACKAGE_SOURCE_PREFIX + packageName + " deparse>");
+                    source = RSource.fromPackageTextInternalWithName(deparse, packageName, currentFunctionName);
                     name = currentFunctionName;
                 } else {
                     source = RSource.fromFileName(deparse, sourcePath);
@@ -930,7 +929,7 @@ public class RSerialize {
         }
 
         private static final String FAILED_DEPARSE_FUNCTION = "function(...) stop(\"FastR error: proxy for lazily loaded function that did not deparse/parse\")";
-        private static final Source FAILED_DEPARSE_FUNCTION_SOURCE = RSource.fromText(FAILED_DEPARSE_FUNCTION, UNKNOWN_PACKAGE_SOURCE_PREFIX + "deparse_error>");
+        private static final Source FAILED_DEPARSE_FUNCTION_SOURCE = RSource.fromTextInternal(FAILED_DEPARSE_FUNCTION, RSource.Internal.DEPARSE_ERROR);
 
         /**
          * GnuR uses a pairlist to represent attributes, whereas FastR uses the abstract RAttributes
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
index dd840334c138f07cebcb3bf861e2d7023b40dc78..7b3291b64fe45091dd12cc771c50e722939754aa 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java
@@ -30,34 +30,168 @@ import java.net.URL;
 
 import com.oracle.truffle.api.source.Source;
 
+/**
+ * A facade for the creation of Truffle {@link Source} objects, which is complicated in R due the
+ * the many different ways in which sources can be created. Particularly tricky are sources created
+ * from deparsing functions from (binary-form) packages and from the {@code source} builtin, as
+ * these are presented as text strings despite being associated with files.
+ *
+ * We separate sources as <i>internal</i> or <i>external</i>, where the former will return
+ * {@code true} to {@link Source#isInternal()}. External sources always correspond to some external
+ * data source, e.g., file, url, even if they are not created using the standard methods in
+ * {@link Source}. An internal source will always return {@code null} to {@link Source#getURI} but
+ * {@link Source#getName} should return a value that indicates how/why the source was created, a
+ * value from {@link Internal}.
+ *
+ */
 public class RSource {
+    /**
+     * Collection of strings that are used to indicate {@link Source} instances that have internal
+     * descriptions.
+     */
+    public enum Internal {
+
+        UNIT_TEST("<unit_test>"),
+        SHELL_INPUT("<shell_input>"),
+        EXPRESSION_INPUT("<expression_input>"),
+        GET_ECHO("<get_echo>"),
+        QUIT_EOF("<<quit_eof>>"),
+        STARTUP_SHUTDOWN("<startup/shutdown>"),
+        REPL_WRAPPER("<repl wrapper>"),
+        EVAL_WRAPPER("<eval wrapper>"),
+        NO_SOURCE("<no source>"),
+        CONTEXT_EVAL("<context_eval>"),
+        RF_FINDFUN("<Rf_findfun>"),
+        BROWSER_INPUT("<browser_input>"),
+        CLEAR_WARNINGS("<clear_warnings>"),
+        DEPARSE("<deparse>"),
+        GET_CONTEXT("<get_context>"),
+        DEBUGTEST_FACTORIAL("<factorial.r>"),
+        DEBUGTEST_DEBUG("<debugtest.r>"),
+        DEBUGTEST_EVAL("<evaltest.r>"),
+        TCK_INIT("<tck_initialization>"),
+        PACKAGE("<package:%s deparse>"),
+        DEPARSE_ERROR("<package_deparse_error>"),
+        LAPPLY("<lapply>");
+
+        public final String string;
+
+        Internal(String text) {
+            this.string = text;
+        }
+
+    }
+
+    /**
+     * Create an (external) source from the {@code text} that is known to originate from the file
+     * system path {@code path}. The simulates the behavior of {@link #fromFile}.
+     */
     public static Source fromFileName(String text, String path) {
         File file = new File(path).getAbsoluteFile();
         try {
             URI uri = new URI("file://" + file.getAbsolutePath());
-            return Source.newBuilder(text).name(path).uri(uri).mimeType(RRuntime.R_APP_MIME).build();
+            return Source.newBuilder(text).name(file.getName()).uri(uri).mimeType(RRuntime.R_APP_MIME).build();
         } catch (URISyntaxException ex) {
             throw RInternalError.shouldNotReachHere(ex);
         }
     }
 
-    public static Source fromText(String text, String name) {
-        return fromText(text, name, RRuntime.R_APP_MIME);
+    /**
+     * Create an {@code internal} source from {@code text} and {@code description}.
+     */
+    public static Source fromTextInternal(String text, Internal description) {
+        return fromTextInternal(text, description, RRuntime.R_APP_MIME);
+    }
+
+    /**
+     * Create an {@code internal} source from {@code text} and {@code description} of given
+     * {@code mimeType}.
+     */
+
+    public static Source fromTextInternal(String text, Internal description, String mimeType) {
+        return Source.newBuilder(text).name(description.string).mimeType(mimeType).internal().build();
+    }
+
+    /**
+     * Create an {@code internal} source for a deparsed package from {@code text} and
+     * {@code packageName}.
+     */
+    public static Source fromPackageTextInternal(String text, String packageName) {
+        String name = String.format(Internal.PACKAGE.string, packageName);
+        return Source.newBuilder(text).name(name).mimeType(RRuntime.R_APP_MIME).build();
     }
 
-    public static Source fromText(String text, String name, String mimeType) {
-        return Source.newBuilder(text).name(name).mimeType(mimeType).build();
+    /**
+     * Create an {@code internal} source for a deparsed package from {@code text} when the function
+     * name might be known. If {@code functionName} is not {@code null}, use it as the "name" for
+     * the source, else default to {@link #fromPackageTextInternal(String, String)}.
+     */
+    public static Source fromPackageTextInternalWithName(String text, String packageName, String functionName) {
+        if (functionName == null) {
+            return fromPackageTextInternal(text, packageName);
+        } else {
+            return Source.newBuilder(text).name(packageName + "::" + functionName).mimeType(RRuntime.R_APP_MIME).build();
+        }
     }
 
+    /**
+     * Create an (external) source from the file system path {@code path}.
+     */
     public static Source fromFileName(String path) throws IOException {
         return Source.newBuilder(new File(path)).name(path).mimeType(RRuntime.R_APP_MIME).build();
     }
 
+    /**
+     * Create an (external) source from the file system path denoted by {@code file}.
+     */
     public static Source fromFile(File file) throws IOException {
         return Source.newBuilder(file).name(file.getName()).mimeType(RRuntime.R_APP_MIME).build();
     }
 
+    /**
+     * Create an (external) source from {@code url}.
+     */
     public static Source fromURL(URL url, String name) throws IOException {
         return Source.newBuilder(url).name(name).mimeType(RRuntime.R_APP_MIME).build();
     }
+
+    /**
+     * If {@code source} was created with {@link #fromPackageTextInternal} return the
+     * "package:name", else {@code null}. This can be used to access the corresponding R
+     * environment.
+     */
+    public static String getPackageName(Source source) {
+        String sourceName = source.getName();
+        if (sourceName.startsWith("<package:")) {
+            return sourceName.substring(1, sourceName.lastIndexOf(' '));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * If {@code source} is "internal", return {@code null} else return the file system path
+     * corresponding to the associated {@link URI}.
+     */
+    public static String getPath(Source source) {
+        if (source == null || source.isInternal()) {
+            return null;
+        }
+        URI uri = source.getURI();
+        assert uri != null;
+        return uri.getPath();
+    }
+
+    /**
+     * Always returns a non-null string even for internal sources.
+     */
+    public static String getOrigin(Source source) {
+        String path = RSource.getPath(source);
+        if (path == null) {
+            return source.getName();
+        } else {
+            return path;
+        }
+    }
+
 }
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 166e7903ba3b821c385b357e291446c3a0d0b105..061d1f60e025fc4c4537791421d1746b8e0f352f 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
@@ -446,10 +446,7 @@ public final class Utils {
                     SourceSection ss = sn != null ? sn.getSourceSection() : null;
                     // fabricate a srcref attribute from ss
                     Source source = ss != null ? ss.getSource() : null;
-                    String path = source != null ? source.getPath() : null;
-                    if (path != null && RInternalSourceDescriptions.isInternal(path)) {
-                        path = null;
-                    }
+                    String path = RSource.getPath(source);
                     RStringVector callerSource = RDataFactory.createStringVectorFromScalar(RContext.getRRuntimeASTAccess().getCallerSource(call));
                     if (path != null) {
                         callerSource.setAttr(RRuntime.R_SRCREF, RSrcref.createLloc(ss, path));
@@ -531,11 +528,6 @@ public final class Utils {
             }
             RCaller call = RArguments.getCall(unwrapped);
             if (call != null) {
-                /*
-                 * Log the frame depths as a triple: d,e,p, where 'd' is the actual depth, 'e' is
-                 * the effective depth and 'p' is the promise frame depth, or -1 if no promise
-                 * evaluation in progress.
-                 */
                 String callSrc = call.isValidCaller() ? RContext.getRRuntimeASTAccess().getCallerSource(call) : "<invalid call>";
                 int depth = RArguments.getDepth(unwrapped);
                 str.append("Frame(d=").append(depth).append("): ").append(callTarget).append(isVirtual ? " (virtual)" : "");
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/WithFunctionUID.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/WithFunctionUID.java
deleted file mode 100644
index b4399e5d19bbc3055b63b0c7afd7e62e2ef296d5..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/WithFunctionUID.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.runtime;
-
-public interface WithFunctionUID {
-
-    FunctionUID getUID();
-}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
index e725f80386447912401b2a090425d39c93e1a23e..4980ef69ae8ba14be31c4ce41bfe8d2b857e90c1 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java
@@ -35,9 +35,8 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextKind;
 /**
  * Represents custom initialization state for an R instance.
  *
- * Use {@link #apply(com.oracle.truffle.api.vm.PolyglotEngine.Builder)} to apply this information to
- * a newly-built {@link PolyglotEngine} instance (it will be stored in the "fastrContextInfo" global
- * symbol).
+ * Use {@link #createVM()} to apply this information to a newly-built {@link PolyglotEngine}
+ * instance (it will be stored in the "fastrContextInfo" global symbol).
  */
 public final class ContextInfo implements TruffleObject {
     static final String GLOBAL_SYMBOL = "fastrContextInfo";
@@ -56,6 +55,7 @@ public final class ContextInfo implements TruffleObject {
     private final RContext parent;
     private final ConsoleHandler consoleHandler;
     private final int id;
+    private PolyglotEngine vm;
 
     private ContextInfo(RCmdOptions options, ContextKind kind, RContext parent, ConsoleHandler consoleHandler, TimeZone systemTimeZone, int id) {
         this.options = options;
@@ -66,8 +66,10 @@ public final class ContextInfo implements TruffleObject {
         this.id = id;
     }
 
-    public PolyglotEngine.Builder apply(PolyglotEngine.Builder builder) {
-        return builder.globalSymbol(GLOBAL_SYMBOL, this);
+    public PolyglotEngine createVM() {
+        PolyglotEngine newVM = PolyglotEngine.newBuilder().globalSymbol(GLOBAL_SYMBOL, this).build();
+        this.vm = newVM;
+        return newVM;
     }
 
     /**
@@ -123,6 +125,10 @@ public final class ContextInfo implements TruffleObject {
         return id;
     }
 
+    public PolyglotEngine getVM() {
+        return vm;
+    }
+
     @Override
     public ForeignAccess getForeignAccess() {
         throw new IllegalStateException("cannot access " + ContextInfo.class.getSimpleName() + " via Truffle");
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
index c049318006f67e40e30d220d80d60841a745659c..d80fe6fc61d4656305192dfc3435fe8d935b81e6 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java
@@ -40,8 +40,6 @@ import com.oracle.truffle.r.runtime.nodes.RNode;
 
 public interface Engine {
 
-    String EVAL_FUNCTION_NAME = "<eval wrapper>";
-
     class ParseException extends IOException {
         private static final long serialVersionUID = 1L;
 
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 505500c15023012ef3ec1ef4a8153d06602bc17c..25accd14e61b46ebeb55b1a213a1a119daed0143 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
@@ -71,7 +71,7 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RStringVector;
 import com.oracle.truffle.r.runtime.env.REnvironment;
 import com.oracle.truffle.r.runtime.ffi.RFFIContextStateFactory;
-import com.oracle.truffle.r.runtime.instrument.TraceState;
+import com.oracle.truffle.r.runtime.instrument.InstrumentationState;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
 import com.oracle.truffle.r.runtime.rng.RRNG;
@@ -172,7 +172,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
      */
     public static class EvalThread extends ContextThread {
 
-        private static final Source GET_CONTEXT = RSource.fromText("invisible(.fastr.context.get())", "<get_context>");
+        private static final Source GET_CONTEXT = RSource.fromTextInternal("invisible(.fastr.context.get())", RSource.Internal.GET_CONTEXT);
 
         private final Source source;
         private final ContextInfo info;
@@ -189,7 +189,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
 
         @Override
         public void run() {
-            PolyglotEngine vm = info.apply(PolyglotEngine.newBuilder()).build();
+            PolyglotEngine vm = info.createVM();
             try {
                 setContext(vm.eval(GET_CONTEXT).as(RContext.class));
             } catch (Exception e1) {
@@ -340,8 +340,8 @@ public final class RContext extends ExecutionContext implements TruffleObject {
     @CompilationFinal private static RContext singleContext;
 
     private final Env env;
-    private final Instrumenter instrumenter;
     private final HashMap<String, TruffleObject> exportedSymbols = new HashMap<>();
+    private final boolean initial;
     /**
      * State that is used to support interposing on loadNamespace() for overrides.
      */
@@ -363,12 +363,12 @@ public final class RContext extends ExecutionContext implements TruffleObject {
     public final ContextState stateRFFI;
     public final RSerialize.ContextStateImpl stateRSerialize;
     public final LazyDBCache.ContextStateImpl stateLazyDBCache;
-    public final TraceState.ContextStateImpl stateTraceHandling;
+    public final InstrumentationState stateInstrumentation;
     public final ContextStateImpl stateInternalCode;
 
     private ContextState[] contextStates() {
         return new ContextState[]{stateREnvVars, stateRProfile, stateROptions, stateREnvironment, stateRErrorHandling, stateRConnection, stateStdConnections, stateRNG, stateRFFI, stateRSerialize,
-                        stateLazyDBCache, stateTraceHandling};
+                        stateLazyDBCache, stateInstrumentation};
     }
 
     private RContext(Env env, Instrumenter instrumenter, boolean isInitial) {
@@ -378,6 +378,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         } else {
             this.info = initialInfo;
         }
+        this.initial = isInitial;
 
         // this must happen before engine activation in the code below
         if (info.getKind() == ContextKind.SHARE_NOTHING) {
@@ -394,7 +395,6 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         }
 
         this.env = env;
-        this.instrumenter = instrumenter;
         if (info.getConsoleHandler() == null) {
             throw Utils.fail("no console handler set");
         }
@@ -432,7 +432,7 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         stateRFFI = RFFIContextStateFactory.newContext(this);
         stateRSerialize = RSerialize.ContextStateImpl.newContext(this);
         stateLazyDBCache = LazyDBCache.ContextStateImpl.newContext(this);
-        stateTraceHandling = TraceState.newContext(this);
+        stateInstrumentation = InstrumentationState.newContext(this, instrumenter);
         stateInternalCode = ContextStateImpl.newContext(this);
         engine.activate(stateREnvironment);
 
@@ -487,8 +487,8 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         return env;
     }
 
-    public Instrumenter getInstrumenter() {
-        return instrumenter;
+    public InstrumentationState getInstrumentationState() {
+        return stateInstrumentation;
     }
 
     public ContextKind getKind() {
@@ -662,6 +662,14 @@ public final class RContext extends ExecutionContext implements TruffleObject {
         return RContext.getInstance().engine;
     }
 
+    public PolyglotEngine getVM() {
+        return info.getVM();
+    }
+
+    public boolean isInitial() {
+        return initial;
+    }
+
     public void setLoadingBase(boolean b) {
         loadingBase = b;
     }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/FunctionUIDFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/FunctionUIDFactory.java
deleted file mode 100644
index c0c02637a774dc0db47a9fe08c0b00bcdd7ecdef..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/FunctionUIDFactory.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2014, 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.instrument;
-
-import com.oracle.truffle.r.runtime.FunctionUID;
-import com.oracle.truffle.r.runtime.Utils;
-
-public abstract class FunctionUIDFactory {
-    private static final String FACTORY_CLASS_PROPERTY = "fastr.fuid.factory.class";
-    private static final String PACKAGE_PREFIX = "com.oracle.truffle.r.nodes.function.";
-    private static final String SUFFIX = "FunctionUIDFactory";
-    private static final String DEFAULT_FACTORY = "along";
-    private static final String DEFAULT_FACTORY_CLASS = mapSimpleName(DEFAULT_FACTORY);
-
-    private static String mapSimpleName(String simpleName) {
-        return PACKAGE_PREFIX + simpleName.toUpperCase() + SUFFIX;
-    }
-
-    private static FunctionUIDFactory instance;
-
-    static {
-        String prop = System.getProperty(FACTORY_CLASS_PROPERTY);
-        if (prop != null) {
-            if (!prop.contains(".")) {
-                // simple name
-                prop = mapSimpleName(prop);
-            }
-        } else {
-            prop = DEFAULT_FACTORY_CLASS;
-        }
-        try {
-            instance = (FunctionUIDFactory) Class.forName(prop).newInstance();
-        } catch (Exception ex) {
-            Utils.fail("Failed to instantiate class: " + prop + ": " + ex);
-        }
-    }
-
-    public static FunctionUIDFactory get() {
-        return instance;
-    }
-
-    public abstract FunctionUID createUID();
-}
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
new file mode 100644
index 0000000000000000000000000000000000000000..87b3341dae1bdc444b1f3e64b7657a8835905597
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.runtime.instrument;
+
+import java.io.PrintWriter;
+import java.util.WeakHashMap;
+
+import com.oracle.truffle.api.instrumentation.EventBinding;
+import com.oracle.truffle.api.instrumentation.ExecutionEventListener;
+import com.oracle.truffle.api.instrumentation.Instrumenter;
+import com.oracle.truffle.api.source.SourceSection;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.tools.Profiler;
+
+/**
+ * The tracingState is a global variable in R, so we store it (and the associated listener objects)
+ * in the {@link RContext}. We also store related {@code debug} state, as that is also context
+ * specific.
+ *
+ */
+public final class InstrumentationState implements RContext.ContextState {
+
+    /**
+     * Records all functions that have trace listeners installed.
+     */
+    private final WeakHashMap<SourceSection, EventBinding<?>> traceBindingMap = new WeakHashMap<>();
+
+    private boolean tracingState = true;
+
+    /**
+     * Records all functions that have debug listeners installed.
+     */
+    private final WeakHashMap<SourceSection, ExecutionEventListener> debugListenerMap = new WeakHashMap<>();
+
+    private final Instrumenter instrumenter;
+
+    private Profiler profiler;
+
+    private final RprofState rprofState;
+
+    /**
+     * State used by {@code Rprof}.
+     *
+     */
+    public static class RprofState {
+        private PrintWriter out;
+        private Thread profileThread;
+        private ExecutionEventListener statementListener;
+        private long intervalInMillis;
+        private boolean lineProfiling;
+
+        public static RprofState newContext(@SuppressWarnings("unused") RContext context) {
+            return new RprofState();
+        }
+
+        public void initialize(PrintWriter outA, Thread profileThreadA, ExecutionEventListener statementListenerA, long intervalInMillisA,
+                        boolean lineProfilingA) {
+            this.out = outA;
+            this.profileThread = profileThreadA;
+            this.statementListener = statementListenerA;
+            this.intervalInMillis = intervalInMillisA;
+            this.lineProfiling = lineProfilingA;
+        }
+
+        public boolean lineProfiling() {
+            return lineProfiling;
+        }
+
+        public PrintWriter out() {
+            return out;
+        }
+
+        public long intervalInMillis() {
+            return intervalInMillis;
+        }
+
+        public ExecutionEventListener statementListener() {
+            return statementListener;
+        }
+
+        public Thread profileThread() {
+            return profileThread;
+        }
+
+    }
+
+    private InstrumentationState(Instrumenter instrumenter) {
+        this.instrumenter = instrumenter;
+        this.rprofState = new RprofState();
+    }
+
+    public void putTraceBinding(SourceSection ss, EventBinding<?> binding) {
+        traceBindingMap.put(ss, binding);
+    }
+
+    public EventBinding<?> getTraceBinding(SourceSection ss) {
+        return traceBindingMap.get(ss);
+    }
+
+    public void putDebugListener(SourceSection ss, ExecutionEventListener listener) {
+        debugListenerMap.put(ss, listener);
+    }
+
+    public EventBinding<?>[] getTraceBindings() {
+        EventBinding<?>[] result = new EventBinding<?>[traceBindingMap.size()];
+        traceBindingMap.values().toArray(result);
+        return result;
+
+    }
+
+    public ExecutionEventListener getDebugListener(SourceSection ss) {
+        return debugListenerMap.get(ss);
+    }
+
+    public boolean setTracingState(boolean state) {
+        boolean prev = tracingState;
+        tracingState = state;
+        return prev;
+    }
+
+    public boolean getTracingState() {
+        return tracingState;
+    }
+
+    public void setProfiler(Profiler profiler) {
+        this.profiler = profiler;
+    }
+
+    public Profiler getProfiler() {
+        return profiler;
+    }
+
+    public Instrumenter getInstrumenter() {
+        return instrumenter;
+    }
+
+    public RprofState getRprof() {
+        return rprofState;
+    }
+
+    public static InstrumentationState newContext(@SuppressWarnings("unused") RContext context, Instrumenter instrumenter) {
+        return new InstrumentationState(instrumenter);
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/TraceState.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/TraceState.java
deleted file mode 100644
index 4bbf3d547340fd38c04948b4f776cc6fdd9a626e..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/TraceState.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.runtime.instrument;
-
-import java.util.WeakHashMap;
-
-import com.oracle.truffle.r.runtime.FunctionUID;
-import com.oracle.truffle.r.runtime.context.RContext;
-
-/**
- * The tracingState is a global variable in R, so we store it (and the associated listener objects)
- * in the {@link RContext}. To finesse the temporary existence of two instrumentation frameworks the
- * receiver is typed as {@link Object}.
- *
- */
-public class TraceState {
-    public static class ContextStateImpl implements RContext.ContextState {
-
-        /**
-         * Records all functions that have trace listeners installed.
-         */
-        private final WeakHashMap<FunctionUID, Object> listenerMap = new WeakHashMap<>();
-        private boolean tracingState = true;
-
-        public void put(FunctionUID functionUID, Object listener) {
-            listenerMap.put(functionUID, listener);
-        }
-
-        public Object get(FunctionUID functionUID) {
-            return listenerMap.get(functionUID);
-        }
-
-        public boolean setTracingState(boolean state) {
-            boolean prev = tracingState;
-            tracingState = state;
-            return prev;
-        }
-
-        public boolean getTracingState() {
-            return tracingState;
-        }
-
-        public Object[] getListeners() {
-            Object[] result = new Object[listenerMap.size()];
-            listenerMap.values().toArray(result);
-            return result;
-        }
-    }
-
-    public static ContextStateImpl newContext(@SuppressWarnings("unused") RContext context) {
-        return new ContextStateImpl();
-    }
-}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowsum.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowsum.java
index bd86a98e2a0a8f0c4791df93819bf260297aeb5a..9e5d90ea9425a6cfdf0c225f88665c730b832808 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowsum.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowsum.java
@@ -19,48 +19,43 @@ public class TestBuiltin_rowsum extends TestBase {
 
     @Test
     public void testrowsum1() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(structure(1:12, .Dim = 3:4), c('Y', 'X', 'Y'), c('X', 'Y'), FALSE, c('X', 'Y')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
+        assertEval("argv <- list(structure(1:12, .Dim = 3:4), c('Y', 'X', 'Y'), c('X', 'Y'), FALSE, c('X', 'Y')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
     }
 
     @Test
     public void testrowsum2() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(structure(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.83678930089809, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.807183221448213, 0, 0, 0, 0, 0, 0, 0, 2.28512598329689, 0, 2.63247834995855, 0, 2.20238351041917, 0, 0.769295244943351, 0, 0, 0, 0, 0, 2.39247868547682, 2.35872046276927, 0, 1.96863683476113, 1.77908247814048, 0, 0, 0, 1.30635392456315, 0, 1.90387659717817, 0, 0.869405556702986, 1.81335102661978, 2.03683243726846, 0, 0.594853387563489, 0, 0, 0.546043346519582, 2.43847447982989, 0, 0, 2.01202685781755, 0, 2.67064226802904, 2.9177625705488, 0.566296850563958, 0, 1.07001449051313, 1.02747153153177, 0, 1.14719850081019, 2.56380862975493, 0.760732567403466, 0.778199262684211, 0, 0.871444851625711, 2.75724254851229, 1.6366914055543, 0.606628090143204, 1.09201998403296, 0.729518678388558, 2.26406822516583, 2.41699231159873, 1.90058654651511), .Names = c('7', '8', '12', '13', '19', '22', '26', '31', '34', '36', '38', '40', '42', '43', '44', '46', '50', '51', '57', '59', '60', '61', '64', '67', '68', '72', '75', '76', '77', '78', '84', '87', '89', '94', '95', '100', '101', '102', '107', '110', '114', '115', '122', '123', '129', '130', '131', '134', '136', '137', '141', '144', '146', '150', '153', '154', '157', '160', '161', '162', '166', '167', '172', '174', '176', '178', '179', '180', '183', '184', '185', '186', '187', '197', '199', '201', '203', '204', '205', '207', '208', '210', '211', '214', '217', '219', '220', '222', '226', '228')), structure(c(310, 361, 654, 728, 61, 81, 520, 473, 107, 122, 965, 731, 153, 433, 145, 95, 765, 735, 5, 687, 345, 444, 60, 208, 821, 305, 226, 426, 705, 363, 167, 641, 740, 245, 588, 166, 559, 450, 529, 351, 201, 524, 199, 550, 551, 543, 293, 511, 511, 371, 201, 62, 356, 340, 315, 182, 364, 376, 384, 268, 266, 194, 348, 382, 296, 186, 145, 269, 350, 272, 292, 332, 285, 243, 276, 79, 240, 202, 235, 224, 239, 173, 252, 92, 192, 211, 175, 203, 105, 177), .Names = c('7', '8', '12', '13', '19', '22', '26', '31', '34', '36', '38', '40', '42', '43', '44', '46', '50', '51', '57', '59', '60', '61', '64', '67', '68', '72', '75', '76', '77', '78', '84', '87', '89', '94', '95', '100', '101', '102', '107', '110', '114', '115', '122', '123', '129', '130', '131', '134', '136', '137', '141', '144', '146', '150', '153', '154', '157', '160', '161', '162', '166', '167', '172', '174', '176', '178', '179', '180', '183', '184', '185', '186', '187', '197', '199', '201', '203', '204', '205', '207', '208', '210', '211', '214', '217', '219', '220', '222', '226', '228')), c(5, 60, 61, 62, 79, 81, 92, 95, 105, 107, 122, 145, 153, 166, 167, 173, 175, 177, 182, 186, 192, 194, 199, 201, 202, 203, 208, 211, 224, 226, 235, 239, 240, 243, 245, 252, 266, 268, 269, 272, 276, 285, 292, 293, 296, 305, 310, 315, 332, 340, 345, 348, 350, 351, 356, 361, 363, 364, 371, 376, 382, 384, 426, 433, 444, 450, 473, 511, 520, 524, 529, 543, 550, 551, 559, 588, 641, 654, 687, 705, 728, 731, 735, 740, 765, 821, 965), FALSE, c('5', '60', '61', '62', '79', '81', '92', '95', '105', '107', '122', '145', '153', '166', '167', '173', '175', '177', '182', '186', '192', '194', '199', '201', '202', '203', '208', '211', '224', '226', '235', '239', '240', '243', '245', '252', '266', '268', '269', '272', '276', '285', '292', '293', '296', '305', '310', '315', '332', '340', '345', '348', '350', '351', '356', '361', '363', '364', '371', '376', '382', '384', '426', '433', '444', '450', '473', '511', '520', '524', '529', '543', '550', '551', '559', '588', '641', '654', '687', '705', '728', '731', '735', '740', '765', '821', '965')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
+        assertEval("argv <- list(structure(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.83678930089809, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.807183221448213, 0, 0, 0, 0, 0, 0, 0, 2.28512598329689, 0, 2.63247834995855, 0, 2.20238351041917, 0, 0.769295244943351, 0, 0, 0, 0, 0, 2.39247868547682, 2.35872046276927, 0, 1.96863683476113, 1.77908247814048, 0, 0, 0, 1.30635392456315, 0, 1.90387659717817, 0, 0.869405556702986, 1.81335102661978, 2.03683243726846, 0, 0.594853387563489, 0, 0, 0.546043346519582, 2.43847447982989, 0, 0, 2.01202685781755, 0, 2.67064226802904, 2.9177625705488, 0.566296850563958, 0, 1.07001449051313, 1.02747153153177, 0, 1.14719850081019, 2.56380862975493, 0.760732567403466, 0.778199262684211, 0, 0.871444851625711, 2.75724254851229, 1.6366914055543, 0.606628090143204, 1.09201998403296, 0.729518678388558, 2.26406822516583, 2.41699231159873, 1.90058654651511), .Names = c('7', '8', '12', '13', '19', '22', '26', '31', '34', '36', '38', '40', '42', '43', '44', '46', '50', '51', '57', '59', '60', '61', '64', '67', '68', '72', '75', '76', '77', '78', '84', '87', '89', '94', '95', '100', '101', '102', '107', '110', '114', '115', '122', '123', '129', '130', '131', '134', '136', '137', '141', '144', '146', '150', '153', '154', '157', '160', '161', '162', '166', '167', '172', '174', '176', '178', '179', '180', '183', '184', '185', '186', '187', '197', '199', '201', '203', '204', '205', '207', '208', '210', '211', '214', '217', '219', '220', '222', '226', '228')), structure(c(310, 361, 654, 728, 61, 81, 520, 473, 107, 122, 965, 731, 153, 433, 145, 95, 765, 735, 5, 687, 345, 444, 60, 208, 821, 305, 226, 426, 705, 363, 167, 641, 740, 245, 588, 166, 559, 450, 529, 351, 201, 524, 199, 550, 551, 543, 293, 511, 511, 371, 201, 62, 356, 340, 315, 182, 364, 376, 384, 268, 266, 194, 348, 382, 296, 186, 145, 269, 350, 272, 292, 332, 285, 243, 276, 79, 240, 202, 235, 224, 239, 173, 252, 92, 192, 211, 175, 203, 105, 177), .Names = c('7', '8', '12', '13', '19', '22', '26', '31', '34', '36', '38', '40', '42', '43', '44', '46', '50', '51', '57', '59', '60', '61', '64', '67', '68', '72', '75', '76', '77', '78', '84', '87', '89', '94', '95', '100', '101', '102', '107', '110', '114', '115', '122', '123', '129', '130', '131', '134', '136', '137', '141', '144', '146', '150', '153', '154', '157', '160', '161', '162', '166', '167', '172', '174', '176', '178', '179', '180', '183', '184', '185', '186', '187', '197', '199', '201', '203', '204', '205', '207', '208', '210', '211', '214', '217', '219', '220', '222', '226', '228')), c(5, 60, 61, 62, 79, 81, 92, 95, 105, 107, 122, 145, 153, 166, 167, 173, 175, 177, 182, 186, 192, 194, 199, 201, 202, 203, 208, 211, 224, 226, 235, 239, 240, 243, 245, 252, 266, 268, 269, 272, 276, 285, 292, 293, 296, 305, 310, 315, 332, 340, 345, 348, 350, 351, 356, 361, 363, 364, 371, 376, 382, 384, 426, 433, 444, 450, 473, 511, 520, 524, 529, 543, 550, 551, 559, 588, 641, 654, 687, 705, 728, 731, 735, 740, 765, 821, 965), FALSE, c('5', '60', '61', '62', '79', '81', '92', '95', '105', '107', '122', '145', '153', '166', '167', '173', '175', '177', '182', '186', '192', '194', '199', '201', '202', '203', '208', '211', '224', '226', '235', '239', '240', '243', '245', '252', '266', '268', '269', '272', '276', '285', '292', '293', '296', '305', '310', '315', '332', '340', '345', '348', '350', '351', '356', '361', '363', '364', '371', '376', '382', '384', '426', '433', '444', '450', '473', '511', '520', '524', '529', '543', '550', '551', '559', '588', '641', '654', '687', '705', '728', '731', '735', '740', '765', '821', '965')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
     }
 
     @Test
     public void testrowsum3() {
-        assertEval(Ignored.Unknown, "argv <- list(numeric(0), numeric(0), numeric(0), FALSE, character(0)); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
+        assertEval("argv <- list(numeric(0), numeric(0), numeric(0), FALSE, character(0)); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
     }
 
     @Test
     public void testrowsum4() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(structure(c(0.432389384893196, 2.31273022636069, 0, 2.31273022636069, 0.432389384893196, 0), .Names = c('1', '3', '4', '5', '6', '7')), structure(c(9, 1, 1, 6, 6, 8), .Names = c('1', '3', '4', '5', '6', '7')), c(1, 6, 8, 9), FALSE, c('1', '6', '8', '9')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
+        assertEval("argv <- list(structure(c(0.432389384893196, 2.31273022636069, 0, 2.31273022636069, 0.432389384893196, 0), .Names = c('1', '3', '4', '5', '6', '7')), structure(c(9, 1, 1, 6, 6, 8), .Names = c('1', '3', '4', '5', '6', '7')), c(1, 6, 8, 9), FALSE, c('1', '6', '8', '9')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
     }
 
     @Test
     public void testrowsum5() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(structure(c(0.102430555555556, 0.102430555555556, 0.102430555555556, 0.546875, -0.078125, 0.477430555555556, -0.0642361111111111, 0.102430555555556), .Names = c('1', '2', '3', '4', '5', '6', '7', '8')), structure(1:8, .Label = c('1', '2', '3', '4', '5', '6', '7', '8'), class = 'factor'), structure(1:8, .Label = c('1', '2', '3', '4', '5', '6', '7', '8'), class = 'factor'), FALSE, c('1', '2', '3', '4', '5', '6', '7', '8')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
+        assertEval("argv <- list(structure(c(0.102430555555556, 0.102430555555556, 0.102430555555556, 0.546875, -0.078125, 0.477430555555556, -0.0642361111111111, 0.102430555555556), .Names = c('1', '2', '3', '4', '5', '6', '7', '8')), structure(1:8, .Label = c('1', '2', '3', '4', '5', '6', '7', '8'), class = 'factor'), structure(1:8, .Label = c('1', '2', '3', '4', '5', '6', '7', '8'), class = 'factor'), FALSE, c('1', '2', '3', '4', '5', '6', '7', '8')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
     }
 
     @Test
     public void testrowsum6() {
-        assertEval(Ignored.Unknown,
+        // NA prints as NaN
+        assertEval(Ignored.OutputFormatting,
                         "argv <- list(structure(c(0, 0.719170679378362, -0.280829320621638, 0, -0.43834135875385, 0, -0.0525040127116955, 0.783590877798991, -0.365543432545085, -0.0525040127116955, -0.31303941983339, 0, 0, NA), .Names = c('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14')), c(3, 3, 4, 5, 5, 6, 6, 6, 7, 1, 1, 1, 1, 2), c(1, 2, 3, 4, 5, 6, 7), FALSE, c('1', '2', '3', '4', '5', '6', '7')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
     }
 
     @Test
     public void testrowsum7() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(structure(c(0.10270237599789, 2.6083215370191, 11.0196744330572, 2.6083215370191, 0.10270237599789, 0.10270237599789, 0.10270237599789, -0.441795512568419, 2.6083215370191, 0.10270237599789, -0.441795512568419), .Dim = c(11L, 1L), .Dimnames = list(c('11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21'), 'x')), structure(c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), .Names = c('11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21')), c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), FALSE, c('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
+        assertEval("argv <- list(structure(c(0.10270237599789, 2.6083215370191, 11.0196744330572, 2.6083215370191, 0.10270237599789, 0.10270237599789, 0.10270237599789, -0.441795512568419, 2.6083215370191, 0.10270237599789, -0.441795512568419), .Dim = c(11L, 1L), .Dimnames = list(c('11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21'), 'x')), structure(c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), .Names = c('11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21')), c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), FALSE, c('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
     }
 
     @Test
     public void testrowsum8() {
-        assertEval(Ignored.Unknown,
-                        "argv <- list(structure(c(1.33333333333333, -1.33333333333333, 1, 1.33333333333333, -2, 0.666666666666667, -0.666666666666667, 0.666666666666667, -0.666666666666667), .Dim = c(9L, 1L), .Dimnames = list(c('1', '2', '3', '4', '5', '6', '7', '8', '9'), 'x')), structure(c(1, 1, 2, 2, 2, 2, 3, 4, 5), .Names = c('1', '2', '3', '4', '5', '6', '7', '8', '9')), c(1, 2, 3, 4, 5), FALSE, c('1', '2', '3', '4', '5')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
+        assertEval("argv <- list(structure(c(1.33333333333333, -1.33333333333333, 1, 1.33333333333333, -2, 0.666666666666667, -0.666666666666667, 0.666666666666667, -0.666666666666667), .Dim = c(9L, 1L), .Dimnames = list(c('1', '2', '3', '4', '5', '6', '7', '8', '9'), 'x')), structure(c(1, 1, 2, 2, 2, 2, 3, 4, 5), .Names = c('1', '2', '3', '4', '5', '6', '7', '8', '9')), c(1, 2, 3, 4, 5), FALSE, c('1', '2', '3', '4', '5')); .Internal(rowsum_matrix(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))");
     }
 }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
index e955f5709063a85d88301d569d56c80e5ee9a09a..b4720533ce8e7378ebe9df32d4c73f6cc2ccf59c 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java
@@ -38,7 +38,6 @@ import com.oracle.truffle.r.runtime.RCmdOptions;
 import com.oracle.truffle.r.runtime.RCmdOptions.Client;
 import com.oracle.truffle.r.runtime.RError;
 import com.oracle.truffle.r.runtime.RInternalError;
-import com.oracle.truffle.r.runtime.RInternalSourceDescriptions;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.context.ConsoleHandler;
 import com.oracle.truffle.r.runtime.context.ContextInfo;
@@ -142,7 +141,7 @@ public final class FastRSession implements RSession {
         return singleton;
     }
 
-    public static final Source GET_CONTEXT = RSource.fromText("invisible(.fastr.context.get())", "<get_context>");
+    public static final Source GET_CONTEXT = RSource.fromTextInternal("invisible(.fastr.context.get())", RSource.Internal.GET_CONTEXT);
 
     public PolyglotEngine createTestContext(ContextInfo contextInfoArg) {
         create();
@@ -152,7 +151,7 @@ public final class FastRSession implements RSession {
         } else {
             contextInfo = contextInfoArg;
         }
-        return contextInfo.apply(PolyglotEngine.newBuilder()).build();
+        return contextInfo.createVM();
     }
 
     public ContextInfo createContextInfo(ContextKind contextKind) {
@@ -165,7 +164,7 @@ public final class FastRSession implements RSession {
         try {
             RCmdOptions options = RCmdOptions.parseArguments(Client.RSCRIPT, new String[]{"--no-restore"});
             ContextInfo info = ContextInfo.create(options, ContextKind.SHARE_NOTHING, null, consoleHandler);
-            main = info.apply(PolyglotEngine.newBuilder()).build();
+            main = info.createVM();
             try {
                 mainContext = main.eval(GET_CONTEXT).as(RContext.class);
                 emitIO();
@@ -245,7 +244,7 @@ public final class FastRSession implements RSession {
                     try {
                         String input = consoleHandler.readLine();
                         while (input != null) {
-                            Source source = RSource.fromText(input, RInternalSourceDescriptions.UNIT_TEST);
+                            Source source = RSource.fromTextInternal(input, RSource.Internal.UNIT_TEST);
                             try {
                                 vm.eval(source);
                                 input = consoleHandler.readLine();
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
index 7eab4bdb9e6ae9574373b6d691d851e88c6e1baf..318c667e9affa52073115f643799afd861e7c6d8 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
@@ -90,7 +90,7 @@ public class FastRDebugTest {
     }
 
     private static Source createFactorial() {
-        return RSource.fromText("main <- function() {\n" +
+        return RSource.fromTextInternal("main <- function() {\n" +
                         "  res = fac(2)\n" +
                         "  res\n" +
                         "}\n" +
@@ -104,7 +104,7 @@ public class FastRDebugTest {
                         "        res\n" +
                         "    }\n" +
                         "}\n",
-                        "factorial.r");
+                        RSource.Internal.DEBUGTEST_FACTORIAL);
     }
 
     protected final String getOut() {
@@ -150,7 +150,7 @@ public class FastRDebugTest {
                         "n", 2.0);
         continueExecution();
 
-        final Source evalSrc = RSource.fromText("main()\n", "debugtest.r");
+        final Source evalSrc = RSource.fromTextInternal("main()\n", RSource.Internal.DEBUGTEST_DEBUG);
         final Value value = engine.eval(evalSrc);
         assertExecutedOK();
         Assert.assertEquals("[1] 2\n", getOut());
@@ -198,7 +198,7 @@ public class FastRDebugTest {
         assertLocation(3, "res", "res", 2.0);
         stepOut();
 
-        final Source evalSource = RSource.fromText("main()\n", "evaltest.r");
+        final Source evalSource = RSource.fromTextInternal("main()\n", RSource.Internal.DEBUGTEST_EVAL);
         final Value value = engine.eval(evalSource);
         assertExecutedOK();
         Assert.assertEquals("[1] 2\n", getOut());
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRTckTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRTckTest.java
index 4453c6ad7eb244fd67375b6fe6e9000628871ecd..0fa17726fa7cf87ef2fa63b2587007471c5b3fc2 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRTckTest.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRTckTest.java
@@ -40,7 +40,7 @@ public class FastRTckTest extends TruffleTCK {
     }
 
     // @formatter:off
-    private static final Source INITIALIZATION = RSource.fromText(
+    private static final Source INITIALIZATION = RSource.fromTextInternal(
         "fourtyTwo <- function() {\n" +
         "  42L\n" +
         "}\n" +
@@ -100,7 +100,7 @@ public class FastRTckTest extends TruffleTCK {
         "  list('byteValue'=0L, 'shortValue'=0L, 'intValue'=0L, 'longValue'=0L, 'floatValue'=0, 'doubleValue'=0, 'charValue'=48L, 'stringValue'='', 'booleanValue'=FALSE)\n" +
         "}\n" +
         ".fastr.interop.export('valuesObject', valuesObject)\n",
-        "<initialization>"
+        RSource.Internal.TCK_INIT
     );
     // @formatter:on
 
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index 127e3a5f5a4966ab412b45a45adc8a0ad312ec01..d00961fd8b0f297a0227a0f693c8284c0eda0c20 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -156,6 +156,7 @@ com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Row.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowMeans.java,purdue.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowSums.java,purdue.copyright
+com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RowsumFunctions.java,gnu_r_gentleman_ihaka2.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/S3DispatchFunctions.java,purdue.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sample.java,gnu_r_sample.copyright
 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtrim.java,gnu_r_gentleman_ihaka.copyright
diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py
index 0e0bdb7ee83826c271a2af54ae9696c2b69ac053..c8de59b9adc32b88b093e0edb259ab209aa4fff8 100644
--- a/mx.fastr/suite.py
+++ b/mx.fastr/suite.py
@@ -317,6 +317,7 @@ suite = {
       "sourceDirs" : ["src"],
       "dependencies" : [
         "truffle:TRUFFLE_API",
+        "truffle:TRUFFLE_DEBUG",
       ],
       "checkstyle" : "com.oracle.truffle.r.runtime",
       "javaCompliance" : "1.8",