blob: d5e43d31886e7773fd986f7c6279a48b535494fb [file] [log] [blame]
/*
* Copyright (C) 2013 University of Washington. All rights reserved.
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
WebInspector.ProbeManager = class ProbeManager extends WebInspector.Object
{
constructor()
{
super();
// Used to detect deleted probe actions.
this._knownProbeIdentifiersForBreakpoint = new Map;
// Main lookup tables for probes and probe sets.
this._probesByIdentifier = new Map;
this._probeSetsByBreakpoint = new Map;
WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointAdded, this._breakpointAdded, this);
WebInspector.debuggerManager.addEventListener(WebInspector.DebuggerManager.Event.BreakpointRemoved, this._breakpointRemoved, this);
WebInspector.Breakpoint.addEventListener(WebInspector.Breakpoint.Event.ActionsDidChange, this._breakpointActionsChanged, this);
// Saved breakpoints should not be restored on the first event loop turn, because it
// makes manager initialization order very fragile. No breakpoints should be available.
console.assert(!WebInspector.debuggerManager.breakpoints.length, "No breakpoints should exist before all the managers are constructed.");
}
// Public
get probeSets()
{
return [...this._probeSetsByBreakpoint.values()];
}
probeForIdentifier(identifier)
{
return this._probesByIdentifier.get(identifier);
}
// Protected (called by WebInspector.DebuggerObserver)
didSampleProbe(sample)
{
console.assert(this._probesByIdentifier.has(sample.probeId), "Unknown probe identifier specified for sample: ", sample);
var probe = this._probesByIdentifier.get(sample.probeId);
var elapsedTime = WebInspector.timelineManager.computeElapsedTime(sample.timestamp);
probe.addSample(new WebInspector.ProbeSample(sample.sampleId, sample.batchId, elapsedTime, sample.payload));
}
// Private
_breakpointAdded(breakpointOrEvent)
{
var breakpoint;
if (breakpointOrEvent instanceof WebInspector.Breakpoint)
breakpoint = breakpointOrEvent;
else
breakpoint = breakpointOrEvent.data.breakpoint;
console.assert(breakpoint instanceof WebInspector.Breakpoint, "Unknown object passed as breakpoint: ", breakpoint);
if (this._knownProbeIdentifiersForBreakpoint.has(breakpoint))
return;
this._knownProbeIdentifiersForBreakpoint.set(breakpoint, new Set);
this._breakpointActionsChanged(breakpoint);
}
_breakpointRemoved(event)
{
var breakpoint = event.data.breakpoint;
console.assert(this._knownProbeIdentifiersForBreakpoint.has(breakpoint));
this._breakpointActionsChanged(breakpoint);
this._knownProbeIdentifiersForBreakpoint.delete(breakpoint);
}
_breakpointActionsChanged(breakpointOrEvent)
{
var breakpoint;
if (breakpointOrEvent instanceof WebInspector.Breakpoint)
breakpoint = breakpointOrEvent;
else
breakpoint = breakpointOrEvent.target;
console.assert(breakpoint instanceof WebInspector.Breakpoint, "Unknown object passed as breakpoint: ", breakpoint);
// Sometimes actions change before the added breakpoint is fully dispatched.
if (!this._knownProbeIdentifiersForBreakpoint.has(breakpoint)) {
this._breakpointAdded(breakpoint);
return;
}
var knownProbeIdentifiers = this._knownProbeIdentifiersForBreakpoint.get(breakpoint);
var seenProbeIdentifiers = new Set;
breakpoint.probeActions.forEach(function(probeAction) {
var probeIdentifier = probeAction.id;
console.assert(probeIdentifier, "Probe added without breakpoint action identifier: ", breakpoint);
seenProbeIdentifiers.add(probeIdentifier);
if (!knownProbeIdentifiers.has(probeIdentifier)) {
// New probe; find or create relevant probe set.
knownProbeIdentifiers.add(probeIdentifier);
var probeSet = this._probeSetForBreakpoint(breakpoint);
var newProbe = new WebInspector.Probe(probeIdentifier, breakpoint, probeAction.data);
this._probesByIdentifier.set(probeIdentifier, newProbe);
probeSet.addProbe(newProbe);
return;
}
var probe = this._probesByIdentifier.get(probeIdentifier);
console.assert(probe, "Probe known but couldn't be found by identifier: ", probeIdentifier);
// Update probe expression; if it differed, change events will fire.
probe.expression = probeAction.data;
}, this);
// Look for missing probes based on what we saw last.
knownProbeIdentifiers.forEach(function(probeIdentifier) {
if (seenProbeIdentifiers.has(probeIdentifier))
return;
// The probe has gone missing, remove it.
var probeSet = this._probeSetForBreakpoint(breakpoint);
var probe = this._probesByIdentifier.get(probeIdentifier);
this._probesByIdentifier.delete(probeIdentifier);
knownProbeIdentifiers.delete(probeIdentifier);
probeSet.removeProbe(probe);
// Remove the probe set if it has become empty.
if (!probeSet.probes.length) {
this._probeSetsByBreakpoint.delete(probeSet.breakpoint);
probeSet.willRemove();
this.dispatchEventToListeners(WebInspector.ProbeManager.Event.ProbeSetRemoved, {probeSet});
}
}, this);
}
_probeSetForBreakpoint(breakpoint)
{
if (this._probeSetsByBreakpoint.has(breakpoint))
return this._probeSetsByBreakpoint.get(breakpoint);
var newProbeSet = new WebInspector.ProbeSet(breakpoint);
this._probeSetsByBreakpoint.set(breakpoint, newProbeSet);
this.dispatchEventToListeners(WebInspector.ProbeManager.Event.ProbeSetAdded, {probeSet: newProbeSet});
return newProbeSet;
}
};
WebInspector.ProbeManager.Event = {
ProbeSetAdded: "probe-manager-probe-set-added",
ProbeSetRemoved: "probe-manager-probe-set-removed",
};