Skip to content

Cherry-pick: Fix class variable caching bugs when class is in finally block#2046

Open
ramonclaudio wants to merge 1 commit into
facebook:250829098.0.0-stablefrom
ramonclaudio:class-in-finally-fix-250829098.0.0-stable
Open

Cherry-pick: Fix class variable caching bugs when class is in finally block#2046
ramonclaudio wants to merge 1 commit into
facebook:250829098.0.0-stablefrom
ramonclaudio:class-in-finally-fix-250829098.0.0-stable

Conversation

@ramonclaudio

Copy link
Copy Markdown
Contributor

Summary

Cherry-pick of 1e94fbe0ebb46d676ff656287e17c58839765e73 from static_h to the 250829098.0.0-stable branch.

A finally block emits its body twice, once for normal flow and once for the exception path. On the second emission, legacy class compilation created fresh internal Variables (class and prototype vars, the instance-element init function, computed field keys, private brands) while cached functions reached via findCompiledEntity still referenced the originals, miscompiling classes declared in finally blocks. The fix caches these in a LegacyClassVars struct keyed by the class AST node (legacyClassVars_) and emits private-brand stores unconditionally.

This landed on static_h after the branch was cut (2025-08-29), so it is missing from the V1 line React Native ships (needed by react/react-native#56816). The stacked typed-class sibling 639e5d6af is intentionally not included: it fixes the Static Hermes typed class path, which standard React Native JS does not exercise. Authored by @tmikov, reviewed internally by @fbmal7.

Test plan

  • Clean cherry-pick, no conflicts. Carries the upstream tests: new test/IRGen/class-static-in-finally.js and test/hermes/class-in-finally.js, a CHECK update to test/IRGen/regress-class-recompiled.js that drops the duplicate ?C1#1, ?C1.prototype#1, <instElemInitFunc:C1>#1 Variables the bug produced, and a brand-store ordering update to test/IRGen/private-properties.js.
  • Built hermes and hermesc from 250829098.0.0-stable (517edaff8): the baseline fails regress-class-recompiled.js and the runtime class-in-finally.js. With this cherry-pick all four bundled tests pass.
  • LIT_FILTER="class-in-finally|regress-class-recompiled|class-static-in-finally" cmake --build build --target check-hermes passes.

Summary:
Finally blocks cause code to be emitted twice: once for normal flow
and once for exception handling. This exposed a class of bugs where
internal Variables created during class compilation were not cached.
On recompilation, new Variables were created, but cached functions
(via findCompiledEntity) still referenced the original Variables,
causing crashes or incorrect behavior.

Fixed issues in genLegacyClassLike:
- classVar, clsPrototypeVar: new Variables created each compilation,
  but cached initializer functions referenced old ones. Caused
  assertion failure: "PutOwn requires object operand".
- instElemInitFuncVar: same issue for instance element initializers.
- Computed field key variables: same issue for computed properties.

Fixed issues in emitPrivateNameDeclarations:
- staticBrand, instanceBrand: Variables for private method brands
  were local variables, not cached. Additionally, brand stores were
  only emitted when creating the Variable (inside getPrivateBrand),
  not on recompilation. This caused "undefined is not a function"
  errors when calling private methods in classes defined in finally
  blocks.

The fix introduces LegacyClassInternalVars to cache all internal
Variables created during legacy class compilation, keyed by the class
AST node. When the same class is compiled multiple times, existing
Variables are reused. For private brands, the stores are now emitted
at the end of emitPrivateNameDeclarations unconditionally, ensuring
they exist in all code paths.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Reviewed By: fbmal7

Differential Revision: D90690547

fbshipit-source-id: abe039ecb6913fe8534faf4a7544a84745991182
(cherry picked from commit 1e94fbe)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed Do not delete this pull request or issue due to inactivity.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant