~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/inspector/front-end/HeapSnapshotProxy.js

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * @extends {WebInspector.Object}
 
34
 */
 
35
WebInspector.HeapSnapshotWorkerWrapper = function()
 
36
{
 
37
}
 
38
 
 
39
WebInspector.HeapSnapshotWorkerWrapper.prototype =  {
 
40
    postMessage: function(message)
 
41
    {
 
42
    },
 
43
    terminate: function()
 
44
    {
 
45
    },
 
46
 
 
47
    __proto__: WebInspector.Object.prototype
 
48
}
 
49
 
 
50
/**
 
51
 * @constructor
 
52
 * @extends {WebInspector.HeapSnapshotWorkerWrapper}
 
53
 */
 
54
WebInspector.HeapSnapshotRealWorker = function()
 
55
{
 
56
    this._worker = new Worker("HeapSnapshotWorker.js");
 
57
    this._worker.addEventListener("message", this._messageReceived.bind(this), false);
 
58
}
 
59
 
 
60
WebInspector.HeapSnapshotRealWorker.prototype = {
 
61
    _messageReceived: function(event)
 
62
    {
 
63
        var message = event.data;
 
64
        if ("callId" in message)
 
65
            this.dispatchEventToListeners("message", message);
 
66
        else {
 
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));
 
69
                return;
 
70
            }
 
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));
 
73
                return;
 
74
            }
 
75
            console[message.method].apply(window[message.object], message.arguments);
 
76
        }
 
77
    },
 
78
 
 
79
    postMessage: function(message)
 
80
    {
 
81
        this._worker.postMessage(message);
 
82
    },
 
83
 
 
84
    terminate: function()
 
85
    {
 
86
        this._worker.terminate();
 
87
    },
 
88
 
 
89
    __proto__: WebInspector.HeapSnapshotWorkerWrapper.prototype
 
90
}
 
91
 
 
92
 
 
93
/**
 
94
 * @constructor
 
95
 */
 
96
WebInspector.AsyncTaskQueue = function()
 
97
{
 
98
    this._queue = [];
 
99
    this._isTimerSheduled = false;
 
100
}
 
101
 
 
102
WebInspector.AsyncTaskQueue.prototype = {
 
103
    /**
 
104
     * @param {function()} task
 
105
     */
 
106
    addTask: function(task)
 
107
    {
 
108
        this._queue.push(task);
 
109
        this._scheduleTimer();
 
110
    },
 
111
 
 
112
    _onTimeout: function()
 
113
    {
 
114
        this._isTimerSheduled = false;
 
115
        var queue = this._queue;
 
116
        this._queue = [];
 
117
        for (var i = 0; i < queue.length; i++) {
 
118
            try {
 
119
                queue[i]();
 
120
            } catch (e) {
 
121
                console.error("Exception while running task: " + e.stack);
 
122
            }
 
123
        }
 
124
        this._scheduleTimer();
 
125
    },
 
126
 
 
127
    _scheduleTimer: function()
 
128
    {
 
129
        if (this._queue.length && !this._isTimerSheduled) {
 
130
            setTimeout(this._onTimeout.bind(this), 0);
 
131
            this._isTimerSheduled = true;
 
132
        }
 
133
    }
 
134
}
 
135
 
 
136
/**
 
137
 * @constructor
 
138
 * @extends {WebInspector.HeapSnapshotWorkerWrapper}
 
139
 */
 
140
WebInspector.HeapSnapshotFakeWorker = function()
 
141
{
 
142
    this._dispatcher = new WebInspector.HeapSnapshotWorkerDispatcher(window, this._postMessageFromWorker.bind(this));
 
143
    this._asyncTaskQueue = new WebInspector.AsyncTaskQueue();
 
144
}
 
145
 
 
146
WebInspector.HeapSnapshotFakeWorker.prototype = {
 
147
    postMessage: function(message)
 
148
    {
 
149
        function dispatch()
 
150
        {
 
151
            if (this._dispatcher)
 
152
                this._dispatcher.dispatchMessage({data: message});
 
153
        }
 
154
        this._asyncTaskQueue.addTask(dispatch.bind(this));
 
155
    },
 
156
 
 
157
    terminate: function()
 
158
    {
 
159
        this._dispatcher = null;
 
160
    },
 
161
 
 
162
    _postMessageFromWorker: function(message)
 
163
    {
 
164
        function send()
 
165
        {
 
166
            this.dispatchEventToListeners("message", message);
 
167
        }
 
168
        this._asyncTaskQueue.addTask(send.bind(this));
 
169
    },
 
170
 
 
171
    __proto__: WebInspector.HeapSnapshotWorkerWrapper.prototype
 
172
}
 
173
 
 
174
 
 
175
/**
 
176
 * @constructor
 
177
 * @extends {WebInspector.Object}
 
178
 */
 
179
WebInspector.HeapSnapshotWorker = function()
 
180
{
 
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);
 
188
}
 
189
 
 
190
WebInspector.HeapSnapshotWorker.prototype = {
 
191
    createObject: function(constructorName)
 
192
    {
 
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});
 
197
        return proxy;
 
198
    },
 
199
 
 
200
    dispose: function()
 
201
    {
 
202
        this._worker.terminate();
 
203
        if (this._interval)
 
204
            clearInterval(this._interval);
 
205
    },
 
206
 
 
207
    disposeObject: function(objectId)
 
208
    {
 
209
        this._postMessage({callId: this._nextCallId++, disposition: "dispose", objectId: objectId});
 
210
    },
 
211
 
 
212
    callGetter: function(callback, objectId, getterName)
 
213
    {
 
214
        var callId = this._nextCallId++;
 
215
        this._callbacks[callId] = callback;
 
216
        this._postMessage({callId: callId, disposition: "getter", objectId: objectId, methodName: getterName});
 
217
    },
 
218
 
 
219
    callFactoryMethod: function(callback, objectId, methodName, proxyConstructorName)
 
220
    {
 
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);
 
225
        if (callback) {
 
226
            function wrapCallback(remoteResult)
 
227
            {
 
228
                callback(remoteResult ? new proxyConstructorFunction(this, newObjectId) : null);
 
229
            }
 
230
            this._callbacks[callId] = wrapCallback.bind(this);
 
231
            this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
 
232
            return null;
 
233
        } else {
 
234
            this._postMessage({callId: callId, disposition: "factory", objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId});
 
235
            return new proxyConstructorFunction(this, newObjectId);
 
236
        }
 
237
    },
 
238
 
 
239
    callMethod: function(callback, objectId, methodName)
 
240
    {
 
241
        var callId = this._nextCallId++;
 
242
        var methodArguments = Array.prototype.slice.call(arguments, 3);
 
243
        if (callback)
 
244
            this._callbacks[callId] = callback;
 
245
        this._postMessage({callId: callId, disposition: "method", objectId: objectId, methodName: methodName, methodArguments: methodArguments});
 
246
    },
 
247
 
 
248
    startCheckingForLongRunningCalls: function()
 
249
    {
 
250
        if (this._interval)
 
251
            return;
 
252
        this._checkLongRunningCalls();
 
253
        this._interval = setInterval(this._checkLongRunningCalls.bind(this), 300);
 
254
    },
 
255
 
 
256
    _checkLongRunningCalls: function()
 
257
    {
 
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;
 
264
            break;
 
265
        }
 
266
        this.dispatchEventToListeners("wait", hasLongRunningCalls);
 
267
        for (callId in this._callbacks)
 
268
            this._previousCallbacks[callId] = true;
 
269
    },
 
270
 
 
271
    _findFunction: function(name)
 
272
    {
 
273
        var path = name.split(".");
 
274
        var result = window;
 
275
        for (var i = 0; i < path.length; ++i)
 
276
            result = result[path[i]];
 
277
        return result;
 
278
    },
 
279
 
 
280
    _messageReceived: function(event)
 
281
    {
 
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];
 
288
            return;
 
289
        }
 
290
        if (!this._callbacks[data.callId])
 
291
            return;
 
292
        var callback = this._callbacks[data.callId];
 
293
        delete this._callbacks[data.callId];
 
294
        callback(data.result);
 
295
    },
 
296
 
 
297
    _postMessage: function(message)
 
298
    {
 
299
        this._worker.postMessage(message);
 
300
    },
 
301
 
 
302
    __proto__: WebInspector.Object.prototype
 
303
}
 
304
 
 
305
 
 
306
/**
 
307
 * @constructor
 
308
 */
 
309
WebInspector.HeapSnapshotProxyObject = function(worker, objectId)
 
310
{
 
311
    this._worker = worker;
 
312
    this._objectId = objectId;
 
313
}
 
314
 
 
315
WebInspector.HeapSnapshotProxyObject.prototype = {
 
316
    _callWorker: function(workerMethodName, args)
 
317
    {
 
318
        args.splice(1, 0, this._objectId);
 
319
        return this._worker[workerMethodName].apply(this._worker, args);
 
320
    },
 
321
 
 
322
    dispose: function()
 
323
    {
 
324
        this._worker.disposeObject(this._objectId);
 
325
    },
 
326
 
 
327
    disposeWorker: function()
 
328
    {
 
329
        this._worker.dispose();
 
330
    },
 
331
 
 
332
    /**
 
333
     * @param {...*} var_args
 
334
     */
 
335
    callFactoryMethod: function(callback, methodName, proxyConstructorName, var_args)
 
336
    {
 
337
        return this._callWorker("callFactoryMethod", Array.prototype.slice.call(arguments, 0));
 
338
    },
 
339
 
 
340
    callGetter: function(callback, getterName)
 
341
    {
 
342
        return this._callWorker("callGetter", Array.prototype.slice.call(arguments, 0));
 
343
    },
 
344
 
 
345
    /**
 
346
     * @param {...*} var_args
 
347
     */
 
348
    callMethod: function(callback, methodName, var_args)
 
349
    {
 
350
        return this._callWorker("callMethod", Array.prototype.slice.call(arguments, 0));
 
351
    },
 
352
 
 
353
    get worker() {
 
354
        return this._worker;
 
355
    }
 
356
};
 
357
 
 
358
/**
 
359
 * @constructor
 
360
 * @extends {WebInspector.HeapSnapshotProxyObject}
 
361
 * @implements {WebInspector.OutputStream}
 
362
 */
 
363
WebInspector.HeapSnapshotLoaderProxy = function(worker, objectId)
 
364
{
 
365
    WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
 
366
    this._pendingSnapshotConsumers = [];
 
367
}
 
368
 
 
369
WebInspector.HeapSnapshotLoaderProxy.prototype = {
 
370
    /**
 
371
     * @param {function(WebInspector.HeapSnapshotProxy)} callback
 
372
     */
 
373
    addConsumer: function(callback)
 
374
    {
 
375
        this._pendingSnapshotConsumers.push(callback);
 
376
    },
 
377
 
 
378
    /**
 
379
     * @param {string} chunk
 
380
     * @param {function(WebInspector.OutputStream)=} callback
 
381
     */
 
382
    write: function(chunk, callback)
 
383
    {
 
384
        this.callMethod(callback, "write", chunk);
 
385
    },
 
386
 
 
387
    close: function()
 
388
    {
 
389
        function buildSnapshot()
 
390
        {
 
391
            this.callFactoryMethod(updateStaticData.bind(this), "buildSnapshot", "WebInspector.HeapSnapshotProxy");
 
392
        }
 
393
        function updateStaticData(snapshotProxy)
 
394
        {
 
395
            this.dispose();
 
396
            snapshotProxy.updateStaticData(notifyPendingConsumers.bind(this));
 
397
        }
 
398
        function notifyPendingConsumers(snapshotProxy)
 
399
        {
 
400
            for (var i = 0; i < this._pendingSnapshotConsumers.length; ++i)
 
401
                this._pendingSnapshotConsumers[i](snapshotProxy);
 
402
            this._pendingSnapshotConsumers = [];
 
403
        }
 
404
        this.callMethod(buildSnapshot.bind(this), "close");
 
405
    },
 
406
 
 
407
    __proto__: WebInspector.HeapSnapshotProxyObject.prototype
 
408
}
 
409
 
 
410
 
 
411
/**
 
412
 * @constructor
 
413
 * @extends {WebInspector.HeapSnapshotProxyObject}
 
414
 */
 
415
WebInspector.HeapSnapshotProxy = function(worker, objectId)
 
416
{
 
417
    WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
 
418
}
 
419
 
 
420
WebInspector.HeapSnapshotProxy.prototype = {
 
421
    aggregates: function(sortedIndexes, key, filter, callback)
 
422
    {
 
423
        this.callMethod(callback, "aggregates", sortedIndexes, key, filter);
 
424
    },
 
425
 
 
426
    aggregatesForDiff: function(callback)
 
427
    {
 
428
        this.callMethod(callback, "aggregatesForDiff");
 
429
    },
 
430
 
 
431
    calculateSnapshotDiff: function(baseSnapshotId, baseSnapshotAggregates, callback)
 
432
    {
 
433
        this.callMethod(callback, "calculateSnapshotDiff", baseSnapshotId, baseSnapshotAggregates);
 
434
    },
 
435
 
 
436
    nodeClassName: function(snapshotObjectId, callback)
 
437
    {
 
438
        this.callMethod(callback, "nodeClassName", snapshotObjectId);
 
439
    },
 
440
 
 
441
    dominatorIdsForNode: function(nodeIndex, callback)
 
442
    {
 
443
        this.callMethod(callback, "dominatorIdsForNode", nodeIndex);
 
444
    },
 
445
 
 
446
    createEdgesProvider: function(nodeIndex, filter)
 
447
    {
 
448
        return this.callFactoryMethod(null, "createEdgesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
 
449
    },
 
450
 
 
451
    createRetainingEdgesProvider: function(nodeIndex, filter)
 
452
    {
 
453
        return this.callFactoryMethod(null, "createRetainingEdgesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndex, filter);
 
454
    },
 
455
 
 
456
    createAddedNodesProvider: function(baseSnapshotId, className)
 
457
    {
 
458
        return this.callFactoryMethod(null, "createAddedNodesProvider", "WebInspector.HeapSnapshotProviderProxy", baseSnapshotId, className);
 
459
    },
 
460
 
 
461
    createDeletedNodesProvider: function(nodeIndexes)
 
462
    {
 
463
        return this.callFactoryMethod(null, "createDeletedNodesProvider", "WebInspector.HeapSnapshotProviderProxy", nodeIndexes);
 
464
    },
 
465
 
 
466
    createNodesProvider: function(filter)
 
467
    {
 
468
        return this.callFactoryMethod(null, "createNodesProvider", "WebInspector.HeapSnapshotProviderProxy", filter);
 
469
    },
 
470
 
 
471
    createNodesProviderForClass: function(className, aggregatesKey)
 
472
    {
 
473
        return this.callFactoryMethod(null, "createNodesProviderForClass", "WebInspector.HeapSnapshotProviderProxy", className, aggregatesKey);
 
474
    },
 
475
 
 
476
    createNodesProviderForDominator: function(nodeIndex)
 
477
    {
 
478
        return this.callFactoryMethod(null, "createNodesProviderForDominator", "WebInspector.HeapSnapshotProviderProxy", nodeIndex);
 
479
    },
 
480
 
 
481
    dispose: function()
 
482
    {
 
483
        this.disposeWorker();
 
484
    },
 
485
 
 
486
    get nodeCount()
 
487
    {
 
488
        return this._staticData.nodeCount;
 
489
    },
 
490
 
 
491
    get nodeFlags()
 
492
    {
 
493
        return this._staticData.nodeFlags;
 
494
    },
 
495
 
 
496
    get rootNodeIndex()
 
497
    {
 
498
        return this._staticData.rootNodeIndex;
 
499
    },
 
500
 
 
501
    updateStaticData: function(callback)
 
502
    {
 
503
        function dataReceived(staticData)
 
504
        {
 
505
            this._staticData = staticData;
 
506
            callback(this);
 
507
        }
 
508
        this.callMethod(dataReceived.bind(this), "updateStaticData");
 
509
    },
 
510
 
 
511
    get totalSize()
 
512
    {
 
513
        return this._staticData.totalSize;
 
514
    },
 
515
 
 
516
    get uid()
 
517
    {
 
518
        return this._staticData.uid;
 
519
    },
 
520
 
 
521
    __proto__: WebInspector.HeapSnapshotProxyObject.prototype
 
522
}
 
523
 
 
524
 
 
525
/**
 
526
 * @constructor
 
527
 * @extends {WebInspector.HeapSnapshotProxyObject}
 
528
 */
 
529
WebInspector.HeapSnapshotProviderProxy = function(worker, objectId)
 
530
{
 
531
    WebInspector.HeapSnapshotProxyObject.call(this, worker, objectId);
 
532
}
 
533
 
 
534
WebInspector.HeapSnapshotProviderProxy.prototype = {
 
535
    nodePosition: function(snapshotObjectId, callback)
 
536
    {
 
537
        this.callMethod(callback, "nodePosition", snapshotObjectId);
 
538
    },
 
539
 
 
540
    isEmpty: function(callback)
 
541
    {
 
542
        this.callMethod(callback, "isEmpty");
 
543
    },
 
544
 
 
545
    serializeItemsRange: function(startPosition, endPosition, callback)
 
546
    {
 
547
        this.callMethod(callback, "serializeItemsRange", startPosition, endPosition);
 
548
    },
 
549
 
 
550
    sortAndRewind: function(comparator, callback)
 
551
    {
 
552
        this.callMethod(callback, "sortAndRewind", comparator);
 
553
    },
 
554
 
 
555
    __proto__: WebInspector.HeapSnapshotProxyObject.prototype
 
556
}
 
557