| /* |
| * xbDebug.js |
| * $Revision$ $Date$ |
| */ |
| |
| /* ***** 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 Netscape code. |
| * |
| * The Initial Developer of the Original Code is |
| * Netscape Corporation. |
| * Portions created by the Initial Developer are Copyright (C) 2001 |
| * the Initial Developer. All Rights Reserved. |
| * |
| * Contributor(s): Bob Clary <bclary@netscape.com> |
| * |
| * ***** END LICENSE BLOCK ***** */ |
| |
| /* |
| ChangeLog: |
| |
| 2002-02-25: bclary - modified xbDebugTraceOject to make sure |
| that original versions of wrapped functions were not |
| rewrapped. This had caused an infinite loop in IE. |
| |
| 2002-02-07: bclary - modified xbDebug.prototype.close to not null |
| the debug window reference. This can cause problems with |
| Internet Explorer if the page is refreshed. These issues will |
| be addressed at a later date. |
| */ |
| |
| function xbDebug() |
| { |
| this.on = false; |
| this.stack = new Array(); |
| this.debugwindow = null; |
| this.execprofile = new Object(); |
| } |
| |
| xbDebug.prototype.push = function () |
| { |
| this.stack[this.stack.length] = this.on; |
| this.on = true; |
| } |
| |
| xbDebug.prototype.pop = function () |
| { |
| this.on = this.stack[this.stack.length - 1]; |
| --this.stack.length; |
| } |
| |
| xbDebug.prototype.open = function () |
| { |
| if (this.debugwindow && !this.debugwindow.closed) |
| this.close(); |
| |
| this.debugwindow = window.open('about:blank', 'DEBUGWINDOW', 'height=400,width=600,resizable=yes,scrollbars=yes'); |
| this.debugwindow.moveTo(0,0); |
| window.focus(); |
| |
| this.debugwindow.document.write('<html><head><title>xbDebug Window</title></head><body><h3>Javascript Debug Window</h3></body></html>'); |
| } |
| |
| xbDebug.prototype.close = function () |
| { |
| if (!this.debugwindow) |
| return; |
| |
| if (!this.debugwindow.closed) |
| this.debugwindow.close(); |
| |
| // bc 2002-02-07, other windows may still hold a reference to this: this.debugwindow = null; |
| } |
| |
| xbDebug.prototype.dump = function (msg) |
| { |
| if (!this.on) |
| return; |
| |
| if (!this.debugwindow || this.debugwindow.closed) |
| this.open(); |
| |
| this.debugwindow.document.write(msg + '<br>'); |
| |
| return; |
| } |
| |
| var xbDEBUG = new xbDebug(); |
| |
| window.onunload = function () { xbDEBUG.close(); } |
| |
| function xbDebugGetFunctionName(funcref) |
| { |
| |
| if (!funcref) |
| { |
| return ''; |
| } |
| |
| if (funcref.name) |
| return funcref.name; |
| |
| var name = funcref + ''; |
| name = name.substring(name.indexOf(' ') + 1, name.indexOf('(')); |
| funcref.name = name; |
| |
| if (!name) alert('name not defined'); |
| return name; |
| } |
| |
| |
| // emulate functionref.apply for IE mac and IE win < 5.5 |
| function xbDebugApplyFunction(funcname, funcref, thisref, argumentsref) |
| { |
| var rv; |
| |
| if (!funcref) |
| { |
| alert('xbDebugApplyFunction: funcref is null'); |
| } |
| |
| if (typeof(funcref.apply) != 'undefined') |
| return funcref.apply(thisref, argumentsref); |
| |
| var applyexpr = 'thisref.xbDebug_orig_' + funcname + '('; |
| var i; |
| |
| for (i = 0; i < argumentsref.length; i++) |
| { |
| applyexpr += 'argumentsref[' + i + '],'; |
| } |
| |
| if (argumentsref.length > 0) |
| { |
| applyexpr = applyexpr.substring(0, applyexpr.length - 1); |
| } |
| |
| applyexpr += ')'; |
| |
| return eval(applyexpr); |
| } |
| |
| function xbDebugCreateFunctionWrapper(scopename, funcname, precall, postcall) |
| { |
| var wrappedfunc; |
| var scopeobject = eval(scopename); |
| var funcref = scopeobject[funcname]; |
| |
| scopeobject['xbDebug_orig_' + funcname] = funcref; |
| |
| wrappedfunc = function () |
| { |
| var rv; |
| |
| precall(scopename, funcname, arguments); |
| rv = xbDebugApplyFunction(funcname, funcref, scopeobject, arguments); |
| postcall(scopename, funcname, arguments, rv); |
| return rv; |
| }; |
| |
| if (typeof(funcref.constructor) != 'undefined') |
| wrappedfunc.constructor = funcref.constuctor; |
| |
| if (typeof(funcref.prototype) != 'undefined') |
| wrappedfunc.prototype = funcref.prototype; |
| |
| scopeobject[funcname] = wrappedfunc; |
| } |
| |
| function xbDebugCreateMethodWrapper(contextname, classname, methodname, precall, postcall) |
| { |
| var context = eval(contextname); |
| var methodref = context[classname].prototype[methodname]; |
| |
| context[classname].prototype['xbDebug_orig_' + methodname] = methodref; |
| |
| var wrappedmethod = function () |
| { |
| var rv; |
| // eval 'this' at method run time to pick up reference to the object's instance |
| var thisref = eval('this'); |
| // eval 'arguments' at method run time to pick up method's arguments |
| var argsref = arguments; |
| |
| precall(contextname + '.' + classname, methodname, argsref); |
| rv = xbDebugApplyFunction(methodname, methodref, thisref, argsref); |
| postcall(contextname + '.' + classname, methodname, argsref, rv); |
| return rv; |
| }; |
| |
| return wrappedmethod; |
| } |
| |
| function xbDebugPersistToString(obj) |
| { |
| var s = ''; |
| |
| if (obj == null) |
| return 'null'; |
| |
| switch(typeof(obj)) |
| { |
| case 'number': |
| return obj; |
| case 'string': |
| return '"' + obj + '"'; |
| case 'undefined': |
| return 'undefined'; |
| case 'boolean': |
| return obj + ''; |
| } |
| |
| if (obj.constructor) |
| return '[' + xbDebugGetFunctionName(obj.constructor) + ']'; |
| |
| return null; |
| } |
| |
| function xbDebugTraceBefore(scopename, funcname, funcarguments) |
| { |
| var i; |
| var s = ''; |
| var execprofile = xbDEBUG.execprofile[scopename + '.' + funcname]; |
| if (!execprofile) |
| execprofile = xbDEBUG.execprofile[scopename + '.' + funcname] = { started: 0, time: 0, count: 0 }; |
| |
| for (i = 0; i < funcarguments.length; i++) |
| { |
| s += xbDebugPersistToString(funcarguments[i]); |
| if (i < funcarguments.length - 1) |
| s += ', '; |
| } |
| |
| xbDEBUG.dump('enter ' + scopename + '.' + funcname + '(' + s + ')'); |
| execprofile.started = (new Date()).getTime(); |
| } |
| |
| function xbDebugTraceAfter(scopename, funcname, funcarguments, rv) |
| { |
| var i; |
| var s = ''; |
| var execprofile = xbDEBUG.execprofile[scopename + '.' + funcname]; |
| if (!execprofile) |
| xbDEBUG.dump('xbDebugTraceAfter: execprofile not created for ' + scopename + '.' + funcname); |
| else if (execprofile.started == 0) |
| xbDEBUG.dump('xbDebugTraceAfter: execprofile.started == 0 for ' + scopename + '.' + funcname); |
| else |
| { |
| execprofile.time += (new Date()).getTime() - execprofile.started; |
| execprofile.count++; |
| execprofile.started = 0; |
| } |
| |
| for (i = 0; i < funcarguments.length; i++) |
| { |
| s += xbDebugPersistToString(funcarguments[i]); |
| if (i < funcarguments.length - 1) |
| s += ', '; |
| } |
| |
| xbDEBUG.dump('exit ' + scopename + '.' + funcname + '(' + s + ')==' + xbDebugPersistToString(rv)); |
| } |
| |
| function xbDebugTraceFunction(scopename, funcname) |
| { |
| xbDebugCreateFunctionWrapper(scopename, funcname, xbDebugTraceBefore, xbDebugTraceAfter); |
| } |
| |
| function xbDebugTraceObject(contextname, classname) |
| { |
| var classref = eval(contextname + '.' + classname); |
| var p; |
| var sp; |
| |
| if (!classref || !classref.prototype) |
| return; |
| |
| for (p in classref.prototype) |
| { |
| sp = p + ''; |
| if (typeof(classref.prototype[sp]) == 'function' && (sp).indexOf('xbDebug_orig') == -1) |
| { |
| classref.prototype[sp] = xbDebugCreateMethodWrapper(contextname, classname, sp, xbDebugTraceBefore, xbDebugTraceAfter); |
| } |
| } |
| } |
| |
| function xbDebugDumpProfile() |
| { |
| var p; |
| var execprofile; |
| var avg; |
| |
| for (p in xbDEBUG.execprofile) |
| { |
| execprofile = xbDEBUG.execprofile[p]; |
| avg = Math.round ( 100 * execprofile.time/execprofile.count) /100; |
| xbDEBUG.dump('Execution profile ' + p + ' called ' + execprofile.count + ' times. Total time=' + execprofile.time + 'ms. Avg Time=' + avg + 'ms.'); |
| } |
| } |