1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
namespace runtime {
extern runtime
ShrinkFinalizationRegistryUnregisterTokenMap(
Context, JSFinalizationRegistry): void;
}
namespace weakref {
extern transitioning macro
RemoveFinalizationRegistryCellFromUnregisterTokenMap(
JSFinalizationRegistry, WeakCell): void;
macro SplitOffTail(weakCell: WeakCell): WeakCell|Undefined {
const weakCellTail = weakCell.next;
weakCell.next = Undefined;
typeswitch (weakCellTail) {
case (Undefined): {
}
case (tailIsNowAHead: WeakCell): {
assert(tailIsNowAHead.prev == weakCell);
tailIsNowAHead.prev = Undefined;
}
}
return weakCellTail;
}
transitioning macro
PopClearedCell(finalizationRegistry: JSFinalizationRegistry): WeakCell|
Undefined {
typeswitch (finalizationRegistry.cleared_cells) {
case (Undefined): {
return Undefined;
}
case (weakCell: WeakCell): {
assert(weakCell.prev == Undefined);
finalizationRegistry.cleared_cells = SplitOffTail(weakCell);
// If the WeakCell has an unregister token, remove the cell from the
// unregister token linked lists and and the unregister token from
// key_map. This doesn't shrink key_map, which is done manually after
// the cleanup loop to avoid a runtime call.
if (weakCell.unregister_token != Undefined) {
RemoveFinalizationRegistryCellFromUnregisterTokenMap(
finalizationRegistry, weakCell);
}
return weakCell;
}
}
}
transitioning macro
FinalizationRegistryCleanupLoop(implicit context: Context)(
finalizationRegistry: JSFinalizationRegistry, callback: Callable) {
while (true) {
const weakCellHead = PopClearedCell(finalizationRegistry);
typeswitch (weakCellHead) {
case (Undefined): {
break;
}
case (weakCell: WeakCell): {
try {
Call(context, callback, Undefined, weakCell.holdings);
} catch (e) {
runtime::ShrinkFinalizationRegistryUnregisterTokenMap(
context, finalizationRegistry);
ReThrow(context, e);
}
}
}
}
runtime::ShrinkFinalizationRegistryUnregisterTokenMap(
context, finalizationRegistry);
}
transitioning javascript builtin
FinalizationRegistryPrototypeCleanupSome(
js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
// 1. Let finalizationRegistry be the this value.
//
// 2. Perform ? RequireInternalSlot(finalizationRegistry, [[Cells]]).
const methodName: constexpr string =
'FinalizationRegistry.prototype.cleanupSome';
const finalizationRegistry =
Cast<JSFinalizationRegistry>(receiver) otherwise ThrowTypeError(
MessageTemplate::kIncompatibleMethodReceiver, methodName, receiver);
let callback: Callable;
if (arguments[0] != Undefined) {
// 4. If callback is not undefined and IsCallable(callback) is
// false, throw a TypeError exception.
callback = Cast<Callable>(arguments[0]) otherwise ThrowTypeError(
MessageTemplate::kWeakRefsCleanupMustBeCallable, arguments[0]);
} else {
callback = finalizationRegistry.cleanup;
}
FinalizationRegistryCleanupLoop(finalizationRegistry, callback);
return Undefined;
}
}
|