niko discussion affects

pull/10/head
Alexis Beingessner 10 years ago committed by Manish Goregaokar
parent d8cbd14d6e
commit c868318ec7

@ -24,7 +24,7 @@ do exactly what we said but, you know, *fast*. Wouldn't that be great?
# Compiler Reordering # Compiler Reordering
Compilers fundamentally want to be able to do all sorts of crazy transformations Compilers fundamentally want to be able to do all sorts of crazy transformations
to reduce data dependencies and eleminate dead code. In particular, they may to reduce data dependencies and eliminate dead code. In particular, they may
radically change the actual order of events, or make events never occur! If we radically change the actual order of events, or make events never occur! If we
write something like write something like

@ -25,14 +25,16 @@ as its direct children. Each variable's direct children would be their fields
From this view, every value in Rust has a unique *path* in the tree of ownership. From this view, every value in Rust has a unique *path* in the tree of ownership.
References to a value can subsequently be interpreted as a path in this tree. References to a value can subsequently be interpreted as a path in this tree.
Of particular interest are *prefixes*: `x` is a prefix of `y` if `x` owns `y` Of particular interest are *ancestors* and *descendants*: if `x` owns `y`, then
`x` is an *ancestor* of `y`, and `y` is a *descendant* of `x`. Note that this is
an inclusive relationship: `x` is a descendant and ancestor of itself.
However much data doesn't reside on the stack, and we must also accommodate this. Tragically, plenty of data doesn't reside on the stack, and we must also accommodate this.
Globals and thread-locals are simple enough to model as residing at the bottom Globals and thread-locals are simple enough to model as residing at the bottom
of the stack (though we must be careful with mutable globals). Data on of the stack (though we must be careful with mutable globals). Data on
the heap poses a different problem. the heap poses a different problem.
If all Rust had on the heap was data uniquely by a pointer on the stack, If all Rust had on the heap was data uniquely owned by a pointer on the stack,
then we can just treat that pointer as a struct that owns the value on then we can just treat that pointer as a struct that owns the value on
the heap. Box, Vec, String, and HashMap, are examples of types which uniquely the heap. Box, Vec, String, and HashMap, are examples of types which uniquely
own data on the heap. own data on the heap.
@ -51,6 +53,10 @@ types provide exclusive access through runtime restrictions. However it is also
possible to establish unique ownership without interior mutability. For instance, possible to establish unique ownership without interior mutability. For instance,
if an Rc has refcount 1, then it is safe to mutate or move its internals. if an Rc has refcount 1, then it is safe to mutate or move its internals.
In order to correctly communicate to the type system that a variable or field of
a struct can have interior mutability, it must be wrapped in an UnsafeCell. This
does not in itself make it safe to perform interior mutability operations on that
value. You still must yourself ensure that mutual exclusion is upheld.
@ -61,9 +67,9 @@ dereferenced. Shared references are always live unless they are literally unreac
(for instance, they reside in freed or leaked memory). Mutable references can be (for instance, they reside in freed or leaked memory). Mutable references can be
reachable but *not* live through the process of *reborrowing*. reachable but *not* live through the process of *reborrowing*.
A mutable reference can be reborrowed to either a shared or mutable reference. A mutable reference can be reborrowed to either a shared or mutable reference to
Further, the reborrow can produce exactly the same reference, or point to a one of its descendants. A reborrowed reference will only be live again once all
path it is a prefix of. For instance, a mutable reference can be reborrowed reborrows derived from it expire. For instance, a mutable reference can be reborrowed
to point to a field of its referent: to point to a field of its referent:
```rust ```rust
@ -79,7 +85,7 @@ let x = &mut (1, 2);
``` ```
It is also possible to reborrow into *multiple* mutable references, as long as It is also possible to reborrow into *multiple* mutable references, as long as
they are *disjoint*: no reference is a prefix of another. Rust they are *disjoint*: no reference is an ancestor of another. Rust
explicitly enables this to be done with disjoint struct fields, because explicitly enables this to be done with disjoint struct fields, because
disjointness can be statically proven: disjointness can be statically proven:
@ -89,6 +95,7 @@ let x = &mut (1, 2);
// reborrow x to two disjoint subfields // reborrow x to two disjoint subfields
let y = &mut x.0; let y = &mut x.0;
let z = &mut x.1; let z = &mut x.1;
// y and z are now live, but x isn't // y and z are now live, but x isn't
*y = 3; *y = 3;
*z = 4; *z = 4;
@ -105,14 +112,14 @@ To simplify things, we can model variables as a fake type of reference: *owned*
references. Owned references have much the same semantics as mutable references: references. Owned references have much the same semantics as mutable references:
they can be re-borrowed in a mutable or shared manner, which makes them no longer they can be re-borrowed in a mutable or shared manner, which makes them no longer
live. Live owned references have the unique property that they can be moved live. Live owned references have the unique property that they can be moved
out of (though mutable references *can* be swapped out of). This is out of (though mutable references *can* be swapped out of). This power is
only given to *live* owned references because moving its referent would of only given to *live* owned references because moving its referent would of
course invalidate all outstanding references prematurely. course invalidate all outstanding references prematurely.
As a local lint against inappropriate mutation, only variables that are marked As a local lint against inappropriate mutation, only variables that are marked
as `mut` can be borrowed mutably. as `mut` can be borrowed mutably.
It is also interesting to note that Box behaves exactly like an owned It is interesting to note that Box behaves exactly like an owned
reference. It can be moved out of, and Rust understands it sufficiently to reference. It can be moved out of, and Rust understands it sufficiently to
reason about its paths like a normal variable. reason about its paths like a normal variable.
@ -123,8 +130,12 @@ reason about its paths like a normal variable.
With liveness and paths defined, we can now properly define *aliasing*: With liveness and paths defined, we can now properly define *aliasing*:
**A mutable reference is aliased if there exists another live reference to it or **A mutable reference is aliased if there exists another live reference to one of
one of its prefixes.** its ancestors or descendants.**
(If you prefer, you may also say the two live references alias *each other*.
This has no semantic consequences, but is probably a more useful notion when
verifying the soundness of a construct.)
That's it. Super simple right? Except for the fact that it took us two pages That's it. Super simple right? Except for the fact that it took us two pages
to define all of the terms in that defintion. You know: Super. Simple. to define all of the terms in that defintion. You know: Super. Simple.

Loading…
Cancel
Save