-
Notifications
You must be signed in to change notification settings - Fork 208
/
weakref.js
119 lines (98 loc) · 3.37 KB
/
weakref.js
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { assert, details as d } from '@agoric/assert';
const { defineProperties } = Object;
/*
* We retain a measure of compatibility with Node.js v12, which does not
* expose WeakRef or FinalizationRegistry (there is a --flag for it, but it's
* * not clear how stable it is). When running on a platform without these *
* tools, vats cannot do GC, and the tools they get will be no-ops. WeakRef
* instances will hold a strong reference, and the FinalizationRegistry will
* never invoke the callbacks.
*
* Modules should do:
*
* import { WeakRef, FinalizationRegistry } from '.../weakref';
*
*/
// TODO We need to migrate this into a ses-level tame-weakref.js, to happen
// as part of `lockdown`. In anticipation, this uses some of the patterns
// followed by the other tamings there.
// Emulate the internal [[WeakRefTarget]] slot. Despite the term "Weak" in the
// "WeakMap" used in the emulation, this map holds the target strongly. The only
// weakness here is that the weakref,target pair can go away together if the
// weakref is not reachable.
const weakRefTarget = new WeakMap();
const FakeWeakRef = function WeakRef(target) {
assert(
new.target !== undefined,
d`WeakRef Constructor requires 'new'`,
TypeError,
);
assert.equal(
Object(target),
target,
d`WeakRef target must be an object`,
TypeError,
);
weakRefTarget.set(this, target);
};
const InertWeakRef = function WeakRef(_target) {
throw new TypeError('Not available');
};
const FakeWeakRefPrototype = {
deref() {
return weakRefTarget.get(this);
},
[Symbol.toStringTag]: 'WeakRef',
};
defineProperties(FakeWeakRef, {
prototype: { value: FakeWeakRefPrototype },
});
const WeakRef = globalThis.WeakRef || FakeWeakRef;
// If there is a real WeakRef constructor, we still make it safe before
// exporting it. Unlike https://github.com/tc39/ecma262/issues/2214
// rather than deleting the `constructor` property, we follow the other
// taming patterns and point it at a throw-only inert one.
defineProperties(WeakRef.prototype, {
constructor: { value: InertWeakRef },
});
harden(WeakRef);
export { WeakRef };
// /////////////////////////////////////////////////////////////////////////////
const FakeFinalizationRegistry = function FinalizationRegistry(
cleanupCallback,
) {
assert(
new.target !== undefined,
d`FinalizationRegistry Constructor requires 'new'`,
TypeError,
);
assert.typeof(
cleanupCallback,
'function',
d`cleanupCallback must be a function`,
);
// fall off the end with an empty instance
};
const InertFinalizationRegistry = function FinalizationRegistry(
_cleanupCallback,
) {
throw new TypeError('Not available');
};
const FakeFinalizationRegistryPrototype = {
register() {},
unregister() {},
[Symbol.toStringTag]: 'FinalizationRegistry',
};
defineProperties(FakeFinalizationRegistry, {
prototype: { value: FakeFinalizationRegistryPrototype },
});
const FinalizationRegistry =
globalThis.FinalizationRegistry || FakeFinalizationRegistry;
// If there is a real FinalizationRegistry constructor, we still make it safe
// before exporting it. Rather than deleting the `constructor` property, we
// follow the other taming patterns and point it at a throw-only inert one.
defineProperties(FinalizationRegistry.prototype, {
constructor: { value: InertFinalizationRegistry },
});
harden(FinalizationRegistry);
export { FinalizationRegistry };