Mercurial > hg > graal-compiler
view 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 source
/* * 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); } } } }