Bug 1424722 - Create actors for symbol values.
MozReview-Commit-ID: KZkdOccFhRn
--- 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]