Skip to content

Conversation

@anivar
Copy link
Contributor

@anivar anivar commented Sep 12, 2025

This PR implements the ES2021 WeakRef constructor and prototype, allowing JavaScript code to hold weak references to objects without preventing their garbage collection. This is particularly useful for implementing caches, memoization, and other memory-sensitive patterns.

Changes

The implementation adds a new NativeWeakRef class that provides the WeakRef constructor and its deref() method. The implementation follows the ES2021 specification while also supporting unregistered symbols as weak targets, which is part of the ES2023 symbols-as-weakmap-keys specification.

Key implementation decisions:

  • Uses Java's WeakReference internally for proper garbage collection semantics
  • Follows the same validation patterns as NativeWeakMap for consistency
  • Implements using the LambdaConstructor pattern consistent with other modern Rhino features
  • Properly validates targets according to the CanBeHeldWeakly specification
  • Supports ES2023 feature: unregistered symbols can be held weakly

Testing

Unit tests: All 29 unit tests pass, covering constructor validation, deref behavior, symbol handling, and error cases.

Test262: 25 out of 29 test262 tests pass (86.21% success rate). The 4 failing tests involve advanced edge cases around cross-realm prototype handling and NewTarget customization that don't affect normal usage.

Additionally, this implementation fixes an existing test262 test (Object/seal/seal-weakref.js) that was previously failing.

Technical Notes

The implementation correctly distinguishes between registered and unregistered symbols per ES2023 symbols-as-weakmap-keys specification. Registered symbols (created with Symbol.for()) cannot be held weakly as they lack unique identity, while unregistered symbols can be held weakly. This matches the behavior of WeakMap and WeakSet.

Partially addresses #943 (WeakRef portion - FinalizationRegistry still needs implementation)

- Add NativeWeakRef class implementing ES2021 WeakRef specification
- Support for unregistered symbols as weak targets (ES2023 feature)
- Correctly reject registered symbols (Symbol.for())
- Use Java WeakReference for garbage collection semantics
- Add comprehensive unit tests (29/29 passing, 100% success)
- Register WeakRef constructor in ES6+ language mode
- Add error messages for invalid WeakRef targets
- Auto-generate test262.properties with proper format
- Fix Object.seal test for WeakRef (seal-weakref.js now passes)
- WeakRef passes 25/29 test262 tests (86.21% success rate)

WeakRef allows holding weak references to objects without preventing
their garbage collection, useful for caches and memory-sensitive code.

Key features:
- new WeakRef(target) constructor validates target can be held weakly
- deref() method returns referenced object or undefined if collected
- Follows ES2021 CanBeHeldWeakly abstract operation specification
- Compatible with ES2023 symbols-as-weakmap-keys proposal

Failing test262 tests are related to cross-realm prototype handling and
NewTarget customization, which are advanced edge cases that don't affect
core WeakRef functionality.

Signed-off-by: Anivar A. Aravind <[email protected]>
Fix code formatting issues identified by CI
Copy link
Collaborator

@gbrail gbrail left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks helpful and straightforward -- thanks!

Do you think that you could put a bit of detail in the comments about the four failing test cases? I feel that if we don't address them now (even if they're advanced use cases) we may never get to them, so I'd like to at least see what the possibilities are. Thanks!

@anivar
Copy link
Contributor Author

anivar commented Sep 13, 2025

@gbrail I've analyzed the 4 failing test cases. They all relate to how the constructor handles the newTarget parameter when called through Reflect.construct.

When calling Reflect.construct(WeakRef, [target], newTarget), the spec requires using newTarget's prototype, but LambdaConstructor always uses WeakRef's prototype. This affects cross-realm construction and custom prototypes.

The deref test fails because it should only work on objects that actually went through WeakRef construction, not just objects that inherit from WeakRef.prototype.

These are edge cases used in proxies and polyfills. The core WeakRef functionality works - it properly holds weak references that don't prevent garbage collection." │

Fixing this requires either extending LambdaConstructor to handle newTarget (which would benefit other built-ins too) or implementing WeakRef with a traditional constructor pattern. The current implementation delivers the core WeakRef functionality - weak references that don't prevent garbage collection - which is what most developers need.

anivar added a commit to anivar/rhino that referenced this pull request Sep 21, 2025
…ments

This PR provides a complete implementation of ES2021 memory management features
with ES2023 symbol support, consolidating both WeakRef and FinalizationRegistry.

- Full ES2021 WeakRef implementation with deref() method
- ES2023 symbols-as-weakmap-keys support via canBeHeldWeakly
- Uses Java WeakReference for proper GC semantics
- Supports unregistered symbols as weak targets
- Follows Rhino patterns with realThis and instanceOfWeakRef

- Complete register/unregister methods per ES2021 spec
- Optional cleanupSome() method for synchronous cleanup (server-side use)
- Thread-safe implementation using ConcurrentHashMap
- Java WeakReference with ReferenceQueue for GC tracking
- Supports symbols as unregister tokens (canBeHeldWeakly)
- Proper SameValue comparison using ScriptRuntime.same()

- Uses LambdaConstructor for consistency with other Rhino built-ins
- Follows established Rhino patterns (realThis, instanceof fields)
- Comprehensive error handling with proper error messages
- Symbol.toStringTag support for both constructors
- Proper validation per ECMAScript spec requirements

- Comprehensive test coverage including edge cases
- Internal method tests using reflection (white-box testing)
- Test pass rate: 95% (80/84 tests passing)
- Minor failures in edge cases that don't affect core functionality

- Added cleanupSome() method addressing reviewer feedback
- Enhanced symbol support for ES2023 compatibility
- Better spec compliance with proper validation
- Additional test coverage for internal methods
- Cleaner code following Rhino conventions

Closes mozilla#943 (FinalizationRegistry support)
Supersedes PR mozilla#2074 (WeakRef-only implementation)
@anivar
Copy link
Contributor Author

anivar commented Sep 21, 2025

Closing this PR as WeakRef is now included in PR #2058 along with FinalizationRegistry. The consolidated implementation provides both ES2021 features together with ES2023 symbol support.

@anivar anivar closed this Sep 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants