Skip to content
Snippets Groups Projects
Commit d54c8ff3 authored by Stepan Sindelar's avatar Stepan Sindelar
Browse files

[GR-7776] [GR-8823] [GR-9063] [GR-9179] Implement new instrumentation features.

PullRequest: fastr/1462
parents c49d3b7c 03f1da76
No related branches found
No related tags found
No related merge requests found
Showing
with 843 additions and 884 deletions
/*
* Copyright (c) 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.engine;
import java.util.List;
import java.util.Set;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.frame.MaterializedFrame;
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.instrumentation.Tag;
import com.oracle.truffle.api.nodes.DirectCallNode;
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.source.SourceSection;
import com.oracle.truffle.r.runtime.ExitException;
import com.oracle.truffle.r.runtime.JumpToTopLevelException;
import com.oracle.truffle.r.runtime.RError;
import com.oracle.truffle.r.runtime.RInternalError;
import com.oracle.truffle.r.runtime.RSource;
import com.oracle.truffle.r.runtime.ReturnException;
import com.oracle.truffle.r.runtime.Utils.DebugExitException;
import com.oracle.truffle.r.runtime.context.RContext;
import com.oracle.truffle.r.runtime.data.RNull;
import com.oracle.truffle.r.runtime.interop.R2Foreign;
import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen;
import com.oracle.truffle.r.runtime.nodes.RNode;
import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
class EngineRootNode extends RootNode {
private final SourceSection sourceSection;
private final MaterializedFrame executionFrame;
private final ContextReference<RContext> contextReference;
@Child private EngineBodyNode bodyNode;
@Child private R2Foreign r2Foreign = R2ForeignNodeGen.create();
EngineRootNode(EngineBodyNode bodyNode, RContext context, SourceSection sourceSection, MaterializedFrame executionFrame) {
super(context.getLanguage());
this.sourceSection = sourceSection;
this.bodyNode = bodyNode;
this.executionFrame = executionFrame;
this.contextReference = context.getLanguage().getContextReference();
}
public static EngineRootNode createEngineRoot(REngine engine, RContext context, List<RSyntaxNode> statements, SourceSection sourceSection, MaterializedFrame executionFrame) {
return new EngineRootNode(new EngineBodyNode(engine, statements, getPrintResult(sourceSection)), context, sourceSection, executionFrame);
}
/**
* The normal {@link REngine#doMakeCallTarget} happens first, then we actually run the call
* using the standard FastR machinery, saving and restoring the {@link RContext}, since we have
* no control over what that might be when the call is initiated.
*/
@Override
public Object execute(VirtualFrame frame) {
Object actualFrame = executionFrame != null ? executionFrame : contextReference.get().stateREnvironment.getGlobalFrame();
try {
return r2Foreign.execute(this.bodyNode.execute(actualFrame));
} catch (ReturnException ex) {
return ex.getResult();
} catch (DebugExitException | JumpToTopLevelException | ExitException | ThreadDeath e) {
CompilerDirectives.transferToInterpreter();
throw e;
} catch (RError e) {
CompilerDirectives.transferToInterpreter();
throw e;
} catch (Throwable t) {
CompilerDirectives.transferToInterpreter();
// other errors didn't produce an output yet
RInternalError.reportError(t);
throw t;
}
}
@Override
public SourceSection getSourceSection() {
return sourceSection;
}
public static boolean isEngineBody(Object node) {
return node instanceof EngineBodyNode;
}
private static boolean getPrintResult(SourceSection sourceSection) {
// can't print if initializing the system in embedded mode (no builtins yet)
return !sourceSection.getSource().getName().equals(RSource.Internal.INIT_EMBEDDED.string) && sourceSection.getSource().isInteractive();
}
private static final class EngineBodyNode extends Node implements InstrumentableNode {
private final REngine engine;
private final List<RSyntaxNode> statements;
@Children protected final DirectCallNode[] calls;
private final boolean printResult;
EngineBodyNode(REngine engine, List<RSyntaxNode> statements, boolean printResult) {
this.engine = engine;
this.statements = statements;
this.calls = new DirectCallNode[statements.size()];
this.printResult = printResult;
}
@ExplodeLoop
Object execute(Object actualFrame) {
Object lastValue = RNull.instance;
int lastStatus = 0;
for (int i = 0; i < calls.length; i++) {
materializeCall(i);
lastValue = calls[i].call(new Object[]{actualFrame});
}
return lastValue;
}
@Override
public boolean isInstrumentable() {
return false;
}
@Override
public WrapperNode createWrapper(ProbeNode probe) {
return null;
}
@Override
public boolean hasTag(Class<? extends Tag> tag) {
return false;
}
@Override
public InstrumentableNode materializeInstrumentableNodes(Set<Class<? extends Tag>> materializedTags) {
for (int i = 0; i < calls.length; i++) {
materializeCall(i);
}
return this;
}
protected void materializeCall(int i) {
if (calls[i] == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
RNode node = statements.get(i).asRNode();
calls[i] = insert(Truffle.getRuntime().createDirectCallNode(engine.doMakeCallTarget(node, RSource.Internal.REPL_WRAPPER.string, printResult, true)));
}
}
}
}
......@@ -22,6 +22,11 @@
*/
package com.oracle.truffle.r.engine;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
......@@ -33,16 +38,14 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.dsl.UnsupportedSpecializationException;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.TruffleObject;
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 +81,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;
......@@ -97,7 +101,6 @@ import com.oracle.truffle.r.runtime.data.RTypedValue;
import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
import com.oracle.truffle.r.runtime.env.REnvironment;
import com.oracle.truffle.r.runtime.interop.R2Foreign;
import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen;
import com.oracle.truffle.r.runtime.nodes.RNode;
import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
......@@ -254,7 +257,7 @@ final class REngine implements Engine, Engine.Timings {
@Override
public Object parseAndEval(Source source, MaterializedFrame frame, boolean printResult) throws ParseException {
List<RSyntaxNode> list = parseImpl(source);
List<RSyntaxNode> list = parseSource(source);
try {
Object lastValue = RNull.instance;
for (RSyntaxNode node : list) {
......@@ -282,21 +285,23 @@ final class REngine implements Engine, Engine.Timings {
}
}
private List<RSyntaxNode> parseImpl(Source source) throws ParseException {
List<RSyntaxNode> parseSource(Source source) throws ParseException {
RParserFactory.Parser<RSyntaxNode> parser = RParserFactory.getParser();
return parser.script(source, new RASTBuilder(), context.getLanguage());
}
@Override
public RExpression parse(Source source) throws ParseException {
List<RSyntaxNode> list = parseImpl(source);
List<RSyntaxNode> list = parseSource(source);
Object[] data = list.stream().map(node -> RASTUtils.createLanguageElement(node)).toArray();
return RDataFactory.createExpression(data);
}
@Override
public CallTarget parseToCallTarget(Source source, MaterializedFrame executionFrame) throws ParseException {
if (source == Engine.GET_CONTEXT) {
if (source.getPath() != null && !source.isInteractive()) {
return Truffle.getRuntime().createCallTarget(createRScriptRoot(source, executionFrame));
} else if (source == Engine.GET_CONTEXT) {
/*
* The "get context" operations should be executed with as little influence on the
* actual engine as possible, therefore this special case takes care of it explicitly.
......@@ -313,20 +318,21 @@ final class REngine implements Engine, Engine.Timings {
}
});
} else {
List<RSyntaxNode> statements = parseImpl(source);
return Truffle.getRuntime().createCallTarget(new PolyglotEngineRootNode(statements, createSourceSection(source, statements), executionFrame));
List<RSyntaxNode> statements = parseSource(source);
EngineRootNode rootNode = EngineRootNode.createEngineRoot(this, context, statements, createSourceSection(source, statements), executionFrame);
return Truffle.getRuntime().createCallTarget(rootNode);
}
}
@Override
public ExecutableNode parseToExecutableNode(Source source) throws ParseException {
List<RSyntaxNode> list = parseImpl(source);
List<RSyntaxNode> list = parseSource(source);
RNode[] statements = new RNode[list.size()];
for (int i = 0; i < statements.length; i++) {
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) {
......@@ -353,68 +359,49 @@ final class REngine implements Engine, Engine.Timings {
}
}
private final class PolyglotEngineRootNode extends RootNode {
private final List<RSyntaxNode> statements;
private final MaterializedFrame executionFrame;
@Children private final DirectCallNode[] calls;
private final boolean printResult;
private final SourceSection sourceSection;
private final ContextReference<RContext> contextReference;
@Child private R2Foreign r2Foreign = R2ForeignNodeGen.create();
PolyglotEngineRootNode(List<RSyntaxNode> statements, SourceSection sourceSection, MaterializedFrame executionFrame) {
super(context.getLanguage());
this.sourceSection = sourceSection;
this.contextReference = context.getLanguage().getContextReference();
// can't print if initializing the system in embedded mode (no builtins yet)
this.printResult = !sourceSection.getSource().getName().equals(RSource.Internal.INIT_EMBEDDED.string) && sourceSection.getSource().isInteractive();
this.statements = statements;
this.executionFrame = executionFrame;
this.calls = new DirectCallNode[statements.size()];
}
@Override
public SourceSection getSourceSection() {
return sourceSection;
}
/**
* The normal {@link #doMakeCallTarget} happens first, then we actually run the call using
* the standard FastR machinery, saving and restoring the {@link RContext}, since we have no
* control over what that might be when the call is initiated.
*/
@Override
@ExplodeLoop
public Object execute(VirtualFrame frame) {
Object actualFrame = executionFrame != null ? executionFrame : contextReference.get().stateREnvironment.getGlobalFrame();
try {
Object lastValue = RNull.instance;
for (int i = 0; i < calls.length; i++) {
if (calls[i] == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
RSyntaxNode node = statements.get(i);
calls[i] = insert(Truffle.getRuntime().createDirectCallNode(doMakeCallTarget(node.asRNode(), RSource.Internal.REPL_WRAPPER.string, printResult, true)));
private EngineRootNode createRScriptRoot(Source fullSource, MaterializedFrame frame) {
URI uri = fullSource.getURI();
String file = fullSource.getPath();
ArrayList<RSyntaxNode> statements = new ArrayList<>(128);
try {
try (BufferedReader br = new BufferedReader(new InputStreamReader(fullSource.getInputStream()))) {
int lineIndex = 1;
int startLine = lineIndex;
StringBuilder sb = new StringBuilder();
while (true) {
String input = br.readLine();
if (input == null) {
if (sb.length() != 0) {
// end of file, but not end of statement => error
statements.add(new SyntaxErrorNode(null, fullSource.createSection(startLine, 1, sb.length())));
}
break;
}
sb.append(input);
Source src = Source.newBuilder(sb.toString()).mimeType(RRuntime.R_APP_MIME).name(file + "#" + startLine + "-" + lineIndex).uri(uri).build();
lineIndex++;
List<RSyntaxNode> currentStmts = null;
try {
RParserFactory.Parser<RSyntaxNode> parser = RParserFactory.getParser();
currentStmts = parser.statements(src, fullSource, startLine, new RASTBuilder(), context.getLanguage());
} catch (IncompleteSourceException e) {
sb.append('\n');
continue;
} catch (ParseException e) {
statements.add(new SyntaxErrorNode(e, fullSource.createSection(startLine, 1, sb.length())));
}
lastValue = calls[i].call(new Object[]{actualFrame});
if (currentStmts != null) {
statements.addAll(currentStmts);
}
// we did not continue on incomplete source exception
sb.setLength(0);
startLine = lineIndex;
}
return r2Foreign.execute(lastValue);
} catch (ReturnException ex) {
return ex.getResult();
} catch (DebugExitException | JumpToTopLevelException | ExitException | ThreadDeath e) {
CompilerDirectives.transferToInterpreter();
throw e;
} catch (RError e) {
CompilerDirectives.transferToInterpreter();
throw e;
} catch (Throwable t) {
CompilerDirectives.transferToInterpreter();
// other errors didn't produce an output yet
RInternalError.reportError(t);
throw t;
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return EngineRootNode.createEngineRoot(this, context, statements, createSourceSection(fullSource, statements), frame);
}
@Override
......@@ -508,7 +495,7 @@ final class REngine implements Engine, Engine.Timings {
* that the body should be executed in.
*/
@TruffleBoundary
private RootCallTarget doMakeCallTarget(RNode body, String description, boolean printResult, boolean topLevel) {
RootCallTarget doMakeCallTarget(RNode body, String description, boolean printResult, boolean topLevel) {
return Truffle.getRuntime().createCallTarget(new AnonymousRootNode(this, body, description, printResult, topLevel));
}
......@@ -529,14 +516,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 +531,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 +607,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;
......
......@@ -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) || EngineRootNode.isEngineBody(parent);
}
case "LoopTag":
return node instanceof AbstractLoopNode;
default:
return false;
}
// TODO: ExpressionTag: (!statement && !loop && !if && !call && !root)??
return false;
}
private static boolean isInternalChild(Node node) {
......
/*
* Copyright (c) 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.engine;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.r.runtime.RInternalError;
import com.oracle.truffle.r.runtime.context.Engine.ParseException;
import com.oracle.truffle.r.runtime.nodes.RInstrumentableNode;
import com.oracle.truffle.r.runtime.nodes.RNode;
import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
/**
* Node that represents piece of AST that would throw syntax error when parser. Used to delay
* parsing error to the point when they should be reported.
*/
final class SyntaxErrorNode extends RNode implements RSyntaxNode, RInstrumentableNode {
private final ParseException exception;
private final SourceSection sourceSection;
SyntaxErrorNode(ParseException exception, SourceSection sourceSection) {
this.exception = exception;
this.sourceSection = sourceSection;
}
@Override
public Object execute(VirtualFrame frame) {
throw exception.throwAsRError();
}
@Override
public SourceSection getSourceSection() {
return this.sourceSection;
}
@Override
public SourceSection getLazySourceSection() {
return this.sourceSection;
}
@Override
public void setSourceSection(SourceSection source) {
throw RInternalError.shouldNotReachHere(String.format("%s should not be serialized/deserialzed.", getClass().getSimpleName()));
}
}
......@@ -34,11 +34,13 @@ import com.oracle.truffle.api.instrumentation.ProvidedTags;
import com.oracle.truffle.api.instrumentation.StandardTags;
import com.oracle.truffle.api.nodes.ExecutableNode;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
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 +59,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<>();
......@@ -188,12 +190,13 @@ public final class TruffleRLanguageImpl extends TruffleRLanguage {
@Override
protected CallTarget parse(ParsingRequest request) throws Exception {
CompilerAsserts.neverPartOfCompilation();
Source source = request.getSource();
try {
return RContext.getEngine().parseToCallTarget(request.getSource(), null);
return RContext.getEngine().parseToCallTarget(source, null);
} catch (IncompleteSourceException e) {
throw e;
} catch (ParseException e) {
if (request.getSource().isInteractive()) {
if (source.isInteractive()) {
throw e.throwAsRError();
} else {
throw e;
......
/*
* Copyright (c) 2017, 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.launcher;
import static java.lang.Integer.max;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.graalvm.options.OptionCategory;
import org.graalvm.options.OptionDescriptor;
import org.graalvm.options.OptionDescriptors;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Instrument;
import org.graalvm.polyglot.Language;
public abstract class Launcher {
private static final boolean STATIC_VERBOSE = Boolean.getBoolean("org.graalvm.launcher.verbose");
private Engine tempEngine;
private final boolean verbose;
private boolean help;
private boolean helpDebug;
private boolean helpExpert;
private boolean helpTools;
private boolean helpLanguages;
private OptionCategory helpCategory;
private VersionAction versionAction = VersionAction.None;
protected enum VersionAction {
None,
PrintAndExit,
PrintAndContinue
}
public Launcher() {
verbose = STATIC_VERBOSE || Boolean.valueOf(System.getenv("VERBOSE_GRAALVM_LAUNCHERS"));
}
private Engine getTempEngine() {
if (tempEngine == null) {
tempEngine = Engine.create();
}
return tempEngine;
}
void setHelpCategory(OptionCategory helpCategory) {
this.helpCategory = helpCategory;
}
protected void setVersionAction(VersionAction versionAction) {
this.versionAction = versionAction;
}
private static class AbortException extends RuntimeException {
static final long serialVersionUID = 4681646279864737876L;
AbortException(String message) {
super(message, null);
}
@SuppressWarnings("sync-override")
@Override
public final Throwable fillInStackTrace() {
return null;
}
}
protected AbortException exit() {
return abort(null, 0);
}
protected AbortException abort(String message) {
return abort(message, 1);
}
protected AbortException abort(String message, int exitCode) {
if (message != null) {
System.err.println("ERROR: " + message);
}
System.exit(exitCode);
throw new AbortException(message);
}
protected abstract void printHelp(OptionCategory maxCategory);
protected abstract void printVersion();
protected abstract void collectArguments(Set<String> options);
protected static void printPolyglotVersions() {
Engine engine = Engine.create();
System.out.println("GraalVM Polyglot Engine Version " + engine.getVersion());
printLanguages(engine, true);
printInstruments(engine, true);
}
protected boolean isVerbose() {
return verbose;
}
final boolean runPolyglotAction() {
OptionCategory maxCategory = helpDebug ? OptionCategory.DEBUG : (helpExpert ? OptionCategory.EXPERT : (helpCategory != null ? helpCategory : OptionCategory.USER));
switch (versionAction) {
case PrintAndContinue:
printVersion();
return false;
case PrintAndExit:
printVersion();
return true;
case None:
break;
}
boolean printDefaultHelp = helpCategory != null || help || ((helpExpert || helpDebug) && !helpTools && !helpLanguages);
Engine tmpEngine = null;
if (printDefaultHelp) {
printHelp(maxCategory);
// @formatter:off
System.out.println();
System.out.println("Runtime Options:");
printOption("--polyglot", "Run with all other guest languages accessible.");
// not applicable at the moment
// printOption("--native", "Run using the native launcher with limited Java access (default).");
// printOption("--native.[option]", "Pass options to the native image; for example, '--native.Xmx1G'. To see available options, use '--native.help'.");
printOption("--jvm", "Run on the Java Virtual Machine with Java access.");
// not applicable at the moment
// printOption("--jvm.[option]", "Pass options to the JVM; for example, '--jvm.classpath=myapp.jar'. To see available options. use '--jvm.help'.");
printOption("--help", "Print this help message.");
printOption("--help:languages", "Print options for all installed languages.");
printOption("--help:tools", "Print options for all installed tools.");
printOption("--help:expert", "Print additional engine options for experts.");
if (helpExpert || helpDebug) {
printOption("--help:debug", "Print additional engine options for debugging.");
}
printOption("--version", "Print version information and exit.");
printOption("--show-version", "Print version information and continue execution.");
// @formatter:on
if (tmpEngine == null) {
tmpEngine = Engine.create();
}
List<PrintableOption> engineOptions = new ArrayList<>();
for (OptionDescriptor descriptor : tmpEngine.getOptions()) {
if (!descriptor.getName().startsWith("engine.") && !descriptor.getName().startsWith("compiler.")) {
continue;
}
if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) {
engineOptions.add(asPrintableOption(descriptor));
}
}
if (!engineOptions.isEmpty()) {
printOptions(engineOptions, "Engine options:", 2);
}
}
if (helpLanguages) {
if (tmpEngine == null) {
tmpEngine = Engine.create();
}
printLanguageOptions(tmpEngine, maxCategory);
}
if (helpTools) {
if (tmpEngine == null) {
tmpEngine = Engine.create();
}
printInstrumentOptions(tmpEngine, maxCategory);
}
if (printDefaultHelp || helpLanguages || helpTools) {
System.out.println("\nSee http://www.oracle.com/technetwork/oracle-labs/program-languages/overview/index.html for more information.");
return true;
}
return false;
}
private static void printInstrumentOptions(Engine engine, OptionCategory maxCategory) {
Map<Instrument, List<PrintableOption>> instrumentsOptions = new HashMap<>();
List<Instrument> instruments = sortedInstruments(engine);
for (Instrument instrument : instruments) {
List<PrintableOption> options = new ArrayList<>();
for (OptionDescriptor descriptor : instrument.getOptions()) {
if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) {
options.add(asPrintableOption(descriptor));
}
}
if (!options.isEmpty()) {
instrumentsOptions.put(instrument, options);
}
}
if (!instrumentsOptions.isEmpty()) {
System.out.println();
System.out.println("Tool options:");
for (Instrument instrument : instruments) {
List<PrintableOption> options = instrumentsOptions.get(instrument);
if (options != null) {
printOptions(options, " " + instrument.getName() + ":", 4);
}
}
}
}
private static void printLanguageOptions(Engine engine, OptionCategory maxCategory) {
Map<Language, List<PrintableOption>> languagesOptions = new HashMap<>();
List<Language> languages = sortedLanguages(engine);
for (Language language : languages) {
List<PrintableOption> options = new ArrayList<>();
for (OptionDescriptor descriptor : language.getOptions()) {
if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) {
options.add(asPrintableOption(descriptor));
}
}
if (!options.isEmpty()) {
languagesOptions.put(language, options);
}
}
if (!languagesOptions.isEmpty()) {
System.out.println();
System.out.println("Language Options:");
for (Language language : languages) {
List<PrintableOption> options = languagesOptions.get(language);
if (options != null) {
printOptions(options, " " + language.getName() + ":", 4);
}
}
}
}
protected boolean parsePolyglotOption(String defaultOptionPrefix, Map<String, String> options, String arg) {
switch (arg) {
case "--help":
help = true;
return true;
case "--help:debug":
helpDebug = true;
return true;
case "--help:expert":
helpExpert = true;
return true;
case "--help:tools":
helpTools = true;
return true;
case "--help:languages":
helpLanguages = true;
return true;
case "--version":
versionAction = VersionAction.PrintAndExit;
return true;
case "--show-version":
versionAction = VersionAction.PrintAndContinue;
return true;
// case "--polyglot":
// case "--jvm":
// case "--native":
// return false;
default:
// getLanguageId() or null?
if (arg.length() <= 2 || !arg.startsWith("--")) {
return false;
}
int eqIdx = arg.indexOf('=');
String key;
String value;
if (eqIdx < 0) {
key = arg.substring(2);
value = null;
} else {
key = arg.substring(2, eqIdx);
value = arg.substring(eqIdx + 1);
}
if (value == null) {
value = "true";
}
int index = key.indexOf('.');
String group = key;
if (index >= 0) {
group = group.substring(0, index);
}
OptionDescriptor descriptor = findPolyglotOptionDescriptor(group, key);
if (descriptor == null) {
if (defaultOptionPrefix != null) {
descriptor = findPolyglotOptionDescriptor(defaultOptionPrefix, defaultOptionPrefix + "." + key);
}
if (descriptor == null) {
return false;
}
}
try {
descriptor.getKey().getType().convert(value);
} catch (IllegalArgumentException e) {
throw abort(String.format("Invalid argument %s specified. %s'", arg, e.getMessage()));
}
options.put(key, value);
return true;
}
}
private OptionDescriptor findPolyglotOptionDescriptor(String group, String key) {
OptionDescriptors descriptors = null;
switch (group) {
case "compiler":
case "engine":
descriptors = getTempEngine().getOptions();
break;
default:
Engine engine = getTempEngine();
if (engine.getLanguages().containsKey(group)) {
descriptors = engine.getLanguages().get(group).getOptions();
} else if (engine.getInstruments().containsKey(group)) {
descriptors = engine.getInstruments().get(group).getOptions();
}
break;
}
if (descriptors == null) {
return null;
}
return descriptors.get(key);
}
protected static List<Language> sortedLanguages(Engine engine) {
List<Language> languages = new ArrayList<>(engine.getLanguages().values());
languages.sort(Comparator.comparing(Language::getId));
return languages;
}
protected static List<Instrument> sortedInstruments(Engine engine) {
List<Instrument> instruments = new ArrayList<>(engine.getInstruments().values());
instruments.sort(Comparator.comparing(Instrument::getId));
return instruments;
}
protected static void printOption(OptionCategory maxCategory, OptionDescriptor descriptor) {
if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) {
printOption(asPrintableOption(descriptor));
}
}
protected static PrintableOption asPrintableOption(OptionDescriptor descriptor) {
StringBuilder key = new StringBuilder("--");
key.append(descriptor.getName());
Object defaultValue = descriptor.getKey().getDefaultValue();
if (defaultValue instanceof Boolean && defaultValue == Boolean.FALSE) {
// nothing to print
} else {
key.append("=<");
key.append(descriptor.getKey().getType().getName());
key.append(">");
}
return new PrintableOption(key.toString(), descriptor.getHelp());
}
protected static void printOption(String option, String description) {
printOption(option, description, 2);
}
protected static void printOption(String option, String description, int indentation) {
StringBuilder indent = new StringBuilder(indentation);
for (int i = 0; i < indentation; i++) {
indent.append(' ');
}
String desc = description != null ? description : "";
if (option.length() >= 45 && description != null) {
System.out.println(String.format("%s%s%n%s%-45s%s", indent, option, indent, "", desc));
} else {
System.out.println(String.format("%s%-45s%s", indent, option, desc));
}
}
protected static void printOption(PrintableOption option) {
printOption(option, 2);
}
protected static void printOption(PrintableOption option, int indentation) {
printOption(option.option, option.description, indentation);
}
private static final class PrintableOption implements Comparable<PrintableOption> {
final String option;
final String description;
private PrintableOption(String option, String description) {
this.option = option;
this.description = description;
}
@Override
public int compareTo(PrintableOption o) {
return this.option.compareTo(o.option);
}
}
private static void printOptions(List<PrintableOption> options, String title, int indentation) {
Collections.sort(options);
System.out.println(title);
for (PrintableOption option : options) {
printOption(option, indentation);
}
}
protected enum OS {
Darwin,
Linux,
Solaris;
private static OS findCurrent() {
final String name = System.getProperty("os.name");
if (name.equals("Linux")) {
return Linux;
}
if (name.equals("SunOS")) {
return Solaris;
}
if (name.equals("Mac OS X") || name.equals("Darwin")) {
return Darwin;
}
throw new IllegalArgumentException("unknown OS: " + name);
}
private static final OS current = findCurrent();
public static OS getCurrent() {
return current;
}
}
protected static void printLanguages(Engine engine, boolean printWhenEmpty) {
if (engine.getLanguages().isEmpty()) {
if (printWhenEmpty) {
System.out.println(" Installed Languages: none");
}
} else {
System.out.println(" Installed Languages:");
List<Language> languages = new ArrayList<>(engine.getLanguages().size());
int nameLength = 0;
for (Language language : engine.getLanguages().values()) {
languages.add(language);
nameLength = max(nameLength, language.getName().length());
}
languages.sort(Comparator.comparing(Language::getId));
String langFormat = " %-" + nameLength + "s%s version %s%n";
for (Language language : languages) {
String version = language.getVersion();
if (version == null || version.length() == 0) {
version = "";
}
System.out.printf(langFormat, language.getName().isEmpty() ? "Unnamed" : language.getName(), version);
}
}
}
protected static void printInstruments(Engine engine, boolean printWhenEmpty) {
if (engine.getInstruments().isEmpty()) {
if (printWhenEmpty) {
System.out.println(" Installed Tools: none");
}
} else {
System.out.println(" Installed Tools:");
List<Instrument> instruments = sortedInstruments(engine);
int nameLength = 0;
for (Instrument instrument : instruments) {
nameLength = max(nameLength, instrument.getName().length());
}
String instrumentFormat = " %-" + nameLength + "s version %s%n";
for (Instrument instrument : instruments) {
String version = instrument.getVersion();
if (version == null || version.length() == 0) {
version = "";
}
System.out.printf(instrumentFormat, instrument.getName().isEmpty() ? "Unnamed" : instrument.getName(), version);
}
}
}
}
/*
* Copyright (c) 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.launcher;
import java.io.Closeable;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.graalvm.launcher.AbstractLanguageLauncher;
import org.graalvm.options.OptionCategory;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Context.Builder;
import com.oracle.truffle.r.launcher.RCmdOptions.Client;
import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption;
public abstract class RAbstractLauncher extends AbstractLanguageLauncher implements Closeable {
private final Client client;
protected final InputStream inStream;
protected final OutputStream outStream;
protected final OutputStream errStream;
protected RCmdOptions options;
private boolean useJVM;
protected ConsoleHandler consoleHandler;
protected Context context;
RAbstractLauncher(Client client, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
this.client = client;
assert env == null : "re-enble environment variables";
this.inStream = inStream;
this.outStream = outStream;
this.errStream = errStream;
}
@Override
protected List<String> preprocessArguments(List<String> arguments, Map<String, String> polyglotOptions) {
boolean[] recognizedArgsIndices = new boolean[arguments.size()];
this.options = RCmdOptions.parseArguments(client, arguments.toArray(new String[arguments.size()]), true, recognizedArgsIndices);
List<String> unrecognizedArgs = new ArrayList<>();
for (int i = 0; i < arguments.size(); i++) {
if ("--jvm".equals(arguments.get(i))) {
useJVM = true;
} else if (!recognizedArgsIndices[i]) {
unrecognizedArgs.add(arguments.get(i));
}
}
return unrecognizedArgs;
}
protected abstract String[] getArguments();
@Override
protected void launch(Builder contextBuilder) {
this.consoleHandler = RCommand.createConsoleHandler(options, null, inStream, outStream);
this.context = contextBuilder.allowAllAccess(true).allowHostAccess(useJVM).arguments("R", getArguments()).in(consoleHandler.createInputStream()).out(
outStream).err(errStream).build();
this.consoleHandler.setContext(context);
}
@Override
protected String getLanguageId() {
return "R";
}
@Override
protected void printHelp(OptionCategory maxCategory) {
RCmdOptions.printHelp(client);
}
@Override
protected void collectArguments(Set<String> opts) {
for (RCmdOption option : RCmdOption.values()) {
if (option.shortName != null) {
opts.add(option.shortName);
}
if (option.plainName != null) {
opts.add(option.plainName);
}
}
}
@Override
public void close() {
if (context != null) {
context.close();
}
}
}
......@@ -268,25 +268,44 @@ public final class RCmdOptions {
* {@code args[0]} and we do not want to parse that!
*/
public static RCmdOptions parseArguments(Client client, String[] args, boolean reparse) {
return parseArguments(client, args, reparse, null);
}
public static RCmdOptions parseArguments(Client client, String[] args, boolean reparse, boolean[] recognizedArgsIndices) {
assert recognizedArgsIndices == null || recognizedArgsIndices.length == args.length;
EnumMap<RCmdOption, Object> options = new EnumMap<>(RCmdOption.class);
if (recognizedArgsIndices != null) {
recognizedArgsIndices[0] = true;
}
int i = 1; // skip the first argument (the command)
int firstNonOptionArgIndex = args.length;
while (i < args.length) {
final String arg = args[i];
MatchResult result = matchOption(arg);
if (result == null) {
// for Rscript, this means we are done
if (client == Client.RSCRIPT) {
boolean isOption = arg.startsWith("--") || arg.startsWith("-");
if (!isOption && client == Client.RSCRIPT) {
// for Rscript, this means we are done
if (recognizedArgsIndices != null) {
recognizedArgsIndices[i] = true;
}
firstNonOptionArgIndex = i;
break;
}
if (!reparse) {
// GnuR does not abort, simply issues a warning
System.out.printf("WARNING: unknown option '%s'%n", arg);
if (recognizedArgsIndices != null) {
recognizedArgsIndices[i] = true;
}
}
i++;
continue;
} else {
if (recognizedArgsIndices != null) {
recognizedArgsIndices[i] = true;
}
RCmdOption option = result.option;
if (result.matchedShort && i == args.length - 1) {
System.out.println("usage:");
......@@ -302,6 +321,9 @@ public final class RCmdOptions {
if (result.matchedShort) {
i++;
setValue(options, option, args[i]);
if (recognizedArgsIndices != null) {
recognizedArgsIndices[i] = true;
}
} else {
if (option.type == RCmdOptionType.BOOLEAN) {
setValue(options, option, true);
......@@ -318,6 +340,14 @@ public final class RCmdOptions {
}
}
}
if (recognizedArgsIndices != null) {
// mark the all non-option arguments (the tail) as recognized
for (int j = firstNonOptionArgIndex; j < recognizedArgsIndices.length; j++) {
recognizedArgsIndices[j] = true;
}
}
// adjust for inserted executable name
return new RCmdOptions(options, args, firstNonOptionArgIndex);
}
......
......@@ -30,15 +30,11 @@ import java.io.OutputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import org.graalvm.options.OptionCategory;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Context.Builder;
import org.graalvm.polyglot.PolyglotException;
import org.graalvm.polyglot.Source;
......@@ -47,37 +43,6 @@ import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption;
import jline.console.UserInterruptException;
class RLauncher extends Launcher {
private final Client client;
RLauncher(Client client) {
this.client = client;
}
@Override
protected void printHelp(OptionCategory maxCategory) {
RCmdOptions.printHelp(client);
}
@Override
protected void printVersion() {
RCmdOptions.printVersion();
}
@Override
protected void collectArguments(Set<String> options) {
for (RCmdOption option : RCmdOption.values()) {
if (option.shortName != null) {
options.add(option.shortName);
}
if (option.plainName != null) {
options.add(option.plainName);
}
}
}
}
/*
* TODO:
*
......@@ -89,40 +54,25 @@ class RLauncher extends Launcher {
/**
* Emulates the (Gnu)R command as precisely as possible.
*/
public class RCommand {
// CheckStyle: stop system..print check
public static RuntimeException fatal(String message, Object... args) {
System.out.println("FATAL: " + String.format(message, args));
System.exit(-1);
return new RuntimeException();
}
public class RCommand extends RAbstractLauncher {
public static RuntimeException fatal(Throwable t, String message, Object... args) {
t.printStackTrace();
System.out.println("FATAL: " + String.format(message, args));
System.exit(-1);
return null;
RCommand(String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
super(Client.R, env, inStream, outStream, errStream);
}
public static void main(String[] args) {
try {
System.exit(doMain(prependCommand(args), null, System.in, System.out, System.err));
// never returns
throw fatal("main should never return");
} catch (Throwable t) {
throw fatal(t, "error during REPL execution");
}
@Override
protected String[] getArguments() {
return options.getArguments();
}
static String[] prependCommand(String[] args) {
String[] result = new String[args.length + 1];
result[0] = "R";
System.arraycopy(args, 0, result, 1, args.length);
return result;
@Override
protected void launch(Builder contextBuilder) {
super.launch(contextBuilder);
StartupTiming.timestamp("VM Created");
StartupTiming.printSummary();
}
public static int doMain(String[] args, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
private int execute(String[] args) {
StartupTiming.timestamp("Main Entered");
ArrayList<String> argsList = new ArrayList<>(Arrays.asList(args));
if (System.console() != null) {
......@@ -143,34 +93,8 @@ public class RCommand {
}
}
boolean useJVM = false;
RLauncher launcher = new RLauncher(Client.R);
Map<String, String> polyglotOptions = new HashMap<>();
Iterator<String> iterator = argsList.iterator();
if (iterator.hasNext()) {
iterator.next(); // skip first argument
while (iterator.hasNext()) {
String arg = iterator.next();
if ("--jvm".equals(arg)) {
useJVM = true;
iterator.remove();
} else if (launcher.parsePolyglotOption("R", polyglotOptions, arg)) {
iterator.remove();
}
}
}
if (launcher.runPolyglotAction()) {
return 0;
}
RCmdOptions options = RCmdOptions.parseArguments(Client.R, argsList.toArray(new String[argsList.size()]), false);
assert env == null || env.length == 0 : "re-enable setting environments";
ConsoleHandler consoleHandler = createConsoleHandler(options, null, inStream, outStream);
try (Context context = Context.newBuilder().allowAllAccess(true).allowHostAccess(useJVM).options(polyglotOptions).arguments("R", options.getArguments()).in(
consoleHandler.createInputStream()).out(outStream).err(errStream).build()) {
consoleHandler.setContext(context);
StartupTiming.timestamp("VM Created");
StartupTiming.printSummary();
launch(argsList.toArray(new String[0]));
if (context != null) {
File srcFile = null;
String fileOption = options.getString(RCmdOption.FILE);
if (fileOption != null) {
......@@ -178,6 +102,45 @@ public class RCommand {
}
return readEvalPrint(context, consoleHandler, srcFile);
} else {
return 0;
}
}
// CheckStyle: stop system..print check
public static RuntimeException fatal(String message, Object... args) {
System.out.println("FATAL: " + String.format(message, args));
System.exit(-1);
return new RuntimeException();
}
public static RuntimeException fatal(Throwable t, String message, Object... args) {
t.printStackTrace();
System.out.println("FATAL: " + String.format(message, args));
System.exit(-1);
return null;
}
static String[] prependCommand(String[] args) {
String[] result = new String[args.length + 1];
result[0] = "R";
System.arraycopy(args, 0, result, 1, args.length);
return result;
}
public static void main(String[] args) {
try {
System.exit(doMain(prependCommand(args), null, System.in, System.out, System.err));
// never returns
throw fatal("main should never return");
} catch (Throwable t) {
throw fatal(t, "error during REPL execution");
}
}
public static int doMain(String[] args, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
try (RCommand rcmd = new RCommand(env, inStream, outStream, errStream)) {
return rcmd.execute(args);
}
}
......
......@@ -23,16 +23,16 @@
package com.oracle.truffle.r.launcher;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.graalvm.options.OptionCategory;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.PolyglotException;
import org.graalvm.polyglot.Source;
import com.oracle.truffle.r.launcher.RCmdOptions.Client;
import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption;
......@@ -43,11 +43,67 @@ import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption;
* way but the effect is similar.
*
*/
public class RscriptCommand {
public final class RscriptCommand extends RAbstractLauncher {
private String[] rScriptArguments;
RscriptCommand(String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
super(Client.RSCRIPT, env, inStream, outStream, errStream);
}
@Override
protected List<String> preprocessArguments(List<String> arguments, Map<String, String> polyglotOptions) {
List<String> unrecognizedArgs = super.preprocessArguments(arguments, polyglotOptions);
try {
this.rScriptArguments = preprocessRScriptOptions(options);
return unrecognizedArgs;
} catch (PrintHelp e) {
return Collections.singletonList("--help");
}
}
@Override
protected String[] getArguments() {
return rScriptArguments;
}
protected int execute(String[] args) {
launch(args);
if (context != null) {
String fileOption = options.getString(RCmdOption.FILE);
if (fileOption != null) {
return executeFile(fileOption);
} else {
return RCommand.readEvalPrint(context, consoleHandler, null);
}
} else {
return 0;
}
}
private int executeFile(String fileOption) {
Source src;
try {
src = Source.newBuilder("R", new File(fileOption)).interactive(false).build();
} catch (IOException ex) {
System.err.printf("IO error while reading the source file '%s'.\nDetails: '%s'.", fileOption, ex.getLocalizedMessage());
return 1;
}
try {
context.eval(src);
return 0;
} catch (Throwable ex) {
if (ex instanceof PolyglotException && ((PolyglotException) ex).isExit()) {
return ((PolyglotException) ex).getExitStatus();
}
// Internal exceptions are reported by the engine already
return 1;
}
}
// CheckStyle: stop system..print check
private static String[] preprocessRScriptOptions(RLauncher launcher, RCmdOptions options) {
private static String[] preprocessRScriptOptions(RCmdOptions options) throws PrintHelp {
String[] arguments = options.getArguments();
int resultArgsLength = arguments.length;
int firstNonOptionArgIndex = options.getFirstNonOptionArgIndex();
......@@ -61,11 +117,7 @@ public class RscriptCommand {
// Either -e options are set or first non-option arg is a file
if (options.getStringList(RCmdOption.EXPR) == null) {
if (firstNonOptionArgIndex == resultArgsLength) {
launcher.setHelpCategory(OptionCategory.USER);
// does not return
if (launcher.runPolyglotAction()) {
System.exit(1);
}
throw new PrintHelp();
} else {
options.setValue(RCmdOption.FILE, arguments[firstNonOptionArgIndex]);
}
......@@ -99,50 +151,18 @@ public class RscriptCommand {
return adjArgs.toArray(new String[adjArgs.size()]);
}
@SuppressWarnings("serial")
static class PrintHelp extends Exception {
}
public static void main(String[] args) {
System.exit(doMain(RCommand.prependCommand(args), null, System.in, System.out, System.err));
throw RCommand.fatal("should not reach here");
}
public static int doMain(String[] args, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
assert env == null : "re-enble environment variables";
ArrayList<String> argsList = new ArrayList<>(Arrays.asList(args));
RLauncher launcher = new RLauncher(Client.RSCRIPT) {
@Override
protected void printVersion() {
System.out.print("R scripting front-end version ");
System.out.print(RVersionNumber.FULL);
System.out.println(RVersionNumber.RELEASE_DATE);
}
};
boolean useJVM = false;
Map<String, String> polyglotOptions = new HashMap<>();
Iterator<String> iterator = argsList.iterator();
if (iterator.hasNext()) {
iterator.next(); // skip first argument
while (iterator.hasNext()) {
String arg = iterator.next();
if ("--jvm".equals(arg)) {
useJVM = true;
iterator.remove();
} else if (launcher.parsePolyglotOption("R", polyglotOptions, arg)) {
iterator.remove();
}
}
}
if (launcher.runPolyglotAction()) {
return 0;
}
RCmdOptions options = RCmdOptions.parseArguments(Client.RSCRIPT, argsList.toArray(new String[argsList.size()]), false);
String[] arguments = preprocessRScriptOptions(launcher, options);
ConsoleHandler consoleHandler = RCommand.createConsoleHandler(options, null, inStream, outStream);
try (Context context = Context.newBuilder().allowAllAccess(true).allowHostAccess(useJVM).options(polyglotOptions).arguments("R", arguments).in(consoleHandler.createInputStream()).out(
outStream).err(errStream).build()) {
consoleHandler.setContext(context);
String fileOption = options.getString(RCmdOption.FILE);
return RCommand.readEvalPrint(context, consoleHandler, fileOption != null ? new File(fileOption) : null);
try (RscriptCommand rcmd = new RscriptCommand(env, inStream, outStream, errStream)) {
return rcmd.execute(args);
}
}
}
......@@ -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);
}
......
......@@ -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() {
}
......
......@@ -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
......
......@@ -51,7 +51,6 @@ public final class LocalReadVariableNode extends Node {
private final Object identifier;
private final boolean forceResult;
@CompilationFinal private boolean firstExecution = true;
@CompilationFinal(dimensions = 1) private boolean[] seenValueKinds;
@CompilationFinal private ValueProfile valueProfile;
......@@ -145,13 +144,6 @@ public final class LocalReadVariableNode extends Node {
isPromiseProfile = ConditionProfile.createBinaryProfile();
}
if (isPromiseProfile.profile(result instanceof RPromise)) {
if (firstExecution) {
CompilerDirectives.transferToInterpreterAndInvalidate();
firstExecution = false;
if (identifier instanceof String) {
return ReadVariableNode.evalPromiseSlowPathWithName((String) identifier, frame, (RPromise) result);
}
}
if (promiseHelper == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
promiseHelper = insert(new PromiseHelperNode());
......
......@@ -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) {
......
/*
* 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);
}
}
}
......@@ -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);
......
......@@ -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 {
......
/*
* 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;
}
......
......@@ -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};
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment