mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-23 20:22:51 +01:00
Make identifiers deterministic.
This commit is contained in:
parent
4f193df0ef
commit
be8a5e89b8
3 changed files with 62 additions and 65 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@
|
||||||
/book/*/book
|
/book/*/book
|
||||||
/target
|
/target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
*.hex
|
||||||
|
|
|
@ -125,6 +125,12 @@ main() {
|
||||||
|
|
||||||
cargo clean
|
cargo clean
|
||||||
for ex in ${exs[@]}; do
|
for ex in ${exs[@]}; do
|
||||||
|
if [ $ex = singleton ]; then
|
||||||
|
# singleton build is currently not reproducible due to
|
||||||
|
# https://github.com/japaric/owned-singleton/issues/2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $ex != types ]; then
|
if [ $ex != types ]; then
|
||||||
arm_example "build" $ex "debug" "" "2"
|
arm_example "build" $ex "debug" "" "2"
|
||||||
cmp ${ex}_debug_1.hex ${ex}_debug_2.hex
|
cmp ${ex}_debug_1.hex ${ex}_debug_2.hex
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, HashMap},
|
collections::{BTreeMap, HashMap},
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
|
@ -44,6 +42,8 @@ struct Context {
|
||||||
tasks: BTreeMap<Ident, Task>,
|
tasks: BTreeMap<Ident, Task>,
|
||||||
// Alias (`struct` / `static mut`)
|
// Alias (`struct` / `static mut`)
|
||||||
timer_queue: Ident,
|
timer_queue: Ident,
|
||||||
|
// Generator of Ident names or suffixes
|
||||||
|
ident_gen: IdentGenerator,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Dispatcher {
|
struct Dispatcher {
|
||||||
|
@ -63,19 +63,22 @@ struct Task {
|
||||||
|
|
||||||
impl Default for Context {
|
impl Default for Context {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let mut ident_gen = IdentGenerator::new();
|
||||||
|
|
||||||
Context {
|
Context {
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
baseline: mk_ident(None),
|
baseline: ident_gen.mk_ident(None),
|
||||||
dispatchers: BTreeMap::new(),
|
dispatchers: BTreeMap::new(),
|
||||||
idle: mk_ident(Some("idle")),
|
idle: ident_gen.mk_ident(Some("idle")),
|
||||||
init: mk_ident(Some("init")),
|
init: ident_gen.mk_ident(Some("init")),
|
||||||
priority: mk_ident(None),
|
priority: ident_gen.mk_ident(None),
|
||||||
statics: Aliases::new(),
|
statics: Aliases::new(),
|
||||||
resources: HashMap::new(),
|
resources: HashMap::new(),
|
||||||
schedule_enum: mk_ident(None),
|
schedule_enum: ident_gen.mk_ident(None),
|
||||||
schedule_fn: Aliases::new(),
|
schedule_fn: Aliases::new(),
|
||||||
tasks: BTreeMap::new(),
|
tasks: BTreeMap::new(),
|
||||||
timer_queue: mk_ident(None),
|
timer_queue: ident_gen.mk_ident(None),
|
||||||
|
ident_gen,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,13 +167,13 @@ pub fn app(app: &App, analysis: &Analysis) -> TokenStream {
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let timer_queue = timer_queue(&ctxt, app, analysis);
|
let timer_queue = timer_queue(&mut ctxt, app, analysis);
|
||||||
|
|
||||||
let pre_init = pre_init(&ctxt, &app, analysis);
|
let pre_init = pre_init(&ctxt, &app, analysis);
|
||||||
|
|
||||||
let assertions = assertions(app, analysis);
|
let assertions = assertions(app, analysis);
|
||||||
|
|
||||||
let main = mk_ident(None);
|
let main = ctxt.ident_gen.mk_ident(None);
|
||||||
quote!(
|
quote!(
|
||||||
#resources
|
#resources
|
||||||
|
|
||||||
|
@ -236,7 +239,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2:
|
||||||
pub static #mut_ #name: #ty = #expr;
|
pub static #mut_ #name: #ty = #expr;
|
||||||
));
|
));
|
||||||
|
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None);
|
||||||
if let Some(Ownership::Shared { ceiling }) = analysis.ownerships.get(name) {
|
if let Some(Ownership::Shared { ceiling }) = analysis.ownerships.get(name) {
|
||||||
items.push(mk_resource(
|
items.push(mk_resource(
|
||||||
ctxt,
|
ctxt,
|
||||||
|
@ -252,7 +255,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2:
|
||||||
|
|
||||||
ctxt.statics.insert(name.clone(), alias);
|
ctxt.statics.insert(name.clone(), alias);
|
||||||
} else {
|
} else {
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None);
|
||||||
let symbol = format!("{}::{}", name, alias);
|
let symbol = format!("{}::{}", name, alias);
|
||||||
|
|
||||||
items.push(
|
items.push(
|
||||||
|
@ -826,7 +829,7 @@ fn prelude(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
pub #name: &'a #mut_ #name
|
pub #name: &'a #mut_ #name
|
||||||
));
|
));
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None);
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
let #mut_ #alias = unsafe {
|
let #mut_ #alias = unsafe {
|
||||||
|
@ -843,7 +846,7 @@ fn prelude(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
pub #name: rtfm::Exclusive<'a, #name>
|
pub #name: rtfm::Exclusive<'a, #name>
|
||||||
));
|
));
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None);
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
let #mut_ #alias = unsafe {
|
let #mut_ #alias = unsafe {
|
||||||
|
@ -910,7 +913,7 @@ fn prelude(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None);
|
||||||
let unsafety = if needs_unsafe {
|
let unsafety = if needs_unsafe {
|
||||||
Some(quote!(unsafe))
|
Some(quote!(unsafe))
|
||||||
} else {
|
} else {
|
||||||
|
@ -971,7 +974,7 @@ fn prelude(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxt.schedule_fn.insert(task.clone(), mk_ident(None));
|
ctxt.schedule_fn.insert(task.clone(), ctxt.ident_gen.mk_ident(None));
|
||||||
}
|
}
|
||||||
|
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
|
@ -1100,7 +1103,7 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec<proc_ma
|
||||||
|
|
||||||
let locals = mk_locals(&exception.statics, false);
|
let locals = mk_locals(&exception.statics, false);
|
||||||
let symbol = ident.to_string();
|
let symbol = ident.to_string();
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None);
|
||||||
let unsafety = &exception.unsafety;
|
let unsafety = &exception.unsafety;
|
||||||
quote!(
|
quote!(
|
||||||
#module
|
#module
|
||||||
|
@ -1179,7 +1182,7 @@ fn interrupts(
|
||||||
};
|
};
|
||||||
|
|
||||||
let locals = mk_locals(&interrupt.statics, false);
|
let locals = mk_locals(&interrupt.statics, false);
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None);
|
||||||
let symbol = ident.to_string();
|
let symbol = ident.to_string();
|
||||||
let unsafety = &interrupt.unsafety;
|
let unsafety = &interrupt.unsafety;
|
||||||
scoped.push(quote!(
|
scoped.push(quote!(
|
||||||
|
@ -1213,10 +1216,10 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
// first pass to generate buffers (statics and resources) and spawn aliases
|
// first pass to generate buffers (statics and resources) and spawn aliases
|
||||||
for (name, task) in &app.tasks {
|
for (name, task) in &app.tasks {
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
let scheduleds_alias = mk_ident(None);
|
let scheduleds_alias = ctxt.ident_gen.mk_ident(None);
|
||||||
let free_alias = mk_ident(None);
|
let free_alias = ctxt.ident_gen.mk_ident(None);
|
||||||
let inputs_alias = mk_ident(None);
|
let inputs_alias = ctxt.ident_gen.mk_ident(None);
|
||||||
let task_alias = mk_ident(Some(&name.to_string()));
|
let task_alias = ctxt.ident_gen.mk_ident(Some(&name.to_string()));
|
||||||
|
|
||||||
let inputs = &task.inputs;
|
let inputs = &task.inputs;
|
||||||
|
|
||||||
|
@ -1277,7 +1280,7 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
alias: task_alias,
|
alias: task_alias,
|
||||||
free_queue: free_alias,
|
free_queue: free_alias,
|
||||||
inputs: inputs_alias,
|
inputs: inputs_alias,
|
||||||
spawn_fn: mk_ident(None),
|
spawn_fn: ctxt.ident_gen.mk_ident(None),
|
||||||
|
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
scheduleds: scheduleds_alias,
|
scheduleds: scheduleds_alias,
|
||||||
|
@ -1362,8 +1365,8 @@ fn dispatchers(
|
||||||
|
|
||||||
let device = &app.args.device;
|
let device = &app.args.device;
|
||||||
for (level, dispatcher) in &analysis.dispatchers {
|
for (level, dispatcher) in &analysis.dispatchers {
|
||||||
let ready_alias = mk_ident(None);
|
let ready_alias = ctxt.ident_gen.mk_ident(None);
|
||||||
let enum_alias = mk_ident(None);
|
let enum_alias = ctxt.ident_gen.mk_ident(None);
|
||||||
let capacity = mk_typenum_capacity(dispatcher.capacity, true);
|
let capacity = mk_typenum_capacity(dispatcher.capacity, true);
|
||||||
|
|
||||||
let variants = dispatcher
|
let variants = dispatcher
|
||||||
|
@ -1452,7 +1455,7 @@ fn dispatchers(
|
||||||
let attrs = &dispatcher.attrs;
|
let attrs = &dispatcher.attrs;
|
||||||
let interrupt = &dispatcher.interrupt;
|
let interrupt = &dispatcher.interrupt;
|
||||||
let symbol = interrupt.to_string();
|
let symbol = interrupt.to_string();
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None);
|
||||||
dispatchers.push(quote!(
|
dispatchers.push(quote!(
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#[export_name = #symbol]
|
#[export_name = #symbol]
|
||||||
|
@ -1703,7 +1706,7 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream {
|
||||||
quote!(#(#items)*)
|
quote!(#(#items)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenStream {
|
fn timer_queue(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenStream {
|
||||||
let tasks = &analysis.timer_queue.tasks;
|
let tasks = &analysis.timer_queue.tasks;
|
||||||
|
|
||||||
if tasks.is_empty() {
|
if tasks.is_empty() {
|
||||||
|
@ -1778,7 +1781,7 @@ fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::T
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let logical_prio = analysis.timer_queue.priority;
|
let logical_prio = analysis.timer_queue.priority;
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None);
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#[export_name = "SysTick"]
|
#[export_name = "SysTick"]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -1989,48 +1992,35 @@ fn mk_typenum_capacity(capacity: u8, power_of_two: bool) -> proc_macro2::TokenSt
|
||||||
quote!(rtfm::export::consts::#ident)
|
quote!(rtfm::export::consts::#ident)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_ident(name: Option<&str>) -> Ident {
|
struct IdentGenerator {
|
||||||
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
rng: rand::rngs::SmallRng,
|
||||||
|
}
|
||||||
|
|
||||||
let elapsed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
impl IdentGenerator {
|
||||||
|
fn new() -> IdentGenerator {
|
||||||
let secs = elapsed.as_secs();
|
IdentGenerator { rng: rand::rngs::SmallRng::seed_from_u64(0) }
|
||||||
let nanos = elapsed.subsec_nanos();
|
|
||||||
|
|
||||||
let count = CALL_COUNT.fetch_add(1, Ordering::SeqCst) as u32;
|
|
||||||
let mut seed: [u8; 16] = [0; 16];
|
|
||||||
|
|
||||||
for (i, v) in seed.iter_mut().take(8).enumerate() {
|
|
||||||
*v = ((secs >> (i * 8)) & 0xFF) as u8
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, v) in seed.iter_mut().skip(8).take(4).enumerate() {
|
fn mk_ident(&mut self, name: Option<&str>) -> Ident {
|
||||||
*v = ((nanos >> (i * 8)) & 0xFF) as u8
|
let n;
|
||||||
}
|
let mut s = if let Some(name) = name {
|
||||||
|
n = 4;
|
||||||
for (i, v) in seed.iter_mut().skip(12).enumerate() {
|
format!("{}_", name)
|
||||||
*v = ((count >> (i * 8)) & 0xFF) as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
let n;
|
|
||||||
let mut s = if let Some(name) = name {
|
|
||||||
n = 4;
|
|
||||||
format!("{}_", name)
|
|
||||||
} else {
|
|
||||||
n = 16;
|
|
||||||
String::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut rng = rand::rngs::SmallRng::from_seed(seed);
|
|
||||||
for i in 0..n {
|
|
||||||
if i == 0 || rng.gen() {
|
|
||||||
s.push(('a' as u8 + rng.gen::<u8>() % 25) as char)
|
|
||||||
} else {
|
} else {
|
||||||
s.push(('0' as u8 + rng.gen::<u8>() % 10) as char)
|
n = 16;
|
||||||
}
|
String::new()
|
||||||
}
|
};
|
||||||
|
|
||||||
Ident::new(&s, Span::call_site())
|
for i in 0..n {
|
||||||
|
if i == 0 || self.rng.gen() {
|
||||||
|
s.push(('a' as u8 + self.rng.gen::<u8>() % 25) as char)
|
||||||
|
} else {
|
||||||
|
s.push(('0' as u8 + self.rng.gen::<u8>() % 10) as char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ident::new(&s, Span::call_site())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// `once = true` means that these locals will be called from a function that will run *once*
|
// `once = true` means that these locals will be called from a function that will run *once*
|
||||||
|
|
Loading…
Reference in a new issue