• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/**
32 * @constructor
33 * @param {function(string, *)} eventHandler
34 * @extends {WebInspector.Object}
35 */
36WebInspector.HeapSnapshotWorkerProxy = function(eventHandler)
37{
38    this._eventHandler = eventHandler;
39    this._nextObjectId = 1;
40    this._nextCallId = 1;
41    this._callbacks = [];
42    this._previousCallbacks = [];
43    this._worker = new Worker("profiler/heap_snapshot_worker/HeapSnapshotWorker.js");
44    this._worker.onmessage = this._messageReceived.bind(this);
45}
46
47WebInspector.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    },
60
61    dispose: function()
62    {
63        this._worker.terminate();
64        if (this._interval)
65            clearInterval(this._interval);
66    },
67
68    disposeObject: function(objectId)
69    {
70        this._postMessage({callId: this._nextCallId++, disposition: "dispose", objectId: objectId});
71    },
72
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    },
79
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++;
93
94        /**
95         * @this {WebInspector.HeapSnapshotWorkerProxy}
96         */
97        function wrapCallback(remoteResult)
98        {
99            callback(remoteResult ? new proxyConstructor(this, newObjectId) : null);
100        }
101
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    },
111
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    },
125
126    startCheckingForLongRunningCalls: function()
127    {
128        if (this._interval)
129            return;
130        this._checkLongRunningCalls();
131        this._interval = setInterval(this._checkLongRunningCalls.bind(this), 300);
132    },
133
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    },
148
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.messageSink.addMessage(WebInspector.UIString("An error occurred when a call to method '%s' was requested", data.errorMethodName));
163            WebInspector.messageSink.addMessage(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    },
173
174    _postMessage: function(message)
175    {
176        this._worker.postMessage(message);
177    },
178
179    __proto__: WebInspector.Object.prototype
180}
181
182
183/**
184 * @constructor
185 * @param {!WebInspector.HeapSnapshotWorkerProxy} worker
186 * @param {number} objectId
187 */
188WebInspector.HeapSnapshotProxyObject = function(worker, objectId)
189{
190    this._worker = worker;
191    this._objectId = objectId;
192}
193
194WebInspector.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    },
204
205    dispose: function()
206    {
207        this._worker.disposeObject(this._objectId);
208    },
209
210    disposeWorker: function()
211    {
212        this._worker.dispose();
213    },
214
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    },
227
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    }
239};
240
241/**
242 * @constructor
243 * @extends {WebInspector.HeapSnapshotProxyObject}
244 * @implements {WebInspector.OutputStream}
245 * @param {!WebInspector.HeapSnapshotWorkerProxy} worker
246 * @param {number} objectId
247 * @param {number} profileUid
248 * @param {function(!WebInspector.HeapSnapshotProxy)} snapshotReceivedCallback
249 */
250WebInspector.HeapSnapshotLoaderProxy = function(worker, objectId, profileUid, snapshotReceivedCallback)
251{
252    WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
253    this._profileUid = profileUid;
254    this._snapshotReceivedCallback = snapshotReceivedCallback;
255}
256
257WebInspector.HeapSnapshotLoaderProxy.prototype = {
258    /**
259     * @param {string} chunk
260     * @param {function(!WebInspector.OutputStream)=} callback
261     */
262    write: function(chunk, callback)
263    {
264        this.callMethod(callback, "write", chunk);
265    },
266
267    /**
268     * @param {function()=} callback
269     */
270    close: function(callback)
271    {
272        /**
273         * @this {WebInspector.HeapSnapshotLoaderProxy}
274         */
275        function buildSnapshot()
276        {
277            if (callback)
278                callback();
279            var showHiddenData = WebInspector.settings.showAdvancedHeapSnapshotProperties.get();
280            this.callFactoryMethod(updateStaticData.bind(this), "buildSnapshot", WebInspector.HeapSnapshotProxy, showHiddenData);
281        }
282
283        /**
284         * @param {!WebInspector.HeapSnapshotProxy} snapshotProxy
285         * @this {WebInspector.HeapSnapshotLoaderProxy}
286         */
287        function updateStaticData(snapshotProxy)
288        {
289            this.dispose();
290            snapshotProxy.setProfileUid(this._profileUid);
291            snapshotProxy.updateStaticData(this._snapshotReceivedCallback.bind(this));
292        }
293
294        this.callMethod(buildSnapshot.bind(this), "close");
295    },
296
297    __proto__: WebInspector.HeapSnapshotProxyObject.prototype
298}
299
300
301/**
302 * @constructor
303 * @extends {WebInspector.HeapSnapshotProxyObject}
304 * @param {!WebInspector.HeapSnapshotWorkerProxy} worker
305 * @param {number} objectId
306 */
307WebInspector.HeapSnapshotProxy = function(worker, objectId)
308{
309    WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
310    /** @type {?WebInspector.HeapSnapshotCommon.StaticData} */
311    this._staticData = null;
312}
313
314WebInspector.HeapSnapshotProxy.prototype = {
315    /**
316     * @param {!WebInspector.HeapSnapshotCommon.NodeFilter} filter
317     * @param {function(!Object.<string, !WebInspector.HeapSnapshotCommon.Aggregate>)} callback
318     */
319    aggregatesWithFilter: function(filter, callback)
320    {
321        this.callMethod(callback, "aggregatesWithFilter", filter);
322    },
323
324    aggregatesForDiff: function(callback)
325    {
326        this.callMethod(callback, "aggregatesForDiff");
327    },
328
329    calculateSnapshotDiff: function(baseSnapshotId, baseSnapshotAggregates, callback)
330    {
331        this.callMethod(callback, "calculateSnapshotDiff", baseSnapshotId, baseSnapshotAggregates);
332    },
333
334    nodeClassName: function(snapshotObjectId, callback)
335    {
336        this.callMethod(callback, "nodeClassName", snapshotObjectId);
337    },
338
339    dominatorIdsForNode: function(nodeIndex, callback)
340    {
341        this.callMethod(callback, "dominatorIdsForNode", nodeIndex);
342    },
343
344    /**
345     * @param {number} nodeIndex
346     * @return {!WebInspector.HeapSnapshotProviderProxy}
347     */
348    createEdgesProvider: function(nodeIndex)
349    {
350        return this.callFactoryMethod(null, "createEdgesProvider", WebInspector.HeapSnapshotProviderProxy, nodeIndex);
351    },
352
353    /**
354     * @param {number} nodeIndex
355     * @return {!WebInspector.HeapSnapshotProviderProxy}
356     */
357    createRetainingEdgesProvider: function(nodeIndex)
358    {
359        return this.callFactoryMethod(null, "createRetainingEdgesProvider", WebInspector.HeapSnapshotProviderProxy, nodeIndex);
360    },
361
362    /**
363     * @param {string} baseSnapshotId
364     * @param {string} className
365     * @return {?WebInspector.HeapSnapshotProviderProxy}
366     */
367    createAddedNodesProvider: function(baseSnapshotId, className)
368    {
369        return this.callFactoryMethod(null, "createAddedNodesProvider", WebInspector.HeapSnapshotProviderProxy, baseSnapshotId, className);
370    },
371
372    /**
373     * @param {!Array.<number>} nodeIndexes
374     * @return {?WebInspector.HeapSnapshotProviderProxy}
375     */
376    createDeletedNodesProvider: function(nodeIndexes)
377    {
378        return this.callFactoryMethod(null, "createDeletedNodesProvider", WebInspector.HeapSnapshotProviderProxy, nodeIndexes);
379    },
380
381    /**
382     * @param {function(*):boolean} filter
383     * @return {?WebInspector.HeapSnapshotProviderProxy}
384     */
385    createNodesProvider: function(filter)
386    {
387        return this.callFactoryMethod(null, "createNodesProvider", WebInspector.HeapSnapshotProviderProxy, filter);
388    },
389
390    /**
391     * @param {string} className
392     * @param {!WebInspector.HeapSnapshotCommon.NodeFilter} nodeFilter
393     * @return {?WebInspector.HeapSnapshotProviderProxy}
394     */
395    createNodesProviderForClass: function(className, nodeFilter)
396    {
397        return this.callFactoryMethod(null, "createNodesProviderForClass", WebInspector.HeapSnapshotProviderProxy, className, nodeFilter);
398    },
399
400    /**
401     * @param {number} nodeIndex
402     * @return {?WebInspector.HeapSnapshotProviderProxy}
403     */
404    createNodesProviderForDominator: function(nodeIndex)
405    {
406        return this.callFactoryMethod(null, "createNodesProviderForDominator", WebInspector.HeapSnapshotProviderProxy, nodeIndex);
407    },
408
409    allocationTracesTops: function(callback)
410    {
411        this.callMethod(callback, "allocationTracesTops");
412    },
413
414    /**
415     * @param {number} nodeId
416     * @param {function(!WebInspector.HeapSnapshotCommon.AllocationNodeCallers)} callback
417     */
418    allocationNodeCallers: function(nodeId, callback)
419    {
420        this.callMethod(callback, "allocationNodeCallers", nodeId);
421    },
422
423    /**
424     * @param {number} nodeIndex
425     * @param {function(?Array.<!WebInspector.HeapSnapshotCommon.AllocationStackFrame>)} callback
426     */
427    allocationStack: function(nodeIndex, callback)
428    {
429        this.callMethod(callback, "allocationStack", nodeIndex);
430    },
431
432    dispose: function()
433    {
434        throw new Error("Should never be called");
435    },
436
437    get nodeCount()
438    {
439        return this._staticData.nodeCount;
440    },
441
442    get rootNodeIndex()
443    {
444        return this._staticData.rootNodeIndex;
445    },
446
447    updateStaticData: function(callback)
448    {
449        /**
450         * @param {!WebInspector.HeapSnapshotCommon.StaticData} staticData
451         * @this {WebInspector.HeapSnapshotProxy}
452         */
453        function dataReceived(staticData)
454        {
455            this._staticData = staticData;
456            callback(this);
457        }
458        this.callMethod(dataReceived.bind(this), "updateStaticData");
459    },
460
461    /**
462     * @param {!function(!WebInspector.HeapSnapshotCommon.Statistics):void} callback
463     */
464    getStatistics: function(callback)
465    {
466        this.callMethod(callback, "getStatistics");
467    },
468
469    get totalSize()
470    {
471        return this._staticData.totalSize;
472    },
473
474    get uid()
475    {
476        return this._profileUid;
477    },
478
479    setProfileUid: function(profileUid)
480    {
481        this._profileUid = profileUid;
482    },
483
484    /**
485     * @return {number}
486     */
487    maxJSObjectId: function()
488    {
489        return this._staticData.maxJSObjectId;
490    },
491
492    __proto__: WebInspector.HeapSnapshotProxyObject.prototype
493}
494
495
496/**
497 * @constructor
498 * @extends {WebInspector.HeapSnapshotProxyObject}
499 * @implements {WebInspector.HeapSnapshotGridNode.ChildrenProvider}
500 * @param {!WebInspector.HeapSnapshotWorkerProxy} worker
501 * @param {number} objectId
502 */
503WebInspector.HeapSnapshotProviderProxy = function(worker, objectId)
504{
505    WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
506}
507
508WebInspector.HeapSnapshotProviderProxy.prototype = {
509    /**
510     * @override
511     * @param {number} snapshotObjectId
512     * @param {function(number)} callback
513     */
514    nodePosition: function(snapshotObjectId, callback)
515    {
516        this.callMethod(callback, "nodePosition", snapshotObjectId);
517    },
518
519    /**
520     * @override
521     * @param {function(boolean)} callback
522     */
523    isEmpty: function(callback)
524    {
525        this.callMethod(callback, "isEmpty");
526    },
527
528    /**
529     * @override
530     * @param {number} startPosition
531     * @param {number} endPosition
532     * @param {function(!WebInspector.HeapSnapshotCommon.ItemsRange)} callback
533     */
534    serializeItemsRange: function(startPosition, endPosition, callback)
535    {
536        this.callMethod(callback, "serializeItemsRange", startPosition, endPosition);
537    },
538
539    /**
540     * @override
541     * @param {!WebInspector.HeapSnapshotCommon.ComparatorConfig} comparator
542     * @param {function()} callback
543     */
544    sortAndRewind: function(comparator, callback)
545    {
546        this.callMethod(callback, "sortAndRewind", comparator);
547    },
548
549    __proto__: WebInspector.HeapSnapshotProxyObject.prototype
550}
551