mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-10 01:40:17 +01:00
2046 lines
55 KiB
JavaScript
2046 lines
55 KiB
JavaScript
|
/* -*- 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;
|
||
|
}
|