Closed Bug 1601618 Opened 4 years ago Closed 3 years ago

Use XPCOMUtils.defineLazyModuleGetters() to defer loading of not immediately necessary modules

Categories

(Remote Protocol :: Agent, task, P2)

task
Points:
2

Tracking

(Fission Milestone:Future, firefox88 fixed)

RESOLVED FIXED
88 Branch
Fission Milestone Future
Tracking Status
firefox88 --- fixed

People

(Reporter: whimboo, Assigned: whimboo)

References

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

Details

(Keywords: perf, Whiteboard: [bidi-m1-mvp])

Attachments

(1 file)

Right now we make use of ChromeUtils.import() in most of our domains, even for modules which aren't necessary when loading the JSM, or creating the contained domain. This is especially expensive in content context.

As such we should move all of those imports over to XPCOMUtils.defineLazyModuleGetters() like the following:

const { XPCOMUtils } = ChromeUtils.import(
  "resource://gre/modules/XPCOMUtils.jsm"
);

XPCOMUtils.defineLazyModuleGetters(this, {
  OS: "resource://gre/modules/osfile.jsm",
});

There has been talk about adopting ES module imports and/or making ChromeUtils.import lazy by default. I don’t know if there are concrete plans or what stage that work is at.

If memory serves me right the problem with implicit lazy loading (that ES modules do) is that there are plenty of cases elsewhere in Gecko that explicitly relies on the process-scoped behaviour of JSMs, and this may block us from adopting any one solution wholesale.

In any case, the modern way to lazy load modules is using ChromeUtils.defineModuleGetter, and it looks like XPCOMUtils.defineLazyModuleGetter was recently changed to use this internally. One caveat is that you must only use the three first arguments aObject, aName, aResource to gain this benefit. Otherwise it will revert to the old and slower JS-based import. I haven’t seen a single case where we rely on the custom behaviour offered by aSymbol, aPreLambda, aPostLambda, or aProxy. The plural version, XPCOMUtils.defineLazyModuleGetters uses ChromeUtils.defineLazyModuleGetter consistently.

To minimise the code we have to write we should prefer ChromeUtils.defineModuleGetter in cases with few imports and XPCOMUtils.defineLazyModuleGetters when there are more than a few, since importing XPCOMUtils.jsm adds a further three lines of boilerplate with its own import. I would argue we should avoid XPCOMUtils.defineLazyModuleGetter entirely because it’s easy to get the argument count wrong and because ChromeUtils.defineModuleGetter is functionally equivalent.

I forgot to say that the downside with all the lazy loading APIs currently on hand is that they make importing multiple symbols from the same module rather awkward:

ChromeUtils.defineModuleGetter(
    this,
    "foo",
    "chrome://remote/content/Whatever.jsm"
);
ChromeUtils.defineModuleGetter(
    this,
    "bar",
    "chrome://remote/content/Whatever.jsm"
);

As compared to:

const { foo, bar } = ChromeUtils.import("chrome://remote/content/Whatever.jsm");

But hopefully the shared state ES module/JSM import problems I alluded to earlier will be resolved at some point and we can have pretty, standards compliant code again…

In those cases it would be good if our modules would just export a single namespace. Very good example is OS. Note that we should do as much as possible lazy loading of modules for JSWindowActor child instances. Otherwise memory usage will spike up, and performance will be degraded.

(In reply to Henrik Skupin (:whimboo) [⌚️UTC+2] from comment #3)

In those cases it would be good if our modules would just export a single namespace. Very good example is OS.

Yes I agree, and that is the model we’ve largely followed throughout remote/. There have even been a couple of patches to move us further in that direction that you can see from the early history.

The notable exceptions are Sync.jsm and Error.jsm. We need to figure out how to structure the exported symbols in a meaningful way, so I’ve filed bug 1603167 to deal with this problem specifically.

Depends on: 1603167
Priority: P3 → P2
Whiteboard: [puppeteer-beta-mvp]
Whiteboard: [puppeteer-beta-mvp] → [puppeteer-beta-reserve]
Priority: P2 → P3
Fission Milestone: --- → Future
Blocks: 1660881
No longer blocks: 1660881
Whiteboard: [puppeteer-beta-reserve] → [puppeteer-beta2-mvp]

See bug 1660881 in how it was done in Marionette.

Not sure if we wanna do it for all the CDP specific modules, but at least we need it for BiDi and the shared modules.

Whiteboard: [puppeteer-beta2-mvp] → [bidi-m1-mvp]
Points: --- → 2
Assignee: nobody → hskupin
Status: NEW → ASSIGNED
Pushed by hskupin@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/ad4f4d69a6a9
[remote] Use lazy loading of modules and delayed setting of global properties. r=remote-protocol-reviewers,jdescottes
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → 88 Branch
Priority: P3 → P2
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: