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

Reply via email to