• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 */
16
17class WeakRefPool {
18  // map objects -> weakrefs
19  private static wmap_ = new WeakMap();
20  // map weakref -> Map<tag, gc-callback>
21  private static fmap_ = new Map();
22  //
23  private static freg_ = new FinalizationRegistry((weakRef: WeakRef<object>) => {
24    WeakRefPool.getTaggedCallbacks(weakRef).forEach(fn => fn());
25    WeakRefPool.fmap_.delete(weakRef);
26  });
27
28  // Create a WeakRef for the given object and put it into the pool, or get
29  // existing WeakRef from the pool if the object is already there. WeakRefs
30  // for the same object are always identical.
31  public static get<T extends object>(obj: T): WeakRef<T>
32  {
33    let weakRef = WeakRefPool.wmap_.get(obj);
34    if (weakRef === undefined) {
35      WeakRefPool.wmap_.set(obj, weakRef = new WeakRef(obj));
36    }
37    return weakRef;
38  }
39
40  // Add handler to track when the given object is GC'ed.
41  // Tag is used by unregister() only. Pair <obj, tag> should be unique per callback
42  public static register<T extends object>(obj: T, tag: unknown, callback: () => void): void {
43    const weakRef = WeakRefPool.get(obj);
44    const tagMap = WeakRefPool.getTaggedCallbacks(weakRef);
45    tagMap.size || WeakRefPool.freg_.register(obj, weakRef);
46    tagMap.set(tag, callback);
47  }
48
49  public static unregister<T extends object>(obj: T, tag: unknown): void {
50    const weakRef = WeakRefPool.get(obj);
51    const tagMap = WeakRefPool.getTaggedCallbacks(weakRef);
52    tagMap.delete(tag);
53    tagMap.size || WeakRefPool.freg_.unregister(weakRef);
54    tagMap.size || WeakRefPool.fmap_.delete(weakRef);
55  }
56
57  private static getTaggedCallbacks<T extends object>(weakRef: WeakRef<T>): Map<unknown, () => void> {
58    let tagMap = WeakRefPool.fmap_.get(weakRef);
59    if (tagMap === undefined) {
60      WeakRefPool.fmap_.set(weakRef, tagMap = new Map());
61    }
62    return tagMap;
63  }
64
65  // debug only
66  private static getTaggedCallbacksSize(): number {
67    let size = 0;
68    WeakRefPool.fmap_.forEach(tagMap => size += tagMap.size);
69    return size;
70  }
71}