You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
bug!("There can never be a SharedReadWrite or a Unique on top of a SharedReadOnly"),
220
-
// When `other` is `SharedReadOnly`, that is NEVER compatible with
221
-
// write accesses.
222
-
// This makes sure read-only pointers become invalid on write accesses (ensures F2a).
223
-
(_, AccessKind::Write, SharedReadOnly) =>
224
-
false,
225
-
// When `other` is `Unique`, that is compatible with nothing.
226
-
// This makes sure unique pointers become invalid on incompatible accesses (ensures U2).
227
-
(_, _, Unique) =>
228
-
false,
229
-
// When we are unique and this is a write/dealloc, we tolerate nothing.
230
-
// This makes sure we re-assert uniqueness ("being on top") on write accesses.
231
-
// (This is particularily important such that when a new mutable ref gets created, it gets
232
-
// pushed onto the right item -- this behaves like a write and we assert uniqueness of the
233
-
// pointer from which this comes, *if* it was a unique pointer.)
234
-
(Unique, AccessKind::Write, _) =>
235
-
false,
236
-
// `SharedReadWrite` items can tolerate any other akin items for any kind of access.
237
-
(SharedReadWrite, _, SharedReadWrite) =>
238
-
true,
239
-
// Any item can tolerate read accesses for shared items.
240
-
// This includes unique items! Reads from unique pointers do not invalidate
241
-
// other pointers.
242
-
(_, AccessKind::Read, SharedReadWrite) |
243
-
(_, AccessKind::Read, SharedReadOnly) =>
244
-
true,
245
-
// That's it.
246
-
}
247
-
}
248
-
```
195
+
In general, the structure of the stack looks as follows:
196
+
On the top, we might have a bunch of `SharedReadOnly` items. Below that, we have "blocks" consisting of either a single `Unique` item, or a bunch of consecutive `SharedReadWrite`.
197
+
`Disabled` items serve to separate two blocks of `SharedReadWrite` that would otherwise be considered one block.
198
+
Using any item within a block is equivalent to using any other item in that same block.
249
199
250
200
### Allocating memory
251
201
@@ -264,51 +214,70 @@ We also initialize the stack of all the memory locations in this new memory allo
264
214
On every memory access, we perform the following extra operation for every location that gets accessed (i.e., for a 4-byte access, this happens for each of the 4 bytes):
265
215
266
216
1. Find the granting item. If there is none, this is UB.
267
-
2. For every item `item` above the granting item in the stack: if the granting item is not compatible with `item`, remove `item` from the stack.
268
-
If furthermore `item` is protected (`item.protector.is_some()`) by an active call, this is UB.
217
+
2. Check if this is a read access or a write access.
218
+
- For write accesses, pop all *blocks* above the one containing the granting item. That is, remove all items above the granting one, except if the granting item is a `SharedReadWrite` in which case the consecutive `SharedReadWrite` above it are kept (but everything beyond is popped).
219
+
- For read accesses, disable all `Unique` items above the granting one: change their permission to `Disabled`. This means they cannot be used any more. We do not remove them from the stack to avoid merging two blocks of `SharedReadWrite`.
269
220
270
221
### Reborrowing
271
222
272
223
Adding new permissions to the stack happens by reborrowing pointers.
273
224
274
225
**Granting a pointer permission to a location.**
275
-
To grant new permissions to a location, we need a parent tag (the tag of the pointer from which the new pointer is derived), an `Item` for the newly created pointer that should be added to the stack (this indicates both which pointer is granted access and what the permission is), and a boolean indicating whether this is a "weak" or a "strong" grant operation.
276
-
As a signature, this would be
226
+
To grant new permissions to a location, we need a parent tag (the tag of the pointer from which the new pointer is derived), and an `Item` for the newly created pointer that should be added to the stack (this indicates both which pointer is granted access and what the permission is).
@@ -341,8 +311,7 @@ For each reference (`&[mut] _`) and box (`Box<_>`) we encounter, and if `kind ==
341
311
1. We compute a fresh tag: `Untagged` for raw pointers, `Tag(Tracking::new_ptr_id())` for everything else.
342
312
2. We determine if we will want to protect the items we are going to generate:
343
313
This is the case only if `kind == FnEntry` and the type of this pointer is a reference (not a box).
344
-
3. We perform reborrowing of the memory this pointer points to with the new tag and indicating whether we want protection, treating boxes as `Unique`. We enforce weak mode if `kind == TwoPhase`.
345
-
4. If `kind == TwoPhase`, we perform *another* reborrow from the *new* place (with the freshly generated tag), with the "new" tag set to the tag of the *old* place and treating it like a shared reference (without protection or forcing weak mode). Basically, we pretend that the old pointer is actually a shared reference derived from the new pointer. This allows reading from the old pointer without invalidating the new one.
314
+
3. We perform reborrowing of the memory this pointer points to with the new tag and indicating whether we want protection, treating boxes as `RefKind::Unique`.
0 commit comments