1 /* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyrightdd 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 WebInspector.HeapSnapshotProxy = function() 32 { 33 this._snapshot = null; 34 } 35 36 WebInspector.HeapSnapshotProxy.prototype = { 37 _invokeGetter: function(getterName, callback) 38 { 39 function returnResult() 40 { 41 callback(this._snapshot[getterName]); 42 } 43 setTimeout(returnResult.bind(this), 0); 44 }, 45 46 aggregates: function(withNodeIndexes, callback) 47 { 48 function returnResult() 49 { 50 callback(this._snapshot.aggregates(withNodeIndexes)); 51 } 52 setTimeout(returnResult.bind(this), 0); 53 }, 54 55 _extractEdgeData: function(edge) 56 { 57 return {name: edge.name, node: this._extractNodeData(edge.node), nodeIndex: edge.nodeIndex, type: edge.type}; 58 }, 59 60 _extractNodeData: function(node) 61 { 62 return {id: node.id, name: node.name, nodeIndex: node.nodeIndex, retainedSize: node.retainedSize, selfSize: node.selfSize, type: node.type}; 63 }, 64 65 createDiff: function(className) 66 { 67 return new WebInspector.HeapSnapshotsDiffProxy(new WebInspector.HeapSnapshotsDiff(this._snapshot, className)); 68 }, 69 70 createEdgesProvider: function(nodeIndex, filter) 71 { 72 function createProvider() 73 { 74 if (filter) 75 filter = filter.bind(this._snapshot); 76 return new WebInspector.HeapSnapshotEdgesProvider(this._snapshot, nodeIndex, filter); 77 } 78 return new WebInspector.HeapSnapshotProviderProxy(createProvider.bind(this), this._extractEdgeData.bind(this)); 79 }, 80 81 createNodesProvider: function(filter) 82 { 83 function createProvider() 84 { 85 if (filter) 86 filter = filter.bind(this._snapshot); 87 return new WebInspector.HeapSnapshotNodesProvider(this._snapshot, filter); 88 } 89 return new WebInspector.HeapSnapshotProviderProxy(createProvider.bind(this), this._extractNodeData.bind(this)); 90 }, 91 92 createPathFinder: function(targetNodeIndex) 93 { 94 return new WebInspector.HeapSnapshotPathFinderProxy(new WebInspector.HeapSnapshotPathFinder(this._snapshot, targetNodeIndex)); 95 }, 96 97 dispose: function() 98 { 99 this._snapshot.dispose(); 100 }, 101 102 finishLoading: function(callback) 103 { 104 if (this._snapshot || !this._isLoading) 105 return false; 106 function parse() { 107 var rawSnapshot = JSON.parse(this._json); 108 var loadCallbacks = this._onLoadCallbacks; 109 loadCallbacks.splice(0, 0, callback); 110 delete this._onLoadCallback; 111 delete this._json; 112 delete this._isLoading; 113 this._snapshot = new WebInspector.HeapSnapshot(rawSnapshot); 114 this._nodeCount = this._snapshot.nodeCount; 115 this._rootNodeIndex = this._snapshot._rootNodeIndex; 116 this._totalSize = this._snapshot.totalSize; 117 for (var i = 0; i < loadCallbacks.length; ++i) 118 loadCallbacks[i](); 119 } 120 setTimeout(parse.bind(this), 0); 121 return true; 122 }, 123 124 get loaded() 125 { 126 return !!this._snapshot; 127 }, 128 129 get nodeCount() 130 { 131 return this._nodeCount; 132 }, 133 134 nodeFieldValuesByIndex: function(fieldName, indexes, callback) 135 { 136 function returnResult() 137 { 138 callback(this._snapshot.nodeFieldValuesByIndex(fieldName, indexes)); 139 } 140 setTimeout(returnResult.bind(this), 0); 141 }, 142 143 nodeIds: function(callback) 144 { 145 this._invokeGetter("nodeIds", callback); 146 }, 147 148 pushJSONChunk: function(chunk) 149 { 150 if (this.loaded || !this._isLoading) 151 return; 152 this._json += chunk; 153 }, 154 155 pushBaseIds: function(snapshotId, className, nodeIds) 156 { 157 this._snapshot.updateBaseNodeIds(snapshotId, className, nodeIds); 158 }, 159 160 get rootNodeIndex() 161 { 162 return this._rootNodeIndex; 163 }, 164 165 startLoading: function(callback) 166 { 167 if (this._snapshot) { 168 function asyncInvoke() 169 { 170 callback(); 171 } 172 setTimeout(callback, 0); 173 return false; 174 } else if (this._isLoading) { 175 this._onLoadCallbacks.push(callback); 176 return false; 177 } else { 178 this._isLoading = true; 179 this._onLoadCallbacks = [callback]; 180 this._json = ""; 181 return true; 182 } 183 }, 184 185 get totalSize() 186 { 187 return this._totalSize; 188 }, 189 190 get uid() 191 { 192 return this._snapshot.uid; 193 } 194 }; 195 196 WebInspector.HeapSnapshotProviderProxy = function(createProvider, extractData) 197 { 198 this._provider = createProvider(); 199 this._extractData = extractData; 200 } 201 202 WebInspector.HeapSnapshotProviderProxy.prototype = { 203 getNextItems: function(count, callback) 204 { 205 function returnResult() 206 { 207 var result = new Array(count); 208 for (var i = 0 ; i < count && this._provider.hasNext(); ++i, this._provider.next()) 209 result[i] = this._extractData(this._provider.item); 210 result.length = i; 211 callback(result, this._provider.hasNext(), this._provider.length); 212 } 213 setTimeout(returnResult.bind(this), 0); 214 }, 215 216 isEmpty: function(callback) 217 { 218 function returnResult() 219 { 220 callback(this._provider.isEmpty); 221 } 222 setTimeout(returnResult.bind(this), 0); 223 }, 224 225 sortAndRewind: function(comparator, callback) 226 { 227 function returnResult() 228 { 229 var result = this._provider.sort(comparator); 230 if (result) 231 this._provider.first(); 232 callback(result); 233 } 234 setTimeout(returnResult.bind(this), 0); 235 } 236 }; 237 238 WebInspector.HeapSnapshotPathFinderProxy = function(pathFinder) 239 { 240 this._pathFinder = pathFinder; 241 } 242 243 WebInspector.HeapSnapshotPathFinderProxy.prototype = { 244 findNext: function(callback) 245 { 246 function returnResult() 247 { 248 callback(this._pathFinder.findNext()); 249 } 250 setTimeout(returnResult.bind(this), 0); 251 }, 252 253 updateRoots: function(filter) 254 { 255 function asyncInvoke() 256 { 257 this._pathFinder.updateRoots(filter); 258 } 259 setTimeout(asyncInvoke.bind(this), 0); 260 } 261 }; 262 263 WebInspector.HeapSnapshotsDiffProxy = function(diff) 264 { 265 this._diff = diff; 266 } 267 268 WebInspector.HeapSnapshotsDiffProxy.prototype = { 269 calculate: function(callback) 270 { 271 function returnResult() 272 { 273 callback(this._diff.calculate()); 274 } 275 setTimeout(returnResult.bind(this), 0); 276 }, 277 278 pushBaseIds: function(baseSnapshotId, baseIds) 279 { 280 this._diff.baseIds = baseIds; 281 }, 282 283 pushBaseSelfSizes: function(baseSelfSizes) 284 { 285 this._diff.baseSelfSizes = baseSelfSizes; 286 } 287 }; 288