Skip to content

Commit cc4c5c1

Browse files
0.2.5 (stable): NonDeDuplicated's generic parameter must implement Any. Docs. cross-crate-demo/. GH Actions.
1 parent ac6abe1 commit cc4c5c1

32 files changed

+258
-75
lines changed

.github/workflows/main.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,19 @@ jobs:
1919

2020
- name: Tests and demos
2121
run: |
22-
rustup component add clippy
22+
rustup component add clippy rustfmt
2323
cargo clippy
24+
cargo fmt --check
25+
cargo doc --no-deps --quiet
2426
cargo test
2527
cargo test --release
2628
rustup install nightly --profile minimal
2729
rustup +nightly component add miri
2830
cargo +nightly miri test
29-
demo-fat-lto/static_option_u8.sh
30-
demo-fat-lto/static_str.sh
31-
demo-fat-lto/literal_str.sh
31+
cross-crate-demo/bin/static_option_u8.sh
32+
cross-crate-demo/bin/static_str.sh
33+
cross-crate-demo/bin/literal_str.sh
34+
cross-crate-demo/bin-fat-lto/static_option_u8.sh
35+
cross-crate-demo/bin-fat-lto/static_str.sh
36+
cross-crate-demo/bin-fat-lto/literal_str.sh
3237
shell: sh

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
/target
2-
/demo-fat-lto/target
3-
/demo-fat-lto/cross-crate/target
2+
/cross-crate-demo/*/target
43

CHANGELOG.md

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,48 @@
11
# Changelog
22

3-
## 0.2.3 and 0.3.3-nightly
3+
This reflects GIT commits on `main` branch (the default branch), that is, `stable` versions
4+
(compatible with `stable` Rust toolchain). Some of the below versions may not have been published to
5+
[crates.io](https://crates.io/crates/ndd) but were skipped.
6+
7+
[`nightly` GIT branch](https://github.com/peter-lyons-kehl/ndd/tree/nightly) may occasionally be
8+
behind `main`. See also [CONTRIBUTING.md](CONTRIBUTING.md).
9+
10+
## 0.2.6 (stable) and 0.3.6-nightly
11+
12+
[`cross-crate-demo`](cross-crate-demo/) demonstrates effect of Fat LTO (Link Time Optimization)
13+
across crates. Also invoked from GitHub Actions.
14+
15+
## 0.2.5 (stable)
16+
17+
- `NonDeDuplicated`'s generic parameter `T` must now implement
18+
[`core::any::Any`](https://doc.rust-lang.org/nightly/core/any/trait.Any.html).
19+
- Tests with [MIRI](https://github.com/rust-lang/miri).
20+
- Docs.
21+
22+
## 0.2.4 (stable)
23+
24+
- GitHub Actions on Alpine Linux
25+
- Docs; GH Actions badge in README
26+
- `fat lto` demo
27+
- [`precommit`](./pre-commit) GIT check
28+
29+
## 0.2.3 (stable) and 0.3.3-nightly
430

531
- Validation: For `static` variables only. Dropping `ndd::NonDeDuplicated` in debug build panics.
632
- New tests.
733
- Documentation: `nightly`, quality,
834
- Versioning scheme validation: GitHub Actions.
935
- Versioning scheme validation: local GIT pre-commit hook.
1036

11-
## 0.2.2
37+
## 0.2.2 (stable)
1238

1339
Documentation.
1440

15-
## 0.2.1
41+
## 0.2.1 (stable)
1642

1743
Documentation.
1844

19-
## 0.2.0
45+
## 0.2.0 (stable)
2046

2147
Initial functionality.
2248

CONTRIBUTING.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ ln -s ../../pre-commit
1919
`nightly` functionality is on [`nightly`
2020
branch](https://github.com/peter-lyons-kehl/ndd/tree/nightly).
2121

22+
### Warning about nightly
23+
24+
`nightly` branch is subject to continuous rebase (and forced push). If you need to extend/modify
25+
`nightly`-specific functionality, communicate first.
26+
2227
## File formatting
2328

2429
- Use `cargo fmt` for Rust source.

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ndd"
3-
version = "0.2.4"
3+
version = "0.2.5"
44
edition = "2024"
55

66
license = "BSD-2-Clause OR Apache-2.0 OR MIT"

README.md

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,48 @@ address**.
1414

1515
Rust (or, rather, LLVM) by default de-duplicates or reuses **addresses** of `static` variables in
1616
`release` builds. And somewhat in `debug` builds, too. For most purposes that is good: The result
17-
binary is smaller, and because of more successful cache hits, the execution may be faster.
17+
binary is smaller, and because of more successful cache hits, the execution is faster.
1818

1919
However, that is counter-productive when the code identifies/compares `static` data by memory
2020
address of the reference (whether a Rust reference/slice, or a pointer/pointer range). For example,
2121
an existing Rust/3rd party API may accept ("ordinary") references/slices. You may want to extend
2222
that API's protocol/behavior with signalling/special handling when the client sends in your
2323
designated `static` variable by reference/slice/pointer/pointer range. (Your special handler may
2424
cast such references/slices to pointers and compare them by address with
25-
[`core::ptr::eq()`](https://doc.rust-lang.org/nightly/core/ptr/fn.eq.html).)
26-
27-
Then you don't want the client, nor the compiler/LLVM, to reuse/share the memory address of such a
28-
designated `static` for any other ("ordinary") `static` or `const` values/expressions, or local
29-
numerical/character/byte/string slice literals. That does work out of the box when the client passes
30-
a reference/slice defined as `static`: (even with the default `release` optimizations) each `static`
31-
gets its own memory space. See a test [`src/lib.rs` ->
25+
[`core::ptr::eq()`](https://doc.rust-lang.org/nightly/core/ptr/fn.eq.html) or
26+
[`core::ptr::addr_eq()`](https://doc.rust-lang.org/nightly/core/ptr/fn.addr_eq.html).)
27+
28+
Then you do **not want** the client, nor the compiler/LLVM, to reuse/share the memory address of
29+
such a designated `static` for any other ("ordinary") `static` or `const` values/expressions, or
30+
local numerical/character/byte/string slice literals. That does work out of the box when the client
31+
passes a reference/slice defined as `static`: each `static` gets its own memory space (even with the
32+
default `release` optimizations). See a test [`src/lib.rs` ->
3233
`addresses_unique_between_statics()`](https://github.com/peter-lyons-kehl/ndd/blob/26d743d9b7bbaf41155e00174f8827efca5d5f32/src/lib.rs#L72).
3334

3435
However, there is a problem (in `release` mode, and for some types even in `debug` mode). It affects
3536
("ordinary") `const` values/expressions that equal in value to any `static` (which may be your
36-
designated `static`). Rust/LLVM re-uses address of one such matching `static`' for references to
37+
designated `static`). Rust/LLVM re-uses address of one such matching `static`' for references to any
3738
equal value(s) defined as `const`. See a test [`src/lib.rs` ->
3839
`addresses_not_unique_between_const_and_static()`](https://github.com/peter-lyons-kehl/ndd/blob/26d743d9b7bbaf41155e00174f8827efca5d5f32/src/lib.rs#L95).
39-
Such `const`, `static` or literal could be in 3rd party code, and even private (see
40-
[`demo-fat-lto`](./demo-fat-lto))!
40+
Such `const`, `static` or literal could be in 3rd party code, and private - not even exported (see
41+
[`cross-crate-demo`](cross-crate-demo))!
4142

42-
Things get worse: `debug` builds don't have this consistent.
43+
Things get worse: `debug` builds don't have this consistent:
4344

4445
- For some types (`u8`, numeric primitive-based enums) `debug` builds don't reuse `static` addresses
4546
for references/slices to `const` values. But
4647
- For other types (`str`), `debug` builds do reuse them...
47-
- Only `MIRI` doesn't reuse `static` addresses at all.
4848

49-
Even worse so: `release` builds don't have this consistent.
49+
`MIRI` reuses `static` addresses even less (than `debug` does), but it still does reuse them
50+
sometimes - for example, between byte literals (`b"Hello"`) and equal string literals (`"Hello"`).
51+
52+
Even worse so: `release` builds don't have this consistent. De-duplication across crates depends on
53+
"fat" link time optimization (LTO):
54+
55+
```toml
56+
[profile.release]
57+
lto = "fat"
58+
```
5059

5160
## Solution
5261

@@ -102,7 +111,8 @@ versions `1.0` or higher.
102111
- **Odd**-numbered major versions (`0.3`, `0.5`...)
103112
- always contain `-nightly` (pre-release identifier) in their name.
104113
- are, indeed, for `nightly` (**unstable**) functionality, and need `nightly` Rust toolchain
105-
(indicated with `rust-toolchain.toml` which is present on `nightly` branch only).
114+
(indicated with `rust-toolchain.toml` which is present on [`nightly`
115+
branch](https://github.com/peter-lyons-kehl/ndd/tree/nightly) GIT branch only).
106116
- include functionality already present in some lower stable versions. Not all of them - only:
107117
- stable versions with a **lower major** numeric version, and
108118
- if the stable **major** version is lower by **`0.1` only** (and not by more), then the stable
@@ -210,22 +220,27 @@ stable not in years, but sooner.
210220

211221
## Quality
212222

213-
Checked and tested (also with [MIRI](https://github.com/rust-lang/miri)):
223+
Checks and tests are run by [GitHub Actions (CI)](.github/workflows/main.yml). All scripts run on
224+
Alpine Linux and are POSIX-compliant.
225+
214226
- `cargo clippy`
227+
- `cargo fmt --check`
228+
- `cargo doc --no-deps --quiet`
215229
- `cargo test`
216230
- `cargo test --release`
217-
- `rustup install nightly --profile minimal`
218-
- `rustup +nightly component add miri`
219-
- `cargo +nightly miri test`
220-
- `release`-only tests:
221-
- `demo-fat-lto/static_option_u8.sh`
222-
- `demo-fat-lto/static_str.sh`
223-
- `demo-fat-lto/literal_str.sh`
224-
225-
The versioning convention is validated:
226-
227-
- locally with GIT [pre-commit](./pre-commit) hook, and
228-
- with a [GitHub action](.github/workflows/main.yml).
231+
- with [MIRI](https://github.com/rust-lang/miri):
232+
- `rustup install nightly --profile minimal`
233+
- `rustup +nightly component add miri`
234+
- `cargo +nightly miri test`
235+
- `release`-only demonstration:
236+
- `cross-crate-demo/bin/static_option_u8.sh`
237+
- `cross-crate-demo/bin/static_str.sh`
238+
- `cross-crate-demo/bin/literal_str.sh`
239+
- `cross-crate-demo/bin-fat-lto/static_option_u8.sh`
240+
- `cross-crate-demo/bin-fat-lto/static_str.sh`
241+
- `cross-crate-demo/bin-fat-lto/literal_str.sh`
242+
- validate the versioning convention:
243+
- [`pre-commit`](./pre-commit)
229244

230245
## Use cases
231246

cross-crate-demo/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Fat LTO effect demo
2+
3+
Demo that LLVM can de-duplicate equal `static` literals or variables and `const` even between
4+
crates, that is, affecting 3-rd party ("innocent") code.
5+
6+
Run and see how `lto = "fat"` (Link Time Optimization) affects de-duplication:
7+
8+
- same `static` and `const` values across crates, **without** `lto = "fat"`, even in standard
9+
`release` build, do **not** get de-duplicated:
10+
- [`bin/literal_str.sh`](bin/literal_str.sh)
11+
- [`bin/static_option_u8.sh`](bin/static_option_u8.sh)
12+
- [`bin/static_str.sh`](bin/static_str.sh)
13+
- but, same `static` and `const` values across crates, **with** `lto = "fat"`, **do** get
14+
de-duplicated:
15+
- [`bin-fat-lto/literal_str.sh`](bin-fat-lto/literal_str.sh)
16+
- [`bin-fat-lto/static_option_u8.sh`](bin-fat-lto/static_option_u8.sh)
17+
- [`bin-fat-lto/static_str.sh`](bin-fat-lto/static_str.sh)
18+
19+
The only difference between [`bin/`](bin) and [`bin-fat-lto/`](bin-fat-lto) is in their
20+
`Cargo.toml`:
21+
22+
- [`bin-fat-lto/Cargo.toml`](bin-fat-lto/Cargo.toml) uses `lto = "fat"`, but
23+
- [`bin/Cargo.toml`](bin/Cargo.toml) does not.
24+
25+
This requires a filesystem that supports symlinks. ([`bin`](bin) and [`bin-fat-lto`](bin-fat-lto)
26+
use symlinks to reuse files from [`bin-shared`](bin-shared).
Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
[package]
2-
name = "demo-fat-lto"
2+
name = "bin"
33
version = "0.1.0"
44
edition = "2024"
55

66
[dependencies]
7-
cross-crate = {path = "cross-crate" }
7+
callee = {path = "../callee" }
88

99
[lints.rust]
1010
unexpected_cfgs = { level = "forbid"}
1111

1212
[profile.release]
1313
lto = "fat"
14+

0 commit comments

Comments
 (0)