Babel preset: Add Hermes V1 native runtime workarounds for hermes#1761#56816
Babel preset: Add Hermes V1 native runtime workarounds for hermes#1761#56816ramonclaudio wants to merge 1 commit into
Conversation
a5fff17 to
b2e38cc
Compare
|
@CalixTang has imported this pull request. If you are a Meta employee, you can view this in D105609206. |
|
Anything I can do to help push this forward @CalixTang? |
b2e38cc to
0b32635
Compare
|
sorry for late response - I don't recall exactly what happened/changed with this PR. Linking another team member onto this. |
0b32635 to
8c26985
Compare
## Summary: Three Babel plugins added to `@react-native/babel-preset` that work around runtime codegen bugs in the bundled Hermes V1 (250829098.0.13, branch cut 2025-08-29) by rewriting source patterns before they reach the engine. Each plugin papers over a different bug that is fixed on Hermes `static_h` but has not been backported to the V1 stable branch (verified absent through the .0.15 stable tip; the only in-flight graft, facebook/hermes#2030, is still open). - `fix-hermes-v1-async-arrow-non-simple-params`: facebook/hermes#1761 (fixed in static_h by 68bfb3a48b31, 2025-09-11). Async arrow functions with destructured, defaulted, or rest parameters silently resolve `await` with `undefined` while the function body continues executing in the background. The plugin rewrites the params to a simple identifier with inline destructuring so Hermes never sees the buggy shape. Gated on `isHermesProfile && preserveAsync` since `plugin-transform-async-to-generator` rewrites the pattern away when `preserveAsync` is false. - `fix-hermes-v1-class-in-finally`: Fixed in static_h by 1e94fbe0ebb4 (2026-02-12). Class declarations inside a `finally` block trip Hermes V1's variable caching path. The plugin wraps them in an IIFE so the class lives in its own scope, and preserves the inferred name of a class expression bound to a plain identifier. - `fix-hermes-v1-super-in-object-accessor`: Fixed in static_h by 18a963465944 (2025-11-04). Object-literal getters and setters using `super.x` trip the `genFunctionExpression` home object path, which segfaults hermesc at compile time. The plugin marks the accessor as computed with a string key, covering identifier, string, and numeric keys. All three gate on `isHermesProfile` and bail out fast on the common case. The plugins are a direct port of work by @kitten (Phil Pluckthun, Expo team) in `babel-preset-expo` (expo/expo#45601, MIT licensed). All plugin design and implementation credit belongs to him. This PR carries his work over to `@react-native/babel-preset` so bare React Native consumers benefit from the same fix. ## Changelog: [GENERAL] [FIXED] - Work around three Hermes V1 source-level codegen bugs in `@react-native/babel-preset` (async-arrow non-simple params, class-in-finally, super-in-object-accessor) ## Test Plan: - 21 inline-snapshot test cases across three new test files verify the transformed output, the fast-bail behavior on irrelevant patterns, and the numeric-key and class-name edge cases. - `yarn jest packages/react-native-babel-preset` clean (76 tests, 27 snapshots). - Full repo `yarn test` clean (278 suites, 5692 tests passed, 1857 snapshots). - `yarn lint`, `yarn format-check`, `yarn flow-check`, `yarn test-typescript`, `yarn featureflags --verify-unchanged`, `yarn build-types --validate` all clean. - Existing `transform-snapshot-test` passes byte-identical: the kitchen-sink fixture has none of the buggy patterns so the new plugins do not change its output for any profile. - Compiled the bug patterns through the bundled compiler (hermes-compiler 250829098.0.14): `get x() { return super.x }` and `get 0() { return super.x }` both segfault hermesc, while the transformed computed-key output compiles clean. - Device repro at ramonclaudio/hermes-1761-repro: 55/55 PASS on iPhone 17 Pro / iOS 26.5 in Debug and Release. ## Caveats: `fix-hermes-v1-class-in-finally` rewrites block-scoped `class` declarations inside `finally` blocks to function-scoped `var` initializers, matching the babel-preset-expo source. Observable only when code in the same `finally` references the class before its declaration or relies on its block scoping (rare). The same plugin shape has shipped in `babel-preset-expo` and Expo SDK 56 without reported regressions, but flagging in case Meta's internal test fleet surfaces an edge case the OSS suite does not catch. ## References: - facebook/hermes#1761 (root-cause issue, fixed in static_h) - facebook/hermes#2030 (in-flight graft of the async-arrow fix onto the V1 stable branch, still open) - expo/expo#45601 (source of the ported plugins, by @kitten) - expo/expo#45592 (user-facing bug report on SDK 56 preview) Co-authored-by: Phil Pluckthun <phil@kitten.sh>
8c26985 to
6377bb8
Compare
No worries. Thank you! @CalixTang |
Why can't we cherry pick those 3 fixes in the |
Yeah this seems strongly preferable to me - @tmikov might have context on whether they're pick-friendly. These are the ones, IIUC (as listed in expo/expo#45601): |
|
Closing this + abandoning D105609206 |
Summary:
Three Babel plugins for
@react-native/babel-presetthat work around live codegen bugs in the bundled Hermes V1 (250829098.0.13). They rewrite the offending source patterns at compile time so Hermes never sees them. Port of @kitten's plugins inbabel-preset-expo(expo/expo#45601, MIT).The three fixes exist on Hermes
static_hbut were never grafted onto the shipped250829098.0.0-stablebranch (absent through the.0.15tip; the only in-flight graft, facebook/hermes#2030, is still open), so the bugs are live on the compiler RN ships. The super-in-object-accessor bug SIGSEGVs hermesc at compile time.Changelog:
[GENERAL] [FIXED] - Work around three Hermes V1 source-level codegen bugs in
@react-native/babel-preset(async-arrow non-simple params, class-in-finally, super-in-object-accessor)Test Plan:
Test repro at ramonclaudio/hermes-1761-repro. 55/55 PASS on iPhone 17 Pro / iOS 26.5 in both Debug and Release; 4 added edge-case tests (numeric-key accessor, class-name preservation) are verified at the compiler level below.
Locally on
packages/react-native-babel-preset:yarn jest packages/react-native-babel-presetclean (76 tests, 27 snapshots).yarn testclean (278 suites, 5692 tests, 1857 snapshots).yarn lint,yarn format-check,yarn flow-check,yarn test-typescript,yarn featureflags --verify-unchanged,yarn build-types --validateall clean.transform-snapshot-testis unchanged: the kitchen-sink fixture has none of the bug patterns so the new plugins don't alter its output.hermes-compiler@250829098.0.14):get x() { return super.x }andget 0() { return super.x }both SIGSEGV hermesc, while the transformed computed-key output compiles clean. A full Metro bundle of the repro (--minify false, the flags RN's Hermes build uses) compiles clean on hermesc for iOS and Android.