2
* Copyright (C) 2011 Google Inc. All rights reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are
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
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.
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.
33
* @extends {WebInspector.Object}
35
WebInspector.HeapSnapshotWorkerWrapper = function()
39
WebInspector.HeapSnapshotWorkerWrapper.prototype = {
40
postMessage: function(message)
47
__proto__: WebInspector.Object.prototype
52
* @extends {WebInspector.HeapSnapshotWorkerWrapper}
54
WebInspector.HeapSnapshotRealWorker = function()
56
this._worker = new Worker("HeapSnapshotWorker.js");
57
this._worker.addEventListener("message", this._messageReceived.bind(this), false);
60
WebInspector.HeapSnapshotRealWorker.prototype = {
61
_messageReceived: function(event)
63
var message = event.data;
64
if ("callId" in message)
65
this.dispatchEventToListeners("message", message);
67
if (message.object !== "console") {
68
console.log(WebInspector.UIString("Worker asks to call a method '%s' on an unsupported object '%s'.", message.method, message.object));
71
if (message.method !== "log" && message.method !== "info" && message.method !== "error") {
72
console.log(WebInspector.UIString("Worker asks to call an unsupported method '%s' on the console object.", message.method));
75
console[message.method].apply(window[message.object], message.arguments);
79
postMessage: function(message)
81
this._worker.postMessage(message);
86
this._worker.terminate();
89
__proto__: WebInspector.HeapSnapshotWorkerWrapper.prototype
96
WebInspector.AsyncTaskQueue = function()
99
this._isTimerSheduled = false;
102
WebInspector.AsyncTaskQueue.prototype = {
104
* @param {function()} task
106
addTask: function(task)
108
this._queue.push(task);
109
this._scheduleTimer();
112
_onTimeout: function()
114
this._isTimerSheduled = false;
115
var queue = this._queue;
117
for (var i = 0; i < queue.length; i++) {
121
console.error("Exception while running task: " + e.stack);
124
this._scheduleTimer();
127
_scheduleTimer: function()
129
if (this._queue.length && !this._isTimerSheduled) {
130
setTimeout(this._onTimeout.bind(this), 0);
131
this._isTimerSheduled = true;
138
* @extends {WebInspector.HeapSnapshotWorkerWrapper}
140
WebInspector.HeapSnapshotFakeWorker = function()
142
this._dispatcher = new WebInspector.HeapSnapshotWorkerDispatcher(window, this._postMessageFromWorker.bind(this));
143
this._asyncTaskQueue = new WebInspector.AsyncTaskQueue();
146
WebInspector.HeapSnapshotFakeWorker.prototype = {
147
postMessage: function(message)
151
if (this._dispatcher)
152
this._dispatcher.dispatchMessage({data: message});
154
this._asyncTaskQueue.addTask(dispatch.bind(this));
157
terminate: function()
159
this._dispatcher = null;
162
_postMessageFromWorker: function(message)
166
this.dispatchEventToListeners("message", message);
168
this._asyncTaskQueue.addTask(send.bind(this));
171
__proto__: WebInspector.HeapSnapshotWorkerWrapper.prototype
177
* @extends {WebInspector.Object}
179
WebInspector.HeapSnapshotWorker = function()
181
this._nextObjectId = 1;
182
this._nextCallId = 1;
183
this._callbacks = [];
184
this._previousCallbacks = [];
185
// There is no support for workers in Chromium DRT.
186
this._worker = typeof InspectorTest === "undefined" ? new WebInspector.HeapSnapshotRealWorker() : new WebInspector.HeapSnapshotFakeWorker();
187
this._worker.addEventListener("message", this._messageReceived, this);
190
WebInspector.HeapSnapshotWorker.prototype = {
191
createObject: function(constructorName)
193
var proxyConstructorFunction = this._findFunction(constructorName + "Proxy");
194
var objectId = this._nextObjectId++;
195
var proxy = new proxyConstructorFunction(this, objectId);
196
this._postMessage({callId: this._nextCallId++, disposition: "create", objectId: objectId, methodName: constructorName});
202
this._worker.terminate();
204
clearInterval(this._interval);
207
disposeObject: function(objectId)
209
this._postMessage({callId: this._nextCallId++, disposition: "dispose", objectId: objectId});
212
callGetter: function(callback, objectId, getterName)
214
var callId = this._nextCallId++;
215
this._callbacks[callId] = callback;
216
this._postMessage({callId: callId, disposition: "getter", objectId: objectId, methodName: getterName});
219
callFactoryMethod: function(callback, objectId, methodName, proxyConstructorName)
221
var callId = this._nextCallId++;
222
var methodArguments = Array.prototype.slice.call(arguments, 4);
223
var newObjectId = this._nextObjectId++;
224
var proxyConstructorFunction = this._findFunction(proxyConstructorName);
226
function wrapCallback(remoteResult)
228
callback(remoteResult ? new proxyConstructorFunction(this, newObjectId) : null);
230
this._callbacks[callId] = wrapCallback.bind(this);
231
this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
234
this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
235
return new proxyConstructorFunction(this, newObjectId);
239
callMethod: function(callback, objectId, methodName)
241
var callId = this._nextCallId++;
242
var methodArguments = Array.prototype.slice.call(arguments, 3);
244
this._callbacks[callId] = callback;
245
this._postMessage({callId: callId, disposition: "method", objectId: objectId, methodName: methodName, methodArguments: methodArguments});
248
startCheckingForLongRunningCalls: function()
252
this._checkLongRunningCalls();
253
this._interval = setInterval(this._checkLongRunningCalls.bind(this), 300);
256
_checkLongRunningCalls: function()
258
for (var callId in this._previousCallbacks)
259
if (!(callId in this._callbacks))
260
delete this._previousCallbacks[callId];
261
var hasLongRunningCalls = false;
262
for (callId in this._previousCallbacks) {
263
hasLongRunningCalls = true;
266
this.dispatchEventToListeners("wait", hasLongRunningCalls);
267
for (callId in this._callbacks)
268
this._previousCallbacks[callId] = true;
271
_findFunction: function(name)
273
var path = name.split(".");
275
for (var i = 0; i < path.length; ++i)
276
result = result[path[i]];
280
_messageReceived: function(event)
282
var data = event.data;
283
if (event.data.error) {
284
if (event.data.errorMethodName)
285
WebInspector.log(WebInspector.UIString("An error happened when a call for method '%s' was requested", event.data.errorMethodName));
286
WebInspector.log(event.data.errorCallStack);
287
delete this._callbacks[data.callId];
290
if (!this._callbacks[data.callId])
292
var callback = this._callbacks[data.callId];
293
delete this._callbacks[data.callId];
294
callback(data.result);
297
_postMessage: function(message)
299
this._worker.postMessage(message);
302
__proto__: WebInspector.Object.prototype
309
WebInspector.HeapSnapshotProxyObject = function(worker, objectId)
311
this._worker = worker;
312
this._objectId = objectId;
315
WebInspector.HeapSnapshotProxyObject.prototype = {
316
_callWorker: function(workerMethodName, args)
318
args.splice(1, 0, this._objectId);
319
return this._worker[workerMethodName].apply(this._worker, args);
324
this._worker.disposeObject(this._objectId);
327
disposeWorker: function()
329
this._worker.dispose();
333
* @param {...*} var_args
335
callFactoryMethod: function(callback, methodName, proxyConstructorName, var_args)
337
return this._callWorker("callFactoryMethod", Array.prototype.slice.call(arguments, 0));
340
callGetter: function(callback, getterName)
342
return this._callWorker("callGetter", Array.prototype.slice.call(arguments, 0));
346
* @param {...*} var_args
348
callMethod: function(callback, methodName, var_args)
350
return this._callWorker("callMethod", Array.prototype.slice.call(arguments, 0));
360
* @extends {WebInspector.HeapSnapshotProxyObject}
361
* @implements {WebInspector.OutputStream}
363
WebInspector.HeapSnapshotLoaderProxy = function(worker, objectId)
365
WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
366
this._pendingSnapshotConsumers = [];
369
WebInspector.HeapSnapshotLoaderProxy.prototype = {
371
* @param {function(WebInspector.HeapSnapshotProxy)} callback
373
addConsumer: function(callback)
375
this._pendingSnapshotConsumers.push(callback);
379
* @param {string} chunk
380
* @param {function(WebInspector.OutputStream)=} callback
382
write: function(chunk, callback)
384
this.callMethod(callback, "write", chunk);
389
function buildSnapshot()
391
this.callFactoryMethod(updateStaticData.bind(this), "buildSnapshot", "WebInspector.HeapSnapshotProxy");
393
function updateStaticData(snapshotProxy)
396
snapshotProxy.updateStaticData(notifyPendingConsumers.bind(this));
398
function notifyPendingConsumers(snapshotProxy)
400
for (var i = 0; i < this._pendingSnapshotConsumers.length; ++i)
401
this._pendingSnapshotConsumers[i](snapshotProxy);
402
this._pendingSnapshotConsumers = [];
404
this.callMethod(buildSnapshot.bind(this), "close");
407
__proto__: WebInspector.HeapSnapshotProxyObject.prototype
413
* @extends {WebInspector.HeapSnapshotProxyObject}
415
WebInspector.HeapSnapshotProxy = function(worker, objectId)
417
WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
420
WebInspector.HeapSnapshotProxy.prototype = {
421
aggregates: function(sortedIndexes, key, filter, callback)
423
this.callMethod(callback, "aggregates", sortedIndexes, key, filter);
426
aggregatesForDiff: function(callback)
428
this.callMethod(callback, "aggregatesForDiff");
431
calculateSnapshotDiff: function(baseSnapshotId, baseSnapshotAggregates, callback)
433
this.callMethod(callback, "calculateSnapshotDiff", baseSnapshotId, baseSnapshotAggregates);
436
nodeClassName: function(snapshotObjectId, callback)
438
this.callMethod(callback, "nodeClassName", snapshotObjectId);
441
dominatorIdsForNode: function(nodeIndex, callback)
443
this.callMethod(callback, "dominatorIdsForNode", nodeIndex);
446
createEdgesProvider: function(nodeIndex, filter)
448
return this.callFactoryMethod(null, "createEdgesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
451
createRetainingEdgesProvider: function(nodeIndex, filter)
453
return this.callFactoryMethod(null, "createRetainingEdgesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
456
createAddedNodesProvider: function(baseSnapshotId, className)
458
return this.callFactoryMethod(null, "createAddedNodesProvider", "WebInspector.HeapSnapshotProviderProxy", baseSnapshotId, className);
461
createDeletedNodesProvider: function(nodeIndexes)
463
return this.callFactoryMethod(null, "createDeletedNodesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndexes);
466
createNodesProvider: function(filter)
468
return this.callFactoryMethod(null, "createNodesProvider", "WebInspector.HeapSnapshotProviderProxy", filter);
471
createNodesProviderForClass: function(className, aggregatesKey)
473
return this.callFactoryMethod(null, "createNodesProviderForClass", "WebInspector.HeapSnapshotProviderProxy", className, aggregatesKey);
476
createNodesProviderForDominator: function(nodeIndex)
478
return this.callFactoryMethod(null, "createNodesProviderForDominator", "WebInspector.HeapSnapshotProviderProxy", nodeIndex);
483
this.disposeWorker();
488
return this._staticData.nodeCount;
493
return this._staticData.nodeFlags;
498
return this._staticData.rootNodeIndex;
501
updateStaticData: function(callback)
503
function dataReceived(staticData)
505
this._staticData = staticData;
508
this.callMethod(dataReceived.bind(this), "updateStaticData");
513
return this._staticData.totalSize;
518
return this._staticData.uid;
521
__proto__: WebInspector.HeapSnapshotProxyObject.prototype
527
* @extends {WebInspector.HeapSnapshotProxyObject}
529
WebInspector.HeapSnapshotProviderProxy = function(worker, objectId)
531
WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
534
WebInspector.HeapSnapshotProviderProxy.prototype = {
535
nodePosition: function(snapshotObjectId, callback)
537
this.callMethod(callback, "nodePosition", snapshotObjectId);
540
isEmpty: function(callback)
542
this.callMethod(callback, "isEmpty");
545
serializeItemsRange: function(startPosition, endPosition, callback)
547
this.callMethod(callback, "serializeItemsRange", startPosition, endPosition);
550
sortAndRewind: function(comparator, callback)
552
this.callMethod(callback, "sortAndRewind", comparator);
555
__proto__: WebInspector.HeapSnapshotProxyObject.prototype