mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
It was attempting to load InjectedScript, etc. with the wrong path and hitting a CHECK(). I moved InjectedScript and DebugScript into the v8_inspector directory and fixed their loading. I also broke the dependency from v8_inspector onto engine/platform by moving the horrible Platform::loadResource hack out of PlatformImpl into a new file just for v8_inspector. In this process I also found some (broken!) code for showing the broken image icon which if we ever hit would just have crashed, so I removed that code as well. BUG=435243 R=ojan@chromium.org Review URL: https://codereview.chromium.org/776743002
566 lines
18 KiB
JavaScript
566 lines
18 KiB
JavaScript
/*
|
|
* Copyright (C) 2010 Google 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:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * 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.
|
|
* * Neither the name of Google Inc. nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* 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
|
|
* OWNER 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.
|
|
*/
|
|
|
|
(function () {
|
|
|
|
var DebuggerScript = {};
|
|
|
|
DebuggerScript.PauseOnExceptionsState = {
|
|
DontPauseOnExceptions: 0,
|
|
PauseOnAllExceptions: 1,
|
|
PauseOnUncaughtExceptions: 2
|
|
};
|
|
|
|
DebuggerScript.ScopeInfoDetails = {
|
|
AllScopes: 0,
|
|
FastAsyncScopes: 1,
|
|
NoScopes: 2
|
|
};
|
|
|
|
DebuggerScript._pauseOnExceptionsState = DebuggerScript.PauseOnExceptionsState.DontPauseOnExceptions;
|
|
Debug.clearBreakOnException();
|
|
Debug.clearBreakOnUncaughtException();
|
|
|
|
DebuggerScript.getAfterCompileScript = function(eventData)
|
|
{
|
|
return DebuggerScript._formatScript(eventData.script_.script_);
|
|
}
|
|
|
|
DebuggerScript.getWorkerScripts = function()
|
|
{
|
|
var result = [];
|
|
var scripts = Debug.scripts();
|
|
for (var i = 0; i < scripts.length; ++i) {
|
|
var script = scripts[i];
|
|
// Workers don't share same V8 heap now so there is no need to complicate stuff with
|
|
// the context id like we do to discriminate between scripts from different pages.
|
|
// However we need to filter out v8 native scripts.
|
|
if (script.context_data && script.context_data === "worker")
|
|
result.push(DebuggerScript._formatScript(script));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DebuggerScript.getFunctionScopes = function(fun)
|
|
{
|
|
var mirror = MakeMirror(fun);
|
|
var count = mirror.scopeCount();
|
|
if (count == 0)
|
|
return null;
|
|
var result = [];
|
|
for (var i = 0; i < count; i++) {
|
|
var scopeDetails = mirror.scope(i).details();
|
|
var scopeObject = DebuggerScript._buildScopeObject(scopeDetails.type(), scopeDetails.object());
|
|
if (!scopeObject)
|
|
continue;
|
|
result.push({
|
|
type: scopeDetails.type(),
|
|
object: scopeObject
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DebuggerScript.getCollectionEntries = function(object)
|
|
{
|
|
var mirror = MakeMirror(object, true /* transient */);
|
|
if (mirror.isMap())
|
|
return mirror.entries();
|
|
if (mirror.isSet()) {
|
|
var result = [];
|
|
var values = mirror.values();
|
|
for (var i = 0; i < values.length; ++i)
|
|
result.push({ value: values[i] });
|
|
return result;
|
|
}
|
|
}
|
|
|
|
DebuggerScript.getInternalProperties = function(value)
|
|
{
|
|
var properties = ObjectMirror.GetInternalProperties(value);
|
|
var result = [];
|
|
for (var i = 0; i < properties.length; i++) {
|
|
var mirror = properties[i];
|
|
result.push({
|
|
name: mirror.name(),
|
|
value: mirror.value().value()
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DebuggerScript.setFunctionVariableValue = function(functionValue, scopeIndex, variableName, newValue)
|
|
{
|
|
var mirror = MakeMirror(functionValue);
|
|
if (!mirror.isFunction())
|
|
throw new Error("Function value has incorrect type");
|
|
return DebuggerScript._setScopeVariableValue(mirror, scopeIndex, variableName, newValue);
|
|
}
|
|
|
|
DebuggerScript._setScopeVariableValue = function(scopeHolder, scopeIndex, variableName, newValue)
|
|
{
|
|
var scopeMirror = scopeHolder.scope(scopeIndex);
|
|
if (!scopeMirror)
|
|
throw new Error("Incorrect scope index");
|
|
scopeMirror.setVariableValue(variableName, newValue);
|
|
return undefined;
|
|
}
|
|
|
|
DebuggerScript.getScripts = function(contextData)
|
|
{
|
|
var result = [];
|
|
|
|
if (!contextData)
|
|
return result;
|
|
var comma = contextData.indexOf(",");
|
|
if (comma === -1)
|
|
return result;
|
|
// Context data is a string in the following format:
|
|
// ("page"|"injected")","<page id>
|
|
var idSuffix = contextData.substring(comma); // including the comma
|
|
|
|
var scripts = Debug.scripts();
|
|
for (var i = 0; i < scripts.length; ++i) {
|
|
var script = scripts[i];
|
|
if (script.context_data && script.context_data.lastIndexOf(idSuffix) != -1)
|
|
result.push(DebuggerScript._formatScript(script));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DebuggerScript._formatScript = function(script)
|
|
{
|
|
var lineEnds = script.line_ends;
|
|
var lineCount = lineEnds.length;
|
|
var endLine = script.line_offset + lineCount - 1;
|
|
var endColumn;
|
|
// V8 will not count last line if script source ends with \n.
|
|
if (script.source[script.source.length - 1] === '\n') {
|
|
endLine += 1;
|
|
endColumn = 0;
|
|
} else {
|
|
if (lineCount === 1)
|
|
endColumn = script.source.length + script.column_offset;
|
|
else
|
|
endColumn = script.source.length - (lineEnds[lineCount - 2] + 1);
|
|
}
|
|
|
|
return {
|
|
id: script.id,
|
|
name: script.nameOrSourceURL(),
|
|
sourceURL: script.source_url,
|
|
sourceMappingURL: script.source_mapping_url,
|
|
source: script.source,
|
|
startLine: script.line_offset,
|
|
startColumn: script.column_offset,
|
|
endLine: endLine,
|
|
endColumn: endColumn,
|
|
isContentScript: !!script.context_data && script.context_data.indexOf("injected") == 0
|
|
};
|
|
}
|
|
|
|
DebuggerScript.setBreakpoint = function(execState, info)
|
|
{
|
|
var positionAlignment = info.interstatementLocation ? Debug.BreakPositionAlignment.BreakPosition : Debug.BreakPositionAlignment.Statement;
|
|
var breakId = Debug.setScriptBreakPointById(info.sourceID, info.lineNumber, info.columnNumber, info.condition, undefined, positionAlignment);
|
|
|
|
var locations = Debug.findBreakPointActualLocations(breakId);
|
|
if (!locations.length)
|
|
return undefined;
|
|
info.lineNumber = locations[0].line;
|
|
info.columnNumber = locations[0].column;
|
|
return breakId.toString();
|
|
}
|
|
|
|
DebuggerScript.removeBreakpoint = function(execState, info)
|
|
{
|
|
Debug.findBreakPoint(info.breakpointId, true);
|
|
}
|
|
|
|
DebuggerScript.pauseOnExceptionsState = function()
|
|
{
|
|
return DebuggerScript._pauseOnExceptionsState;
|
|
}
|
|
|
|
DebuggerScript.setPauseOnExceptionsState = function(newState)
|
|
{
|
|
DebuggerScript._pauseOnExceptionsState = newState;
|
|
|
|
if (DebuggerScript.PauseOnExceptionsState.PauseOnAllExceptions === newState)
|
|
Debug.setBreakOnException();
|
|
else
|
|
Debug.clearBreakOnException();
|
|
|
|
if (DebuggerScript.PauseOnExceptionsState.PauseOnUncaughtExceptions === newState)
|
|
Debug.setBreakOnUncaughtException();
|
|
else
|
|
Debug.clearBreakOnUncaughtException();
|
|
}
|
|
|
|
DebuggerScript.frameCount = function(execState)
|
|
{
|
|
return execState.frameCount();
|
|
}
|
|
|
|
DebuggerScript.currentCallFrame = function(execState, data)
|
|
{
|
|
var maximumLimit = data >> 2;
|
|
var scopeDetailsLevel = data & 3;
|
|
|
|
var frameCount = execState.frameCount();
|
|
if (maximumLimit && maximumLimit < frameCount)
|
|
frameCount = maximumLimit;
|
|
var topFrame = undefined;
|
|
for (var i = frameCount - 1; i >= 0; i--) {
|
|
var frameMirror = execState.frame(i);
|
|
topFrame = DebuggerScript._frameMirrorToJSCallFrame(frameMirror, topFrame, scopeDetailsLevel);
|
|
}
|
|
return topFrame;
|
|
}
|
|
|
|
DebuggerScript.currentCallFrameByIndex = function(execState, index)
|
|
{
|
|
if (index < 0)
|
|
return undefined;
|
|
var frameCount = execState.frameCount();
|
|
if (index >= frameCount)
|
|
return undefined;
|
|
return DebuggerScript._frameMirrorToJSCallFrame(execState.frame(index), undefined, DebuggerScript.ScopeInfoDetails.NoScopes);
|
|
}
|
|
|
|
DebuggerScript.stepIntoStatement = function(execState)
|
|
{
|
|
execState.prepareStep(Debug.StepAction.StepIn, 1);
|
|
}
|
|
|
|
DebuggerScript.stepOverStatement = function(execState, callFrame)
|
|
{
|
|
execState.prepareStep(Debug.StepAction.StepNext, 1);
|
|
}
|
|
|
|
DebuggerScript.stepOutOfFunction = function(execState, callFrame)
|
|
{
|
|
execState.prepareStep(Debug.StepAction.StepOut, 1);
|
|
}
|
|
|
|
// Returns array in form:
|
|
// [ 0, <v8_result_report> ] in case of success
|
|
// or [ 1, <general_error_message>, <compiler_message>, <line_number>, <column_number> ] in case of compile error, numbers are 1-based.
|
|
// or throws exception with message.
|
|
DebuggerScript.liveEditScriptSource = function(scriptId, newSource, preview)
|
|
{
|
|
var scripts = Debug.scripts();
|
|
var scriptToEdit = null;
|
|
for (var i = 0; i < scripts.length; i++) {
|
|
if (scripts[i].id == scriptId) {
|
|
scriptToEdit = scripts[i];
|
|
break;
|
|
}
|
|
}
|
|
if (!scriptToEdit)
|
|
throw("Script not found");
|
|
|
|
var changeLog = [];
|
|
try {
|
|
var result = Debug.LiveEdit.SetScriptSource(scriptToEdit, newSource, preview, changeLog);
|
|
return [0, result];
|
|
} catch (e) {
|
|
if (e instanceof Debug.LiveEdit.Failure && "details" in e) {
|
|
var details = e.details;
|
|
if (details.type === "liveedit_compile_error") {
|
|
var startPosition = details.position.start;
|
|
return [1, String(e), String(details.syntaxErrorMessage), Number(startPosition.line), Number(startPosition.column)];
|
|
}
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
DebuggerScript.clearBreakpoints = function(execState, info)
|
|
{
|
|
Debug.clearAllBreakPoints();
|
|
}
|
|
|
|
DebuggerScript.setBreakpointsActivated = function(execState, info)
|
|
{
|
|
Debug.debuggerFlags().breakPointsActive.setValue(info.enabled);
|
|
}
|
|
|
|
DebuggerScript.getScriptSource = function(eventData)
|
|
{
|
|
return eventData.script().source();
|
|
}
|
|
|
|
DebuggerScript.setScriptSource = function(eventData, source)
|
|
{
|
|
if (eventData.script().data() === "injected-script")
|
|
return;
|
|
eventData.script().setSource(source);
|
|
}
|
|
|
|
DebuggerScript.getScriptName = function(eventData)
|
|
{
|
|
return eventData.script().script_.nameOrSourceURL();
|
|
}
|
|
|
|
DebuggerScript.getBreakpointNumbers = function(eventData)
|
|
{
|
|
var breakpoints = eventData.breakPointsHit();
|
|
var numbers = [];
|
|
if (!breakpoints)
|
|
return numbers;
|
|
|
|
for (var i = 0; i < breakpoints.length; i++) {
|
|
var breakpoint = breakpoints[i];
|
|
var scriptBreakPoint = breakpoint.script_break_point();
|
|
numbers.push(scriptBreakPoint ? scriptBreakPoint.number() : breakpoint.number());
|
|
}
|
|
return numbers;
|
|
}
|
|
|
|
DebuggerScript.isEvalCompilation = function(eventData)
|
|
{
|
|
var script = eventData.script();
|
|
return (script.compilationType() === Debug.ScriptCompilationType.Eval);
|
|
}
|
|
|
|
// NOTE: This function is performance critical, as it can be run on every
|
|
// statement that generates an async event (like addEventListener) to support
|
|
// asynchronous call stacks. Thus, when possible, initialize the data lazily.
|
|
DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame, scopeDetailsLevel)
|
|
{
|
|
// Stuff that can not be initialized lazily (i.e. valid while paused with a valid break_id).
|
|
// The frameMirror and scopeMirror can be accessed only while paused on the debugger.
|
|
var frameDetails = frameMirror.details();
|
|
|
|
var funcObject = frameDetails.func();
|
|
var sourcePosition = frameDetails.sourcePosition();
|
|
var thisObject = frameDetails.receiver();
|
|
|
|
var isAtReturn = !!frameDetails.isAtReturn();
|
|
var returnValue = isAtReturn ? frameDetails.returnValue() : undefined;
|
|
|
|
var scopeMirrors = (scopeDetailsLevel === DebuggerScript.ScopeInfoDetails.NoScopes ? [] : frameMirror.allScopes(scopeDetailsLevel === DebuggerScript.ScopeInfoDetails.FastAsyncScopes));
|
|
var scopeTypes = new Array(scopeMirrors.length);
|
|
var scopeObjects = new Array(scopeMirrors.length);
|
|
for (var i = 0; i < scopeMirrors.length; ++i) {
|
|
var scopeDetails = scopeMirrors[i].details();
|
|
scopeTypes[i] = scopeDetails.type();
|
|
scopeObjects[i] = scopeDetails.object();
|
|
}
|
|
|
|
// Calculated lazily.
|
|
var scopeChain;
|
|
var funcMirror;
|
|
var location;
|
|
|
|
function lazyScopeChain()
|
|
{
|
|
if (!scopeChain) {
|
|
scopeChain = [];
|
|
for (var i = 0, j = 0; i < scopeObjects.length; ++i) {
|
|
var scopeObject = DebuggerScript._buildScopeObject(scopeTypes[i], scopeObjects[i]);
|
|
if (scopeObject) {
|
|
scopeTypes[j] = scopeTypes[i];
|
|
scopeChain[j] = scopeObject;
|
|
++j;
|
|
}
|
|
}
|
|
scopeTypes.length = scopeChain.length;
|
|
scopeObjects = null; // Free for GC.
|
|
}
|
|
return scopeChain;
|
|
}
|
|
|
|
function lazyScopeTypes()
|
|
{
|
|
if (!scopeChain)
|
|
lazyScopeChain();
|
|
return scopeTypes;
|
|
}
|
|
|
|
function ensureFuncMirror()
|
|
{
|
|
if (!funcMirror) {
|
|
funcMirror = MakeMirror(funcObject);
|
|
if (!funcMirror.isFunction())
|
|
funcMirror = new UnresolvedFunctionMirror(funcObject);
|
|
}
|
|
return funcMirror;
|
|
}
|
|
|
|
function ensureLocation()
|
|
{
|
|
if (!location) {
|
|
var script = ensureFuncMirror().script();
|
|
if (script)
|
|
location = script.locationFromPosition(sourcePosition, true);
|
|
if (!location)
|
|
location = { line: 0, column: 0 };
|
|
}
|
|
return location;
|
|
}
|
|
|
|
function line()
|
|
{
|
|
return ensureLocation().line;
|
|
}
|
|
|
|
function column()
|
|
{
|
|
return ensureLocation().column;
|
|
}
|
|
|
|
function sourceID()
|
|
{
|
|
var script = ensureFuncMirror().script();
|
|
return script && script.id();
|
|
}
|
|
|
|
function scriptName()
|
|
{
|
|
var script = ensureFuncMirror().script();
|
|
return script && script.name();
|
|
}
|
|
|
|
function functionName()
|
|
{
|
|
var func = ensureFuncMirror();
|
|
if (!func.resolved())
|
|
return undefined;
|
|
var displayName;
|
|
var valueMirror = func.property("displayName").value();
|
|
if (valueMirror && valueMirror.isString())
|
|
displayName = valueMirror.value();
|
|
return displayName || func.name() || func.inferredName();
|
|
}
|
|
|
|
function evaluate(expression)
|
|
{
|
|
return frameMirror.evaluate(expression, false).value();
|
|
}
|
|
|
|
function restart()
|
|
{
|
|
return Debug.LiveEdit.RestartFrame(frameMirror);
|
|
}
|
|
|
|
function setVariableValue(scopeNumber, variableName, newValue)
|
|
{
|
|
return DebuggerScript._setScopeVariableValue(frameMirror, scopeNumber, variableName, newValue);
|
|
}
|
|
|
|
function stepInPositions()
|
|
{
|
|
var stepInPositionsV8 = frameMirror.stepInPositions();
|
|
var stepInPositionsProtocol;
|
|
if (stepInPositionsV8) {
|
|
stepInPositionsProtocol = [];
|
|
var script = ensureFuncMirror().script();
|
|
if (script) {
|
|
var scriptId = String(script.id());
|
|
for (var i = 0; i < stepInPositionsV8.length; i++) {
|
|
var item = {
|
|
scriptId: scriptId,
|
|
lineNumber: stepInPositionsV8[i].position.line,
|
|
columnNumber: stepInPositionsV8[i].position.column
|
|
};
|
|
stepInPositionsProtocol.push(item);
|
|
}
|
|
}
|
|
}
|
|
return JSON.stringify(stepInPositionsProtocol);
|
|
}
|
|
|
|
return {
|
|
"sourceID": sourceID,
|
|
"line": line,
|
|
"column": column,
|
|
"scriptName": scriptName,
|
|
"functionName": functionName,
|
|
"thisObject": thisObject,
|
|
"scopeChain": lazyScopeChain,
|
|
"scopeType": lazyScopeTypes,
|
|
"evaluate": evaluate,
|
|
"caller": callerFrame,
|
|
"restart": restart,
|
|
"setVariableValue": setVariableValue,
|
|
"stepInPositions": stepInPositions,
|
|
"isAtReturn": isAtReturn,
|
|
"returnValue": returnValue
|
|
};
|
|
}
|
|
|
|
DebuggerScript._buildScopeObject = function(scopeType, scopeObject)
|
|
{
|
|
var result;
|
|
switch (scopeType) {
|
|
case ScopeType.Local:
|
|
case ScopeType.Closure:
|
|
case ScopeType.Catch:
|
|
// For transient objects we create a "persistent" copy that contains
|
|
// the same properties.
|
|
// Reset scope object prototype to null so that the proto properties
|
|
// don't appear in the local scope section.
|
|
result = { __proto__: null };
|
|
var properties = MakeMirror(scopeObject, true /* transient */).properties();
|
|
for (var j = 0; j < properties.length; j++) {
|
|
var name = properties[j].name();
|
|
if (name.charAt(0) === ".")
|
|
continue; // Skip internal variables like ".arguments"
|
|
result[name] = properties[j].value_;
|
|
}
|
|
break;
|
|
case ScopeType.Global:
|
|
case ScopeType.With:
|
|
result = scopeObject;
|
|
break;
|
|
case ScopeType.Block:
|
|
// Unsupported yet. Mustn't be reachable.
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DebuggerScript.getPromiseDetails = function(eventData)
|
|
{
|
|
return {
|
|
"promise": eventData.promise().value(),
|
|
"parentPromise": eventData.parentPromise().value(),
|
|
"status": eventData.status()
|
|
};
|
|
}
|
|
|
|
// We never resolve Mirror by its handle so to avoid memory leaks caused by Mirrors in the cache we disable it.
|
|
ToggleMirrorCache(false);
|
|
|
|
return DebuggerScript;
|
|
})();
|