Update Compiler Explorer links

case-study-borrow-checker
Bradlee Speice 2019-02-02 18:15:15 -05:00
parent 2f702ebbc5
commit 763ffb4cb9
1 changed files with 17 additions and 19 deletions

View File

@ -88,7 +88,7 @@ Now let's address some conditions and caveats before going much further:
([`malloc`](https://www.tutorialspoint.com/c_standard_library/c_function_malloc.htm)) that we'll ignore. ([`malloc`](https://www.tutorialspoint.com/c_standard_library/c_function_malloc.htm)) that we'll ignore.
- We'll assume a "debug" build of Rust code (what you get with `cargo run` and `cargo test`) - We'll assume a "debug" build of Rust code (what you get with `cargo run` and `cargo test`)
and address (pun intended) release mode at the end (`cargo run --release` and `cargo test --release`). and address (pun intended) release mode at the end (`cargo run --release` and `cargo test --release`).
- All content will be run using Rust 1.31, as that's the highest currently supported in the - All content will be run using Rust 1.32, as that's the highest currently supported in the
[Compiler Exporer](https://godbolt.org/). As such, we'll avoid upcoming innovations like [Compiler Exporer](https://godbolt.org/). As such, we'll avoid upcoming innovations like
[compile-time evaluation of `static`](https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md) [compile-time evaluation of `static`](https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md)
that are available in nightly. that are available in nightly.
@ -214,7 +214,7 @@ pub fn multiply(value: u32) -> u32 {
value * (*CELL.get_mut()) value * (*CELL.get_mut())
} }
``` ```
-- [Compiler Explorer](https://godbolt.org/z/ZMjmdM) -- [Compiler Explorer](https://godbolt.org/z/2KXUcN)
The compiler only creates one `RefCell`, and uses it everywhere. However, that value The compiler only creates one `RefCell`, and uses it everywhere. However, that value
is fully realized at compile time, and is fully stored in the `.L__unnamed_1` section. is fully realized at compile time, and is fully stored in the `.L__unnamed_1` section.
@ -232,7 +232,7 @@ pub fn multiply_twice(value: u32) -> u32 {
value * FACTOR * FACTOR value * FACTOR * FACTOR
} }
``` ```
-- [Compiler Explorer](https://odbolt.org/z/Qc7tHM) -- [Compiler Explorer](https://godbolt.org/z/_JiT9O)
In this example, the `FACTOR` value is turned into the `mov edi, 1000` instruction In this example, the `FACTOR` value is turned into the `mov edi, 1000` instruction
in both the `multiply` and `multiply_twice` functions; the "1000" value is never in both the `multiply` and `multiply_twice` functions; the "1000" value is never
@ -279,9 +279,9 @@ pub fn multiply_twice(value: u32) -> u32 {
value * FACTOR * FACTOR value * FACTOR * FACTOR
} }
``` ```
-- [Compiler Explorer](https://godbolt.org/z/MGBr5Y) -- [Compiler Explorer](https://godbolt.org/z/bSfBxn)
Where [previously](https://godbolt.org/z/MGBr5Y) there were plenty of Where [previously](https://godbolt.org/z/_JiT90) there were plenty of
references to multiplying by 1000, the new assembly refers to `FACTOR` references to multiplying by 1000, the new assembly refers to `FACTOR`
as a named memory location instead. No initialization work needs to be done, as a named memory location instead. No initialization work needs to be done,
but the compiler can no longer prove the value never changes during execution. but the compiler can no longer prove the value never changes during execution.
@ -439,9 +439,7 @@ everything is on the heap. JIT compilers ([PyPy](https://www.pypy.org/),
optimize some heap allocations away, but you should never assume it will happen. optimize some heap allocations away, but you should never assume it will happen.
C makes things clear with calls to special functions ([malloc(3)](https://linux.die.net/man/3/malloc) C makes things clear with calls to special functions ([malloc(3)](https://linux.die.net/man/3/malloc)
is one) being the way to use heap memory. Old C++ has the [`new`](https://stackoverflow.com/a/655086/1454178) is one) being the way to use heap memory. Old C++ has the [`new`](https://stackoverflow.com/a/655086/1454178)
keyword, though modern C++/C++11 is more complicated with [RAII](https://en.cppreference.com/w/cpp/language/raii) keyword, though modern C++/C++11 is more complicated with [RAII](https://en.cppreference.com/w/cpp/language/raii).
([`std::make_unique()`](https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) and
[`std::make_shared()`](https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared))
For Rust specifically, the principle is this: *stack allocation will be used for everything For Rust specifically, the principle is this: *stack allocation will be used for everything
that doesn't involve "smart pointers" and collections.* If we're interested in proving that doesn't involve "smart pointers" and collections.* If we're interested in proving
@ -458,9 +456,9 @@ it though, there are three things to watch for:
x x
} }
``` ```
-- [Compiler Explorer](https://godbolt.org/z/gKFOgB) -- [Compiler Explorer](https://godbolt.org/z/5WSgc9)
2. Tracking when heap allocation calls happen is difficult. It's typically easier to 2. Tracking when exactly heap allocation calls happen is difficult. It's typically easier to
watch for `call core::ptr::drop_in_place`, and infer that a heap allocation happened watch for `call core::ptr::drop_in_place`, and infer that a heap allocation happened
in the recent past: in the recent past:
```rust ```rust
@ -472,7 +470,7 @@ it though, there are three things to watch for:
x x
} }
``` ```
-- [Compiler Explorer](https://godbolt.org/z/T2xoh8) (`drop_in_place` happens on line 1321) -- [Compiler Explorer](https://godbolt.org/z/epfgoQ) (`drop_in_place` happens on line 1317)
<span style="font-size: .8em">Note: While the [`Drop` trait](https://doc.rust-lang.org/std/ops/trait.Drop.html) <span style="font-size: .8em">Note: While the [`Drop` trait](https://doc.rust-lang.org/std/ops/trait.Drop.html)
is called for stack-allocated objects, the Rust standard library only defines `Drop` implementations is called for stack-allocated objects, the Rust standard library only defines `Drop` implementations
for types that involve heap allocation.</span> for types that involve heap allocation.</span>
@ -531,8 +529,8 @@ or your data is of unknown or dynamic size, you'll make use of these types.
The term [smart pointer](https://en.wikipedia.org/wiki/Smart_pointer) The term [smart pointer](https://en.wikipedia.org/wiki/Smart_pointer)
comes from C++, and is used to describe objects that are responsible for managing comes from C++, and is used to describe objects that are responsible for managing
ownership of data allocated on the heap. Some familiar smart pointers come from the ownership of data allocated on the heap. The smart pointers available in the `alloc`
low-level `alloc` crate: crate should look rather familiar:
- [`Box`](https://doc.rust-lang.org/alloc/boxed/struct.Box.html) - [`Box`](https://doc.rust-lang.org/alloc/boxed/struct.Box.html)
- [`Rc`](https://doc.rust-lang.org/alloc/rc/struct.Rc.html) - [`Rc`](https://doc.rust-lang.org/alloc/rc/struct.Rc.html)
- [`Arc`](https://doc.rust-lang.org/alloc/sync/struct.Arc.html) - [`Arc`](https://doc.rust-lang.org/alloc/sync/struct.Arc.html)
@ -561,26 +559,26 @@ use std::sync::Arc;
use std::borrow::Cow; use std::borrow::Cow;
pub fn my_box() { pub fn my_box() {
// Drop at line 1674 // Drop at line 1640
Box::new(0); Box::new(0);
} }
pub fn my_rc() { pub fn my_rc() {
// Drop at line 1684 // Drop at line 1650
Rc::new(0); Rc::new(0);
} }
pub fn my_arc() { pub fn my_arc() {
// Drop at line 1694 // Drop at line 1660
Arc::new(0); Arc::new(0);
} }
pub fn my_cow() { pub fn my_cow() {
// Drop at line 1707 // Drop at line 1672
Cow::from("drop"); Cow::from("drop");
} }
``` ```
-- [Compiler Explorer](https://godbolt.org/z/QOPR4V) -- [Compiler Explorer](https://godbolt.org/z/SaDpWg)
Collections types use heap memory because they have dynamic size; they will request more memory Collections types use heap memory because they have dynamic size; they will request more memory
[when they need it](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve), [when they need it](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve),
@ -600,7 +598,7 @@ pub fn my_vec() {
Vec::<u8>::new(); Vec::<u8>::new();
} }
``` ```
-- [Compiler Explorer](https://godbolt.org/z/3-Gjqz) -- [Compiler Explorer](https://godbolt.org/z/1WkNtC)
But because the vector has no elements it is managing, no calls to the allocator But because the vector has no elements it is managing, no calls to the allocator
will ever be dispatched. A couple of places to look at for confirming this behavior: will ever be dispatched. A couple of places to look at for confirming this behavior: