# HG changeset patch # User Michael Van De Vanter # Date 1398800607 25200 # Node ID 3774b6f4319b16566d4e4b412e42ee45c04721b0 # Parent be0c151d912b70bb5c9be94e16407de0729ba68c# Parent 2f684eda1938cc92a72a35461c8d00f1871fe389 Merge with 2f684eda1938cc92a72a35461c8d00f1871fe389 diff -r 2f684eda1938 -r 3774b6f4319b 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 Tue Apr 29 19:30:38 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/ExecutionContext.java Tue Apr 29 12:43:27 2014 -0700 @@ -49,12 +49,12 @@ /** * Gets access to AST instrumentation services. */ - Instrumentation instrumentation(); + Instrumentation getInstrumentation(); /** * Access to information visualization services for the specific language. */ - Visualizer visualizer(); + Visualizer getVisualizer(); /** * Add instrumentation to subsequently constructed Truffle ASTs for the guest language; every diff -r 2f684eda1938 -r 3774b6f4319b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java Tue Apr 29 19:30:38 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java Tue Apr 29 12:43:27 2014 -0700 @@ -44,11 +44,11 @@ return sourceManager; } - public final Instrumentation instrumentation() { + public final Instrumentation getInstrumentation() { return instrumentation; } - public Visualizer visualizer() { + public Visualizer getVisualizer() { return visualizer; } diff -r 2f684eda1938 -r 3774b6f4319b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Tue Apr 29 19:30:38 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java Tue Apr 29 12:43:27 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -24,17 +24,103 @@ */ package com.oracle.truffle.api.instrument; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.CompilerDirectives.SlowPath; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.instrument.impl.*; +import com.oracle.truffle.api.nodes.*; + /** * A receiver of Truffle AST {@link ExecutionEvents}, propagated from a {@link Probe} to which the - * instrument is attached. + * instrument is attached, for the benefit of associated tools. *

- * Disclaimer: experimental interface under development. + * Guidelines for implementing Instruments, with particular attention to avoiding undesired runtime + * performance overhead: + *

    + *
  1. Extend {@link Instrument} and override only the event handling methods for which some action + * is needed.
  2. + *
  3. Instruments are Truffle {@link Node}s and should be coded as much as possible in the desired + * Truffle style, documented more thoroughly elsewhere.
  4. + *
  5. Maintain as little state as possible.
  6. + *
  7. If state is necessary, make it {@code final} if possible.
  8. + *
  9. If non-final state is necessary, annotate it as {@link CompilationFinal} and call + * {@linkplain InstrumentationNode#notifyProbeChanged(Instrument)} whenever it is modified.
  10. + *
  11. Never store a {@link Frame} value in a field.
  12. + *
  13. Minimize computation in standard execution paths.
  14. + *
  15. Callbacks to tools should be made via callbacks provided at construction and stored in + * {@code final} fields.
  16. + *
  17. Tool callback methods should usually be annotated as {@link SlowPath} to prevent them from + * being inlined into fast execution paths.
  18. + *
  19. If computation is needed, and if performance is important, then the computation is best + * expressed as a guest language AST and evaluated using standard Truffle mechanisms so that + * standard Truffle optimizations can be applied.
  20. + *
+ *

+ * Guidelines for attachment to a {@link Probe}: + *

    + *
  1. An Instrument instance must only attached to a single {@link Probe}, each of which is + * associated uniquely with a specific syntactic unit of a guest language program, and thus + * (initially) to a specific {@linkplain Node Truffle AST node}.
  2. + *
  3. When the AST containing such a node is copied at runtime, the {@link Probe} will be shared by + * every copy, and so the Instrument will receive events corresponding to the intended syntactic + * unit of code, independent of which AST copy is being executed.
  4. + *
+ * + *

+ * Disclaimer: experimental; under development. + * + * @see Instrumentation + * @see Probe + * @see Instrument + * @see ASTNodeProber */ -public interface Instrument extends ExecutionEvents { +public class Instrument extends InstrumentationNode { + + protected Instrument() { + } + + public void enter(Node astNode, VirtualFrame frame) { + } + + public void leave(Node astNode, VirtualFrame frame) { + } + + public void leave(Node astNode, VirtualFrame frame, boolean result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, byte result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, short result) { + leave(astNode, frame, (Object) result); + } - /** - * @return the {@link Probe} to which this instrument is attached. - */ - Probe getProbe(); + public void leave(Node astNode, VirtualFrame frame, int result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, long result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, char result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, float result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, double result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, Object result) { + } + + public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + } } diff -r 2f684eda1938 -r 3774b6f4319b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java Tue Apr 29 19:30:38 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java Tue Apr 29 12:43:27 2014 -0700 @@ -24,10 +24,18 @@ */ package com.oracle.truffle.api.instrument; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; /** - * Visualization services for guest language and Truffle information. + * Visualization services for the benefit of {@link Instrumentation}-based tools, possibly + * specialized for each guest language and possibly specialized for relevant information from the + * underlying Truffle implementation. + *

+ * Disclaimer: experimental interface under development. + * + * @See Instrumentation */ public interface Visualizer { @@ -38,6 +46,21 @@ ASTPrinter getASTPrinter(); /** + * A short description of a source location in terms of source + line number. + */ + String displaySourceLocation(Node node); + + /** + * Describes the name of the method containing a node. + */ + String displayMethodName(Node node); + + /** + * The name of the method. + */ + String displayCallTargetName(CallTarget callTarget); + + /** * Converts a value in the guest language to a display string. */ String displayValue(Object value); diff -r 2f684eda1938 -r 3774b6f4319b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrument.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultInstrument.java Tue Apr 29 19:30:38 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * 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.instrument.impl; - -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; - -/** - * An {@link Instrument} that implements all {@link ExecutionEvents} notifications with empty - * methods. - */ -public class DefaultInstrument extends InstrumentationNodeImpl implements Instrument { - - protected DefaultInstrument() { - } - - public void enter(Node astNode, VirtualFrame frame) { - } - - public void leave(Node astNode, VirtualFrame frame) { - } - - public void leave(Node astNode, VirtualFrame frame, boolean result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, byte result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, short result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, int result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, long result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, char result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, float result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, double result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, Object result) { - } - - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - } - -} diff -r 2f684eda1938 -r 3774b6f4319b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java Tue Apr 29 19:30:38 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java Tue Apr 29 12:43:27 2014 -0700 @@ -24,8 +24,12 @@ */ package com.oracle.truffle.api.instrument.impl; +import java.io.*; + +import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; public class DefaultVisualizer implements Visualizer { @@ -39,6 +43,43 @@ return astPrinter; } + public String displaySourceLocation(Node node) { + if (node == null) { + return ""; + } + SourceSection section = node.getSourceSection(); + boolean estimated = false; + if (section == null) { + section = node.getEncapsulatingSourceSection(); + estimated = true; + } + + String sourceString; + if (section == null || section.getSource() == null) { + sourceString = ""; + } else { + String sourceName = new File(section.getSource().getName()).getName(); + int startLine = section.getStartLine(); + sourceString = String.format("%s:%d%s", sourceName, startLine, estimated ? "~" : ""); + } + return sourceString; + } + + public String displayMethodName(Node node) { + if (node == null) { + return null; + } + RootNode root = node.getRootNode(); + if (root == null) { + return "unknown"; + } + return root.getCallTarget().toString(); + } + + public String displayCallTargetName(CallTarget callTarget) { + return callTarget.toString(); + } + public String displayValue(Object value) { return value.toString(); } diff -r 2f684eda1938 -r 3774b6f4319b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationImpl.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationImpl.java Tue Apr 29 19:30:38 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationImpl.java Tue Apr 29 12:43:27 2014 -0700 @@ -30,10 +30,6 @@ import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.source.*; -/** - * @author mlvdv - * - */ public final class InstrumentationImpl implements Instrumentation { private final ExecutionContext context; @@ -80,7 +76,7 @@ if (probe != null) { return probe; } - probe = InstrumentationNodeImpl.createProbe(this, sourceSection, eventListener); + probe = InstrumentationNode.createProbe(this, sourceSection, eventListener); // Register new probe by unique SourceSection srcToProbe.put(sourceSection, probe); diff -r 2f684eda1938 -r 3774b6f4319b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java Tue Apr 29 12:43:27 2014 -0700 @@ -0,0 +1,446 @@ +/* + * 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.instrument.impl; + +import java.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments. + *

+ * Coordinates propagation of Truffle AST {@link ExecutionEvents}. + */ +public abstract class InstrumentationNode extends Node implements ExecutionEvents { + + // TODO (mlvdv) This is a pretty awkward design; it is a priority to revise it. + + /** + * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection} + * extent of guest language source code. + * + * @param eventListener an optional listener for certain instrumentation-related events. + * @return a new probe + */ + static Probe createProbe(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) { + return new ProbeImpl(instrumentation, sourceSection, eventListener); + } + + /** + * Next in chain. + */ + @Child protected InstrumentationNode next; + + protected InstrumentationNode() { + } + + /** + * @return the instance of {@link Probe} to which this instrument is attached. + */ + public Probe getProbe() { + final InstrumentationNode parent = (InstrumentationNode) getParent(); + return parent == null ? null : parent.getProbe(); + } + + /** + * Add a probe to the end of this probe chain. + */ + private void internalAddInstrument(Instrument newInstrument) { + if (next == null) { + this.next = insert(newInstrument); + } else { + next.internalAddInstrument(newInstrument); + } + } + + private void internalRemoveInstrument(Instrument oldInstrument) { + if (next == null) { + throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument); + } else if (next == oldInstrument) { + if (oldInstrument.next == null) { + this.next = null; + } else { + this.next = insert(oldInstrument.next); + oldInstrument.next = null; + } + } else { + next.internalRemoveInstrument(oldInstrument); + } + } + + /** + * Reports to the instance of {@link Probe} holding this instrument that some essential state + * has changed that requires deoptimization. + */ + @CompilerDirectives.SlowPath + protected void notifyProbeChanged(Instrument instrument) { + final ProbeImpl probe = (ProbeImpl) getProbe(); + probe.notifyProbeChanged(instrument); + } + + private void internalEnter(Node astNode, VirtualFrame frame) { + enter(astNode, frame); + if (next != null) { + next.internalEnter(astNode, frame); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame) { + leave(astNode, frame); + if (next != null) { + next.internalLeave(astNode, frame); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, boolean result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, byte result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, short result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, int result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, long result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, char result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, float result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, double result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeave(Node astNode, VirtualFrame frame, Object result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + private void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + leaveExceptional(astNode, frame, null); + if (next != null) { + next.internalLeaveExceptional(astNode, frame, e); + } + } + + /** + * Holder of a chain of {@linkplain InstrumentationNode instruments}: manages the + * {@link Assumption} that none of the instruments have changed since last checked. + *

+ * An instance is intended to be shared by every clone of the AST node with which it is + * originally attached, so it holds no parent pointer. + *

+ * May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful + * for instrumentation about its AST location(s). + */ + private static final class ProbeImpl extends InstrumentationNode implements Probe { + + final InstrumentationImpl instrumentation; + + final InstrumentEventListener eventListener; + + @CompilerDirectives.CompilationFinal private Assumption probeUnchanged; + + /** + * When in stepping mode, ordinary line breakpoints are ignored, but every entry at a line + * will cause a halt. + */ + @CompilerDirectives.CompilationFinal private boolean stepping; + + /** + * Source information about the AST node to which this instrumentation is attached. + */ + private final SourceSection probedSourceSection; + + private final Set tags = EnumSet.noneOf(PhylumTag.class); + + private ProbeImpl(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) { + this.instrumentation = instrumentation; + this.probedSourceSection = sourceSection; + this.eventListener = eventListener == null ? NullInstrumentEventListener.INSTANCE : eventListener; + this.probeUnchanged = Truffle.getRuntime().createAssumption(); + this.next = null; + } + + @Override + public Probe getProbe() { + return this; + } + + @Override + protected void notifyProbeChanged(Instrument instrument) { + probeUnchanged.invalidate(); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + + public SourceSection getSourceLocation() { + return probedSourceSection; + } + + public void tagAs(PhylumTag tag) { + assert tag != null; + if (!tags.contains(tag)) { + tags.add(tag); + instrumentation.newTagAdded(this, tag); + } + } + + public boolean isTaggedAs(PhylumTag tag) { + assert tag != null; + return tags.contains(tag); + } + + public Set getPhylumTags() { + return tags; + } + + public void setStepping(boolean stepping) { + if (this.stepping != stepping) { + this.stepping = stepping; + probeUnchanged.invalidate(); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + } + + public boolean isStepping() { + return stepping; + } + + @CompilerDirectives.SlowPath + public void addInstrument(Instrument instrument) { + probeUnchanged.invalidate(); + super.internalAddInstrument(instrument); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + + @CompilerDirectives.SlowPath + public void removeInstrument(Instrument instrument) { + probeUnchanged.invalidate(); + super.internalRemoveInstrument(instrument); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + + public void notifyEnter(Node astNode, VirtualFrame frame) { + if (stepping || next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + if (stepping) { + eventListener.haltedAt(astNode, frame.materialize()); + } + if (next != null) { + next.internalEnter(astNode, frame); + } + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, byte result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, short result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, int result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, long result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, char result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, float result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, double result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeave(Node astNode, VirtualFrame frame, Object result) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeave(astNode, frame, result); + } + } + + public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalLeaveExceptional(astNode, frame, e); + } + } + + public void enter(Node astNode, VirtualFrame frame) { + } + + public void leave(Node astNode, VirtualFrame frame) { + } + + public void leave(Node astNode, VirtualFrame frame, boolean result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, byte result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, short result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, int result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, long result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, char result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, float result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, double result) { + leave(astNode, frame, (Object) result); + } + + public void leave(Node astNode, VirtualFrame frame, Object result) { + } + + public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + } + + } + +} diff -r 2f684eda1938 -r 3774b6f4319b graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNodeImpl.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNodeImpl.java Tue Apr 29 19:30:38 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,448 +0,0 @@ -/* - * 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.instrument.impl; - -import java.util.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.instrument.*; -import com.oracle.truffle.api.nodes.*; - -/** - * Abstract implementation of Truffle {@link Node} to be used for AST probes and instruments. - *

- * Coordinates propagation of Truffle AST {@link ExecutionEvents}. - */ -public abstract class InstrumentationNodeImpl extends Node implements ExecutionEvents { - - // TODO (mlvdv) This is a pretty awkward design. - - /** - * Creates a new {@link Probe}, presumed to be unique to a particular {@linkplain SourceSection} - * extent of guest language source code. - * - * @param eventListener an optional listener for certain instrumentation-related events. - * @return a new probe - */ - static Probe createProbe(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) { - return new ProbeImpl(instrumentation, sourceSection, eventListener); - } - - /** - * Next in chain. - */ - @Child protected InstrumentationNodeImpl next; - - protected InstrumentationNodeImpl() { - } - - /** - * @return the instance of {@link Probe} to which this instrument is attached. - */ - public Probe getProbe() { - final InstrumentationNodeImpl parent = (InstrumentationNodeImpl) getParent(); - return parent == null ? null : parent.getProbe(); - } - - /** - * Add a probe to the end of this probe chain. - */ - void internalAddInstrument(InstrumentationNodeImpl newInstrument) { - if (next == null) { - this.next = insert(newInstrument); - } else { - next.internalAddInstrument(newInstrument); - } - } - - void internalRemoveInstrument(InstrumentationNodeImpl oldInstrument) { - if (next == null) { - throw new RuntimeException("Couldn't find probe to remove: " + oldInstrument); - } else if (next == oldInstrument) { - if (oldInstrument.next == null) { - this.next = null; - } else { - this.next = insert(oldInstrument.next); - oldInstrument.next = null; - } - } else { - next.internalRemoveInstrument(oldInstrument); - } - } - - /** - * Reports to the instance of {@link Probe} holding this instrument that some essential state - * has changed that requires deoptimization. - */ - @CompilerDirectives.SlowPath - protected void notifyProbeChanged(InstrumentationNodeImpl instrument) { - final ProbeImpl probe = (ProbeImpl) getProbe(); - probe.notifyProbeChanged(instrument); - } - - private void internalEnter(Node astNode, VirtualFrame frame) { - enter(astNode, frame); - if (next != null) { - next.internalEnter(astNode, frame); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame) { - leave(astNode, frame); - if (next != null) { - next.internalLeave(astNode, frame); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, boolean result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, byte result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, short result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, int result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, long result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, char result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, float result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, double result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeave(Node astNode, VirtualFrame frame, Object result) { - leave(astNode, frame, result); - if (next != null) { - next.internalLeave(astNode, frame, result); - } - } - - private void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - leaveExceptional(astNode, frame, null); - if (next != null) { - next.internalLeaveExceptional(astNode, frame, e); - } - } - - /** - * Holder of a chain of {@linkplain InstrumentationNodeImpl instruments}: manages the - * {@link Assumption} that none of the instruments have changed since last checked. - *

- * An instance is intended to be shared by every clone of the AST node with which it is - * originally attached, so it holds no parent pointer. - *

- * May be categorized by one or more {@linkplain PhylumTag tags}, signifying information useful - * for instrumentation about its AST location(s). - */ - private static final class ProbeImpl extends InstrumentationNodeImpl implements Probe { - - final InstrumentationImpl instrumentation; - - final InstrumentEventListener eventListener; - - @CompilerDirectives.CompilationFinal private Assumption probeUnchanged; - - /** - * When in stepping mode, ordinary line breakpoints are ignored, but every entry at a line - * will cause a halt. - */ - @CompilerDirectives.CompilationFinal private boolean stepping; - - /** - * Source information about the AST node to which this instrumentation is attached. - */ - private final SourceSection probedSourceSection; - - private final Set tags = EnumSet.noneOf(PhylumTag.class); - - private ProbeImpl(InstrumentationImpl instrumentation, SourceSection sourceSection, InstrumentEventListener eventListener) { - this.instrumentation = instrumentation; - this.probedSourceSection = sourceSection; - this.eventListener = eventListener == null ? NullInstrumentEventListener.INSTANCE : eventListener; - this.probeUnchanged = Truffle.getRuntime().createAssumption(); - this.next = null; - } - - @Override - public Probe getProbe() { - return this; - } - - @Override - protected void notifyProbeChanged(InstrumentationNodeImpl instrument) { - probeUnchanged.invalidate(); - probeUnchanged = Truffle.getRuntime().createAssumption(); - } - - public SourceSection getSourceLocation() { - return probedSourceSection; - } - - public void tagAs(PhylumTag tag) { - assert tag != null; - if (!tags.contains(tag)) { - tags.add(tag); - instrumentation.newTagAdded(this, tag); - } - } - - public boolean isTaggedAs(PhylumTag tag) { - assert tag != null; - return tags.contains(tag); - } - - public Set getPhylumTags() { - return tags; - } - - public void setStepping(boolean stepping) { - if (this.stepping != stepping) { - this.stepping = stepping; - probeUnchanged.invalidate(); - probeUnchanged = Truffle.getRuntime().createAssumption(); - } - } - - public boolean isStepping() { - return stepping; - } - - @CompilerDirectives.SlowPath - public void addInstrument(Instrument instrument) { - probeUnchanged.invalidate(); - final InstrumentationNodeImpl instrumentImpl = (InstrumentationNodeImpl) instrument; - super.internalAddInstrument(instrumentImpl); - probeUnchanged = Truffle.getRuntime().createAssumption(); - } - - @CompilerDirectives.SlowPath - public void removeInstrument(Instrument instrument) { - probeUnchanged.invalidate(); - final InstrumentationNodeImpl instrumentImpl = (InstrumentationNodeImpl) instrument; - super.internalRemoveInstrument(instrumentImpl); - probeUnchanged = Truffle.getRuntime().createAssumption(); - } - - public void notifyEnter(Node astNode, VirtualFrame frame) { - if (stepping || next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - if (stepping) { - eventListener.haltedAt(astNode, frame.materialize()); - } - if (next != null) { - next.internalEnter(astNode, frame); - } - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, boolean result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, byte result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, short result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, int result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, long result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, char result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, float result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, double result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeave(Node astNode, VirtualFrame frame, Object result) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeave(astNode, frame, result); - } - } - - public void notifyLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - if (next != null) { - if (!probeUnchanged.isValid()) { - CompilerDirectives.transferToInterpreter(); - } - next.internalLeaveExceptional(astNode, frame, e); - } - } - - public void enter(Node astNode, VirtualFrame frame) { - } - - public void leave(Node astNode, VirtualFrame frame) { - } - - public void leave(Node astNode, VirtualFrame frame, boolean result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, byte result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, short result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, int result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, long result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, char result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, float result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, double result) { - leave(astNode, frame, (Object) result); - } - - public void leave(Node astNode, VirtualFrame frame, Object result) { - } - - public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { - } - - } - -}