Bug 1574190 - Add watchpoint as a trait in the server, remove watchpoints when object actor is released, add watchpoint to property descriptor object r=jlast
authorMiriam <bmiriam1230@gmail.com>
Fri, 06 Sep 2019 18:12:06 +0000
changeset 492059 b0a5b50962e7774af1c0500098a7a14170397961
parent 492058 3182a1d6debb009c402ad74fba1c03a1a19966bf
child 492060 3bcc094e0863013bd86996c7665260594d6413e1
push id36543
push userncsoregi@mozilla.com
push dateSat, 07 Sep 2019 09:40:21 +0000
treeherdermozilla-central@de62729b366c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlast
bugs1574190
milestone71.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 1574190 - Add watchpoint as a trait in the server, remove watchpoints when object actor is released, add watchpoint to property descriptor object r=jlast Differential Revision: https://phabricator.services.mozilla.com/D45044
devtools/server/actors/object.js
devtools/server/actors/root.js
--- a/devtools/server/actors/object.js
+++ b/devtools/server/actors/object.js
@@ -103,27 +103,30 @@ const proto = {
     this._originalDescriptors = new Map();
   },
 
   rawValue: function() {
     return this.obj.unsafeDereference();
   },
 
   addWatchpoint(property, label, watchpointType) {
+    // We promote the object actor to the thread pool
+    // so that it lives for the lifetime of the watchpoint.
+    this.thread.threadObjectGrip(this);
+
     if (this._originalDescriptors.has(property)) {
       return;
     }
     const desc = this.obj.getOwnPropertyDescriptor(property);
 
-    //If there is already a setter or getter, don't add watchpoint.
     if (desc.set || desc.get) {
       return;
     }
 
-    this._originalDescriptors.set(property, desc);
+    this._originalDescriptors.set(property, { desc, watchpointType });
 
     const pauseAndRespond = () => {
       const frame = this.thread.dbg.getNewestFrame();
       this.thread._pauseAndRespond(frame, {
         type: "watchpoint",
         message: label,
       });
     };
@@ -132,42 +135,52 @@ const proto = {
       this.obj.defineProperty(property, {
         configurable: desc.configurable,
         enumerable: desc.enumerable,
         set: this.obj.makeDebuggeeValue(v => {
           desc.value = v;
         }),
         get: this.obj.makeDebuggeeValue(() => {
           pauseAndRespond();
+          return desc.value;
         }),
       });
     }
 
     if (watchpointType === "set") {
       this.obj.defineProperty(property, {
         configurable: desc.configurable,
         enumerable: desc.enumerable,
         set: this.obj.makeDebuggeeValue(v => {
+          pauseAndRespond();
           desc.value = v;
-          pauseAndRespond();
+        }),
+        get: this.obj.makeDebuggeeValue(v => {
+          return desc.value;
         }),
       });
     }
   },
 
   removeWatchpoint(property) {
     if (!this._originalDescriptors.has(property)) {
       return;
     }
 
-    const desc = this._originalDescriptors.get(property);
+    const desc = this._originalDescriptors.get(property).desc;
     this._originalDescriptors.delete(property);
     this.obj.defineProperty(property, desc);
   },
 
+  removeWatchpoints() {
+    this._originalDescriptors.forEach(property =>
+      this.removeWatchpoint(property)
+    );
+  },
+
   /**
    * Returns a grip for this actor for returning in a protocol message.
    */
   form: function() {
     const g = {
       type: "object",
       actor: this.actorID,
     };
@@ -776,18 +789,20 @@ const proto = {
       configurable: desc.configurable,
       enumerable: desc.enumerable,
     };
 
     if ("value" in desc) {
       retval.writable = desc.writable;
       retval.value = this.hooks.createValueGrip(desc.value);
     } else if (this._originalDescriptors.has(name)) {
-      const value = this._originalDescriptors.get(name).value;
-      retval.value = this.hooks.createValueGrip(value);
+      const watchpointType = this._originalDescriptors.get(name).watchpointType;
+      desc = this._originalDescriptors.get(name).desc;
+      retval.value = this.hooks.createValueGrip(desc.value);
+      retval.watchpoint = watchpointType;
     } else {
       if ("get" in desc) {
         retval.get = this.hooks.createValueGrip(desc.get);
       }
 
       if ("set" in desc) {
         retval.set = this.hooks.createValueGrip(desc.set);
       }
@@ -1011,13 +1026,15 @@ const proto = {
       proxyHandler: this.hooks.createValueGrip(this.obj.proxyHandler),
     };
   },
 
   /**
    * Release the actor, when it isn't needed anymore.
    * Protocol.js uses this release method to call the destroy method.
    */
-  release: function() {},
+  release: function() {
+    this.removeWatchpoints();
+  },
 };
 
 exports.ObjectActor = protocol.ActorClassWithSpec(objectSpec, proto);
 exports.ObjectActorProto = proto;
--- a/devtools/server/actors/root.js
+++ b/devtools/server/actors/root.js
@@ -177,16 +177,18 @@ RootActor.prototype = {
     // `front.startProfiler`. This is an optional parameter but it will throw an error if
     // the profiled Firefox doesn't accept it.
     perfActorVersion: 1,
     // Supports native log points and modifying the condition/log of an existing
     // breakpoints. Fx66+
     nativeLogpoints: true,
     // support older browsers for Fx69+
     hasThreadFront: true,
+    // Support watchpoints in the server for Fx71+
+    watchpoints: true,
   },
 
   /**
    * Return a 'hello' packet as specified by the Remote Debugging Protocol.
    */
   sayHello: function() {
     return {
       from: this.actorID,