From 2f89688ca974944781878a74873801597c0b1f11 Mon Sep 17 00:00:00 2001 From: Hugo van der Wijst Date: Tue, 15 Jan 2019 22:42:50 -0800 Subject: Make builds reproducible This is done by using `BTreeMap`s and `BTreeSet`s to get deterministic ordering. Also updated the CI job to check reproducibility of all examples. --- macros/src/codegen.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'macros/src/codegen.rs') diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index af3def6..a96eaef 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -2,7 +2,7 @@ use proc_macro::TokenStream; use std::{ - collections::HashMap, + collections::{BTreeMap, HashMap}, sync::atomic::{AtomicUsize, Ordering}, time::{SystemTime, UNIX_EPOCH}, }; @@ -20,13 +20,13 @@ use crate::{ // NOTE to avoid polluting the user namespaces we map some identifiers to pseudo-hygienic names. // In some instances we also use the pseudo-hygienic names for safety, for example the user should // not modify the priority field of resources. -type Aliases = HashMap; +type Aliases = BTreeMap; struct Context { // Alias #[cfg(feature = "timer-queue")] baseline: Ident, - dispatchers: HashMap, + dispatchers: BTreeMap, // Alias (`fn`) idle: Ident, // Alias (`fn`) @@ -41,7 +41,7 @@ struct Context { schedule_enum: Ident, // Task -> Alias (`fn`) schedule_fn: Aliases, - tasks: HashMap, + tasks: BTreeMap, // Alias (`struct` / `static mut`) timer_queue: Ident, } @@ -66,7 +66,7 @@ impl Default for Context { Context { #[cfg(feature = "timer-queue")] baseline: mk_ident(None), - dispatchers: HashMap::new(), + dispatchers: BTreeMap::new(), idle: mk_ident(Some("idle")), init: mk_ident(Some("init")), priority: mk_ident(None), @@ -74,7 +74,7 @@ impl Default for Context { resources: HashMap::new(), schedule_enum: mk_ident(None), schedule_fn: Aliases::new(), - tasks: HashMap::new(), + tasks: BTreeMap::new(), timer_queue: mk_ident(None), } } @@ -2034,7 +2034,7 @@ fn mk_ident(name: Option<&str>) -> Ident { } // `once = true` means that these locals will be called from a function that will run *once* -fn mk_locals(locals: &HashMap, once: bool) -> proc_macro2::TokenStream { +fn mk_locals(locals: &BTreeMap, once: bool) -> proc_macro2::TokenStream { let lt = if once { Some(quote!('static)) } else { None }; let locals = locals -- cgit v1.2.3 From be8a5e89b8c5763dc691bb748ba1da73a56cb2cc Mon Sep 17 00:00:00 2001 From: Hugo van der Wijst Date: Wed, 16 Jan 2019 17:36:55 -0800 Subject: Make identifiers deterministic. --- macros/src/codegen.rs | 118 +++++++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 64 deletions(-) (limited to 'macros/src/codegen.rs') diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index a96eaef..9eb875c 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -3,8 +3,6 @@ use proc_macro::TokenStream; use std::{ collections::{BTreeMap, HashMap}, - sync::atomic::{AtomicUsize, Ordering}, - time::{SystemTime, UNIX_EPOCH}, }; use proc_macro2::Span; @@ -44,6 +42,8 @@ struct Context { tasks: BTreeMap, // Alias (`struct` / `static mut`) timer_queue: Ident, + // Generator of Ident names or suffixes + ident_gen: IdentGenerator, } struct Dispatcher { @@ -63,19 +63,22 @@ struct Task { impl Default for Context { fn default() -> Self { + let mut ident_gen = IdentGenerator::new(); + Context { #[cfg(feature = "timer-queue")] - baseline: mk_ident(None), + baseline: ident_gen.mk_ident(None), dispatchers: BTreeMap::new(), - idle: mk_ident(Some("idle")), - init: mk_ident(Some("init")), - priority: mk_ident(None), + idle: ident_gen.mk_ident(Some("idle")), + init: ident_gen.mk_ident(Some("init")), + priority: ident_gen.mk_ident(None), statics: Aliases::new(), resources: HashMap::new(), - schedule_enum: mk_ident(None), + schedule_enum: ident_gen.mk_ident(None), schedule_fn: Aliases::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!(), }; - 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 assertions = assertions(app, analysis); - let main = mk_ident(None); + let main = ctxt.ident_gen.mk_ident(None); quote!( #resources @@ -236,7 +239,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2: 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) { items.push(mk_resource( ctxt, @@ -252,7 +255,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2: ctxt.statics.insert(name.clone(), alias); } else { - let alias = mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None); let symbol = format!("{}::{}", name, alias); items.push( @@ -826,7 +829,7 @@ fn prelude( #(#cfgs)* pub #name: &'a #mut_ #name )); - let alias = mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None); items.push(quote!( #(#cfgs)* let #mut_ #alias = unsafe { @@ -843,7 +846,7 @@ fn prelude( #(#cfgs)* pub #name: rtfm::Exclusive<'a, #name> )); - let alias = mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None); items.push(quote!( #(#cfgs)* 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 { Some(quote!(unsafe)) } else { @@ -971,7 +974,7 @@ fn prelude( 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!( @@ -1100,7 +1103,7 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec proc_macro2::Tok // first pass to generate buffers (statics and resources) and spawn aliases for (name, task) in &app.tasks { #[cfg(feature = "timer-queue")] - let scheduleds_alias = mk_ident(None); - let free_alias = mk_ident(None); - let inputs_alias = mk_ident(None); - let task_alias = mk_ident(Some(&name.to_string())); + let scheduleds_alias = ctxt.ident_gen.mk_ident(None); + let free_alias = ctxt.ident_gen.mk_ident(None); + let inputs_alias = ctxt.ident_gen.mk_ident(None); + let task_alias = ctxt.ident_gen.mk_ident(Some(&name.to_string())); let inputs = &task.inputs; @@ -1277,7 +1280,7 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok alias: task_alias, free_queue: free_alias, inputs: inputs_alias, - spawn_fn: mk_ident(None), + spawn_fn: ctxt.ident_gen.mk_ident(None), #[cfg(feature = "timer-queue")] scheduleds: scheduleds_alias, @@ -1362,8 +1365,8 @@ fn dispatchers( let device = &app.args.device; for (level, dispatcher) in &analysis.dispatchers { - let ready_alias = mk_ident(None); - let enum_alias = mk_ident(None); + let ready_alias = ctxt.ident_gen.mk_ident(None); + let enum_alias = ctxt.ident_gen.mk_ident(None); let capacity = mk_typenum_capacity(dispatcher.capacity, true); let variants = dispatcher @@ -1452,7 +1455,7 @@ fn dispatchers( let attrs = &dispatcher.attrs; let interrupt = &dispatcher.interrupt; let symbol = interrupt.to_string(); - let alias = mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None); dispatchers.push(quote!( #(#attrs)* #[export_name = #symbol] @@ -1703,7 +1706,7 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream { 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; if tasks.is_empty() { @@ -1778,7 +1781,7 @@ fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::T .collect::>(); let logical_prio = analysis.timer_queue.priority; - let alias = mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None); items.push(quote!( #[export_name = "SysTick"] #[doc(hidden)] @@ -1989,48 +1992,35 @@ fn mk_typenum_capacity(capacity: u8, power_of_two: bool) -> proc_macro2::TokenSt quote!(rtfm::export::consts::#ident) } -fn mk_ident(name: Option<&str>) -> Ident { - static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); - - let elapsed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); - - let secs = elapsed.as_secs(); - 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() { - *v = ((nanos >> (i * 8)) & 0xFF) as u8 - } +struct IdentGenerator { + rng: rand::rngs::SmallRng, +} - for (i, v) in seed.iter_mut().skip(12).enumerate() { - *v = ((count >> (i * 8)) & 0xFF) as u8 +impl IdentGenerator { + fn new() -> IdentGenerator { + IdentGenerator { rng: rand::rngs::SmallRng::seed_from_u64(0) } } - 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::() % 25) as char) + fn mk_ident(&mut self, name: Option<&str>) -> Ident { + let n; + let mut s = if let Some(name) = name { + n = 4; + format!("{}_", name) } else { - s.push(('0' as u8 + rng.gen::() % 10) as char) + n = 16; + String::new() + }; + + for i in 0..n { + if i == 0 || self.rng.gen() { + s.push(('a' as u8 + self.rng.gen::() % 25) as char) + } else { + s.push(('0' as u8 + self.rng.gen::() % 10) as char) + } } - } - Ident::new(&s, Span::call_site()) + Ident::new(&s, Span::call_site()) + } } // `once = true` means that these locals will be called from a function that will run *once* -- cgit v1.2.3 From a654d13eefa846b9dc7fcdc1ccf5af43fc33834e Mon Sep 17 00:00:00 2001 From: Hugo van der Wijst Date: Tue, 22 Jan 2019 15:23:16 -0800 Subject: Seed RNG with package name and prepend string to full random name. --- macros/src/codegen.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'macros/src/codegen.rs') diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index 9eb875c..9fc0e27 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -1998,7 +1998,12 @@ struct IdentGenerator { impl IdentGenerator { fn new() -> IdentGenerator { - IdentGenerator { rng: rand::rngs::SmallRng::seed_from_u64(0) } + let crate_name = env!("CARGO_PKG_NAME"); + let seed = [0u8; 16]; + for (i, b) in crate_name.bytes().enumerate() { + seed[i%seed.len()].wrapping_add(b); + } + IdentGenerator { rng: rand::rngs::SmallRng::from_seed(seed) } } fn mk_ident(&mut self, name: Option<&str>) -> Ident { @@ -2007,8 +2012,9 @@ impl IdentGenerator { n = 4; format!("{}_", name) } else { + let crate_name = env!("CARGO_PKG_NAME").replace("-", "_").to_lowercase(); n = 16; - String::new() + format!("{}__internal__", crate_name) }; for i in 0..n { -- cgit v1.2.3 From 577d188f72398461650a4e76d81396bf0abea0f4 Mon Sep 17 00:00:00 2001 From: Hugo van der Wijst Date: Sun, 10 Feb 2019 15:25:33 -0800 Subject: Make generated names stable when sorting. --- macros/src/codegen.rs | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'macros/src/codegen.rs') diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index 9fc0e27..e2e5ac4 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -3,6 +3,7 @@ use proc_macro::TokenStream; use std::{ collections::{BTreeMap, HashMap}, + time::{SystemTime, UNIX_EPOCH}, }; use proc_macro2::Span; @@ -1993,30 +1994,48 @@ fn mk_typenum_capacity(capacity: u8, power_of_two: bool) -> proc_macro2::TokenSt } struct IdentGenerator { + call_count: u32, rng: rand::rngs::SmallRng, } impl IdentGenerator { fn new() -> IdentGenerator { - let crate_name = env!("CARGO_PKG_NAME"); - let seed = [0u8; 16]; - for (i, b) in crate_name.bytes().enumerate() { - seed[i%seed.len()].wrapping_add(b); + let elapsed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + + let secs = elapsed.as_secs(); + let nanos = elapsed.subsec_nanos(); + + 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() { + *v = ((nanos >> (i * 8)) & 0xFF) as u8 + } + + let rng = rand::rngs::SmallRng::from_seed(seed); + + IdentGenerator { + call_count: 0, + rng, } - IdentGenerator { rng: rand::rngs::SmallRng::from_seed(seed) } } fn mk_ident(&mut self, name: Option<&str>) -> Ident { let n; - let mut s = if let Some(name) = name { + let s = if let Some(name) = name { n = 4; format!("{}_", name) } else { let crate_name = env!("CARGO_PKG_NAME").replace("-", "_").to_lowercase(); - n = 16; + n = 4; format!("{}__internal__", crate_name) }; + let mut s = format!("{}{}_", s, self.call_count); + for i in 0..n { if i == 0 || self.rng.gen() { s.push(('a' as u8 + self.rng.gen::() % 25) as char) @@ -2025,6 +2044,8 @@ impl IdentGenerator { } } + self.call_count += 1; + Ident::new(&s, Span::call_site()) } } -- cgit v1.2.3 From 2b8e743f35a69b9b09a4de4c346eb9015c6b45ea Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 16 Feb 2019 00:22:00 +0100 Subject: make debug builds reproducible --- macros/src/codegen.rs | 233 ++++++++++++++++++++++++++++---------------------- 1 file changed, 132 insertions(+), 101 deletions(-) (limited to 'macros/src/codegen.rs') diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index e2e5ac4..1405c2f 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -68,17 +68,17 @@ impl Default for Context { Context { #[cfg(feature = "timer-queue")] - baseline: ident_gen.mk_ident(None), + baseline: ident_gen.mk_ident(None, false), dispatchers: BTreeMap::new(), - idle: ident_gen.mk_ident(Some("idle")), - init: ident_gen.mk_ident(Some("init")), - priority: ident_gen.mk_ident(None), + idle: ident_gen.mk_ident(Some("idle"), false), + init: ident_gen.mk_ident(Some("init"), false), + priority: ident_gen.mk_ident(None, false), statics: Aliases::new(), resources: HashMap::new(), - schedule_enum: ident_gen.mk_ident(None), + schedule_enum: ident_gen.mk_ident(None, false), schedule_fn: Aliases::new(), tasks: BTreeMap::new(), - timer_queue: ident_gen.mk_ident(None), + timer_queue: ident_gen.mk_ident(None, false), ident_gen, } } @@ -174,7 +174,7 @@ pub fn app(app: &App, analysis: &Analysis) -> TokenStream { let assertions = assertions(app, analysis); - let main = ctxt.ident_gen.mk_ident(None); + let main = ctxt.ident_gen.mk_ident(None, false); quote!( #resources @@ -240,7 +240,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2: pub static #mut_ #name: #ty = #expr; )); - let alias = ctxt.ident_gen.mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None, true); // XXX is randomness required? if let Some(Ownership::Shared { ceiling }) = analysis.ownerships.get(name) { items.push(mk_resource( ctxt, @@ -256,7 +256,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2: ctxt.statics.insert(name.clone(), alias); } else { - let alias = ctxt.ident_gen.mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None, false); let symbol = format!("{}::{}", name, alias); items.push( @@ -409,7 +409,7 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> (proc_macro2::Tok let baseline = &ctxt.baseline; let baseline_let = match () { #[cfg(feature = "timer-queue")] - () => quote!(let #baseline = rtfm::Instant::artificial(0);), + () => quote!(let ref #baseline = rtfm::Instant::artificial(0);), #[cfg(not(feature = "timer-queue"))] () => quote!(), @@ -419,7 +419,7 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> (proc_macro2::Tok #[cfg(feature = "timer-queue")] () => quote!( #[allow(unused_variables)] - let start = #baseline; + let start = *#baseline; ), #[cfg(not(feature = "timer-queue"))] () => quote!(), @@ -434,21 +434,27 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> (proc_macro2::Tok #module + // unsafe trampoline to deter end-users from calling this non-reentrant function #(#attrs)* - #unsafety fn #init(mut core: rtfm::Peripherals) #ret { - #(#locals)* + unsafe fn #init(core: rtfm::Peripherals) #ret { + #[inline(always)] + #unsafety fn init(mut core: rtfm::Peripherals) #ret { + #(#locals)* - #baseline_let + #baseline_let - #prelude + #prelude - let mut device = unsafe { #device::Peripherals::steal() }; + let mut device = unsafe { #device::Peripherals::steal() }; - #start_let + #start_let - #(#stmts)* + #(#stmts)* + + #(#assigns)* + } - #(#assigns)* + init(core) } ), has_late_resources, @@ -567,7 +573,7 @@ fn module( #[derive(Clone, Copy)] pub struct Schedule<'a> { #[doc(hidden)] - pub #priority: &'a core::cell::Cell, + pub #priority: &'a rtfm::export::Priority, } )); } @@ -586,7 +592,7 @@ fn module( #[derive(Clone, Copy)] pub struct Spawn<'a> { #[doc(hidden)] - pub #priority: &'a core::cell::Cell, + pub #priority: &'a rtfm::export::Priority, } )); } else { @@ -595,8 +601,10 @@ fn module( () => { let baseline = &ctxt.baseline; quote!( + // NOTE this field is visible so we use a shared reference to make it + // immutable #[doc(hidden)] - pub #baseline: rtfm::Instant, + pub #baseline: &'a rtfm::Instant, ) } #[cfg(not(feature = "timer-queue"))] @@ -609,7 +617,7 @@ fn module( pub struct Spawn<'a> { #baseline_field #[doc(hidden)] - pub #priority: &'a core::cell::Cell, + pub #priority: &'a rtfm::export::Priority, } )); } @@ -691,7 +699,7 @@ fn prelude( let mut exprs = vec![]; // NOTE This field is just to avoid unused type parameter errors around `'a` - defs.push(quote!(#[allow(dead_code)] #priority: &'a core::cell::Cell)); + defs.push(quote!(#[allow(dead_code)] pub #priority: &'a rtfm::export::Priority)); exprs.push(parse_quote!(#priority)); let mut may_call_lock = false; @@ -830,7 +838,8 @@ fn prelude( #(#cfgs)* pub #name: &'a #mut_ #name )); - let alias = ctxt.ident_gen.mk_ident(None); + // XXX is randomness required? + let alias = ctxt.ident_gen.mk_ident(None, true); items.push(quote!( #(#cfgs)* let #mut_ #alias = unsafe { @@ -847,7 +856,8 @@ fn prelude( #(#cfgs)* pub #name: rtfm::Exclusive<'a, #name> )); - let alias = ctxt.ident_gen.mk_ident(None); + // XXX is randomness required? + let alias = ctxt.ident_gen.mk_ident(None, true); items.push(quote!( #(#cfgs)* let #mut_ #alias = unsafe { @@ -914,7 +924,7 @@ fn prelude( } } - let alias = ctxt.ident_gen.mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None, false); let unsafety = if needs_unsafe { Some(quote!(unsafe)) } else { @@ -975,7 +985,8 @@ fn prelude( continue; } - ctxt.schedule_fn.insert(task.clone(), ctxt.ident_gen.mk_ident(None)); + ctxt.schedule_fn + .insert(task.clone(), ctxt.ident_gen.mk_ident(None, false)); } items.push(quote!( @@ -991,7 +1002,7 @@ fn prelude( quote!() } else { quote!( - let ref #priority = core::cell::Cell::new(#logical_prio); + let ref #priority = unsafe { rtfm::export::Priority::new(#logical_prio) }; #(#items)* ) @@ -1035,13 +1046,19 @@ fn idle( quote!( #module + // unsafe trampoline to deter end-users from calling this non-reentrant function #(#attrs)* - #unsafety fn #idle() -> ! { - #(#locals)* + unsafe fn #idle() -> ! { + #[inline(always)] + #unsafety fn idle() -> ! { + #(#locals)* - #prelude + #prelude - #(#stmts)* + #(#stmts)* + } + + idle() } ), quote!(#idle()), @@ -1087,7 +1104,7 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec quote!(let #baseline = rtfm::Instant::now();), + () => quote!(let ref #baseline = rtfm::Instant::now();), #[cfg(not(feature = "timer-queue"))] () => quote!(), }; @@ -1096,7 +1113,7 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec quote!( #[allow(unused_variables)] - let start = #baseline; + let start = *#baseline; ), #[cfg(not(feature = "timer-queue"))] () => quote!(), @@ -1104,26 +1121,31 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec quote!(let #baseline = rtfm::Instant::now();), + () => quote!(let ref #baseline = rtfm::Instant::now();), #[cfg(not(feature = "timer-queue"))] () => quote!(), }; @@ -1176,34 +1198,40 @@ fn interrupts( #[cfg(feature = "timer-queue")] () => quote!( #[allow(unused_variables)] - let start = #baseline; + let start = *#baseline; ), #[cfg(not(feature = "timer-queue"))] () => quote!(), }; let locals = mk_locals(&interrupt.statics, false); - let alias = ctxt.ident_gen.mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None, false); let symbol = ident.to_string(); let unsafety = &interrupt.unsafety; scoped.push(quote!( + // unsafe trampoline to deter end-users from calling this non-reentrant function #(#attrs)* #[export_name = #symbol] - #unsafety fn #alias() { - // check that this interrupt exists - let _ = #device::interrupt::#ident; + unsafe fn #alias() { + #[inline(always)] + #unsafety fn interrupt() { + // check that this interrupt exists + let _ = #device::interrupt::#ident; - #(#locals)* + #(#locals)* - #baseline_let + #baseline_let - #prelude + #prelude - #start_let + #start_let - rtfm::export::run(move || { - #(#stmts)* - }) + rtfm::export::run(move || { + #(#stmts)* + }) + } + + interrupt() } )); } @@ -1217,10 +1245,10 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok // first pass to generate buffers (statics and resources) and spawn aliases for (name, task) in &app.tasks { #[cfg(feature = "timer-queue")] - let scheduleds_alias = ctxt.ident_gen.mk_ident(None); - let free_alias = ctxt.ident_gen.mk_ident(None); - let inputs_alias = ctxt.ident_gen.mk_ident(None); - let task_alias = ctxt.ident_gen.mk_ident(Some(&name.to_string())); + let scheduleds_alias = ctxt.ident_gen.mk_ident(None, false); + let free_alias = ctxt.ident_gen.mk_ident(None, false); + let inputs_alias = ctxt.ident_gen.mk_ident(None, false); + let task_alias = ctxt.ident_gen.mk_ident(Some(&name.to_string()), false); let inputs = &task.inputs; @@ -1281,7 +1309,7 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok alias: task_alias, free_queue: free_alias, inputs: inputs_alias, - spawn_fn: ctxt.ident_gen.mk_ident(None), + spawn_fn: ctxt.ident_gen.mk_ident(None, false), #[cfg(feature = "timer-queue")] scheduleds: scheduleds_alias, @@ -1300,7 +1328,7 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok #[cfg(feature = "timer-queue")] () => { let baseline = &ctxt.baseline; - quote!(let scheduled = #baseline;) + quote!(let scheduled = *#baseline;) } #[cfg(not(feature = "timer-queue"))] () => quote!(), @@ -1329,26 +1357,33 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok let attrs = &task.attrs; let cfgs = &task.cfgs; let task_alias = &ctxt.tasks[name].alias; - let baseline_arg = match () { + let (baseline, baseline_arg) = match () { #[cfg(feature = "timer-queue")] () => { let baseline = &ctxt.baseline; - quote!(#baseline: rtfm::Instant,) + (quote!(#baseline,), quote!(#baseline: &rtfm::Instant,)) } #[cfg(not(feature = "timer-queue"))] - () => quote!(), + () => (quote!(), quote!()), }; + let pats = tuple_pat(inputs); items.push(quote!( + // unsafe trampoline to deter end-users from calling this non-reentrant function #(#attrs)* #(#cfgs)* - #unsafety fn #task_alias(#baseline_arg #(#inputs,)*) { - #(#locals)* + unsafe fn #task_alias(#baseline_arg #(#inputs,)*) { + #[inline(always)] + #unsafety fn task(#baseline_arg #(#inputs,)*) { + #(#locals)* - #prelude + #prelude + + #scheduled_let - #scheduled_let + #(#stmts)* + } - #(#stmts)* + task(#baseline #pats) } )); } @@ -1366,8 +1401,8 @@ fn dispatchers( let device = &app.args.device; for (level, dispatcher) in &analysis.dispatchers { - let ready_alias = ctxt.ident_gen.mk_ident(None); - let enum_alias = ctxt.ident_gen.mk_ident(None); + let ready_alias = ctxt.ident_gen.mk_ident(None, false); + let enum_alias = ctxt.ident_gen.mk_ident(None, false); let capacity = mk_typenum_capacity(dispatcher.capacity, true); let variants = dispatcher @@ -1431,7 +1466,7 @@ fn dispatchers( let baseline = ptr::read(#scheduleds.get_ref().get_unchecked(usize::from(index))); ); - call = quote!(#alias(baseline, #pats)); + call = quote!(#alias(&baseline, #pats)); } #[cfg(not(feature = "timer-queue"))] () => { @@ -1456,7 +1491,7 @@ fn dispatchers( let attrs = &dispatcher.attrs; let interrupt = &dispatcher.interrupt; let symbol = interrupt.to_string(); - let alias = ctxt.ident_gen.mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None, false); dispatchers.push(quote!( #(#attrs)* #[export_name = #symbol] @@ -1538,7 +1573,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt #(#cfgs)* unsafe fn #alias( #baseline_arg - #priority: &core::cell::Cell, + #priority: &rtfm::export::Priority, #(#args,)* ) -> Result<(), #ty> { use core::ptr; @@ -1587,7 +1622,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt if is_idle { quote!(rtfm::Instant::now(),) } else { - quote!(self.#baseline,) + quote!(*self.#baseline,) } } #[cfg(not(feature = "timer-queue"))] @@ -1636,7 +1671,7 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream { #[inline(always)] #(#cfgs)* unsafe fn #alias( - #priority: &core::cell::Cell, + #priority: &rtfm::export::Priority, instant: rtfm::Instant, #(#args,)* ) -> Result<(), #ty> { @@ -1782,14 +1817,14 @@ fn timer_queue(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro .collect::>(); let logical_prio = analysis.timer_queue.priority; - let alias = ctxt.ident_gen.mk_ident(None); + let alias = ctxt.ident_gen.mk_ident(None, false); items.push(quote!( #[export_name = "SysTick"] #[doc(hidden)] unsafe fn #alias() { use rtfm::Mutex; - let ref #priority = core::cell::Cell::new(#logical_prio); + let ref #priority = rtfm::export::Priority::new(#logical_prio); rtfm::export::run(|| { rtfm::export::sys_tick(#tq { #priority }, |task, index| { @@ -1933,7 +1968,7 @@ fn mk_resource( #(#cfgs)* pub struct #struct_<'a> { #[doc(hidden)] - pub #priority: &'a core::cell::Cell, + pub #priority: &'a rtfm::export::Priority, } )); @@ -1942,7 +1977,7 @@ fn mk_resource( items.push(quote!( #(#cfgs)* struct #struct_<'a> { - #priority: &'a core::cell::Cell, + #priority: &'a rtfm::export::Priority, } )); @@ -2017,35 +2052,31 @@ impl IdentGenerator { let rng = rand::rngs::SmallRng::from_seed(seed); - IdentGenerator { - call_count: 0, - rng, - } + IdentGenerator { call_count: 0, rng } } - fn mk_ident(&mut self, name: Option<&str>) -> Ident { - let n; + fn mk_ident(&mut self, name: Option<&str>, random: bool) -> Ident { let s = if let Some(name) = name { - n = 4; format!("{}_", name) } else { - let crate_name = env!("CARGO_PKG_NAME").replace("-", "_").to_lowercase(); - n = 4; - format!("{}__internal__", crate_name) + "__rtfm_internal_".to_string() }; - let mut s = format!("{}{}_", s, self.call_count); + let mut s = format!("{}{}", s, self.call_count); + self.call_count += 1; + + if random { + s.push('_'); - for i in 0..n { - if i == 0 || self.rng.gen() { - s.push(('a' as u8 + self.rng.gen::() % 25) as char) - } else { - s.push(('0' as u8 + self.rng.gen::() % 10) as char) + for i in 0..4 { + if i == 0 || self.rng.gen() { + s.push(('a' as u8 + self.rng.gen::() % 25) as char) + } else { + s.push(('0' as u8 + self.rng.gen::() % 10) as char) + } } } - self.call_count += 1; - Ident::new(&s, Span::call_site()) } } -- cgit v1.2.3 From e5e54ee8f1b7afca614f642ee064a7f00a1f8548 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 16 Feb 2019 00:28:12 +0100 Subject: rebase fix --- macros/src/codegen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'macros/src/codegen.rs') diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs index 1405c2f..af09ad4 100644 --- a/macros/src/codegen.rs +++ b/macros/src/codegen.rs @@ -364,7 +364,7 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> (proc_macro2::Tok let (late_resources, late_resources_ident, ret) = if app.init.returns_late_resources { // create `LateResources` struct in the root of the crate - let ident = mk_ident(None); + let ident = ctxt.ident_gen.mk_ident(None, false); let fields = app .resources -- cgit v1.2.3