From 2bee338b022e0d66192aeeef1db6501a2a6e9ae8 Mon Sep 17 00:00:00 2001 From: Lukas Stadler <lukas.stadler@oracle.com> Date: Tue, 31 Jan 2017 16:07:12 +0100 Subject: [PATCH] introduce visibleExecute and use whereever visibility is required --- .../com/oracle/truffle/r/engine/REngine.java | 4 +- .../r/nodes/builtin/base/BasePackage.java | 4 +- .../truffle/r/nodes/builtin/base/Return.java | 55 ++++++++++++++--- .../r/nodes/builtin/base/WithVisible.java | 61 +++++++++++++++---- .../truffle/r/nodes/InlineCacheNode.java | 2 +- .../truffle/r/nodes/access/ConstantNode.java | 24 +++++--- .../nodes/access/WriteVariableSyntaxNode.java | 19 +++++- .../access/variables/ReadVariableNode.java | 30 ++++++--- .../r/nodes/builtin/RBuiltinRootNode.java | 4 +- .../truffle/r/nodes/control/BlockNode.java | 23 ++++++- .../truffle/r/nodes/control/IfNode.java | 57 +++++++++++------ .../control/ReplacementDispatchNode.java | 13 +++- .../function/FunctionDefinitionNode.java | 4 +- .../r/nodes/function/PromiseHelperNode.java | 10 ++- .../r/nodes/function/RCallSpecialNode.java | 16 +++++ .../nodes/function/WrapArgumentBaseNode.java | 15 ++++- .../visibility/SetVisibilityNode.java | 13 +--- .../oracle/truffle/r/runtime/nodes/RNode.java | 17 +++++- .../instrumentation/RNodeWrapperFactory.java | 15 ++++- 19 files changed, 297 insertions(+), 89 deletions(-) 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 87c08f476e..7dee98d92d 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 @@ -525,7 +525,7 @@ final class REngine implements Engine, Engine.Timings { VirtualFrame vf = prepareFrame(frame); Object result = null; try { - result = body.execute(vf); + result = body.visibleExecute(vf); assert checkResult(result); if (printResult && result != null) { assert topLevel; @@ -536,7 +536,7 @@ final class REngine implements Engine, Engine.Timings { if (topLevel) { RErrorHandling.printWarnings(suppressWarnings); } - setVisibility.executeEndOfFunction(vf, this); + setVisibility.executeEndOfFunction(vf); } catch (RError e) { CompilerDirectives.transferToInterpreter(); throw e; 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 369665c952..4910299b1d 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 @@ -335,7 +335,7 @@ public class BasePackage extends RBuiltinPackage { add(EnvFunctions.UnlockBinding.class, EnvFunctionsFactory.UnlockBindingNodeGen::create); add(Eval.class, EvalNodeGen::create); add(RecordGraphics.class, RecordGraphics::create); - add(WithVisible.class, WithVisibleNodeGen::create); + add(WithVisible.class, WithVisibleNodeGen::create, WithVisible::createSpecial); add(Exists.class, ExistsNodeGen::create); add(Expression.class, ExpressionNodeGen::create); add(FastRContext.R.class, FastRContextFactory.RNodeGen::create); @@ -567,7 +567,7 @@ public class BasePackage extends RBuiltinPackage { add(Repeat.class, RepeatNodeGen::create); add(RepeatInternal.class, RepeatInternalNodeGen::create); add(RepeatLength.class, RepeatLengthNodeGen::create); - add(Return.class, ReturnNodeGen::create); + add(Return.class, ReturnNodeGen::create, Return::createSpecial); add(Rhome.class, RhomeNodeGen::create); add(Rm.class, RmNodeGen::create); add(Round.class, RoundNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java index d2407dfe62..7001a7a168 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Return.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,16 +25,39 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; +import com.oracle.truffle.r.nodes.function.PromiseHelperNode; +import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; +import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.ReturnException; import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RPromise; +import com.oracle.truffle.r.runtime.nodes.RNode; + +final class ReturnSpecial extends RNode { + + @Child private RNode value; + private final BranchProfile isPromiseEvalProfile = BranchProfile.create(); + + protected ReturnSpecial(RNode value) { + this.value = value; + } + + @Override + public Object execute(VirtualFrame frame) { + return Return.doReturn(frame, value.visibleExecute(frame), isPromiseEvalProfile); + } +} /** * Return a value from the currently executing function, which is identified by the @@ -42,18 +65,14 @@ import com.oracle.truffle.r.runtime.data.RNull; * delivered via a {@link ReturnException}, which is subsequently caught in the * {@link FunctionDefinitionNode}. */ -@RBuiltin(name = "return", kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX) +@RBuiltin(name = "return", kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX, nonEvalArgs = {0}) public abstract class Return extends RBuiltinNode { - private final BranchProfile isPromiseEvalProfile = BranchProfile.create(); - - @Override - public Object[] getDefaultParameterValues() { - return new Object[]{RNull.instance}; + public static RNode createSpecial(@SuppressWarnings("unused") ArgumentsSignature signature, RNode[] arguments, @SuppressWarnings("unused") boolean inReplacement) { + return arguments.length == 1 ? new ReturnSpecial(arguments[0]) : null; } - @Specialization - protected Object returnFunction(VirtualFrame frame, Object value) { + static ReturnException doReturn(VirtualFrame frame, Object value, BranchProfile isPromiseEvalProfile) { RCaller call = RArguments.getCall(frame); while (call.isPromise()) { isPromiseEvalProfile.enter(); @@ -61,4 +80,22 @@ public abstract class Return extends RBuiltinNode { } throw new ReturnException(value, call); } + + @Specialization + protected Object returnFunction(VirtualFrame frame, RPromise x, + @Cached("new()") PromiseHelperNode promiseHelper, + @Cached("create()") BranchProfile isPromiseEvalProfile, + @Cached("create()") SetVisibilityNode visibility) { + if (x.isEvaluated()) { + visibility.execute(frame, true); + } + Object value = promiseHelper.evaluate(frame, x); + throw doReturn(frame, value, isPromiseEvalProfile); + } + + @Specialization + protected RList returnFunction(VirtualFrame frame, @SuppressWarnings("unused") RMissing x, + @Cached("create()") BranchProfile isPromiseEvalProfile) { + throw doReturn(frame, RNull.instance, isPromiseEvalProfile); + } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java index f1bdec68e3..5fb69cbcaa 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/WithVisible.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,37 +25,76 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.visibility.GetVisibilityNode; +import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RMissing; +import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.nodes.RNode; + +final class WithVisibleSpecial extends RNode { + + @Child private RNode delegate; + @Child private GetVisibilityNode visibility = GetVisibilityNode.create(); + + protected WithVisibleSpecial(RNode delegate) { + this.delegate = delegate; + } + + @Override + public Object execute(VirtualFrame frame) { + Object value = delegate.visibleExecute(frame); + if (value == RMissing.instance) { + CompilerDirectives.transferToInterpreter(); + throw RError.error(this, Message.ARGUMENT_MISSING, "x"); + } + return RDataFactory.createList(new Object[]{value, RRuntime.asLogical(visibility.execute(frame))}, WithVisible.LISTNAMES); + } +} // TODO The base package manual says this is a primitive but GNU R implements it as .Internal. // That causes problems as the .Internal adds another layer of visibility setting that // gets the wrong result. I believe that the only way to handle it as a .Internal would be to // set noEvalArgs and evaluate the argument here and set the visibility explicitly. -@RBuiltin(name = "withVisible", kind = PRIMITIVE, parameterNames = "x", behavior = COMPLEX) +@RBuiltin(name = "withVisible", kind = PRIMITIVE, parameterNames = "x", behavior = COMPLEX, nonEvalArgs = {0}) public abstract class WithVisible extends RBuiltinNode { - private static final RStringVector LISTNAMES = (RStringVector) RDataFactory.createStringVector(new String[]{"value", "visible"}, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent(); + static final RStringVector LISTNAMES = (RStringVector) RDataFactory.createStringVector(new String[]{"value", "visible"}, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent(); - @Override - protected void createCasts(CastBuilder casts) { - casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENT_MISSING, "x"); + public static RNode createSpecial(@SuppressWarnings("unused") ArgumentsSignature signature, RNode[] arguments, @SuppressWarnings("unused") boolean inReplacement) { + return arguments.length == 1 ? new WithVisibleSpecial(arguments[0]) : null; + } + + @Specialization + protected RList withVisible(VirtualFrame frame, RPromise x, + @Cached("create()") GetVisibilityNode visibility, + @Cached("new()") PromiseHelperNode promiseHelper) { + if (x.isEvaluated()) { + return RDataFactory.createList(new Object[]{x.getValue(), RRuntime.LOGICAL_TRUE}, LISTNAMES); + } + Object value = promiseHelper.evaluate(frame, x); + if (value == RMissing.instance) { + CompilerDirectives.transferToInterpreter(); + throw RError.error(this, Message.ARGUMENT_MISSING, "x"); + } + return RDataFactory.createList(new Object[]{value, RRuntime.asLogical(visibility.execute(frame))}, LISTNAMES); } @Specialization - protected RList withVisible(VirtualFrame frame, Object x, - @Cached("create()") GetVisibilityNode visibility) { - Object[] data = new Object[]{x, RRuntime.asLogical(visibility.execute(frame))}; - return RDataFactory.createList(data, LISTNAMES); + protected RList withVisible(@SuppressWarnings("unused") RMissing x) { + CompilerDirectives.transferToInterpreter(); + throw RError.error(this, Message.ARGUMENT_MISSING, "x"); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java index 8cc35b81b0..40622acfcd 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/InlineCacheNode.java @@ -71,7 +71,7 @@ public abstract class InlineCacheNode extends RBaseNode { } else { vf = SubstituteVirtualFrame.create(frame.materialize()); } - return reified.execute(vf); + return reified.visibleExecute(vf); } protected RNode cache(Object value) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java index 9cdd88d0e8..5a339754ec 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package com.oracle.truffle.r.nodes.access; import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.source.SourceSection; @@ -39,7 +40,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; public abstract class ConstantNode extends RSourceSectionNode implements RSyntaxNode, RSyntaxConstant { - @Child private SetVisibilityNode visibility = SetVisibilityNode.create(); + @Child private SetVisibilityNode visibility; private ConstantNode(SourceSection sourceSection) { super(sourceSection); @@ -60,13 +61,23 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax @Override public abstract Object getValue(); - protected final void handleVisibility(VirtualFrame frame) { - visibility.execute(frame, true); + @Override + public final void voidExecute(VirtualFrame frame) { + // nothing to do } @Override public final Object execute(VirtualFrame frame) { - handleVisibility(frame); + return getValue(); + } + + @Override + public final Object visibleExecute(VirtualFrame frame) { + if (visibility == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + visibility = insert(SetVisibilityNode.create()); + } + visibility.execute(frame, true); return getValue(); } @@ -113,7 +124,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax @Override public double executeDouble(VirtualFrame frame) { - handleVisibility(frame); return doubleValue; } } @@ -136,7 +146,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax @Override public byte executeByte(VirtualFrame frame) { - handleVisibility(frame); return logicalValue; } } @@ -159,7 +168,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax @Override public int executeInteger(VirtualFrame frame) { - handleVisibility(frame); return intValue; } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java index a442c0747a..2840ed66f3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableSyntaxNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.access; import static com.oracle.truffle.api.nodes.NodeCost.NONE; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.source.SourceSection; @@ -42,7 +43,7 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup; public final class WriteVariableSyntaxNode extends OperatorNode { @Child private WriteVariableNode write; - @Child private SetVisibilityNode visibility = SetVisibilityNode.create(); + @Child private SetVisibilityNode visibility; private final RSyntaxElement lhs; @@ -68,9 +69,23 @@ public final class WriteVariableSyntaxNode extends OperatorNode { assert write != null; } + @Override + public void voidExecute(VirtualFrame frame) { + write.execute(frame); + } + @Override public Object execute(VirtualFrame frame) { + return write.execute(frame); + } + + @Override + public Object visibleExecute(VirtualFrame frame) { Object result = write.execute(frame); + if (visibility == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + visibility = insert(SetVisibilityNode.create()); + } visibility.execute(frame, false); return result; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java index cf0585f4b1..990fdbfe45 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,7 +125,7 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta @Child private PromiseHelperNode promiseHelper; @Child private CheckTypeNode checkTypeNode; - @Child private SetVisibilityNode visibility = SetVisibilityNode.create(); + @Child private SetVisibilityNode visibility; @CompilationFinal private FrameLevel read; @CompilationFinal private boolean needsCopying; @@ -167,20 +167,34 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta return identifier instanceof String; } + @Override + public void voidExecute(VirtualFrame frame) { + executeInternal(frame, frame); + } + @Override public Object execute(VirtualFrame frame) { - return executeInternal(frame, kind == ReadKind.Super ? superEnclosingFrameProfile.profile(RArguments.getEnclosingFrame(frame)) : frame); + return executeInternal(frame, frame); + } + + @Override + public Object visibleExecute(VirtualFrame frame) { + assert kind != ReadKind.Silent; + if (visibility == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + visibility = insert(SetVisibilityNode.create()); + } + visibility.execute(frame, true); + return executeInternal(frame, frame); } public Object execute(VirtualFrame frame, Frame variableFrame) { assert frame != null; - return executeInternal(frame, kind == ReadKind.Super ? superEnclosingFrameProfile.profile(RArguments.getEnclosingFrame(variableFrame)) : variableFrame); + return executeInternal(frame, variableFrame); } - private Object executeInternal(VirtualFrame frame, Frame variableFrame) { - if (kind != ReadKind.Silent) { - visibility.execute(frame, true); - } + private Object executeInternal(VirtualFrame frame, Frame initialFrame) { + Frame variableFrame = kind == ReadKind.Super ? superEnclosingFrameProfile.profile(RArguments.getEnclosingFrame(initialFrame)) : initialFrame; Object result; if (read == null) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java index 9e0044e241..88652dcff5 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RBuiltinRootNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,7 +89,7 @@ public final class RBuiltinRootNode extends RRootNode { throw new RInternalError(e, "internal error"); } finally { visibility.execute(frame, factory.getVisibility()); - visibility.executeEndOfFunction(frame, this); + visibility.executeEndOfFunction(frame); } } 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 6b94d1cb09..e660d18e3c 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.nodes.control; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.source.SourceSection; @@ -41,7 +42,7 @@ public final class BlockNode extends OperatorNode { public static final RNode[] EMPTY_BLOCK = new RNode[0]; @Children protected final RNode[] sequence; - @Child private SetVisibilityNode visibility = SetVisibilityNode.create(); + @Child private SetVisibilityNode visibility; public BlockNode(SourceSection src, RSyntaxLookup operator, RNode[] sequence) { super(src, operator); @@ -55,7 +56,6 @@ public final class BlockNode extends OperatorNode { @Override @ExplodeLoop public Object execute(VirtualFrame frame) { - visibility.execute(frame, true); if (sequence.length == 0) { return RNull.instance; } @@ -73,6 +73,23 @@ public final class BlockNode extends OperatorNode { } } + @Override + @ExplodeLoop + public Object visibleExecute(VirtualFrame frame) { + if (visibility == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + visibility = insert(SetVisibilityNode.create()); + } + visibility.execute(frame, true); + if (sequence.length == 0) { + return RNull.instance; + } + for (int i = 0; i < sequence.length - 1; i++) { + sequence[i].voidExecute(frame); + } + return sequence[sequence.length - 1].visibleExecute(frame); + } + @Override public RSyntaxNode[] getSyntaxArguments() { return RASTUtils.asSyntaxNodes(sequence); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java index fd5b395b0c..ae9a2cf35d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ public final class IfNode extends OperatorNode { @Child private ConvertBooleanNode condition; @Child private RNode thenPart; @Child private RNode elsePart; - @Child private SetVisibilityNode visibility = SetVisibilityNode.create(); + @Child private SetVisibilityNode visibility; private final ConditionProfile conditionProfile = ConditionProfile.createCountingProfile(); @@ -53,30 +53,32 @@ public final class IfNode extends OperatorNode { this.elsePart = elsePart == null ? null : elsePart.asRNode(); } - /** - * Result visibility of an {@code if} expression is not only a property of the {@code if} - * builtin; it also depends on whether there is an else branch or not, and on the condition. For - * instance, the expression {@code if (FALSE) 23} will evaluate to {@code NULL}, but the result - * will not be printed in the shell. Conversely, {@code NULL} will be printed for - * {@code if (FALSE) 23 else NULL} because the else branch is given. - */ - - @Override - public Object execute(VirtualFrame frame) { + private boolean evaluateCondition(VirtualFrame frame) { byte cond = condition.executeByte(frame); - visibility.execute(frame, elsePart != null || cond == RRuntime.LOGICAL_TRUE); - if (cond == RRuntime.LOGICAL_NA) { - // NA is the only remaining option CompilerDirectives.transferToInterpreter(); throw RError.error(this, RError.Message.NA_UNEXP); } + assert cond == RRuntime.LOGICAL_FALSE || cond == RRuntime.LOGICAL_TRUE : "logical value none of TRUE|FALSE|NA"; + return conditionProfile.profile(cond == RRuntime.LOGICAL_TRUE); + } - if (conditionProfile.profile(cond == RRuntime.LOGICAL_TRUE)) { - return thenPart.execute(frame); + @Override + public void voidExecute(VirtualFrame frame) { + if (evaluateCondition(frame)) { + thenPart.voidExecute(frame); } else { - assert cond == RRuntime.LOGICAL_FALSE : "logical value none of TRUE|FALSE|NA"; + if (elsePart != null) { + elsePart.voidExecute(frame); + } + } + } + @Override + public Object execute(VirtualFrame frame) { + if (evaluateCondition(frame)) { + return thenPart.execute(frame); + } else { if (elsePart != null) { return elsePart.execute(frame); } else { @@ -85,6 +87,25 @@ public final class IfNode extends OperatorNode { } } + @Override + public Object visibleExecute(VirtualFrame frame) { + if (evaluateCondition(frame)) { + return thenPart.visibleExecute(frame); + } else { + if (elsePart != null) { + return elsePart.visibleExecute(frame); + } else { + // otherwise: return invisible NULL + if (visibility == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + visibility = insert(SetVisibilityNode.create()); + } + visibility.execute(frame, false); + return RNull.instance; + } + } + } + public ConvertBooleanNode getCondition() { return condition; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java index 144d1200fd..ffd2040d06 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,16 +70,23 @@ public final class ReplacementDispatchNode extends OperatorNode { this.tempNamesStartIndex = tempNamesStartIndex; } + @Override + public void voidExecute(VirtualFrame frame) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + create(true).voidExecute(frame); + } + @Override public Object execute(VirtualFrame frame) { CompilerDirectives.transferToInterpreterAndInvalidate(); return create(false).execute(frame); + } @Override - public void voidExecute(VirtualFrame frame) { + public Object visibleExecute(VirtualFrame frame) { CompilerDirectives.transferToInterpreterAndInvalidate(); - create(true).voidExecute(frame); + return create(false).visibleExecute(frame); } public RNode create(boolean isVoid) { 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 33b8ab9319..3d5bd7b6d2 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 @@ -251,7 +251,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo verifyEnclosingAssumptions(frame); setupDispatchSlots(frame); saveArguments.execute(frame); - Object result = body.execute(frame); + Object result = body.visibleExecute(frame); normalExit.enter(); return result; } catch (ReturnException ex) { @@ -290,12 +290,12 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo * has no exit handlers (by fiat), so any exceptions from onExits handlers will be * caught above. */ - visibility.executeEndOfFunction(frame, this); if (argPostProcess != null) { resetArgs.enter(); argPostProcess.execute(frame); } if (runOnExitHandlers) { + visibility.executeEndOfFunction(frame); if (!noHandlerStackSlot.isValid() && frame.isObject(handlerStackSlot)) { try { RErrorHandling.restoreHandlerStack(frame.getObject(handlerStackSlot)); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java index ba04478ae0..75bf2c9831 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import com.oracle.truffle.api.profiles.PrimitiveValueProfile; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.nodes.InlineCacheNode; import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode; +import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; @@ -383,6 +384,8 @@ public class PromiseHelperNode extends RBaseNode { private static final int GENERIC = -2; @CompilationFinal private int cachedWrapIndex = UNINITIALIZED; + @Child private SetVisibilityNode visibility; + /** * Returns {@link EagerPromise#getEagerValue()} profiled. */ @@ -419,6 +422,11 @@ public class PromiseHelperNode extends RBaseNode { } } } + if (visibility == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + visibility = insert(SetVisibilityNode.create()); + } + visibility.execute(frame, true); return eagerValueProfile.profile(o); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java index 15cc7f5aa2..ce167a93b4 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java @@ -29,11 +29,13 @@ import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.nodes.access.variables.LocalReadVariableNode; +import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RDispatch; import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RVisibility; import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor; import com.oracle.truffle.r.runtime.builtins.RSpecialFactory; import com.oracle.truffle.r.runtime.context.RContext; @@ -120,10 +122,12 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode @Child private RNode functionNode; @Child private RNode special; + @Child private SetVisibilityNode visibility; private final RSyntaxNode[] arguments; private final ArgumentsSignature signature; private final RFunction expectedFunction; + private final RVisibility visible; /** * If this is true, then any bailout should simply be forwarded by re-throwing the exception. @@ -143,6 +147,7 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode this.functionNode = functionNode; this.arguments = arguments; this.signature = signature; + this.visible = expectedFunction.getRBuiltin().getVisibility(); } /** @@ -310,6 +315,17 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode return execute(frame, functionNode.execute(frame)); } + @Override + public Object visibleExecute(VirtualFrame frame) { + Object result = execute(frame, functionNode.execute(frame)); + if (visibility == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + visibility = insert(SetVisibilityNode.create()); + } + visibility.execute(frame, visible); + return result; + } + @Override public RSyntaxElement getSyntaxLHS() { return functionNode == null ? RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "FUN", true) : functionNode.asRSyntaxNode(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java index cb11340263..ebc6853f82 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/WrapArgumentBaseNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ package com.oracle.truffle.r.nodes.function; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage; import com.oracle.truffle.r.runtime.nodes.RNode; @@ -46,13 +47,23 @@ public abstract class WrapArgumentBaseNode extends RNode { return operand; } + @Override + public final void voidExecute(VirtualFrame frame) { + throw RInternalError.shouldNotReachHere(); + } + @Override public final Object execute(VirtualFrame frame) { - assert operand != null; Object result = operand.execute(frame); return execute(frame, result); } + @Override + public final Object visibleExecute(VirtualFrame frame) { + Object result = operand.visibleExecute(frame); + return execute(frame, result); + } + public Object execute(VirtualFrame frame, Object result) { if (isShareable.profile(result instanceof RSharingAttributeStorage)) { return handleShareable(frame, (RSharingAttributeStorage) result); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java index c20ab69256..a259f498ad 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/visibility/SetVisibilityNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; 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.nodes.RootNode; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RInternalError; @@ -88,19 +87,11 @@ public final class SetVisibilityNode extends Node { * Needs to be called at the end of each function, so that the visibility is transferred from * the current frame into the {@link RCaller}. */ - public void executeEndOfFunction(VirtualFrame frame, RootNode root) { + public void executeEndOfFunction(VirtualFrame frame) { ensureFrameSlot(frame); try { if (frame.isBoolean(frameSlot)) { RArguments.getCall(frame).setVisibility(frame.getBoolean(frameSlot) == Boolean.TRUE); - } else { - CompilerDirectives.transferToInterpreter(); - /* - * Most likely the (only) builtin call in the function was configured to - * RVisibility.CUSTOM and didn't actually set the visibility. Another possible - * problem is a node that is created by RASTBuilder that does not set visibility. - */ - throw RInternalError.shouldNotReachHere("visibility not set at the end of " + root.getName()); } } catch (FrameSlotTypeException e) { throw RInternalError.shouldNotReachHere(e); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java index c07a69b873..8629846c53 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java @@ -63,17 +63,28 @@ import com.oracle.truffle.r.runtime.env.REnvironment; @Instrumentable(factory = com.oracle.truffle.r.runtime.nodes.instrumentation.RNodeWrapperFactory.class) public abstract class RNode extends RBaseNode implements RInstrumentableNode { + /** + * Normal execute function that is called when the return value, but not its visibility is + * needed. + */ public abstract Object execute(VirtualFrame frame); /** - * This function can be called when the result is not needed, and normally just dispatches to - * {@link #execute(VirtualFrame)}. Its name does not start with "execute" so that the DSL does - * not treat it like an execute function. + * This function is called when the result is not needed. Its name does not start with "execute" + * so that the DSL does not treat it like an execute function. */ public void voidExecute(VirtualFrame frame) { execute(frame); } + /** + * This function is called when both the result and the result's visibility are needed. Its name + * does not start with "execute" so that the DSL does not treat it like an execute function. + */ + public Object visibleExecute(VirtualFrame frame) { + return execute(frame); + } + public int executeInteger(VirtualFrame frame) throws UnexpectedResultException { Object value = execute(frame); assert value != null; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java index d79719b63e..b385fc6fe9 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/instrumentation/RNodeWrapperFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,6 +80,19 @@ public final class RNodeWrapperFactory implements InstrumentableFactory<RNode> { } } + @Override + public Object visibleExecute(VirtualFrame frame) { + try { + probeNode.onEnter(frame); + Object returnValue = delegate.visibleExecute(frame); + probeNode.onReturnValue(frame, returnValue); + return returnValue; + } catch (Throwable t) { + probeNode.onReturnExceptional(frame, t); + throw t; + } + } + @Override public RSyntaxNode getRSyntaxNode() { return delegate.asRSyntaxNode(); -- GitLab