RetroZilla/extensions/venkman/resources/content/venkman-debugger.js

2046 lines
55 KiB
JavaScript
Raw Normal View History

2015-10-21 05:03:22 +02:00
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is The JavaScript Debugger.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Robert Ginda, <rginda@netscape.com>, original author
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const JSD_CTRID = "@mozilla.org/js/jsd/debugger-service;1";
const jsdIDebuggerService = Components.interfaces.jsdIDebuggerService;
const jsdIExecutionHook = Components.interfaces.jsdIExecutionHook;
const jsdIErrorHook = Components.interfaces.jsdIErrorHook;
const jsdICallHook = Components.interfaces.jsdICallHook;
const jsdIValue = Components.interfaces.jsdIValue;
const jsdIProperty = Components.interfaces.jsdIProperty;
const jsdIScript = Components.interfaces.jsdIScript;
const jsdIStackFrame = Components.interfaces.jsdIStackFrame;
const TYPE_VOID = jsdIValue.TYPE_VOID;
const TYPE_NULL = jsdIValue.TYPE_NULL;
const TYPE_BOOLEAN = jsdIValue.TYPE_BOOLEAN;
const TYPE_INT = jsdIValue.TYPE_INT;
const TYPE_DOUBLE = jsdIValue.TYPE_DOUBLE;
const TYPE_STRING = jsdIValue.TYPE_STRING;
const TYPE_FUNCTION = jsdIValue.TYPE_FUNCTION;
const TYPE_OBJECT = jsdIValue.TYPE_OBJECT;
const PROP_ENUMERATE = jsdIProperty.FLAG_ENUMERATE;
const PROP_READONLY = jsdIProperty.FLAG_READONLY;
const PROP_PERMANENT = jsdIProperty.FLAG_PERMANENT;
const PROP_ALIAS = jsdIProperty.FLAG_ALIAS;
const PROP_ARGUMENT = jsdIProperty.FLAG_ARGUMENT;
const PROP_VARIABLE = jsdIProperty.FLAG_VARIABLE;
const PROP_EXCEPTION = jsdIProperty.FLAG_EXCEPTION;
const PROP_ERROR = jsdIProperty.FLAG_ERROR;
const PROP_HINTED = jsdIProperty.FLAG_HINTED;
const SCRIPT_NODEBUG = jsdIScript.FLAG_DEBUG;
const SCRIPT_NOPROFILE = jsdIScript.FLAG_PROFILE;
const COLLECT_PROFILE_DATA = jsdIDebuggerService.COLLECT_PROFILE_DATA;
const PCMAP_SOURCETEXT = jsdIScript.PCMAP_SOURCETEXT;
const PCMAP_PRETTYPRINT = jsdIScript.PCMAP_PRETTYPRINT;
const RETURN_CONTINUE = jsdIExecutionHook.RETURN_CONTINUE;
const RETURN_CONT_THROW = jsdIExecutionHook.RETURN_CONTINUE_THROW;
const RETURN_VALUE = jsdIExecutionHook.RETURN_RET_WITH_VAL;
const RETURN_THROW = jsdIExecutionHook.RETURN_THROW_WITH_VAL;
const FTYPE_STD = 0;
const FTYPE_SUMMARY = 1;
const FTYPE_ARRAY = 2;
const BREAKPOINT_STOPNEVER = 0;
const BREAKPOINT_STOPALWAYS = 1;
const BREAKPOINT_STOPTRUE = 2;
const BREAKPOINT_EARLYRETURN = 3;
var $ = new Array(); /* array to store results from evals in debug frames */
function compareVersion(maj, min)
{
if (console.jsds.implementationMajor < maj)
return -1;
if (console.jsds.implementationMajor > maj)
return 1;
if (console.jsds.implementationMinor < min)
return -1;
if (console.jsds.implementationMinor > min)
return 1;
return 0;
}
function initDebugger()
{
dd ("initDebugger {");
console.instanceSequence = 0;
console._continueCodeStack = new Array(); /* top of stack is the default */
/* return code for the most */
/* recent debugTrap(). */
console.scriptWrappers = new Object();
console.scriptManagers = new Object();
console.breaks = new Object();
console.fbreaks = new Object();
console.sbreaks = new Object();
/* create the debugger instance */
if (!(JSD_CTRID in Components.classes))
throw new BadMojo (ERR_NO_DEBUGGER);
console.jsds =
Components.classes[JSD_CTRID].getService(jsdIDebuggerService);
console.jsds.on();
if (compareVersion(1, 2) >= 0)
console.jsds.flags = jsdIDebuggerService.DISABLE_OBJECT_TRACE;
console.executionHook = { onExecute: jsdExecutionHook };
console.errorHook = { onError: jsdErrorHook };
console.callHook = { onCall: jsdCallHook };
console.jsdConsole = console.jsds.wrapValue(console);
dispatch ("tmode", {mode: console.prefs["lastThrowMode"]});
dispatch ("emode", {mode: console.prefs["lastErrorMode"]});
var enumer = { enumerateScript: console.scriptHook.onScriptCreated };
console.jsds.scriptHook = console.scriptHook;
console.jsds.enumerateScripts(enumer);
console.jsds.breakpointHook = console.executionHook;
console.jsds.debuggerHook = console.executionHook;
console.jsds.debugHook = console.executionHook;
console.jsds.errorHook = console.errorHook;
console.jsds.flags = jsdIDebuggerService.ENABLE_NATIVE_FRAMES;
dd ("} initDebugger");
}
function detachDebugger()
{
if ("frames" in console)
console.jsds.exitNestedEventLoop();
var b;
for (b in console.breaks)
console.breaks[b].clearBreakpoint();
for (b in console.fbreaks)
console.fbreaks[b].clearFutureBreakpoint();
console.jsds.topLevelHook = null;
console.jsds.functionHook = null;
console.jsds.breakpointHook = null;
console.jsds.debuggerHook = null;
console.jsds.errorHook = null;
console.jsds.scriptHook = null;
console.jsds.interruptHook = null;
console.jsds.clearAllBreakpoints();
console.jsds.GC();
if (!console.jsds.initAtStartup)
console.jsds.off();
}
console.scriptHook = new Object();
console.scriptHook.onScriptCreated =
function sh_created (jsdScript)
{
try
{
jsdScriptCreated(jsdScript);
}
catch (ex)
{
dd ("caught " + dumpObjectTree(ex) + " while creating script.");
}
}
console.scriptHook.onScriptDestroyed =
function sh_destroyed (jsdScript)
{
try
{
jsdScriptDestroyed(jsdScript);
}
catch (ex)
{
dd ("caught " + dumpObjectTree(ex) + " while destroying script.");
}
}
function jsdScriptCreated (jsdScript)
{
var url = jsdScript.fileName;
var manager;
if (!(url in console.scriptManagers))
{
manager = console.scriptManagers[url] = new ScriptManager(url);
//dispatchCommand (console.coManagerCreated, { scriptManager: manager });
}
else
{
manager = console.scriptManagers[url];
}
manager.onScriptCreated(jsdScript);
}
function jsdScriptDestroyed (jsdScript)
{
if (!(jsdScript.tag in console.scriptWrappers))
return;
var scriptWrapper = console.scriptWrappers[jsdScript.tag];
scriptWrapper.scriptManager.onScriptInvalidated(scriptWrapper);
if (scriptWrapper.scriptManager.instances.length == 0 &&
scriptWrapper.scriptManager.transientCount == 0)
{
delete console.scriptManagers[scriptWrapper.scriptManager.url];
//dispatchCommand (console.coManagerDestroyed,
// { scriptManager: scriptWrapper.scriptManager });
}
}
function jsdExecutionHook (frame, type, rv)
{
dd ("execution hook: " + formatFrame(frame));
var hookReturn = jsdIExecutionHook.RETURN_CONTINUE;
if (!console.initialized)
return hookReturn;
if (!ASSERT(!("frames" in console),
"Execution hook called while stopped") ||
frame.isNative ||
!ASSERT(frame.script, "Execution hook called with no script") ||
frame.script.fileName == MSG_VAL_CONSOLE ||
!ASSERT(!(frame.script.flags & SCRIPT_NODEBUG),
"Stopped in a script marked as don't debug") ||
!ASSERT(isURLVenkman(frame.script.fileName) ||
!isURLFiltered(frame.script.fileName),
"stopped in a filtered URL"))
{
return hookReturn;
}
var frames = new Array();
var prevFrame = frame;
var hasDisabledFrame = false;
while (prevFrame)
{
frames.push(prevFrame);
prevFrame = prevFrame.callingFrame;
}
var targetWindow = null;
var wasModal = false;
var cx;
try
{
cx = frame.executionContext;
}
catch (ex)
{
dd ("no context");
cx = null;
}
var targetWasEnabled = true;
var debuggerWasEnabled = console.baseWindow.enabled;
console.baseWindow.enabled = true;
if (!ASSERT(cx, "no cx in execution hook"))
return hookReturn;
var glob = cx.globalObject;
if (!ASSERT(glob, "no glob in execution hook"))
return hookReturn;
console.targetWindow = getBaseWindowFromWindow(glob.getWrappedValue());
targetWasEnabled = console.targetWindow.enabled;
if (console.targetWindow != console.baseWindow)
{
cx.scriptsEnabled = false;
console.targetWindow.enabled = false;
}
try
{
//dd ("debug trap " + formatFrame(frame));
hookReturn = debugTrap(frames, type, rv);
//dd ("debug trap returned " + hookReturn);
}
catch (ex)
{
display (MSG_ERR_INTERNAL_BPT, MT_ERROR);
display (formatException(ex), MT_ERROR);
}
if (console.targetWindow && console.targetWindow != console.baseWindow)
{
console.targetWindow.enabled = targetWasEnabled;
cx.scriptsEnabled = true;
}
console.baseWindow.enabled = debuggerWasEnabled;
delete console.frames;
delete console.targetWindow;
if ("__exitAfterContinue__" in console)
window.close();
return hookReturn;
}
function jsdCallHook (frame, type)
{
if (!console.initialized)
return;
if (type == jsdICallHook.TYPE_FUNCTION_CALL)
{
setStopState(false);
//dd ("Calling: " + frame.functionName);
}
else if (type == jsdICallHook.TYPE_FUNCTION_RETURN)
{
// we're called *before* the returning frame is popped from the
// stack, so we want our depth calculation to be off by one.
var depth = -1;
var prevFrame = frame;
while (prevFrame)
{
depth++;
prevFrame = prevFrame.callingFrame;
}
//dd ("Returning: " + frame.functionName +
// ", target depth: " + console._stepOverDepth +
// ", current depth: " + depth);
if (depth <= console._stepOverDepth)
{
//dd ("step over at target depth of " + depth);
setStopState(true);
console.jsds.functionHook = null;
delete console._stepOverDepth;
}
}
}
function jsdErrorHook (message, fileName, line, pos, flags, exception)
{
if (!console.initialized || isURLFiltered (fileName))
return true;
try
{
var flagstr;
flagstr =
(flags && jsdIErrorHook.REPORT_EXCEPTION) ? "x" : "-";
flagstr +=
(flags && jsdIErrorHook.REPORT_STRICT) ? "s" : "-";
//dd ("===\n" + message + "\n" + fileName + "@" +
// line + ":" + pos + "; " + flagstr);
var msn = (flags & jsdIErrorHook.REPORT_WARNING) ?
MSN_ERPT_WARN : MSN_ERPT_ERROR;
if (console.errorMode != EMODE_IGNORE)
display (getMsg(msn, [message, flagstr, fileName,
line, pos]), MT_ETRACE);
if (console.errorMode == EMODE_BREAK)
return false;
return true;
}
catch (ex)
{
dd ("error in error hook: " + ex);
}
return true;
}
function ScriptManager (url)
{
this.url = url;
this.instances = new Array();
this.transients = new Object();
this.transientCount = 0;
this.disableTransients = isURLFiltered(url);
}
ScriptManager.prototype.onScriptCreated =
function smgr_created (jsdScript)
{
var instance;
if (!ASSERT(jsdScript.isValid, "invalid script created!"))
return;
if (this.instances.length != 0)
instance = this.instances[this.instances.length - 1];
if (!instance || (instance.isSealed && jsdScript.functionName))
{
//dd ("instance created for " + jsdScript.fileName);
instance = new ScriptInstance(this);
instance.sequence = console.instanceSequence++;
this.instances.push(instance);
dispatchCommand (console.coInstanceCreated,
{ scriptInstance: instance });
}
if ("_lastScriptWrapper" in console)
{
if ((console._lastScriptWrapper.scriptManager != this ||
console._lastScriptWrapper.scriptInstance != instance) &&
console._lastScriptWrapper.scriptInstance.scriptCount &&
!console._lastScriptWrapper.scriptInstance.isSealed)
{
console._lastScriptWrapper.scriptInstance.seal();
}
}
var scriptWrapper = new ScriptWrapper(jsdScript);
console._lastScriptWrapper = scriptWrapper;
scriptWrapper.scriptManager = this;
console.scriptWrappers[jsdScript.tag] = scriptWrapper;
scriptWrapper.scriptInstance = instance;
if (!instance.isSealed)
{
//dd ("function created " + formatScript(jsdScript));
instance.onScriptCreated (scriptWrapper);
}
else
{
//dd ("transient created " + formatScript(jsdScript));
++this.transientCount;
if (this.disableTransients)
jsdScript.flags |= SCRIPT_NODEBUG | SCRIPT_NOPROFILE;
this.transients[jsdScript.tag] = scriptWrapper;
scriptWrapper.functionName = MSG_VAL_EVSCRIPT;
//dispatch ("hook-transient-script", { scriptWrapper: scriptWrapper });
}
}
ScriptManager.prototype.onScriptInvalidated =
function smgr_invalidated (scriptWrapper)
{
//dd ("script invalidated");
delete console.scriptWrappers[scriptWrapper.tag];
if (scriptWrapper.tag in this.transients)
{
//dd ("transient destroyed " + formatScript(scriptWrapper.jsdScript));
--this.transientCount;
delete this.transients[scriptWrapper.tag];
//dispatch ("hook-script-invalidated", { scriptWrapper: scriptWrapper });
}
else
{
//dd ("function destroyed " + formatScript(scriptWrapper.jsdScript));
scriptWrapper.scriptInstance.onScriptInvalidated(scriptWrapper);
//dispatch ("hook-script-invalidated", { scriptWrapper: scriptWrapper });
if (scriptWrapper.scriptInstance.scriptCount == 0)
{
var i = arrayIndexOf(this.instances, scriptWrapper.scriptInstance);
arrayRemoveAt(this.instances, i);
dispatchCommand (console.coInstanceDestroyed,
{ scriptInstance: scriptWrapper.scriptInstance });
}
}
}
ScriptManager.prototype.__defineGetter__ ("sourceText", smgr_sourcetext);
function smgr_sourcetext()
{
return this.instances[this.instances.length - 1].sourceText;
}
ScriptManager.prototype.__defineGetter__ ("lineMap", smgr_linemap);
function smgr_linemap()
{
return this.instances[this.instances.length - 1].lineMap;
}
ScriptManager.prototype.getInstanceBySequence =
function smgr_bysequence (seq)
{
for (var i = 0; i < this.instances.length; ++i)
{
if (this.instances[i].sequence == seq)
return this.instances[i];
}
return null;
}
ScriptManager.prototype.isLineExecutable =
function smgr_isexe (line)
{
for (var i in this.instances)
{
if (this.instances[i].isLineExecutable(line))
return true;
}
return false;
}
ScriptManager.prototype.hasBreakpoint =
function smgr_hasbp (line)
{
for (var i in this.instances)
{
if (this.instances[i].hasBreakpoint(line))
return true;
}
return false;
}
ScriptManager.prototype.setBreakpoint =
function smgr_break (line, parentBP, props)
{
var found = false;
for (var i in this.instances)
found |= this.instances[i].setBreakpoint(line, parentBP, props);
return found;
}
ScriptManager.prototype.clearBreakpoint =
function smgr_break (line)
{
var found = false;
for (var i in this.instances)
found |= this.instances[i].clearBreakpoint(line);
return found;
}
ScriptManager.prototype.hasFutureBreakpoint =
function smgr_hasbp (line)
{
var key = this.url + "#" + line;
return (key in console.fbreaks);
}
ScriptManager.prototype.getFutureBreakpoint =
function smgr_getfbp (line)
{
return getFutureBreakpoint (this.url, line);
}
ScriptManager.prototype.noteFutureBreakpoint =
function smgr_fbreak (line, state)
{
for (var i in this.instances)
{
if (this.instances[i]._lineMapInited)
{
if (state)
{
arrayOrFlag (this.instances[i]._lineMap, line - 1, LINE_FBREAK);
}
else
{
arrayAndFlag (this.instances[i]._lineMap, line - 1,
~LINE_FBREAK);
}
}
}
}
function ScriptInstance (manager)
{
this.scriptManager = manager;
this.url = manager.url;
this.creationDate = new Date();
this.topLevel = null;
this.functions = new Object();
this.nestLevel = 0;
this.isSealed = false;
this.scriptCount = 0;
this.breakpointCount = 0;
this.disabledScripts = 0;
this._lineMap = new Array();
this._lineMapInited = false;
}
ScriptInstance.prototype.scanForMetaComments =
function si_scan (start)
{
const CHUNK_SIZE = 500;
const CHUNK_DELAY = 100;
var scriptInstance = this;
var sourceText = this.sourceText;
function onSourceLoaded(result)
{
if (result == Components.results.NS_OK)
scriptInstance.scanForMetaComments();
};
if (!sourceText.isLoaded)
{
sourceText.loadSource(onSourceLoaded);
return;
}
if (typeof start == "undefined")
start = 0;
var end = Math.min (sourceText.lines.length, start + CHUNK_SIZE);
var obj = new Object();
for (var i = start; i < end; ++i)
{
var ary = sourceText.lines[i].match (/\/\/@(\S+)(.*)/);
if (ary && ary[1] in console.metaDirectives && !(ary[1] in obj))
{
try
{
console.metaDirectives[ary[1]](scriptInstance, i + 1, ary);
}
catch (ex)
{
display (getMsg(MSN_ERR_META_FAILED, [ary[1], this.url, i + 1]),
MT_ERROR);
display (formatException (ex), MT_ERROR);
}
}
}
if (i != sourceText.lines.length)
setTimeout (this.scanForMetaComments, CHUNK_DELAY, i);
}
ScriptInstance.prototype.seal =
function si_seal ()
{
this.sealDate = new Date();
this.isSealed = true;
if (isURLFiltered(this.url))
{
this.disabledScripts = 1;
var nada = SCRIPT_NODEBUG | SCRIPT_NOPROFILE;
if (this.topLevel && this.topLevel.isValid)
this.topLevel.jsdScript.flags |= nada;
for (var f in this.functions)
{
if (this.functions[f].jsdScript.isValid)
this.functions[f].jsdScript.flags |= nada;
++this.disabledScripts;
}
}
dispatch ("hook-script-instance-sealed", { scriptInstance: this });
}
ScriptInstance.prototype.onScriptCreated =
function si_created (scriptWrapper)
{
var tag = scriptWrapper.jsdScript.tag;
if (scriptWrapper.functionName)
{
this.functions[tag] = scriptWrapper;
}
else
{
this.topLevel = scriptWrapper;
scriptWrapper.functionName = MSG_VAL_TLSCRIPT;
scriptWrapper.addToLineMap(this._lineMap);
//var dummy = scriptWrapper.sourceText;
this.seal();
}
++this.scriptCount;
}
ScriptInstance.prototype.onScriptInvalidated =
function si_invalidated (scriptWrapper)
{
//dd ("script invalidated");
scriptWrapper.clearBreakpoints();
--this.scriptCount;
}
ScriptInstance.prototype.__defineGetter__ ("sourceText", si_gettext);
function si_gettext ()
{
if (!("_sourceText" in this))
this._sourceText = new SourceText (this);
return this._sourceText;
}
ScriptInstance.prototype.__defineGetter__ ("lineMap", si_linemap);
function si_linemap()
{
if (!this._lineMapInited)
{
if (this.topLevel && this.topLevel.jsdScript.isValid)
this.topLevel.addToLineMap(this._lineMap);
for (var i in this.functions)
{
if (this.functions[i].jsdScript.isValid)
this.functions[i].addToLineMap(this._lineMap);
}
for (var fbp in console.fbreaks)
{
var fbreak = console.fbreaks[fbp];
if (fbreak.url == this.url)
arrayOrFlag (this._lineMap, fbreak.lineNumber - 1, LINE_FBREAK);
}
this._lineMapInited = true;
}
return this._lineMap;
}
ScriptInstance.prototype.isLineExecutable =
function si_isexe (line)
{
if (this.topLevel && this.topLevel.jsdScript.isValid &&
this.topLevel.jsdScript.isLineExecutable (line, PCMAP_SOURCETEXT))
{
return true;
}
for (var f in this.functions)
{
var jsdScript = this.functions[f].jsdScript;
if (line >= jsdScript.baseLineNumber &&
line <= jsdScript.baseLineNumber + jsdScript.lineExtent &&
jsdScript.isLineExecutable (line, PCMAP_SOURCETEXT))
{
return true;
}
}
return false;
}
ScriptInstance.prototype.hasBreakpoint =
function si_hasbp (line)
{
return Boolean (this.getBreakpoint(line));
}
ScriptInstance.prototype.getBreakpoint =
function si_getbp (line)
{
for (var b in console.breaks)
{
if (console.breaks[b].scriptWrapper.scriptInstance == this)
{
if (typeof line == "undefined")
return true;
var jsdScript = console.breaks[b].scriptWrapper.jsdScript;
if (jsdScript.pcToLine(console.breaks[b].pc, PCMAP_SOURCETEXT) ==
line)
{
return console.breaks[b];
}
}
}
return false;
}
ScriptInstance.prototype.setBreakpoint =
function si_setbp (line, parentBP, props)
{
function setBP (scriptWrapper)
{
if (!scriptWrapper.jsdScript.isValid)
return false;
var jsdScript = scriptWrapper.jsdScript;
if (line >= jsdScript.baseLineNumber &&
line <= jsdScript.baseLineNumber + jsdScript.lineExtent &&
(jsdScript.isLineExecutable (line, PCMAP_SOURCETEXT) ||
jsdScript.baseLineNumber == line))
{
var pc = jsdScript.lineToPc(line, PCMAP_SOURCETEXT);
scriptWrapper.setBreakpoint(pc, parentBP, props);
return true;
}
return false;
};
var found;
if (this.topLevel)
found = setBP (this.topLevel);
for (var f in this.functions)
found |= setBP (this.functions[f]);
if (this._lineMapInited && found)
arrayOrFlag(this._lineMap, line - 1, LINE_BREAK);
return found;
}
ScriptInstance.prototype.clearBreakpoint =
function si_setbp (line)
{
var found = false;
function clearBP (scriptWrapper)
{
var jsdScript = scriptWrapper.jsdScript;
if (!jsdScript.isValid)
return;
var pc = jsdScript.lineToPc(line, PCMAP_SOURCETEXT);
if (line >= jsdScript.baseLineNumber &&
line <= jsdScript.baseLineNumber + jsdScript.lineExtent &&
scriptWrapper.hasBreakpoint(pc))
{
found |= scriptWrapper.clearBreakpoint(pc);
}
};
if (this._lineMapInited)
arrayAndFlag(this._lineMap, line - 1, ~LINE_BREAK);
if (this.topLevel)
clearBP (this.topLevel);
for (var f in this.functions)
clearBP (this.functions[f]);
return found;
}
ScriptInstance.prototype.getScriptWrapperAtLine =
function si_getscript (line)
{
var targetScript = null;
var scriptWrapper;
if (this.topLevel)
{
scriptWrapper = this.topLevel;
if (line >= scriptWrapper.jsdScript.baseLineNumber &&
line <= scriptWrapper.jsdScript.baseLineNumber +
scriptWrapper.jsdScript.lineExtent)
{
targetScript = scriptWrapper;
}
}
for (var f in this.functions)
{
scriptWrapper = this.functions[f];
if ((line >= scriptWrapper.jsdScript.baseLineNumber &&
line <= scriptWrapper.jsdScript.baseLineNumber +
scriptWrapper.jsdScript.lineExtent) &&
(!targetScript ||
scriptWrapper.jsdScript.lineExtent <
targetScript.jsdScript.lineExtent))
{
targetScript = scriptWrapper;
}
}
return targetScript;
}
ScriptInstance.prototype.containsScriptTag =
function si_contains (tag)
{
return ((this.topLevel && this.topLevel.tag == tag) ||
(tag in this.functions));
}
ScriptInstance.prototype.guessFunctionNames =
function si_guessnames ()
{
var sourceLines = this._sourceText.lines;
var context = console.prefs["guessContext"];
var pattern = new RegExp (console.prefs["guessPattern"]);
var scanText;
function getSourceContext (end)
{
var startLine = end - context;
if (startLine < 0)
startLine = 0;
var text = "";
for (i = startLine; i <= targetLine; ++i)
text += String(sourceLines[i]);
var pos = text.lastIndexOf ("function");
if (pos != -1)
text = text.substring(0, pos);
return text;
};
for (var i in this.functions)
{
var scriptWrapper = this.functions[i];
if (scriptWrapper.jsdScript.functionName != "anonymous")
continue;
var targetLine = scriptWrapper.jsdScript.baseLineNumber;
if (targetLine > sourceLines.length)
{
dd ("not enough source to guess function at line " + targetLine);
return;
}
scanText = getSourceContext(targetLine);
var ary = scanText.match (pattern);
if (ary)
{
if ("charset" in this._sourceText)
ary[1] = toUnicode(ary[1], this._sourceText.charset);
scriptWrapper.functionName = getMsg(MSN_FMT_GUESSEDNAME, ary[1]);
}
else
{
if ("guessFallback" in console)
{
var name = console.guessFallback(scriptWrapper, scanText);
if (name)
{
scriptWrapper.functionName = getMsg(MSN_FMT_GUESSEDNAME,
name);
}
}
}
}
dispatch ("hook-guess-complete", { scriptInstance: this });
}
function ScriptWrapper (jsdScript)
{
this.jsdScript = jsdScript;
this.tag = jsdScript.tag;
this.functionName = jsdScript.functionName;
this.breakpointCount = 0;
this._lineMap = null;
this.breaks = new Object();
}
ScriptWrapper.prototype.__defineGetter__ ("sourceText", sw_getsource);
function sw_getsource ()
{
if (!("_sourceText" in this))
{
if (!this.jsdScript.isValid)
return null;
this._sourceText = new PPSourceText(this);
}
return this._sourceText;
}
ScriptWrapper.prototype.__defineGetter__ ("lineMap", sw_linemap);
function sw_linemap ()
{
if (!this._lineMap)
this.addToLineMap(this._lineMap);
return this._lineMap;
}
ScriptWrapper.prototype.hasBreakpoint =
function sw_hasbp (pc)
{
var key = this.jsdScript.tag + ":" + pc;
return key in console.breaks;
}
ScriptWrapper.prototype.getBreakpoint =
function sw_hasbp (pc)
{
var key = this.jsdScript.tag + ":" + pc;
if (key in console.breaks)
return console.breaks[key];
return null;
}
ScriptWrapper.prototype.setBreakpoint =
function sw_setbp (pc, parentBP, props)
{
var key = this.jsdScript.tag + ":" + pc;
//dd ("setting breakpoint in " + this.functionName + " " + key);
if (key in console.breaks)
return null;
var brk = new BreakInstance (parentBP, this, pc);
if (props)
brk.setProperties(props);
console.breaks[key] = brk;
this.breaks[key] = brk;
if (parentBP)
{
parentBP.childrenBP[key] = brk;
brk.lineNumber = parentBP.lineNumber;
brk.url = parentBP.url;
}
if ("_sourceText" in this)
{
var line = this.jsdScript.pcToLine(brk.pc, PCMAP_PRETTYPRINT);
arrayOrFlag (this._sourceText.lineMap, line - 1, LINE_BREAK);
}
++this.scriptInstance.breakpointCount;
++this.breakpointCount;
if (this.scriptInstance._lineMapInited)
{
line = this.jsdScript.pcToLine (pc, PCMAP_SOURCETEXT);
arrayOrFlag (this.scriptInstance._lineMap, line - 1, LINE_BREAK);
}
dispatch ("hook-break-set", { breakWrapper: brk });
return brk;
}
ScriptWrapper.prototype.clearBreakpoints =
function sw_clearbps ()
{
var found = false;
for (b in this.breaks)
found |= this.clearBreakpoint(this.breaks[b].pc);
return found;
}
ScriptWrapper.prototype.clearBreakpoint =
function sw_clearbp (pc)
{
var key = this.jsdScript.tag + ":" + pc;
if (!(key in console.breaks))
return false;
var brk = console.breaks[key];
if ("propsWindow" in brk)
brk.propsWindow.close();
delete console.breaks[key];
delete this.breaks[key];
if (brk.parentBP)
delete brk.parentBP.childrenBP[key];
var line;
if ("_sourceText" in this && this.jsdScript.isValid)
{
line = this.jsdScript.pcToLine(brk.pc, PCMAP_PRETTYPRINT);
this._sourceText.lineMap[line - 1] &= ~LINE_BREAK;
}
--this.scriptInstance.breakpointCount;
--this.breakpointCount;
if (this.scriptInstance._lineMapInited)
{
if (this.jsdScript.isValid)
{
line = this.jsdScript.pcToLine (pc, PCMAP_SOURCETEXT);
if (!this.scriptInstance.hasBreakpoint(line))
this.scriptInstance._lineMap[line - 1] &= ~LINE_BREAK;
}
else
{
/* script is gone, no way to find out where the break actually
* was, so we have to redo the whole map. */
this.scriptInstance._lineMapInited = false;
this.scriptInstance._lineMap.length = 0;
var dummy = this.scriptInstance.lineMap;
}
}
dispatch ("hook-break-clear", { breakWrapper: brk });
if (this.jsdScript.isValid)
this.jsdScript.clearBreakpoint (pc);
return true;
}
ScriptWrapper.prototype.addToLineMap =
function sw_addmap (lineMap)
{
var jsdScript = this.jsdScript;
var end = jsdScript.baseLineNumber + jsdScript.lineExtent;
for (var i = jsdScript.baseLineNumber; i < end; ++i)
{
if (jsdScript.isLineExecutable(i, PCMAP_SOURCETEXT))
arrayOrFlag (lineMap, i - 1, LINE_BREAKABLE);
}
for (i in this.breaks)
{
var line = jsdScript.pcToLine(this.breaks[i].pc, PCMAP_SOURCETEXT);
arrayOrFlag (lineMap, line - 1, LINE_BREAK);
}
}
function getScriptWrapper(jsdScript)
{
if (!ASSERT(jsdScript, "getScriptWrapper: null jsdScript"))
return null;
var tag = jsdScript.tag;
if (tag in console.scriptWrappers)
return console.scriptWrappers[tag];
dd ("Can't find a wrapper for " + formatScript(jsdScript));
return null;
}
function BreakInstance (parentBP, scriptWrapper, pc)
{
this._enabled = true;
this.parentBP = parentBP;
this.scriptWrapper = scriptWrapper;
this.pc = pc;
this.url = scriptWrapper.jsdScript.fileName;
this.lineNumber = scriptWrapper.jsdScript.pcToLine (pc, PCMAP_SOURCETEXT);
this.oneTime = false;
this.triggerCount = 0;
scriptWrapper.jsdScript.setBreakpoint (pc);
}
BreakInstance.prototype.__defineGetter__ ("jsdURL", bi_getURL);
function bi_getURL ()
{
return ("x-jsd:break?url=" + encodeURIComponent(this.url) +
"&lineNumber=" + this.lineNumber +
"&conditionEnabled=" + this.conditionEnabled +
"&condition=" + encodeURIComponent(this.condition) +
"&passExceptions=" + this.passExceptions +
"&logResult=" + this.logResult +
"&resultAction=" + this.resultAction +
"&enabled=" + this.enabled);
}
BreakInstance.prototype.getProperties =
function bi_getprops()
{
var rv = new Object();
rv.enabled = this._enabled;
if ("_conditionEnabled" in this)
rv.conditionEnabled = this._conditionEnabled;
if ("_condition" in this)
rv.condition = this._condition;
if ("_passExceptions" in this)
rv.passExceptions = this._passExceptions;
if ("_logResult" in this)
rv.logResult = this._logResult;
if ("_resultAction" in this)
rv.resultAction = this._resultAction;
return rv;
}
BreakInstance.prototype.setProperties =
function bi_setprops(obj)
{
for (var p in obj)
{
if (p.search(/pc|url|lineNumber/) == -1)
this[p] = obj[p];
}
if ("propsWindow" in this)
this.propsWindow.populateFromBreakpoint();
}
BreakInstance.prototype.clearBreakpoint =
function bi_clear()
{
this.scriptWrapper.clearBreakpoint(this.pc);
}
BreakInstance.prototype.__defineGetter__ ("enabled", bi_getEnabled);
function bi_getEnabled ()
{
return this._enabled;
}
BreakInstance.prototype.__defineSetter__ ("enabled", bi_setEnabled);
function bi_setEnabled (state)
{
if (state != this._enabled)
{
this._enabled = state;
if (state)
this.scriptWrapper.jsdScript.setBreakpoint(this.pc);
else
this.scriptWrapper.jsdScript.clearBreakpoint(this.pc);
}
return state;
}
BreakInstance.prototype.__defineGetter__ ("conditionEnabled", bi_getCondEnabled);
function bi_getCondEnabled ()
{
if ("_conditionEnabled" in this)
return this._conditionEnabled;
if (this.parentBP)
return this.parentBP.conditionEnabled;
return false;
}
BreakInstance.prototype.__defineSetter__ ("conditionEnabled", bi_setCondEnabled);
function bi_setCondEnabled (state)
{
if (this.parentBP)
return this.parentBP.conditionEnabled = state;
return this._conditionEnabled = state;
}
BreakInstance.prototype.__defineGetter__ ("condition", bi_getCondition);
function bi_getCondition ()
{
if ("_condition" in this)
return this._condition;
if (this.parentBP)
return this.parentBP.condition;
return "";
}
BreakInstance.prototype.__defineSetter__ ("condition", bi_setCondition);
function bi_setCondition (value)
{
if (this.parentBP)
return this.parentBP.condition = value;
return this._condition = value;
}
BreakInstance.prototype.__defineGetter__ ("passExceptions", bi_getException);
function bi_getException ()
{
if ("_passExceptions" in this)
return this._passExceptions;
if (this.parentBP)
return this.parentBP.passExceptions;
return false;
}
BreakInstance.prototype.__defineSetter__ ("passExceptions", bi_setException);
function bi_setException (state)
{
if (this.parentBP)
return this.parentBP.passExceptions = state;
return this._passExceptions = state;
}
BreakInstance.prototype.__defineGetter__ ("logResult", bi_getLogResult);
function bi_getLogResult ()
{
if ("_logResult" in this)
return this._logResult;
if (this.parentBP)
return this.parentBP.logResult;
return false;
}
BreakInstance.prototype.__defineSetter__ ("logResult", bi_setLogResult);
function bi_setLogResult (state)
{
if (this.parentBP)
return this.parentBP.logResult = state;
return this._logResult = state;
}
BreakInstance.prototype.__defineGetter__ ("resultAction", bi_getResultAction);
function bi_getResultAction ()
{
if ("_resultAction" in this)
return this._resultAction;
if (this.parentBP)
return this.parentBP.resultAction;
return BREAKPOINT_STOPALWAYS;
}
BreakInstance.prototype.__defineSetter__ ("resultAction", bi_setResultAction);
function bi_setResultAction (state)
{
if (this.parentBP)
return this.parentBP.resultAction = state;
return this._resultAction = state;
}
function FutureBreakpoint (url, lineNumber)
{
this.url = url;
this.lineNumber = lineNumber;
this.enabled = true;
this.childrenBP = new Object();
this.conditionEnabled = false;
this.condition = "";
this.passExceptions = false;
this.logResult = false;
this.resultAction = BREAKPOINT_STOPALWAYS;
}
FutureBreakpoint.prototype.__defineGetter__ ("jsdURL", fb_getURL);
function fb_getURL ()
{
return ("x-jsd:fbreak?url=" + encodeURIComponent(this.url) +
"&lineNumber=" + this.lineNumber +
"&conditionEnabled=" + this.conditionEnabled +
"&condition=" + encodeURIComponent(this.condition) +
"&passExceptions=" + this.passExceptions +
"&logResult=" + this.logResult +
"&resultAction=" + this.resultAction +
"&enabled=" + this.enabled);
}
FutureBreakpoint.prototype.getProperties =
function fb_getprops()
{
var rv = new Object();
rv.conditionEnabled = this.conditionEnabled;
rv.condition = this.condition;
rv.passExceptions = this.passExceptions;
rv.logResult = this.logResult;
rv.resultAction = this.resultAction;
return rv;
}
FutureBreakpoint.prototype.setProperties =
function fb_setprops(obj)
{
for (var p in obj)
{
if (p.search(/url|lineNumber|childrenBP/) == -1)
this[p] = obj[p];
}
if ("propsWindow" in this)
this.propsWindow.populateFromBreakpoint();
}
FutureBreakpoint.prototype.clearFutureBreakpoint =
function fb_clear ()
{
clearFutureBreakpoint (this.url, this.lineNumber);
}
FutureBreakpoint.prototype.resetInstances =
function fb_reseti ()
{
for (var url in console.scriptManagers)
{
if (url.indexOf(this.url) != -1)
console.scriptManagers[url].setBreakpoint(this.lineNumber);
}
}
FutureBreakpoint.prototype.clearInstances =
function fb_cleari ()
{
for (var url in console.scriptManagers)
{
if (url.indexOf(this.url) != -1)
console.scriptManagers[url].clearBreakpoint(this.lineNumber);
}
}
function testBreakpoint(currentFrame, rv)
{
var tag = currentFrame.script.tag;
if (!(tag in console.scriptWrappers))
return -1;
var scriptWrapper = console.scriptWrappers[tag];
var breakpoint = scriptWrapper.getBreakpoint(currentFrame.pc);
if (!ASSERT(breakpoint, "can't find breakpoint for " +
formatFrame(currentFrame)))
{
return -1;
}
if (!ASSERT(breakpoint.enabled, "stopped at a disabled breakpoint?"))
return RETURN_CONTINUE;
++breakpoint.triggerCount;
if ("propsWindow" in breakpoint)
breakpoint.propsWindow.onBreakpointTriggered();
if (breakpoint.oneTime)
scriptWrapper.clearBreakpoint(currentFrame.pc);
if (breakpoint.conditionEnabled && breakpoint.condition)
{
var result = new Object();
var script = "var __trigger__ = function (__count__) {" +
breakpoint.condition + "}; __trigger__.apply(this, [" +
breakpoint.triggerCount + "]);";
if (!currentFrame.eval (script,
JSD_URL_SCHEME + "breakpoint-condition",
1, result))
{
/* condition raised an exception */
if (breakpoint.passExceptions)
{
rv.value = result.value;
return RETURN_THROW;
}
display (MSG_ERR_CONDITION_FAILED, MT_ERROR);
display (formatException(result.value.getWrappedValue()), MT_ERROR);
}
else
{
/* condition executed ok */
if (breakpoint.logResult)
{
display (result.value.stringValue, MT_LOG);
}
if (breakpoint.resultAction == BREAKPOINT_EARLYRETURN)
{
rv.value = result.value;
return RETURN_VALUE;
}
if (breakpoint.resultAction == BREAKPOINT_STOPNEVER ||
(breakpoint.resultAction == BREAKPOINT_STOPTRUE &&
!result.value.booleanValue))
{
return RETURN_CONTINUE;
}
}
}
return -1;
}
const EMODE_IGNORE = 0;
const EMODE_TRACE = 1;
const EMODE_BREAK = 2;
const TMODE_IGNORE = 0;
const TMODE_TRACE = 1;
const TMODE_BREAK = 2;
function debugTrap (frames, type, rv)
{
var tn = "";
var retcode = jsdIExecutionHook.RETURN_CONTINUE;
//dd ("debugTrap");
var frame = frames[0];
$ = new Array();
switch (type)
{
case jsdIExecutionHook.TYPE_BREAKPOINT:
var bpResult = testBreakpoint(frame, rv);
if (bpResult != -1)
return bpResult;
tn = MSG_VAL_BREAKPOINT;
break;
case jsdIExecutionHook.TYPE_DEBUG_REQUESTED:
tn = MSG_VAL_DEBUG;
break;
case jsdIExecutionHook.TYPE_DEBUGGER_KEYWORD:
tn = MSG_VAL_DEBUGGER;
break;
case jsdIExecutionHook.TYPE_THROW:
dd (dumpObjectTree(rv));
display (getMsg(MSN_EXCEPTION_TRACE,
[rv.value.stringValue, formatFrame(frame)]),
MT_ETRACE);
if (rv.value.jsClassName == "Error")
display (formatProperty(rv.value.getProperty("message")),
MT_EVAL_OUT);
if (console.throwMode != TMODE_BREAK)
return jsdIExecutionHook.RETURN_CONTINUE_THROW;
console.currentException = rv.value;
retcode = jsdIExecutionHook.RETURN_CONTINUE_THROW;
tn = MSG_VAL_THROW;
break;
case jsdIExecutionHook.TYPE_INTERRUPTED:
if (!frame.script.functionName &&
isURLFiltered(frame.script.fileName))
{
//dd ("filtered url: " + frame.script.fileName);
frame.script.flags |= SCRIPT_NOPROFILE | SCRIPT_NODEBUG;
return retcode;
}
var line;
if (console.prefs["prettyprint"])
line = frame.script.pcToLine (frame.pc, PCMAP_PRETTYPRINT);
else
line = frame.line;
if (console._stepPast ==
frames.length + frame.script.fileName + line)
{
//dd("stepPast: " + console._stepPast);
return retcode;
}
delete console._stepPast;
setStopState(false);
break;
default:
/* don't print stop/cont messages for other types */
}
console.jsds.functionHook = null;
/* set our default return value */
console._continueCodeStack.push (retcode);
if (tn)
display (getMsg(MSN_STOP, tn), MT_STOP);
/* build an array of frames */
console.frames = frames;
console.trapType = type;
try
{
console.jsds.enterNestedEventLoop({onNest: eventLoopNested});
}
catch (ex)
{
dd ("caught " + ex + " while nested");
}
/* execution pauses here until someone calls exitNestedEventLoop() */
clearCurrentFrame();
rv.value = ("currentException" in console) ? console.currentException : null;
delete console.frames;
delete console.trapType;
delete console.currentException;
$ = new Array();
dispatch ("hook-debug-continue");
if (tn)
display (getMsg(MSN_CONT, tn), MT_CONT);
return console._continueCodeStack.pop();
}
function eventLoopNested ()
{
window.focus();
window.getAttention();
dispatch ("hook-debug-stop");
}
function getCurrentFrame()
{
if ("frames" in console)
return console.frames[console._currentFrameIndex];
return null;
}
function getCurrentFrameIndex()
{
if (typeof console._currentFrameIndex == "undefined")
return -1;
return console._currentFrameIndex;
}
function setCurrentFrameByIndex (index)
{
if (!console.frames)
throw new BadMojo (ERR_NO_STACK);
ASSERT (index >= 0 && index < console.frames.length, "index out of range");
console._currentFrameIndex = index;
var cf = console.frames[console._currentFrameIndex];
dispatch ("set-eval-obj", { jsdValue: cf });
console.stopFile = (cf.isNative) ? MSG_URL_NATIVE : cf.script.fileName;
console.stopLine = cf.line;
delete console._pp_stopLine;
return cf;
}
function clearCurrentFrame ()
{
if (!console.frames)
throw new BadMojo (ERR_NO_STACK);
if (console.currentEvalObject instanceof jsdIStackFrame)
dispatch ("set-eval-obj", { jsdValue: console.jsdConsole });
delete console.stopLine;
delete console._pp_stopLine;
delete console.stopFile;
delete console._currentFrameIndex;
}
function formatArguments (v)
{
if (!v)
return "";
var ary = new Array();
var p = new Object();
v.getProperties (p, {});
p = p.value;
for (var i = 0; i < p.length; ++i)
{
if (p[i].flags & jsdIProperty.FLAG_ARGUMENT)
ary.push (getMsg(MSN_FMT_ARGUMENT,
[p[i].name.stringValue,
formatValue(p[i].value, FTYPE_SUMMARY)]));
}
return ary.join (MSG_COMMASP);
}
function formatFlags (flags)
{
var s = "";
if (flags & PROP_ENUMERATE)
s += MSG_VF_ENUMERABLE;
if (flags & PROP_READONLY)
s += MSG_VF_READONLY;
if (flags & PROP_PERMANENT)
s += MSG_VF_PERMANENT;
if (flags & PROP_ALIAS)
s += MSG_VF_ALIAS;
if (flags & PROP_ARGUMENT)
s += MSG_VF_ARGUMENT;
if (flags & PROP_VARIABLE)
s += MSG_VF_VARIABLE;
if (flags & PROP_ERROR)
s += MSG_VF_ERROR;
if (flags & PROP_EXCEPTION)
s += MSG_VF_EXCEPTION;
if (flags & PROP_HINTED)
s += MSG_VF_HINTED;
return s;
}
function formatProperty (p, formatType)
{
if (!p)
throw new BadMojo (ERR_REQUIRED_PARAM, "p");
var s = formatFlags (p.flags);
if (formatType == FTYPE_ARRAY)
{
var rv = formatValue (p.value, FTYPE_ARRAY);
return [p.name.stringValue, rv[1] ? rv[1] : rv[0], rv[2], s];
}
return getMsg(MSN_FMT_PROPERTY, [s, p.name.stringValue,
formatValue(p.value)]);
}
function formatScript (script)
{
if (!script)
throw new BadMojo (ERR_REQUIRED_PARAM, "script");
var functionName;
if (script.tag in console.scriptWrappers)
functionName = console.scriptWrappers[script.tag].functionName;
else
functionName = script.functionName;
return getMsg (MSN_FMT_SCRIPT, [functionName, script.fileName]);
}
function formatFrame (f)
{
if (!f)
throw new BadMojo (ERR_REQUIRED_PARAM, "f");
var url = (f.isNative) ? MSG_URL_NATIVE : f.script.fileName;
return getMsg (MSN_FMT_FRAME,
[f.functionName, formatArguments(f.scope), url, f.line]);
}
function formatValue (v, formatType)
{
if (!v)
throw new BadMojo (ERR_REQUIRED_PARAM, "v");
if (!(v instanceof jsdIValue))
throw new BadMojo (ERR_INVALID_PARAM, "v", String(v));
var type;
var value;
switch (v.jsType)
{
case jsdIValue.TYPE_BOOLEAN:
type = MSG_TYPE_BOOLEAN;
value = String(v.booleanValue);
break;
case jsdIValue.TYPE_DOUBLE:
type = MSG_TYPE_DOUBLE;
value = v.doubleValue;
break;
case jsdIValue.TYPE_INT:
type = MSG_TYPE_INT;
value = v.intValue;
break;
case jsdIValue.TYPE_FUNCTION:
type = MSG_TYPE_FUNCTION;
value = v.jsFunctionName;
break;
case jsdIValue.TYPE_NULL:
type = MSG_TYPE_NULL;
value = MSG_TYPE_NULL;
break;
case jsdIValue.TYPE_OBJECT:
if (formatType == FTYPE_STD)
{
type = MSG_TYPE_OBJECT;
value = getMsg(MSN_FMT_OBJECT, String(v.propertyCount));
}
else
{
if (v.jsClassName)
if (v.jsClassName == "XPCWrappedNative_NoHelper")
type = MSG_CLASS_XPCOBJ;
else
type = v.jsClassName;
else
type = MSG_TYPE_OBJECT;
value = "{" + String(v.propertyCount) + "}";
}
break;
case jsdIValue.TYPE_STRING:
type = MSG_TYPE_STRING;
var strval = v.stringValue;
if (strval.length > console.prefs["maxStringLength"])
strval = getMsg(MSN_FMT_LONGSTR, strval.length);
else
strval = strval.quote()
value = strval;
break;
case jsdIValue.TYPE_VOID:
type = MSG_TYPE_VOID;
value = MSG_TYPE_VOID;
break;
default:
type = MSG_TYPE_UNKNOWN;
value = MSG_TYPE_UNKNOWN;
break;
}
if (formatType == FTYPE_SUMMARY)
return getMsg (MSN_FMT_VALUE_SHORT, [type, value]);
var className;
if (v.jsClassName)
if (v.jsClassName == "XPCWrappedNative_NoHelper")
/* translate this long, unintuitive, and common class name into
* something more palatable. */
className = MSG_CLASS_XPCOBJ;
else
className = v.jsClassName;
if (formatType == FTYPE_ARRAY)
return [type, className, value];
if (className)
return getMsg (MSN_FMT_VALUE_LONG, [type, v.jsClassName, value]);
return getMsg (MSN_FMT_VALUE_MED, [type, value]);
}
function displayCallStack ()
{
for (var i = 0; i < console.frames.length; ++i)
displayFrame (console.frames[i], i);
}
function displayProperties (v)
{
if (!v)
throw new BadMojo (ERR_REQUIRED_PARAM, "v");
if (!(v instanceof jsdIValue))
throw new BadMojo (ERR_INVALID_PARAM, "v", String(v));
var p = new Object();
v.getProperties (p, {});
for (var i in p.value) display(formatProperty (p.value[i]), MT_EVAL_OUT);
}
function displaySourceContext (sourceText, line, contextLines)
{
function onSourceLoaded (status)
{
if (status == Components.results.NS_OK)
displaySourceContext (sourceText, line, contextLines);
}
if (sourceText.isLoaded)
{
for (var i = line - contextLines; i <= line + contextLines; ++i)
{
if (i > 0 && i < sourceText.lines.length)
{
var sourceLine;
if ("charset" in sourceText)
{
sourceLine = toUnicode(sourceText.lines[i - 1],
sourceText.charset);
}
else
{
sourceLine = sourceText.lines[i - 1];
}
display (getMsg(MSN_SOURCE_LINE, [zeroPad (i, 3), sourceLine]),
i == line ? MT_STEP : MT_SOURCE);
}
}
}
else
{
sourceText.loadSource (onSourceLoaded);
}
}
function displayFrame (jsdFrame, idx, showHeader, sourceContext)
{
if (typeof idx == "undefined")
{
for (idx = 0; idx < console.frames.length; ++idx)
if (jsdFrame == console.frames[idx])
break;
if (idx >= console.frames.length)
idx = MSG_VAL_UNKNOWN;
}
if (typeof showHeader == "undefined")
showHeader = true;
if (typeof sourceContext == "undefined")
sourceContext = null;
display(getMsg(MSN_FMT_FRAME_LINE, [idx, formatFrame(jsdFrame)]), MT_OUTPUT);
if (!jsdFrame.isNative && sourceContext != null)
{
var jsdScript = jsdFrame.script;
var scriptWrapper = getScriptWrapper(jsdScript);
if (!ASSERT(scriptWrapper, "Couldn't get a script wrapper"))
return;
if (console.prefs["prettyprint"] && jsdScript.isValid)
{
displaySourceContext (scriptWrapper.sourceText,
jsdScript.pcToLine(jsdFrame.pc,
PCMAP_PRETTYPRINT),
sourceContext);
}
else
{
displaySourceContext (scriptWrapper.scriptInstance.sourceText,
jsdFrame.line, sourceContext);
}
}
}
function getFutureBreakpoint (urlPattern, lineNumber)
{
var key = urlPattern + "#" + lineNumber;
if (key in console.fbreaks)
return console.fbreaks[key];
return null;
}
function setFutureBreakpoint (urlPattern, lineNumber, props)
{
var key = urlPattern + "#" + lineNumber;
if (key in console.fbreaks)
return false;
var url;
for (url in console.scriptManagers)
{
if (url == urlPattern)
console.scriptManagers[url].noteFutureBreakpoint(lineNumber, true);
}
for (url in console.files)
{
if (url == urlPattern)
console.files[url].noteFutureBreakpoint(lineNumber, true);
}
var fbreak = new FutureBreakpoint (urlPattern, lineNumber);
if (props)
fbreak.setProperties(props);
console.fbreaks[key] = fbreak;
dispatch ("hook-fbreak-set", { fbreak: fbreak });
return fbreak;
}
function clearFutureBreakpoint (urlPattern, lineNumber)
{
var key = urlPattern + "#" + lineNumber;
if (!(key in console.fbreaks))
return false;
var i;
var fbreak = console.fbreaks[key];
if ("propsWindow" in fbreak)
fbreak.propsWindow.close();
delete console.fbreaks[key];
for (i in fbreak.childrenBP)
fbreak.childrenBP[i].parentBP = null;
var url;
for (url in console.scriptManagers)
{
if (url.indexOf(urlPattern) != -1)
console.scriptManagers[url].noteFutureBreakpoint(lineNumber, false);
}
for (url in console.files)
{
if (url == urlPattern)
console.files[url].noteFutureBreakpoint(lineNumber, false);
}
dispatch ("hook-fbreak-clear", { fbreak: fbreak });
return true;
}