# HG changeset patch # User Doug Simon # Date 1390520036 -3600 # Node ID b9c5875e3a36a1e25927b9682dac2d6fc5afb2a8 # Parent 3424bc098ca083eebabf185ac47b5dc0f692be0a# Parent 64fa703198908c030edb114c79c38cda2314062c Merge. diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Wed Jan 22 18:46:38 2014 +0100 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Fri Jan 24 00:33:56 2014 +0100 @@ -148,7 +148,7 @@ } private boolean canOffloadToGPU(ResolvedJavaMethod method) { - return method.getName().contains("lambda$main$") & method.isSynthetic(); + return method.getName().contains("lambda$") & method.isSynthetic(); } }; } diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Jan 22 18:46:38 2014 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Fri Jan 24 00:33:56 2014 +0100 @@ -556,9 +556,8 @@ int id = allocateCompileTaskId(method, entryBCI); HotSpotBackend backend = runtime.getHostBackend(); CompilationTask task = new CompilationTask(backend, method, entryBCI, id); - boolean isLambdaMethod = (method.getName().contains("lambda$main$") & method.isSynthetic()); - if (blocking || isLambdaMethod) { + if (blocking) { task.runCompilation(true); } else { try { diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/DebugManager.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/DebugManager.java Wed Jan 22 18:46:38 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/DebugManager.java Fri Jan 24 00:33:56 2014 +0100 @@ -27,7 +27,7 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.instrument.*; -import com.oracle.truffle.api.source.*; +import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain; /** * Language-agnostic access to AST-based debugging support. @@ -37,42 +37,29 @@ public interface DebugManager { /** - * Gets a list of current breakpoints. - */ - LineBreakpoint[] getBreakpoints(); - - /** - * Sets a breakpoint at a line-based location. + * Informs the {@link DebugManager} that the Guest Language runtime is starting to load a + * source. Care should be taken to ensure that under any circumstance there is always a + * following call to {@link #notifyFinishedLoading(Source)} with the same argument. */ - LineBreakpoint setBreakpoint(SourceLineLocation lineLocation); - - /** - * Sets a breakpoint at a line-based location with a boolean expression in the guest language to - * serve as a break condition. - */ - LineBreakpoint setConditionalBreakpoint(SourceLineLocation lineLocation, String condition); + void notifyStartLoading(Source source); /** - * Sets a breakpoint at a line-based location that will remove itself when hit. + * Informs the {@link DebugManager} that the Guest Language runtime has finished loading a + * source. Care should be taken to ensure that under any circumstance there is always a prior + * call to {@link #notifyStartLoading(Source)} with the same argument. */ - LineBreakpoint setOneShotBreakpoint(SourceLineLocation lineLocation); - - /** - * Is there a line-based breakpoint set at a location? - */ - boolean hasBreakpoint(SourceLineLocation lineLocation); + void notifyFinishedLoading(Source source); /** - * Removes a breakpoint at a line-based location. + * Return a reference to the (canonical) instrumentation site associated with a particular + * source code location; this site will have effect on any Truffle/AST implementation + * corresponding to the source location, even if the AST is copied multiple times. */ - void removeBreakpoint(SourceLineLocation lineLocation); + ProbeChain getProbeChain(SourceSection sourceSection); /** - * Notification from Truffle execution that execution should halt in a debugging context. - */ - /** - * Receives notification of a suspended execution context; execution resumes when this method - * returns. + * Informs the {@link DebugManager} that Truffle execution has halted; execution will resume + * when this method returns. * * @param astNode a guest language AST node that represents the current execution site, assumed * not to be any kind of {@link InstrumentationNode}, @@ -80,14 +67,4 @@ */ void haltedAt(Node astNode, MaterializedFrame frame); - /** - * Description of a line-based breakpoint. - */ - interface LineBreakpoint { - - SourceLineLocation getSourceLineLocation(); - - String getDebugStatus(); - } - } diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Wed Jan 22 18:46:38 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Fri Jan 24 00:33:56 2014 +0100 @@ -42,9 +42,4 @@ */ DebugManager getDebugManager(); - /** - * Gets access to utilities for printing different aspects of a Truffle AST. - */ - ASTPrinter getASTPrinter(); - } diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDebugManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultDebugManager.java Fri Jan 24 00:33:56 2014 +0100 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013, 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.api.impl; + +import java.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain; +import com.oracle.truffle.api.source.*; + +/** + * A minimal, language-agnostic implementation that tracks loaded sources, and keeps maps describing + * what locations in the source have instrumentation available. + */ +public class DefaultDebugManager implements DebugManager { + + private final Set loadedSources = new HashSet<>(); + + private Source beingLoaded = null; + + /** + * Map: SourceSection ==> probe chain associated with that source section in an AST. + */ + private final Map srcToProbeChain = new HashMap<>(); + + /** + * Map: Source lines ==> probe chains associated with source sections starting on the line. + */ + private final Map> lineToProbeChains = new HashMap<>(); + + private final ExecutionContext context; + + public DefaultDebugManager(ExecutionContext context) { + this.context = context; + } + + /** + * Gets the {@linkplain ProbeChain probe} associated with a particular {@link SourceSection + * source location}, creating a new one if needed. There should only be one probe associated + * with each {@linkplain SourceSection source location}. + */ + public ProbeChain getProbeChain(SourceSection sourceSection) { + assert sourceSection != null; + assert sourceSection.getSource().equals(beingLoaded); + + ProbeChain probeChain = srcToProbeChain.get(sourceSection); + + if (probeChain != null) { + return probeChain; + } + probeChain = new ProbeChain(context, sourceSection, null); + + // Register new ProbeChain by unique SourceSection + srcToProbeChain.put(sourceSection, probeChain); + + // Register new ProbeChain by source line, there may be more than one + // Create line location for map key + final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine()); + + Set probeChains = lineToProbeChains.get(lineLocation); + if (probeChains == null) { + probeChains = new HashSet<>(); + lineToProbeChains.put(lineLocation, probeChains); + } + probeChains.add(probeChain); + + return probeChain; + } + + public void notifyStartLoading(Source source) { + assert beingLoaded == null; + beingLoaded = source; + } + + public void notifyFinishedLoading(Source source) { + assert source == beingLoaded; + loadedSources.add(source); + beingLoaded = null; + } + + public void haltedAt(Node astNode, MaterializedFrame frame) { + } + +} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java Wed Jan 22 18:46:38 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java Fri Jan 24 00:33:56 2014 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This * code is released under a tri EPL/GPL/LGPL license. You can use it, * redistribute it and/or modify it under the terms of the: * @@ -17,7 +17,6 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.ruby.nodes.*; import com.oracle.truffle.ruby.nodes.control.*; -import com.oracle.truffle.ruby.nodes.debug.*; import com.oracle.truffle.ruby.nodes.methods.arguments.*; import com.oracle.truffle.ruby.nodes.objects.*; import com.oracle.truffle.ruby.runtime.*; @@ -48,7 +47,6 @@ getMethods(methods, ClassNodesFactory.getFactories()); getMethods(methods, ContinuationNodesFactory.getFactories()); getMethods(methods, ComparableNodesFactory.getFactories()); - getMethods(methods, DebugNodesFactory.getFactories()); getMethods(methods, DirNodesFactory.getFactories()); getMethods(methods, ExceptionNodesFactory.getFactories()); getMethods(methods, FalseClassNodesFactory.getFactories()); diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/DebugNodes.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/DebugNodes.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.nodes.debug; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.source.*; -import com.oracle.truffle.ruby.nodes.call.*; -import com.oracle.truffle.ruby.nodes.core.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.control.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -@CoreClass(name = "Debug") -public abstract class DebugNodes { - - @CoreMethod(names = "break", isModuleMethod = true, needsSelf = false, needsBlock = true, appendCallNode = true, minArgs = 0, maxArgs = 3) - public abstract static class BreakNode extends CoreMethodNode { - - public BreakNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public BreakNode(BreakNode prev) { - super(prev); - } - - @Specialization(order = 1) - public NilPlaceholder debugBreak(VirtualFrame frame, Node callNode, @SuppressWarnings("unused") UndefinedPlaceholder undefined0, @SuppressWarnings("unused") UndefinedPlaceholder undefined1, - @SuppressWarnings("unused") UndefinedPlaceholder block) { - final RubyContext context = getContext(); - if (context.getConfiguration().getDebug()) { - Node realCallNode = callNode; - while (realCallNode != null && !(realCallNode instanceof CallNode)) { - realCallNode = realCallNode.getParent(); - } - context.getDebugManager().haltedAt(realCallNode, frame.materialize()); - } - return NilPlaceholder.INSTANCE; - } - - @Specialization(order = 2) - public NilPlaceholder debugBreak(RubyString fileName, int line, @SuppressWarnings("unused") Node callNode, @SuppressWarnings("unused") UndefinedPlaceholder block) { - final RubyContext context = getContext(); - if (context.getConfiguration().getDebug()) { - final Source source = context.getSourceManager().get(fileName.toString()); - final SourceLineLocation lineLocation = new SourceLineLocation(source, line); - context.getDebugManager().setBreakpoint(lineLocation); - } - return NilPlaceholder.INSTANCE; - } - - @Specialization(order = 3) - public NilPlaceholder debugBreak(RubyString fileName, int line, @SuppressWarnings("unused") Node callNode, RubyProc block) { - final RubyContext context = getContext(); - if (context.getConfiguration().getDebug()) { - final Source source = context.getSourceManager().get(fileName.toString()); - final SourceLineLocation lineLocation = new SourceLineLocation(source, line); - context.getDebugManager().setLineProc(lineLocation, block); - } - return NilPlaceholder.INSTANCE; - } - - @Specialization(order = 4) - public NilPlaceholder debugBreak(RubySymbol methodName, RubySymbol localName, @SuppressWarnings("unused") Node callNode, @SuppressWarnings("unused") UndefinedPlaceholder block) { - final RubyContext context = getContext(); - if (context.getConfiguration().getDebug()) { - final RubyMethod method = context.getCoreLibrary().getMainObject().getLookupNode().lookupMethod(methodName.toString()); - context.getDebugManager().setLocalBreak(method.getUniqueIdentifier(), localName.toString()); - } - return NilPlaceholder.INSTANCE; - } - - @Specialization(order = 5) - public NilPlaceholder debugBreak(RubySymbol methodName, RubySymbol localName, @SuppressWarnings("unused") Node callNode, RubyProc block) { - final RubyContext context = getContext(); - if (context.getConfiguration().getDebug()) { - final RubyMethod method = context.getCoreLibrary().getMainObject().getLookupNode().lookupMethod(methodName.toString()); - context.getDebugManager().setLocalProc(method.getUniqueIdentifier(), localName.toString(), block); - } - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "continue", isModuleMethod = true, needsSelf = false, maxArgs = 0) - public abstract static class ContinueNode extends CoreMethodNode { - - public ContinueNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public ContinueNode(ContinueNode prev) { - super(prev); - } - - @Specialization - public Object debugContinue() { - if (getContext().getConfiguration().getDebug()) { - throw new BreakShellException(); - } - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "enabled?", isModuleMethod = true, needsSelf = false, maxArgs = 0) - public abstract static class EnabledNode extends CoreMethodNode { - - public EnabledNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public EnabledNode(ContinueNode prev) { - super(prev); - } - - @Specialization - public boolean enabled() { - return getContext().getConfiguration().getDebug(); - } - - } - - @CoreMethod(names = "where", isModuleMethod = true, needsSelf = false, appendCallNode = true, minArgs = 1, maxArgs = 1) - public abstract static class WhereNode extends CoreMethodNode { - - public WhereNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public WhereNode(WhereNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder where(Node callNode) { - final RubyContext context = getContext(); - if (context.getConfiguration().getDebug()) { - context.getConfiguration().getStandardOut().println(callNode.getSourceSection()); - } - return NilPlaceholder.INSTANCE; - } - - } - - @CoreMethod(names = "remove", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 2, maxArgs = 2) - public abstract static class RemoveNode extends CoreMethodNode { - - public RemoveNode(RubyContext context, SourceSection sourceSection) { - super(context, sourceSection); - } - - public RemoveNode(RemoveNode prev) { - super(prev); - } - - @Specialization - public NilPlaceholder debugRemove(RubyString fileName, int line) { - final RubyContext context = getContext(); - if (context.getConfiguration().getDebug()) { - final Source source = context.getSourceManager().get(fileName.toString()); - final SourceLineLocation lineLocation = new SourceLineLocation(source, line); - context.getDebugManager().removeBreakpoint(lineLocation); - } - return NilPlaceholder.INSTANCE; - } - - @Specialization - public NilPlaceholder debugRemove(RubySymbol methodName, RubySymbol localName) { - final RubyContext context = getContext(); - if (context.getConfiguration().getDebug()) { - final RubyMethod method = context.getCoreLibrary().getMainObject().getLookupNode().lookupMethod(methodName.toString()); - context.getDebugManager().removeLocalProbe(method.getUniqueIdentifier(), localName.toString()); - } - return NilPlaceholder.INSTANCE; - } - - } - -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyProxyNode.java --- a/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyProxyNode.java Wed Jan 22 18:46:38 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/debug/RubyProxyNode.java Fri Jan 24 00:33:56 2014 +0100 @@ -19,6 +19,7 @@ import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain; import com.oracle.truffle.ruby.nodes.*; import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.control.*; import com.oracle.truffle.ruby.runtime.core.*; import com.oracle.truffle.ruby.runtime.core.array.*; @@ -69,6 +70,8 @@ try { result = child.execute(frame); probeChain.notifyLeave(child, frame, result); + } catch (BreakShellException e) { + throw (e); } catch (Exception e) { probeChain.notifyLeaveExceptional(child, frame, e); throw (e); @@ -86,6 +89,8 @@ try { result = child.executeArray(frame); probeChain.notifyLeave(child, frame, result); + } catch (BreakShellException e) { + throw (e); } catch (Exception e) { probeChain.notifyLeaveExceptional(child, frame, e); throw (e); @@ -103,6 +108,8 @@ try { result = child.executeBignum(frame); probeChain.notifyLeave(child, frame, result); + } catch (BreakShellException e) { + throw (e); } catch (Exception e) { probeChain.notifyLeaveExceptional(child, frame, e); throw (e); @@ -120,6 +127,8 @@ try { result = child.executeBoolean(frame); probeChain.notifyLeave(child, frame, result); + } catch (BreakShellException e) { + throw (e); } catch (Exception e) { probeChain.notifyLeaveExceptional(child, frame, e); throw (e); @@ -142,6 +151,8 @@ try { result = child.executeFixnum(frame); probeChain.notifyLeave(child, frame, result); + } catch (BreakShellException e) { + throw (e); } catch (Exception e) { probeChain.notifyLeaveExceptional(child, frame, e); throw (e); @@ -159,6 +170,8 @@ try { result = child.executeFloat(frame); probeChain.notifyLeave(child, frame, result); + } catch (BreakShellException e) { + throw (e); } catch (Exception e) { probeChain.notifyLeaveExceptional(child, frame, e); throw (e); @@ -176,6 +189,8 @@ try { result = child.executeString(frame); probeChain.notifyLeave(child, frame, result); + } catch (BreakShellException e) { + throw (e); } catch (Exception e) { probeChain.notifyLeaveExceptional(child, frame, e); throw (e); @@ -191,6 +206,8 @@ try { child.executeVoid(frame); probeChain.notifyLeave(child, frame); + } catch (BreakShellException e) { + throw (e); } catch (Exception e) { probeChain.notifyLeaveExceptional(child, frame, e); throw (e); diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DefaultRubyNodeInstrumenter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/DefaultRubyNodeInstrumenter.java Fri Jan 24 00:33:56 2014 +0100 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This + * code is released under a tri EPL/GPL/LGPL license. You can use it, + * redistribute it and/or modify it under the terms of the: + * + * Eclipse Public License version 1.0 + * GNU General Public License version 2 + * GNU Lesser General Public License version 2.1 + */ +package com.oracle.truffle.ruby.parser; + +import com.oracle.truffle.api.nodes.instrument.*; +import com.oracle.truffle.ruby.nodes.*; +import com.oracle.truffle.ruby.nodes.debug.*; +import com.oracle.truffle.ruby.runtime.*; +import com.oracle.truffle.ruby.runtime.debug.*; +import com.oracle.truffle.ruby.runtime.methods.*; + +/** + * Utility for instrumenting Ruby AST nodes to support the language's built-in tracing + * facility. It ignores nodes other than {@linkplain NodePhylum#STATEMENT statements}. + */ +final class DefaultRubyNodeInstrumenter implements RubyNodeInstrumenter { + + public DefaultRubyNodeInstrumenter() { + } + + public RubyNode instrumentAsStatement(RubyNode rubyNode) { + assert rubyNode != null; + assert !(rubyNode instanceof RubyProxyNode); + final RubyContext context = rubyNode.getContext(); + if (context.getConfiguration().getTrace()) { + final RubyProxyNode proxy = new RubyProxyNode(context, rubyNode); + proxy.markAs(NodePhylum.STATEMENT); + proxy.getProbeChain().appendProbe(new RubyTraceProbe(context)); + return proxy; + } + return rubyNode; + } + + public RubyNode instrumentAsCall(RubyNode node, String callName) { + return node; + } + + public RubyNode instrumentAsLocalAssignment(RubyNode node, UniqueMethodIdentifier methodIdentifier, String localName) { + return node; + } + +} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java Wed Jan 22 18:46:38 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java Fri Jan 24 00:33:56 2014 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This + * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This * code is released under a tri EPL/GPL/LGPL license. You can use it, * redistribute it and/or modify it under the terms of the: * @@ -21,15 +21,26 @@ import com.oracle.truffle.ruby.runtime.*; import com.oracle.truffle.ruby.runtime.control.*; import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.debug.*; import com.oracle.truffle.ruby.runtime.methods.*; public class JRubyParser implements RubyParser { private long nextReturnID = 0; + private final RubyNodeInstrumenter instrumenter; + + public JRubyParser() { + this(new DefaultRubyNodeInstrumenter()); + } + + public JRubyParser(RubyNodeInstrumenter instrumenter) { + assert instrumenter != null; + this.instrumenter = instrumenter; + } + @Override public RubyParserResult parse(RubyContext context, Source source, ParserContext parserContext, MaterializedFrame parentFrame) { + // Set up the JRuby parser final org.jrubyparser.Parser parser = new org.jrubyparser.Parser(); @@ -100,7 +111,7 @@ RubyNode truffleNode; - final RubyDebugManager debugManager = context.getDebugManager(); + final DebugManager debugManager = context.getDebugManager(); try { if (debugManager != null) { debugManager.notifyStartLoading(source); @@ -171,6 +182,10 @@ return allocated; } + public RubyNodeInstrumenter getNodeInstrumenter() { + return instrumenter; + } + private TranslatorEnvironment environmentForFrame(RubyContext context, MaterializedFrame frame) { if (frame == null) { return null; diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/RubyNodeInstrumenter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/RubyNodeInstrumenter.java Fri Jan 24 00:33:56 2014 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.ruby.parser; + +import com.oracle.truffle.api.nodes.instrument.*; +import com.oracle.truffle.ruby.nodes.*; +import com.oracle.truffle.ruby.runtime.methods.*; + +public interface RubyNodeInstrumenter { + + /** + * Adds instrumentation support at a node that should be considered a member of + * {@link NodePhylum#STATEMENT}, possibly returning a new {@link InstrumentationProxyNode} that + * holds the original as its child. + */ + RubyNode instrumentAsStatement(RubyNode node); + + /** + * Adds instrumentation support at a node that should be considered a member of + * {@link NodePhylum#CALL}, possibly returning a new {@link InstrumentationProxyNode} that holds + * the original as its child. + */ + RubyNode instrumentAsCall(RubyNode node, String callName); + + /** + * Adds instrumentation support at a node that should be considered a member of + * {@link NodePhylum#ASSIGNMENT}, possibly returning a new {@link InstrumentationProxyNode} that + * holds the original as its child. + */ + RubyNode instrumentAsLocalAssignment(RubyNode node, UniqueMethodIdentifier methodIdentifier, String localName); + +} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java Wed Jan 22 18:46:38 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java Fri Jan 24 00:33:56 2014 +0100 @@ -16,15 +16,12 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.impl.*; -import com.oracle.truffle.api.nodes.instrument.*; -import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain; import com.oracle.truffle.ruby.nodes.*; import com.oracle.truffle.ruby.nodes.call.*; import com.oracle.truffle.ruby.nodes.cast.*; import com.oracle.truffle.ruby.nodes.constants.*; import com.oracle.truffle.ruby.nodes.control.*; import com.oracle.truffle.ruby.nodes.core.*; -import com.oracle.truffle.ruby.nodes.debug.*; import com.oracle.truffle.ruby.nodes.literal.*; import com.oracle.truffle.ruby.nodes.literal.array.*; import com.oracle.truffle.ruby.nodes.methods.*; @@ -35,7 +32,6 @@ import com.oracle.truffle.ruby.runtime.*; import com.oracle.truffle.ruby.runtime.core.*; import com.oracle.truffle.ruby.runtime.core.range.*; -import com.oracle.truffle.ruby.runtime.debug.*; import com.oracle.truffle.ruby.runtime.methods.*; /** @@ -50,6 +46,7 @@ protected final RubyContext context; protected final TranslatorEnvironment environment; protected final Source source; + protected final RubyNodeInstrumenter instrumenter; private boolean translatingForStatement = false; @@ -89,15 +86,6 @@ nodeDefinedNames.put(org.jrubyparser.ast.DVarNode.class, "local-variable"); } - private static final Set debugIgnoredCalls = new HashSet<>(); - - static { - debugIgnoredCalls.add("downto"); - debugIgnoredCalls.add("each"); - debugIgnoredCalls.add("times"); - debugIgnoredCalls.add("upto"); - } - /** * Global variables which in common usage have frame local semantics. */ @@ -108,6 +96,7 @@ this.parent = parent; this.environment = environment; this.source = source; + this.instrumenter = environment.getNodeInstrumenter(); } @Override @@ -302,18 +291,7 @@ RubyNode translated = new CallNode(context, sourceSection, node.getName(), receiverTranslated, argumentsAndBlock.getBlock(), argumentsAndBlock.isSplatted(), argumentsAndBlock.getArguments()); - if (context.getConfiguration().getDebug()) { - final CallNode callNode = (CallNode) translated; - if (!debugIgnoredCalls.contains(callNode.getName())) { - - final RubyProxyNode proxy = new RubyProxyNode(context, translated); - proxy.markAs(NodePhylum.CALL); - proxy.getProbeChain().appendProbe(new RubyCallProbe(context, node.getName())); - translated = proxy; - } - } - - return translated; + return instrumenter.instrumentAsCall(translated, node.getName()); } protected class ArgumentsAndBlockTranslation { @@ -1162,22 +1140,9 @@ RubyNode translated = ((ReadNode) lhs).makeWriteNode(rhs); - if (context.getConfiguration().getDebug()) { - final UniqueMethodIdentifier methodIdentifier = environment.findMethodForLocalVar(node.getName()); - - RubyProxyNode proxy; - if (translated instanceof RubyProxyNode) { - proxy = (RubyProxyNode) translated; - } else { - proxy = new RubyProxyNode(context, translated); - } - proxy.markAs(NodePhylum.ASSIGNMENT); - context.getDebugManager().registerLocalDebugProxy(methodIdentifier, node.getName(), proxy.getProbeChain()); - - translated = proxy; - } - - return translated; + final UniqueMethodIdentifier methodIdentifier = environment.findMethodForLocalVar(node.getName()); + + return instrumenter.instrumentAsLocalAssignment(translated, methodIdentifier, node.getName()); } @Override @@ -1476,39 +1441,7 @@ @Override public Object visitNewlineNode(org.jrubyparser.ast.NewlineNode node) { RubyNode translated = (RubyNode) node.getNextNode().accept(this); - - if (context.getConfiguration().getDebug()) { - - RubyProxyNode proxy; - if (translated instanceof RubyProxyNode) { - proxy = (RubyProxyNode) translated; - if (proxy.getChild() instanceof CallNode) { - // Special case; replace proxy with one registered by line, merge in information - final CallNode callNode = (CallNode) proxy.getChild(); - final ProbeChain probeChain = proxy.getProbeChain(); - - proxy = new RubyProxyNode(context, callNode, probeChain); - } - } else { - proxy = new RubyProxyNode(context, translated); - } - proxy.markAs(NodePhylum.STATEMENT); - translated = proxy; - } - - if (context.getConfiguration().getTrace()) { - RubyProxyNode proxy; - if (translated instanceof RubyProxyNode) { - proxy = (RubyProxyNode) translated; - } else { - proxy = new RubyProxyNode(context, translated); - } - proxy.getProbeChain().appendProbe(new RubyTraceProbe(context)); - - translated = proxy; - } - - return translated; + return instrumenter.instrumentAsStatement(translated); } @Override diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/TranslatorEnvironment.java --- a/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/TranslatorEnvironment.java Wed Jan 22 18:46:38 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/TranslatorEnvironment.java Fri Jan 24 00:33:56 2014 +0100 @@ -224,4 +224,8 @@ public List getFlipFlopStates() { return flipFlopStates; } + + public RubyNodeInstrumenter getNodeInstrumenter() { + return parser.getNodeInstrumenter(); + } } diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java Wed Jan 22 18:46:38 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java Fri Jan 24 00:33:56 2014 +0100 @@ -16,12 +16,12 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.ruby.runtime.configuration.*; import com.oracle.truffle.ruby.runtime.control.*; import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.debug.*; import com.oracle.truffle.ruby.runtime.methods.*; import com.oracle.truffle.ruby.runtime.objects.*; import com.oracle.truffle.ruby.runtime.subsystems.*; @@ -40,7 +40,7 @@ private final ThreadManager threadManager; private final FiberManager fiberManager; private final AtExitManager atExitManager; - private final RubyDebugManager debugManager; + private final DebugManager debugManager; private final SourceManager sourceManager; private final ASTPrinter astPrinter; @@ -76,7 +76,7 @@ atExitManager = new AtExitManager(); sourceManager = new SourceManager(); - debugManager = configuration.getDebug() ? new RubyDebugManager(this) : null; + debugManager = new DefaultDebugManager(this); // Must initialize threads before fibers @@ -84,11 +84,11 @@ fiberManager = new FiberManager(this); } - public String getLanguageShortName() { - return "Ruby"; + public final String getLanguageShortName() { + return "Ruby " + CoreLibrary.RUBY_VERSION; } - public RubyDebugManager getDebugManager() { + public DebugManager getDebugManager() { return debugManager; } diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/MethodLocal.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/MethodLocal.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * A method and local variable identifier tuple. - */ -public class MethodLocal { - - private final UniqueMethodIdentifier method; - private final String local; - - public MethodLocal(UniqueMethodIdentifier method, String local) { - super(); - this.method = method; - this.local = local; - } - - @Override - public String toString() { - return "MethodLocal [method=" + method + ", local=" + local + "]"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((local == null) ? 0 : local.hashCode()); - result = prime * result + ((method == null) ? 0 : method.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof MethodLocal)) { - return false; - } - MethodLocal other = (MethodLocal) obj; - if (local == null) { - if (other.local != null) { - return false; - } - } else if (!local.equals(other.local)) { - return false; - } - if (method == null) { - if (other.method != null) { - return false; - } - } else if (!method.equals(other.method)) { - return false; - } - return true; - } - -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyBreakAfterLineProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyBreakAfterLineProbe.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.source.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A Ruby probe for halting execution at a line after a child execution method completes. - */ -public final class RubyBreakAfterLineProbe extends RubyLineProbe { - - /** - * Creates a probe that will cause a halt when child execution is complete; a {@code oneShot} - * probe will remove itself the first time it halts. - */ - public RubyBreakAfterLineProbe(RubyContext context, SourceLineLocation location, boolean oneShot) { - super(context, location, oneShot); - } - - @Override - public void leave(Node astNode, VirtualFrame frame) { - if (oneShot) { - // One-shot breakpoints retire after one activation. - context.getDebugManager().retireLineProbe(location, this); - } - context.getDebugManager().haltedAt(astNode, frame.materialize()); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, boolean result) { - leave(astNode, frame); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, int result) { - leave(astNode, frame); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, double result) { - leave(astNode, frame); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, Object result) { - leave(astNode, frame); - } - - @Override - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - leave(astNode, frame); - } - -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyBreakAfterLocalProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyBreakAfterLocalProbe.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A Ruby probe for halting execution after a local assignment. - */ -public final class RubyBreakAfterLocalProbe extends RubyLocalProbe { - - public RubyBreakAfterLocalProbe(RubyContext context, MethodLocal local) { - super(context, local, false); - } - - @Override - public void leave(Node astNode, VirtualFrame frame) { - context.getDebugManager().haltedAt(astNode, frame.materialize()); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, boolean result) { - context.getDebugManager().haltedAt(astNode, frame.materialize()); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, int result) { - context.getDebugManager().haltedAt(astNode, frame.materialize()); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, double result) { - context.getDebugManager().haltedAt(astNode, frame.materialize()); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, Object result) { - context.getDebugManager().haltedAt(astNode, frame.materialize()); - } - - @Override - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - context.getDebugManager().haltedAt(astNode, frame.materialize()); - } - -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyBreakBeforeLineProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyBreakBeforeLineProbe.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.source.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A probe for halting execution at a line before a child execution method. - */ -public final class RubyBreakBeforeLineProbe extends RubyLineProbe { - - /** - * Creates a probe that will cause a halt just before child execution starts; a {@code oneShot} - * probe will remove itself the first time it halts. - */ - public RubyBreakBeforeLineProbe(RubyContext context, SourceLineLocation location, boolean oneShot) { - super(context, location, oneShot); - } - - @Override - public void enter(Node astNode, VirtualFrame frame) { - - if (!isStepping()) { - // Ordinary line breakpoints ignored during stepping so no double halts. - if (oneShot) { - // One-shot breakpoints retire after one activation. - context.getDebugManager().retireLineProbe(location, this); - } - context.getDebugManager().haltedAt(astNode, frame.materialize()); - } - } -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyCallProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyCallProbe.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; - -public final class RubyCallProbe extends RubyProbe { - - private final String name; - - public RubyCallProbe(RubyContext context, String name) { - super(context, false); - this.name = name; - } - - @Override - public void enter(Node astNode, VirtualFrame frame) { - context.getDebugManager().notifyCallEntry(astNode, name); - } - - @Override - public void leave(Node astNode, VirtualFrame frame) { - context.getDebugManager().notifyCallExit(astNode, name); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, boolean result) { - context.getDebugManager().notifyCallExit(astNode, name); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, int result) { - context.getDebugManager().notifyCallExit(astNode, name); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, double result) { - context.getDebugManager().notifyCallExit(astNode, name); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, Object result) { - context.getDebugManager().notifyCallExit(astNode, name); - } - - @Override - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - context.getDebugManager().notifyCallExit(astNode, name); - } -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyDebugManager.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyDebugManager.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,862 +0,0 @@ -/* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import java.io.*; -import java.util.*; -import java.util.Map.Entry; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.nodes.instrument.InstrumentationProbeNode.ProbeChain; -import com.oracle.truffle.api.nodes.instrument.*; -import com.oracle.truffle.api.source.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; -import com.oracle.truffle.ruby.runtime.methods.*; - -/** - * Manager for Ruby AST execution under debugging control. - */ -public final class RubyDebugManager implements DebugManager { - - // TODO (mlvdv) no REPL support yet for debugging "locals" (assignment to local variables); only - // line-based step/next/return - - private static final boolean TRACE = false; - private static final PrintStream OUT = System.out; - - private static enum ExecutionMode { - - /** - * Context: ordinary debugging execution, e.g. in response to a "Continue" request or a - * "Load-Run" request. - *
    - *
  • User breakpoints are enabled.
  • - *
  • Continue until either: - *
      - *
    1. execution arrives at a node with attached user breakpoint, or:
    2. - *
    3. execution completes.
    4. - *
    - *
- */ - CONTINUE, - - /** - * Context: per-statement stepping execution, e.g. in response to a "Step" request. - *
    - *
  • User breakpoints are disabled.
  • - *
  • Continue until either: - *
      - *
    1. execution arrives at a "Statement" node, or:
    2. - *
    3. execution completes.
    4. - *
    - *
- */ - STEP, - - /** - * Context: per-statement stepping in response to a "Next" request and when not nested in - * any function/method call. - *
    - *
  • User breakpoints are disabled.
  • - *
  • Continue until either: - *
      - *
    1. execution arrives at a "Statement" node or:
    2. - *
    3. the program completes or:
    4. - *
    5. execution arrives at a function/method entry, in which case the mode changes to - * {@link #NEXT_NESTED} and execution continues.
    6. - *
    - *
- */ - NEXT, - - /** - * Context: ordinary debugging execution in response to a "Next" requested and when nested - * at least one deep in function/method calls. - *
    - *
  • User breakpoints are enabled.
  • - *
  • Execute until either: - *
      - *
    1. execution arrives at a node with attached user breakpoint, or:
    2. - *
    3. execution completes, or:
    4. - *
    5. execution returns from all nested function/method calls, in which case the mode - * changes to {@link #NEXT} and execution continues.
    6. - *
    - *
- */ - NEXT_NESTED; - } - - private static enum BreakpointStatus { - - /** - * Created for a source location but not yet attached for some legitimate reason: perhaps - * newly created and not yet attached; perhaps newly created and the source file hasn't been - * loaded yet; perhaps old and the source file is in the process of being reloaded. - */ - PENDING("Pending"), - - /** - * Has a {@link RubyProbe}, which is attached to a {@linkplain ProbeChain known location} in - * the AST. - */ - ACTIVE("Active"), - - /** - * Has a {@link RubyProbe}, which is associated with a {@linkplain ProbeChain known - * location} in the AST, but which has been temporarily removed. - */ - DISABLED("Disabled"), - - /** - * Should be attached, but the line location cannot be found in the source. - */ - ERROR("Error: line not found"), - - /** - * Abandoned, not attached. - */ - RETIRED("Retired"); - - private final String name; - - BreakpointStatus(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } - } - - private final Set loadedSources = new HashSet<>(); - - private Source beingLoaded = null; - - /** - * The current mode of execution. - */ - private ExecutionMode executionMode = ExecutionMode.CONTINUE; - - /** - * When running in "step" mode, this is the number of steps that haven't yet completed. - */ - private int unfinishedStepCount = 0; - - /** - * When running in "next" mode, this is the number of steps that haven't yet completed. - */ - private int unfinishedNextCount = 0; - /** - * When running in "next" mode, this is non-null when running a function/method that must be - * continued across. - */ - private Node nextNestedInCallNode = null; - - /** - * Map: SourceSection ==> probe chain associated with that source section in an AST. - */ - private final Map srcToProbeChain = new HashMap<>(); - - /** - * Map: Source lines ==> probe chains associated with source sections starting on the line. - */ - private final Map> lineToProbeChains = new HashMap<>(); - - /** - * Map: Source lines ==> attached Breakpoints/procs to be activated before execution at line. - * There should be no more than one line breakpoint associated with a line. - */ - private final Map lineToBreakpoint = new TreeMap<>(); - - /** - * Map: Method locals in AST ==> Method local assignments where breakpoints can be attached. - */ - private final Map localsToProbeChains = new HashMap<>(); - - /** - * Map: Method locals ==> Breakpoints & procs to be activated after assignment to a local. - */ - private final Map localsToAttachedBreakpoints = new HashMap<>(); - - private final RubyContext context; - - public RubyDebugManager(RubyContext context) { - this.context = context; - } - - /** - * Gets the {@linkplain ProbeChain probe} associated with a particular {@link SourceSection - * source location}, creating a new one if needed. There should only be one probe associated - * with each {@linkplain SourceSection source location}. - */ - public ProbeChain getProbeChain(SourceSection sourceSection) { - assert sourceSection != null; - assert sourceSection.getSource().equals(beingLoaded); - - ProbeChain probeChain = srcToProbeChain.get(sourceSection); - - if (probeChain != null) { - return probeChain; - } - probeChain = new ProbeChain(context, sourceSection, null); - - // Register new ProbeChain by unique SourceSection - srcToProbeChain.put(sourceSection, probeChain); - - // Register new ProbeChain by source line, there may be more than one - // Create line location for map key - final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine()); - - Set probeChains = lineToProbeChains.get(lineLocation); - if (probeChains == null) { - probeChains = new HashSet<>(); - lineToProbeChains.put(lineLocation, probeChains); - } - probeChains.add(probeChain); - - return probeChain; - } - - public void notifyStartLoading(Source source) { - - beingLoaded = source; - - /** - * We'd like to know when we're reloading a file if the old AST is completely dead, so that - * we can correctly identify the state of breakpoints related to it, but that doesn't seem - * possible. - * - * Before we start, find any breakpoints that never got attached, which get reported as - * errors. Revert them to "pending", in case their lines are found this time around. - */ - for (RubyLineBreakpoint breakpoint : lineToBreakpoint.values()) { - if (breakpoint.getSourceLineLocation().getSource().equals(beingLoaded)) { - if (breakpoint.status == BreakpointStatus.ERROR) { - // It was an error, which means we have not yet found that line for this Source. - // It might show up while loading this time, so make it pending. - breakpoint.setPending(); - } - } - } - } - - public void notifyFinishedLoading(Source source) { - assert source == beingLoaded; - - // Update any pending breakpoints associated with this source - - for (RubyLineBreakpoint breakpoint : lineToBreakpoint.values()) { - if (breakpoint.getSourceLineLocation().getSource().equals(beingLoaded)) { - if (breakpoint.status == BreakpointStatus.PENDING) { - final ProbeChain probeChain = findProbeChain(breakpoint.location); - if (probeChain == null) { - breakpoint.setError(); - } else { - breakpoint.attach(probeChain); - } - } - } - } - loadedSources.add(source); - beingLoaded = null; - } - - /** - * Returns a {@link ProbeChain} associated with source that starts on a specified line; if there - * are more than one, return the one with the first character location. - */ - private ProbeChain findProbeChain(SourceLineLocation lineLocation) { - ProbeChain probeChain = null; - final Set probeChains = lineToProbeChains.get(lineLocation); - if (probeChains != null) { - assert probeChains.size() > 0; - for (ProbeChain chain : probeChains) { - if (probeChain == null) { - probeChain = chain; - } else if (chain.getProbedSourceSection().getCharIndex() < probeChain.getProbedSourceSection().getCharIndex()) { - probeChain = chain; - } - } - } - return probeChain; - } - - /** - * Remove a probe from a line location and retire it permanently. - */ - public void retireLineProbe(SourceLineLocation location, RubyLineProbe probe) { - final RubyLineBreakpoint breakpoint = lineToBreakpoint.get(location); - lineToBreakpoint.remove(location); - breakpoint.retire(probe); - } - - @Override - public LineBreakpoint[] getBreakpoints() { - return lineToBreakpoint.values().toArray(new LineBreakpoint[0]); - } - - @Override - public RubyLineBreakpoint setBreakpoint(SourceLineLocation lineLocation) { - - RubyLineBreakpoint breakpoint = lineToBreakpoint.get(lineLocation); - - if (breakpoint != null) { - switch (breakpoint.status) { - case ACTIVE: - throw new RuntimeException("Breakpoint already set at line " + lineLocation); - - case PENDING: - case ERROR: - throw new RuntimeException("Breakpoint already pending at line " + lineLocation); - - default: - assert false; - } - } else { - breakpoint = new RubyLineBreakpoint(lineLocation, new RubyBreakBeforeLineProbe(context, lineLocation, false)); - lineToBreakpoint.put(lineLocation, breakpoint); - - final ProbeChain probeChain = findProbeChain(lineLocation); - if (probeChain != null) { - breakpoint.attach(probeChain); - } - } - - return breakpoint; - } - - @Override - public RubyLineBreakpoint setConditionalBreakpoint(SourceLineLocation lineLocation, String condition) { - throw new UnsupportedOperationException("conditional breakpoints not yet supported"); - } - - @Override - public LineBreakpoint setOneShotBreakpoint(SourceLineLocation lineLocation) { - RubyLineBreakpoint breakpoint = lineToBreakpoint.get(lineLocation); - - if (breakpoint != null) { - switch (breakpoint.status) { - case ACTIVE: - throw new RuntimeException("Breakpoint already set at line " + lineLocation); - - case PENDING: - case ERROR: - throw new RuntimeException("Breakpoint already pending at line " + lineLocation); - - default: - assert false; - } - } else { - breakpoint = new RubyLineBreakpoint(lineLocation, new RubyBreakBeforeLineProbe(context, lineLocation, true)); - lineToBreakpoint.put(lineLocation, breakpoint); - - final ProbeChain probeChain = findProbeChain(lineLocation); - if (probeChain != null) { - breakpoint.attach(probeChain); - } - } - - return breakpoint; - } - - public boolean hasBreakpoint(SourceLineLocation lineLocation) { - return lineToBreakpoint.get(lineLocation) != null; - } - - @Override - public void removeBreakpoint(SourceLineLocation lineLocation) { - final RubyLineBreakpoint breakpoint = lineToBreakpoint.get(lineLocation); - if (breakpoint == null) { - throw new RuntimeException("No break/proc located at line " + lineLocation); - } - lineToBreakpoint.remove(lineLocation); - breakpoint.retire(); - } - - private void removeOneShotBreakpoints() { - for (Entry entry : lineToBreakpoint.entrySet()) { - final RubyLineBreakpoint breakpoint = entry.getValue(); - if (breakpoint.probe.isOneShot()) { - lineToBreakpoint.remove(entry.getKey()); - breakpoint.retire(); - } - } - } - - /** - * Prepare to execute a "Continue": - *
    - *
  • Execution will continue until either: - *
      - *
    1. execution arrives at a node to which a breakpoint is attached, or:
    2. - *
    3. execution completes.
    4. - *
    - *
- */ - public void setContinue() { - // Nothing to do here; "Continue" is the default, which should be restored after each halt. - } - - /** - * Prepare to execute a "Step": - *
    - *
  • User breakpoints are disabled.
  • - *
  • Execution will continue until either: - *
      - *
    1. execution arrives at a "Statement" node, or:
    2. - *
    3. execution completes.
    4. - *
    - * This status persists only through one execution, and reverts to - * {@link ExecutionMode#CONTINUE}. - *
- */ - public void setStep(int stepCount) { - assert executionMode == ExecutionMode.CONTINUE; - disableLineBreakpoints(); - setStepping(true); - unfinishedStepCount = stepCount; - setMode(ExecutionMode.STEP); - } - - /** - * Prepare to execute a "Next": - *
    - *
  • Execution will continue until either: - *
      - *
    1. execution arrives at a "Statement" node when not nested in one or more function/method - * calls, or:
    2. - *
    3. execution arrives at a node to which a breakpoint is attached and when nested in one or - * more function/method calls, or:
    4. - *
    5. execution completes.
    6. - *
    - * This status persists only through one execution, and reverts to - * {@link ExecutionMode#CONTINUE}. - *
- */ - public void setNext(int nextCount) { - assert executionMode == ExecutionMode.CONTINUE; - disableLineBreakpoints(); - setStepping(true); - unfinishedNextCount = nextCount; - setMode(ExecutionMode.NEXT); - } - - private void disableLineBreakpoints() { - for (RubyLineBreakpoint breakpoint : lineToBreakpoint.values()) { - if (breakpoint.status == BreakpointStatus.ACTIVE) { - breakpoint.disable(); - } - } - } - - private void enableLineBreakpoints() { - for (RubyLineBreakpoint breakpoint : lineToBreakpoint.values()) { - if (breakpoint.status == BreakpointStatus.DISABLED) { - breakpoint.enable(); - } - } - } - - private void setStepping(boolean isStepping) { - // Set the "stepping" flag on every statement probe. - for (ProbeChain probeChain : srcToProbeChain.values()) { - if (probeChain.isMarkedAs(NodePhylum.STATEMENT)) { - probeChain.setStepping(isStepping); - } - } - } - - private void setMode(ExecutionMode mode) { - if (TRACE) { - OUT.println("DebugManager: " + executionMode.toString() + "-->" + mode.toString()); - } - executionMode = mode; - } - - /** - * Sets a Ruby proc of no arguments to be run before a specified line is executed. - */ - public void setLineProc(SourceLineLocation lineLocation, RubyProc proc) { - - RubyLineBreakpoint breakpoint = lineToBreakpoint.get(lineLocation); - - if (breakpoint != null) { - switch (breakpoint.status) { - case ACTIVE: - throw new RuntimeException("Breakpoint already set at line " + lineLocation); - - case PENDING: - case ERROR: - throw new RuntimeException("Breakpoint already pending at line " + lineLocation); - - default: - assert false; - } - } else { - breakpoint = new RubyLineBreakpoint(lineLocation, new RubyProcBeforeLineProbe(context, lineLocation, proc)); - lineToBreakpoint.put(lineLocation, breakpoint); - - final ProbeChain probeChain = findProbeChain(lineLocation); - if (probeChain != null) { - breakpoint.attach(probeChain); - } - } - } - - // TODO (mlvdv) rework locals (watchpoints) to work like breaks; I doubt it is even correct now - /** - * Registers the chain of probes associated with a method local variable assignment in the AST. - */ - public void registerLocalDebugProxy(UniqueMethodIdentifier methodIdentifier, String localName, ProbeChain probeChain) { - final MethodLocal methodLocal = new MethodLocal(methodIdentifier, localName); - localsToProbeChains.put(methodLocal, probeChain); - } - - /** - * Sets a breakpoint after assignment to a method local variable in the AST. - */ - public void setLocalBreak(UniqueMethodIdentifier methodIdentifier, String localName) { - final MethodLocal methodLocal = new MethodLocal(methodIdentifier, localName); - ProbeChain probeChain = localsToProbeChains.get(methodLocal); - if (probeChain == null) { - throw new RuntimeException("Can't find method local " + methodLocal); - } - RubyProbe probe = localsToAttachedBreakpoints.get(methodLocal); - if (probe != null) { - throw new RuntimeException("Breakpoint already set on method local " + methodLocal); - } - probe = new RubyBreakAfterLocalProbe(context, methodLocal); - localsToAttachedBreakpoints.put(methodLocal, probe); - probeChain.appendProbe(probe); - } - - /** - * Sets a Ruby proc of one argument to be run after a method local assignment, passed the new - * value. - */ - public void setLocalProc(UniqueMethodIdentifier methodIdentifier, String localName, RubyProc proc) { - final MethodLocal methodLocal = new MethodLocal(methodIdentifier, localName); - ProbeChain probeChain = localsToProbeChains.get(methodLocal); - if (probeChain == null) { - throw new RuntimeException("Can't find method local " + methodLocal); - } - RubyProbe probe = localsToAttachedBreakpoints.get(methodLocal); - if (probe != null) { - throw new RuntimeException("Assignment proc already set on method local " + methodLocal); - } - probe = new RubyProcAfterLocalProbe(context, methodLocal, proc); - localsToAttachedBreakpoints.put(methodLocal, probe); - probeChain.appendProbe(probe); - } - - /** - * Removes a break or proc on assignment to a method local variable in the AST. - */ - public void removeLocalProbe(UniqueMethodIdentifier methodIdentifier, String localName) { - final MethodLocal methodLocal = new MethodLocal(methodIdentifier, localName); - RubyProbe probe = localsToAttachedBreakpoints.get(methodLocal); - if (probe == null) { - throw new RuntimeException("No breakpoint set on method local " + methodLocal); - } - localsToProbeChains.get(methodLocal).removeProbe(probe); - localsToAttachedBreakpoints.remove(methodLocal); - } - - public void haltedAt(Node astNode, MaterializedFrame frame) { - switch (executionMode) { - case CONTINUE: - case NEXT_NESTED: - // User breakpoints should already be enabled - // Stepping should be false - nextNestedInCallNode = null; - break; - case STEP: - unfinishedStepCount--; - if (unfinishedStepCount > 0) { - return; - } - // Revert to default mode. - enableLineBreakpoints(); - setStepping(false); - break; - case NEXT: - unfinishedNextCount--; - if (unfinishedNextCount > 0) { - return; - } - // Revert to default mode. - enableLineBreakpoints(); - setStepping(false); - break; - default: - assert false; // Should not happen - break; - - } - // Clean up, just in cased the one-shot breakpoints got confused - removeOneShotBreakpoints(); - - setMode(ExecutionMode.CONTINUE); - - // Return control to the debug client - context.haltedAt(astNode, frame); - - } - - private RubyProbe createReplacement(RubyProbe probe) { - // Should be a specialized replacement for any kind of probe created. - // Ugly, but there's no other way to reset the parent pointer and reuse a probe node. - if (probe instanceof RubyBreakBeforeLineProbe) { - final RubyBreakBeforeLineProbe oldProbe = (RubyBreakBeforeLineProbe) probe; - return new RubyBreakBeforeLineProbe(context, oldProbe.getLineLocation(), oldProbe.isOneShot()); - } - if (probe instanceof RubyProcBeforeLineProbe) { - final RubyProcBeforeLineProbe oldProbe = (RubyProcBeforeLineProbe) probe; - return new RubyProcBeforeLineProbe(context, oldProbe.getLineLocation(), oldProbe.getProc()); - } - assert false; - return null; - } - - /** - * A breakpoint of the sort that would be created by a client, with a life-cycle represented by - * {@link BreakpointStatus}. - */ - private final class RubyLineBreakpoint implements DebugManager.LineBreakpoint, Comparable { - - private final SourceLineLocation location; - - private RubyProbe probe; // non-null until RETIRED, but may get replaced. - private ProbeChain probeChain = null; - private BreakpointStatus status = BreakpointStatus.PENDING; - - public RubyLineBreakpoint(SourceLineLocation location, RubyProbe probe) { - this.location = location; - this.probe = probe; - } - - public SourceLineLocation getSourceLineLocation() { - return location; - } - - // ensure sorted by location - public int compareTo(Object o) { - final RubyLineBreakpoint other = (RubyLineBreakpoint) o; - return location.compareTo(other.location); - } - - @Override - public String getDebugStatus() { - String result = status == null ? "" : status.name; - if (probe.isOneShot()) { - result = result + ", " + "One-Shot"; - } - return result; - } - - private void attach(ProbeChain chain) { - assert status == BreakpointStatus.PENDING; - - probeChain = chain; - probeChain.appendProbe(probe); - - status = BreakpointStatus.ACTIVE; - } - - private void disable() { - assert status == BreakpointStatus.ACTIVE; - - probeChain.removeProbe(probe); - status = BreakpointStatus.DISABLED; - } - - private void enable() { - assert status == BreakpointStatus.DISABLED; - - // Can't re-attach to probe chain, because can't re-assign parent. - probe = createReplacement(probe); - probeChain.appendProbe(probe); - status = BreakpointStatus.ACTIVE; - } - - private void setPending() { - assert status == BreakpointStatus.ERROR; - - status = BreakpointStatus.PENDING; - } - - public void setError() { - assert status == BreakpointStatus.PENDING; - - status = BreakpointStatus.ERROR; - } - - private void retire() { - - if (status == BreakpointStatus.ACTIVE) { - probeChain.removeProbe(probe); - } - probe = null; - probeChain = null; - - status = BreakpointStatus.RETIRED; - } - - private void retire(RubyProbe retiredProbe) { - - assert this.probe == retiredProbe; - retire(); - } - } - - private static final class CallRecord { - - final SourceSection section; - @SuppressWarnings("unused") final String name; - final CallRecord predecessor; - - public CallRecord(SourceSection section, String name, CallRecord predecessor) { - this.section = section; - this.name = name; - this.predecessor = predecessor; - } - } - - private CallRecord callStack = null; - - public void notifyCallEntry(Node astNode, String name) { - if (TRACE) { - OUT.println("DebugManager: ENTER \"" + name + "\" " + nodeToString(astNode)); - } - if (executionMode == ExecutionMode.NEXT && nextNestedInCallNode == null) { - // In "Next" mode, where we have been "stepping", but are about to enter a call. - // Switch modes to be like "Continue" until/if return from this call - nextNestedInCallNode = astNode; - enableLineBreakpoints(); - setStepping(false); - setMode(ExecutionMode.NEXT_NESTED); - } - - callStack = new CallRecord(astNode.getSourceSection(), name, callStack); - } - - public void notifyCallExit(Node astNode, String name) { - if (TRACE) { - OUT.println("DebugManager: EXIT \"" + name + "\" " + nodeToString(astNode)); - } - - if (executionMode == ExecutionMode.NEXT_NESTED) { - assert nextNestedInCallNode != null; - if (nextNestedInCallNode == astNode) { - // In "Next" mode while nested in a function/method call, but about to return. - // Switch modes to be like "Step" until/if enter another function/method call. - nextNestedInCallNode = null; - disableLineBreakpoints(); - setStepping(true); - setMode(ExecutionMode.NEXT); - } - } - - final SourceSection section = astNode.getSourceSection(); - if (section instanceof NullSourceSection) { - if (TRACE) { - OUT.println("Ignoring call exit \"" + name + "\" " + nodeToString(astNode)); - } - } - callStack = callStack.predecessor; - } - - /** - * Sets a one-shot breakpoint to halt just after the completion of the call site at the top of - * the current call stack. - */ - public boolean setReturnBreakpoint() { - if (callStack == null) { - return false; - } - final SourceLineLocation lineLocation = new SourceLineLocation(callStack.section); - RubyLineBreakpoint breakpoint = lineToBreakpoint.get(lineLocation); - if (breakpoint != null) { - return true; - } - final ProbeChain probeChain = findProbeChain(lineLocation); - if (probeChain != null) { - breakpoint = new RubyLineBreakpoint(lineLocation, new RubyBreakAfterLineProbe(context, lineLocation, true)); - lineToBreakpoint.put(lineLocation, breakpoint); - breakpoint.attach(probeChain); - return true; - } - return false; - } - - /** - * Notifies that a new execution is about to start, i.e. running a program or an eval. - */ - @SuppressWarnings("static-method") - public void startExecution(String name) { - if (TRACE) { - OUT.println("RubyDebugManager: START " + name); - } - // TODO (mlvdv) push the current call stack onto a stack; start new empty call stack - } - - /** - * Notifies that the current execution has ended. - */ - public void endExecution(String name) { - if (TRACE) { - OUT.println("RubyDebugManager: END " + name); - } - - // TODO (mlvdv) pop the current call stack, restore previous - - switch (executionMode) { - case CONTINUE: - case NEXT_NESTED: - // User breakpoints should already be enabled - // Stepping should be false - nextNestedInCallNode = null; - break; - case STEP: - // Revert to default mode. - enableLineBreakpoints(); - setStepping(false); - unfinishedStepCount = 0; - break; - case NEXT: - // Revert to default mode. - enableLineBreakpoints(); - setStepping(false); - unfinishedNextCount = 0; - break; - default: - assert false; // Should not happen - break; - } - // Clean up, just in cased the one-shot breakpoints got confused - removeOneShotBreakpoints(); - - setMode(ExecutionMode.CONTINUE); - } - - @SuppressWarnings("static-method") - private String nodeToString(Node astNode) { - final SourceSection sourceSection = astNode.getSourceSection(); - if (sourceSection != null) { - return Integer.toString(sourceSection.getStartLine()) + ":" + astNode; - } - return astNode.toString(); - } - -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyLineProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyLineProbe.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.api.source.*; -import com.oracle.truffle.ruby.runtime.*; - -/** - * A Ruby probe situated at a Ruby "line". - */ -public abstract class RubyLineProbe extends RubyProbe { - - protected final SourceLineLocation location; - - /** - * Creates a probe that will cause a halt just before child execution starts; a {@code oneShot} - * probe will remove itself the first time it halts. - */ - public RubyLineProbe(RubyContext context, SourceLineLocation location, boolean oneShot) { - super(context, oneShot); - this.location = location; - } - - public SourceLineLocation getLineLocation() { - return location; - } - -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyLocalProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyLocalProbe.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.ruby.runtime.*; - -/** - * A Ruby probe situated at a Ruby local assignment. - */ -public abstract class RubyLocalProbe extends RubyProbe { - - protected final MethodLocal local; - - public RubyLocalProbe(RubyContext context, MethodLocal local, boolean oneShot) { - super(context, oneShot); - this.local = local; - } - -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProcAfterLineProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProcAfterLineProbe.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.source.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * A probe for instrumenting a Ruby program with a Ruby procedure to run on the return value from - * node execution at a line. - */ -public final class RubyProcAfterLineProbe extends RubyLineProbe { - - private final RubyProc proc; - - public RubyProcAfterLineProbe(RubyContext context, SourceLineLocation location, RubyProc proc) { - super(context, location, false); - this.proc = proc; - } - - @Override - public void leave(Node astNode, VirtualFrame frame) { - proc.call(frame.pack()); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, boolean result) { - proc.call(frame.pack(), result); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, int result) { - proc.call(frame.pack(), result); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, double result) { - proc.call(frame.pack(), result); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, Object result) { - proc.call(frame.pack(), result); - } - - @Override - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - proc.call(frame.pack()); - } -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProcAfterLocalProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProcAfterLocalProbe.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * A probe for instrumenting a Ruby program with a Ruby procedure to run on the return value from a - * local assignment. - */ -public final class RubyProcAfterLocalProbe extends RubyLocalProbe { - - private final RubyProc proc; - - public RubyProcAfterLocalProbe(RubyContext context, MethodLocal local, RubyProc proc) { - super(context, local, false); - this.proc = proc; - } - - @Override - public void leave(Node astNode, VirtualFrame frame) { - proc.call(frame.pack()); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, boolean result) { - proc.call(frame.pack(), result); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, int result) { - proc.call(frame.pack(), result); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, double result) { - proc.call(frame.pack(), result); - } - - @Override - public void leave(Node astNode, VirtualFrame frame, Object result) { - proc.call(frame.pack(), result); - } - - @Override - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - proc.call(frame.pack()); - } -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProcBeforeLineProbe.java --- a/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/debug/RubyProcBeforeLineProbe.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013, 2014 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.runtime.debug; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.source.*; -import com.oracle.truffle.ruby.runtime.*; -import com.oracle.truffle.ruby.runtime.core.*; - -/** - * A probe for instrumenting a Ruby program with a Ruby procedure to run before a calling a child - * node at a line. - */ -public final class RubyProcBeforeLineProbe extends RubyLineProbe { - - private final RubyProc proc; - - public RubyProcBeforeLineProbe(RubyContext context, SourceLineLocation location, RubyProc proc) { - super(context, location, false); - this.proc = proc; - } - - @Override - public void enter(Node astNode, VirtualFrame frame) { - proc.call(frame.pack()); - } - - public RubyProc getProc() { - return proc; - } - -} diff -r 3424bc098ca0 -r b9c5875e3a36 graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/debug/DebugTests.java --- a/graal/com.oracle.truffle.ruby.test/src/com/oracle/truffle/ruby/test/debug/DebugTests.java Wed Jan 22 18:46:38 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This - * code is released under a tri EPL/GPL/LGPL license. You can use it, - * redistribute it and/or modify it under the terms of the: - * - * Eclipse Public License version 1.0 - * GNU General Public License version 2 - * GNU Lesser General Public License version 2.1 - */ -package com.oracle.truffle.ruby.test.debug; - -import org.junit.*; - -import com.oracle.truffle.ruby.runtime.configuration.*; -import com.oracle.truffle.ruby.test.*; - -/** - * Test the debugger. - */ -public class DebugTests extends RubyTests { - - @Test - public void testBreakContinue() { - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.setDebug(true); - final Configuration configuration = new Configuration(configurationBuilder); - - final String fakeFileName = "test.rb"; - final String code = "Debug.break; puts 2"; - final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'"; - final String expected = "1\n=> \n2\n"; - - assertPrints(configuration, expected, fakeFileName, code, input, new String[]{}); - } - - @Test - public void testLineBreak() { - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.setDebug(true); - final Configuration configuration = new Configuration(configurationBuilder); - - final String fakeFileName = "test.rb"; - final String code = "Debug.break(\"test.rb\", 2) \n puts 2 \n puts 3"; - final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'"; - final String expected = "1\n=> \n2\n3\n"; - - assertPrints(configuration, expected, fakeFileName, code, input, new String[]{}); - } - - @Test - public void testLineCustomBreak() { - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.setDebug(true); - final Configuration configuration = new Configuration(configurationBuilder); - - final String fakeFileName = "test.rb"; - final String code = "Debug.break('test.rb', 2) { puts 1; Debug.break }\nputs 3\nputs 4"; - final String input = "puts 2 \n Debug.continue \n puts 'error' \n puts 'error'"; - final String expected = "1\n2\n=> \n3\n4\n"; - - assertPrints(configuration, expected, fakeFileName, code, input, new String[]{}); - } - - @Test - public void testLocalBreak() { - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.setDebug(true); - final Configuration configuration = new Configuration(configurationBuilder); - - final String fakeFileName = "test.rb"; - final String code = "def foo \n puts 0 \n x = 14 \n end \n Debug.break(:foo, :x) \n foo \n puts 2"; - final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'"; - final String expected = "0\n1\n=> \n2\n"; - - assertPrints(configuration, expected, fakeFileName, code, input, new String[]{}); - } - - @Test - public void testLocalCustomBreak() { - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.setDebug(true); - final Configuration configuration = new Configuration(configurationBuilder); - - final String fakeFileName = "test.rb"; - final String code = "def foo \n puts 0 \n x = 14 \n end \n Debug.break(:foo, :x) { |v| puts v; Debug.break } \n foo \n puts 2"; - final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'"; - final String expected = "0\n14\n1\n=> \n2\n"; - - assertPrints(configuration, expected, fakeFileName, code, input, new String[]{}); - } - - @Test - public void testRemoveLineBreak() { - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.setDebug(true); - final Configuration configuration = new Configuration(configurationBuilder); - - final String fakeFileName = "test.rb"; - final String code = "Debug.break('test.rb', 3) \n Debug.remove('test.rb', 3) \n puts 2 \n puts 3"; - final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'"; - final String expected = "2\n3\n"; - - assertPrints(configuration, expected, fakeFileName, code, input, new String[]{}); - } - - @Test - public void testRemoveLocalBreak() { - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.setDebug(true); - final Configuration configuration = new Configuration(configurationBuilder); - - final String fakeFileName = "test.rb"; - final String code = "def foo \n puts 0 \n x = 14 \n end \n Debug.break(:foo, :x) \n foo \n Debug.remove(:foo, :x) \n foo \n puts 2"; - final String input = "puts 1 \n Debug.continue \n puts 'error' \n puts 'error'"; - final String expected = "0\n1\n=> \n0\n2\n"; - - assertPrints(configuration, expected, fakeFileName, code, input, new String[]{}); - } - - @Test - public void testWhere() { - final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); - configurationBuilder.setDebug(true); - final Configuration configuration = new Configuration(configurationBuilder); - - final String fakeFileName = "test.rb"; - final String code = "puts 1 \n Debug.where \n puts 2"; - final String expected = "1\ntest.rb:2\n2\n"; - - assertPrints(configuration, expected, fakeFileName, code, "", new String[]{}); - } - -} diff -r 3424bc098ca0 -r b9c5875e3a36 make/bsd/makefiles/vm.make --- a/make/bsd/makefiles/vm.make Wed Jan 22 18:46:38 2014 +0100 +++ b/make/bsd/makefiles/vm.make Fri Jan 24 00:33:56 2014 +0100 @@ -222,20 +222,22 @@ ifneq ($(INCLUDE_GRAAL), true) GRAAL_SPECIFIC_FILES := graal\* + GRAAL_SPECIFIC_GPU_FILES := gpu\* ptx\* hsail\* else GRAAL_SPECIFIC_FILES := + GRAAL_SPECIFIC_GPU_FILES := endif # Always exclude these. Src_Files_EXCLUDE += jsig.c jvmtiEnvRecommended.cpp jvmtiEnvStub.cpp # Exclude per type. -Src_Files_EXCLUDE/CORE := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) ciTypeFlow.cpp -Src_Files_EXCLUDE/COMPILER1 := $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) ciTypeFlow.cpp -Src_Files_EXCLUDE/COMPILER2 := $(COMPILER1_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) -Src_Files_EXCLUDE/TIERED := $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) -Src_Files_EXCLUDE/ZERO := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) ciTypeFlow.cpp -Src_Files_EXCLUDE/SHARK := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) +Src_Files_EXCLUDE/CORE := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) ciTypeFlow.cpp +Src_Files_EXCLUDE/COMPILER1 := $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) ciTypeFlow.cpp +Src_Files_EXCLUDE/COMPILER2 := $(COMPILER1_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) +Src_Files_EXCLUDE/TIERED := $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) +Src_Files_EXCLUDE/ZERO := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) ciTypeFlow.cpp +Src_Files_EXCLUDE/SHARK := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) Src_Files_EXCLUDE/GRAAL := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) ciTypeFlow.cpp Src_Files_EXCLUDE += $(Src_Files_EXCLUDE/$(TYPE)) diff -r 3424bc098ca0 -r b9c5875e3a36 make/linux/makefiles/vm.make --- a/make/linux/makefiles/vm.make Wed Jan 22 18:46:38 2014 +0100 +++ b/make/linux/makefiles/vm.make Fri Jan 24 00:33:56 2014 +0100 @@ -201,21 +201,23 @@ ZERO_SPECIFIC_FILES := zero ifneq ($(INCLUDE_GRAAL), true) - GRAAL_SPECIFIC_FILES := graal\* + GRAAL_SPECIFIC_FILES := graal\* + GRAAL_SPECIFIC_GPU_FILES := gpu\* ptx\* hsail\* else GRAAL_SPECIFIC_FILES := + GRAAL_SPECIFIC_GPU_FILES := endif # Always exclude these. Src_Files_EXCLUDE += jsig.c jvmtiEnvRecommended.cpp jvmtiEnvStub.cpp # Exclude per type. -Src_Files_EXCLUDE/CORE := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) ciTypeFlow.cpp -Src_Files_EXCLUDE/COMPILER1 := $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) ciTypeFlow.cpp -Src_Files_EXCLUDE/COMPILER2 := $(COMPILER1_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) -Src_Files_EXCLUDE/TIERED := $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) -Src_Files_EXCLUDE/ZERO := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) ciTypeFlow.cpp -Src_Files_EXCLUDE/SHARK := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) +Src_Files_EXCLUDE/CORE := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) ciTypeFlow.cpp +Src_Files_EXCLUDE/COMPILER1 := $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) ciTypeFlow.cpp +Src_Files_EXCLUDE/COMPILER2 := $(COMPILER1_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) +Src_Files_EXCLUDE/TIERED := $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) +Src_Files_EXCLUDE/ZERO := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) ciTypeFlow.cpp +Src_Files_EXCLUDE/SHARK := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) Src_Files_EXCLUDE/GRAAL := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) ciTypeFlow.cpp Src_Files_EXCLUDE += $(Src_Files_EXCLUDE/$(TYPE)) diff -r 3424bc098ca0 -r b9c5875e3a36 make/solaris/makefiles/vm.make --- a/make/solaris/makefiles/vm.make Wed Jan 22 18:46:38 2014 +0100 +++ b/make/solaris/makefiles/vm.make Fri Jan 24 00:33:56 2014 +0100 @@ -219,17 +219,18 @@ SHARK_SPECIFIC_FILES := shark ZERO_SPECIFIC_FILES := zero GRAAL_SPECIFIC_FILES := graal +GRAAL_SPECIFIC_GPU_FILES := gpu\* ptx\* hsail\* # Always exclude these. Src_Files_EXCLUDE := dtrace jsig.c jvmtiEnvRecommended.cpp jvmtiEnvStub.cpp # Exclude per type. -Src_Files_EXCLUDE/CORE := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) ciTypeFlow.cpp -Src_Files_EXCLUDE/COMPILER1 := $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) ciTypeFlow.cpp -Src_Files_EXCLUDE/COMPILER2 := $(COMPILER1_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) -Src_Files_EXCLUDE/TIERED := $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) -Src_Files_EXCLUDE/ZERO := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) ciTypeFlow.cpp -Src_Files_EXCLUDE/SHARK := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) +Src_Files_EXCLUDE/CORE := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) ciTypeFlow.cpp +Src_Files_EXCLUDE/COMPILER1 := $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) ciTypeFlow.cpp +Src_Files_EXCLUDE/COMPILER2 := $(COMPILER1_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) +Src_Files_EXCLUDE/TIERED := $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) +Src_Files_EXCLUDE/ZERO := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) ciTypeFlow.cpp +Src_Files_EXCLUDE/SHARK := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(GRAAL_SPECIFIC_FILES) $(GRAAL_SPECIFIC_GPU_FILES) Src_Files_EXCLUDE/GRAAL := $(COMPILER1_SPECIFIC_FILES) $(COMPILER2_SPECIFIC_FILES) $(ZERO_SPECIFIC_FILES) $(SHARK_SPECIFIC_FILES) ciTypeFlow.cpp Src_Files_EXCLUDE += $(Src_Files_EXCLUDE/$(TYPE)) diff -r 3424bc098ca0 -r b9c5875e3a36 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Wed Jan 22 18:46:38 2014 +0100 +++ b/src/share/vm/compiler/compileBroker.cpp Fri Jan 24 00:33:56 2014 +0100 @@ -1144,7 +1144,9 @@ } #ifdef GRAALVM if (!JavaThread::current()->is_graal_compiling()) { - GraalCompiler::instance()->compile_method(method, osr_bci, is_compile_blocking(method, osr_bci)); + bool blockingCompilation = is_compile_blocking(method, osr_bci) || + CompilationPolicy::can_be_offloaded_to_gpu(method); + GraalCompiler::instance()->compile_method(method, osr_bci, blockingCompilation); } else { // Recursive compile request => ignore. } diff -r 3424bc098ca0 -r b9c5875e3a36 src/share/vm/graal/graalGlobals.hpp --- a/src/share/vm/graal/graalGlobals.hpp Wed Jan 22 18:46:38 2014 +0100 +++ b/src/share/vm/graal/graalGlobals.hpp Fri Jan 24 00:33:56 2014 +0100 @@ -79,6 +79,12 @@ develop(bool, TraceUncollectedSpeculations, false, \ "Print message when a failed speculation was not collected") \ \ + product(bool, GPUOffload, false, \ + "Offload execution to GPU whenever possible") \ + \ + product(bool, TraceGPUInteraction, false, \ + "Trace external GPU Interaction") \ + \ // Read default values for Graal globals diff -r 3424bc098ca0 -r b9c5875e3a36 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Wed Jan 22 18:46:38 2014 +0100 +++ b/src/share/vm/oops/method.cpp Fri Jan 24 00:33:56 2014 +0100 @@ -2025,28 +2025,3 @@ guarantee(md == NULL || md->is_methodData(), "should be method data"); } - -#ifdef GRAAL - -// Return true if the name of the method indicates that this is a -// lambda method other than . Lambda method is one with a name -// that starts with lambda$ and is synthetic. - -bool Method::is_lambda() const { - Symbol * klass_name = method_holder()->name(); - Symbol * method_name = name(); - ResourceMark rm; - if (klass_name != NULL) { - if (klass_name != NULL && method_name != NULL) { - const char* lambdaPrefix = "lambda$main$"; - char* methodPrefix = strstr(method_name->as_C_string(), lambdaPrefix); - if (methodPrefix != 0) { - if ((strncmp(lambdaPrefix, methodPrefix, strlen(lambdaPrefix)) == 0) && is_synthetic()) { - return true; - } - } - } - } - return false; -} -#endif diff -r 3424bc098ca0 -r b9c5875e3a36 src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Wed Jan 22 18:46:38 2014 +0100 +++ b/src/share/vm/oops/method.hpp Fri Jan 24 00:33:56 2014 +0100 @@ -617,11 +617,6 @@ // simultaneously. Use with caution. bool has_compiled_code() const { return code() != NULL; } -#ifdef GRAAL - // Return true if the name of the method indicates that this is a - // lambda method other than . - bool is_lambda() const; -#endif // sizing static int header_size() { return sizeof(Method)/HeapWordSize; } static int size(bool is_native); diff -r 3424bc098ca0 -r b9c5875e3a36 src/share/vm/runtime/compilationPolicy.cpp --- a/src/share/vm/runtime/compilationPolicy.cpp Wed Jan 22 18:46:38 2014 +0100 +++ b/src/share/vm/runtime/compilationPolicy.cpp Fri Jan 24 00:33:56 2014 +0100 @@ -105,30 +105,7 @@ if (m->has_compiled_code()) return false; // already compiled -#ifdef GRAAL - // Check if this is a Lambda method that can be compiled to a GPU. - if (m->is_lambda()) { - // If GPU is available and the necessary linkage is available - // rerurn true indicatin that this method must be compiled. - if (gpu::is_available() && gpu::has_gpu_linkage()) { - if (TraceGPUInteraction) { - tty->print("Compiling Lambda method"); - m->print_short_name(); - switch (gpu::get_target_il_type()) { - case gpu::PTX : - tty->print_cr(" to PTX"); - break; - case gpu::HSAIL : - tty->print_cr(" to HSAIL"); - break; - default : - tty->print_cr(" to Unknown GPU!!!"); - } - } - return true; - } - } -#endif + if (CompilationPolicy::can_be_offloaded_to_gpu(m)) return true; if (!can_be_compiled(m, comp_level)) return false; @@ -184,6 +161,58 @@ return (result && can_be_compiled(m, comp_level)); } +bool CompilationPolicy::can_be_offloaded_to_gpu(methodHandle m) { +#ifdef GRAAL + if (GPUOffload) { + // Check if this method can be offloaded to GPU. + // 1. Offload it to GPU if it is a Lambda method + if (m->is_synthetic()) { + // A lambda method is a syntheric method. + Symbol * klass_name = m->method_holder()->name(); + Symbol * method_name = m->name(); + bool offloadToGPU = false; + { + ResourceMark rm; + if (klass_name != NULL) { + if (klass_name != NULL && method_name != NULL) { + const char* lambdaPrefix = "lambda$"; + char* methodPrefix = strstr(method_name->as_C_string(), lambdaPrefix); + if (methodPrefix != 0) { + if ((strncmp(lambdaPrefix, methodPrefix, strlen(lambdaPrefix)) == 0)) { + offloadToGPU = true; + } + } + } + } + } + if (offloadToGPU) { + // If GPU is available and the necessary linkage is available + // return true indicatin that this method must be compiled. + if (gpu::is_available() && gpu::has_gpu_linkage()) { + if (TraceGPUInteraction) { + tty->print("Compiling Lambda method "); + m->print_short_name(); + switch (gpu::get_target_il_type()) { + case gpu::PTX : + tty->print_cr("to PTX"); + break; + case gpu::HSAIL : + tty->print_cr("to HSAIL"); + break; + default : + tty->print_cr("to Unknown GPU!!!"); + } + } + return true; + } + } + } + } +#endif + + return false; +} + bool CompilationPolicy::is_compilation_enabled() { // NOTE: CompileBroker::should_compile_new_jobs() checks for UseCompiler return !delay_compilation_during_startup() && CompileBroker::should_compile_new_jobs(); diff -r 3424bc098ca0 -r b9c5875e3a36 src/share/vm/runtime/compilationPolicy.hpp --- a/src/share/vm/runtime/compilationPolicy.hpp Wed Jan 22 18:46:38 2014 +0100 +++ b/src/share/vm/runtime/compilationPolicy.hpp Fri Jan 24 00:33:56 2014 +0100 @@ -58,6 +58,9 @@ static void set_policy(CompilationPolicy* policy) { _policy = policy; } static CompilationPolicy* policy() { return _policy; } + // m is allowed to be offloaded to a gpu + static bool can_be_offloaded_to_gpu(methodHandle m); + // Profiling elapsedTimer* accumulated_time() { return &_accumulated_time; } void print_time() PRODUCT_RETURN; diff -r 3424bc098ca0 -r b9c5875e3a36 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Wed Jan 22 18:46:38 2014 +0100 +++ b/src/share/vm/runtime/globals.hpp Fri Jan 24 00:33:56 2014 +0100 @@ -3840,9 +3840,6 @@ product(bool , AllowNonVirtualCalls, false, \ "Obey the ACC_SUPER flag and allow invokenonvirtual calls") \ \ - product(bool, TraceGPUInteraction, false, \ - "Trace external GPU Interaction") \ - \ product(bool, UseHSAILSimulator, false, \ "Run code on HSAIL Simulator") \ \ diff -r 3424bc098ca0 -r b9c5875e3a36 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Jan 22 18:46:38 2014 +0100 +++ b/src/share/vm/runtime/thread.cpp Fri Jan 24 00:33:56 2014 +0100 @@ -3394,9 +3394,13 @@ jint parse_result = Arguments::parse(args); if (parse_result != JNI_OK) return parse_result; - // Probe for existance of supported GPU and initialize it if one - // exists. - gpu::init(); +#ifdef GRAAL + if (GPUOffload) { + // Probe for existance of supported GPU and initialize it if one + // exists. + gpu::init(); + } +#endif os::init_before_ergo();