# HG changeset patch # User Michael Van De Vanter # Date 1390111962 28800 # Node ID fbf4489292600bd6693546481958fe213cb6168f # Parent 72f85504e79e5b9fc022a73c08c5d1c959f0b772 Ruby: remove some prototyping code no longer needed diff -r 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/DebugManager.java Sat Jan 18 22:12:42 2014 -0800 @@ -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,40 +37,6 @@ public interface DebugManager { /** - * Gets a list of current breakpoints. - */ - LineBreakpoint[] getBreakpoints(); - - /** - * Sets a breakpoint at a line-based location. - */ - 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); - - /** - * Sets a breakpoint at a line-based location that will remove itself when hit. - */ - LineBreakpoint setOneShotBreakpoint(SourceLineLocation lineLocation); - - /** - * Is there a line-based breakpoint set at a location? - */ - boolean hasBreakpoint(SourceLineLocation lineLocation); - - /** - * Removes a breakpoint at a line-based location. - */ - void removeBreakpoint(SourceLineLocation lineLocation); - - /** - * 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. * @@ -80,14 +46,10 @@ */ void haltedAt(Node astNode, MaterializedFrame frame); - /** - * Description of a line-based breakpoint. - */ - interface LineBreakpoint { + void notifyFinishedLoading(Source source); - SourceLineLocation getSourceLineLocation(); + void notifyStartLoading(Source source); - String getDebugStatus(); - } + ProbeChain getProbeChain(SourceSection sourceSection); } diff -r 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 2014 +0100 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Sat Jan 18 22:12:42 2014 -0800 @@ -42,9 +42,4 @@ */ DebugManager getDebugManager(); - /** - * Gets access to utilities for printing different aspects of a Truffle AST. - */ - ASTPrinter getASTPrinter(); - } diff -r 72f85504e79e -r fbf448929260 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 Sat Jan 18 22:12:42 2014 -0800 @@ -0,0 +1,106 @@ +/* + * 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.*; + +public final 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; + } + + @Override + public void notifyStartLoading(Source source) { + assert beingLoaded == null; + beingLoaded = source; + } + + @Override + public void notifyFinishedLoading(Source source) { + assert source == beingLoaded; + loadedSources.add(source); + beingLoaded = null; + } + + public void haltedAt(Node astNode, MaterializedFrame frame) { + } + +} diff -r 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/CoreMethodNodeManager.java Sat Jan 18 22:12:42 2014 -0800 @@ -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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/JRubyParser.java Sat Jan 18 22:12:42 2014 -0800 @@ -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,7 +21,6 @@ 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 { @@ -100,7 +99,7 @@ RubyNode truffleNode; - final RubyDebugManager debugManager = context.getDebugManager(); + final DebugManager debugManager = context.getDebugManager(); try { if (debugManager != null) { debugManager.notifyStartLoading(source); diff -r 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java Sat Jan 18 22:12:42 2014 -0800 @@ -16,8 +16,6 @@ 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.*; @@ -89,15 +87,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. */ @@ -302,17 +291,6 @@ 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; } @@ -1162,21 +1140,6 @@ 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; } @@ -1477,25 +1440,6 @@ 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) { diff -r 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 2014 +0100 +++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/RubyContext.java Sat Jan 18 22:12:42 2014 -0800 @@ -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 = configuration.getDebug() ? new DefaultDebugManager(this) : null; // Must initialize threads before fibers @@ -88,7 +88,7 @@ return "Ruby"; } - public RubyDebugManager getDebugManager() { + public DebugManager getDebugManager() { return debugManager; } diff -r 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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 72f85504e79e -r fbf448929260 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 Fri Jan 17 23:16:59 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[]{}); - } - -}