summaryrefslogtreecommitdiffstats
path: root/devtools/client/fronts/memory.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/fronts/memory.js')
-rw-r--r--devtools/client/fronts/memory.js117
1 files changed, 117 insertions, 0 deletions
diff --git a/devtools/client/fronts/memory.js b/devtools/client/fronts/memory.js
new file mode 100644
index 0000000000..aa2bda6ec9
--- /dev/null
+++ b/devtools/client/fronts/memory.js
@@ -0,0 +1,117 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { memorySpec } = require("devtools/shared/specs/memory");
+const {
+ FrontClassWithSpec,
+ registerFront,
+} = require("devtools/shared/protocol");
+
+loader.lazyRequireGetter(
+ this,
+ "FileUtils",
+ "resource://gre/modules/FileUtils.jsm",
+ true
+);
+loader.lazyRequireGetter(
+ this,
+ "HeapSnapshotFileUtils",
+ "devtools/shared/heapsnapshot/HeapSnapshotFileUtils"
+);
+
+class MemoryFront extends FrontClassWithSpec(memorySpec) {
+ constructor(client, targetFront, parentFront) {
+ super(client, targetFront, parentFront);
+ this._client = client;
+ this.heapSnapshotFileActorID = null;
+
+ // Attribute name from which to retrieve the actorID out of the target actor's form
+ this.formAttributeName = "memoryActor";
+ }
+
+ /**
+ * Save a heap snapshot, transfer it from the server to the client if the
+ * server and client do not share a file system, and return the local file
+ * path to the heap snapshot.
+ *
+ * Note that this is safe to call for actors inside sandoxed child processes,
+ * as we jump through the correct IPDL hoops.
+ *
+ * @params Boolean options.forceCopy
+ * Always force a bulk data copy of the saved heap snapshot, even when
+ * the server and client share a file system.
+ *
+ * @params {Object|undefined} options.boundaries
+ * The boundaries for the heap snapshot. See
+ * ChromeUtils.webidl for more details.
+ *
+ * @returns Promise<String>
+ */
+ async saveHeapSnapshot(options = {}) {
+ const snapshotId = await super.saveHeapSnapshot(options.boundaries);
+
+ if (
+ !options.forceCopy &&
+ (await HeapSnapshotFileUtils.haveHeapSnapshotTempFile(snapshotId))
+ ) {
+ return HeapSnapshotFileUtils.getHeapSnapshotTempFilePath(snapshotId);
+ }
+
+ return this.transferHeapSnapshot(snapshotId);
+ }
+
+ /**
+ * Given that we have taken a heap snapshot with the given id, transfer the
+ * heap snapshot file to the client. The path to the client's local file is
+ * returned.
+ *
+ * @param {String} snapshotId
+ *
+ * @returns Promise<String>
+ */
+ async transferHeapSnapshot(snapshotId) {
+ if (!this.heapSnapshotFileActorID) {
+ const form = await this._client.mainRoot.rootForm;
+ this.heapSnapshotFileActorID = form.heapSnapshotFileActor;
+ }
+
+ try {
+ const request = this._client.request({
+ to: this.heapSnapshotFileActorID,
+ type: "transferHeapSnapshot",
+ snapshotId,
+ });
+
+ const outFilePath = HeapSnapshotFileUtils.getNewUniqueHeapSnapshotTempFilePath();
+ const outFile = new FileUtils.File(outFilePath);
+ const outFileStream = FileUtils.openSafeFileOutputStream(outFile);
+
+ // This request is a bulk request. That's why the result of the request is
+ // an object with the `copyTo` function that can transfer the data to
+ // another stream.
+ // See devtools/shared/transport/transport.js to know more about this mode.
+ const { copyTo } = await request;
+ await copyTo(outFileStream);
+
+ FileUtils.closeSafeFileOutputStream(outFileStream);
+ return outFilePath;
+ } catch (e) {
+ if (e.error) {
+ // This isn't a real error, rather this is a message coming from the
+ // server. So let's throw a real error instead.
+ throw new Error(
+ `The server's actor threw an error: (${e.error}) ${e.message}`
+ );
+ }
+
+ // Otherwise, rethrow the error
+ throw e;
+ }
+ }
+}
+
+exports.MemoryFront = MemoryFront;
+registerFront(MemoryFront);