Open Bug 1037992 Opened 10 years ago Updated 2 years ago

[meta] Refactor the thread actor to use protocol.js

Categories

(DevTools :: Framework, task, P5)

x86
macOS
task

Tracking

(Not tracked)

People

(Reporter: ejpbruel, Unassigned)

References

(Depends on 1 open bug, Blocks 2 open bugs)

Details

(Keywords: meta)

User Story

All actors in devtools/server/actors/script.js should be made subclasses of ActorClass. The methods they expose should be converted to use protocol.js. Additionally, they should be moved to their own individual files.

The actors are:

- EnvironmentActor (bug 1235371)
- ChromeDebuggerActor (bug 1239008)
- AddonThreadActor
- ThreadActor (bug 1256397, bug 1450284)
- PauseActor
- PauseScopedActor
- SourceActor (bug 1250896)
- PauseScopedObjectActor
- FrameActor (bug 1235375)
- BreakpointActor (bug 1235374)

Attachments

(4 files, 3 obsolete files)

A long term goal for the devtools team is to refactor all debugger actors to use protocol.js. The script actors are the most prominent amongst those, so they seem like a good place to start.
This patch refactors ThreadActor and its specializations, ChromeDebuggerActor and AddonDebuggerActor, to use protocol.js. It's not perfect yet (we could do better than simply returning a json packet as the return value for each request, for instance), but that's something we can address in a followup patch. The immediate goal here is to rewrite the actors in terms of ActorClass.

Protocol.js expects method names to match the type field of their corresponding request packet. Because of this, I had to rename the sources property to threadSources.

The attach and interrupt methods need some special handling because they enter a nested event loop. They need to send their response before the event loop is entered, and consequently, some way to inform protocol.js that a response doesn't need to be sent when the handler returns. For this purpose, I've added a new dummy type, NoResponseNeeded.
Attachment #8455050 - Flags: review?(past)
Assignee: nobody → ejpbruel
We actually had bug 698841 for this.
Comment on attachment 8455050 [details] [diff] [review]
Refactor ThreadActor to use protocol.js

Review of attachment 8455050 [details] [diff] [review]:
-----------------------------------------------------------------

This is a surprisingly small patch and it results in unsurprisingly cleaner code. But what about converting dbg-client.jsm to use actor fronts? That could be an even bigger win in terms of simplification and would add a sanity check to these changes.

::: toolkit/devtools/server/actors/script.js
@@ +491,5 @@
>   */
> +types.addDictType("location", {
> +  url: "string",
> +  line: "number",
> +  column: "nullable:number",

Why is addDictType necessary here? Since the location properties are all primitives it seems that "json" would be the type we need here.

Also, the comment above applies to the ThreadActor below.

@@ +783,5 @@
>      }
>  
>      this._state = "attached";
>  
> +    update(this._options, options || {});

The "|| {}" part shouldn't be necessary with the argument's default value, right?

@@ +828,5 @@
> +    request: {
> +      options: {
> +        autoBlackBox: Option(0, "boolean"),
> +        ignoreCaughtExceptions: Option(0, "boolean"),
> +        pauseOnDOMEvents: Option(0, "boolean"),

pauseOnDOMEvents is not a boolean, its value will be an array or a string.

@@ +853,5 @@
>      if (this.state == "exited") {
>        return { error: "wrongState" };
>      }
>  
> +    update(this._options, options || {});

How about we use {} as the default options value instead?

@@ +863,5 @@
> +    request: {
> +      options: {
> +        autoBlackBox: Option(0, "boolean"),
> +        ignoreCaughtExceptions: Option(0, "boolean"),
> +        pauseOnDOMEvents: Option(0, "boolean"),

Same here: pauseOnDOMEvents is not a boolean, its value will be an array or a string.

@@ +1197,5 @@
> +      ignoreCaughtExceptions: Option(0, "boolean"),
> +      pauseOnExceptions: Option(0, "boolean"),
> +      pauseOnDOMEvents: Option(0),
> +      resumeLimit: Option(0),
> +    },

This doesn't look like it's buying us much compared to the simpler: Arg(0, "json").

@@ +1524,5 @@
> +      condition: Arg(1, "nullable:string"),
> +    },
> +    response: RetVal(types.addDictType("setBreakpointResponse", {
> +      actualLocation: "location",
> +    })),

This too doesn't seem much better than RetVal("json").

@@ +4832,5 @@
>   *        An object with preNest and postNest methods for calling when entering
>   *        and exiting a nested event loop.
>   */
> +const ChromeDebuggerActor = Class({
> +  extends: ThreadActor,

Hmm, doesn't extending via Class() result in reusing the typeName of the parent? I can't find this pattern anywhere in our code. Won't that be a problem if/when we try to serialize these actors?

Perhaps this is the kind of problem that will appear when the actor fronts are implemented.

@@ +5663,5 @@
> +/* -*- 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/. */

Er, what is that?

::: toolkit/devtools/server/protocol.js
@@ +950,5 @@
>          let args = spec.request.read(packet, this);
>  
>          let ret = this[spec.name].apply(this, args);
>  
> +        if (spec.oneway || (ret instanceof NoResponseNeeded)) {

Nit: instanceof has a higher precedence than || so the parens are unnecessary.
Attachment #8455050 - Flags: review?(past)
Blocks: dbg-server
Attached patch Implement ProtocolError. (obsolete) — Splinter Review
As far as I can tell, protocol.js does not offer a way to send back custom error packets to the client, something that the script actors do quite often.

It looks like it would be easy to tweak protocol.js to support this, by implementing a custom error class. Here's a patch that does just that.
Attachment #8455050 - Attachment is obsolete: true
Attachment #8664233 - Flags: review?(past)
I'm still a bit unfamiliar with protocol.js, so I have a quick question.

EnvironmentActor supports a bindings request which returns a list of bindings for that environment. The response is essentially a JSON object, but some fields in it are value grips, and therefore might be actors.

Since the structure of the bindings object can't be known ahead of time, the best we can do here is to make the response RetVal("json"), right? That is, we can't really make a special type for this.
Attachment #8664243 - Flags: feedback?(past)
I have more patches coming up, but it looks like jryans just landed his mass move of the devtools code, so I'm going to have to do some rebasing tomorrow morning before filing the rest.
Comment on attachment 8664243 [details] [diff] [review]
Change EnvironmentActor to protocol.js

Review of attachment 8664243 [details] [diff] [review]:
-----------------------------------------------------------------

I think a JSON value should work, which you can easily test once the patch is testable. Another approach in similar cases is to define a new type for this particular response, if you need special marshaling. Here is such a case from Valence:

https://github.com/mozilla/valence/blob/master/lib/chromium/value.js#L26

You can see the chromium_grip type being used in the webconsole, for example:

https://github.com/mozilla/valence/blob/master/lib/chromium/webconsole.js#L12
Attachment #8664243 - Flags: feedback?(past) → feedback+
Fixed a minor bug in this patch.
Attachment #8664233 - Attachment is obsolete: true
Attachment #8664233 - Flags: review?(past)
Attachment #8664978 - Flags: review?(jryans)
A couple of notes on the upcoming patches:
- Some of the script actors do some funky stuff (such as ThreadActor manually   
  sending a response packet before entering a nested event loop), so the plan is 
  to attack these actors one at a time.
- I'm not going to refactor the client fronts yet: doing so would interfere with 
  jlongster's refactor of the frontend. I will file a followup for refactoring   
  the fronts once this bug is fixed.
Attachment #8664243 - Attachment is obsolete: true
Attachment #8664980 - Flags: review?(jryans)
Attachment #8664982 - Flags: review?(jryans)
Attachment #8664984 - Flags: review?(jryans)
Depends on: 1207702
Comment on attachment 8664980 [details] [diff] [review]
Change EnvironmentActor to protocol.js

Review of attachment 8664980 [details] [diff] [review]:
-----------------------------------------------------------------

::: devtools/server/actors/script.js
@@ +3416,5 @@
>   *        The lexical environment that will be used to create the actor.
>   * @param ThreadActor aThreadActor
>   *        The parent thread actor that contains this environment.
>   */
> +let EnvironmentActor = ActorClass({

I guess these actor will manage their lifetimes outside of p.js's usual flow?  I see this one is added a to a pool, for example.
Attachment #8664980 - Flags: review?(jryans) → review+
Comment on attachment 8664982 [details] [diff] [review]
Change BreakpointActor to protocol.js

Review of attachment 8664982 [details] [diff] [review]:
-----------------------------------------------------------------

::: devtools/server/actors/script.js
@@ +3255,2 @@
>  
> +  initialize: function (aThreadActor, aOriginalLocation) {

You could convert away from `aArg` style to `arg` if you wanted...

@@ +3392,5 @@
> +  delete: method(function () {
> +    return this._delete();
> +  }),
> +
> +  _delete: function () {

You don't need 2 separate functions.  It's safe for an actor to call a function defined via p.js `method(...)` directly, because `method(...)` returns the function itself, which will be available on the actor object like normal.
Attachment #8664982 - Flags: review?(jryans)
Comment on attachment 8664978 [details] [diff] [review]
Implement ProtocolError.

Review of attachment 8664978 [details] [diff] [review]:
-----------------------------------------------------------------

::: devtools/server/protocol.js
@@ +907,5 @@
>      console.error(err);
>      if (err.stack) {
>        dump(err.stack);
>      }
> +    if (err instanceof ProtocolError) {

Please add a test of this new protocol.js behavior.  See devtools/server/tests/unit/test_protocol_*.

@@ +1438,5 @@
> + *   Optional. Other fields to be included in the error packet.
> + * @constructor
> + */
> +var ProtocolError = Class({
> +  initialize: function (error, message = "", packet = {}) {

Hmm, any reason to prefer this style over just accepting an object for the whole thing including error and message?

Does it make sense to extend from the Error object?
Attachment #8664978 - Flags: review?(jryans)
I'm splitting this out into separate issues and turning this into a META. I've moved the attached patches to:

- bug 1235370
- bug 1235371
- bug 1235374
- bug 1235375

Please add yourself to the CC list to those issues if you want to follow their progress.
Summary: Refactor the script actors to use protocol.js → [META] Refactor the script actors to use protocol.js
Assignee: ejpbruel → lclark
User Story: (updated)
Status: NEW → ASSIGNED
User Story: (updated)
Depends on: 1239008
Depends on: 1250896
Un-assigning since I'm focusing on web console atm.
Assignee: lclark → nobody
Status: ASSIGNED → NEW
Depends on: 1256397
See Also: → 1263289
Blocks: 1263289, 1265717
Severity: normal → enhancement
Summary: [META] Refactor the script actors to use protocol.js → [meta-html] Refactor the script actors to use protocol.js
Whiteboard: [meta-html] [devtools-html]
Blocks: devtools-html-phase2
No longer blocks: 1263289
Whiteboard: [meta-html] [devtools-html] → [meta-html]
No longer blocks: devtools-html-phase2
Summary: [meta-html] Refactor the script actors to use protocol.js → Refactor the script actors to use protocol.js
Whiteboard: [meta-html]
Keywords: meta
Priority: -- → P5
Summary: Refactor the script actors to use protocol.js → [meta] Refactor the script actors to use protocol.js
Product: Firefox → DevTools
Type: enhancement → task
Component: Debugger → Framework
Summary: [meta] Refactor the script actors to use protocol.js → [meta] Refactor the thread actor to use protocol.js

ThreadActor is the last actor to not be using protocol.js
A proof of that is this usage of requestTypes:
https://searchfox.org/mozilla-central/rev/c61720a7d0c094d772059f9d6a7844eb7619f107/devtools/server/actors/thread.js#2245-2256
And many usages of .form() in the actor, which means that we are not using protocol.js automatic marshalling.

Depends on: 1604733
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: