tizen beta release
[profile/ivi/webkit-efl.git] / Source / WebCore / inspector / front-end / HeapSnapshotProxy.js
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.HeapSnapshotRealWorker = function()
32 {
33     this._worker = new Worker("HeapSnapshotWorker.js");
34     this._worker.addEventListener("message", this._messageReceived.bind(this), false);
35 }
36
37 WebInspector.HeapSnapshotRealWorker.prototype = {
38     _messageReceived: function(event)
39     {
40         this.dispatchEventToListeners("message", event.data);
41     },
42
43     postMessage: function(message)
44     {
45         this._worker.postMessage(message);
46     },
47
48     terminate: function()
49     {
50         this._worker.terminate();
51     }
52 };
53
54 WebInspector.HeapSnapshotRealWorker.prototype.__proto__ = WebInspector.Object.prototype;
55
56 WebInspector.HeapSnapshotFakeWorker = function()
57 {
58     this._dispatcher = new WebInspector.HeapSnapshotWorkerDispatcher(window, this._postMessageFromWorker.bind(this));
59 }
60
61 WebInspector.HeapSnapshotFakeWorker.prototype = {
62     postMessage: function(message)
63     {
64         function dispatch()
65         {
66             if (this._dispatcher)
67                 this._dispatcher.dispatchMessage({data: message});
68         }
69         setTimeout(dispatch.bind(this), 0);
70     },
71
72     terminate: function()
73     {
74         this._dispatcher = null;
75     },
76
77     _postMessageFromWorker: function(message)
78     {
79         function send()
80         {
81             this.dispatchEventToListeners("message", message);
82         }
83         setTimeout(send.bind(this), 0);
84     }
85 };
86
87 WebInspector.HeapSnapshotFakeWorker.prototype.__proto__ = WebInspector.Object.prototype;
88
89 WebInspector.HeapSnapshotWorker = function()
90 {
91     this._nextObjectId = 1;
92     this._nextCallId = 1;
93     this._callbacks = [];
94     this._previousCallbacks = [];
95     // There is no support for workers in Chromium DRT.
96     this._worker = typeof InspectorTest === "undefined" ? new WebInspector.HeapSnapshotRealWorker() : new WebInspector.HeapSnapshotFakeWorker();
97     this._worker.addEventListener("message", this._messageReceived.bind(this), false);
98 }
99
100 WebInspector.HeapSnapshotWorker.prototype = {
101     createObject: function(constructorName)
102     {
103         var proxyConstructorFunction = this._findFunction(constructorName + "Proxy");
104         var objectId = this._nextObjectId++;
105         var proxy = new proxyConstructorFunction(this, objectId);
106         this._postMessage({callId: this._nextCallId++, disposition: "create", objectId: objectId, methodName: constructorName});
107         return proxy;
108     },
109
110     dispose: function()
111     {
112         this._worker.terminate();
113         if (this._interval)
114             clearInterval(this._interval);
115     },
116
117     disposeObject: function(objectId)
118     {
119         this._postMessage({callId: this._nextCallId++, disposition: "dispose", objectId: objectId});
120     },
121
122     callGetter: function(callback, objectId, getterName)
123     {
124         var callId = this._nextCallId++;
125         this._callbacks[callId] = callback;
126         this._postMessage({callId: callId, disposition: "getter", objectId: objectId, methodName: getterName});
127     },
128
129     callFactoryMethod: function(callback, objectId, methodName, proxyConstructorName)
130     {
131         var callId = this._nextCallId++;
132         var methodArguments = Array.prototype.slice.call(arguments, 4);
133         var newObjectId = this._nextObjectId++;
134         var proxyConstructorFunction = this._findFunction(proxyConstructorName);
135         if (callback) {
136             function wrapCallback(remoteResult)
137             {
138                 callback(remoteResult ? new proxyConstructorFunction(this, newObjectId) : null);
139             }
140             this._callbacks[callId] = wrapCallback.bind(this);
141             this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
142             return null;
143         } else {
144             this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
145             return new proxyConstructorFunction(this, newObjectId);
146         }
147     },
148
149     callMethod: function(callback, objectId, methodName)
150     {
151         var callId = this._nextCallId++;
152         var methodArguments = Array.prototype.slice.call(arguments, 3);
153         if (callback)
154             this._callbacks[callId] = callback;
155         this._postMessage({callId: callId, disposition: "method", objectId: objectId, methodName: methodName, methodArguments: methodArguments});
156     },
157
158     startCheckingForLongRunningCalls: function()
159     {
160         this._checkLongRunningCalls();
161         this._interval = setInterval(this._checkLongRunningCalls.bind(this), 300);
162     },
163
164     _checkLongRunningCalls: function()
165     {
166         for (var callId in this._previousCallbacks)
167             if (!(callId in this._callbacks))
168                 delete this._previousCallbacks[callId];
169         var hasLongRunningCalls = false;
170         for (callId in this._previousCallbacks) {
171             hasLongRunningCalls = true;
172             break;
173         }
174         this.dispatchEventToListeners("wait", hasLongRunningCalls);
175         for (callId in this._callbacks)
176             this._previousCallbacks[callId] = true;
177     },
178
179     _findFunction: function(name)
180     {
181         var path = name.split(".");
182         var result = window;
183         for (var i = 0; i < path.length; ++i)
184             result = result[path[i]];
185         return result;
186     },
187
188     _messageReceived: function(event)
189     {
190         var data = event.data;
191         if (!this._callbacks[data.callId])
192             return;
193         var callback = this._callbacks[data.callId];
194         delete this._callbacks[data.callId];
195         callback(data.result);
196     },
197
198     _postMessage: function(message)
199     {
200         this._worker.postMessage(message);
201     }
202 };
203
204 WebInspector.HeapSnapshotWorker.prototype.__proto__ = WebInspector.Object.prototype;
205
206 WebInspector.HeapSnapshotProxyObject = function(worker, objectId)
207 {
208     this._worker = worker;
209     this._objectId = objectId;
210 }
211
212 WebInspector.HeapSnapshotProxyObject.prototype = {
213     _callWorker: function(workerMethodName, args)
214     {
215         args.splice(1, 0, this._objectId);
216         return this._worker[workerMethodName].apply(this._worker, args);
217     },
218
219     dispose: function()
220     {
221         this._worker.disposeObject(this._objectId);
222     },
223
224     disposeWorker: function()
225     {
226         this._worker.dispose();
227     },
228
229     callFactoryMethod: function(callback, methodName, proxyConstructorName)
230     {
231         return this._callWorker("callFactoryMethod", Array.prototype.slice.call(arguments, 0));
232     },
233
234     callGetter: function(callback, getterName)
235     {
236         return this._callWorker("callGetter", Array.prototype.slice.call(arguments, 0));
237     },
238
239     callMethod: function(callback, methodName)
240     {
241         return this._callWorker("callMethod", Array.prototype.slice.call(arguments, 0));
242     },
243
244     get worker() {
245         return this._worker;
246     }
247 };
248
249 WebInspector.HeapSnapshotLoaderProxy = function(worker, objectId)
250 {
251     WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
252     this._loading = false;
253     this._loaded = false;
254 }
255
256 WebInspector.HeapSnapshotLoaderProxy.prototype = {
257     finishLoading: function(callback)
258     {
259         if (!this._loading)
260             return false;
261         var loadCallbacks = this._onLoadCallbacks;
262         loadCallbacks.splice(0, 0, callback);
263         delete this._onLoadCallbacks;
264         this._loading = false;
265         this._loaded = true;
266         function callLoadCallbacks(snapshotProxy)
267         {
268             for (var i = 0; i < loadCallbacks.length; ++i)
269                 loadCallbacks[i](snapshotProxy);
270         }
271         function updateStaticData(snapshotProxy)
272         {
273             this.dispose();
274             snapshotProxy.updateStaticData(callLoadCallbacks);
275         }
276         this.callFactoryMethod(updateStaticData.bind(this), "finishLoading", "WebInspector.HeapSnapshotProxy");
277         return true;
278     },
279
280     get loaded()
281     {
282         return this._loaded;
283     },
284
285     startLoading: function(callback)
286     {
287         if (!this._loading) {
288             this._onLoadCallbacks = [callback];
289             this._loading = true;
290             return true;
291         } else {
292             this._onLoadCallbacks.push(callback);
293             return false;
294         }
295     },
296
297     pushJSONChunk: function(chunk)
298     {
299         if (!this._loading)
300             return;
301         this.callMethod(null, "pushJSONChunk", chunk);
302     }
303 };
304
305 WebInspector.HeapSnapshotLoaderProxy.prototype.__proto__ = WebInspector.HeapSnapshotProxyObject.prototype;
306
307 WebInspector.HeapSnapshotProxy = function(worker, objectId)
308 {
309     WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
310 }
311
312 WebInspector.HeapSnapshotProxy.prototype = {
313     aggregates: function(sortedIndexes, key, filter, callback)
314     {
315         this.callMethod(callback, "aggregates", sortedIndexes, key, filter);
316     },
317
318     createDiff: function(className)
319     {
320         return this.callFactoryMethod(null, "createDiff",  "WebInspector.HeapSnapshotsDiffProxy", className);
321     },
322
323     createEdgesProvider: function(nodeIndex, filter)
324     {
325         return this.callFactoryMethod(null, "createEdgesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
326     },
327
328     createNodesProvider: function(filter)
329     {
330         return this.callFactoryMethod(null, "createNodesProvider", "WebInspector.HeapSnapshotProviderProxy", filter);
331     },
332
333     createNodesProviderForClass: function(className, aggregatesKey)
334     {
335         return this.callFactoryMethod(null, "createNodesProviderForClass", "WebInspector.HeapSnapshotProviderProxy", className, aggregatesKey);
336     },
337
338     createNodesProviderForDominator: function(nodeIndex, filter)
339     {
340         return this.callFactoryMethod(null, "createNodesProviderForDominator", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
341     },
342
343     createPathFinder: function(targetNodeIndex)
344     {
345         return this.callFactoryMethod(null, "createPathFinder", "WebInspector.HeapSnapshotPathFinderProxy", targetNodeIndex);
346     },
347
348     dispose: function()
349     {
350         this.disposeWorker();
351     },
352
353     finishLoading: function()
354     {
355         return false;
356     },
357
358     get loaded()
359     {
360         return !!this._objectId;
361     },
362
363     get maxNodeId()
364     {
365         return this._staticData.maxNodeId;
366     },
367
368     get nodeCount()
369     {
370         return this._staticData.nodeCount;
371     },
372
373     nodeFieldValuesByIndex: function(fieldName, indexes, callback)
374     {
375         this.callMethod(callback, "nodeFieldValuesByIndex", fieldName, indexes);
376     },
377
378     get nodeFlags()
379     {
380         return this._staticData.nodeFlags;
381     },
382
383     pushBaseIds: function(snapshotId, className, nodeIds)
384     {
385         this.callMethod(null, "pushBaseIds", snapshotId, className, nodeIds);
386     },
387
388     get rootNodeIndex()
389     {
390         return this._staticData.rootNodeIndex;
391     },
392
393     updateStaticData: function(callback)
394     {
395         function dataReceived(staticData)
396         {
397             this._staticData = staticData;
398             callback(this);
399         }
400         this.callMethod(dataReceived.bind(this), "updateStaticData");
401     },
402
403     startLoading: function(callback)
404     {
405         setTimeout(callback.bind(null, this), 0);
406         return false;
407     },
408
409     get totalSize()
410     {
411         return this._staticData.totalSize;
412     },
413
414     get uid()
415     {
416         return this._staticData.uid;
417     }
418 };
419
420 WebInspector.HeapSnapshotProxy.prototype.__proto__ = WebInspector.HeapSnapshotProxyObject.prototype;
421
422 WebInspector.HeapSnapshotProviderProxy = function(worker, objectId)
423 {
424     WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
425 }
426
427 WebInspector.HeapSnapshotProviderProxy.prototype = {
428     isEmpty: function(callback)
429     {
430         this.callGetter(callback, "isEmpty");
431     },
432
433     serializeNextItems: function(count, callback)
434     {
435         this.callMethod(callback, "serializeNextItems", count);
436     },
437
438     sortAndRewind: function(comparator, callback)
439     {
440         this.callMethod(callback, "sortAndRewind", comparator);
441     }
442 };
443
444 WebInspector.HeapSnapshotProviderProxy.prototype.__proto__ = WebInspector.HeapSnapshotProxyObject.prototype;
445
446 WebInspector.HeapSnapshotPathFinderProxy = function(worker, objectId)
447 {
448     WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
449 }
450
451 WebInspector.HeapSnapshotPathFinderProxy.prototype = {
452     findNext: function(callback)
453     {
454         this.callMethod(callback, "findNext");
455     },
456
457     updateRoots: function(filter)
458     {
459         this.callMethod(null, "updateRoots", filter);
460     }
461 };
462
463 WebInspector.HeapSnapshotPathFinderProxy.prototype.__proto__ = WebInspector.HeapSnapshotProxyObject.prototype;
464
465 WebInspector.HeapSnapshotsDiffProxy = function(worker, objectId)
466 {
467     WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
468 }
469
470 WebInspector.HeapSnapshotsDiffProxy.prototype = {
471     calculate: function(callback)
472     {
473         this.callMethod(callback, "calculate");
474     },
475
476     pushBaseIds: function(baseIds)
477     {
478         this.callMethod(null, "pushBaseIds", baseIds);
479     },
480
481     pushBaseSelfSizes: function(baseSelfSizes)
482     {
483         this.callMethod(null, "pushBaseSelfSizes", baseSelfSizes);
484     }
485 };
486
487 WebInspector.HeapSnapshotsDiffProxy.prototype.__proto__ = WebInspector.HeapSnapshotProxyObject.prototype;