From ea784a2bbad2e9034550df44e8c86343310cf7be Mon Sep 17 00:00:00 2001 From: stepan <stepan.sindelar@oracle.com> Date: Wed, 4 Apr 2018 10:14:37 +0200 Subject: [PATCH] Change the AST structure so that args are copied in RootTagged node * New interface RootBodyNode implemented by FunctionBodyNode * FunctionBodyNode saves args and then executes the actual body node * New tag FunctionBodyBlockTag that tags BlockStatements that are function bodies * FastR debugger that used to listen to RootTags (originally BlockNodes that had FunctionDefinitionNode as parent) is now listening to FunctionBodyBlockTags --- .../com/oracle/truffle/r/engine/REngine.java | 35 +++- .../r/engine/RRuntimeASTAccessImpl.java | 71 ++++---- .../r/engine/TruffleRLanguageImpl.java | 3 +- .../nodes/builtin/helpers/DebugHandling.java | 26 +-- .../nodes/builtin/helpers/TraceHandling.java | 6 +- .../truffle/r/nodes/test/SpecialCallTest.java | 4 +- .../truffle/r/nodes/control/BlockNode.java | 2 +- .../r/nodes/function/FunctionBodyNode.java | 155 ++++++++++++++++++ .../function/FunctionDefinitionNode.java | 104 +----------- .../truffle/r/nodes/function/RCallNode.java | 5 + .../instrumentation/RInstrumentation.java | 5 +- .../r/nodes/instrumentation/RSyntaxTags.java | 19 ++- .../truffle/r/runtime/RootBodyNode.java | 60 +++++++ .../truffle/r/runtime/RootWithBody.java | 12 +- .../instrumentation/RRootBodyNodeWrapper.java | 91 ++++++++++ .../truffle/r/test/tck/FastRDebugTest.java | 4 +- 16 files changed, 437 insertions(+), 165 deletions(-) create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionBodyNode.java create mode 100644 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootBodyNode.java create mode 100644 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RRootBodyNodeWrapper.java 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 371e16066c..1fb2aa2354 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 @@ -43,6 +43,7 @@ import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.ExecutableNode; import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.api.source.Source; @@ -78,6 +79,7 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSource; import com.oracle.truffle.r.runtime.ReturnException; import com.oracle.truffle.r.runtime.RootWithBody; +import com.oracle.truffle.r.runtime.RootBodyNode; import com.oracle.truffle.r.runtime.ThreadTimings; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.Utils.DebugExitException; @@ -326,7 +328,7 @@ final class REngine implements Engine, Engine.Timings { statements[i] = list.get(i).asRNode(); } return new ExecutableNode(context.getLanguage()) { - @Child R2Foreign toForeignNode = R2Foreign.create(); + @Child private R2Foreign toForeignNode = R2Foreign.create(); @Override public Object execute(VirtualFrame frame) { @@ -529,14 +531,14 @@ final class REngine implements Engine, Engine.Timings { private final boolean topLevel; private final boolean suppressWarnings; - @Child private RNode body; + @Child private RootBodyNode body; @Child private GetVisibilityNode visibility = GetVisibilityNode.create(); @Child private SetVisibilityNode setVisibility = SetVisibilityNode.create(); protected AnonymousRootNode(REngine engine, RNode body, String description, boolean printResult, boolean topLevel) { super(engine.context.getLanguage()); this.suppressWarnings = engine.suppressWarnings; - this.body = body; + this.body = new AnonymousBodyNode(body); this.description = description; this.printResult = printResult; this.topLevel = topLevel; @@ -544,12 +546,12 @@ final class REngine implements Engine, Engine.Timings { @Override public SourceSection getSourceSection() { - return body.getSourceSection(); + return getBody().getSourceSection(); } @Override public boolean isInternal() { - return RSyntaxNode.isInternal(body.asRSyntaxNode().getLazySourceSection()); + return RSyntaxNode.isInternal(getBody().getLazySourceSection()); } private VirtualFrame prepareFrame(VirtualFrame frame) { @@ -620,6 +622,29 @@ final class REngine implements Engine, Engine.Timings { return false; } + @Override + public RSyntaxNode getBody() { + return body.getBody().asRSyntaxNode(); + } + } + + private static final class AnonymousBodyNode extends Node implements RootBodyNode { + @Child private RNode body; + + AnonymousBodyNode(RNode body) { + this.body = body; + } + + @Override + public Object visibleExecute(VirtualFrame frame) { + return body.visibleExecute(frame); + } + + @Override + public SourceSection getSourceSection() { + return body.getSourceSection(); + } + @Override public RNode getBody() { return body; 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 08cbe18cd4..63c73a1f26 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 @@ -33,6 +33,9 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; +import com.oracle.truffle.api.instrumentation.StandardTags.CallTag; +import com.oracle.truffle.api.instrumentation.StandardTags.RootTag; +import com.oracle.truffle.api.instrumentation.StandardTags.StatementTag; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.r.launcher.RCommand; @@ -54,6 +57,8 @@ import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation; +import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags.FunctionBodyBlockTag; +import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags.LoopTag; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; @@ -61,7 +66,7 @@ import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.ShowCallerOf; import com.oracle.truffle.r.runtime.RRuntimeASTAccess; -import com.oracle.truffle.r.runtime.RootWithBody; +import com.oracle.truffle.r.runtime.RootBodyNode; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.Engine; import com.oracle.truffle.r.runtime.context.RContext; @@ -265,45 +270,49 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { @Override public boolean isTaggedWith(Node node, Class<?> tag) { + if (node instanceof RootBodyNode) { + return (tag == RootTag.class); + } + if (node instanceof RootNode) { + // roots don't have any tags + return false; + } if (!(node instanceof RSyntaxNode)) { return false; } if (isInternalChild(node)) { return false; } - String className = tag.getSimpleName(); - switch (className) { - case "CallTag": - return node instanceof RCallNode; - - case "StatementTag": { - Node parent = ((RInstrumentableNode) node).unwrapParent(); - if (node instanceof BlockNode) { - // TODO we may reconsider this - return false; - } - // Most likely - if (parent instanceof BlockNode) { - return true; - } else { - // single statement block, variable parent - // note: RepeatingNode is not a RSyntaxElement but the body of a loop is - // under the repeating node ! - return parent instanceof FunctionDefinitionNode || parent instanceof RootWithBody || parent instanceof IfNode || AbstractLoopNode.isLoopBody(node); - } + if (tag == CallTag.class) { + return node instanceof RCallNode; + } + if (tag == FunctionBodyBlockTag.class) { + return node instanceof BlockNode && ((BlockNode) node).unwrapParent() instanceof RootBodyNode; + } + if (tag == LoopTag.class) { + return node instanceof AbstractLoopNode; + } + if (tag == StatementTag.class) { + if (node instanceof BlockNode) { + // so that the stepping location is not the block itself, but the first statement in + // the block, note that the FastR's own debugging and tracing mechanism uses + // FunctionBodyBlockTag to recognize function bodies. + return false; } - - case "RootTag": { - Node parent = ((RInstrumentableNode) node).unwrapParent(); - return parent instanceof FunctionDefinitionNode || parent instanceof RootWithBody; + // How to recognize statement from some node inside a statement (e.g. expression)? + Node parent = ((RInstrumentableNode) node).unwrapParent(); + if (parent instanceof BlockNode) { + // It's in a block of statements + return true; + } else { + // single statement block: as function body, if/else body, loop body + // note: RepeatingNode is not a RSyntaxElement but the body of a loop is + // under the repeating node ! + return parent instanceof RootBodyNode || parent instanceof IfNode || AbstractLoopNode.isLoopBody(node); } - - case "LoopTag": - return node instanceof AbstractLoopNode; - - default: - return false; } + // TODO: ExpressionTag: (!statement && !loop && !if && !call && !root)?? + return false; } private static boolean isInternalChild(Node node) { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java index e84096fba5..494ff445ab 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java @@ -39,6 +39,7 @@ import com.oracle.truffle.r.engine.interop.RForeignAccessFactoryImpl; import com.oracle.truffle.r.nodes.RASTBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinPackages; import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags; +import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags.FunctionBodyBlockTag; import com.oracle.truffle.r.runtime.ExitException; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RAccuracyInfo; @@ -57,7 +58,7 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory; import com.oracle.truffle.r.runtime.nodes.RBaseNode; @TruffleLanguage.Registration(name = "R", id = "R", version = "3.3.2", mimeType = {RRuntime.R_APP_MIME, RRuntime.R_TEXT_MIME}, interactive = true) -@ProvidedTags({StandardTags.CallTag.class, StandardTags.StatementTag.class, StandardTags.RootTag.class, RSyntaxTags.LoopTag.class}) +@ProvidedTags({StandardTags.CallTag.class, StandardTags.StatementTag.class, StandardTags.RootTag.class, RSyntaxTags.LoopTag.class, FunctionBodyBlockTag.class}) public final class TruffleRLanguageImpl extends TruffleRLanguage { private final HashMap<String, RFunction> builtinFunctionCache = new HashMap<>(); 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 70bda866de..e5d0ee8f42 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 @@ -46,6 +46,7 @@ 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.nodes.instrumentation.RSyntaxTags.FunctionBodyBlockTag; import com.oracle.truffle.r.runtime.JumpToTopLevelException; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RDeparse; @@ -76,7 +77,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxVisitor; * Three different listener classes are defined: * <ul> * <li>{@link FunctionStatementsEventListener}: attaches to function bodies and handles the special - * behavior on entry/exit</li> + * behavior on entry/exit</li>. Function body is distinguished with tag {@link FunctionBodyBlockTag} * <li>{@link StatementEventListener}: attaches to all {@code StandardTags.StatementTag} nodes and * handles "n" and "s" browser commands</li> * <li>{@link LoopStatementEventListener}: attaches to {@link AbstractLoopNode} instances and @@ -89,7 +90,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxVisitor; * mode and reset it's state on return. This is handled as follows: * <ol> * <li>On a step-into, attach a {@link StepIntoInstrumentListener} with a filter that matches all - * functions and the {@code StandardTags.RootTag} tag</li> + * functions and their bodies like {@link FunctionStatementsEventListener}.</li> * <li>On entry to that listener instrument/enable the function we have entered (if necessary) for * one-time (unless already)</li> * <li>Dispose the {@link StepIntoInstrumentListener} and continue, which will then stop at the @@ -219,7 +220,7 @@ public class DebugHandling { } @CompilationFinal private boolean disabled; - CyclicAssumption disabledUnchangedAssumption = new CyclicAssumption("debug event disabled state unchanged"); + private final CyclicAssumption disabledUnchangedAssumption = new CyclicAssumption("debug event disabled state unchanged"); boolean disabled() { return disabled || RContext.getInstance().stateInstrumentation.debugGloballyDisabled(); @@ -317,7 +318,7 @@ public class DebugHandling { @TruffleBoundary private void attachStepInto() { FunctionStatementsEventListener parentListener = getFunctionStatementsEventListener(functionDefinitionNode); - parentListener.stepIntoInstrument = RInstrumentation.getInstrumenter().attachExecutionEventListener(SourceSectionFilter.newBuilder().tagIs(StandardTags.RootTag.class).build(), + parentListener.stepIntoInstrument = RInstrumentation.getInstrumenter().attachExecutionEventListener(SourceSectionFilter.newBuilder().tagIs(FunctionBodyBlockTag.class).build(), new StepIntoInstrumentListener(parentListener)); } @@ -430,8 +431,10 @@ public class DebugHandling { public void attach() { + // Note: BlockStatement is not tagged as a STATEMENT, but there is FastR specific + // FunctionBodyBlockTag Instrumenter instrumenter = RInstrumentation.getInstrumenter(); - SourceSectionFilter.Builder functionBuilder = RInstrumentation.createFunctionFilter(functionDefinitionNode, StandardTags.RootTag.class); + SourceSectionFilter.Builder functionBuilder = RInstrumentation.createFunctionFilter(functionDefinitionNode, FunctionBodyBlockTag.class); setBinding(instrumenter.attachExecutionEventListener(functionBuilder.build(), this)); // Next attach statement handler to all STATEMENTs except LOOPs @@ -470,7 +473,7 @@ public class DebugHandling { accept(element.getSyntaxBody()); return null; } - }.accept(functionDefinitionNode); + }.accept(functionDefinitionNode.getBody()); } @Override @@ -524,8 +527,9 @@ public class DebugHandling { CompilerDirectives.transferToInterpreter(); print("debugging in: ", false); printCall(frame); - printNode(context.getInstrumentedNode(), true); - browserInteract(context.getInstrumentedNode(), frame); + Node node = context.getInstrumentedNode(); + printNode(node, true); + browserInteract(node, frame); } @Override @@ -582,6 +586,7 @@ public class DebugHandling { String callString = RContext.getRRuntimeASTAccess().getCallerSource(RArguments.getCall(frame)); print(callString, true); } + } @TruffleBoundary @@ -621,10 +626,7 @@ public class DebugHandling { // in case we did a step into that never called a function clearStepInstrument(); RBaseNode node = (RBaseNode) context.getInstrumentedNode(); - if (node.hasTag(StandardTags.RootTag.class)) { - // already handled - return; - } + assert !node.hasTag(StandardTags.RootTag.class) : "root is not a statement"; printNode(node, false); browserInteract(node, frame); } 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 72c9913923..142a26bbdd 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,9 +33,9 @@ import com.oracle.truffle.api.instrumentation.EventBinding; 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.utilities.CyclicAssumption; import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation; +import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags.FunctionBodyBlockTag; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; @@ -88,7 +88,7 @@ public class TraceHandling { if (FastROptions.TraceCalls.getBooleanValue()) { PrimitiveFunctionEntryEventListener fser = new PrimitiveFunctionEntryEventListener(); SourceSectionFilter.Builder builder = SourceSectionFilter.newBuilder(); - builder.tagIs(StandardTags.RootTag.class); + builder.tagIs(FunctionBodyBlockTag.class); SourceSectionFilter filter = builder.build(); RInstrumentation.getInstrumenter().attachExecutionEventListener(filter, fser); setOutputHandler(); @@ -122,7 +122,7 @@ public class TraceHandling { private abstract static class TraceEventListener implements ExecutionEventListener { @CompilationFinal private boolean disabled; - CyclicAssumption disabledUnchangedAssumption = new CyclicAssumption("trace event disabled state unchanged"); + private final CyclicAssumption disabledUnchangedAssumption = new CyclicAssumption("trace event disabled state unchanged"); protected TraceEventListener() { } diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/SpecialCallTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/SpecialCallTest.java index 243a5e9e83..89a959f4b3 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/SpecialCallTest.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/test/SpecialCallTest.java @@ -52,7 +52,7 @@ public class SpecialCallTest extends TestBase { public int special; CountCallsVisitor(RootCallTarget callTarget) { - accept(((RootWithBody) callTarget.getRootNode()).getBody().asRSyntaxNode()); + accept(((RootWithBody) callTarget.getRootNode()).getBody()); } @Override @@ -108,7 +108,7 @@ public class SpecialCallTest extends TestBase { void print(RootCallTarget callTarget) { System.out.println(); - accept(((RootWithBody) callTarget.getRootNode()).getBody().asRSyntaxNode()); + accept(((RootWithBody) callTarget.getRootNode()).getBody()); } @Override diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java index 184b48c6d5..bce05cd02c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java @@ -39,7 +39,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; */ public final class BlockNode extends OperatorNode { - @Children protected final RNode[] sequence; + @Children private final RNode[] sequence; @Child private SetVisibilityNode visibility; public BlockNode(SourceSection src, RSyntaxLookup operator, RNode[] sequence) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionBodyNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionBodyNode.java new file mode 100644 index 0000000000..949b918b94 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionBodyNode.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2018, 2018, 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 com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.frame.FrameSlotKind; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.BranchProfile; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.RArguments; +import com.oracle.truffle.r.runtime.RArguments.DispatchArgs; +import com.oracle.truffle.r.runtime.RArguments.S3Args; +import com.oracle.truffle.r.runtime.RArguments.S4Args; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RootBodyNode; +import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; +import com.oracle.truffle.r.runtime.nodes.RNode; + +public final class FunctionBodyNode extends Node implements RootBodyNode { + + @Child private RNode body; + @Child private RNode saveArguments; + @Child private SetupS3ArgsNode setupS3Args; + @Child private SetupS4ArgsNode setupS4Args; + + public FunctionBodyNode(RNode saveArguments, RNode body) { + this.body = body; + this.saveArguments = saveArguments; + } + + @Override + public Object visibleExecute(VirtualFrame frame) { + setupDispatchSlots(frame); + saveArguments.execute(frame); + return body.visibleExecute(frame); + } + + @Override + public RNode getBody() { + return body; + } + + @Override + public SourceSection getSourceSection() { + return body.getSourceSection(); + } + + private void setupDispatchSlots(VirtualFrame frame) { + DispatchArgs dispatchArgs = RArguments.getDispatchArgs(frame); + if (dispatchArgs == null) { + return; + } + if (dispatchArgs instanceof S3Args) { + S3Args s3Args = (S3Args) dispatchArgs; + if (setupS3Args == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + setupS3Args = insert(new SetupS3ArgsNode(frame.getFrameDescriptor())); + } + setupS3Args.execute(frame, s3Args); + } else { + S4Args s4Args = (S4Args) dispatchArgs; + if (setupS4Args == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + setupS4Args = insert(new SetupS4ArgsNode(frame.getFrameDescriptor())); + } + setupS4Args.execute(frame, s4Args); + } + } + + private abstract static class SetupDispatchNode extends Node { + // S3/S4 slots + private final FrameSlot dotGenericSlot; + private final FrameSlot dotMethodSlot; + + final BranchProfile invalidateFrameSlotProfile = BranchProfile.create(); + + SetupDispatchNode(FrameDescriptor frameDescriptor) { + dotGenericSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC, FrameSlotKind.Object); + dotMethodSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_METHOD, FrameSlotKind.Object); + } + + void executeDispatchArgs(VirtualFrame frame, DispatchArgs args) { + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericSlot, args.generic, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodSlot, args.method, false, invalidateFrameSlotProfile); + } + } + + private static final class SetupS3ArgsNode extends SetupDispatchNode { + // S3 slots + private final FrameSlot dotClassSlot; + private final FrameSlot dotGenericCallEnvSlot; + private final FrameSlot dotGenericCallDefSlot; + private final FrameSlot dotGroupSlot; + + SetupS3ArgsNode(FrameDescriptor frameDescriptor) { + super(frameDescriptor); + dotClassSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_CLASS, FrameSlotKind.Object); + dotGenericCallEnvSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC_CALL_ENV, FrameSlotKind.Object); + dotGenericCallDefSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC_DEF_ENV, FrameSlotKind.Object); + dotGroupSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GROUP, FrameSlotKind.Object); + } + + void execute(VirtualFrame frame, S3Args args) { + super.executeDispatchArgs(frame, args); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotClassSlot, args.clazz, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallEnvSlot, args.callEnv, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallDefSlot, args.defEnv, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGroupSlot, args.group, false, invalidateFrameSlotProfile); + } + } + + private static final class SetupS4ArgsNode extends SetupDispatchNode { + // S4 slots + private final FrameSlot dotDefinedSlot; + private final FrameSlot dotTargetSlot; + private final FrameSlot dotMethodsSlot; + + SetupS4ArgsNode(FrameDescriptor frameDescriptor) { + super(frameDescriptor); + dotDefinedSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_DEFINED, FrameSlotKind.Object); + dotTargetSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_TARGET, FrameSlotKind.Object); + dotMethodsSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_METHODS, FrameSlotKind.Object); + } + + void execute(VirtualFrame frame, S4Args args) { + super.executeDispatchArgs(frame, args); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotDefinedSlot, args.defined, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotTargetSlot, args.target, false, invalidateFrameSlotProfile); + FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodsSlot, args.methods, false, invalidateFrameSlotProfile); + } + } +} 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 fbb1754702..34712bf494 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 @@ -35,7 +35,6 @@ import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeUtil; import com.oracle.truffle.api.nodes.NodeUtil.NodeCountFilter; import com.oracle.truffle.api.profiles.BranchProfile; @@ -55,16 +54,13 @@ import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.ExitException; import com.oracle.truffle.r.runtime.JumpToTopLevelException; import com.oracle.truffle.r.runtime.RArguments; -import com.oracle.truffle.r.runtime.RArguments.DispatchArgs; -import com.oracle.truffle.r.runtime.RArguments.S3Args; -import com.oracle.truffle.r.runtime.RArguments.S4Args; import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RErrorHandling; import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.ReturnException; +import com.oracle.truffle.r.runtime.RootBodyNode; import com.oracle.truffle.r.runtime.Utils.DebugExitException; import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor; import com.oracle.truffle.r.runtime.context.RContext; @@ -89,7 +85,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo private final FormalArguments formalArguments; - @Child private RNode body; + @Child private RootBodyNode body; /** * This exists for debugging purposes. It is set initially when the function is defined to @@ -108,7 +104,6 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo private final RNodeClosureCache closureCache = new RNodeClosureCache(); - @Child private RNode saveArguments; @Child private FrameSlotNode onExitSlot; @Child private InlineCacheNode onExitExpressionCache; private final ConditionProfile onExitProfile = ConditionProfile.createBinaryProfile(); @@ -121,9 +116,6 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo @Child private PostProcessArgumentsNode argPostProcess; - @Child private SetupS3ArgsNode setupS3Args; - @Child private SetupS4ArgsNode setupS4Args; - private final boolean needsSplitting; @CompilationFinal private boolean containsDispatch; @@ -153,8 +145,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo assert FrameSlotChangeMonitor.isValidFrameDescriptor(frameDesc); assert src != null; this.sourceSectionR = src; - this.saveArguments = saveArguments; - this.body = body.asRNode(); + this.body = new FunctionBodyNode(saveArguments, body.asRNode()); this.name = name; this.onExitSlot = FrameSlotNode.createInitialized(frameDesc, RFrameSlot.OnExit, false); this.needsSplitting = needsAnyBuiltinSplitting(); @@ -269,7 +260,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo } public RSyntaxNode getBody() { - return body.asRSyntaxNode(); + return body.getBody().asRSyntaxNode(); } public PostProcessArgumentsNode getArgPostProcess() { @@ -281,8 +272,6 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo boolean runOnExitHandlers = true; try { verifyEnclosingAssumptions(frame); - setupDispatchSlots(frame); - saveArguments.execute(frame); Object result = body.visibleExecute(frame); normalExit.enter(); if (CompilerDirectives.inInterpreter() && result == null) { @@ -398,91 +387,6 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo } } - private abstract static class SetupDispatchNode extends Node { - // S3/S4 slots - private final FrameSlot dotGenericSlot; - private final FrameSlot dotMethodSlot; - - final BranchProfile invalidateFrameSlotProfile = BranchProfile.create(); - - SetupDispatchNode(FrameDescriptor frameDescriptor) { - dotGenericSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC, FrameSlotKind.Object); - dotMethodSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_METHOD, FrameSlotKind.Object); - } - - void execute(VirtualFrame frame, DispatchArgs args) { - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericSlot, args.generic, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodSlot, args.method, false, invalidateFrameSlotProfile); - } - } - - private static final class SetupS3ArgsNode extends SetupDispatchNode { - // S3 slots - private final FrameSlot dotClassSlot; - private final FrameSlot dotGenericCallEnvSlot; - private final FrameSlot dotGenericCallDefSlot; - private final FrameSlot dotGroupSlot; - - SetupS3ArgsNode(FrameDescriptor frameDescriptor) { - super(frameDescriptor); - dotClassSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_CLASS, FrameSlotKind.Object); - dotGenericCallEnvSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC_CALL_ENV, FrameSlotKind.Object); - dotGenericCallDefSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GENERIC_DEF_ENV, FrameSlotKind.Object); - dotGroupSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_GROUP, FrameSlotKind.Object); - } - - void execute(VirtualFrame frame, S3Args args) { - super.execute(frame, args); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotClassSlot, args.clazz, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallEnvSlot, args.callEnv, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGenericCallDefSlot, args.defEnv, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotGroupSlot, args.group, false, invalidateFrameSlotProfile); - } - } - - private static final class SetupS4ArgsNode extends SetupDispatchNode { - // S4 slots - private final FrameSlot dotDefinedSlot; - private final FrameSlot dotTargetSlot; - private final FrameSlot dotMethodsSlot; - - SetupS4ArgsNode(FrameDescriptor frameDescriptor) { - super(frameDescriptor); - dotDefinedSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_DEFINED, FrameSlotKind.Object); - dotTargetSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_TARGET, FrameSlotKind.Object); - dotMethodsSlot = FrameSlotChangeMonitor.findOrAddFrameSlot(frameDescriptor, RRuntime.R_DOT_METHODS, FrameSlotKind.Object); - } - - void execute(VirtualFrame frame, S4Args args) { - super.execute(frame, args); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotDefinedSlot, args.defined, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotTargetSlot, args.target, false, invalidateFrameSlotProfile); - FrameSlotChangeMonitor.setObjectAndInvalidate(frame, dotMethodsSlot, args.methods, false, invalidateFrameSlotProfile); - } - } - - private void setupDispatchSlots(VirtualFrame frame) { - DispatchArgs dispatchArgs = RArguments.getDispatchArgs(frame); - if (dispatchArgs == null) { - return; - } - if (dispatchArgs instanceof S3Args) { - S3Args s3Args = (S3Args) dispatchArgs; - if (setupS3Args == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - setupS3Args = insert(new SetupS3ArgsNode(frame.getFrameDescriptor())); - } - setupS3Args.execute(frame, s3Args); - } else { - S4Args s4Args = (S4Args) dispatchArgs; - if (setupS4Args == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - setupS4Args = insert(new SetupS4ArgsNode(frame.getFrameDescriptor())); - } - setupS4Args.execute(frame, s4Args); - } - } - private static RPairList getCurrentOnExitList(VirtualFrame frame, FrameSlot slot) { try { return (RPairList) FrameSlotChangeMonitor.getObject(slot, frame); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java index 6f987abcbb..1474a417c3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java @@ -787,6 +787,11 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS return arg; } + @Override + public SourceSection getSourceSection() { + return arg.getSourceSection(); + } + @Override public Object execute(VirtualFrame frame) { try { 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 56581f056d..e83d262ee7 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -30,6 +30,7 @@ import com.oracle.truffle.api.instrumentation.StandardTags; 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.nodes.instrumentation.RSyntaxTags.FunctionBodyBlockTag; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RSource; import com.oracle.truffle.r.runtime.context.RContext; @@ -102,7 +103,7 @@ public class RInstrumentation { public static SourceSectionFilter.Builder createFunctionStartFilter(RFunction func) { FunctionDefinitionNode fdn = (FunctionDefinitionNode) func.getRootNode(); SourceSectionFilter.Builder builder = SourceSectionFilter.newBuilder(); - builder.tagIs(StandardTags.RootTag.class); + builder.tagIs(FunctionBodyBlockTag.class); builder.sourceSectionEquals(fdn.getBody().getSourceSection()); return builder; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RSyntaxTags.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RSyntaxTags.java index 75e32fd080..becb1090f3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RSyntaxTags.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/instrumentation/RSyntaxTags.java @@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.instrumentation; import com.oracle.truffle.api.instrumentation.StandardTags; import com.oracle.truffle.api.instrumentation.Tag; +import com.oracle.truffle.r.runtime.RootBodyNode; public class RSyntaxTags { @@ -33,6 +34,22 @@ public class RSyntaxTags { } } + /** + * Marks a block of statements that is the body of a function, the difference to + * {@link com.oracle.truffle.api.instrumentation.StandardTags.RootTag} is that the + * {@code RootTag} is supposed to save arguments and then invoke the actual body tagged with + * this tag. + * + * More technically, this tag tags {@link com.oracle.truffle.r.nodes.control.BlockNode}s that + * have parent of type {@link RootBodyNode}. + */ + @Tag.Identifier("FUNCTIONBODYBLOCK") + public static final class FunctionBodyBlockTag extends Tag { + private FunctionBodyBlockTag() { + // no instances + } + } + @SuppressWarnings("unchecked") public static final Class<? extends Tag>[] ALL_TAGS = (Class<? extends Tag>[]) new Class<?>[]{StandardTags.CallTag.class, StandardTags.StatementTag.class, - StandardTags.RootTag.class, LoopTag.class}; + StandardTags.RootTag.class, LoopTag.class, FunctionBodyBlockTag.class}; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootBodyNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootBodyNode.java new file mode 100644 index 0000000000..68031a62f3 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootBodyNode.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.instrumentation.ProbeNode; +import com.oracle.truffle.api.instrumentation.StandardTags.RootTag; +import com.oracle.truffle.api.instrumentation.Tag; +import com.oracle.truffle.r.runtime.nodes.RInstrumentableNode; +import com.oracle.truffle.r.runtime.nodes.RNode; +import com.oracle.truffle.r.runtime.nodes.instrumentation.RRootBodyNodeWrapper; + +/** + * Marks a node that represents the body of a {@link com.oracle.truffle.api.nodes.RootNode}, such + * nodes are tagged with {@link com.oracle.truffle.api.instrumentation.StandardTags.RootTag} and + * should inherit {@link RNode}. + * + * The {@link RootBodyNode} task is to save the arguments from frame's arguments array to the local + * variables and then invoke the actual body statement accessible via {@link #getBody()}. + */ +public interface RootBodyNode extends RInstrumentableNode { + RNode getBody(); + + Object visibleExecute(VirtualFrame frame); + + @Override + default boolean isInstrumentable() { + return true; + } + + @Override + default boolean hasTag(Class<? extends Tag> tag) { + return tag == RootTag.class; + } + + @Override + default WrapperNode createWrapper(ProbeNode probe) { + return new RRootBodyNodeWrapper(this, probe); + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootWithBody.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootWithBody.java index b2736e10e5..2af8f9a54a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootWithBody.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RootWithBody.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,12 +22,16 @@ */ package com.oracle.truffle.r.runtime; -import com.oracle.truffle.r.runtime.nodes.RNode; +import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; /** - * Used for testing. + * Used to allow access to the body field for testing purposes. */ public interface RootWithBody { - RNode getBody(); + /** + * Should return the real body, i.e. what is wrapped by {@link RootBodyNode}. + */ + RSyntaxNode getBody(); + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RRootBodyNodeWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RRootBodyNodeWrapper.java new file mode 100644 index 0000000000..37ca385062 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RRootBodyNodeWrapper.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2018, 2018, 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.nodes.instrumentation; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.instrumentation.InstrumentableNode; +import com.oracle.truffle.api.instrumentation.ProbeNode; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeCost; +import com.oracle.truffle.api.nodes.NodeInfo; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.RootBodyNode; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@NodeInfo(cost = NodeCost.NONE) +public final class RRootBodyNodeWrapper extends Node implements RootBodyNode, InstrumentableNode.WrapperNode { + @Child private RootBodyNode delegate; + @Child private ProbeNode probeNode; + + public RRootBodyNodeWrapper(RootBodyNode delegate, ProbeNode probeNode) { + assert delegate != null; + assert !(delegate instanceof RRootBodyNodeWrapper); + this.delegate = delegate; + this.probeNode = probeNode; + } + + @Override + public Node getDelegateNode() { + return (Node) delegate; + } + + @Override + public ProbeNode getProbeNode() { + return probeNode; + } + + @Override + public Object visibleExecute(VirtualFrame frame) { + Object returnValue; + for (;;) { + boolean wasOnReturnExecuted = false; + try { + probeNode.onEnter(frame); + returnValue = delegate.visibleExecute(frame); + wasOnReturnExecuted = true; + probeNode.onReturnValue(frame, returnValue); + break; + } catch (Throwable t) { + Object result = probeNode.onReturnExceptionalOrUnwind(frame, t, wasOnReturnExecuted); + if (result == ProbeNode.UNWIND_ACTION_REENTER) { + continue; + } else if (result != null) { + returnValue = result; + break; + } + throw t; + } + } + return returnValue; + } + + @Override + public RNode getBody() { + return delegate.getBody(); + } + + @Override + public SourceSection getSourceSection() { + return ((Node) delegate).getSourceSection(); + } +} 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 00e515d31f..a18d440f52 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 @@ -39,7 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import com.oracle.truffle.api.debug.Breakpoint; @@ -498,7 +497,6 @@ public class FastRDebugTest { } @Test - @Ignore public void testReenterArgumentsAndValues() throws Throwable { // Test that after a re-enter, arguments are kept and variables are cleared. final Source source = sourceFromText("" + @@ -719,7 +717,7 @@ public class FastRDebugTest { } assertNotNull("identifier \"" + expectedIdentifier + "\" not found", value); String valueStr = value.as(String.class); - assertEquals(expectedValueStr, valueStr); + assertEquals(line + ": " + code + "; identifier: '" + expectedIdentifier + "'", expectedValueStr, valueStr); } if (!run.isEmpty()) { -- GitLab