1# Maintaining V8 in Node.js 2 3## Background 4 5V8 follows the Chromium release schedule. The support horizon for Chromium is 6different compared to the support horizon for Node.js. As a result, Node.js 7needs to support multiple versions of V8 longer than what upstream needs 8to support. V8 branches in Node.js lack of an official maintenance process due 9to a missing LTS supported branch. 10 11This document attempts to outline the current maintenance processes, proposes 12a workflow for maintaining the V8 branches in both Node.js LTS and current 13releases, and discusses how the Node.js and V8 teams at Google can help. 14 15## V8 release schedule 16 17V8 and Chromium follow a 18[roughly 4-week release cadence][ChromiumReleaseCalendar]. At any given time 19there are several V8 branches that are **active**, see the 20[V8 release process](https://v8.dev/docs/release-process). All older branches 21are abandoned and are not maintained by the V8 team. 22 23### V8 merge process overview 24 25The process for backporting bug fixes to active branches is officially 26documented [on the V8 wiki][V8MergingPatching]. The summary of the process is: 27 28* V8 only supports active branches. There is no testing done on any branches 29 older than the current stable/beta/master. 30* A fix needing backport is tagged w/ _merge-request-x.x_ tag. This can be done 31 by anyone interested in getting the fix backported. Issues with this tag are 32 reviewed by the V8 team regularly as candidates for backporting. 33* Fixes need some 'baking time' before they can be approved for backporting. 34 This means waiting a few days to ensure that no issues are detected on the 35 canary/beta builds. 36* Once ready, the issue is tagged w/ _merge-approved-x.x_ and one can do the 37 actual merge by using the scripts on the [wiki page][V8MergingPatching]. 38* Merge requests to an abandoned branch will be rejected. 39* Only bug fixes are accepted for backporting. 40 41## Node.js support requirements 42 43At any given time Node.js needs to be maintaining a few different V8 branches 44for the various Current, LTS, and nightly releases. 45The versions of V8 used in Node.js may have already been 46abandoned by upstream V8. However, Node.js needs to continue supporting 47these branches for many months (Current branches) or several 48years (LTS branches). 49 50## Maintenance process 51 52Once a bug in Node.js has been identified to be caused by V8, the first step is 53to identify the versions of Node.js and V8 affected. The bug may be present in 54multiple different locations, each of which follows a slightly different 55process. 56 57* Unfixed bugs. The bug exists in the V8 master branch. 58* Fixed, but needs backport. The bug may need porting to one or more branches. 59 * Backporting to active branches. 60 * Backporting to abandoned branches. 61* Backports identified by the V8 team. Bugs identified by upstream V8 that we 62 haven't encountered in Node.js yet. 63 64### Unfixed upstream bugs 65 66If the bug can be reproduced on the [Node.js `canary` branch][], Chromium 67canary, or V8 tip-of-tree, and the test case is valid, then the bug needs to be 68fixed upstream first. 69 70* Start by opening a bug upstream using [this template][V8TemplateUpstreamBug]. 71* Make sure to include a link to the corresponding Node.js issue 72 (if one exists). 73* If the fix is simple enough, you may fix it yourself; 74 [contributions][V8Contributing] are welcome. 75* V8's build waterfall tests your change. 76* Once the bug is fixed it may still need backporting, if it exists in other V8 77 branches that are still active or are branches that Node.js cares about. 78 Follow the process for backporting below. 79 80### Backporting to active branches 81 82If the bug exists in any of the active V8 branches, we may need to get the fix 83backported. At any given time, there are [two active branches][V8ActiveBranches] 84(beta and stable) in addition to master. The following steps are needed to 85backport the fix: 86 87* Identify which version of V8 the bug was fixed in. 88* Identify if any active V8 branches still contain the bug: 89* A tracking bug is needed to request a backport. 90 * If there isn't already a V8 bug tracking the fix, open a new merge request 91 bug using this [Node.js specific template][V8TemplateMergeRequest]. 92 * If a bug already exists 93 * Add a reference to the GitHub issue. 94 * Attach _merge-request-x.x_ labels to the bug for any active branches 95 that still contain the bug. 96* Once the merge has been approved, it should be merged using the 97 [merge script documented in the V8 wiki][V8MergingPatching]. Merging requires 98 commit access to the V8 repository. If you don't have commit access you can 99 indicate someone on the V8 team can do the merge for you. 100* It is possible that the merge request may not get approved, for example if it 101 is considered to be a feature or otherwise too risky for V8 stable. In such 102 cases we float the patch on the Node.js side. See the process on 'Backporting 103 to Abandoned branches'. 104* Once the fix has been merged upstream, it can be picked up during an update of 105 the V8 branch (see below). 106 107### Backporting to abandoned branches 108 109Abandoned V8 branches are supported in the Node.js repository. The fix needs 110to be cherry-picked in the Node.js repository and V8-CI must test the change. 111 112As an example for how to backport changes, consider the bug 113[RegExp show inconsistent result with other browsers](https://crbug.com/v8/5199). 114From the bug we can see that it was merged by V8 into 5.2 and 5.3, and not into 115V8 5.1 (since it was already abandoned). Since Node.js `v6.x` uses V8 5.1, the 116fix needed to be backported. 117 118#### Backporting with `git-node` (recommended) 119 120You can use [`git-node`][] to help you backport patches. This removes 121some manual steps and is recommended. 122 123Here are the steps for the bug mentioned above: 124 1251. Install `git-node` by installing [`node-core-utils`][]. 1262. Install the prerequisites for [`git-node-v8`][]. 1273. Find the commit hash linked-to in the issue (in this case a51f429). 1284. Checkout a branch off the appropriate _vY.x-staging_ branch (e.g. 129 _v6.x-staging_ to fix an issue in V8 5.1). 1305. Run `git node v8 backport a51f429`. 1316. If there are conflicts, `git-node` will wait for you to resolve them: 132 133```console 134$ git node v8 backport a51f429 135✔ Update local V8 clone 136❯ V8 commit backport 137 ✔ Get current V8 version 138 ✔ Generate patches 139 ❯ Apply and commit patches to deps/v8 140 ❯ Commit a51f429772d1 141 ⠏ Apply patch 142 ◼ Increment embedder version number 143 ◼ Commit patch 144 145? Resolve merge conflicts and enter 'RESOLVED' ‣ 146``` 147 148Resolve conflicts, stage the files (you may need to open another terminal or use 149a GUI git client), then return to the terminal running `git-node`, type 150`RESOLVED`, and hit <kbd>Enter</kbd>. 151 1527. After you resolve conflicts (or if there are no conflicts), the 153 output should look like this: 154 155```console 156$ git node v8 backport a51f429 157✔ Update local V8 clone 158✔ V8 commit backport 159``` 160 1618. Open a PR against the v6.x-staging branch in the Node.js repository. 162 Launch the normal and [V8 CI][] using the Node.js CI system. We only 163 needed to backport to v6.x as the other LTS branches weren't affected 164 by this bug. 165 166See [`git-node-v8-backport`][] for more documentation and additional options. 167 168#### Backporting manually 169 170* For each abandoned V8 branch corresponding to an LTS branch that is affected 171 by the bug: 172 * Checkout a branch off the appropriate _vY.x-staging_ branch (e.g. 173 _v6.x-staging_ to fix an issue in V8 5.1). 174 * Cherry-pick the commit(s) from the V8 repository. 175 * Increase the `v8_embedder_string` number in `common.gypi`. 176 * In some cases the patch may require extra effort to merge in case V8 has 177 changed substantially. For important issues, we may be able to lean on the 178 V8 team to get help with reimplementing the patch. 179 * Open a cherry-pick pull request on `nodejs/node` targeting the 180 _vY.x-staging_ branch and notify the `@nodejs/v8` team. 181 * Run the Node.js [V8 CI][] in addition to the [Node.js CI][]. 182 The CI uses the `test-v8` target in the `Makefile`, which uses 183 `tools/make-v8.sh` to reconstruct a git tree in the `deps/v8` directory to 184 run V8 tests.[^1] 185 186Here are the steps for the bug mentioned above: 187 188* Download and apply the commit linked-to in the issue (in this case a51f429): 189 190 ```console 191 curl -L https://github.com/v8/v8/commit/a51f429.patch | git am -3 --directory=deps/v8 192 ``` 193 194 If the branches have diverged significantly, this may not apply cleanly. It 195 may help to try to cherry-pick the merge to the oldest branch that was done 196 upstream in V8. In this example, this would be the patch from the merge to 197 5.2. The hope is that this would be closer to the V8 5.1, and has a better 198 chance of applying cleanly. 199* Modify the commit message to match the format we use for V8 backports and 200 replace yourself as the author. `git commit --amend --reset-author`. You may 201 want to add extra description if necessary to indicate the impact of the fix 202 on Node.js. In this case the original issue was descriptive enough. Example: 203 204```console 205deps: cherry-pick a51f429 from V8 upstream 206 207Original commit message: 208 [regexp] Fix case-insensitive matching for one-byte subjects. 209 210 The bug occurs because we do not canonicalize character class ranges 211 before adding case equivalents. While adding case equivalents, we abort 212 early for one-byte subject strings, assuming that the ranges are sorted. 213 Which they are not. 214 215 R=marja@chromium.org 216 BUG=v8:5199 217 218 Review-Url: https://codereview.chromium.org/2159683002 219 Cr-Commit-Position: refs/heads/master@{#37833} 220 221Refs: https://github.com/v8/v8/commit/a51f429772d1e796744244128c9feeab4c26a854 222PR-URL: https://github.com/nodejs/node/pull/7833 223``` 224 225* Increase the `v8_embedder_string` number in `common.gypi`. 226* Open a PR against the `v6.x-staging` branch in the Node.js repository. Launch 227 the normal and [V8 CI][] using the Node.js CI system. We only needed to 228 backport to `v6.x` as the other LTS branches weren't affected by this bug. 229 230### Backports identified by the V8 team 231 232For bugs found through the browser or other channels, the V8 team marks bugs 233that might be applicable to the abandoned branches in use by Node.js. This is 234done through manual tagging by the V8 team and through an automated process that 235tags any fix that gets backported to the stable branch (as it is likely 236candidate for backporting further). 237 238Such fixes are tagged with the following labels in the V8 issue tracker: 239 240* `NodeJS-Backport-Review` ([V8][NodeJS-Backport-Review-V8], 241 [Chromium][NodeJS-Backport-Review-Chromium]): to be reviewed if this is 242 applicable to abandoned branches in use by Node.js. This list if regularly 243 reviewed by the Node.js team at Google to determine applicability to Node.js. 244* `NodeJS-Backport-Approved` ([V8][NodeJS-Backport-Approved-V8], 245 [Chromium][NodeJS-Backport-Approved-Chromium]): marks bugs that are deemed 246 relevant to Node.js and should be backported. 247* `NodeJS-Backport-Done` ([V8][NodeJS-Backport-Done-V8], 248 [Chromium][NodeJS-Backport-Done-Chromium]): Backport for Node.js has been 249 performed already. 250* `NodeJS-Backport-Rejected` ([V8][NodeJS-Backport-Rejected-V8], 251 [Chromium][NodeJS-Backport-Rejected-Chromium]): Backport for Node.js is not 252 desired. 253 254The backlog of issues with such is regularly reviewed by the node-team at Google 255to shepherd through the backport process. External contributors are welcome to 256collaborate on the backport process as well. Some of the bugs may be 257security issues and will not be visible to external collaborators. 258 259## Updating V8 260 261Node.js keeps a vendored copy of V8 inside of the deps/ directory. In addition, 262Node.js may need to float patches that do not exist upstream. This means that 263some care may need to be taken to update the vendored copy of V8. 264 265V8 builds against the version of ICU supplied by Node.js, 266see [maintaining-icu.md](./maintaining-icu.md) for special considerations. 267Specifically, a V8 update may necessitate an ICU update. 268 269### Minor updates (patch level) 270 271Because there may be floating patches on the version of V8 in Node.js, it is 272safest to apply the patch level updates as a patch. For example, imagine that 273upstream V8 is at 5.0.71.47 and Node.js is at 5.0.71.32. It would be best to 274compute the diff between these tags on the V8 repository, and then apply that 275patch on the copy of V8 in Node.js. This should preserve the patches/backports 276that Node.js may be floating (or else cause a merge conflict). 277 278#### Applying minor updates with `git-node` (recommended) 279 2801. Install [`git-node`][] by installing [`node-core-utils`][]. 2812. Install the prerequisites for [`git-node-v8`][]. 2823. Run `git node v8 minor` to apply a minor update. 283 284See [`git-node-v8-minor`][] for more documentation and additional options. 285 286#### Applying minor updates manually 287 288The rough outline of the process is: 289 290```bash 291# Assuming your fork of Node.js is checked out in $NODE_DIR 292# and you want to update the Node.js main branch. 293# Find the current (OLD) version in 294# $NODE_DIR/deps/v8/include/v8-version.h 295cd $NODE_DIR 296git checkout main 297git merge --ff-only origin/main 298git checkout -b V8_NEW_VERSION 299curl -L https://github.com/v8/v8/compare/${V8_OLD_VERSION}...${V8_NEW_VERSION}.patch | git apply --directory=deps/v8 300# You may want to amend the commit message to describe the nature of the update 301``` 302 303V8 also keeps tags of the form _5.4-lkgr_ which point to the _Last Known Good 304Revision_ from the 5.4 branch that can be useful in the update process above. 305 306### Major updates 307 308We upgrade the version of V8 in Node.js `main` whenever a V8 release goes stable 309upstream, that is, whenever a new release of Chrome comes out. 310 311Upgrading major versions would be much harder to do with the patch mechanism 312above. A better strategy is to 313 3141. Audit the current `main` branch and look at the patches that have been 315 floated since the last major V8 update. 3162. Replace the copy of V8 in Node.js with a fresh checkout of the latest stable 317 V8 branch. Special care must be taken to recursively update the DEPS that V8 318 has a compile time dependency on (at the moment of this writing, these are 319 only trace\_event and gtest\_prod.h) 3203. Reset the `v8_embedder_string` variable to "-node.0" in `common.gypi`. 3214. Refloat (cherry-pick) all the patches from list computed in 1) as necessary. 322 Some of the patches may no longer be necessary. 323 324To audit for floating patches: 325 326```bash 327git log --oneline deps/v8 328``` 329 330To replace the copy of V8 in Node.js, use the [`git-node`][] tool. For example, 331if you want to replace the copy of V8 in Node.js with the branch-head for V8 5.1 332branch: 333 334```bash 335cd $NODE_DIR 336git node v8 major --branch=5.1-lkgr 337``` 338 339This should be followed up with manual refloating of all relevant patches. 340 341## Proposal: Using a fork repository to track upstream V8 342 343The fact that Node.js keeps a vendored, potentially edited copy of V8 in deps/ 344makes the above processes a bit complicated. An alternative proposal would be to 345create a fork of V8 at `nodejs/v8` that would be used to maintain the V8 346branches. This has several benefits: 347 348* The process to update the version of V8 in Node.js could be automated to track 349 the tips of various V8 branches in `nodejs/v8`. 350* It would simplify cherry-picking and porting of fixes between branches as the 351 version bumps in `v8-version.h` would happen as part of this update instead of 352 on every change. 353* It would simplify the V8-CI and make it more automatable. 354* The history of the V8 branch in `nodejs/v8` becomes purer and it would make it 355 easier to pull in the V8 team for help with reviewing. 356* It would make it simpler to setup an automated build that tracks Node.js 357 `main` + V8 lkgr integration build. 358 359This would require some tooling to: 360 361* A script that would update the V8 in a specific Node.js branch with V8 from 362 upstream (dependent on branch abandoned vs. active). 363* We need a script to bump V8 version numbers when a new version of V8 is 364 promoted from `nodejs/v8` to `nodejs/node`. 365* Enabled the V8-CI build in Jenkins to build from the `nodejs/v8` fork. 366 367[^1]: On macOS, the V8 tests require a full Xcode install, not just the "command 368 line tools" for Xcode. 369 370[ChromiumReleaseCalendar]: https://www.chromium.org/developers/calendar 371[Node.js CI]: https://ci.nodejs.org/job/node-test-pull-request/ 372[Node.js `canary` branch]: https://github.com/nodejs/node-v8/tree/canary 373[NodeJS-Backport-Approved-Chromium]: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=label%3ANodeJS-Backport-Approved 374[NodeJS-Backport-Approved-V8]: https://bugs.chromium.org/p/v8/issues/list?can=1&q=label%3ANodeJS-Backport-Approved 375[NodeJS-Backport-Done-Chromium]: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=label%3ANodeJS-Backport-Done 376[NodeJS-Backport-Done-V8]: https://bugs.chromium.org/p/v8/issues/list?can=1&q=label%3ANodeJS-Backport-Done 377[NodeJS-Backport-Rejected-Chromium]: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=label%3ANodeJS-Backport-Rejected 378[NodeJS-Backport-Rejected-V8]: https://bugs.chromium.org/p/v8/issues/list?can=1&q=label%3ANodeJS-Backport-Rejected 379[NodeJS-Backport-Review-Chromium]: https://bugs.chromium.org/p/chromium/issues/list?can=1&q=label%3ANodeJS-Backport-Review 380[NodeJS-Backport-Review-V8]: https://bugs.chromium.org/p/v8/issues/list?can=1&q=label%3ANodeJS-Backport-Review 381[V8 CI]: https://ci.nodejs.org/job/node-test-commit-v8-linux/ 382[V8ActiveBranches]: https://build.chromium.org/p/client.v8.branches/console 383[V8Contributing]: https://v8.dev/docs/contribute 384[V8MergingPatching]: https://v8.dev/docs/merge-patch 385[V8TemplateMergeRequest]: https://bugs.chromium.org/p/v8/issues/entry?template=Node.js%20merge%20request 386[V8TemplateUpstreamBug]: https://bugs.chromium.org/p/v8/issues/entry?template=Node.js%20upstream%20bug 387[`git-node-v8-backport`]: https://github.com/nodejs/node-core-utils/blob/main/docs/git-node.md#git-node-v8-backport-sha 388[`git-node-v8-minor`]: https://github.com/nodejs/node-core-utils/blob/main/docs/git-node.md#git-node-v8-minor 389[`git-node-v8`]: https://github.com/nodejs/node-core-utils/blob/HEAD/docs/git-node.md#git-node-v8 390[`git-node`]: https://github.com/nodejs/node-core-utils/blob/HEAD/docs/git-node.md#git-node-v8 391[`node-core-utils`]: https://github.com/nodejs/node-core-utils#Install 392