UNPKG

@dcloudio/uni-debugger

Version:

uni-app debugger

529 lines (475 loc) 14.9 kB
/* * Copyright (C) 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyrightdd * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @unrestricted */ Profiler.HeapSnapshotWorkerProxy = class extends Common.Object { /** * @param {function(string, *)} eventHandler */ constructor(eventHandler) { super(); this._eventHandler = eventHandler; this._nextObjectId = 1; this._nextCallId = 1; /** @type {!Map<number, function(*)>} */ this._callbacks = new Map(); /** @type {!Set<number>} */ this._previousCallbacks = new Set(); this._worker = new Common.Worker('heap_snapshot_worker'); this._worker.onmessage = this._messageReceived.bind(this); } /** * @param {number} profileUid * @param {function(!Profiler.HeapSnapshotProxy)} snapshotReceivedCallback * @return {!Profiler.HeapSnapshotLoaderProxy} */ createLoader(profileUid, snapshotReceivedCallback) { const objectId = this._nextObjectId++; const proxy = new Profiler.HeapSnapshotLoaderProxy(this, objectId, profileUid, snapshotReceivedCallback); this._postMessage({ callId: this._nextCallId++, disposition: 'create', objectId: objectId, methodName: 'HeapSnapshotWorker.HeapSnapshotLoader' }); return proxy; } dispose() { this._worker.terminate(); if (this._interval) clearInterval(this._interval); } disposeObject(objectId) { this._postMessage({callId: this._nextCallId++, disposition: 'dispose', objectId: objectId}); } evaluateForTest(script, callback) { const callId = this._nextCallId++; this._callbacks.set(callId, callback); this._postMessage({callId: callId, disposition: 'evaluateForTest', source: script}); } /** * @param {?function(...?)} callback * @param {string} objectId * @param {string} methodName * @param {function(new:T, ...?)} proxyConstructor * @return {?Object} * @template T */ callFactoryMethod(callback, objectId, methodName, proxyConstructor) { const callId = this._nextCallId++; const methodArguments = Array.prototype.slice.call(arguments, 4); const newObjectId = this._nextObjectId++; /** * @this {Profiler.HeapSnapshotWorkerProxy} */ function wrapCallback(remoteResult) { callback(remoteResult ? new proxyConstructor(this, newObjectId) : null); } if (callback) { this._callbacks.set(callId, wrapCallback.bind(this)); this._postMessage({ callId: callId, disposition: 'factory', objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId }); return null; } else { this._postMessage({ callId: callId, disposition: 'factory', objectId: objectId, methodName: methodName, methodArguments: methodArguments, newObjectId: newObjectId }); return new proxyConstructor(this, newObjectId); } } /** * @param {function(*)} callback * @param {string} objectId * @param {string} methodName */ callMethod(callback, objectId, methodName) { const callId = this._nextCallId++; const methodArguments = Array.prototype.slice.call(arguments, 3); if (callback) this._callbacks.set(callId, callback); this._postMessage({ callId: callId, disposition: 'method', objectId: objectId, methodName: methodName, methodArguments: methodArguments }); } startCheckingForLongRunningCalls() { if (this._interval) return; this._checkLongRunningCalls(); this._interval = setInterval(this._checkLongRunningCalls.bind(this), 300); } _checkLongRunningCalls() { for (const callId of this._previousCallbacks) { if (!this._callbacks.has(callId)) this._previousCallbacks.delete(callId); } const hasLongRunningCalls = !!this._previousCallbacks.size; this.dispatchEventToListeners(Profiler.HeapSnapshotWorkerProxy.Events.Wait, hasLongRunningCalls); for (const callId of this._callbacks.keysArray()) this._previousCallbacks.add(callId); } /** * @param {!MessageEvent} event */ _messageReceived(event) { const data = event.data; if (data.eventName) { if (this._eventHandler) this._eventHandler(data.eventName, data.data); return; } if (data.error) { if (data.errorMethodName) { Common.console.error( Common.UIString('An error occurred when a call to method \'%s\' was requested', data.errorMethodName)); } Common.console.error(data['errorCallStack']); this._callbacks.delete(data.callId); return; } if (!this._callbacks.has(data.callId)) return; const callback = this._callbacks.get(data.callId); this._callbacks.delete(data.callId); callback(data.result); } _postMessage(message) { this._worker.postMessage(message); } }; Profiler.HeapSnapshotWorkerProxy.Events = { Wait: Symbol('Wait') }; /** * @unrestricted */ Profiler.HeapSnapshotProxyObject = class { /** * @param {!Profiler.HeapSnapshotWorkerProxy} worker * @param {number} objectId */ constructor(worker, objectId) { this._worker = worker; this._objectId = objectId; } /** * @param {string} workerMethodName * @param {!Array.<*>} args */ _callWorker(workerMethodName, args) { args.splice(1, 0, this._objectId); return this._worker[workerMethodName].apply(this._worker, args); } dispose() { this._worker.disposeObject(this._objectId); } disposeWorker() { this._worker.dispose(); } /** * @param {?function(...?)} callback * @param {string} methodName * @param {function (new:T, ...?)} proxyConstructor * @param {...*} var_args * @return {!T} * @template T */ callFactoryMethod(callback, methodName, proxyConstructor, var_args) { return this._callWorker('callFactoryMethod', Array.prototype.slice.call(arguments, 0)); } /** * @param {string} methodName * @param {...*} var_args * @return {!Promise.<?T>} * @template T */ _callMethodPromise(methodName, var_args) { const args = Array.prototype.slice.call(arguments); return new Promise(resolve => this._callWorker('callMethod', [resolve, ...args])); } }; /** * @implements {Common.OutputStream} * @unrestricted */ Profiler.HeapSnapshotLoaderProxy = class extends Profiler.HeapSnapshotProxyObject { /** * @param {!Profiler.HeapSnapshotWorkerProxy} worker * @param {number} objectId * @param {number} profileUid * @param {function(!Profiler.HeapSnapshotProxy)} snapshotReceivedCallback */ constructor(worker, objectId, profileUid, snapshotReceivedCallback) { super(worker, objectId); this._profileUid = profileUid; this._snapshotReceivedCallback = snapshotReceivedCallback; } /** * @override * @param {string} chunk * @return {!Promise} */ write(chunk) { return this._callMethodPromise('write', chunk); } /** * @override */ async close() { await this._callMethodPromise('close'); const snapshotProxy = await new Promise(resolve => this.callFactoryMethod(resolve, 'buildSnapshot', Profiler.HeapSnapshotProxy)); this.dispose(); snapshotProxy.setProfileUid(this._profileUid); await snapshotProxy.updateStaticData(); this._snapshotReceivedCallback(snapshotProxy); } }; /** * @unrestricted */ Profiler.HeapSnapshotProxy = class extends Profiler.HeapSnapshotProxyObject { /** * @param {!Profiler.HeapSnapshotWorkerProxy} worker * @param {number} objectId */ constructor(worker, objectId) { super(worker, objectId); /** @type {?HeapSnapshotModel.StaticData} */ this._staticData = null; } /** * @param {!HeapSnapshotModel.SearchConfig} searchConfig * @param {!HeapSnapshotModel.NodeFilter} filter * @return {!Promise<!Array<number>>} */ search(searchConfig, filter) { return this._callMethodPromise('search', searchConfig, filter); } /** * @param {!HeapSnapshotModel.NodeFilter} filter * @return {!Promise<!Object<string, !HeapSnapshotModel.Aggregate>>} */ aggregatesWithFilter(filter) { return this._callMethodPromise('aggregatesWithFilter', filter); } /** * @return {!Promise<!Object.<string, !HeapSnapshotModel.AggregateForDiff>>} */ aggregatesForDiff() { return this._callMethodPromise('aggregatesForDiff'); } /** * @param {string} baseSnapshotId * @param {!Object<string, !HeapSnapshotModel.AggregateForDiff>} baseSnapshotAggregates * @return {!Promise<!Object<string, !HeapSnapshotModel.Diff>>} */ calculateSnapshotDiff(baseSnapshotId, baseSnapshotAggregates) { return this._callMethodPromise('calculateSnapshotDiff', baseSnapshotId, baseSnapshotAggregates); } /** * @param {number} snapshotObjectId * @return {!Promise<?string>} */ nodeClassName(snapshotObjectId) { return this._callMethodPromise('nodeClassName', snapshotObjectId); } /** * @param {number} nodeIndex * @return {!Profiler.HeapSnapshotProviderProxy} */ createEdgesProvider(nodeIndex) { return this.callFactoryMethod(null, 'createEdgesProvider', Profiler.HeapSnapshotProviderProxy, nodeIndex); } /** * @param {number} nodeIndex * @return {!Profiler.HeapSnapshotProviderProxy} */ createRetainingEdgesProvider(nodeIndex) { return this.callFactoryMethod(null, 'createRetainingEdgesProvider', Profiler.HeapSnapshotProviderProxy, nodeIndex); } /** * @param {string} baseSnapshotId * @param {string} className * @return {?Profiler.HeapSnapshotProviderProxy} */ createAddedNodesProvider(baseSnapshotId, className) { return this.callFactoryMethod( null, 'createAddedNodesProvider', Profiler.HeapSnapshotProviderProxy, baseSnapshotId, className); } /** * @param {!Array.<number>} nodeIndexes * @return {?Profiler.HeapSnapshotProviderProxy} */ createDeletedNodesProvider(nodeIndexes) { return this.callFactoryMethod(null, 'createDeletedNodesProvider', Profiler.HeapSnapshotProviderProxy, nodeIndexes); } /** * @param {function(*):boolean} filter * @return {?Profiler.HeapSnapshotProviderProxy} */ createNodesProvider(filter) { return this.callFactoryMethod(null, 'createNodesProvider', Profiler.HeapSnapshotProviderProxy, filter); } /** * @param {string} className * @param {!HeapSnapshotModel.NodeFilter} nodeFilter * @return {?Profiler.HeapSnapshotProviderProxy} */ createNodesProviderForClass(className, nodeFilter) { return this.callFactoryMethod( null, 'createNodesProviderForClass', Profiler.HeapSnapshotProviderProxy, className, nodeFilter); } /** * @return {!Promise<!Array<!HeapSnapshotModel.SerializedAllocationNode>>} */ allocationTracesTops() { return this._callMethodPromise('allocationTracesTops'); } /** * @param {number} nodeId * @return {!Promise<!HeapSnapshotModel.AllocationNodeCallers>} */ allocationNodeCallers(nodeId) { return this._callMethodPromise('allocationNodeCallers', nodeId); } /** * @param {number} nodeIndex * @return {!Promise<?Array<!HeapSnapshotModel.AllocationStackFrame>>} */ allocationStack(nodeIndex) { return this._callMethodPromise('allocationStack', nodeIndex); } /** * @override */ dispose() { throw new Error('Should never be called'); } get nodeCount() { return this._staticData.nodeCount; } get rootNodeIndex() { return this._staticData.rootNodeIndex; } /** * @return {!Promise} */ async updateStaticData() { this._staticData = await this._callMethodPromise('updateStaticData'); } /** * @return {!Promise<!HeapSnapshotModel.Statistics>} */ getStatistics() { return this._callMethodPromise('getStatistics'); } /** * @return {!Promise.<?HeapSnapshotModel.Samples>} */ getSamples() { return this._callMethodPromise('getSamples'); } get totalSize() { return this._staticData.totalSize; } get uid() { return this._profileUid; } setProfileUid(profileUid) { this._profileUid = profileUid; } /** * @return {number} */ maxJSObjectId() { return this._staticData.maxJSObjectId; } }; /** * @implements {Profiler.HeapSnapshotGridNode.ChildrenProvider} * @unrestricted */ Profiler.HeapSnapshotProviderProxy = class extends Profiler.HeapSnapshotProxyObject { /** * @param {!Profiler.HeapSnapshotWorkerProxy} worker * @param {number} objectId */ constructor(worker, objectId) { super(worker, objectId); } /** * @override * @param {number} snapshotObjectId * @return {!Promise<number>} */ nodePosition(snapshotObjectId) { return this._callMethodPromise('nodePosition', snapshotObjectId); } /** * @override * @return {!Promise<boolean>} */ isEmpty() { return this._callMethodPromise('isEmpty'); } /** * @override * @param {number} startPosition * @param {number} endPosition * @return {!Promise<!HeapSnapshotModel.ItemsRange>} */ serializeItemsRange(startPosition, endPosition) { return this._callMethodPromise('serializeItemsRange', startPosition, endPosition); } /** * @override * @param {!HeapSnapshotModel.ComparatorConfig} comparator * @return {!Promise} */ sortAndRewind(comparator) { return this._callMethodPromise('sortAndRewind', comparator); } };