diff graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java @ 15605:bb9473723904

Truffle/Instrumentation: - Merge instrumentation support into the general execution context; remove separate Instrumentation interface and implementation - Generalize the ?tagging? mechanism for extensibility: the enum PhylumTag is now an interface, and the standard tags moved to the new enum StandardTag - A new ?trap? mechanism interrupts program execution at any probed node holding a specified PhylumTag; this replaces some other special-purpose code. - Refine several interface by factoring out callback methods and simplifying collaboration among key implementation classes.
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Mon, 12 May 2014 20:17:25 -0700
parents be0c151d912b
children
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java	Fri May 02 16:12:07 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/AbstractExecutionContext.java	Mon May 12 20:17:25 2014 -0700
@@ -24,41 +24,175 @@
  */
 package com.oracle.truffle.api.impl;
 
+import java.util.*;
+
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.instrument.impl.*;
+import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeCallback;
+import com.oracle.truffle.api.instrument.impl.InstrumentationNode.ProbeImpl;
 import com.oracle.truffle.api.source.*;
 
 public abstract class AbstractExecutionContext implements ExecutionContext {
 
+    // TODO (mlvdv) use weak references.
+    /**
+     * Map: SourceSection ==> probe associated with that source section in an AST.
+     */
+    private final Map<SourceSection, ProbeImpl> srcToProbe = new HashMap<>();
+
+    // TODO (mlvdv) use weak references.
+    /**
+     * Map: Source line ==> probes associated with source sections starting on the line.
+     */
+    private final Map<SourceLineLocation, Collection<Probe>> lineToProbes = new HashMap<>();
+
     private final SourceManager sourceManager = new SourceManager();
-    private final Instrumentation instrumentation;
+    private final List<SourceListener> sourceListeners = new ArrayList<>();
+    private final List<ProbeListener> probeListeners = new ArrayList<>();
+
+    private final SourceCallback sourceCallback = new SourceCallback() {
+
+        public void startLoading(Source source) {
+            for (SourceListener listener : sourceListeners) {
+                listener.loadStarting(source);
+            }
+        }
+
+        public void endLoading(Source source) {
+            for (SourceListener listener : sourceListeners) {
+                listener.loadEnding(source);
+            }
+        }
+    };
+
+    private final ProbeCallback probeCallback = new ProbeCallback() {
+        /**
+         * Receives (from the {@link Probe} implementation) and distributes notification that a
+         * {@link Probe} has acquired a new {@linkplain PhylumTag tag}.
+         */
+        public void newTagAdded(ProbeImpl probe, PhylumTag tag) {
+            for (ProbeListener listener : probeListeners) {
+                listener.probeTaggedAs(probe, tag);
+            }
+            if (trap != null && tag == trap.getTag()) {
+                probe.setTrap(trap);
+            }
+        }
+    };
+
     private Visualizer visualizer = new DefaultVisualizer();
-    protected ASTProber astProber = null;
+
+    /**
+     * When non-null, "enter" events with matching tags will trigger a callback.
+     */
+    private PhylumTrap trap = null;
 
     protected AbstractExecutionContext() {
-        this.instrumentation = InstrumentationFactory.create(this);
+    }
+
+    public void initialize() {
+        setSourceCallback(sourceCallback);
     }
 
     public final SourceManager getSourceManager() {
         return sourceManager;
     }
 
-    public final Instrumentation getInstrumentation() {
-        return instrumentation;
+    public void addSourceListener(SourceListener listener) {
+        assert listener != null;
+        sourceListeners.add(listener);
+    }
+
+    public void addProbeListener(ProbeListener listener) {
+        assert listener != null;
+        probeListeners.add(listener);
+    }
+
+    public Probe getProbe(SourceSection sourceSection) {
+        assert sourceSection != null;
+
+        ProbeImpl probe = srcToProbe.get(sourceSection);
+
+        if (probe != null) {
+            return probe;
+        }
+        probe = InstrumentationNode.createProbe(sourceSection, probeCallback);
+
+        // Register new probe by unique SourceSection
+        srcToProbe.put(sourceSection, probe);
+
+        // Register new probe by source line, there may be more than one
+        // Create line location for map key
+        final SourceLineLocation lineLocation = new SourceLineLocation(sourceSection.getSource(), sourceSection.getStartLine());
+
+        Collection<Probe> probes = lineToProbes.get(lineLocation);
+        if (probes == null) {
+            probes = new ArrayList<>(2);
+            lineToProbes.put(lineLocation, probes);
+        }
+        probes.add(probe);
+
+        for (ProbeListener listener : probeListeners) {
+            listener.newProbeInserted(sourceSection, probe);
+        }
+
+        return probe;
+    }
+
+    /**
+     * Returns all existing probes with specific tag, or all probes if {@code tag = null}; empty
+     * collection if no probes found.
+     */
+    public Collection<Probe> findProbesTaggedAs(PhylumTag tag) {
+        final List<Probe> probes = new ArrayList<>();
+        for (Probe probe : srcToProbe.values()) {
+            if (tag == null || probe.isTaggedAs(tag)) {
+                probes.add(probe);
+            }
+        }
+        return probes;
+    }
+
+    public Collection<Probe> findProbesByLine(SourceLineLocation lineLocation) {
+        final Collection<Probe> probes = lineToProbes.get(lineLocation);
+        if (probes == null) {
+            return Collections.emptyList();
+        }
+        return new ArrayList<>(probes);
+    }
+
+    // TODO (mlvdv) consider allowing multiple traps (without inhibiting Truffle inlining)
+    public void setTrap(PhylumTrap trap) {
+        assert trap != null;
+        if (this.trap != null) {
+            throw new IllegalStateException("trap already set");
+        }
+        this.trap = trap;
+
+        for (ProbeImpl probe : srcToProbe.values()) {
+            if (probe.isTaggedAs(trap.getTag())) {
+                probe.setTrap(trap);
+            }
+        }
+    }
+
+    public void clearTrap() {
+        if (this.trap == null) {
+            throw new IllegalStateException("no trap set");
+        }
+        for (ProbeImpl probe : srcToProbe.values()) {
+            if (probe.isTaggedAs(trap.getTag())) {
+                probe.setTrap(null);
+            }
+        }
+        trap = null;
     }
 
     public Visualizer getVisualizer() {
         return visualizer;
     }
 
-    public void addNodeProber(ASTNodeProber nodeProber) {
-        if (astProber == null) {
-            throw new IllegalStateException("No ASTProber installed in context");
-        }
-        astProber.addNodeProber(nodeProber);
-    }
-
     /**
      * Assign guest language-specific visualization support for tools. This must be assigned outside
      * the implementation context to avoid build circularities.
@@ -73,19 +207,11 @@
      * implementation context to avoid build circularities. It must also be set before any
      * instrumentation probe implementations are assigned.
      */
-    public void setASTProber(ASTProber astProber) {
-        this.astProber = astProber;
-    }
+    public abstract void setASTProber(ASTProber astProber);
 
     /**
-     * Gets a guest language-specific {@link ASTNodeProber} that will apply all that have been
-     * added; {@code null} if no instrumentation in AST.
+     * Establishes source event reporting
      */
-    public ASTNodeProber getCombinedNodeProber() {
-        return astProber == null ? null : astProber.getCombinedNodeProber();
-    }
+    protected abstract void setSourceCallback(SourceCallback sourceCallback);
 
-    public abstract void setInstrumentEventListener(InstrumentEventListener listener);
-
-    public abstract InstrumentEventListener getInstrumentEventListener();
 }