Mercurial > hg > graal-compiler
diff graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java @ 13455:69d2e4baa215
Truffle: new infrastructure related to instrumentation, and in particular debugging: support for managing Source objects; framework for generalized "instrumentation proxy nodes" (to be inserted into ASTs with no runtime cost when inactive), and "probes" (which can be attached to proxy nodes to receive event notification); a rudimentary interface and abstract implementation for a "debug manager" (mostly a placeholder at this point); and the beginning of a language-agnostic ExecutionContext interface.
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Tue, 17 Dec 2013 20:22:45 -0800 |
parents | |
children | b88852aea6f3 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/instrument/InstrumentationProbeNode.java Tue Dec 17 20:22:45 2013 -0800 @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2013, 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.nodes.instrument; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * A <strong>probe</strong>: a Truffle instrumentation node that holds code to perform some action + * when notified (via a {@linkplain InstrumentationProxyNode proxy node} in the AST) of a + * {@linkplain InstrumentationProbeEvents probe event} taking place at the AST node. + * <p> + * Probes are only active when attached to a {@linkplain ProbeChain "probe chain"} that is referred + * to by one or more {@linkplain InstrumentationProxyNode proxy nodes} in an AST. + */ +public abstract class InstrumentationProbeNode extends Node implements InstrumentationNode, InstrumentationProbeEvents { + + /** + * Next in chain. + */ + @Child protected InstrumentationProbeNode next; + + protected InstrumentationProbeNode() { + } + + protected int countProbes() { + return next == null ? 0 : next.countProbes() + 1; + } + + /** + * Add a probe to the end of this probe chain. + */ + protected void internalAppendProbe(InstrumentationProbeNode newProbeNode) { + if (next == null) { + this.next = adoptChild(newProbeNode); + } else { + next.internalAppendProbe(newProbeNode); + } + } + + protected void internalRemoveProbe(InstrumentationProbeNode oldProbeNode) { + if (next == null) { + throw new RuntimeException("Couldn't find probe to remove: " + oldProbeNode); + } else if (next == oldProbeNode) { + if (oldProbeNode.next == null) { + this.next = null; + } else { + this.next = adoptChild(oldProbeNode.next); + } + } else { + next.internalRemoveProbe(oldProbeNode); + } + } + + /** + * Passes up the chain notification that a probe has changed its execution state in a way that + * invalidates fast path code. Assumes that there is an instance of {@link ProbeChain} at the + * head of the chain. + */ + @CompilerDirectives.SlowPath + protected void notifyProbeChanged(InstrumentationProbeNode probeNode) { + final InstrumentationProbeNode parent = (InstrumentationProbeNode) getParent(); + parent.notifyProbeChanged(probeNode); + } + + // TODO (mlvdv) making the internal*() methods public is a workaround for a bug/limitation in + // the Truffle compiler; they are intended to be private. + + public void internalEnter(Node astNode, VirtualFrame frame) { + enter(astNode, frame); + if (next != null) { + next.internalEnter(astNode, frame); + } + } + + public void internalLeave(Node astNode, VirtualFrame frame) { + leave(astNode, frame); + if (next != null) { + next.internalLeave(astNode, frame); + } + } + + public void internalLeave(Node astNode, VirtualFrame frame, boolean result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + public void internalLeave(Node astNode, VirtualFrame frame, byte result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + public void internalLeave(Node astNode, VirtualFrame frame, short result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + public void internalLeave(Node astNode, VirtualFrame frame, int result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + public void internalLeave(Node astNode, VirtualFrame frame, long result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + public void internalLeave(Node astNode, VirtualFrame frame, char result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + public void internalLeave(Node astNode, VirtualFrame frame, float result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + public void internalLeave(Node astNode, VirtualFrame frame, double result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + public void internalLeave(Node astNode, VirtualFrame frame, Object result) { + leave(astNode, frame, result); + if (next != null) { + next.internalLeave(astNode, frame, result); + } + } + + public void internalLeaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + leaveExceptional(astNode, frame, null); + if (next != null) { + next.internalLeaveExceptional(astNode, frame, e); + } + } + + public void internalReplace(Node oldAstNode, Node newAstNode, String reason) { + replace(oldAstNode, newAstNode, reason); + if (next != null) { + next.internalReplace(oldAstNode, newAstNode, reason); + } + } + + /** + * A probe implementation that implements all of {@link InstrumentationProbeEvents} with empty + * methods; concrete subclasses can override only the methods for which something is to be done. + */ + public static class DefaultProbeNode extends InstrumentationProbeNode { + + public void enter(Node astNode, VirtualFrame frame) { + } + + public void leave(Node astNode, VirtualFrame frame) { + } + + public void leave(Node astNode, VirtualFrame frame, boolean result) { + } + + public void leave(Node astNode, VirtualFrame frame, byte result) { + } + + public void leave(Node astNode, VirtualFrame frame, short result) { + } + + public void leave(Node astNode, VirtualFrame frame, int result) { + } + + public void leave(Node astNode, VirtualFrame frame, long result) { + } + + public void leave(Node astNode, VirtualFrame frame, char result) { + } + + public void leave(Node astNode, VirtualFrame frame, float result) { + } + + public void leave(Node astNode, VirtualFrame frame, double result) { + } + + public void leave(Node astNode, VirtualFrame frame, Object result) { + } + + public void leaveExceptional(Node astNode, VirtualFrame frame, Exception e) { + } + + public void replace(Node oldAstNode, Node newAstNode, String reason) { + } + + } + + /** + * Holder of a chain of {@linkplain InstrumentationProbeNode probes}: manages the + * {@link Assumption} that the chain has not changed since checked checked. + */ + public static final class ProbeChain extends DefaultProbeNode { + + @CompilerDirectives.CompilationFinal private Assumption probeUnchanged; + + /** + * Source information about the node to which this probe chain is attached; it isn't + * otherwise available. A probe chain is shared by every copy made during runtime, so there + * is no parent pointer. + */ + @SuppressWarnings("unused") private final SourceSection sourceSection; + + private final String description; // for debugging + + /** + * Creates a new, empty chain of {@linkplain InstrumentationProbeNode probes}, to which + * probes can be added/removed, and all of which will be notified of + * {@linkplain InstrumentationProbeEvents events} when the chain is notified. + */ + public ProbeChain(SourceSection sourceSection, String description) { + this.probeUnchanged = Truffle.getRuntime().createAssumption(); + this.sourceSection = sourceSection; + this.description = description; + this.next = null; + } + + public int probeCount() { + return countProbes(); + } + + public String getDescription() { + return description; + } + + @Override + protected int countProbes() { + // The head of the chain does not itself hold a probe + return next == null ? 0 : next.countProbes(); + } + + @Override + protected void notifyProbeChanged(InstrumentationProbeNode probeNode) { + probeUnchanged.invalidate(); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + + @CompilerDirectives.SlowPath + public void appendProbe(InstrumentationProbeNode newProbeNode) { + probeUnchanged.invalidate(); + super.internalAppendProbe(newProbeNode); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + + @CompilerDirectives.SlowPath + public void removeProbe(InstrumentationProbeNode oldProbeNode) { + probeUnchanged.invalidate(); + super.internalRemoveProbe(oldProbeNode); + probeUnchanged = Truffle.getRuntime().createAssumption(); + } + + public void notifyEnter(Node astNode, VirtualFrame frame) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + 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 notifyReplace(Node oldAstNode, Node newAstNode, String reason) { + if (next != null) { + if (!probeUnchanged.isValid()) { + CompilerDirectives.transferToInterpreter(); + } + next.internalReplace(oldAstNode, newAstNode, reason); + } + } + + } + +}