Bug 1545021 - Convert ArrayBuffer to a Front and Protocoljs actor; r=ochameau,jdescottes
authoryulia <ystartsev@mozilla.com>
Tue, 30 Apr 2019 14:40:43 +0000
changeset 530793 78df5dc92c3f9a0c58043d625a3c93352135948f
parent 530792 542c3b51efa1deda9a07a1081d635150a0d8d45f
child 530794 05e9997b6809900677149992d3a5634ae43b3a11
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau, jdescottes
bugs1545021
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1545021 - Convert ArrayBuffer to a Front and Protocoljs actor; r=ochameau,jdescottes This introduces an ArrayBuffer front, so that we no longer need to go through the thread client to get an array buffer for the sourceFront (this is the only place it is used). It also converts the arrayBufferActor to a protocol.js actor. I was running into an issue between them. I need to double check what this issue was. If these two refactors need to be split, I can do that, but for now it looks like it wasn’t that large of a change. Differential Revision: https://phabricator.services.mozilla.com/D27878
devtools/server/actors/array-buffer.js
devtools/server/actors/source.js
devtools/shared/client/array-buffer-client.js
devtools/shared/client/moz.build
devtools/shared/client/thread-client.js
devtools/shared/fronts/array-buffer.js
devtools/shared/fronts/moz.build
devtools/shared/fronts/source.js
devtools/shared/specs/array-buffer.js
devtools/shared/specs/index.js
devtools/shared/specs/moz.build
devtools/shared/specs/source.js
--- a/devtools/server/actors/array-buffer.js
+++ b/devtools/server/actors/array-buffer.js
@@ -1,86 +1,59 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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";
 
+var protocol = require("devtools/shared/protocol");
+const {arrayBufferSpec} = require("devtools/shared/specs/array-buffer");
+
 /**
  * Creates an actor for the specified ArrayBuffer.
  *
+ * @param {DebuggerServerConnection} conn
+ *    The server connection.
  * @param buffer ArrayBuffer
  *        The buffer.
  */
-function ArrayBufferActor(buffer) {
-  this.buffer = buffer;
-  this.bufferLength = buffer.byteLength;
-}
-
-ArrayBufferActor.prototype = {
-  actorPrefix: "arrayBuffer",
+const ArrayBufferActor = protocol.ActorClassWithSpec(arrayBufferSpec, {
+  initialize: function(conn, buffer) {
+    protocol.Actor.prototype.initialize.call(this, conn);
+    this.buffer = buffer;
+    this.bufferLength = buffer.byteLength;
+  },
 
   rawValue: function() {
     return this.buffer;
   },
 
-  destroy: function() {
-  },
-
-  grip() {
+  form: function() {
     return {
-      "type": "arrayBuffer",
-      "length": this.bufferLength,
-      "actor": this.actorID,
+      typeName: this.typeName,
+      length: this.bufferLength,
+      actor: this.actorID,
     };
   },
 
-  onSlice({start, count}) {
+  slice(start, count) {
     const slice = new Uint8Array(this.buffer, start, count);
     const parts = [];
     let offset = 0;
     const PortionSize = 0x6000; // keep it divisible by 3 for btoa() and join()
     while (offset + PortionSize < count) {
       parts.push(btoa(
         String.fromCharCode.apply(null, slice.subarray(offset, offset + PortionSize))));
       offset += PortionSize;
     }
     parts.push(btoa(String.fromCharCode.apply(null, slice.subarray(offset, count))));
     return {
       "from": this.actorID,
       "encoded": parts.join(""),
     };
   },
-};
-
-ArrayBufferActor.prototype.requestTypes = {
-  "slice": ArrayBufferActor.prototype.onSlice,
-};
-
-/**
- * Create a grip for the given ArrayBuffer.
- *
- * @param buffer ArrayBuffer
- *        The ArrayBuffer we are creating a grip for.
- * @param pool ActorPool
- *        The actor pool where the new actor will be added.
- */
-function arrayBufferGrip(buffer, pool) {
-  if (!pool.arrayBufferActors) {
-    pool.arrayBufferActors = new WeakMap();
-  }
-
-  if (pool.arrayBufferActors.has(buffer)) {
-    return pool.arrayBufferActors.get(buffer).grip();
-  }
-
-  const actor = new ArrayBufferActor(buffer);
-  pool.addActor(actor);
-  pool.arrayBufferActors.set(buffer, actor);
-  return actor.grip();
-}
+});
 
 module.exports = {
   ArrayBufferActor,
-  arrayBufferGrip,
 };
--- a/devtools/server/actors/source.js
+++ b/devtools/server/actors/source.js
@@ -9,17 +9,17 @@
 const { Ci } = require("chrome");
 const { setBreakpointAtEntryPoints } = require("devtools/server/actors/breakpoint");
 const { ActorClassWithSpec } = require("devtools/shared/protocol");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const { assert, fetch } = DevToolsUtils;
 const { joinURI } = require("devtools/shared/path");
 const { sourceSpec } = require("devtools/shared/specs/source");
 
-loader.lazyRequireGetter(this, "arrayBufferGrip", "devtools/server/actors/array-buffer", true);
+loader.lazyRequireGetter(this, "ArrayBufferActor", "devtools/server/actors/array-buffer", true);
 loader.lazyRequireGetter(this, "LongStringActor", "devtools/server/actors/string", true);
 
 function isEvalSource(source) {
   const introType = source.introductionType;
 
   // Script elements that are dynamically created are treated as eval sources.
   // We detect these by looking at whether there was another script on the stack
   // when the source was created.
@@ -332,17 +332,17 @@ const SourceActor = ActorClassWithSpec(s
    */
   onSource: function() {
     return Promise.resolve(this._init)
       .then(this._getSourceText)
       .then(({ content, contentType }) => {
         if (typeof content === "object" && content && content.constructor &&
             content.constructor.name === "ArrayBuffer") {
           return {
-            source: arrayBufferGrip(content, this.threadActor.threadLifetimePool),
+            source: new ArrayBufferActor(this.threadActor.conn, content),
             contentType,
           };
         }
 
         return {
           source: new LongStringActor(this.threadActor.conn, content),
           contentType,
         };
--- a/devtools/shared/client/moz.build
+++ b/devtools/shared/client/moz.build
@@ -1,16 +1,15 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 DevToolsModules(
-    'array-buffer-client.js',
     'connection-manager.js',
     'constants.js',
     'debugger-client.js',
     'environment-client.js',
     'event-source.js',
     'long-string-client.js',
     'object-client.js',
     'property-iterator-client.js',
--- a/devtools/shared/client/thread-client.js
+++ b/devtools/shared/client/thread-client.js
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client");
 const eventSource = require("devtools/shared/client/event-source");
 const {ThreadStateTypes} = require("devtools/shared/client/constants");
 
-loader.lazyRequireGetter(this, "ArrayBufferClient", "devtools/shared/client/array-buffer-client");
+loader.lazyRequireGetter(this, "ArrayBufferFront", "devtools/shared/fronts/array-buffer");
 loader.lazyRequireGetter(this, "LongStringClient", "devtools/shared/client/long-string-client");
 loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/object-client");
 loader.lazyRequireGetter(this, "SourceFront", "devtools/shared/fronts/source", true);
 
 /**
  * Creates a thread client for the remote debugging protocol server. This client
  * is a front to the thread actor created in the server side, hiding the
  * protocol details in a traditional JavaScript API.
@@ -410,19 +410,19 @@ ThreadClient.prototype = {
    *        The property name of the grip client cache to check for existing
    *        clients in.
    */
   _arrayBuffer: function(grip, gripCacheName) {
     if (grip.actor in this[gripCacheName]) {
       return this[gripCacheName][grip.actor];
     }
 
-    const client = new ArrayBufferClient(this.client, grip);
-    this[gripCacheName][grip.actor] = client;
-    return client;
+    const front = new ArrayBufferFront(this.client, grip);
+    this[gripCacheName][grip.actor] = front;
+    return front;
   },
 
   /**
    * Return an instance of ArrayBufferClient for the given ArrayBuffer grip that
    * is scoped to the thread lifetime.
    *
    * @param grip Object
    *        The ArrayBuffer grip returned by the protocol.
@@ -539,17 +539,17 @@ ThreadClient.prototype = {
   /**
    * Return an instance of SourceFront for the given source actor form.
    */
   source: function(form) {
     if (form.actor in this._threadGrips) {
       return this._threadGrips[form.actor];
     }
 
-    this._threadGrips[form.actor] = new SourceFront(this.client, form, this);
+    this._threadGrips[form.actor] = new SourceFront(this.client, form);
     return this._threadGrips[form.actor];
   },
 
   events: ["newSource", "progress"],
 };
 
 eventSource(ThreadClient.prototype);
 
rename from devtools/shared/client/array-buffer-client.js
rename to devtools/shared/fronts/array-buffer.js
--- a/devtools/shared/client/array-buffer-client.js
+++ b/devtools/shared/fronts/array-buffer.js
@@ -1,43 +1,21 @@
 /* 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 {arg, DebuggerClient} = require("devtools/shared/client/debugger-client");
+const { arrayBufferSpec } = require("devtools/shared/specs/array-buffer");
+const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
 
 /**
  * A ArrayBufferClient provides a way to access ArrayBuffer from the
  * debugger server.
- *
- * @param client DebuggerClient
- *        The debugger client parent.
- * @param grip Object
- *        A pause-lifetime ArrayBuffer grip returned by the protocol.
  */
-function ArrayBufferClient(client, grip) {
-  this._grip = grip;
-  this._client = client;
-  this.request = this._client.request;
+class ArrayBufferFront extends FrontClassWithSpec(arrayBufferSpec) {
+  form(json) {
+    this.length = json.length;
+  }
 }
-ArrayBufferClient.prototype = {
-  get actor() {
-    return this._grip.actor;
-  },
-  get length() {
-    return this._grip.length;
-  },
-  get _transport() {
-    return this._client._transport;
-  },
 
-  valid: true,
-
-  slice: DebuggerClient.requester({
-    type: "slice",
-    start: arg(0),
-    count: arg(1),
-  }),
-};
-
-module.exports = ArrayBufferClient;
+exports.ArrayBufferFront = ArrayBufferFront;
+registerFront(ArrayBufferFront);
--- a/devtools/shared/fronts/moz.build
+++ b/devtools/shared/fronts/moz.build
@@ -10,16 +10,17 @@ DIRS += [
     'targets',
     'worker',
 ]
 
 DevToolsModules(
     'accessibility.js',
     'actor-registry.js',
     'animation.js',
+    'array-buffer.js',
     'changes.js',
     'css-properties.js',
     'device.js',
     'emulation.js',
     'framerate.js',
     'highlighters.js',
     'inspector.js',
     'layout.js',
--- a/devtools/shared/fronts/source.js
+++ b/devtools/shared/fronts/source.js
@@ -1,33 +1,30 @@
 /* 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 { sourceSpec } = require("devtools/shared/specs/source");
 const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
+const { ArrayBufferFront } = require("devtools/shared/fronts/array-buffer");
 
 /**
  * A SourceFront provides a way to access the source text of a script.
  *
  * @param client DebuggerClient
  *        The Debugger Client instance.
  * @param form Object
  *        The form sent across the remote debugging protocol.
- * @param activeThread ThreadClient
- *        The thread client parent. Used until the SourceFront marshalls LongStringFront
- *        and ArrayBuffer.
  */
 class SourceFront extends FrontClassWithSpec(sourceSpec) {
-  constructor(client, form, activeThread) {
+  constructor(client, form) {
     super(client);
     this._url = form.url;
-    this._activeThread = activeThread;
     // this is here for the time being, until the source front is managed
     // via protocol.js marshalling
     this.actorID = form.actor;
     this.manage(this);
   }
 
   get actor() {
     return this.actorID;
@@ -43,32 +40,28 @@ class SourceFront extends FrontClassWith
   }
 
   // Alias for source.unblackbox to avoid changing protocol.js packets
   unblackBox() {
     return this.unblackbox();
   }
 
   /**
-   * Get a long string grip for this SourceFront's source.
+   * Get a Front for either an arrayBuffer or LongString
+   * for this SourceFront's source.
    */
   async source() {
     const response = await this.onSource();
     return this._onSourceResponse(response);
   }
 
   _onSourceResponse(response) {
-    if (typeof response.source === "string") {
-      return response;
-    }
-
     const { contentType, source } = response;
-    if (source.type === "arrayBuffer") {
-      const arrayBuffer = this._activeThread.threadArrayBuffer(source);
-      return arrayBuffer.slice(0, source.length).then(function(resp) {
+    if (source instanceof ArrayBufferFront) {
+      return source.slice(0, source.length).then(function(resp) {
         if (resp.error) {
           return resp;
         }
         // Keeping str as a string, ArrayBuffer/Uint8Array will not survive
         // setIn/mergeIn operations.
         const str = atob(resp.encoded);
         const newResponse = {
           source: {
new file mode 100644
--- /dev/null
+++ b/devtools/shared/specs/array-buffer.js
@@ -0,0 +1,24 @@
+/* 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 protocol = require("devtools/shared/protocol");
+const {Arg, RetVal, generateActorSpec} = protocol;
+
+const arrayBufferSpec = generateActorSpec({
+  typeName: "arraybuffer",
+
+  methods: {
+    slice: {
+      request: {
+        start: Arg(0),
+        count: Arg(1),
+      },
+      response: RetVal("json"),
+    },
+    release: { release: true },
+  },
+});
+
+exports.arrayBufferSpec = arrayBufferSpec;
--- a/devtools/shared/specs/index.js
+++ b/devtools/shared/specs/index.js
@@ -38,16 +38,21 @@ const Types = exports.__TypesForTests = 
     front: "devtools/shared/fronts/addon/webextension-inspected-window",
   },
   {
     types: ["animationplayer", "animations"],
     spec: "devtools/shared/specs/animation",
     front: "devtools/shared/fronts/animation",
   },
   {
+    types: ["arraybuffer"],
+    spec: "devtools/shared/specs/array-buffer",
+    front: "devtools/shared/fronts/array-buffer",
+  },
+  {
     types: ["changes"],
     spec: "devtools/shared/specs/changes",
     front: "devtools/shared/fronts/changes",
   },
   {
     types: ["cssProperties"],
     spec: "devtools/shared/specs/css-properties",
     front: "devtools/shared/fronts/css-properties",
--- a/devtools/shared/specs/moz.build
+++ b/devtools/shared/specs/moz.build
@@ -9,16 +9,17 @@ DIRS += [
     'targets',
     'worker',
 ]
 
 DevToolsModules(
     'accessibility.js',
     'actor-registry.js',
     'animation.js',
+    'array-buffer.js',
     'changes.js',
     'css-properties.js',
     'device.js',
     'emulation.js',
     'environment.js',
     'frame.js',
     'framerate.js',
     'heap-snapshot-file.js',
--- a/devtools/shared/specs/source.js
+++ b/devtools/shared/specs/source.js
@@ -1,28 +1,32 @@
 /* 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 {Arg, RetVal, generateActorSpec, types} = require("devtools/shared/protocol");
 
 const longstringType = types.getType("longstring");
+const arraybufferType = types.getType("arraybuffer");
 // The sourcedata type needs some custom marshalling, because it is sometimes
 // returned as an arraybuffer and sometimes as a longstring.
 types.addType("sourcedata", {
   write: (value, context, detail) => {
-    if (value.type === "arrayBuffer") {
-      return value;
+    if (value.typeName === "arraybuffer") {
+      return arraybufferType.write(value, context, detail);
     }
     return longstringType.write(value, context, detail);
   },
   read: (value, context, detail) => {
-    if (value.type === "arrayBuffer") {
-      return value;
+    // backward compatibility for FF67 or older: value might be an old style ArrayBuffer
+    // actor grip with type="arrayBuffer". The content should be the same so it can be
+    // translated to a regular ArrayBufferFront.
+    if (value.typeName === "arraybuffer" || value.type === "arrayBuffer") {
+      return arraybufferType.read(value, context, detail);
     }
     return longstringType.read(value, context, detail);
   },
 });
 
 types.addDictType("sourceposition", {
   line: "number",
   column: "number",