Coverage Report

Created: 2025-03-04 07:22

/src/serenity/Userland/Libraries/LibJS/Runtime/FinalizationRegistry.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2021-2022, Idan Horowitz <idan.horowitz@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <LibJS/Runtime/AbstractOperations.h>
8
#include <LibJS/Runtime/FinalizationRegistry.h>
9
10
namespace JS {
11
12
JS_DEFINE_ALLOCATOR(FinalizationRegistry);
13
14
FinalizationRegistry::FinalizationRegistry(Realm& realm, NonnullGCPtr<JobCallback> cleanup_callback, Object& prototype)
15
0
    : Object(ConstructWithPrototypeTag::Tag, prototype)
16
0
    , WeakContainer(heap())
17
0
    , m_realm(realm)
18
0
    , m_cleanup_callback(cleanup_callback)
19
0
{
20
0
}
21
22
void FinalizationRegistry::add_finalization_record(Cell& target, Value held_value, Cell* unregister_token)
23
0
{
24
0
    VERIFY(!held_value.is_empty());
25
0
    m_records.append({ &target, held_value, unregister_token });
26
0
}
27
28
// Extracted from FinalizationRegistry.prototype.unregister ( unregisterToken )
29
bool FinalizationRegistry::remove_by_token(Cell& unregister_token)
30
0
{
31
    // 4. Let removed be false.
32
0
    auto removed = false;
33
34
    // 5. For each Record { [[WeakRefTarget]], [[HeldValue]], [[UnregisterToken]] } cell of finalizationRegistry.[[Cells]], do
35
0
    for (auto it = m_records.begin(); it != m_records.end(); ++it) {
36
        //  a. If cell.[[UnregisterToken]] is not empty and SameValue(cell.[[UnregisterToken]], unregisterToken) is true, then
37
0
        if (it->unregister_token == &unregister_token) {
38
            // i. Remove cell from finalizationRegistry.[[Cells]].
39
0
            it.remove(m_records);
40
41
            // ii. Set removed to true.
42
0
            removed = true;
43
0
        }
44
0
    }
45
46
    // 6. Return removed.
47
0
    return removed;
48
0
}
49
50
void FinalizationRegistry::remove_dead_cells(Badge<Heap>)
51
0
{
52
0
    auto any_cells_were_removed = false;
53
0
    for (auto& record : m_records) {
54
0
        if (!record.target || record.target->state() == Cell::State::Live)
55
0
            continue;
56
0
        record.target = nullptr;
57
0
        any_cells_were_removed = true;
58
0
        break;
59
0
    }
60
0
    if (any_cells_were_removed)
61
0
        vm().host_enqueue_finalization_registry_cleanup_job(*this);
62
0
}
63
64
// 9.13 CleanupFinalizationRegistry ( finalizationRegistry ), https://tc39.es/ecma262/#sec-cleanup-finalization-registry
65
ThrowCompletionOr<void> FinalizationRegistry::cleanup(JS::GCPtr<JobCallback> callback)
66
0
{
67
0
    auto& vm = this->vm();
68
69
    // 1. Assert: finalizationRegistry has [[Cells]] and [[CleanupCallback]] internal slots.
70
    // Note: Ensured by type.
71
72
    // 2. Let callback be finalizationRegistry.[[CleanupCallback]].
73
0
    auto cleanup_callback = callback ? callback : m_cleanup_callback;
74
75
    // 3. While finalizationRegistry.[[Cells]] contains a Record cell such that cell.[[WeakRefTarget]] is empty, an implementation may perform the following steps:
76
0
    for (auto it = m_records.begin(); it != m_records.end(); ++it) {
77
        // a. Choose any such cell.
78
0
        if (it->target != nullptr)
79
0
            continue;
80
81
        // b. Remove cell from finalizationRegistry.[[Cells]].
82
0
        MarkedVector<Value> arguments(vm.heap());
83
0
        arguments.append(it->held_value);
84
0
        it.remove(m_records);
85
86
        // c. Perform ? HostCallJobCallback(callback, undefined, « cell.[[HeldValue]] »).
87
0
        TRY(vm.host_call_job_callback(*cleanup_callback, js_undefined(), move(arguments)));
88
0
    }
89
90
    // 4. Return unused.
91
0
    return {};
92
0
}
93
94
void FinalizationRegistry::visit_edges(Cell::Visitor& visitor)
95
0
{
96
0
    Base::visit_edges(visitor);
97
0
    visitor.visit(m_realm);
98
0
    visitor.visit(m_cleanup_callback);
99
0
    for (auto& record : m_records) {
100
0
        visitor.visit(record.held_value);
101
0
        visitor.visit(record.unregister_token);
102
0
    }
103
0
}
104
105
}