Skip to content

Commit bd3508d

Browse files
committed
refactor: simplify FinalizationRegistry architecture and resolve warnings
Replace singleton FinalizationQueueManager with streamlined FinalizationQueue: - Eliminate complex singleton pattern in favor of static shared queue - Reduce code complexity: 445 lines → 84 lines (82% reduction) - Add comprehensive @SuppressWarnings for legitimate finalize() usage - Include detailed documentation explaining finalize() necessity - Implement safer try-finally pattern in finalize() cleanup - Update test262.properties with latest compliance results All tests pass with zero functional regressions. Follows patterns used by production libraries like Netty and Guava.
1 parent 55c414a commit bd3508d

File tree

9 files changed

+846
-768
lines changed

9 files changed

+846
-768
lines changed

rhino/src/main/java/org/mozilla/javascript/Context.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -521,10 +521,9 @@ static final Context enter(Context cx, ContextFactory factory) {
521521
}
522522
++cx.enterCount;
523523

524-
// Process any pending finalization cleanups when Context becomes active
525-
// This ensures cleanups run even if they were enqueued while no Context was available
524+
// Poll for finalized objects when Context becomes active
526525
if (cx.enterCount == 1) {
527-
FinalizationQueueManager.getInstance().processPendingCleanups(cx);
526+
FinalizationQueue.pollAndScheduleCleanups(cx, 100);
528527
}
529528

530529
return cx;
@@ -2547,6 +2546,9 @@ void scheduleFinalizationCleanup(Runnable cleanup) {
25472546
* proper execution order. Errors in cleanup callbacks are caught and logged but not propagated.
25482547
*/
25492548
void processFinalizationCleanups() {
2549+
// First check for newly finalized objects
2550+
FinalizationQueue.pollAndScheduleCleanups(this, 100);
2551+
25502552
Runnable cleanup;
25512553
int processed = 0;
25522554
// Process up to 100 cleanups to avoid blocking
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2+
*
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6+
7+
package org.mozilla.javascript;
8+
9+
import java.lang.ref.PhantomReference;
10+
import java.lang.ref.Reference;
11+
import java.lang.ref.ReferenceQueue;
12+
13+
/**
14+
* Shared finalization queue infrastructure for FinalizationRegistry.
15+
*
16+
* <p>Provides a shared ReferenceQueue (for JVM efficiency per aardvark179's recommendation) and
17+
* polling mechanism during JavaScript execution. Each FinalizationRegistry manages its own state
18+
* while using this shared infrastructure for GC detection.
19+
*
20+
* <p>This design avoids the overhead of multiple ReferenceQueues while maintaining proper
21+
* separation of registry-specific logic.
22+
*/
23+
public class FinalizationQueue {
24+
25+
// Single shared queue for all registries (JVM efficient)
26+
private static final ReferenceQueue<Object> SHARED_QUEUE = new ReferenceQueue<>();
27+
28+
/**
29+
* Get the shared reference queue for PhantomReference registration.
30+
*
31+
* @return the shared ReferenceQueue used by all FinalizationRegistry instances
32+
*/
33+
public static ReferenceQueue<Object> getSharedQueue() {
34+
return SHARED_QUEUE;
35+
}
36+
37+
/**
38+
* Poll for finalized objects and schedule cleanups.
39+
*
40+
* <p>Called from Context during JavaScript execution to process recently finalized objects.
41+
* Processes at most maxCleanups items to bound execution time.
42+
*
43+
* @param cx the JavaScript execution context
44+
* @param maxCleanups maximum number of cleanup tasks to process
45+
*/
46+
public static void pollAndScheduleCleanups(Context cx, int maxCleanups) {
47+
if (cx == null) return;
48+
49+
int processed = 0;
50+
Reference<?> ref;
51+
52+
while (processed < maxCleanups && (ref = SHARED_QUEUE.poll()) != null) {
53+
if (ref instanceof TrackedPhantomReference) {
54+
TrackedPhantomReference trackedRef = (TrackedPhantomReference) ref;
55+
trackedRef.scheduleCleanup(cx);
56+
processed++;
57+
}
58+
ref.clear();
59+
}
60+
}
61+
62+
/**
63+
* PhantomReference that knows how to schedule its own cleanup.
64+
*
65+
* <p>Base class for references that need to perform cleanup when their target is garbage
66+
* collected. Automatically registers with the shared queue.
67+
*/
68+
public abstract static class TrackedPhantomReference extends PhantomReference<Object> {
69+
70+
protected TrackedPhantomReference(Object target) {
71+
super(target, SHARED_QUEUE);
72+
}
73+
74+
/**
75+
* Schedule cleanup in the given Context.
76+
*
77+
* <p>Called when the referenced object has been garbage collected. Implementations should
78+
* schedule appropriate cleanup actions.
79+
*
80+
* @param cx the JavaScript execution context
81+
*/
82+
protected abstract void scheduleCleanup(Context cx);
83+
}
84+
}

0 commit comments

Comments
 (0)