Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / front_end / profiler / HeapSnapshotProxy.js
blobf52f23b190cc2b6fadf78ddf80d29bfbbe7d786b
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  */
31 /**
32  * @constructor
33  * @param {function(string, *)} eventHandler
34  * @extends {WebInspector.Object}
35  */
36 WebInspector.HeapSnapshotWorkerProxy = function(eventHandler)
38     this._eventHandler = eventHandler;
39     this._nextObjectId = 1;
40     this._nextCallId = 1;
41     this._callbacks = [];
42     this._previousCallbacks = [];
43     this._worker = new WorkerRuntime.Worker("heap_snapshot_worker");
44     this._worker.onmessage = this._messageReceived.bind(this);
47 WebInspector.HeapSnapshotWorkerProxy.prototype = {
48     /**
49      * @param {number} profileUid
50      * @param {function(!WebInspector.HeapSnapshotProxy)} snapshotReceivedCallback
51      * @return {!WebInspector.HeapSnapshotLoaderProxy}
52      */
53     createLoader: function(profileUid, snapshotReceivedCallback)
54     {
55         var objectId = this._nextObjectId++;
56         var proxy = new WebInspector.HeapSnapshotLoaderProxy(this, objectId, profileUid, snapshotReceivedCallback);
57         this._postMessage({callId: this._nextCallId++, disposition: "create", objectId: objectId, methodName: "WebInspector.HeapSnapshotLoader"});
58         return proxy;
59     },
61     dispose: function()
62     {
63         this._worker.terminate();
64         if (this._interval)
65             clearInterval(this._interval);
66     },
68     disposeObject: function(objectId)
69     {
70         this._postMessage({callId: this._nextCallId++, disposition: "dispose", objectId: objectId});
71     },
73     evaluateForTest: function(script, callback)
74     {
75         var callId = this._nextCallId++;
76         this._callbacks[callId] = callback;
77         this._postMessage({callId: callId, disposition: "evaluateForTest", source: script});
78     },
80     /**
81      * @param {?function(...?)} callback
82      * @param {string} objectId
83      * @param {string} methodName
84      * @param {function(new:T, ...?)} proxyConstructor
85      * @return {?Object}
86      * @template T
87      */
88     callFactoryMethod: function(callback, objectId, methodName, proxyConstructor)
89     {
90         var callId = this._nextCallId++;
91         var methodArguments = Array.prototype.slice.call(arguments, 4);
92         var newObjectId = this._nextObjectId++;
94         /**
95          * @this {WebInspector.HeapSnapshotWorkerProxy}
96          */
97         function wrapCallback(remoteResult)
98         {
99             callback(remoteResult ? new proxyConstructor(this, newObjectId) : null);
100         }
102         if (callback) {
103             this._callbacks[callId] = wrapCallback.bind(this);
104             this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
105             return null;
106         } else {
107             this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
108             return new proxyConstructor(this, newObjectId);
109         }
110     },
112     /**
113      * @param {function(*)} callback
114      * @param {string} objectId
115      * @param {string} methodName
116      */
117     callMethod: function(callback, objectId, methodName)
118     {
119         var callId = this._nextCallId++;
120         var methodArguments = Array.prototype.slice.call(arguments, 3);
121         if (callback)
122             this._callbacks[callId] = callback;
123         this._postMessage({callId: callId, disposition: "method", objectId: objectId, methodName: methodName, methodArguments: methodArguments});
124     },
126     startCheckingForLongRunningCalls: function()
127     {
128         if (this._interval)
129             return;
130         this._checkLongRunningCalls();
131         this._interval = setInterval(this._checkLongRunningCalls.bind(this), 300);
132     },
134     _checkLongRunningCalls: function()
135     {
136         for (var callId in this._previousCallbacks)
137             if (!(callId in this._callbacks))
138                 delete this._previousCallbacks[callId];
139         var hasLongRunningCalls = false;
140         for (callId in this._previousCallbacks) {
141             hasLongRunningCalls = true;
142             break;
143         }
144         this.dispatchEventToListeners("wait", hasLongRunningCalls);
145         for (callId in this._callbacks)
146             this._previousCallbacks[callId] = true;
147     },
149     /**
150      * @param {!MessageEvent} event
151      */
152     _messageReceived: function(event)
153     {
154         var data = event.data;
155         if (data.eventName) {
156             if (this._eventHandler)
157                 this._eventHandler(data.eventName, data.data);
158             return;
159         }
160         if (data.error) {
161             if (data.errorMethodName)
162                 WebInspector.console.error(WebInspector.UIString("An error occurred when a call to method '%s' was requested", data.errorMethodName));
163             WebInspector.console.error(data["errorCallStack"]);
164             delete this._callbacks[data.callId];
165             return;
166         }
167         if (!this._callbacks[data.callId])
168             return;
169         var callback = this._callbacks[data.callId];
170         delete this._callbacks[data.callId];
171         callback(data.result);
172     },
174     _postMessage: function(message)
175     {
176         this._worker.postMessage(message);
177     },
179     __proto__: WebInspector.Object.prototype
184  * @constructor
185  * @param {!WebInspector.HeapSnapshotWorkerProxy} worker
186  * @param {number} objectId
187  */
188 WebInspector.HeapSnapshotProxyObject = function(worker, objectId)
190     this._worker = worker;
191     this._objectId = objectId;
194 WebInspector.HeapSnapshotProxyObject.prototype = {
195     /**
196      * @param {string} workerMethodName
197      * @param {!Array.<*>} args
198      */
199     _callWorker: function(workerMethodName, args)
200     {
201         args.splice(1, 0, this._objectId);
202         return this._worker[workerMethodName].apply(this._worker, args);
203     },
205     dispose: function()
206     {
207         this._worker.disposeObject(this._objectId);
208     },
210     disposeWorker: function()
211     {
212         this._worker.dispose();
213     },
215     /**
216      * @param {?function(...?)} callback
217      * @param {string} methodName
218      * @param {function (new:T, ...?)} proxyConstructor
219      * @param {...*} var_args
220      * @return {!T}
221      * @template T
222      */
223     callFactoryMethod: function(callback, methodName, proxyConstructor, var_args)
224     {
225         return this._callWorker("callFactoryMethod", Array.prototype.slice.call(arguments, 0));
226     },
228     /**
229      * @param {function(T)|undefined} callback
230      * @param {string} methodName
231      * @param {...*} var_args
232      * @return {*}
233      * @template T
234      */
235     callMethod: function(callback, methodName, var_args)
236     {
237         return this._callWorker("callMethod", Array.prototype.slice.call(arguments, 0));
238     },
240     /**
241      * @param {string} methodName
242      * @param {...*} var_args
243      * @return {!Promise.<?T>}
244      * @template T
245      */
246     _callMethodPromise: function(methodName, var_args)
247     {
248         /**
249          * @param {!Array.<*>} args
250          * @param {function(?T)} fulfill
251          * @this {WebInspector.HeapSnapshotProxyObject}
252          * @template T
253          */
254         function action(args, fulfill)
255         {
256             this._callWorker("callMethod", [fulfill].concat(args));
257         }
258         return new Promise(action.bind(this, Array.prototype.slice.call(arguments)));
259     }
263  * @constructor
264  * @extends {WebInspector.HeapSnapshotProxyObject}
265  * @implements {WebInspector.OutputStream}
266  * @param {!WebInspector.HeapSnapshotWorkerProxy} worker
267  * @param {number} objectId
268  * @param {number} profileUid
269  * @param {function(!WebInspector.HeapSnapshotProxy)} snapshotReceivedCallback
270  */
271 WebInspector.HeapSnapshotLoaderProxy = function(worker, objectId, profileUid, snapshotReceivedCallback)
273     WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
274     this._profileUid = profileUid;
275     this._snapshotReceivedCallback = snapshotReceivedCallback;
278 WebInspector.HeapSnapshotLoaderProxy.prototype = {
279     /**
280      * @override
281      * @param {string} chunk
282      * @param {function(!WebInspector.OutputStream)=} callback
283      */
284     write: function(chunk, callback)
285     {
286         this.callMethod(callback, "write", chunk);
287     },
289     /**
290      * @override
291      * @param {function()=} callback
292      */
293     close: function(callback)
294     {
295         /**
296          * @this {WebInspector.HeapSnapshotLoaderProxy}
297          */
298         function buildSnapshot()
299         {
300             if (callback)
301                 callback();
302             var showHiddenData = WebInspector.moduleSetting("showAdvancedHeapSnapshotProperties").get();
303             this.callFactoryMethod(updateStaticData.bind(this), "buildSnapshot", WebInspector.HeapSnapshotProxy, showHiddenData);
304         }
306         /**
307          * @param {!WebInspector.HeapSnapshotProxy} snapshotProxy
308          * @this {WebInspector.HeapSnapshotLoaderProxy}
309          */
310         function updateStaticData(snapshotProxy)
311         {
312             this.dispose();
313             snapshotProxy.setProfileUid(this._profileUid);
314             snapshotProxy.updateStaticData(this._snapshotReceivedCallback.bind(this));
315         }
317         this.callMethod(buildSnapshot.bind(this), "close");
318     },
320     __proto__: WebInspector.HeapSnapshotProxyObject.prototype
325  * @constructor
326  * @extends {WebInspector.HeapSnapshotProxyObject}
327  * @param {!WebInspector.HeapSnapshotWorkerProxy} worker
328  * @param {number} objectId
329  */
330 WebInspector.HeapSnapshotProxy = function(worker, objectId)
332     WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
333     /** @type {?WebInspector.HeapSnapshotCommon.StaticData} */
334     this._staticData = null;
337 WebInspector.HeapSnapshotProxy.prototype = {
338     /**
339      * @param {!WebInspector.HeapSnapshotCommon.SearchConfig} searchConfig
340      * @param {!WebInspector.HeapSnapshotCommon.NodeFilter} filter
341      * @return {!Promise<!Array<number>>}
342      */
343     search: function(searchConfig, filter)
344     {
345         return this._callMethodPromise("search", searchConfig, filter);
346     },
348     /**
349      * @param {!WebInspector.HeapSnapshotCommon.NodeFilter} filter
350      * @param {function(!Object.<string, !WebInspector.HeapSnapshotCommon.Aggregate>)} callback
351      */
352     aggregatesWithFilter: function(filter, callback)
353     {
354         this.callMethod(callback, "aggregatesWithFilter", filter);
355     },
357     aggregatesForDiff: function(callback)
358     {
359         this.callMethod(callback, "aggregatesForDiff");
360     },
362     calculateSnapshotDiff: function(baseSnapshotId, baseSnapshotAggregates, callback)
363     {
364         this.callMethod(callback, "calculateSnapshotDiff", baseSnapshotId, baseSnapshotAggregates);
365     },
367     /**
368      * @param {number} snapshotObjectId
369      * @return {!Promise<?string>}
370      */
371     nodeClassName: function(snapshotObjectId)
372     {
373         return this._callMethodPromise("nodeClassName", snapshotObjectId);
374     },
376     /**
377      * @param {number} nodeIndex
378      * @return {!WebInspector.HeapSnapshotProviderProxy}
379      */
380     createEdgesProvider: function(nodeIndex)
381     {
382         return this.callFactoryMethod(null, "createEdgesProvider", WebInspector.HeapSnapshotProviderProxy, nodeIndex);
383     },
385     /**
386      * @param {number} nodeIndex
387      * @return {!WebInspector.HeapSnapshotProviderProxy}
388      */
389     createRetainingEdgesProvider: function(nodeIndex)
390     {
391         return this.callFactoryMethod(null, "createRetainingEdgesProvider", WebInspector.HeapSnapshotProviderProxy, nodeIndex);
392     },
394     /**
395      * @param {string} baseSnapshotId
396      * @param {string} className
397      * @return {?WebInspector.HeapSnapshotProviderProxy}
398      */
399     createAddedNodesProvider: function(baseSnapshotId, className)
400     {
401         return this.callFactoryMethod(null, "createAddedNodesProvider", WebInspector.HeapSnapshotProviderProxy, baseSnapshotId, className);
402     },
404     /**
405      * @param {!Array.<number>} nodeIndexes
406      * @return {?WebInspector.HeapSnapshotProviderProxy}
407      */
408     createDeletedNodesProvider: function(nodeIndexes)
409     {
410         return this.callFactoryMethod(null, "createDeletedNodesProvider", WebInspector.HeapSnapshotProviderProxy, nodeIndexes);
411     },
413     /**
414      * @param {function(*):boolean} filter
415      * @return {?WebInspector.HeapSnapshotProviderProxy}
416      */
417     createNodesProvider: function(filter)
418     {
419         return this.callFactoryMethod(null, "createNodesProvider", WebInspector.HeapSnapshotProviderProxy, filter);
420     },
422     /**
423      * @param {string} className
424      * @param {!WebInspector.HeapSnapshotCommon.NodeFilter} nodeFilter
425      * @return {?WebInspector.HeapSnapshotProviderProxy}
426      */
427     createNodesProviderForClass: function(className, nodeFilter)
428     {
429         return this.callFactoryMethod(null, "createNodesProviderForClass", WebInspector.HeapSnapshotProviderProxy, className, nodeFilter);
430     },
432     allocationTracesTops: function(callback)
433     {
434         this.callMethod(callback, "allocationTracesTops");
435     },
437     /**
438      * @param {number} nodeId
439      * @param {function(!WebInspector.HeapSnapshotCommon.AllocationNodeCallers)} callback
440      */
441     allocationNodeCallers: function(nodeId, callback)
442     {
443         this.callMethod(callback, "allocationNodeCallers", nodeId);
444     },
446     /**
447      * @param {number} nodeIndex
448      * @param {function(?Array.<!WebInspector.HeapSnapshotCommon.AllocationStackFrame>)} callback
449      */
450     allocationStack: function(nodeIndex, callback)
451     {
452         this.callMethod(callback, "allocationStack", nodeIndex);
453     },
455     dispose: function()
456     {
457         throw new Error("Should never be called");
458     },
460     get nodeCount()
461     {
462         return this._staticData.nodeCount;
463     },
465     get rootNodeIndex()
466     {
467         return this._staticData.rootNodeIndex;
468     },
470     updateStaticData: function(callback)
471     {
472         /**
473          * @param {!WebInspector.HeapSnapshotCommon.StaticData} staticData
474          * @this {WebInspector.HeapSnapshotProxy}
475          */
476         function dataReceived(staticData)
477         {
478             this._staticData = staticData;
479             callback(this);
480         }
481         this.callMethod(dataReceived.bind(this), "updateStaticData");
482     },
484     /**
485      * @return {!Promise.<!WebInspector.HeapSnapshotCommon.Statistics>}
486      */
487     getStatistics: function()
488     {
489         return this._callMethodPromise("getStatistics");
490     },
492     /**
493      * @return {!Promise.<?WebInspector.HeapSnapshotCommon.Samples>}
494      */
495     getSamples: function()
496     {
497         return this._callMethodPromise("getSamples");
498     },
500     get totalSize()
501     {
502         return this._staticData.totalSize;
503     },
505     get uid()
506     {
507         return this._profileUid;
508     },
510     setProfileUid: function(profileUid)
511     {
512         this._profileUid = profileUid;
513     },
515     /**
516      * @return {number}
517      */
518     maxJSObjectId: function()
519     {
520         return this._staticData.maxJSObjectId;
521     },
523     __proto__: WebInspector.HeapSnapshotProxyObject.prototype
528  * @constructor
529  * @extends {WebInspector.HeapSnapshotProxyObject}
530  * @implements {WebInspector.HeapSnapshotGridNode.ChildrenProvider}
531  * @param {!WebInspector.HeapSnapshotWorkerProxy} worker
532  * @param {number} objectId
533  */
534 WebInspector.HeapSnapshotProviderProxy = function(worker, objectId)
536     WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
539 WebInspector.HeapSnapshotProviderProxy.prototype = {
540     /**
541      * @override
542      * @param {number} snapshotObjectId
543      * @return {!Promise<number>}
544      */
545     nodePosition: function(snapshotObjectId)
546     {
547         return this._callMethodPromise("nodePosition", snapshotObjectId);
548     },
550     /**
551      * @override
552      * @param {function(boolean)} callback
553      */
554     isEmpty: function(callback)
555     {
556         this.callMethod(callback, "isEmpty");
557     },
559     /**
560      * @override
561      * @param {number} startPosition
562      * @param {number} endPosition
563      * @param {function(!WebInspector.HeapSnapshotCommon.ItemsRange)} callback
564      */
565     serializeItemsRange: function(startPosition, endPosition, callback)
566     {
567         this.callMethod(callback, "serializeItemsRange", startPosition, endPosition);
568     },
570     /**
571      * @override
572      * @param {!WebInspector.HeapSnapshotCommon.ComparatorConfig} comparator
573      * @return {!Promise<?>}
574      */
575     sortAndRewind: function(comparator)
576     {
577         return this._callMethodPromise("sortAndRewind", comparator);
578     },
580     __proto__: WebInspector.HeapSnapshotProxyObject.prototype