Author: ptw
Date: 2007-12-09 05:42:32 -0800 (Sun, 09 Dec 2007)
New Revision: 7489
Modified:
openlaszlo/trunk/WEB-INF/lps/lfc/compiler/LzFormatter.lzs
openlaszlo/trunk/WEB-INF/lps/lfc/debugger/LzMessage.lzs
openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/dhtml/LzDebug.js
openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzDebug.as
openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzMemory.as
Log:
Change 20071207-ptw-v by [EMAIL PROTECTED] on 2007-12-07 22:50:21 EST
in /Users/ptw/OpenLaszlo/ringding-2
for http://svn.openlaszlo.org/openlaszlo/trunk
Summary: Bring memory tracing to the modern era
Bugs Fixed:
LPP-5205: 'Debug.whyAlive no longer shows reference keeping object alive'
Technical Reviewer: [EMAIL PROTECTED] (message:<[EMAIL PROTECTED]>)
QA Reviewer: [EMAIL PROTECTED] (pending)
Details:
LzMessage: fix error in concat observed in passing, make
appendInternal of another LzMessage concat, not present the
message
LzMemory: Make some things classes. Store leaks as a new class
that has a pretty descriptor and breaks out the leak information
for easy inspection. Use a stable sort on leaks, sort the biggest
leak to the front of the Array. Make whyAlive describe the top
leaks.
LzDebug.*: Use user toString methods, obey unique flag.
LzFormatter: New formatting flag `=` takes the next argument as
the object to be represented by the format (overriding the normal
hot-linking that occurs in the debugger so you can write a custom
representation for an object).
Tests:
Debug.markObjects()
Debug.findNewObjects()
Debug.whyAlive()
now yields useful information:
lzx> Debug.whyAlive()
global.spriteroot.$m1.debugloader.loadmc1.reqobj: (?\194?\16352)
?\194?\171Object#100| {_dbg_check:...?\194?\187
global.LzFocus.csel.sprite.__LZtextclip.filters: (?\194?\1636)
?\194?\171Array(0)#102| []?\194?\187
global.LzModeManager.__LZlastclick.sprite.__LZbuttonRef.but.filters:
(?\194?\1636) ?\194?\171Array(0)#104| []?\194?\187
global.__offscreenkeyclip.filters: (?\194?\1636) ?\194?\171Array(0)#106|
[]?\194?\187
global.spriteroot.$m0.$m0.$m5.$LzText.filters: (?\194?\1636)
?\194?\171Array(0)#108| []?\194?\187
global.spriteroot.$m0.$m0.$mcB.but.filters: (?\194?\1636)
?\194?\171Array(0)#110| []?\194?\187
global.spriteroot.$m1.$m0.$m0.$mcB.but.filters: (?\194?\1636)
?\194?\171Array(0)#112| []?\194?\187
global.spriteroot.$m1.$m0.$m1.$m0.$mcB.but.filters: (?\194?\1636)
?\194?\171Array(0)#114| []?\194?\187
global.spriteroot.$m1.$m0.$m1.$m1.$mcB.but.filters: (?\194?\1636)
?\194?\171Array(0)#116| []?\194?\187
global.spriteroot.$m1.$m0.$m1.$m2.$mcB.but.filters: (?\194?\1636)
?\194?\171Array(0)#118| []?\194?\187
...
?\194?\171__LzLeaks(28)#120| 208 smoots?\194?\187
lzx>
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/compiler/LzFormatter.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/compiler/LzFormatter.lzs 2007-12-09
00:53:16 UTC (rev 7488)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/compiler/LzFormatter.lzs 2007-12-09
13:42:32 UTC (rev 7489)
@@ -171,7 +171,10 @@
* full `Debug.__String` format used by <xref
* linkend="Debug+debug.write"/>. `%w` format obeys <xref
* linkend="Debug+debug.printLength"/>. If a precision is specified,
- * that is used as printLength.
+ * that is used as printLength. There is an additional modifier
+ * (=) which will take the next argument as the object to be
+ * represented (i.e., linked to) by the formatted string; thus
+ * permitting custom representations.
*
* @param string control: A control string where % indicates a
* subsequent argument is to be substituted.
@@ -241,6 +244,8 @@
var length = '';
var precision = null;
var directive = null;
+ // The object that is to be represented
+ var object = null;
// var extra = null;
while ((start < limit) &&
// swf7 (! directive)
@@ -283,6 +288,11 @@
break;
case '.': precision = ''; break;
case 'h': case 'l': break;
+ case '=':
+ // Take the next argument to be the object represented
+ object = getarg(argno);
+ argno++;
+ break;
// case '{':
// // Look for a match
// var close = ctrl.indexOf('}', start);
@@ -299,6 +309,7 @@
}
}
var value = getarg(argno);
+ if (object == null) { object = value; }
// set decimals
var decimals = null;
var force = false;
@@ -359,7 +370,7 @@
switch (directive) {
case 'D': case 'U': case 'I': case 'O': case 'X': case 'F': case 'E':
case 'G':
value = Number(value);
- out.append(this.pad(value, length, decimals, pad, sign, radix,
force).toUpperCase());
+ out.appendInternal(this.pad(value, length, decimals, pad, sign,
radix, force).toUpperCase(), object);
argno++; // consume value
break;
case 'c':
@@ -372,7 +383,7 @@
// We let __String abbreviate, for best legibility
out.appendInternal(this.pad(Debug.__String(value, true, width,
alternate),
length, null, pad, sign, radix, force),
- value);
+ object);
argno++; // consume value
break;
}
@@ -394,12 +405,12 @@
str = '' + value;
}
out.appendInternal(this.pad(str, length, decimals, pad, sign, radix,
force),
- value);
+ object);
argno++; // consume value
break;
case 'd': case 'u': case 'i': case 'o': case 'x': case 'f': case 'e':
case 'g':
value = Number(value);
- out.append(this.pad(value, length, decimals, pad, sign, radix,
force));
+ out.appendInternal(this.pad(value, length, decimals, pad, sign,
radix, force), object);
argno++; // consume value
break;
case '%':
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/debugger/LzMessage.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/debugger/LzMessage.lzs 2007-12-09
00:53:16 UTC (rev 7488)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/debugger/LzMessage.lzs 2007-12-09
13:42:32 UTC (rev 7489)
@@ -102,7 +102,7 @@
*/
LzMessage.prototype.concat = function () {
var msg = new LzMessage(this.message.concat.apply(this, arguments));
- var offset = 0;
+ var offset = this.message.length;
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (arg instanceof LzMessage) {
@@ -152,13 +152,22 @@
* @param Object obj: the object represented, or null
*/
LzMessage.prototype.appendInternal = function (str, obj) {
- if (arguments.length < 2) {
+ if (arguments.length < 2) {
var id = null;
} else {
var id = Debug.IDForObject(obj);
}
if (id == null) {
this.message += str;
+ } else if (obj instanceof LzMessage) {
+ // If it is already a message, just concatenate it
+ var offset = this.message.length;
+ this.message += obj.message;
+ var ao = obj.objects;
+ for (var j = 0; j < ao.length; j++) {
+ var od = ao[j];
+ this.objects.push({id: od.id, start: od.start+offset, end:
od.end+offset});
+ }
} else {
var start = this.message.length;
this.message += str;
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/dhtml/LzDebug.js
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/dhtml/LzDebug.js
2007-12-09 00:53:16 UTC (rev 7488)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/dhtml/LzDebug.js
2007-12-09 13:42:32 UTC (rev 7489)
@@ -295,7 +295,7 @@
// No pretty for these, you don't know if the user toString is
// uniquifying
pretty = (! unique);
- s = String(thing);
+ s = thing.toString();
}
// Print unidentified objects and arrays as abbreviated list of props
else {
@@ -370,7 +370,9 @@
s = String(thing);
}
- if (pretty && (s != "") && (s.length < limit)) {
+ if (pretty &&
+ ((t != 'object') || (! unique)) &&
+ (s != "") && (s.length < limit)) {
return s;
}
}
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzDebug.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzDebug.as
2007-12-09 00:53:16 UTC (rev 7488)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzDebug.as
2007-12-09 13:42:32 UTC (rev 7489)
@@ -354,7 +354,7 @@
// No pretty for these, you don't know if the user toString is
// uniquifying
pretty = (! unique);
- s = String(thing);
+ s = thing.toString();
}
// Print unidentified objects and arrays as abbreviated list of props
else {
@@ -429,7 +429,9 @@
s = String(thing);
}
- if (pretty && (s != "") && (s.length < limit)) {
+ if (pretty &&
+ ((t != 'object') || (! unique))
+ && (s != "") && (s.length < limit)) {
return s;
}
// Compute id; force if you couldn't print pretty due to
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzMemory.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzMemory.as
2007-12-09 00:53:16 UTC (rev 7488)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/debugger/platform/swf/LzMemory.as
2007-12-09 13:42:32 UTC (rev 7489)
@@ -367,135 +367,148 @@
Debug.format('Finding new objects... ');
} else {
Debug.error('Call %w first', Debug.markObjects);
-}
-}
+ }
+};
+
/**
+ * A leak descriptor
+ */
+class __LzLeak {
+ var obj = null;
+ var path = '';
+ var parent = null
+ var property = '';
+ var leaked = 0;
+
+ function initialize (o) {
+ var annotations = Debug.annotation;
+ var why = annotations.why;
+ var leaked = annotations.leaked;
+ this.obj = o;
+ if (o && (why in o) && (leaked in o)) {
+ var path = o[why];
+ var lastdot = path.lastIndexOf('.');
+ this.path = path.substring(0, lastdot);
+ this.parent = eval(this.path);
+ this.property = path.substring(lastdot + 1, path.length);
+ this.leaked = o[leaked];
+ }
+ }
+
+ /**
+ * Describe an individual leak
+ * @access private
+ */
+ function toString () {
+ if (this.obj) {
+ return Debug.formatToString("%=s.%s: (\xa3%d) %0.32#w", this.parent,
this.path, this.property, this.leaked, this.obj);
+ } else {
+ return '' + this.obj;
+ }
+ }
+};
+
+/**
* Snapshot of the current leaks
* @access private
*/
-var __LzLeaks = function () {
- var l = Debug.leaks;
- var ll = l.length;
- var annotations = Debug.annotation;
- var why = annotations.why;
- var size = annotations.size;
- var leaked = '_dbg_check';
+class __LzLeaks /* extends Array */ {
+ // Act like an Array
+ var length = 0;
- // Sort leaks according to path
- l.sort(function (a, b) {
- var an = a[why];
- var bn = b[why];
- return (an > bn) - (an < bn);
- });
+ var sort = Array.prototype.sort;
- // Merge leaks under the same path
- this.length = 0;
- for (var i = 0; i < ll; i = j) {
- var p = l[i];
- p[leaked] = p[size];
- var j = i + 1;
- var pn = p[why];
- if (typeof(pn) != 'undefined') {
- while (j < ll) {
- var c = l[j];
- var cn = c[why];
- if (typeof(cn) != 'undefined') {
- if (cn.indexOf(pn) == 0) {
- // Don't count loops
- if (c !== p) {
- p[leaked] += c[size];
- } else {
- if (Debug.debugTrace) {
- Debug.format('%s is %s\n', pn, cn);
+ function initialize () {
+ var l = Debug.leaks;
+ var ll = l.length;
+ var annotations = Debug.annotation;
+ var why = annotations.why;
+ var size = annotations.size;
+ var leaked = '_dbg_check';
+
+ // Sort leaks according to path
+ l.sort(function (a, b) {
+ var an = a[why];
+ var bn = b[why];
+ return (an > bn) - (an < bn);
+ });
+
+ // Merge leaks under the same path
+ this.length = 0;
+ for (var i = 0; i < ll; i = j) {
+ var p = l[i];
+ p[leaked] = p[size];
+ var j = i + 1;
+ var pn = p[why];
+ if (typeof(pn) != 'undefined') {
+ while (j < ll) {
+ var c = l[j];
+ var cn = c[why];
+ if (typeof(cn) != 'undefined') {
+ if (cn.indexOf(pn) == 0) {
+ // Don't count loops
+ if (c !== p) {
+ p[leaked] += c[size];
+ } else {
+ if (Debug.debugTrace) {
+ Debug.format('%s is %s\n', pn, cn);
+ }
}
+ j++;
+ continue;
}
- j++;
- continue;
}
+ break;
}
- break;
}
+ this[this.length++] = new __LzLeak(p);
}
- this[this.length++] = p;
}
-}
-// An __LzLeaks is an array
-__LzLeaks.prototype = new Array();
-// Work around Flash deficiency...
-__LzLeaks.prototype.constructor = __LzLeaks;
-/**
- * Convert a leaks to a string
- * @param printer:Function the function to print the leaks
- * functions with. Defaults to Debug.__String
- * @param length:Number the length to abbreviate the string to
- *
- * @access private
- */
-__LzLeaks.prototype.toStringInternal = function(printer, length) {
- switch (arguments.length) {
- case 0:
- printer = function (o) { return Debug.__String(o); };
- case 1:
- length = Debug.printLength;
- }
- var leaks = "";
- var sep = "\n";
- for (var i = this.length - 1; i >= 0 && leaks.length < length; i--) {
- if (this[i]) {
- leaks += printer(this[i]) + sep;
+ function _dbg_name () {
+ var leakage = 0;
+ for (var i in this) {
+ var s = this[i].leaked;
+ if (! isNaN(s)) {
+ leakage += s;
+ }
}
+ return leakage + ' smoots';
}
- // Trim trailing sep
- if (leaks != '') {
- leaks = leaks.substring(0, leaks.length - sep.length);
- }
- leaks = Debug.abbreviate(leaks, length);
- return leaks;
}
/**
- * Leaks printer
+ * List new objects and why they are alive
+ *
+ * @param top Number: How many leaks to detail, default is 10
* @access private
*/
-__LzLeaks.prototype.toString = function () {
- var annotations = Debug.annotation;
- var why = annotations.why;
- var leaked = annotations.leaked;
- return this.toStringInternal(function (o) { return o[why] + ' (' + o[leaked]
+ '): ' + Debug.__String(o); });
-}
-
-/**
- * Name for debug
- * @access private
- */
-__LzLeaks.prototype._dbg_name = function () {
- var leaked = Debug.annotation.leaked;
- var leakage = 0;
- for (var i in this) {
- var s = this[i][leaked];
- if (! isNaN(s)) {
- leakage += s;
- }
+Debug.whyAlive = function (top) {
+ switch (arguments.length) {
+ case 0:
+ top = 10;
}
- return leakage + ' smoots';
-}
-
-
-/**
- * List new objects and why they are alive
- * @access private
- */
-Debug.whyAlive = function () {
- var leaked = this.annotation.leaked;
if (this['leaks']) {
var l = new __LzLeaks();
// Sort the largest to the top
- l.sort(function (a, b) { return a[leaked] - b[leaked] });
+ l.sort(function (a, b) {
+ var al = a.leaked;
+ var bl = b.leaked;
+ return (al < bl) - (al > bl); });
+ // Output the top leaks
+ if (top > l.length) { top = l.length; }
+ for (var i = 0; i < top; i++) {
+ Debug.format("%w\n", l[i].toString());
+ }
+ if (top < l.length) {
+ Debug.write('...');
+ }
+
+ // Return the data for inspection
return l;
} else {
Debug.error('Call %w first', Debug.findNewObjects);
_______________________________________________
Laszlo-checkins mailing list
[email protected]
http://www.openlaszlo.org/mailman/listinfo/laszlo-checkins