Add manual tail calls to _recomputeAttrInfoForRows to avoid overflowing the call stack, bug 556151 0.7.1
authorPatrick Walton <pwalton@mozilla.com>
Wed, 07 Apr 2010 12:27:13 -0700
changeset 1233 6763defc2cecfc87b921120a65b6e313c1f23bbf
parent 1232 6cb24951159068f6a02dcba5f0daa30e1074d0ec
child 1234 406c1503b0a6b4daeeb10428832e7757b9c9b504
push id633
push userpwalton@mozilla.com
push dateWed, 07 Apr 2010 19:27:16 +0000
bugs556151
Add manual tail calls to _recomputeAttrInfoForRows to avoid overflowing the call stack, bug 556151
plugins/supported/syntax_manager/controllers/syntaxmanager.js
--- a/plugins/supported/syntax_manager/controllers/syntaxmanager.js
+++ b/plugins/supported/syntax_manager/controllers/syntaxmanager.js
@@ -398,27 +398,31 @@ exports.SyntaxManager = SC.Object.extend
 
         return mergedGroups;
     },
 
     // Runs the syntax highlighters. Returns the first unchanged row (i.e. the
     // row immediately following the row where the synchronization happened),
     // or null if the highlighting failed to synchronize before the end of the
     // range.
-    _recomputeAttrInfoForRows: function(startRow, endRow) {
+    _recomputeAttrInfoForRows: function(startRow, endRow, depth) {
         var promise = new Promise();
         var lineAttrInfo = this._lineAttrInfo;
 
         if (startRow === endRow) {
             // We succeeded only if we got to the end of the buffer.
             var result = startRow === lineAttrInfo.length ? startRow : false;
             promise.resolve(result);
             return promise;
         }
 
+        if (SC.none(depth)) {
+            depth = 0;
+        }
+
         var thisLineAttrInfo = lineAttrInfo[startRow];
         var line = this.getPath('textStorage.lines')[startRow];
 
         this._deepSyntaxInfoForLine(thisLineAttrInfo.snapshot, line).
             then(function(deepSyntaxInfo) {
                 thisLineAttrInfo.attrs =
                     deepSyntaxInfo.map(function(dsi) { return dsi.attrs; });
 
@@ -432,20 +436,33 @@ exports.SyntaxManager = SC.Object.extend
                     if (this._snapshotsEqual(oldSnapshot, newSnapshot)) {
                         promise.resolve(startRow + 1);
                         return;
                     }
 
                     nextLineAttrInfo.snapshot = newSnapshot;
                 }
 
-                this._recomputeAttrInfoForRows(startRow + 1, endRow).
-                    then(function(lastRow) {
-                        promise.resolve(lastRow);
-                    });
+                if (depth === 50) {
+                    // Do a "manual tail call" so that we don't overflow the
+                    // call stack. See bug 556151.
+                    window.setTimeout(function() {
+                        SC.run(function() {
+                            this._recomputeAttrInfoForRows(startRow + 1,
+                                endRow, 0).then(function(lastRow) {
+                                    promise.resolve(lastRow);
+                                });
+                        }.bind(this));
+                    }.bind(this), 0);
+                } else {
+                    this._recomputeAttrInfoForRows(startRow + 1, endRow,
+                        depth + 1).then(function(lastRow) {
+                            promise.resolve(lastRow);
+                        });
+                }
             }.bind(this));
 
         return promise;
     },
 
     // Invalidates all the highlighting.
     _reset: function() {
         var lineAttrInfo = [];