You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit ca95277
Browse filesBrowse the repository at this point in the historyBrowse files
Babel preset: Remove regenerator from Hermes dev builds (#59390)
Summary:
(This is a re-land of #59303.)
## Motivation
- Dev/release consistency in correctness and performance shape.
- ~10% faster dev cold builds
- More responsive dev apps (~2x faster promise handling)
- Improved debugging support
Since #52651, Hermes profiles have lowered generators (with `enableBabelRuntime: false`), `for...of`, `?.`, `??` and optional catch binding in dev builds only, because Hermes couldn't show local variables when paused on a breakpoint in a native generator.
That turned out to be a Hermes bug: a breakpoint on that a `yield` line resolved to scope-less entry code before the body had even run. It was fixed in meta/hermes@d1238c8 (hermes-v260318099.0.2), which main has used since #58397.
This removes `enableRegenerator`, so Hermes-profile dev output matches release. It also fixes a dev-only divergence - loose `for-of` never calls `iterator.return()`, so breaking out of a `for...of` over a generator skipped its `finally` in dev but not release.
Note that with the default `enableBabelRuntime`, generators were already native in dev, so in practice the generator change mostly affects `enableBabelRuntime: false` setups, including RN's own Jest. (There's no good reason generator was ever conditional on `enableBabelRuntime === false` - it seems to date from #44668 and probably a misunderstanding of what the `regenerator` argument to `babel/plugin-transform-runtime` did - it doesn't make that plugin transform generators, it just rewrites the helper import.)
Native generator debugging still isn't perfect on .0.2 - stepping through `try`/`catch` can stop on a `catch` line that doesn't run, and breakpoints on `yield*` lines or on a `throw` after a resume don't fire. Those already affect every default config though, so there's no regression in most cases. Regenerator has its own problems, eg breakpoints often stop a line early because statements merge into its `case` blocks. Overall, native is now a better experience.
Detailed comparison in https://robhogan.github.io/reports/react-native-regenerator-removal/
## Changelog
[GENERAL] [FIXED] - Babel preset: Hermes profiles no longer lower generators, `for...of`, optional chaining, nullish coalescing or optional catch binding in dev, matching release
Pull Request resolved: #59390
Test Plan:
Reproduced the original bug through Hermes's `CDPAgent` test harness with `Debugger.setBreakpointByUrl`. On hermes-v250829098.0.16 and v260318099.0.1, a breakpoint on a generator's last `yield` line pauses at the generator call with only the global scope, and every local evaluates to `undefined`. On v260318099.0.2 and .0.4 it pauses at the real code with all locals.
AI-driven breakpoint sweep: this preset with `dev: true, enableBabelRuntime: false`, before and after this change, over 248 source lines of generator, async function, async generator, exception and loop fixtures. A breakpoint was set on every line, each pause was mapped back through the source map, and every local was evaluated. Same results with eager and lazy compilation.
| Hermes | Identical | Different, equivalent | Native better | Native worse | Mixed (loop headers) | Total |
| --- | --- | --- | --- | --- | --- | --- |
| 250829098.0.16 | 164 | 10 | 49 | 22 | 3 | 248 |
| 260318099.0.2 | 183 | 11 | 47 | 3 | 3 | 247 |
| 260318099.0.4 | 184 | 11 | 47 | 3 | 3 | 248 |
Local validation:
- `js1 test xplat/js/react-native-github/packages/react-native-babel-preset xplat/js/react-native-github/scripts/releases/__tests__/set-version-test.js --runInBand --skipFilter`: 8 suites, 134 tests and 54 snapshots passed.
- `js1 test xplat/js/scripts/rn-native-modules/__tests__/findTurboModules-test.js --runInBand --skipFilter`: 14 tests passed across development and minified release bundles. Covers optional access, optional calls, both combined, `get` and `getEnforcing`; development also covers namespace imports and CommonJS. With the original scanner, all six added optional development cases failed while the ordinary-call control passed.
- `arc lint -a`: no lint issues.
- Independent expert review: no blockers.
- `buck2 build fbsource//fbandroid/apps/oculus/twilight:twilight_arm64_debug-turbomodule-check fbsource//fbandroid/apps/oculus/twilight:twilight_x86_debug-turbomodule-check @//xplat/mode/hermes/disable_dev_assert @//fbandroid/mode/legacy_apk`: BUILD SUCCEEDED (exit 0). https://www.internalfb.com/buck2/c5b626d6-0feb-4560-958d-87e1e2c54824
- `buck2 build fbsource//fbobjc/Apps/Oculus/Twilight:Twilight-turbomodule-plugin-assertion @//fbobjc/mode/buck2/linux @//xplat/mode/hermes/disable_dev_assert @//fbobjc/mode/twilight-hsr-native -c apple.dry_run_code_signing=true`: BUILD SUCCEEDED (exit 0). https://www.internalfb.com/buck2/fae8c6c0-e740-41ec-9f81-a6f202d9a2aa
- CodeSync export of draft 456916329 was blocked: the linked PR #59390 belongs to a different author, and CodeSync only permits that PR owner to export it. Export job: https://www.internalfb.com/intern/sandcastle/job/49539596691166518. The existing PR was not unlinked or replaced. Other draft CI remains in progress; no claim of full CI success.
Reviewed By: andrewdacenko
Differential Revision: D127195443
Pulled By: javache
fbshipit-source-id: dd0a115bc8e8306f4800b67800a038141e477ff6
function_createForOfIteratorHelperLoose(r,e){vart="undefined"!=typeofSymbol&&r[Symbol.iterator]||r["@@iterator"];if(t)return(t=t.call(r)).next.bind(t);if(Array.isArray(r)||(t=_unsupportedIterableToArray(r))||e&&r&&"number"==typeofr.length){t&&(r=t);varo=0;returnfunction(){returno>=r.length ? {done: !0} : {done: !1,value: r[o++]};};}thrownewTypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");}
function_createForOfIteratorHelperLoose(r,e){vart="undefined"!=typeofSymbol&&r[Symbol.iterator]||r["@@iterator"];if(t)return(t=t.call(r)).next.bind(t);if(Array.isArray(r)||(t=_unsupportedIterableToArray(r))||e&&r&&"number"==typeofr.length){t&&(r=t);varo=0;returnfunction(){returno>=r.length ? {done: !0} : {done: !1,value: r[o++]};};}thrownewTypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");}
Copy file name to clipboardExpand all lines: packages/react-native-babel-preset/src/__tests__/__fixtures__/output/hermes-stable-dev-preserve-block-scoping.js
+5-10Lines changed: 5 additions & 10 deletions
Original file line number
Diff line number
Diff line change
@@ -53,9 +53,6 @@ var _dataUtils = require("./data-utils");
function_createForOfIteratorHelperLoose(r,e){vart="undefined"!=typeofSymbol&&r[Symbol.iterator]||r["@@iterator"];if(t)return(t=t.call(r)).next.bind(t);if(Array.isArray(r)||(t=_unsupportedIterableToArray(r))||e&&r&&"number"==typeofr.length){t&&(r=t);varo=0;returnfunction(){returno>=r.length ? {done: !0} : {done: !1,value: r[o++]};};}thrownewTypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");}
0 commit comments