forked from mirrors/gecko-dev
Bug 1807899 - Remove the trailing whitespace and Windows CR on md files r=linter-reviewers,necko-reviewers,marco,jesup
Differential Revision: https://phabricator.services.mozilla.com/D165662
This commit is contained in:
parent
e3f27e55cf
commit
e2b52a1324
69 changed files with 696 additions and 716 deletions
|
|
@ -29,7 +29,7 @@ Special custom onboarding experience shown to users when they try to download an
|
|||
|
||||
Note that this uses [attribution data](https://docs.google.com/document/d/1zB5zwiyNVOiTD4I3aZ-Wm8KFai9nnWuRHsPg-NW4tcc/edit#heading=h.szk066tfte4n) added to the browser during the download process, which is only currently implemented for Windows.
|
||||
|
||||
Testing instructions:
|
||||
Testing instructions:
|
||||
- Set pref browser.newtabpage.activity-stream.asrouter.devtoolsEnabled as true
|
||||
- Open about:newtab#devtools
|
||||
- Click Targeting -> Attribution -> Force Attribution
|
||||
|
|
@ -39,7 +39,7 @@ Testing instructions:
|
|||
- Run experiments and roll-outs through Nimbus (see [FeatureManifests](https://searchfox.org/mozilla-central/rev/5e955a47c4af398e2a859b34056017764e7a2252/toolkit/components/nimbus/FeatureManifest.js#56)), only windows is supported. FeatureConfig (from prefs or experiments) has higher precedence to defaults. See [Default experience variations](#default-experience-variations)
|
||||
- AboutWelcomeDefaults methods [getDefaults](https://searchfox.org/mozilla-central/rev/81c32a2ea5605c5cb22bd02d28c362c140b5cfb4/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm#539) and [prepareContentForReact](https://searchfox.org/mozilla-central/rev/81c32a2ea5605c5cb22bd02d28c362c140b5cfb4/browser/components/newtab/aboutwelcome/lib/AboutWelcomeDefaults.jsm#566) have dynamic rules which are applied to both experiments and default UI before content is shown to user.
|
||||
- about:welcome only shows up for users who download Firefox Beta or release (currently not enabled on Nightly)
|
||||
- [Enterprise builds](https://searchfox.org/mozilla-central/rev/5e955a47c4af398e2a859b34056017764e7a2252/browser/components/enterprisepolicies/Policies.jsm#1385) can turn off about:welcome by setting the browser.aboutwelcome.enabled preference to false.
|
||||
- [Enterprise builds](https://searchfox.org/mozilla-central/rev/5e955a47c4af398e2a859b34056017764e7a2252/browser/components/enterprisepolicies/Policies.jsm#1385) can turn off about:welcome by setting the browser.aboutwelcome.enabled preference to false.
|
||||
|
||||
#### Default experience variations
|
||||
In order of precedence:
|
||||
|
|
@ -52,7 +52,7 @@ In order of precedence:
|
|||
- Import screen allows user to import password, bookmarks and browsing history from previous browser.
|
||||
- Set a theme lets users personalize Firefox with a theme.
|
||||
|
||||
### Upgrade Dialog
|
||||
### Upgrade Dialog
|
||||
Upgrade Dialog was first introduced in Fx89 with MR1 release. It replaces whatsnew tab with an upgrade modal explaining proton changes, setting Firefox as default and/or pinning, and allowing theme change.
|
||||
|
||||
#### Feature Details:
|
||||
|
|
|
|||
|
|
@ -64,4 +64,4 @@ If there is no `USB_RUNTIMES` environment variable, the tests will not run. This
|
|||
}
|
||||
// Of course, you can append additional USB devices. Some tests can do with multiple devices.
|
||||
]
|
||||
```
|
||||
```
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ instances, and source maps in general.)
|
|||
* `indent` - The string that you want your code indented by. Most people want
|
||||
one of `" "`, `" "`, or `"\t"`.
|
||||
|
||||
* `ecmaVersion` - Indicates the ECMAScript version to parse.
|
||||
* `ecmaVersion` - Indicates the ECMAScript version to parse.
|
||||
See acorn.parse documentation for more details. Defaults to `"latest"`.
|
||||
|
||||
## Issues
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ RootActor: First one, automatically instantiated when we start connecting.
|
|||
| PreferenceActor (for Firefox prefs)
|
||||
|
|
||||
\-- Descriptor Actor's -or- Watcher Actor
|
||||
|
|
||||
|
|
||||
\ -- Target actors:
|
||||
Actors that represent the main "thing" being targeted by a given toolbox,
|
||||
such as a tab, frame, worker, add-on, etc. and track its lifetime.
|
||||
|
|
|
|||
|
|
@ -56,4 +56,3 @@ It can also be useful for patch authors: if the changes comply with these guidel
|
|||
* R+: the code should land as soon as possible.
|
||||
* R+ with comments: there are some comments, but they are minor enough, or don't require a new review once addressed, trust the author.
|
||||
* R cancel / R- / F+: there is something wrong with the code, and a new review is required.
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ If you added an `:ircnickname` in your Bugzilla's `Real name`, Phabricator will
|
|||
|
||||
---
|
||||
|
||||
Once you understand the above, please [create a Phabricator account](https://moz-conduit.readthedocs.io/en/latest/phabricator-user.html#creating-an-account).
|
||||
Once you understand the above, please [create a Phabricator account](https://moz-conduit.readthedocs.io/en/latest/phabricator-user.html#creating-an-account).
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,4 +7,3 @@ We have pages defining standards, best practices and tips for various languages
|
|||
* [JavaScript](./javascript.md)
|
||||
* [CSS](./css.md)
|
||||
* [SVG](../frontend/svgs.md)
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ The appropriate value for the `dir` attribute will then be set when the toolbox
|
|||
|
||||
### Testing
|
||||
|
||||
The recommended workflow to test RTL on DevTools is to use the [Force RTL extension](https://addons.mozilla.org/en-US/firefox/addon/force-rtl/). After changing the direction using Force RTL, you should restart DevTools to make sure all modules apply the new direction. A future version of Force RTL will be able to update dynamically all DevTools documents.<!--TODO: update when the fate of this addon/webextension is known-->
|
||||
The recommended workflow to test RTL on DevTools is to use the [Force RTL extension](https://addons.mozilla.org/en-US/firefox/addon/force-rtl/). After changing the direction using Force RTL, you should restart DevTools to make sure all modules apply the new direction. A future version of Force RTL will be able to update dynamically all DevTools documents.<!--TODO: update when the fate of this addon/webextension is known-->
|
||||
|
||||
## Toggles
|
||||
|
||||
|
|
@ -128,4 +128,3 @@ The Mozilla way is to perform the toggle using an attribute rather than a class:
|
|||
|
||||
* Use `:empty` to match a node that doesn't have children.
|
||||
* Usually, if `margin` or `padding` has 4 values, something is wrong. If the left and right values are asymmetrical, you're supposed to use `-start` and `-end`. If the values are symmetrical, use only 3 values (see localization section).
|
||||
|
||||
|
|
|
|||
|
|
@ -155,4 +155,3 @@ This should help you write eslint-clean code:
|
|||
* ESLint also runs on `<script>` tags in HTML files, so if you create new HTML test files for mochitests for example, make sure that JavaScript code in those files is free of ESLint errors.
|
||||
* Depending on how a dependency is loaded into a file, the symbols this dependency exports might not be considered as defined by ESLint. For instance, using `Cu.import("some.jsm")` doesn't explicitly say which symbols are now available in the scope of the file, and so using those symbols will be consider by ESLint as using undefined variables. When this happens, please avoid using the `/* globals ... */` ESLint comment (which tells it that these variables are defined). Instead, please use `/* import-globals-from relative/path/to/file.js */`. This way, you won't have a list of variables to maintain manually, the globals are going to be imported dynamically instead.
|
||||
* In test files (xpcshell and mochitest), all globals from the corresponding `head.js` file are imported automatically, so you don't need to define them using a `/* globals ... */` comment or a `/* import-globals-from head.js */` comment.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Getting started working on a bug can be hard, specially if you lack context.
|
||||
|
||||
This guide is meant to provide a list of steps to provide the necessary information to resolve a bug.
|
||||
This guide is meant to provide a list of steps to provide the necessary information to resolve a bug.
|
||||
|
||||
* Use a descriptive title. Avoid jargon and abbreviations where possible, they make it hard for other people to find existing bugs, and to understand them.
|
||||
* Explain the problem in depth and provide the steps to reproduce. Be as specific as possible, and include things such as operating system and version if reporting a bug.
|
||||
|
|
|
|||
|
|
@ -10,4 +10,3 @@ This page provides a very top level overview of what is on each directory in the
|
|||
* `devtools/client`: Code for the front-end side of our tools. In theory, each directory corresponds to a panel, but this is not always the case. This directory is only shipped with desktop Firefox, as opposed to other directories above, which are shipped with all Gecko products (Firefox for Android, etc.)
|
||||
* `devtools/client/locales`: Strings used in the client front-end.
|
||||
* `devtools/client/themes`: CSS and images used in the client front-end.
|
||||
|
||||
|
|
|
|||
|
|
@ -39,4 +39,4 @@ Sketch vector work is a little different but the fundamentals (keeping your SVG
|
|||
|
||||
- **Expand all your paths so strokes expand properly as the SVG gets resized.** You can do this at ```Layer > Paths > Vectorize Stroke```.
|
||||
|
||||
- **Align anything that isn't boxy to the pixel grid with item selected then ```Layer > Round to Nearest Pixel Edge```.**
|
||||
- **Align anything that isn't boxy to the pixel grid with item selected then ```Layer > Round to Nearest Pixel Edge```.**
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Claim the bug by creating a Bugzilla account and posting a comment on the bug’
|
|||
|
||||
## Set up your dev environment
|
||||
|
||||
Follow the steps of Firefox’s [contributor guide](https://firefox-source-docs.mozilla.org/contributing/how_to_contribute_firefox.html) to install and run Firefox locally. During installation, follow the steps for “Artifact Mode.”
|
||||
Follow the steps of Firefox’s [contributor guide](https://firefox-source-docs.mozilla.org/contributing/how_to_contribute_firefox.html) to install and run Firefox locally. During installation, follow the steps for “Artifact Mode.”
|
||||
|
||||
If you run into errors about missing libraries, search the web to learn how to install whatever is missing. If you get stuck, ask for help on [Matrix](https://chat.mozilla.org/#/room/#devtools:mozilla.org).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Architecture overview
|
||||
# Architecture overview
|
||||
|
||||
Broadly speaking, the tools are divided in two parts: the server and the client. A **server** is anything that can be debugged: for example, your browser, but it could also be Firefox for Android, running on another device. The **client** is the front-end side of the tools, and it is what developers interact with when using the tools.
|
||||
|
||||
|
|
@ -9,5 +9,3 @@ You will often hear about `actors`. Each feature that can be debugged (for examp
|
|||
Often, an actor will correspond to a panel. But a panel might want to get data from multiple actors.
|
||||
|
||||
You might also hear about `the toolbox`. The toolbox is what everyone else calls `developer tools` i.e. the front-end that you see when you open the tools in your browser.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,4 +11,3 @@ On the other hand, the repositories in `devtools-html` are more straightforward
|
|||
Even if you only want to work on a tool whose code is on `devtools-html`, you might still need to go through the step of getting and compiling the code from `mozilla-central` in order to do integration work (such as updating a tool bundle).
|
||||
|
||||
From now on, this guide will focus on building the full DevTools within Firefox. Please refer to individual project instructions for tools hosted in `devtools-html`.
|
||||
|
||||
|
|
|
|||
|
|
@ -11,4 +11,3 @@ To run a specific chrome mochitest:
|
|||
```bash
|
||||
./mach mochitest devtools/path/to/the/test_you_want_to_run.html
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -66,4 +66,3 @@ Then we can run our test with:
|
|||
```
|
||||
./mach talos-test --suite damp --subtest inspector.click
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -38,4 +38,4 @@ window.addEventListener("click", function () {
|
|||
## Keep your test execution short.
|
||||
|
||||
Running performance tests is expensive. We are currently running them 25 times for each changeset landed in Firefox.
|
||||
Aim to run tests in less than a second on try.
|
||||
Aim to run tests in less than a second on try.
|
||||
|
|
|
|||
|
|
@ -142,4 +142,3 @@ Once it is done executing, the profile lives in a zip file you have to uncompres
|
|||
unzip testing/mozharness/build/blobber_upload_dir/profile_damp.zip
|
||||
```
|
||||
Then you have to open [https://profiler.firefox.com/](https://profiler.firefox.com/) and manually load the profile file that lives here: `profile_damp/page_0_pagecycle_1/cycle_0.profile`
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ For example, if you were to add the test from the previous section, you'd add th
|
|||
|
||||
Sometimes your test may need to open an HTML file in a tab, and it may also need to load CSS or JavaScript. For this to work, you'll need to...
|
||||
|
||||
1. place these files in the same directory, and also
|
||||
1. place these files in the same directory, and also
|
||||
2. reference them in the `browser.ini` file.
|
||||
|
||||
There's a naming convention for support files: `doc_<support-some-test>.html`
|
||||
|
|
@ -222,7 +222,7 @@ When tests fail, it's far better to have them fail and end immediately with an e
|
|||
|
||||
## Adding new helpers
|
||||
|
||||
In some cases, you may want to extract some common code from your test to use it another another test.
|
||||
In some cases, you may want to extract some common code from your test to use it another another test.
|
||||
|
||||
* If this is very common code that all tests could use, then add it to `devtools/client/shared/test/shared-head.js`.
|
||||
* If this is common code specific to a given tool, then add it to the corresponding `head.js` file.
|
||||
|
|
@ -235,4 +235,3 @@ In some cases, you may want to extract some common code from your test to use it
|
|||
* Use the special ESLint comment `/* import-globals-from helper_file.js */` to prevent ESLint errors for undefined variables.
|
||||
|
||||
In all cases, new helper functions should be properly commented with an jsdoc comment block.
|
||||
|
||||
|
|
|
|||
|
|
@ -11,4 +11,3 @@ To run a specific xpcshell test:
|
|||
```bash
|
||||
./mach xpcshell-test devtools/path/to/the/test_you_want_to_run.js
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,158 +1,158 @@
|
|||
# Console Tool Architecture
|
||||
|
||||
The Console panel is responsible for rendering all logs coming from the current page.
|
||||
|
||||
## Architecture
|
||||
|
||||
Internal architecture of the Console panel (the client side) is described
|
||||
on the following diagram.
|
||||
|
||||
<figure class="hero">
|
||||
<pre class="diagram">
|
||||
┌──────────────────────────────┐ ┌────────────────────────┐
|
||||
│ DevTools │ │ WebConsolePanel │
|
||||
│[client/framework/devtools.js]│ │ [panel.js] │
|
||||
└──────────────────────────────┘ └────────────────────────┘
|
||||
│ │
|
||||
│
|
||||
openBrowserConsole() or │
|
||||
toggleBrowserConsole() │
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────────────────────────┐ {hud}
|
||||
│ BrowserConsoleManager │ │
|
||||
│ [browser-console-manager.js] │ │
|
||||
└──────────────────────────────┘ │
|
||||
│ │
|
||||
│ │
|
||||
{_browserConsole} │
|
||||
│ │
|
||||
▼ 0..1 ▼ 1
|
||||
┌──────────────────────────────┐ ┌────────────────────────┐
|
||||
│ BrowserConsole │ │ WebConsole │
|
||||
│ [browser-console.js] │─ ─ extends ─ ▶│ [webconsole.js] │
|
||||
└──────────────────────────────┘ └──────────────1─────────┘
|
||||
│
|
||||
{ui}
|
||||
│
|
||||
▼ 1
|
||||
┌────────────────────────┐
|
||||
│ WebConsoleUI │
|
||||
│ [webconsole-ui.js] │
|
||||
└────────────────────────┘
|
||||
│
|
||||
{wrapper}
|
||||
│
|
||||
│
|
||||
▼ 1
|
||||
┌────────────────────────┐
|
||||
│ WebConsoleWrapper │
|
||||
│[webconsole-wrapper.js] │
|
||||
└────────────────────────┘
|
||||
│
|
||||
<renders>
|
||||
│
|
||||
▼
|
||||
┌────────────────────────┐
|
||||
│ App │
|
||||
└────────────────────────┘
|
||||
</pre>
|
||||
<figcaption>Elements between curly bracket on arrows represent the property name of the reference (for example, the WebConsolePanel as a `hud` property that is a reference to the WebConsole instance)</figcaption>
|
||||
</figure>
|
||||
|
||||
## Components
|
||||
|
||||
The Console panel UI is built on top of [React](../frontend/react.md). It defines set of React components in `components` directory
|
||||
The React architecture is described on the following diagram.
|
||||
|
||||
<figure class="hero">
|
||||
<pre class="diagram">
|
||||
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
WebConsole React components │
|
||||
│ [/components] ┌────────────────────────┐
|
||||
│ App │ │
|
||||
│ └────────────────────────┘
|
||||
│ │
|
||||
│ │
|
||||
┌───────────────────┬──────────────────────┬───────────────────┬───────────┴─────────┬───────────────────────┬────────────────────┬─────────────────┐ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ │ ┌────────────────────────────────────────┐
|
||||
│ ┌──────────┐ ┌────────────────┐ ┌────────────────┐ ┌───────────┐ ┌────────────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────┐ │ Editor │
|
||||
│ SideBar │ │NotificationBox │ │ ConfirmDialog │ │ FilterBar │ │ ReverseSearchInput │ │ConsoleOutput │ │EditorToolbar │ │ JSTerm │──.editor───▶│ <CodeMirror> │
|
||||
│ └──────────┘ └────────────────┘ │ <portal> │ └───────────┘ └────────────────────┘ └──────────────┘ └──────────────┘ └─────────┘ │ [client/shared/sourceeditor/editor.js] │
|
||||
│ └────────────────┘ │ │ │ └────────────────────────────────────────┘
|
||||
│ │ ┌─────────┴─────────────┐ │
|
||||
│ │ │ │ │
|
||||
│ │ ▼ ▼ ▼
|
||||
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
|
||||
│ │ │ FilterButton │ │ FilterCheckbox │ │ MessageContainer │
|
||||
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ │ ┌──────────────────┐
|
||||
│ │ Message │ │
|
||||
│ │ └──────────────────┘
|
||||
│ │ │ ┌─────────────────────────────────────┐
|
||||
│ │ │ │ Frame │
|
||||
│ ┌─────────────────────┬─────────────────────┬─────────────────────┬───────┴─────────────┬─────────────────────┬─────────────┼─────┬──▶│ [client/shared/components/Frame.js] │
|
||||
│ │ │ │ │ │ │ │ │ └─────────────────────────────────────┘
|
||||
│ ▼ ▼ ▼ ▼ ▼ ▼ │ │
|
||||
│ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ ┌────────────────────────────────────────┐
|
||||
│ │ MessageIndent │ │ MessageIcon │ │ CollapseButton │ │ GripMessageBody │ │ ConsoleTable │ │ MessageRepeat │ │ │ │ SmartTrace │
|
||||
│ │ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ ├──▶│[client/shared/components/SmartTrace.js]│
|
||||
│ │ │ │ │ └────────────────────────────────────────┘
|
||||
└ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
|
||||
│ │ │ │ ┌──────────────────────────────────────────────────┐
|
||||
│ │ │ │ │ TabboxPanel │
|
||||
│ ├─────────────────────┘ └──▶│[client/netmonitor/src/components/TabboxPanel.js] │
|
||||
│ │ └──────────────────────────────────────────────────┘
|
||||
│ │
|
||||
│ │
|
||||
│ ▼
|
||||
│ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
│ Reps ┌──────────────────────┐ │
|
||||
│ │ [client/shared/components/reps/reps.js] │ ObjectInspector │
|
||||
│ └──────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ │ ┌──────────────────────┐
|
||||
│ │ ObjectInspectorItem │ │
|
||||
│ │ └──────────────────────┘
|
||||
└───────────────────────────────────────────────────────────────▶ │ │
|
||||
│ ▼
|
||||
┌──────────────────────┐ │
|
||||
│ ┌─▶│ Rep │
|
||||
│ └──────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ └──────────────┘
|
||||
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
|
||||
</pre>
|
||||
</figure>
|
||||
|
||||
There are several external components we use from the WebConsole:
|
||||
- ObjectInspector/Rep: Used to display a variable in the console output and handle expanding the variable when it's not a primitive.
|
||||
- Frame: Used to display the location of messages.
|
||||
- SmartTrace: Used to display the stack trace of messages and errors
|
||||
- TabboxPanel: Used to render a network message detail. This is directly using the component from the Netmonitor so we are consistent in how we display a request internals.
|
||||
|
||||
## Actions
|
||||
|
||||
The Console panel implements a set of actions divided into several groups.
|
||||
|
||||
- **Filters** Actions related to content filtering.
|
||||
- **Messages** Actions related to list of messages rendered in the panel.
|
||||
- **UI** Actions related to the UI state.
|
||||
|
||||
### State
|
||||
|
||||
The Console panel manages the app state via [Redux](../frontend/redux.md).
|
||||
|
||||
There are following reducers defining the panel state:
|
||||
|
||||
- `reducers/filters.js` state for panel filters. These filters can be set from within the panel's toolbar (e.g. error, info, log, css, etc.)
|
||||
- `reducers/messages.js` state of all messages rendered within the panel.
|
||||
- `reducers/prefs.js` Preferences associated with the Console panel (e.g. logLimit)
|
||||
- `reducers/ui.js` UI related state (sometimes also called a presentation state). This state contains state of the filter bar (visible/hidden), state of the time-stamp (visible/hidden), etc.
|
||||
# Console Tool Architecture
|
||||
|
||||
The Console panel is responsible for rendering all logs coming from the current page.
|
||||
|
||||
## Architecture
|
||||
|
||||
Internal architecture of the Console panel (the client side) is described
|
||||
on the following diagram.
|
||||
|
||||
<figure class="hero">
|
||||
<pre class="diagram">
|
||||
┌──────────────────────────────┐ ┌────────────────────────┐
|
||||
│ DevTools │ │ WebConsolePanel │
|
||||
│[client/framework/devtools.js]│ │ [panel.js] │
|
||||
└──────────────────────────────┘ └────────────────────────┘
|
||||
│ │
|
||||
│
|
||||
openBrowserConsole() or │
|
||||
toggleBrowserConsole() │
|
||||
│ │
|
||||
▼ │
|
||||
┌──────────────────────────────┐ {hud}
|
||||
│ BrowserConsoleManager │ │
|
||||
│ [browser-console-manager.js] │ │
|
||||
└──────────────────────────────┘ │
|
||||
│ │
|
||||
│ │
|
||||
{_browserConsole} │
|
||||
│ │
|
||||
▼ 0..1 ▼ 1
|
||||
┌──────────────────────────────┐ ┌────────────────────────┐
|
||||
│ BrowserConsole │ │ WebConsole │
|
||||
│ [browser-console.js] │─ ─ extends ─ ▶│ [webconsole.js] │
|
||||
└──────────────────────────────┘ └──────────────1─────────┘
|
||||
│
|
||||
{ui}
|
||||
│
|
||||
▼ 1
|
||||
┌────────────────────────┐
|
||||
│ WebConsoleUI │
|
||||
│ [webconsole-ui.js] │
|
||||
└────────────────────────┘
|
||||
│
|
||||
{wrapper}
|
||||
│
|
||||
│
|
||||
▼ 1
|
||||
┌────────────────────────┐
|
||||
│ WebConsoleWrapper │
|
||||
│[webconsole-wrapper.js] │
|
||||
└────────────────────────┘
|
||||
│
|
||||
<renders>
|
||||
│
|
||||
▼
|
||||
┌────────────────────────┐
|
||||
│ App │
|
||||
└────────────────────────┘
|
||||
</pre>
|
||||
<figcaption>Elements between curly bracket on arrows represent the property name of the reference (for example, the WebConsolePanel as a `hud` property that is a reference to the WebConsole instance)</figcaption>
|
||||
</figure>
|
||||
|
||||
## Components
|
||||
|
||||
The Console panel UI is built on top of [React](../frontend/react.md). It defines set of React components in `components` directory
|
||||
The React architecture is described on the following diagram.
|
||||
|
||||
<figure class="hero">
|
||||
<pre class="diagram">
|
||||
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
WebConsole React components │
|
||||
│ [/components] ┌────────────────────────┐
|
||||
│ App │ │
|
||||
│ └────────────────────────┘
|
||||
│ │
|
||||
│ │
|
||||
┌───────────────────┬──────────────────────┬───────────────────┬───────────┴─────────┬───────────────────────┬────────────────────┬─────────────────┐ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ │ ┌────────────────────────────────────────┐
|
||||
│ ┌──────────┐ ┌────────────────┐ ┌────────────────┐ ┌───────────┐ ┌────────────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────┐ │ Editor │
|
||||
│ SideBar │ │NotificationBox │ │ ConfirmDialog │ │ FilterBar │ │ ReverseSearchInput │ │ConsoleOutput │ │EditorToolbar │ │ JSTerm │──.editor───▶│ <CodeMirror> │
|
||||
│ └──────────┘ └────────────────┘ │ <portal> │ └───────────┘ └────────────────────┘ └──────────────┘ └──────────────┘ └─────────┘ │ [client/shared/sourceeditor/editor.js] │
|
||||
│ └────────────────┘ │ │ │ └────────────────────────────────────────┘
|
||||
│ │ ┌─────────┴─────────────┐ │
|
||||
│ │ │ │ │
|
||||
│ │ ▼ ▼ ▼
|
||||
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
|
||||
│ │ │ FilterButton │ │ FilterCheckbox │ │ MessageContainer │
|
||||
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ │ ┌──────────────────┐
|
||||
│ │ Message │ │
|
||||
│ │ └──────────────────┘
|
||||
│ │ │ ┌─────────────────────────────────────┐
|
||||
│ │ │ │ Frame │
|
||||
│ ┌─────────────────────┬─────────────────────┬─────────────────────┬───────┴─────────────┬─────────────────────┬─────────────┼─────┬──▶│ [client/shared/components/Frame.js] │
|
||||
│ │ │ │ │ │ │ │ │ └─────────────────────────────────────┘
|
||||
│ ▼ ▼ ▼ ▼ ▼ ▼ │ │
|
||||
│ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ ┌────────────────────────────────────────┐
|
||||
│ │ MessageIndent │ │ MessageIcon │ │ CollapseButton │ │ GripMessageBody │ │ ConsoleTable │ │ MessageRepeat │ │ │ │ SmartTrace │
|
||||
│ │ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘ ├──▶│[client/shared/components/SmartTrace.js]│
|
||||
│ │ │ │ │ └────────────────────────────────────────┘
|
||||
└ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
|
||||
│ │ │ │ ┌──────────────────────────────────────────────────┐
|
||||
│ │ │ │ │ TabboxPanel │
|
||||
│ ├─────────────────────┘ └──▶│[client/netmonitor/src/components/TabboxPanel.js] │
|
||||
│ │ └──────────────────────────────────────────────────┘
|
||||
│ │
|
||||
│ │
|
||||
│ ▼
|
||||
│ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
|
||||
│ Reps ┌──────────────────────┐ │
|
||||
│ │ [client/shared/components/reps/reps.js] │ ObjectInspector │
|
||||
│ └──────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ │ ┌──────────────────────┐
|
||||
│ │ ObjectInspectorItem │ │
|
||||
│ │ └──────────────────────┘
|
||||
└───────────────────────────────────────────────────────────────▶ │ │
|
||||
│ ▼
|
||||
┌──────────────────────┐ │
|
||||
│ ┌─▶│ Rep │
|
||||
│ └──────────────────────┘ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ └──────────────┘
|
||||
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
|
||||
</pre>
|
||||
</figure>
|
||||
|
||||
There are several external components we use from the WebConsole:
|
||||
- ObjectInspector/Rep: Used to display a variable in the console output and handle expanding the variable when it's not a primitive.
|
||||
- Frame: Used to display the location of messages.
|
||||
- SmartTrace: Used to display the stack trace of messages and errors
|
||||
- TabboxPanel: Used to render a network message detail. This is directly using the component from the Netmonitor so we are consistent in how we display a request internals.
|
||||
|
||||
## Actions
|
||||
|
||||
The Console panel implements a set of actions divided into several groups.
|
||||
|
||||
- **Filters** Actions related to content filtering.
|
||||
- **Messages** Actions related to list of messages rendered in the panel.
|
||||
- **UI** Actions related to the UI state.
|
||||
|
||||
### State
|
||||
|
||||
The Console panel manages the app state via [Redux](../frontend/redux.md).
|
||||
|
||||
There are following reducers defining the panel state:
|
||||
|
||||
- `reducers/filters.js` state for panel filters. These filters can be set from within the panel's toolbar (e.g. error, info, log, css, etc.)
|
||||
- `reducers/messages.js` state of all messages rendered within the panel.
|
||||
- `reducers/prefs.js` Preferences associated with the Console panel (e.g. logLimit)
|
||||
- `reducers/ui.js` UI related state (sometimes also called a presentation state). This state contains state of the filter bar (visible/hidden), state of the time-stamp (visible/hidden), etc.
|
||||
|
|
|
|||
|
|
@ -1,93 +1,93 @@
|
|||
# High-Level Inspector Architecture
|
||||
|
||||
## UI structure
|
||||
The Inspector panel is a tab in the toolbox. Like all tabs, it's in its own iframe.
|
||||
|
||||
The high-level hierarchy looks something like this:
|
||||
|
||||
Toolbox
|
||||
|
|
||||
InspectorPanel
|
||||
|
|
||||
+-------------+------------------+---------------+
|
||||
| | | |
|
||||
MarkupView SelectorSearch HTMLBreadcrumbs ToolSidebar widget (iframes)
|
||||
|
|
||||
+- RuleView
|
||||
|
|
||||
+- ComputedView
|
||||
|
|
||||
+- LayoutView
|
||||
|
|
||||
+- FontInspector
|
||||
|
|
||||
+- AnimationInspector
|
||||
|
||||
## Server dependencies
|
||||
- The inspector panel relies on a series of actors that live on the server.
|
||||
- Some of the most important actors are actually instantiated by the toolbox, because these actors are needed for other panels to preview and link to DOM nodes. For example, the webconsole needs to output DOM nodes, highlight them in the page on mouseover, and open them in the inspector on click. This is achieved using some of the same actors that the inspector panel uses.
|
||||
- See Toolbox.prototype.initInspector: This method instantiates the InspectorActor, WalkerActor and HighlighterActor lazily, whenever they're needed by a panel.
|
||||
|
||||
## Panel loading overview
|
||||
- As with other panels, this starts with Toolbox.prototype.loadTool(id)
|
||||
- For the inspector though, this calls Toolbox.prototype.initInspector
|
||||
- When the panel's open method is called:
|
||||
- It uses the WalkerActor for the first time to know the default selected node (which could be a node that was selected before on the same page).
|
||||
- It starts listening to the WalkerActor's "new-root" events to know when to display a new DOM tree (when there's a page navigation).
|
||||
- It creates the breadcrumbs widget, the sidebar widget, the search widget, the markup-view
|
||||
- Sidebar:
|
||||
- When this widget initializes, it loads its sub-iframes (rule-view, ...)
|
||||
- Each of these iframes contain panel that, in turn, listen to inspector events like "new-node-front" to know when to retrieve information about a node (i.e the rule-view will fetch the css rules for a node).
|
||||
- Markup-view:
|
||||
- This panel initializes in its iframe, and gets a reference to the WalkerActor. It uses it to know the DOM tree to display. It knows when nodes change (markup-mutations), and knows what root node to start from.
|
||||
- It only displays the nodes that are supposed to be visible at first (usually html, head, body and direct children of body).
|
||||
- Then, as you expand nodes, it uses the WalkerActor to get more nodes lazily. It only ever knows data about nodes that have already been expanded once in the UI.
|
||||
|
||||
## Server-side structure
|
||||
Simplified actor hierarchy
|
||||
|
||||
InspectorActor
|
||||
|
|
||||
+---------------+
|
||||
| |
|
||||
WalkerActor PageStyleActor (for rule-view/computed-view)
|
||||
| |
|
||||
NodeActor StyleRuleActor
|
||||
|
||||
__InspectorActor__
|
||||
|
||||
This tab-level actor is the one the inspector-panel connects to. It doesn't do much apart from creating and returning the WalkerActor and PageStyleActor.
|
||||
|
||||
__WalkerActor__
|
||||
|
||||
- Single most important part of the inspector panel.
|
||||
- Responsible for walking the DOM on the current page but:
|
||||
- also walks iframes
|
||||
- also finds pseudo-elements ::before and ::after
|
||||
- also finds anonymous content (e.g. in the BrowserToolbox)
|
||||
- The actor uses an instance of inIDeepTreeWalker to walk the DOM
|
||||
- Provides a tree of NodeActor objects that reflects the DOM.
|
||||
- But only has a partial knowledge of the DOM (what is currently displayed/expanded in the MarkupView). It doesn't need to walk the whole tree when you first instantiate it.
|
||||
- Reflects some of the usual DOM APIs like querySelector.
|
||||
- Note that methods like querySelector return arbitrarily nested NodeActors, in which case the WalkerActor also sends the list of parents to link the returned nodes to the closest known nodes, so the UI can display the tree correctly.
|
||||
- Emits events when there are DOM mutations. These events are sent to the front-end and used to, for example refresh the markup-view. This uses an instance of MutationObserver (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) configured with, in particular, nativeAnonymousChildList set to true, so that mutation events are also sent when pseudo elements are added/removed via css.
|
||||
|
||||
__NodeActor__
|
||||
|
||||
- Representation of a single DOM node (tagname, namespace, attributes, parent, sibblings, ...), which panels use to display previews of nodes.
|
||||
- Also provide useful methods to:
|
||||
- change attributes
|
||||
- scroll into view
|
||||
- get event listeners data
|
||||
- get image data
|
||||
- get unique css selector
|
||||
|
||||
## Highlighters
|
||||
|
||||
One of the important aspects of the inspector is the highlighters.
|
||||
You can find a lot more [documentation about highlighters here](highlighters.md).
|
||||
|
||||
We don't just have 1 highlighter, we have a framework for highlighters:
|
||||
- a (chrome-only) platform API to inject markup in a native-anonymous node in content (that works on all targets)
|
||||
- a number of specific highlighter implementations (css transform, rect, selector, geometry, rulers, ...)
|
||||
- a CustomHighlighterActor to get instances of specific highlighters
|
||||
# High-Level Inspector Architecture
|
||||
|
||||
## UI structure
|
||||
The Inspector panel is a tab in the toolbox. Like all tabs, it's in its own iframe.
|
||||
|
||||
The high-level hierarchy looks something like this:
|
||||
|
||||
Toolbox
|
||||
|
|
||||
InspectorPanel
|
||||
|
|
||||
+-------------+------------------+---------------+
|
||||
| | | |
|
||||
MarkupView SelectorSearch HTMLBreadcrumbs ToolSidebar widget (iframes)
|
||||
|
|
||||
+- RuleView
|
||||
|
|
||||
+- ComputedView
|
||||
|
|
||||
+- LayoutView
|
||||
|
|
||||
+- FontInspector
|
||||
|
|
||||
+- AnimationInspector
|
||||
|
||||
## Server dependencies
|
||||
- The inspector panel relies on a series of actors that live on the server.
|
||||
- Some of the most important actors are actually instantiated by the toolbox, because these actors are needed for other panels to preview and link to DOM nodes. For example, the webconsole needs to output DOM nodes, highlight them in the page on mouseover, and open them in the inspector on click. This is achieved using some of the same actors that the inspector panel uses.
|
||||
- See Toolbox.prototype.initInspector: This method instantiates the InspectorActor, WalkerActor and HighlighterActor lazily, whenever they're needed by a panel.
|
||||
|
||||
## Panel loading overview
|
||||
- As with other panels, this starts with Toolbox.prototype.loadTool(id)
|
||||
- For the inspector though, this calls Toolbox.prototype.initInspector
|
||||
- When the panel's open method is called:
|
||||
- It uses the WalkerActor for the first time to know the default selected node (which could be a node that was selected before on the same page).
|
||||
- It starts listening to the WalkerActor's "new-root" events to know when to display a new DOM tree (when there's a page navigation).
|
||||
- It creates the breadcrumbs widget, the sidebar widget, the search widget, the markup-view
|
||||
- Sidebar:
|
||||
- When this widget initializes, it loads its sub-iframes (rule-view, ...)
|
||||
- Each of these iframes contain panel that, in turn, listen to inspector events like "new-node-front" to know when to retrieve information about a node (i.e the rule-view will fetch the css rules for a node).
|
||||
- Markup-view:
|
||||
- This panel initializes in its iframe, and gets a reference to the WalkerActor. It uses it to know the DOM tree to display. It knows when nodes change (markup-mutations), and knows what root node to start from.
|
||||
- It only displays the nodes that are supposed to be visible at first (usually html, head, body and direct children of body).
|
||||
- Then, as you expand nodes, it uses the WalkerActor to get more nodes lazily. It only ever knows data about nodes that have already been expanded once in the UI.
|
||||
|
||||
## Server-side structure
|
||||
Simplified actor hierarchy
|
||||
|
||||
InspectorActor
|
||||
|
|
||||
+---------------+
|
||||
| |
|
||||
WalkerActor PageStyleActor (for rule-view/computed-view)
|
||||
| |
|
||||
NodeActor StyleRuleActor
|
||||
|
||||
__InspectorActor__
|
||||
|
||||
This tab-level actor is the one the inspector-panel connects to. It doesn't do much apart from creating and returning the WalkerActor and PageStyleActor.
|
||||
|
||||
__WalkerActor__
|
||||
|
||||
- Single most important part of the inspector panel.
|
||||
- Responsible for walking the DOM on the current page but:
|
||||
- also walks iframes
|
||||
- also finds pseudo-elements ::before and ::after
|
||||
- also finds anonymous content (e.g. in the BrowserToolbox)
|
||||
- The actor uses an instance of inIDeepTreeWalker to walk the DOM
|
||||
- Provides a tree of NodeActor objects that reflects the DOM.
|
||||
- But only has a partial knowledge of the DOM (what is currently displayed/expanded in the MarkupView). It doesn't need to walk the whole tree when you first instantiate it.
|
||||
- Reflects some of the usual DOM APIs like querySelector.
|
||||
- Note that methods like querySelector return arbitrarily nested NodeActors, in which case the WalkerActor also sends the list of parents to link the returned nodes to the closest known nodes, so the UI can display the tree correctly.
|
||||
- Emits events when there are DOM mutations. These events are sent to the front-end and used to, for example refresh the markup-view. This uses an instance of MutationObserver (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) configured with, in particular, nativeAnonymousChildList set to true, so that mutation events are also sent when pseudo elements are added/removed via css.
|
||||
|
||||
__NodeActor__
|
||||
|
||||
- Representation of a single DOM node (tagname, namespace, attributes, parent, sibblings, ...), which panels use to display previews of nodes.
|
||||
- Also provide useful methods to:
|
||||
- change attributes
|
||||
- scroll into view
|
||||
- get event listeners data
|
||||
- get image data
|
||||
- get unique css selector
|
||||
|
||||
## Highlighters
|
||||
|
||||
One of the important aspects of the inspector is the highlighters.
|
||||
You can find a lot more [documentation about highlighters here](highlighters.md).
|
||||
|
||||
We don't just have 1 highlighter, we have a framework for highlighters:
|
||||
- a (chrome-only) platform API to inject markup in a native-anonymous node in content (that works on all targets)
|
||||
- a number of specific highlighter implementations (css transform, rect, selector, geometry, rulers, ...)
|
||||
- a CustomHighlighterActor to get instances of specific highlighters
|
||||
|
|
|
|||
|
|
@ -87,4 +87,4 @@ Other CRUD operations work very similar to this one.
|
|||
|
||||
- We call `StorageMock.getWindowFromHost` so we can get the storage principal. Since this is a parent process resource, it doesn't have access to an actual window, so it returns a mock instead (but with a real principal).
|
||||
- To detect changes in storage, we subscribe to different events that platform provides via `Services.obs.addObserver`.
|
||||
- To manipulate storage data, we use different methods depending on the storage type. For cookies, we use the API provided by `Services.cookies`.
|
||||
- To manipulate storage data, we use different methods depending on the storage type. For cookies, we use the API provided by `Services.cookies`.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ in terms of its impact on other parts of Firefox. Always keep in mind
|
|||
the side effects your changes may have, from blocking other tasks, to
|
||||
interfering with other user interface elements.
|
||||
|
||||
## Avoid the main thread where possible
|
||||
## Avoid the main thread where possible
|
||||
|
||||
The main thread is where we process user events and do painting. It's
|
||||
also important to note that most of our JavaScript runs on the main
|
||||
|
|
@ -21,7 +21,7 @@ elevated privileges than a standard worker allows, consider using a
|
|||
ChromeWorker, which is a Firefox-only API which lets you create
|
||||
workers with more elevated privileges.
|
||||
|
||||
## Use requestIdleCallback()
|
||||
## Use requestIdleCallback()
|
||||
|
||||
If you simply cannot avoid doing some kind of long job on the main
|
||||
thread, try to break it up into smaller pieces that you can run when the
|
||||
|
|
@ -45,7 +45,7 @@ document, set the **hidden** attribute to **true** by default. By doing
|
|||
so, you cause the binding applied on demand rather than at load time,
|
||||
which makes initial construction of the XUL document faster.
|
||||
|
||||
## Get familiar with the pipeline that gets pixels to the screen
|
||||
## Get familiar with the pipeline that gets pixels to the screen
|
||||
|
||||
Learn how pixels you draw make their way to the screen. Knowing the path
|
||||
they will take through the various layers of the browser engine will
|
||||
|
|
@ -55,7 +55,7 @@ The rendering process goes through the following steps:
|
|||
|
||||

|
||||
|
||||
The above image is used under [Creative Commons Attribution 3.0](https://creativecommons.org/licenses/by/3.0/),
|
||||
The above image is used under [Creative Commons Attribution 3.0](https://creativecommons.org/licenses/by/3.0/),
|
||||
courtesy of [this page](https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing)
|
||||
from our friends at Google, which itself is well worth the read.
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ of your DOM writes (most importantly, anything that could change the
|
|||
size or position of things in the DOM) just before the style and layout
|
||||
steps of the pipeline, combining all the style and layout calculations
|
||||
into a single batch so it all happens once, in a single frame tick,
|
||||
instead of across multiple frames.
|
||||
instead of across multiple frames.
|
||||
|
||||
See [Detecting and avoiding synchronous reflow](#detecting-and-avoiding-synchronous-reflow)
|
||||
below for more information.
|
||||
|
|
@ -80,9 +80,9 @@ below for more information.
|
|||
This also means that *requestAnimationFrame()* is **not a good place**
|
||||
to put queries for layout or style information.
|
||||
|
||||
## Detecting and avoiding synchronous style flushes
|
||||
## Detecting and avoiding synchronous style flushes
|
||||
|
||||
### What are style flushes?
|
||||
### What are style flushes?
|
||||
When CSS is applied to a document (HTML or XUL, it doesn’t matter), the
|
||||
browser does calculations to figure out which CSS styles will apply to
|
||||
each element. This happens the first time the page loads and the CSS is
|
||||
|
|
@ -166,7 +166,7 @@ driver.
|
|||
tracks work to make it impossible to modify the DOM within a
|
||||
*promiseDocumentFlushed* callback.
|
||||
|
||||
### Writing tests to ensure you don’t add more synchronous style flushes
|
||||
### Writing tests to ensure you don’t add more synchronous style flushes
|
||||
|
||||
Unlike reflow, there isn’t a “observer” mechanism for style
|
||||
recalculations. However, as of Firefox 49, the
|
||||
|
|
@ -236,7 +236,7 @@ worse (see next section).
|
|||
**To repeat, only interruptible reflows in web content can be
|
||||
interrupted.**
|
||||
|
||||
### Uninterruptible reflow
|
||||
### Uninterruptible reflow
|
||||
|
||||
Uninterruptible reflow is what we want to **avoid at all costs**.
|
||||
Uninterruptible reflow occurs when some DOM node’s styles have changed
|
||||
|
|
@ -286,7 +286,7 @@ place (the layout step of the 16ms tick) as opposed to multiple times
|
|||
during the 16ms tick (which has a higher probability of running through
|
||||
the 16ms budget).
|
||||
|
||||
### How do I avoid triggering uninterruptible reflow?
|
||||
### How do I avoid triggering uninterruptible reflow?
|
||||
|
||||
Here's a [list of things that JavaScript can ask for that can cause
|
||||
uninterruptible reflow](https://gist.github.com/paulirish/5d52fb081b3570c81e3a), to
|
||||
|
|
@ -460,7 +460,7 @@ post](https://davidwalsh.name/documentfragment):
|
|||
var frag = document.createDocumentFragment();
|
||||
|
||||
// Create numerous list items, add to fragment
|
||||
|
||||
|
||||
for(var x = 0; x < 10; x++) {
|
||||
var li = document.createElement("li");
|
||||
li.innerHTML = "List item " + x;
|
||||
|
|
@ -474,7 +474,7 @@ post](https://davidwalsh.name/documentfragment):
|
|||
The above is strictly cheaper than individually adding each node to the
|
||||
DOM.
|
||||
|
||||
## The Gecko profiler add-on is your friend
|
||||
## The Gecko profiler add-on is your friend
|
||||
|
||||
The Gecko profiler is your best friend when diagnosing performance
|
||||
problems and looking for bottlenecks. There’s plenty of excellent
|
||||
|
|
@ -484,7 +484,7 @@ documentation on MDN about the Gecko profiler:
|
|||
|
||||
- [Advanced profile analysis](https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Profiling_with_the_Built-in_Profiler)
|
||||
|
||||
## Don’t guess—measure.
|
||||
## Don’t guess—measure.
|
||||
|
||||
If you’re working on a performance improvement, this should go without
|
||||
saying: ensure that what you care about is actually improving by
|
||||
|
|
@ -553,7 +553,7 @@ A Promise-based wrapper for IndexedDB,
|
|||
[IndexedDB.sys.mjs](http://searchfox.org/mozilla-central/source/toolkit/modules/IndexedDB.sys.mjs)
|
||||
is available for chrome code.
|
||||
|
||||
## Test on weak hardware
|
||||
## Test on weak hardware
|
||||
|
||||
For the folks paid to work on Firefox, we tend to have pretty powerful
|
||||
hardware for development. This is great, because it reduces build times,
|
||||
|
|
@ -566,7 +566,7 @@ a sense of what our users are working with. Test on slower machines to
|
|||
make it more obvious to yourself if what you’ve written impacts the
|
||||
performance of the browser.
|
||||
|
||||
## Consider loading scripts with the subscript loader asynchronously
|
||||
## Consider loading scripts with the subscript loader asynchronously
|
||||
|
||||
If you've ever used the subscript loader, you might not know that it can
|
||||
load scripts asynchronously, and return a Promise once they're loaded.
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ explains how to use the Gecko profiler.
|
|||
* [GC and CC Logs](memory/gc_and_cc_logs.md)
|
||||
* [Leak Gauge](memory/leak_gauge.md) can be generated and analyzed to in various ways. In particular, they can help you understand why a particular object is being kept alive.
|
||||
* [LogAlloc](https://searchfox.org/mozilla-central/source/memory/replace/logalloc/README) is a tool that dumps a log of memory allocations in Gecko. That log can then be replayed against Firefox's default memory allocator independently or through another replace-malloc library, allowing the testing of other allocators under the exact same workload.
|
||||
* [See also the documentation on Leak-hunting strategies and tips.](memory/leak_hunting_strategies_and_tips.md)
|
||||
* [See also the documentation on Leak-hunting strategies and tips.](memory/leak_hunting_strategies_and_tips.md)
|
||||
|
||||
## Profiling and performance tools
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ explains how to use the Gecko profiler.
|
|||
|
||||
## Power Profiling
|
||||
|
||||
* [An overview of power profiling](power_profiling_overview.md). It includes details about hardware, what can be measured, and recommended approaches. It should be the starting point for anybody new to power profiling.
|
||||
* [An overview of power profiling](power_profiling_overview.md). It includes details about hardware, what can be measured, and recommended approaches. It should be the starting point for anybody new to power profiling.
|
||||
* **(Mac, Linux)** [tools/power/rapl](tools_power_rapl.md) is a command-line utility in the Mozilla codebase that uses the Intel RAPL interface to gather direct power estimates for the package, cores, GPU and memory.
|
||||
* **(Mac-only)** [powermetrics](powermetrics.md) is a command-line utility that gathers and displays a wide range of global and per-process measurements, including CPU usage, GPU usage, and various wakeups frequencies.
|
||||
* **(All-platforms)** [TimerFirings](timerfirings_logging.md) logging is a built-in logging mechanism that prints data on every time fired.
|
||||
|
|
@ -50,4 +50,4 @@ explains how to use the Gecko profiler.
|
|||
|
||||
## Performance Metrics
|
||||
|
||||
* [PerfStats](perfstats.md) - A framework for low-overhead collection of internal performance metrics.
|
||||
* [PerfStats](perfstats.md) - A framework for low-overhead collection of internal performance metrics.
|
||||
|
|
|
|||
|
|
@ -110,4 +110,4 @@ sudo apt-get install libc6-prof
|
|||
It may also be useful to have access to kernel addresses during profiling. These can be exposed with:
|
||||
```
|
||||
sudo sh -c "echo 0 > /proc/sys/kernel/kptr_restrict"
|
||||
```
|
||||
```
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ Stack\":
|
|||
Now at the top we can immediately see the `createToolbarButton()` call
|
||||
accounting for 89% of the heap usage in our page.
|
||||
|
||||
## no stack available
|
||||
## no stack available
|
||||
|
||||
In the example above you\'ll note that 7% of the heap is marked \"(no
|
||||
stack available)\". This is because not all heap usage results from your
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Are We Slim Yet (AWSY)
|
||||
|
||||
The Are We Slim Yet project (commonly known as AWSY) for several years
|
||||
tracked memory usage across builds on the (now defunct) website.
|
||||
tracked memory usage across builds on the (now defunct) website.
|
||||
It used the same
|
||||
infrastructure as
|
||||
[about:memory](about_colon_memory.md) to measure
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ it, open the developer tool settings, and check the "Memory" box under
|
|||
|
||||
From Firefox 50 onwards, the Memory tool is enabled by default.
|
||||
|
||||
## Taking a heap snapshot
|
||||
## Taking a heap snapshot
|
||||
|
||||
To take a snapshot of the heap, click the "Take snapshot" button, or
|
||||
the camera icon on the left:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Dominators
|
||||
# Dominators
|
||||
|
||||
This article provides an introduction to the concepts of *Reachability*,
|
||||
*Shallow* versus *Retained* size, and *Dominators*, as they apply in
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Dominators view
|
||||
# Dominators view
|
||||
|
||||
The Dominators view is new in Firefox 46.
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ are, skip to the Dominators UI section. Otherwise, you might want to
|
|||
review the article on [Dominators
|
||||
concepts](dominators.md).
|
||||
|
||||
## Dominators UI
|
||||
## Dominators UI
|
||||
|
||||
To see the Dominators view for a snapshot, select \"Dominators\" in the
|
||||
\"View\" drop-down list. It looks something like this:
|
||||
|
|
@ -111,7 +111,7 @@ take you to that spot in the Debugger.
|
|||
|
||||
<iframe width="595" height="325" src="https://www.youtube.com/embed/qTF5wCSD124" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"></iframe>
|
||||
|
||||
:::
|
||||
:::
|
||||
Sometimes you\'ll see \"(no stack available)\" here. In particular,
|
||||
allocation stacks are currently only recorded for objects, not for
|
||||
arrays, strings, or internal structures.
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ in a path separator. For instance, `~/logs/leak/`.
|
|||
|
||||
The command you need to run Firefox will look something like this:
|
||||
|
||||
XPCOM_MEM_BLOAT_LOG=1 MOZ_CC_LOG_SHUTDOWN=1 MOZ_DISABLE_CONTENT_SANDBOX=t MOZ_CC_LOG_DIRECTORY=$logdir
|
||||
XPCOM_MEM_BLOAT_LOG=1 MOZ_CC_LOG_SHUTDOWN=1 MOZ_DISABLE_CONTENT_SANDBOX=t MOZ_CC_LOG_DIRECTORY=$logdir
|
||||
MOZ_CC_LOG_PROCESS=content MOZ_CC_LOG_THREAD=main MOZ_DMD_SHUTDOWN_LOG=$logdir MOZ_DMD_LOG_PROCESS=tab ./mach run --dmd --mode=scan
|
||||
|
||||
Breaking this down:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Memory Tools
|
||||
|
||||
The Memory tool lets you take a snapshot of the current tab's memory
|
||||
[heap](https://en.wikipedia.org/wiki/Memory_management#HEAP).
|
||||
[heap](https://en.wikipedia.org/wiki/Memory_management#HEAP).
|
||||
It then provides a number of views of the heap that can
|
||||
show you which objects account for memory usage and exactly where in
|
||||
your code you are allocating memory.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ Performance counter stats for 'system wide':
|
|||
|
||||
It's not clear from the output, but the following relationship holds.
|
||||
|
||||
```
|
||||
```
|
||||
energy-pkg >= energy-cores + energy-gpu
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# PerfStats
|
||||
|
||||
PerfStats is a framework for the low-overhead selective collection of internal performance metrics.
|
||||
PerfStats is a framework for the low-overhead selective collection of internal performance metrics.
|
||||
The results are accessible through ChromeUtils, Browsertime output, and in select performance tests.
|
||||
|
||||
## Adding a new PerfStat
|
||||
Define the new PerfStat by adding it to [this list](https://searchfox.org/mozilla-central/rev/b1e5f2c7c96be36974262551978d54f457db2cae/tools/performance/PerfStats.h#34-53) in [`PerfStats.h`](https://searchfox.org/mozilla-central/rev/52da19becaa3805e7f64088e91e9dade7dec43c8/tools/performance/PerfStats.h).
|
||||
Define the new PerfStat by adding it to [this list](https://searchfox.org/mozilla-central/rev/b1e5f2c7c96be36974262551978d54f457db2cae/tools/performance/PerfStats.h#34-53) in [`PerfStats.h`](https://searchfox.org/mozilla-central/rev/52da19becaa3805e7f64088e91e9dade7dec43c8/tools/performance/PerfStats.h).
|
||||
Then, in C++ code, wrap execution in an RAII object, e.g.
|
||||
```
|
||||
PerfStats::AutoMetricRecording<PerfStats::Metric::MyMetric>()
|
||||
|
|
@ -13,7 +13,7 @@ or call the following function manually:
|
|||
```
|
||||
PerfStats::RecordMeasurement(PerfStats::Metric::MyMetric, Start, End)
|
||||
```
|
||||
For incrementing counters, use the following:
|
||||
For incrementing counters, use the following:
|
||||
```
|
||||
PerfStats::RecordMeasurementCount(PerfStats::Metric::MyMetric, incrementCount)
|
||||
```
|
||||
|
|
@ -21,10 +21,10 @@ PerfStats::RecordMeasurementCount(PerfStats::Metric::MyMetric, incrementCount)
|
|||
[Here's an example of a patch where a new PerfStat was added and used.](https://hg.mozilla.org/mozilla-central/rev/3e85a73d1fa5c816fdaead66ecee603b38f9b725)
|
||||
|
||||
## Enabling collection
|
||||
To enable collection, use `ChromeUtils.SetPerfStatsCollectionMask(MetricMask mask)`, where `mask=0` disables all metrics and `mask=0xFFFFFFFF` enables all of them.
|
||||
To enable collection, use `ChromeUtils.SetPerfStatsCollectionMask(MetricMask mask)`, where `mask=0` disables all metrics and `mask=0xFFFFFFFF` enables all of them.
|
||||
`MetricMask` is a bitmask based on `Metric`, i.e. `Metric::LayerBuilding (2)` is synonymous to `1 << 2` in `MetricMask`.
|
||||
|
||||
## Accessing results
|
||||
Results can be accessed with `ChromeUtils.CollectPerfStats()`.
|
||||
The Browsertime test framework will sum results across processes and report them in its output.
|
||||
Results can be accessed with `ChromeUtils.CollectPerfStats()`.
|
||||
The Browsertime test framework will sum results across processes and report them in its output.
|
||||
The raptor-browsertime Windows essential pageload tests also collect all PerfStats.
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ not sure).
|
|||
|
||||
## String tests
|
||||
|
||||
* PerfStripWhitespace
|
||||
* PerfCompressWhitespace
|
||||
* PerfStripCharsWhitespace
|
||||
* PerfStripCRLF
|
||||
* PerfStripWhitespace
|
||||
* PerfCompressWhitespace
|
||||
* PerfStripCharsWhitespace
|
||||
* PerfStripCRLF
|
||||
* PerfStripCharsCRLF
|
||||
|
||||
These tests measure the amount of time it takes to perform a large
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ sample output.
|
|||
plugin-container 67269 31.49 72.46 1.80 0.00 186.90 66.68 0.00
|
||||
com.apple.WebKit.Plugin.64 67373 55.55 74.38 0.74 0.00 9.51 3.13 0.02
|
||||
com.apple.Terminal 109 6.22 0.40 0.23 0.00
|
||||
Terminal 208 6.25 92.99 0.00 0.00 0.33 0.20 0.00
|
||||
Terminal 208 6.25 92.99 0.00 0.00 0.33 0.20 0.00
|
||||
|
||||
The `rapl` output is first, then the `powermetrics` output. As well as
|
||||
the browser processes, the `WindowServer` and kernel tasks are shown
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ mouse to interact with the UI:
|
|||
for your performance problem and/or send it to the appropriate
|
||||
person. Try to give some context about what you were doing when the
|
||||
performance problem arose such as the URL you were viewing and what
|
||||
actions were you doing (ex. scrolling on gmail.com).
|
||||
actions were you doing (ex. scrolling on gmail.com).
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ sudo turbostat
|
|||
If you get an error saying `"turbostat: no /dev/cpu/0/msr"`, you need to
|
||||
run the following command:
|
||||
|
||||
```
|
||||
```
|
||||
sudo modprobe msr
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ for the `xpcom` crate, run these commands:
|
|||
cd xpcom/rust/xpcom
|
||||
MOZ_TOPOBJDIR=$OBJDIR cargo doc
|
||||
cd -
|
||||
firefox target/doc/xpcom/index.html
|
||||
firefox target/doc/xpcom/index.html
|
||||
```
|
||||
where `$OBJDIR` is the path to the object directory.
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ Here's how you can create a new set of bindings using UniFFI:
|
|||
3. Generate bindings code for your crate
|
||||
- Add the path of your UDL (that you made in step 1) in `toolkit/components/uniffi-bindgen-gecko-js/mach_commands.py`
|
||||
- Run `./mach uniffi generate`
|
||||
- add your newly generated `Rust{udl-name}.jsm` file to `toolkit/components/uniffi-bindgen-gecko-js/components/moz.build`
|
||||
- add your newly generated `Rust{udl-name}.jsm` file to `toolkit/components/uniffi-bindgen-gecko-js/components/moz.build`
|
||||
- Then simply import your `jsm` module to the file you want to use it in and start using your APIs!
|
||||
|
||||
Example from tabs module:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Rust toolchains used and required to build Firefox.
|
|||
|
||||
This allows contributors to know when new features will be usable, and
|
||||
downstream packagers to know what toolchain will be required for each Firefox
|
||||
release. Both benefit from the predictability of a schedule.
|
||||
release. Both benefit from the predictability of a schedule.
|
||||
|
||||
## Policy
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ The main concept behind it is a problem solver which takes a list of resources a
|
|||
The algorithm is notoriously hard to read, write, and modify, which prompts this documentation to be extensive and provide an example with diagram presentations to aid the reader.
|
||||
|
||||
# Example
|
||||
For the purpose of a graphical illustration of the example, we will evaluate a scenario with two sources and three resources.
|
||||
For the purpose of a graphical illustration of the example, we will evaluate a scenario with two sources and three resources.
|
||||
|
||||
The sources and resource identifiers will be named in concise way (*1* or *A*) to simplify diagrams, while a more tangible names derived from real-world examples in Firefox use-case will be listed in their initial definition.
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ and which starting point can be visualized as:
|
|||
┌┲━┱┬───┬───┐
|
||||
│┃0┃│ │ │
|
||||
└╂─╂┴───┴───┘
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┗━┛
|
||||
```
|
||||
###### Diagrams generated with use of http://marklodato.github.io/js-boxdrawing/
|
||||
|
|
@ -110,7 +110,7 @@ for set in multi_prod {
|
|||
#### Reasons for a custom algorithm
|
||||
|
||||
Unfortunately, the computational complexity of generating all possible sets is growing exponentially, both in the cost of CPU and memory use.
|
||||
On a high-end laptop, computing the sets for all possible variations of the example above generates *8* sets and takes only *700 nanoseconds*, but computing the same for four sources and 16 resources (a scenario theoretically possible in Firefox with one language pack and Preferences UI for example) generates over *4 billion* sets and takes over *2 minutes*.
|
||||
On a high-end laptop, computing the sets for all possible variations of the example above generates *8* sets and takes only *700 nanoseconds*, but computing the same for four sources and 16 resources (a scenario theoretically possible in Firefox with one language pack and Preferences UI for example) generates over *4 billion* sets and takes over *2 minutes*.
|
||||
|
||||
Since one part of static cost is the I/O, the application of a [Memoization](https://en.wikipedia.org/wiki/Memoization) technique allows us to minimize the cost of constructing, storing and retrieving sets.
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ Second important observation is that in most scenarios any resource exists in on
|
|||
|
||||
## Optimizations
|
||||
|
||||
The algorithm used here is highly efficient. For the conservative scenario listed above, where 4 sources and 15 resources are all present in every source, the total time on the reference hardware is cut from *2 minutes* to *24 seconds*, while generating the same *4 billion* sets for a **5x** performance improvement.
|
||||
The algorithm used here is highly efficient. For the conservative scenario listed above, where 4 sources and 15 resources are all present in every source, the total time on the reference hardware is cut from *2 minutes* to *24 seconds*, while generating the same *4 billion* sets for a **5x** performance improvement.
|
||||
|
||||
### Streaming Iterator
|
||||
Unline regular iterator, a streaming iterator allows a borrowed reference to be returned, which in this case, where the solver yields a read-only "view" of a solution, allows us to avoid having to clone it.
|
||||
|
|
@ -141,13 +141,13 @@ This can be performed in one of two ways:
|
|||
The algorithm is synchronous and each extension of the candidate is evaluated serially, one by one, allowing the for *backtracking* as soon as a given extension of a partial solution is confirmed to not lead to a complete solution.
|
||||
|
||||
Bringing back the initial state of the solver:
|
||||
|
||||
|
||||
```text
|
||||
▼
|
||||
┌┲━┱┬───┬───┐
|
||||
│┃0┃│ │ │
|
||||
└╂─╂┴───┴───┘
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┗━┛
|
||||
```
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ If the test returns a success, the extensions of the candidate is generated:
|
|||
┌┲━┱┬┲━┱┬───┐
|
||||
│┃0┃│┃0┃│ │
|
||||
└╂─╂┴╂─╂┴───┘
|
||||
┃ ┃ ┃ ┃
|
||||
┃ ┃ ┃ ┃
|
||||
┗━┛ ┗━┛
|
||||
```
|
||||
|
||||
|
|
@ -178,8 +178,8 @@ If the test returns a failure, the next step is to evaluate alternative source f
|
|||
┌┲━┱┬╂─╂┬───┐
|
||||
│┃0┃│┃1┃│ │
|
||||
└╂─╂┴┺━┹┴───┘
|
||||
┃ ┃
|
||||
┗━┛
|
||||
┃ ┃
|
||||
┗━┛
|
||||
```
|
||||
|
||||
and that will potentially lead to a partial solution `[0, 1, ]` to be stored for the next iteration.
|
||||
|
|
@ -237,4 +237,3 @@ The algorithm explained above is tailored to the problem domain of `L10nRegistry
|
|||
It is important to maintain this guide up to date as any changes to the algorithm are to be made.
|
||||
|
||||
Good luck.
|
||||
|
||||
|
|
|
|||
|
|
@ -166,10 +166,10 @@ call, it must be an object.
|
|||
|
||||
SpiderMonkey only calls `onNativeCall` hooks when execution is inside a
|
||||
debugger evaluation associated with the debugger that has the `onNativeCall`
|
||||
hook. Such evaluation methods include `Debugger.Object.apply`, `Debugger.Object.call`,
|
||||
hook. Such evaluation methods include `Debugger.Object.apply`, `Debugger.Object.call`,
|
||||
`Debugger.Object.executeInGlobal`, `Debugger.Frame.eval`, and associated methods.
|
||||
|
||||
Separately, any Debugger hooks triggered during calls to `Debugger.Object.apply`, `Debugger.Object.call`,
|
||||
Separately, any Debugger hooks triggered during calls to `Debugger.Object.apply`, `Debugger.Object.call`,
|
||||
`Debugger.Object.executeInGlobal`, `Debugger.Frame.eval`, and associated methods
|
||||
will only be triggered on Debugger objects owned by the Debugger performing
|
||||
the evaluation.
|
||||
|
|
|
|||
|
|
@ -91,4 +91,4 @@ page whenever it executes a JavaScript `debugger;` statement.
|
|||
|
||||
[img-chrome-pref]: enable-chrome-devtools.png
|
||||
[img-scratchpad-browser]: scratchpad-browser-environment.png
|
||||
[img-example-alert]: debugger-alert.png
|
||||
[img-example-alert]: debugger-alert.png
|
||||
|
|
|
|||
|
|
@ -41,4 +41,4 @@ fastpath in the common case or fall back to something more expensive if necessar
|
|||
|
||||
[intrinsic]: https://searchfox.org/mozilla-central/search?q=intrinsic_&path=js%2Fsrc%2F&case=false®exp=false
|
||||
[emitCopy]: https://searchfox.org/mozilla-central/rev/650c19c96529eb28d081062c1ca274bc50ef3635/js/src/frontend/BytecodeEmitter.cpp#5018,5027,5039,5045,5050,5055,5067
|
||||
[optimize]: https://searchfox.org/mozilla-central/rev/c1180ea13e73eb985a49b15c0d90e977a1aa919c/js/src/jit/CacheIR.cpp#10140
|
||||
[optimize]: https://searchfox.org/mozilla-central/rev/c1180ea13e73eb985a49b15c0d90e977a1aa919c/js/src/jit/CacheIR.cpp#10140
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# JavaScript Language Feature Checklist
|
||||
So you're working on a new JavaScript feature in SpiderMonkey: Congratulations! Here's a set of checklists and guidelines to help you on your way.
|
||||
So you're working on a new JavaScript feature in SpiderMonkey: Congratulations! Here's a set of checklists and guidelines to help you on your way.
|
||||
|
||||
## High Level Feature Ship Checklist.
|
||||
(Note: Some of these pieces can happen in parallel, so it's not necessary to
|
||||
|
|
@ -8,18 +8,18 @@ work directly top-down)
|
|||
- ☐ Send an Intent to Prototype email to `dev-platform`. This is part of the
|
||||
[Exposure Guidelines](https://wiki.mozilla.org/ExposureGuidelines) process. We
|
||||
historically haven't been amazing at sending intent-to-prototype emails, but
|
||||
we can always get better.
|
||||
we can always get better.
|
||||
- ☐ Create a shell option for the feature.
|
||||
- ☐ Stage 2 or earlier proposals should be developed under compile time guards,
|
||||
disabled by default.
|
||||
- ☐ Create a browser preference for the feature.
|
||||
- ☐ Implement the Feature.
|
||||
- ☐ Land feature disabled by pref and shell-option.
|
||||
- ☐ Land feature disabled by pref and shell-option.
|
||||
- ☐ Import the test262 test cases for the feature, or enable them if they're
|
||||
already imported. (See `js/src/test/Readme.txt` for guidance)
|
||||
- ☐ Contact `fuzzing@mozilla.org` to arrange fuzzing for the feature.
|
||||
already imported. (See `js/src/test/Readme.txt` for guidance)
|
||||
- ☐ Contact `fuzzing@mozilla.org` to arrange fuzzing for the feature.
|
||||
- ☐ Add shell option to `js/src/shell/fuzz-flags.txt`. This signals to other
|
||||
fuzzers as well that the feature is ready for fuzzing.
|
||||
fuzzers as well that the feature is ready for fuzzing.
|
||||
- ☐ Send an Intent to Ship Email to `dev-platform`. This is also part of the
|
||||
[Exposure Guidelines](https://wiki.mozilla.org/ExposureGuidelines) process.
|
||||
- ☐ Ship the feature; default the preference to true and the command-line
|
||||
|
|
@ -33,17 +33,17 @@ work directly top-down)
|
|||
|
||||
- ☐ If it seems possible that the feature will cause webcompat issues,
|
||||
consider shipping `NIGHTLY_ONLY` for a cycle or two, to use nightly as an
|
||||
attempt to shake out potential webcompat issues.
|
||||
attempt to shake out potential webcompat issues.
|
||||
|
||||
|
||||
### Web Platform Integration Checklist
|
||||
|
||||
_Sometimes Complexity of the web-platform leaks into JS Feature works_
|
||||
|
||||
- ☐ Ensure the appropriate web-platform tests exist, and are being run.
|
||||
- ☐ Ensure the appropriate web-platform tests exist, and are being run.
|
||||
- ☐ Is your feature correctly enabled inside of Workers? (They have different
|
||||
option set than main thread, and it's easy to forget them!) You may want to
|
||||
write a mochitest.
|
||||
write a mochitest.
|
||||
|
||||
### Syntax Features Checklist
|
||||
|
||||
|
|
@ -57,13 +57,13 @@ _Sometimes Complexity of the web-platform leaks into JS Feature works_
|
|||
|
||||
_There's lots of complexity in SpiderMonkey that isn't always captured by the
|
||||
specification, so the below is some useful guidance to behaviour to pay
|
||||
attention to that may not be tested by a feature's test262 tests_
|
||||
attention to that may not be tested by a feature's test262 tests_
|
||||
|
||||
- ☐ How does your feature interact with multiple compartments? What happens if
|
||||
references happen across compartments, or if `this` is a
|
||||
`CrossCompartmentWrapper`?
|
||||
`CrossCompartmentWrapper`?
|
||||
- ☐ Are your error messages being emitted in the correct realm, with the
|
||||
correct prototype?
|
||||
correct prototype?
|
||||
- ☐ If async functions or promises are involved, are user-code objects
|
||||
resolved? If so, does the feature correctly handle [the `.then` property
|
||||
behaviour of promise
|
||||
|
|
|
|||
|
|
@ -34,4 +34,3 @@ tail end of the prologue; subsequent lines comprise the operation;
|
|||
finally there is the beginning of the epilogue. Sometimes there is
|
||||
only the end of the prologue and the beginning of the operation, as
|
||||
the operation is long and we don't care about its tail.
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
DO NOT ADD A directives.txt FILE IN THIS DIRECTORY. THE TEST CASE MUST RUN WITH MINIMAL PRELIMINARIES.
|
||||
DO NOT ADD A directives.txt FILE IN THIS DIRECTORY. THE TEST CASE MUST RUN WITH MINIMAL PRELIMINARIES.
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
DO NOT ADD A directives.txt FILE IN THIS DIRECTORY. THE TEST CASE MUST RUN WITH MINIMAL PRELIMINARIES.
|
||||
DO NOT ADD A directives.txt FILE IN THIS DIRECTORY. THE TEST CASE MUST RUN WITH MINIMAL PRELIMINARIES.
|
||||
|
|
|
|||
|
|
@ -10,4 +10,3 @@ The layout debugger can dump a variety of things including:
|
|||
## Usage
|
||||
- Use a debug build or add `ac_add_options --enable-layout-debugger` to your mozconfig.
|
||||
- Run with `./mach run --layoutdebug [filename]`
|
||||
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ values as the parent process.
|
|||
### Child process startup (parent side)
|
||||
When the first child process is created, the parent process serializes most of
|
||||
its hash table into a shared, immutable snapshot. This snapshot is stored in a
|
||||
shared memory region managed by a `SharedPrefMap` instance.
|
||||
shared memory region managed by a `SharedPrefMap` instance.
|
||||
|
||||
Sanitized preferences (matching _either_ the denylist of the dynamically named
|
||||
heuristic) are not included in the shared memory region. After building the
|
||||
|
|
|
|||
|
|
@ -77,4 +77,4 @@ pref("network.connectivity-service.DNSv6.domain", "example.org");
|
|||
pref("network.connectivity-service.IPv4.url", "http://detectportal.firefox.com/success.txt?ipv4");
|
||||
pref("network.connectivity-service.IPv6.url", "http://detectportal.firefox.com/success.txt?ipv6");
|
||||
|
||||
```
|
||||
```
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ enabled by setting network.trr.strict\_native\_fallback to true. With
|
|||
this, while we will still completely skip TRR for certain requests (like
|
||||
captive portal detection, bootstrapping the TRR provider, etc.) we will
|
||||
only fall back after a TRR failure to **Do53** for three possible
|
||||
reasons:
|
||||
reasons:
|
||||
1. We detected, via Confirmation, that TRR is currently out of
|
||||
service on the network. This could mean the provider is down or blocked.
|
||||
2. The address successfully resolved via TRR could not be connected to.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Value: 0
|
|||
This reason is set on _nsHostRecord_ before we attempt to resolve the domain.
|
||||
Normally we should not report this value into telemetry - if we do that means there's a bug in the code.
|
||||
|
||||
|
||||
|
||||
## TRR_OK
|
||||
|
||||
Value: 1
|
||||
|
|
@ -226,4 +226,3 @@ This reason is set when the DNS response contains NXDOMAIN rcode (0x03).
|
|||
Value: 31
|
||||
|
||||
This reason is set when the request was cancelled prior to completion.
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ The HTTP/3 and QUIC protocol are implemented in the neqo library. Http3Session,
|
|||
The following classes are necessary:
|
||||
- HttpConnectionUDP - this is the object that is registered in nsHttpConnectionMgr and it is also used as an async listener to socket events (it implements nsIUDPSocketSyncListener)
|
||||
- nsUDPSocket - represent a UDP socket and implements nsASocketHandler. nsSocketTransportService manages UDP and TCP sockets and calls the corresponding nsASocketHandler when the socket encounters an error or has data to be read, etc.
|
||||
- NeqoHttp3Conn is a c++ object that maps to the rust object Http3Client.
|
||||
- NeqoHttp3Conn is a c++ object that maps to the rust object Http3Client.
|
||||
- Http3Session manages NeqoHttp3Conn/Http3Client and provides bridge between the rust implementation and necko legacy code, i.e. HttpConnectionUDP and nsHttpTransaction.
|
||||
- Http3Streams are used to map reading and writing from/into a nsHttpTransaction onto the NeqoHttp3Conn/Http3Client API (e.g. nsHttpTransaction::OnWriteSegment will call Http3Client::read_data). NeqoHttp3Conn is only accessed by Http3Sesson and NeqoHttp3Conn functions are exposed through Http3Session where needed.
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ graph TD
|
|||
As described in [this docs](https://github.com/mozilla/neqo/blob/main/neqo-http3/src/lib.rs), neqo does not create a socket, it produces, i.e. encodes, data that should be sent as a payload in a UDP packet and consumes data received on the UDP socket. Therefore the necko is responsible for creating a socket and reading and writing data from/into the socket. Necko uses nsUDPSocket and nsSocketTransportService for this.
|
||||
The UDP socket is constantly polled for reading. It is not polled for writing, we let QUIC control to not overload the network path and buffers.
|
||||
|
||||
When the UDP socket has an available packet, nsSocketTransportService will return from the polling function and call nsUDPSocket::OnSocketReady, which calls HttpConnectionUDP::OnPacketReceived, HttpConnectionUDP::RecvData and further Http3Session::RecvData. For writing data
|
||||
When the UDP socket has an available packet, nsSocketTransportService will return from the polling function and call nsUDPSocket::OnSocketReady, which calls HttpConnectionUDP::OnPacketReceived, HttpConnectionUDP::RecvData and further Http3Session::RecvData. For writing data
|
||||
HttpConnectionUDP::SendData is called which calls Http3Session::SendData.
|
||||
|
||||
Neqo needs an external timer. The timer is managed by Http3Session. When the timer expires HttpConnectionUDP::OnQuicTimeoutExpired is executed that calls Http3Session::ProcessOutputAndEvents.
|
||||
|
|
@ -48,7 +48,7 @@ Three main neqo functions responsible for driving neqo are process_input, proces
|
|||
In this function we take data from the UDP socket and call NeqoHttp3Conn::ProcessInput that maps to Http3Client::process_input. The packets are read from the socket until the socket buffer is empty.
|
||||
|
||||
**ProcessEvents**
|
||||
This function process all available neqo events. It returns earlier only in case of a fatal error.
|
||||
This function process all available neqo events. It returns earlier only in case of a fatal error.
|
||||
It calls NeqoHttp3Conn::GetEvent which maps to Http3Client::next_event.
|
||||
The events and their handling will be explained below.
|
||||
|
||||
|
|
@ -149,6 +149,6 @@ For **HeaderReady** and **DataReadable** the Http3Stream::WriteSegments function
|
|||
|
||||
The **Session** event is posted when a WebTransport session is successfully negotiated.
|
||||
|
||||
The **SessionClosed** event is posted when a connection is closed gracefully or abruptly.
|
||||
The **SessionClosed** event is posted when a connection is closed gracefully or abruptly.
|
||||
|
||||
The **NewStream** is posted when a new stream has been opened by the peer.
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ While we could simply pass strings around and leave it to the final consumer to
|
|||
|
||||
### Diagram of interfaces
|
||||
```{mermaid}
|
||||
classDiagram
|
||||
classDiagram
|
||||
nsISupports <-- nsIURI
|
||||
nsIURI <-- nsIURL
|
||||
nsIURL <-- nsIFileURL
|
||||
|
|
@ -114,7 +114,7 @@ nsIJARURI o-- nsJARURI
|
|||
## Class and interface diagram
|
||||
|
||||
```{mermaid}
|
||||
classDiagram
|
||||
classDiagram
|
||||
nsISupports <-- nsIURI
|
||||
nsIURI <-- nsIURL
|
||||
nsIURL <-- nsIFileURL
|
||||
|
|
|
|||
|
|
@ -4,4 +4,3 @@ WebTransport
|
|||
Components:
|
||||
|
||||
- [WebTransportSessionProxy](webtransportsessionproxy.md)
|
||||
|
||||
|
|
|
|||
|
|
@ -53,4 +53,3 @@ The following metrics are added to the ping:
|
|||
Data categories are [defined here](https://wiki.mozilla.org/Firefox/Data_Collection).
|
||||
|
||||
<!-- AUTOGENERATED BY glean_parser. DO NOT EDIT. -->
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ These scripts have been moved from
|
|||
nsSTSPreloadList.inc from whichever `BRANCH` is specified, add in the mandatory
|
||||
hosts, and those from the Chromium source, and check them all to see if their
|
||||
SSL configuration is valid, and whether or not they have the
|
||||
Strict-Transport-Security header set with an appropriate `max-age`.
|
||||
Strict-Transport-Security header set with an appropriate `max-age`.
|
||||
|
||||
This javascript has been modified to use async calls to improve performance.
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ Debugging tests
|
|||
---------------
|
||||
|
||||
The `./mach test` and `./mach mochitest` commands support a `--jsdebugger`
|
||||
flag which will open the browser toolbox. If you add the
|
||||
flag which will open the browser toolbox. If you add the
|
||||
[`debugger;` keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger)
|
||||
in your test, the debugger will pause there.
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ let result = await SpecialPowers.spawn(browser, [42, 100], async (val, val2) =>
|
|||
// Replaces the document body with '42':
|
||||
content.document.body.textContent = val;
|
||||
// Optionally, return a result. Has to be serializable to make it back to
|
||||
// the parent process (so DOM nodes or similar won't work!).
|
||||
// the parent process (so DOM nodes or similar won't work!).
|
||||
return Promise.resolve(val2 * 2);
|
||||
});
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,65 +1,64 @@
|
|||
# Configuration Changes
|
||||
|
||||
This process outlines how Mozilla will handle configuration changes. For a list of configuration changes, please see the [schedule](schedule.md)
|
||||
|
||||
## Infrastructure setup (2-4 weeks)
|
||||
|
||||
This is behind the scenes, when there is a need for a configuration change (upgrade or addition of a new platform), the first step
|
||||
is to build a machine and work to get the OS working with taskcluster. This is work for hardware/cloud is done by IT. Sometimes
|
||||
this is as simple as installing a package or changing an OS setting on an existing machine, but this requires automation and documentation.
|
||||
|
||||
In some cases there is little to no work as the CI change is running tests with different runtime settings (environment variables or preferences).
|
||||
|
||||
|
||||
## Setting up a pool on try server (1 week)
|
||||
|
||||
The next step is getting some machines available on try server. This is where we add some code in tree to support the new config
|
||||
(a new worker type, test variant, etc.) and validate any setup done by IT works with taskcluster client. Then Releng ensures the target tests
|
||||
can run at a basic level (mozharness, testharness, os environment, logging, something passes).
|
||||
|
||||
|
||||
## Green up tests (1 week)
|
||||
|
||||
This is a stage where Releng will run all the target tests on try server and disable, skip, fail-if all tests that are not passing or frequently
|
||||
intermittent. Typically there are a dozen or so iterations of this because a crash on one test means we don't run the rest of the tests in the
|
||||
manifest.
|
||||
|
||||
|
||||
## Turn on new config as tier-2 (1/2 week)
|
||||
|
||||
We will time this at the start of a new release.
|
||||
|
||||
Releng will land changes to manifests for all non passing tests and then schedule the new jobs by default. This will be tier-2 for a couple reasons:
|
||||
* it is a new config with a lot of tests that still need attention
|
||||
* in many cases there is a previous config (lets say upgrading windows 10 from 1803 -> 1903) which is still running in parallel as tier-1
|
||||
|
||||
This will now run on central and integration and be available on try server. In a few cases where there are limited machines (android phones),
|
||||
there will be needs to turn off the old config, or make the try server access hidden behind `./mach try --full`
|
||||
|
||||
|
||||
## Turn on new backstop jobs which run the skipped tests (1/2 week)
|
||||
|
||||
Releng will turn on a new temporary job that will run the tests which are not green by default. These will run as tier-2 on mozilla-central and be sheriffed.
|
||||
|
||||
The goal here is to find tests that are now passing and should be run by default. By doing this we are effectively running all the tests instead of
|
||||
disabling dozens of tests and forgetting about them.
|
||||
|
||||
|
||||
## Handoff to developers (1 week)
|
||||
|
||||
Releng will file bugs for all failing tests (one bug per manifest) and needinfo the triage owner to raise awareness that one or more tests in their area need
|
||||
attention. At this point, Releng is done and will move onto other work. Developers can reproduce the failures on try server and when fixed edit the manifest
|
||||
as appropriate.
|
||||
|
||||
There will be at least 6 weeks to investigate and fix the tests before they are promoted to tier-1.
|
||||
|
||||
|
||||
## move config to tier-1 (6-7 weeks later)
|
||||
|
||||
After the config has been running as tier-2 makes it to beta and then to the release branch (i.e. 2 new releases later), Releng will:
|
||||
* turn off the old tier-1 tests (if applicable)
|
||||
* promote the tier-2 jobs to tier-1
|
||||
* turn off the backstop jobs
|
||||
|
||||
This allows developers to schedule time in a 6 weeks period to investigate and fix any test failures.
|
||||
|
||||
# Configuration Changes
|
||||
|
||||
This process outlines how Mozilla will handle configuration changes. For a list of configuration changes, please see the [schedule](schedule.md)
|
||||
|
||||
## Infrastructure setup (2-4 weeks)
|
||||
|
||||
This is behind the scenes, when there is a need for a configuration change (upgrade or addition of a new platform), the first step
|
||||
is to build a machine and work to get the OS working with taskcluster. This is work for hardware/cloud is done by IT. Sometimes
|
||||
this is as simple as installing a package or changing an OS setting on an existing machine, but this requires automation and documentation.
|
||||
|
||||
In some cases there is little to no work as the CI change is running tests with different runtime settings (environment variables or preferences).
|
||||
|
||||
|
||||
## Setting up a pool on try server (1 week)
|
||||
|
||||
The next step is getting some machines available on try server. This is where we add some code in tree to support the new config
|
||||
(a new worker type, test variant, etc.) and validate any setup done by IT works with taskcluster client. Then Releng ensures the target tests
|
||||
can run at a basic level (mozharness, testharness, os environment, logging, something passes).
|
||||
|
||||
|
||||
## Green up tests (1 week)
|
||||
|
||||
This is a stage where Releng will run all the target tests on try server and disable, skip, fail-if all tests that are not passing or frequently
|
||||
intermittent. Typically there are a dozen or so iterations of this because a crash on one test means we don't run the rest of the tests in the
|
||||
manifest.
|
||||
|
||||
|
||||
## Turn on new config as tier-2 (1/2 week)
|
||||
|
||||
We will time this at the start of a new release.
|
||||
|
||||
Releng will land changes to manifests for all non passing tests and then schedule the new jobs by default. This will be tier-2 for a couple reasons:
|
||||
* it is a new config with a lot of tests that still need attention
|
||||
* in many cases there is a previous config (lets say upgrading windows 10 from 1803 -> 1903) which is still running in parallel as tier-1
|
||||
|
||||
This will now run on central and integration and be available on try server. In a few cases where there are limited machines (android phones),
|
||||
there will be needs to turn off the old config, or make the try server access hidden behind `./mach try --full`
|
||||
|
||||
|
||||
## Turn on new backstop jobs which run the skipped tests (1/2 week)
|
||||
|
||||
Releng will turn on a new temporary job that will run the tests which are not green by default. These will run as tier-2 on mozilla-central and be sheriffed.
|
||||
|
||||
The goal here is to find tests that are now passing and should be run by default. By doing this we are effectively running all the tests instead of
|
||||
disabling dozens of tests and forgetting about them.
|
||||
|
||||
|
||||
## Handoff to developers (1 week)
|
||||
|
||||
Releng will file bugs for all failing tests (one bug per manifest) and needinfo the triage owner to raise awareness that one or more tests in their area need
|
||||
attention. At this point, Releng is done and will move onto other work. Developers can reproduce the failures on try server and when fixed edit the manifest
|
||||
as appropriate.
|
||||
|
||||
There will be at least 6 weeks to investigate and fix the tests before they are promoted to tier-1.
|
||||
|
||||
|
||||
## move config to tier-1 (6-7 weeks later)
|
||||
|
||||
After the config has been running as tier-2 makes it to beta and then to the release branch (i.e. 2 new releases later), Releng will:
|
||||
* turn off the old tier-1 tests (if applicable)
|
||||
* promote the tier-2 jobs to tier-1
|
||||
* turn off the backstop jobs
|
||||
|
||||
This allows developers to schedule time in a 6 weeks period to investigate and fix any test failures.
|
||||
|
|
|
|||
|
|
@ -1,48 +1,48 @@
|
|||
# Schedule
|
||||
|
||||
For each CI config change, we need to follow:
|
||||
* scope of work (what will run, how frequently)
|
||||
* capacity planning (cost, physical space limitations)
|
||||
* will this replace anything or is this 100% new
|
||||
* puppet/deployment scripts or documentation
|
||||
* setup pool on try server
|
||||
* documented updated on this page, communicate with release management and others as appropriate
|
||||
|
||||
|
||||
## Current / Future CI config changes
|
||||
|
||||
Start Date | Completed | Tracking Bug | Description
|
||||
--- | --- | --- | ---
|
||||
October 2020 | TBD | [Bug 1665012](https://bugzilla.mozilla.org/show_bug.cgi?id=1665012) | add samsung S7 phones for perf testing
|
||||
November 2020 | TBD | [Bug 1676850](https://bugzilla.mozilla.org/show_bug.cgi?id=1676850) | Windows tests migrate from AWS -> Datacenter/Azure and 1803 -> 1903
|
||||
November 2020 | TBD | TBD | upgrade datacenter linux perf machines from ubuntu 16.04 to 18.04
|
||||
TBD | TBD | [Bug 1665012](https://bugzilla.mozilla.org/show_bug.cgi?id=1665012) | Android phones upgrade from version 7 -> 10
|
||||
October 2020 | TBD | [Bug 1673067](https://bugzilla.mozilla.org/show_bug.cgi?id=1673067) | Run tests on MacOSX BigSur (subset in parallel)
|
||||
October 2020 | TBD | [Bug 1673067](https://bugzilla.mozilla.org/show_bug.cgi?id=1673067) | Run tests on MacOSX Aarch64 (subset in parallel)
|
||||
December 2020 | TBD | TBD | Migrate OSX from Mac Mini R7, OSX 10.14 (Mojave) -> Mac Mini R8, OSX 10.15 (Catalina)
|
||||
TBD | TBD | TBD | Migrate more coverage of OSX from 10.14 to BigSur/aarch64
|
||||
TBD | TBD | TBD | Upgrade ubuntu from 18.04 to 20.04
|
||||
TBD | TBD | TBD | Upgrade android emulators to modern version
|
||||
September 2020 | TBD | [Bug 1548264](https://bugzilla.mozilla.org/show_bug.cgi?id=1548264) | Python 2.7 -> 3.6 migration in CI
|
||||
TBD | TBD | [Bug 1665010](https://bugzilla.mozilla.org/show_bug.cgi?id=1665010) | Add more android phone hardware (replace moto g5 and probably pixel 2)
|
||||
TBD | TBD | TBD | Upgrade datacenter hardware for windows/linux (primarily perf)
|
||||
TBD | TBD | TBD | Add Linux ARM64 worker in AWS (as it is close to Apple Silicon)
|
||||
|
||||
|
||||
## Completed CI config changes
|
||||
|
||||
Start Date | Completed | Tracking Bug | Description
|
||||
--- | --- | --- | ---
|
||||
July 2020 | October 2020| [Bug 1653344](https://bugzilla.mozilla.org/show_bug.cgi?id=1653344) | Remove EDID dongles from MacOSX machines
|
||||
August 2020 | September 2020 | [Bug 1643689](https://bugzilla.mozilla.org/show_bug.cgi?id=1643689) | Schedule tests by test selection/manifest
|
||||
June 2020 | August 2020 | [Bug 1486004](https://bugzilla.mozilla.org/show_bug.cgi?id=1486004) | Android hardware tests running without rooted phones
|
||||
August 2019 | January 2020 | [Bug 1572242](https://bugzilla.mozilla.org/show_bug.cgi?id=1572242) | Upgrade Ubuntu from 16.04 to 18.04 (finished in January)
|
||||
|
||||
|
||||
## Appendix:
|
||||
* *OS*: base operating system such as Android, Linux, Mac OSX, Windows
|
||||
* *Hardware*: specific cpu/memory/disk/graphics/display/inputs that we are using, could be physical hardware we own or manage, or it could be a cloud provider.
|
||||
* *Platform*: a combination of hardware and OS
|
||||
* *Configuration*: what we change on a platform (can be runtime with flags), installed OS software updates (service pack), tools (python/node/etc.), hardware or OS settings (anti aliasing, display resolution, background processes, clipboard), environment variables,
|
||||
* *Test Failure*: a test doesn’t report the expected result (if we expect fail and we crash, that is unexpected). Typically this is a failure, but it can be a timeout, crash, not run, or even pass
|
||||
* *Greening up*: Assuming all tests return expected results (passing), they are green. When tests fail, they are orange. We need to find a way to get all tests green by investigating test failures.
|
||||
# Schedule
|
||||
|
||||
For each CI config change, we need to follow:
|
||||
* scope of work (what will run, how frequently)
|
||||
* capacity planning (cost, physical space limitations)
|
||||
* will this replace anything or is this 100% new
|
||||
* puppet/deployment scripts or documentation
|
||||
* setup pool on try server
|
||||
* documented updated on this page, communicate with release management and others as appropriate
|
||||
|
||||
|
||||
## Current / Future CI config changes
|
||||
|
||||
Start Date | Completed | Tracking Bug | Description
|
||||
--- | --- | --- | ---
|
||||
October 2020 | TBD | [Bug 1665012](https://bugzilla.mozilla.org/show_bug.cgi?id=1665012) | add samsung S7 phones for perf testing
|
||||
November 2020 | TBD | [Bug 1676850](https://bugzilla.mozilla.org/show_bug.cgi?id=1676850) | Windows tests migrate from AWS -> Datacenter/Azure and 1803 -> 1903
|
||||
November 2020 | TBD | TBD | upgrade datacenter linux perf machines from ubuntu 16.04 to 18.04
|
||||
TBD | TBD | [Bug 1665012](https://bugzilla.mozilla.org/show_bug.cgi?id=1665012) | Android phones upgrade from version 7 -> 10
|
||||
October 2020 | TBD | [Bug 1673067](https://bugzilla.mozilla.org/show_bug.cgi?id=1673067) | Run tests on MacOSX BigSur (subset in parallel)
|
||||
October 2020 | TBD | [Bug 1673067](https://bugzilla.mozilla.org/show_bug.cgi?id=1673067) | Run tests on MacOSX Aarch64 (subset in parallel)
|
||||
December 2020 | TBD | TBD | Migrate OSX from Mac Mini R7, OSX 10.14 (Mojave) -> Mac Mini R8, OSX 10.15 (Catalina)
|
||||
TBD | TBD | TBD | Migrate more coverage of OSX from 10.14 to BigSur/aarch64
|
||||
TBD | TBD | TBD | Upgrade ubuntu from 18.04 to 20.04
|
||||
TBD | TBD | TBD | Upgrade android emulators to modern version
|
||||
September 2020 | TBD | [Bug 1548264](https://bugzilla.mozilla.org/show_bug.cgi?id=1548264) | Python 2.7 -> 3.6 migration in CI
|
||||
TBD | TBD | [Bug 1665010](https://bugzilla.mozilla.org/show_bug.cgi?id=1665010) | Add more android phone hardware (replace moto g5 and probably pixel 2)
|
||||
TBD | TBD | TBD | Upgrade datacenter hardware for windows/linux (primarily perf)
|
||||
TBD | TBD | TBD | Add Linux ARM64 worker in AWS (as it is close to Apple Silicon)
|
||||
|
||||
|
||||
## Completed CI config changes
|
||||
|
||||
Start Date | Completed | Tracking Bug | Description
|
||||
--- | --- | --- | ---
|
||||
July 2020 | October 2020| [Bug 1653344](https://bugzilla.mozilla.org/show_bug.cgi?id=1653344) | Remove EDID dongles from MacOSX machines
|
||||
August 2020 | September 2020 | [Bug 1643689](https://bugzilla.mozilla.org/show_bug.cgi?id=1643689) | Schedule tests by test selection/manifest
|
||||
June 2020 | August 2020 | [Bug 1486004](https://bugzilla.mozilla.org/show_bug.cgi?id=1486004) | Android hardware tests running without rooted phones
|
||||
August 2019 | January 2020 | [Bug 1572242](https://bugzilla.mozilla.org/show_bug.cgi?id=1572242) | Upgrade Ubuntu from 16.04 to 18.04 (finished in January)
|
||||
|
||||
|
||||
## Appendix:
|
||||
* *OS*: base operating system such as Android, Linux, Mac OSX, Windows
|
||||
* *Hardware*: specific cpu/memory/disk/graphics/display/inputs that we are using, could be physical hardware we own or manage, or it could be a cloud provider.
|
||||
* *Platform*: a combination of hardware and OS
|
||||
* *Configuration*: what we change on a platform (can be runtime with flags), installed OS software updates (service pack), tools (python/node/etc.), hardware or OS settings (anti aliasing, display resolution, background processes, clipboard), environment variables,
|
||||
* *Test Failure*: a test doesn’t report the expected result (if we expect fail and we crash, that is unexpected). Typically this is a failure, but it can be a timeout, crash, not run, or even pass
|
||||
* *Greening up*: Assuming all tests return expected results (passing), they are green. When tests fail, they are orange. We need to find a way to get all tests green by investigating test failures.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ To add a new test file to this test suite:
|
|||
|
||||
import helpers
|
||||
|
||||
helpers.setup()
|
||||
helpers.setup()
|
||||
```
|
||||
- don't forget to call `mozunit.main` at the end of the test file:
|
||||
```
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ https://github.com/mozilla-extensions/quitter
|
|||
|
||||
This is within the mozilla-extensions organization so that we can sign the .xpi.
|
||||
|
||||
To update code, please submit a PR to the github repo. Once that is merged in, a JIRA ticket (ex [ADDONSOPS-194](https://mozilla-hub.atlassian.net/browse/ADDONSOPS-194)) is needed to resign the .xpi.
|
||||
To update code, please submit a PR to the github repo. Once that is merged in, a JIRA ticket (ex [ADDONSOPS-194](https://mozilla-hub.atlassian.net/browse/ADDONSOPS-194)) is needed to resign the .xpi.
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Update Verification
|
|||
`verify.sh`
|
||||
|
||||
> Does a low-level check of all advertised MAR files. Expects to have a
|
||||
> file named all-locales, but does not (yet) handle platform exceptions, so
|
||||
> file named all-locales, but does not (yet) handle platform exceptions, so
|
||||
> these should be removed from the locales file.
|
||||
>
|
||||
> Prints errors on both STDOUT and STDIN, the intention is to run the
|
||||
|
|
@ -31,10 +31,10 @@ Update Verification
|
|||
> 3) check that the partial and full match the advertised size and sha1sum
|
||||
> 4) downloads the latest release, and an older release
|
||||
> 5) applies MAR to the older release, and compares the two releases.
|
||||
>
|
||||
>
|
||||
> Step 5 is repeated for both the complete and partial MAR.
|
||||
>
|
||||
> Expects to have an updates.cfg file, describing all releases to try updating
|
||||
> Expects to have an updates.cfg file, describing all releases to try updating
|
||||
> from.
|
||||
|
||||
Valid Platforms for AUS
|
||||
|
|
|
|||
|
|
@ -1,227 +1,227 @@
|
|||
# A primer on macOS SDKs
|
||||
|
||||
## Overview
|
||||
|
||||
A macOS SDK is an on-disk directory that contains header files and meta information for macOS APIs.
|
||||
Apple distributes SDKs as part of the Xcode app bundle. Each Xcode version comes with one macOS SDK,
|
||||
the SDK for the most recent released version of macOS at the time of the Xcode release.
|
||||
The SDK is located at `/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk`.
|
||||
|
||||
Compiling Firefox for macOS requires a macOS SDK. The build system uses the SDK from Xcode.app by
|
||||
default, and you can select a different SDK using the `mozconfig` option `--with-macos-sdk`:
|
||||
|
||||
```text
|
||||
ac_add_options --with-macos-sdk=/Users/username/SDKs/MacOSX11.3.sdk
|
||||
```
|
||||
|
||||
## Supported SDKs
|
||||
|
||||
First off, Firefox runs on 10.12 and above. This is called the "minimum deployment target" and is
|
||||
independent of the SDK version.
|
||||
|
||||
Our official Firefox builds compiled in CI (continuous integration) currently use the 11.3 SDK (last updated in [bug 1788854](https://bugzilla.mozilla.org/show_bug.cgi?id=1788854)). This is also the minimum supported SDK version for local builds.
|
||||
|
||||
Compiling with different SDKs breaks from time to time. Such breakages should be [reported in Bugzilla](https://bugzilla.mozilla.org/enter_bug.cgi?blocked=mach-busted&bug_type=defect&cc=:spohl,:mstange&component=General&form_name=enter_bug&keywords=regression&op_sys=macOS&product=Firefox%20Build%20System&rep_platform=All) and fixed quickly.
|
||||
|
||||
## Obtaining SDKs
|
||||
|
||||
Sometimes you need an SDK that's different from the one in your Xcode.app, for example
|
||||
to check whether your code change breaks building with other SDKs, or to verify the
|
||||
runtime behavior with the SDK used for CI builds.
|
||||
|
||||
The easy but slightly questionable way to obtain an SDK is to download it from a public github repo.
|
||||
|
||||
Here's another option:
|
||||
|
||||
1. Have your Apple ID login details ready, and bring enough time and patience for a 5GB download.
|
||||
2. Check [these tables in the Xcode wikipedia article](https://en.wikipedia.org/wiki/Xcode#Xcode_7.0_-_10.x_(since_Free_On-Device_Development))
|
||||
and find an Xcode version that contains the SDK you need.
|
||||
3. Look up the Xcode version number on [xcodereleases.com](https://xcodereleases.com/) and click the Download link for it.
|
||||
4. Log in with your Apple ID. Then the download should start.
|
||||
5. Wait for the 5GB Xcode_*.xip download to finish.
|
||||
6. Open the downloaded xip file. This will extract the Xcode.app bundle.
|
||||
7. Inside the app bundle, the SDK is at `Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk`.
|
||||
|
||||
## Effects of the SDK version
|
||||
|
||||
An SDK only contains declarations of APIs. It does not contain the implementations for these APIs.
|
||||
|
||||
The implementation of an API is provided by the OS that the app runs on. It is supplied at runtime,
|
||||
when your app starts up, by the dynamic linker. For example, the AppKit implementation comes
|
||||
from `/System/Library/Frameworks/AppKit.framework` from the OS that the app is run on, regardless
|
||||
of what SDK was used when compiling the app.
|
||||
|
||||
In other words, building with a macOS SDK of a higher version doesn't magically make new APIs available
|
||||
when running on older versions of macOS. And, conversely, building with a lower macOS SDK doesn't limit
|
||||
which APIs you can use if your app is run on a newer version of macOS, assuming you manage to convince the
|
||||
compiler to accept your code.
|
||||
|
||||
The SDK used for building an app determines three things:
|
||||
|
||||
1. Whether your code compiles at all,
|
||||
2. which range of macOS versions your app can run on (available deployment targets), and
|
||||
3. certain aspects of runtime behavior.
|
||||
|
||||
The first is straightforward: An SDK contains header files. If you call an API that's not declared
|
||||
anywhere - neither in a header file nor in your own code - then your compiler will emit an error.
|
||||
(Special case: Calling an unknown Objective-C method usually only emits a warning, not an error.)
|
||||
|
||||
The second aspect, available deployment targets, is usually not worth worrying about:
|
||||
SDKs have large ranges of supported macOS deployment targets.
|
||||
For example, the 10.15 SDK supports running your app on macOS versions all the way back to 10.6.
|
||||
This information is written down in the SDK's `SDKSettings.plist`.
|
||||
|
||||
The third aspect, varying runtime behavior, is perhaps the most insidious and surprising aspect, and is described
|
||||
in the next section.
|
||||
|
||||
## Runtime differences based on macOS SDK version
|
||||
|
||||
When a new version of macOS is released, existing APIs can change their behavior.
|
||||
These changes are usually described in the AppKit release notes:
|
||||
|
||||
- [macOS 10.15 release notes](https://developer.apple.com/documentation/macos_release_notes/macos_catalina_10_15_release_notes?language=objc)
|
||||
- [macOS 10.14 AppKit release notes](https://developer.apple.com/documentation/macos_release_notes/macos_mojave_10_14_release_notes/appkit_release_notes_for_macos_10_14?language=objc)
|
||||
- [macOS 10.13 AppKit release notes](https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKit/)
|
||||
- [macOS 10.12 and older AppKit release notes](https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKitOlderNotes/)
|
||||
|
||||
Sometimes, these differences in behavior have the potential to break existing apps. In those instances,
|
||||
Apple often provides the old (compatible) behavior until the app is re-built with the new SDK, expecting
|
||||
developers to update their apps so that they work with the new behavior, at the same time as
|
||||
they update to the new SDK.
|
||||
|
||||
Here's an [example from the 10.13 release notes](https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKit/#10_13NSCollectionView%20Responsive%20Scrolling):
|
||||
|
||||
> Responsive Scrolling in NSCollectionViews is enabled only for apps linked on or after macOS 10.13.
|
||||
|
||||
Here, "linked on or after macOS 10.13" means "linked against the macOS 10.13 SDK or newer".
|
||||
|
||||
Apple's expectation is that you upgrade to the new macOS version when it is released, download a new
|
||||
Xcode version when it is released, synchronize these updates across the machines of all developers
|
||||
that work on your app, use the SDK in the newest Xcode to compile your app, and make changes to your
|
||||
app to be compatible with any behavior changes whenever you update Xcode.
|
||||
This expectation does not always match reality. It definitely doesn't match what we're doing with Firefox.
|
||||
|
||||
For Firefox, SDK-dependent compatibility behaviors mean that developers who build Firefox locally
|
||||
can see different runtime behavior than the users of our CI builds, if they use a different SDK than
|
||||
the SDK used in CI.
|
||||
That is, unless we change the Firefox code so that it has the same behavior regardless of SDK version.
|
||||
Often this can be achieved by using APIs in a way that's more in line with the API's recommended use.
|
||||
|
||||
For example, we've had cases of
|
||||
[broken placeholder text in search fields](https://bugzilla.mozilla.org/show_bug.cgi?id=1273106),
|
||||
[missing](https://bugzilla.mozilla.org/show_bug.cgi?id=941325) or [double-drawn focus rings](https://searchfox.org/mozilla-central/rev/9ad88f80aeedcd3cd7d7f63be07f577861727054/widget/cocoa/nsNativeThemeCocoa.mm#149-169),
|
||||
[a startup crash](https://bugzilla.mozilla.org/show_bug.cgi?id=1516437),
|
||||
[fully black windows](https://bugzilla.mozilla.org/show_bug.cgi?id=1494022),
|
||||
[fully gray windows](https://bugzilla.mozilla.org/show_bug.cgi?id=1576113#c4),
|
||||
[broken vibrancy](https://bugzilla.mozilla.org/show_bug.cgi?id=1475694), and
|
||||
[broken colors in dark mode](https://bugzilla.mozilla.org/show_bug.cgi?id=1578917).
|
||||
|
||||
In most of these cases, the breakage was either very minor, or it was caused by Firefox doing things
|
||||
that were explicitly discouraged, like creating unexpected NSView hierarchies, or relying on unspecified
|
||||
implementation details. (With one exception: In 10.14, HiDPI-aware `NSOpenGLContext` rendering in
|
||||
layer-backed windows simply broke.)
|
||||
|
||||
And in all of these cases, it was the SDK-dependent compatibility behavior that protected our users from being
|
||||
exposed to the breakage. Our CI builds continued to work because they were built with an older SDK.
|
||||
|
||||
We have addressed all known cases of breakage when building Firefox with newer SDKs.
|
||||
I am not aware of any current instances of this problem as of this writing (June 2020).
|
||||
|
||||
For more information about how these compatibility tricks work,
|
||||
read the [Overriding SDK-dependent runtime behavior](#overriding-sdk-dependent-runtime-behavior) section.
|
||||
|
||||
## Supporting multiple SDKs
|
||||
|
||||
As described under [Supported SDKs](#supported-sdks), Firefox can be built with a wide variety of SDK versions.
|
||||
|
||||
This ability comes at the cost of some manual labor; it requires some well-placed `#ifdefs` and
|
||||
copying of header definitions.
|
||||
|
||||
Every SDK defines the macro `MAC_OS_X_VERSION_MAX_ALLOWED` with a value that matches the SDK version,
|
||||
in the SDK's `AvailabilityMacros.h` header. This header also defines version constants like `MAC_OS_X_VERSION_10_12`.
|
||||
For example, I have a version of the 10.12 SDK which contains the line
|
||||
|
||||
```cpp
|
||||
#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_12_4
|
||||
```
|
||||
|
||||
The name `MAC_OS_X_VERSION_MAX_ALLOWED` is rather misleading; a better name would be
|
||||
`MAC_OS_X_VERSION_MAX_KNOWN_BY_SDK`. Compiling with an old SDK *does not* prevent apps from running
|
||||
on newer versions of macOS.
|
||||
|
||||
With the help of the `MAC_OS_X_VERSION_MAX_ALLOWED` macro, we can make our code adapt to the SDK that's
|
||||
being used. Here's [an example](https://searchfox.org/mozilla-central/rev/9ad88f80aeedcd3cd7d7f63be07f577861727054/toolkit/xre/MacApplicationDelegate.mm#345-351) where the 10.14 SDK changed the signature of
|
||||
[an `NSApplicationDelegate` method](https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428471-application?language=objc):
|
||||
|
||||
```objc++
|
||||
- (BOOL)application:(NSApplication*)application
|
||||
continueUserActivity:(NSUserActivity*)userActivity
|
||||
#if defined(MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
||||
restorationHandler:(void (^)(NSArray<id<NSUserActivityRestoring>>*))restorationHandler {
|
||||
#else
|
||||
restorationHandler:(void (^)(NSArray*))restorationHandler {
|
||||
#endif
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
We can also use this macro to supply missing API definitions in such a way that
|
||||
they don't conflict with the definitions from the SDK.
|
||||
This is described in the "Using macOS APIs" document, under [Using new APIs with old SDKs](./macos-apis.html#using-new-apis-with-old-sdks).
|
||||
|
||||
## Overriding SDK-dependent runtime behavior
|
||||
|
||||
This section contains some more details on the compatibility tricks that cause different runtime
|
||||
behavior dependent on the SDK, as described in
|
||||
[Runtime differences based on macOS SDK version](#runtime-differences-based-on-macos-sdk-version).
|
||||
|
||||
### How it works
|
||||
|
||||
AppKit is the one system framework I know of that employs these tricks. Let's explore how AppKit makes this work,
|
||||
by going back to the [NSCollectionView example](https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKit/#10_13NSCollectionView%20Responsive%20Scrolling) from above:
|
||||
|
||||
> Responsive Scrolling in NSCollectionViews is enabled only for apps linked on or after macOS 10.13.
|
||||
|
||||
For each of these SDK-dependent behavior differences, both the old and the new behavior are implemented
|
||||
in the version of AppKit that ships with the new macOS version.
|
||||
At runtime, AppKit selects one of the behaviors based on the SDK version, with a call to
|
||||
`_CFExecutableLinkedOnOrAfter()`. This call checks the SDK version of the main executable of the
|
||||
process that's running AppKit code; in our case that's the `firefox` or `plugin-container` executable.
|
||||
The SDK version is stored in the mach-o headers of the executable by the linker.
|
||||
|
||||
One interesting design aspect of AppKit's compatibility tricks is the fact that most of these behavior differences
|
||||
can be toggled with a "user default" preference.
|
||||
For example, the "responsive scrolling in NSCollectionViews" behavior change can be controlled with
|
||||
a user default with the name "NSCollectionViewPrefetchingEnabled".
|
||||
The SDK check only happens if "NSCollectionViewPrefetchingEnabled" is not set to either YES or NO.
|
||||
|
||||
More precisely, this example works as follows:
|
||||
|
||||
- `-[NSCollectionView prepareContentInRect:]` is the function that supports both the old and the new behavior.
|
||||
- It calls `_NSGetBoolAppConfig` for the value "NSCollectionViewPrefetchingEnabled", and also supplies a "default
|
||||
value function".
|
||||
- If the user default is not set, the default value function is called. This function has the name
|
||||
`NSCollectionViewPrefetchingEnabledDefaultValueFunction`.
|
||||
- `NSCollectionViewPrefetchingEnabledDefaultValueFunction` calls `_CFExecutableLinkedOnOrAfter(13)`.
|
||||
|
||||
You can find many similar toggles if you list the AppKit symbols that end in `DefaultValueFunction`,
|
||||
for example by executing `nm /System/Library/Frameworks/AppKit.framework/AppKit | grep DefaultValueFunction`.
|
||||
|
||||
### Overriding SDK-dependent runtime behavior
|
||||
|
||||
You can set these preferences programmatically, in a way that `_NSGetBoolAppConfig()` can pick them up,
|
||||
for example with [`registerDefaults`](https://developer.apple.com/documentation/foundation/nsuserdefaults/1417065-registerdefaults?language=objc)
|
||||
or like this:
|
||||
|
||||
```objc++
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NSViewAllowsRootLayerBacking"];
|
||||
```
|
||||
|
||||
The AppKit release notes mention this ability but ask for it to only be used for debugging purposes:
|
||||
|
||||
> In some cases, we provide defaults (preferences) settings which can be used to get the old or new behavior,
|
||||
> independent of what system an application was built against. Often these preferences are provided for
|
||||
> debugging purposes only; in some cases the preferences can be used to globally modify the behavior
|
||||
> of an application by registering the values (do it somewhere very early, with `-[NSUserDefaults registerDefaults:]`).
|
||||
|
||||
It's interesting that they mention this at all because, as far as I can tell, none of these values are documented.
|
||||
# A primer on macOS SDKs
|
||||
|
||||
## Overview
|
||||
|
||||
A macOS SDK is an on-disk directory that contains header files and meta information for macOS APIs.
|
||||
Apple distributes SDKs as part of the Xcode app bundle. Each Xcode version comes with one macOS SDK,
|
||||
the SDK for the most recent released version of macOS at the time of the Xcode release.
|
||||
The SDK is located at `/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk`.
|
||||
|
||||
Compiling Firefox for macOS requires a macOS SDK. The build system uses the SDK from Xcode.app by
|
||||
default, and you can select a different SDK using the `mozconfig` option `--with-macos-sdk`:
|
||||
|
||||
```text
|
||||
ac_add_options --with-macos-sdk=/Users/username/SDKs/MacOSX11.3.sdk
|
||||
```
|
||||
|
||||
## Supported SDKs
|
||||
|
||||
First off, Firefox runs on 10.12 and above. This is called the "minimum deployment target" and is
|
||||
independent of the SDK version.
|
||||
|
||||
Our official Firefox builds compiled in CI (continuous integration) currently use the 11.3 SDK (last updated in [bug 1788854](https://bugzilla.mozilla.org/show_bug.cgi?id=1788854)). This is also the minimum supported SDK version for local builds.
|
||||
|
||||
Compiling with different SDKs breaks from time to time. Such breakages should be [reported in Bugzilla](https://bugzilla.mozilla.org/enter_bug.cgi?blocked=mach-busted&bug_type=defect&cc=:spohl,:mstange&component=General&form_name=enter_bug&keywords=regression&op_sys=macOS&product=Firefox%20Build%20System&rep_platform=All) and fixed quickly.
|
||||
|
||||
## Obtaining SDKs
|
||||
|
||||
Sometimes you need an SDK that's different from the one in your Xcode.app, for example
|
||||
to check whether your code change breaks building with other SDKs, or to verify the
|
||||
runtime behavior with the SDK used for CI builds.
|
||||
|
||||
The easy but slightly questionable way to obtain an SDK is to download it from a public github repo.
|
||||
|
||||
Here's another option:
|
||||
|
||||
1. Have your Apple ID login details ready, and bring enough time and patience for a 5GB download.
|
||||
2. Check [these tables in the Xcode wikipedia article](https://en.wikipedia.org/wiki/Xcode#Xcode_7.0_-_10.x_(since_Free_On-Device_Development))
|
||||
and find an Xcode version that contains the SDK you need.
|
||||
3. Look up the Xcode version number on [xcodereleases.com](https://xcodereleases.com/) and click the Download link for it.
|
||||
4. Log in with your Apple ID. Then the download should start.
|
||||
5. Wait for the 5GB Xcode_*.xip download to finish.
|
||||
6. Open the downloaded xip file. This will extract the Xcode.app bundle.
|
||||
7. Inside the app bundle, the SDK is at `Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk`.
|
||||
|
||||
## Effects of the SDK version
|
||||
|
||||
An SDK only contains declarations of APIs. It does not contain the implementations for these APIs.
|
||||
|
||||
The implementation of an API is provided by the OS that the app runs on. It is supplied at runtime,
|
||||
when your app starts up, by the dynamic linker. For example, the AppKit implementation comes
|
||||
from `/System/Library/Frameworks/AppKit.framework` from the OS that the app is run on, regardless
|
||||
of what SDK was used when compiling the app.
|
||||
|
||||
In other words, building with a macOS SDK of a higher version doesn't magically make new APIs available
|
||||
when running on older versions of macOS. And, conversely, building with a lower macOS SDK doesn't limit
|
||||
which APIs you can use if your app is run on a newer version of macOS, assuming you manage to convince the
|
||||
compiler to accept your code.
|
||||
|
||||
The SDK used for building an app determines three things:
|
||||
|
||||
1. Whether your code compiles at all,
|
||||
2. which range of macOS versions your app can run on (available deployment targets), and
|
||||
3. certain aspects of runtime behavior.
|
||||
|
||||
The first is straightforward: An SDK contains header files. If you call an API that's not declared
|
||||
anywhere - neither in a header file nor in your own code - then your compiler will emit an error.
|
||||
(Special case: Calling an unknown Objective-C method usually only emits a warning, not an error.)
|
||||
|
||||
The second aspect, available deployment targets, is usually not worth worrying about:
|
||||
SDKs have large ranges of supported macOS deployment targets.
|
||||
For example, the 10.15 SDK supports running your app on macOS versions all the way back to 10.6.
|
||||
This information is written down in the SDK's `SDKSettings.plist`.
|
||||
|
||||
The third aspect, varying runtime behavior, is perhaps the most insidious and surprising aspect, and is described
|
||||
in the next section.
|
||||
|
||||
## Runtime differences based on macOS SDK version
|
||||
|
||||
When a new version of macOS is released, existing APIs can change their behavior.
|
||||
These changes are usually described in the AppKit release notes:
|
||||
|
||||
- [macOS 10.15 release notes](https://developer.apple.com/documentation/macos_release_notes/macos_catalina_10_15_release_notes?language=objc)
|
||||
- [macOS 10.14 AppKit release notes](https://developer.apple.com/documentation/macos_release_notes/macos_mojave_10_14_release_notes/appkit_release_notes_for_macos_10_14?language=objc)
|
||||
- [macOS 10.13 AppKit release notes](https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKit/)
|
||||
- [macOS 10.12 and older AppKit release notes](https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKitOlderNotes/)
|
||||
|
||||
Sometimes, these differences in behavior have the potential to break existing apps. In those instances,
|
||||
Apple often provides the old (compatible) behavior until the app is re-built with the new SDK, expecting
|
||||
developers to update their apps so that they work with the new behavior, at the same time as
|
||||
they update to the new SDK.
|
||||
|
||||
Here's an [example from the 10.13 release notes](https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKit/#10_13NSCollectionView%20Responsive%20Scrolling):
|
||||
|
||||
> Responsive Scrolling in NSCollectionViews is enabled only for apps linked on or after macOS 10.13.
|
||||
|
||||
Here, "linked on or after macOS 10.13" means "linked against the macOS 10.13 SDK or newer".
|
||||
|
||||
Apple's expectation is that you upgrade to the new macOS version when it is released, download a new
|
||||
Xcode version when it is released, synchronize these updates across the machines of all developers
|
||||
that work on your app, use the SDK in the newest Xcode to compile your app, and make changes to your
|
||||
app to be compatible with any behavior changes whenever you update Xcode.
|
||||
This expectation does not always match reality. It definitely doesn't match what we're doing with Firefox.
|
||||
|
||||
For Firefox, SDK-dependent compatibility behaviors mean that developers who build Firefox locally
|
||||
can see different runtime behavior than the users of our CI builds, if they use a different SDK than
|
||||
the SDK used in CI.
|
||||
That is, unless we change the Firefox code so that it has the same behavior regardless of SDK version.
|
||||
Often this can be achieved by using APIs in a way that's more in line with the API's recommended use.
|
||||
|
||||
For example, we've had cases of
|
||||
[broken placeholder text in search fields](https://bugzilla.mozilla.org/show_bug.cgi?id=1273106),
|
||||
[missing](https://bugzilla.mozilla.org/show_bug.cgi?id=941325) or [double-drawn focus rings](https://searchfox.org/mozilla-central/rev/9ad88f80aeedcd3cd7d7f63be07f577861727054/widget/cocoa/nsNativeThemeCocoa.mm#149-169),
|
||||
[a startup crash](https://bugzilla.mozilla.org/show_bug.cgi?id=1516437),
|
||||
[fully black windows](https://bugzilla.mozilla.org/show_bug.cgi?id=1494022),
|
||||
[fully gray windows](https://bugzilla.mozilla.org/show_bug.cgi?id=1576113#c4),
|
||||
[broken vibrancy](https://bugzilla.mozilla.org/show_bug.cgi?id=1475694), and
|
||||
[broken colors in dark mode](https://bugzilla.mozilla.org/show_bug.cgi?id=1578917).
|
||||
|
||||
In most of these cases, the breakage was either very minor, or it was caused by Firefox doing things
|
||||
that were explicitly discouraged, like creating unexpected NSView hierarchies, or relying on unspecified
|
||||
implementation details. (With one exception: In 10.14, HiDPI-aware `NSOpenGLContext` rendering in
|
||||
layer-backed windows simply broke.)
|
||||
|
||||
And in all of these cases, it was the SDK-dependent compatibility behavior that protected our users from being
|
||||
exposed to the breakage. Our CI builds continued to work because they were built with an older SDK.
|
||||
|
||||
We have addressed all known cases of breakage when building Firefox with newer SDKs.
|
||||
I am not aware of any current instances of this problem as of this writing (June 2020).
|
||||
|
||||
For more information about how these compatibility tricks work,
|
||||
read the [Overriding SDK-dependent runtime behavior](#overriding-sdk-dependent-runtime-behavior) section.
|
||||
|
||||
## Supporting multiple SDKs
|
||||
|
||||
As described under [Supported SDKs](#supported-sdks), Firefox can be built with a wide variety of SDK versions.
|
||||
|
||||
This ability comes at the cost of some manual labor; it requires some well-placed `#ifdefs` and
|
||||
copying of header definitions.
|
||||
|
||||
Every SDK defines the macro `MAC_OS_X_VERSION_MAX_ALLOWED` with a value that matches the SDK version,
|
||||
in the SDK's `AvailabilityMacros.h` header. This header also defines version constants like `MAC_OS_X_VERSION_10_12`.
|
||||
For example, I have a version of the 10.12 SDK which contains the line
|
||||
|
||||
```cpp
|
||||
#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_12_4
|
||||
```
|
||||
|
||||
The name `MAC_OS_X_VERSION_MAX_ALLOWED` is rather misleading; a better name would be
|
||||
`MAC_OS_X_VERSION_MAX_KNOWN_BY_SDK`. Compiling with an old SDK *does not* prevent apps from running
|
||||
on newer versions of macOS.
|
||||
|
||||
With the help of the `MAC_OS_X_VERSION_MAX_ALLOWED` macro, we can make our code adapt to the SDK that's
|
||||
being used. Here's [an example](https://searchfox.org/mozilla-central/rev/9ad88f80aeedcd3cd7d7f63be07f577861727054/toolkit/xre/MacApplicationDelegate.mm#345-351) where the 10.14 SDK changed the signature of
|
||||
[an `NSApplicationDelegate` method](https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428471-application?language=objc):
|
||||
|
||||
```objc++
|
||||
- (BOOL)application:(NSApplication*)application
|
||||
continueUserActivity:(NSUserActivity*)userActivity
|
||||
#if defined(MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
||||
restorationHandler:(void (^)(NSArray<id<NSUserActivityRestoring>>*))restorationHandler {
|
||||
#else
|
||||
restorationHandler:(void (^)(NSArray*))restorationHandler {
|
||||
#endif
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
We can also use this macro to supply missing API definitions in such a way that
|
||||
they don't conflict with the definitions from the SDK.
|
||||
This is described in the "Using macOS APIs" document, under [Using new APIs with old SDKs](./macos-apis.html#using-new-apis-with-old-sdks).
|
||||
|
||||
## Overriding SDK-dependent runtime behavior
|
||||
|
||||
This section contains some more details on the compatibility tricks that cause different runtime
|
||||
behavior dependent on the SDK, as described in
|
||||
[Runtime differences based on macOS SDK version](#runtime-differences-based-on-macos-sdk-version).
|
||||
|
||||
### How it works
|
||||
|
||||
AppKit is the one system framework I know of that employs these tricks. Let's explore how AppKit makes this work,
|
||||
by going back to the [NSCollectionView example](https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKit/#10_13NSCollectionView%20Responsive%20Scrolling) from above:
|
||||
|
||||
> Responsive Scrolling in NSCollectionViews is enabled only for apps linked on or after macOS 10.13.
|
||||
|
||||
For each of these SDK-dependent behavior differences, both the old and the new behavior are implemented
|
||||
in the version of AppKit that ships with the new macOS version.
|
||||
At runtime, AppKit selects one of the behaviors based on the SDK version, with a call to
|
||||
`_CFExecutableLinkedOnOrAfter()`. This call checks the SDK version of the main executable of the
|
||||
process that's running AppKit code; in our case that's the `firefox` or `plugin-container` executable.
|
||||
The SDK version is stored in the mach-o headers of the executable by the linker.
|
||||
|
||||
One interesting design aspect of AppKit's compatibility tricks is the fact that most of these behavior differences
|
||||
can be toggled with a "user default" preference.
|
||||
For example, the "responsive scrolling in NSCollectionViews" behavior change can be controlled with
|
||||
a user default with the name "NSCollectionViewPrefetchingEnabled".
|
||||
The SDK check only happens if "NSCollectionViewPrefetchingEnabled" is not set to either YES or NO.
|
||||
|
||||
More precisely, this example works as follows:
|
||||
|
||||
- `-[NSCollectionView prepareContentInRect:]` is the function that supports both the old and the new behavior.
|
||||
- It calls `_NSGetBoolAppConfig` for the value "NSCollectionViewPrefetchingEnabled", and also supplies a "default
|
||||
value function".
|
||||
- If the user default is not set, the default value function is called. This function has the name
|
||||
`NSCollectionViewPrefetchingEnabledDefaultValueFunction`.
|
||||
- `NSCollectionViewPrefetchingEnabledDefaultValueFunction` calls `_CFExecutableLinkedOnOrAfter(13)`.
|
||||
|
||||
You can find many similar toggles if you list the AppKit symbols that end in `DefaultValueFunction`,
|
||||
for example by executing `nm /System/Library/Frameworks/AppKit.framework/AppKit | grep DefaultValueFunction`.
|
||||
|
||||
### Overriding SDK-dependent runtime behavior
|
||||
|
||||
You can set these preferences programmatically, in a way that `_NSGetBoolAppConfig()` can pick them up,
|
||||
for example with [`registerDefaults`](https://developer.apple.com/documentation/foundation/nsuserdefaults/1417065-registerdefaults?language=objc)
|
||||
or like this:
|
||||
|
||||
```objc++
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NSViewAllowsRootLayerBacking"];
|
||||
```
|
||||
|
||||
The AppKit release notes mention this ability but ask for it to only be used for debugging purposes:
|
||||
|
||||
> In some cases, we provide defaults (preferences) settings which can be used to get the old or new behavior,
|
||||
> independent of what system an application was built against. Often these preferences are provided for
|
||||
> debugging purposes only; in some cases the preferences can be used to globally modify the behavior
|
||||
> of an application by registering the values (do it somewhere very early, with `-[NSUserDefaults registerDefaults:]`).
|
||||
|
||||
It's interesting that they mention this at all because, as far as I can tell, none of these values are documented.
|
||||
|
|
|
|||
Loading…
Reference in a new issue