Bug 1424722 - Create actors for symbol values. draft
authorOriol Brufau <oriol-bugzilla@hotmail.com>
Thu, 21 Dec 2017 01:03:20 +0100
changeset 716007 fd54bbecb80e4f72c51d4711190da6dfb1023a12
parent 714369 947b1418ebb23e1faf716cec11237c6861c5d061
child 744921 5373f95b7890d6910217af3a0665adbc1e2c405a
push id94298
push userbmo:oriol-bugzilla@hotmail.com
push dateThu, 04 Jan 2018 22:38:30 +0000
bugs1424722
milestone59.0a1
Bug 1424722 - Create actors for symbol values. MozReview-Commit-ID: KZkdOccFhRn
devtools/server/actors/object.js
devtools/server/tests/unit/test_symbolactor.js
devtools/server/tests/unit/xpcshell.ini
--- a/devtools/server/actors/object.js
+++ b/devtools/server/actors/object.js
@@ -2255,17 +2255,17 @@ var stringifiers = {
 function makeDebuggeeValueIfNeeded(obj, value) {
   if (value && (typeof value == "object" || typeof value == "function")) {
     return obj.makeDebuggeeValue(value);
   }
   return value;
 }
 
 /**
- * Creates an actor for the specied "very long" string. "Very long" is specified
+ * Creates an actor for the specified "very long" string. "Very long" is specified
  * at the server's discretion.
  *
  * @param string String
  *        The string.
  */
 function LongStringActor(string) {
   this.string = string;
   this.stringLength = string.length;
@@ -2311,17 +2311,17 @@ LongStringActor.prototype = {
     };
   },
 
   /**
    * Handle a request to release this LongStringActor instance.
    */
   onRelease: function () {
     // TODO: also check if registeredPool === threadActor.threadLifetimePool
-    // when the web console moves aray from manually releasing pause-scoped
+    // when the web console moves away from manually releasing pause-scoped
     // actors.
     this._releaseActor();
     this.registeredPool.removeActor(this);
     return {};
   },
 
   _releaseActor: function () {
     if (this.registeredPool && this.registeredPool.longStringActors) {
@@ -2331,17 +2331,80 @@ LongStringActor.prototype = {
 };
 
 LongStringActor.prototype.requestTypes = {
   "substring": LongStringActor.prototype.onSubstring,
   "release": LongStringActor.prototype.onRelease
 };
 
 /**
- * Creates an actor for the specied ArrayBuffer.
+ * Creates an actor for the specified symbol.
+ *
+ * @param symbol Symbol
+ *        The symbol.
+ */
+function SymbolActor(symbol) {
+  this.symbol = symbol;
+}
+
+SymbolActor.prototype = {
+  actorPrefix: "symbol",
+
+  rawValue: function () {
+    return this.symbol;
+  },
+
+  destroy: function () {
+    // Because symbolActors is not a weak map, we won't automatically leave
+    // it so we need to manually leave on destroy so that we don't leak
+    // memory.
+    this._releaseActor();
+  },
+
+  /**
+   * Returns a grip for this actor for returning in a protocol message.
+   */
+  grip: function () {
+    let form = {
+      type: "symbol",
+      actor: this.actorID,
+    };
+    let name = getSymbolName(this.symbol);
+    if (name !== undefined) {
+      // Create a grip for the name because it might be a longString.
+      form.name = createValueGrip(name, this.registeredPool);
+    }
+    return form;
+  },
+
+  /**
+   * Handle a request to release this SymbolActor instance.
+   */
+  onRelease: function () {
+    // TODO: also check if registeredPool === threadActor.threadLifetimePool
+    // when the web console moves away from manually releasing pause-scoped
+    // actors.
+    this._releaseActor();
+    this.registeredPool.removeActor(this);
+    return {};
+  },
+
+  _releaseActor: function () {
+    if (this.registeredPool && this.registeredPool.symbolActors) {
+      delete this.registeredPool.symbolActors[this.symbol];
+    }
+  }
+};
+
+SymbolActor.prototype.requestTypes = {
+  "release": SymbolActor.prototype.onRelease
+};
+
+/**
+ * Creates an actor for the specified ArrayBuffer.
  *
  * @param buffer ArrayBuffer
  *        The buffer.
  */
 function ArrayBufferActor(buffer) {
   this.buffer = buffer;
   this.bufferLength = buffer.byteLength;
 }
@@ -2428,24 +2491,17 @@ function createValueGrip(value, pool, ma
           optimizedOut: value.optimizedOut,
           uninitialized: value.uninitialized,
           missingArguments: value.missingArguments
         };
       }
       return makeObjectGrip(value, pool);
 
     case "symbol":
-      let form = {
-        type: "symbol"
-      };
-      let name = getSymbolName(value);
-      if (name !== undefined) {
-        form.name = createValueGrip(name, pool, makeObjectGrip);
-      }
-      return form;
+      return symbolGrip(value, pool);
 
     default:
       assert(false, "Failed to provide a grip for: " + value);
       return null;
   }
 }
 
 const symbolProtoToString = Symbol.prototype.toString;
@@ -2485,16 +2541,39 @@ function longStringGrip(str, pool) {
 
   let actor = new LongStringActor(str);
   pool.addActor(actor);
   pool.longStringActors[str] = actor;
   return actor.grip();
 }
 
 /**
+ * Create a grip for the given symbol.
+ *
+ * @param sym Symbol
+ *        The symbol we are creating a grip for.
+ * @param pool ActorPool
+ *        The actor pool where the new actor will be added.
+ */
+function symbolGrip(sym, pool) {
+  if (!pool.symbolActors) {
+    pool.symbolActors = Object.create(null);
+  }
+
+  if (sym in pool.symbolActors) {
+    return pool.symbolActors[sym].grip();
+  }
+
+  let actor = new SymbolActor(sym);
+  pool.addActor(actor);
+  pool.symbolActors[sym] = actor;
+  return actor.grip();
+}
+
+/**
  * 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) {
@@ -2589,12 +2668,13 @@ function isArrayIndex(str) {
   return num + "" === str &&
     // Array indices cannot attain the maximum Uint32 value.
     num != -1 >>> 0;
 }
 
 exports.ObjectActor = ObjectActor;
 exports.PropertyIteratorActor = PropertyIteratorActor;
 exports.LongStringActor = LongStringActor;
+exports.SymbolActor = SymbolActor;
 exports.createValueGrip = createValueGrip;
 exports.stringIsLong = stringIsLong;
 exports.longStringGrip = longStringGrip;
 exports.arrayBufferGrip = arrayBufferGrip;
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/unit/test_symbolactor.js
@@ -0,0 +1,49 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { SymbolActor } = require("devtools/server/actors/object");
+
+function run_test() {
+  test_SA_destroy();
+  test_SA_grip();
+  test_SA_raw();
+}
+
+const SYMBOL_NAME = "abc";
+const TEST_SYMBOL = Symbol(SYMBOL_NAME);
+
+function makeMockSymbolActor() {
+  let symbol = TEST_SYMBOL;
+  let actor = new SymbolActor(symbol);
+  actor.actorID = "symbol1";
+  actor.registeredPool = {
+    symbolActors: {
+      [symbol]: actor
+    }
+  };
+  return actor;
+}
+
+function test_SA_destroy() {
+  let actor = makeMockSymbolActor();
+  strictEqual(actor.registeredPool.symbolActors[TEST_SYMBOL], actor);
+
+  actor.destroy();
+  strictEqual(TEST_SYMBOL in actor.registeredPool.symbolActors, false);
+}
+
+function test_SA_grip() {
+  let actor = makeMockSymbolActor();
+  let grip = actor.grip();
+  strictEqual(grip.type, "symbol");
+  strictEqual(grip.actor, actor.actorID);
+  strictEqual(grip.name, SYMBOL_NAME);
+}
+
+function test_SA_raw() {
+  let actor = makeMockSymbolActor();
+  strictEqual(actor.rawValue(), TEST_SYMBOL);
+}
--- a/devtools/server/tests/unit/xpcshell.ini
+++ b/devtools/server/tests/unit/xpcshell.ini
@@ -230,8 +230,9 @@ support-files = xpcshell_debugging_scrip
 [test_setBreakpoint-on-line-in-gcd-script.js]
 [test_setBreakpoint-on-line-with-multiple-offsets.js]
 [test_setBreakpoint-on-line-with-multiple-statements.js]
 [test_setBreakpoint-on-line-with-no-offsets.js]
 [test_setBreakpoint-on-line-with-no-offsets-in-gcd-script.js]
 [test_safe-getter.js]
 [test_client_close.js]
 [test_shapes_highlighter_helpers.js]
+[test_symbolactor.js]