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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*
* Copyright 2019 The Starlark in Rust Authors.
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use fmt;
use PhantomData;
use Allocative;
use Trace;
use crate as starlark;
use crateProvidesStaticType;
use crateFrozenValue;
use crateValue;
unsafe
unsafe
/// See the documentation on `HeapSendable`
unsafe
/// See the documentation on `HeapSendable`
unsafe
/// A trait for handling the unusual sendness requirements of starlark values.
///
/// Semantically, the send and sync impls in starlark exist in support of the following goals, from
/// more obvious to less obvious:
///
/// 1. Frozen heaps and values should be fully thread safe - parallel starlark evaluations must be
/// able to depend on the same frozen heap.
/// 2. Unfrozen values should support non-thread safe interior mutability such as `RefCell`; in
/// other words, they must support being non-sync.
/// 3. Unfrozen heaps should be sendable. Concretely, it should be possible to hold them over an
/// await point so as to interleave starlark evaluation with other async work.
///
/// Since a `Value<'v>` is semantically a reference to an unfrozen value, an immediate consequence
/// of 2 is that `Value<'v>` cannot `Send`. Given that starlark values need to contain `Value<'v>`s,
/// this makes the third condition weird. However, we achieve soundness by requiring a combination
/// of two properties:
///
/// a. Unfrozen starlark values must be send up to any `Value<'v>` inside them. In other words,
/// they can contain a `Vec<Value<'v>>` or whatever, but not a `Rc<u8>`.
///
/// b. When we send a heap to another thread, we enforce that the heap is sent "in its entirety",
/// ie together with any references into that heap.
///
/// To be able to check these requirements, our heap allocation functions have a signature that
/// looks (slightly simplified) like this:
///
/// ```rust,ignore
/// impl<'v> Heap<'v> {
/// fn alloc(self, x: T) -> Value<'v>
/// where
/// T: StarlarkValue<'v>,
/// T: ProvidesStaticType<'v>,
/// T::StaticType: Send;
/// }
/// ```
///
/// The first trait bound is obvious.
///
/// The `T: ProvidesStaticType<'v>` trait bound says that all lifetimes appearing on `T` must be
/// `'v`. Together with branding, this guarantees that any `Value`s that `T` holds are `Value<'v>`s
/// for the same `'v` that our heap has, ie that the contained values point back into the same heap.
/// This, together with branding on heap access, is how we achieve the second requirement above. It
/// prevents `Value<'v>`s from leaking either out of the heap access closure or into any heap other
/// than the one they're associated with.
///
/// The third impl is how we achieve the first requirement above. As a reminder, we would like to
/// write `T: Send`, but that would prevent users from holding any `Value<'v>` in `T`. So instead,
/// we replace the `T: Send` bound with a combination of the following two things:
///
/// ```rust,ignore
/// // Bound. `T::StaticType` is effectively "`T` with all lifetimes replaced with `'static`
/// T::StaticType: Send;
/// // impl
/// impl Send for Value<'static>;
/// ```
///
/// `T::StaticType`, while not quite equivalent, is *almost* as good as `T: Send`. On the other
/// hand, the `'static` thing together with the impl on `Value` means that it is actually satisfied
/// for a `T` that contains a `Value<'v>`, which is what we want.
/// The sync analogue of `HeapSendable`.
///
/// Mostly see the docs on `HeapSendable`, which is slightly more interesting - this one is just
/// needed on frozen heaps.
/// A helper to pass the send-if-static property through `dyn Trait<'v>`.
///
/// Unfortunately, the property of starlark values that they are send for `'v = 'static` does not
/// cleanly pass through `dyn MyTrait<'v>`; concretely, it's not possible to make `dyn
/// MyTrait<'static>: Send` even if that is true of the underlying concrete type.
///
/// This type acts as a wrapper to recover the send impl; where previously you might've written
///
/// ```rust,ignore
/// trait MyTrait<'v>: Trace {}
///
/// struct MyValue<'v> {
/// field: Box<dyn MyTrait<'v>>,
/// }
/// ```
///
/// Now write instead:
///
/// ```rust,ignore
/// trait MyTrait<'v>: Trace + HeapSendable<'v> {}
///
/// struct MyValue<'v> {
/// field: Box<DynStarlark<dyn MyTrait<'v>>>,
/// }
/// ```
where
T: ?Sized;
// SAFETY: Sealing guarantees that the only impl of `HeapSendable` is the one above, and that impl
// requires this to hold.
unsafe
unsafe
unsafe