1use super::TrapCode;
4use crate::HashMap;
5use crate::entity::{self, PrimaryMap};
6pub use crate::machinst::MachMemFlags;
7use alloc::borrow::Cow;
8use core::fmt;
9use core::hash::{Hash, Hasher};
10use core::ops::Index;
11use core::str::FromStr;
12use cranelift_entity::{entity_impl, packed_option::PackedOption};
13
14#[cfg(feature = "enable-serde")]
15use serde_derive::{Deserialize, Serialize};
16
17#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
19pub enum Endianness {
20 Little,
22 Big,
24}
25
26#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
31#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
32pub struct AliasRegion(u32);
33entity_impl!(AliasRegion, "region");
34
35#[derive(Clone, Debug, PartialEq, Eq, Hash)]
37#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
38pub struct AliasRegionData {
39 pub user_id: u32,
49
50 pub description: Cow<'static, str>,
55}
56
57#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
64#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
65pub struct MemFlags(u16);
66
67impl MemFlags {
68 pub fn with_number(n: u32) -> Option<Self> {
72 let val = u16::try_from(n).ok()?;
73 if val == u16::MAX {
74 None
75 } else {
76 Some(Self(val))
77 }
78 }
79}
80
81impl entity::EntityRef for MemFlags {
82 #[inline]
83 fn new(index: usize) -> Self {
84 let val = u16::try_from(index).expect("MemFlags index overflow");
85 Self(val)
86 }
87
88 #[inline]
89 fn index(self) -> usize {
90 usize::from(self.0)
91 }
92}
93
94impl entity::packed_option::ReservedValue for MemFlags {
95 #[inline]
96 fn reserved_value() -> Self {
97 Self(u16::MAX)
98 }
99
100 #[inline]
101 fn is_reserved_value(&self) -> bool {
102 self.0 == u16::MAX
103 }
104}
105
106impl MemFlags {
107 #[inline]
109 pub fn from_u32(x: u32) -> Self {
110 Self(u16::try_from(x).unwrap())
111 }
112
113 #[inline]
115 pub fn as_u32(self) -> u32 {
116 u32::from(self.0)
117 }
118
119 #[inline]
121 pub fn as_bits(self) -> u32 {
122 u32::from(self.0)
123 }
124
125 #[inline]
127 pub fn from_bits(x: u32) -> Self {
128 Self(u16::try_from(x).unwrap())
129 }
130}
131
132impl fmt::Display for MemFlags {
133 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134 write!(f, "memflags{}", self.0)
135 }
136}
137
138impl fmt::Debug for MemFlags {
139 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140 (self as &dyn fmt::Display).fmt(f)
141 }
142}
143
144#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
155#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
156pub struct MemFlagsData {
157 flags: MachMemFlags,
159
160 region: PackedOption<AliasRegion>,
162}
163
164const fn no_alias_region() -> PackedOption<AliasRegion> {
165 PackedOption::new(AliasRegion(u32::MAX))
166}
167
168impl MemFlagsData {
169 pub const fn new() -> Self {
171 Self {
172 flags: MachMemFlags::new(),
173 region: no_alias_region(),
174 }
175 }
176
177 pub const fn trusted() -> Self {
180 Self::new().with_notrap().with_aligned()
181 }
182
183 pub fn alias_region(self) -> Option<AliasRegion> {
185 self.region.expand()
186 }
187
188 pub fn with_alias_region(mut self, region: Option<AliasRegion>) -> Self {
190 self.region = region.into();
191 self
192 }
193
194 pub fn set_alias_region(&mut self, region: Option<AliasRegion>) {
196 self.region = region.into();
197 }
198
199 pub fn set_by_name(&mut self, name: &str) -> Result<bool, &'static str> {
209 *self = match name {
210 "notrap" => self.with_trap_code(None),
211 "aligned" => self.with_aligned(),
212 "readonly" => self.with_readonly(),
213 "little" => {
214 if self.flags.explicit_endianness() == Some(Endianness::Big) {
215 return Err("cannot set both big and little endian bits");
216 }
217 self.with_endianness(Endianness::Little)
218 }
219 "big" => {
220 if self.flags.explicit_endianness() == Some(Endianness::Little) {
221 return Err("cannot set both big and little endian bits");
222 }
223 self.with_endianness(Endianness::Big)
224 }
225 "can_move" => self.with_can_move(),
226
227 other => match TrapCode::from_str(other) {
228 Ok(code) => self.with_trap_code(Some(code)),
229 Err(()) => return Ok(false),
230 },
231 };
232 Ok(true)
233 }
234
235 pub const fn endianness(self, native_endianness: Endianness) -> Endianness {
241 self.flags.endianness(native_endianness)
242 }
243
244 pub const fn explicit_endianness(self) -> Option<Endianness> {
249 self.flags.explicit_endianness()
250 }
251
252 pub fn set_endianness(&mut self, endianness: Endianness) {
254 *self = self.with_endianness(endianness);
255 }
256
257 pub const fn with_endianness(mut self, endianness: Endianness) -> Self {
259 self.flags = self.flags.with_endianness(endianness);
260 self
261 }
262
263 pub const fn notrap(self) -> bool {
280 self.trap_code().is_none()
281 }
282
283 pub fn set_notrap(&mut self) {
285 *self = self.with_notrap();
286 }
287
288 pub const fn with_notrap(self) -> Self {
291 self.with_trap_code(None)
292 }
293
294 pub const fn can_move(self) -> bool {
310 self.flags.can_move()
311 }
312
313 pub const fn set_can_move(&mut self) {
315 *self = self.with_can_move();
316 }
317
318 pub const fn with_can_move(mut self) -> Self {
320 self.flags = self.flags.with_can_move();
321 self
322 }
323
324 pub const fn aligned(self) -> bool {
330 self.flags.aligned()
331 }
332
333 pub fn set_aligned(&mut self) {
335 *self = self.with_aligned();
336 }
337
338 pub const fn with_aligned(mut self) -> Self {
340 self.flags = self.flags.with_aligned();
341 self
342 }
343
344 pub const fn readonly(self) -> bool {
350 self.flags.readonly()
351 }
352
353 pub fn set_readonly(&mut self) {
355 *self = self.with_readonly();
356 }
357
358 pub const fn with_readonly(mut self) -> Self {
360 self.flags = self.flags.with_readonly();
361 self
362 }
363 pub const fn trap_code(self) -> Option<TrapCode> {
367 self.flags.trap_code()
368 }
369
370 pub const fn with_trap_code(mut self, code: Option<TrapCode>) -> Self {
377 self.flags = self.flags.with_trap_code(code);
378 self
379 }
380}
381
382impl From<MemFlagsData> for MachMemFlags {
383 fn from(flags: MemFlagsData) -> Self {
384 flags.flags
385 }
386}
387
388impl From<MachMemFlags> for MemFlagsData {
389 fn from(flags: MachMemFlags) -> Self {
390 Self {
391 flags,
392 region: no_alias_region(),
393 }
394 }
395}
396
397impl fmt::Display for MemFlagsData {
398 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
399 write!(f, "{}", self.flags)?;
400 match self.alias_region() {
401 None => {}
402 Some(region) => write!(f, " {region}")?,
403 }
404 Ok(())
405 }
406}
407
408#[derive(Clone, Copy, Debug, PartialEq, Eq)]
409pub struct MemFlagsSetOverflow;
410
411#[derive(Clone, Debug)]
413#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
414pub struct MemFlagsSet {
415 mem_flags: PrimaryMap<MemFlags, MemFlagsData>,
416 dedupe_map: HashMap<MemFlagsData, MemFlags>,
417}
418
419impl PartialEq for MemFlagsSet {
420 fn eq(&self, other: &Self) -> bool {
421 self.mem_flags == other.mem_flags
422 }
423}
424
425impl Eq for MemFlagsSet {}
426
427impl Hash for MemFlagsSet {
428 fn hash<H: Hasher>(&self, state: &mut H) {
429 self.mem_flags.hash(state);
430 }
431}
432
433impl MemFlagsSet {
434 pub fn new() -> Self {
436 Self {
437 mem_flags: PrimaryMap::new(),
438 dedupe_map: HashMap::new(),
439 }
440 }
441
442 pub fn insert(&mut self, data: MemFlagsData) -> Result<MemFlags, MemFlagsSetOverflow> {
446 if let Some(&existing) = self.dedupe_map.get(&data) {
447 return Ok(existing);
448 }
449 let next = u32::try_from(self.mem_flags.len())
450 .ok()
451 .and_then(MemFlags::with_number)
452 .ok_or(MemFlagsSetOverflow)?;
453 let key = self.mem_flags.push(data);
454 debug_assert_eq!(key, next);
455 self.dedupe_map.insert(data, key);
456 Ok(key)
457 }
458
459 pub fn insert_unchecked(&mut self, data: MemFlagsData) -> MemFlags {
461 match self.insert(data) {
462 Ok(flags) => flags,
463 Err(_) => panic!("MemFlags index overflow"),
464 }
465 }
466
467 pub fn is_valid(&self, mf: MemFlags) -> bool {
469 self.mem_flags.is_valid(mf)
470 }
471
472 pub fn clear(&mut self) {
474 *self = Self::new();
475 }
476
477 pub fn get(&self, data: MemFlagsData) -> Option<MemFlags> {
479 self.dedupe_map.get(&data).copied()
480 }
481}
482
483impl Index<MemFlags> for MemFlagsSet {
486 type Output = MemFlagsData;
487
488 fn index(&self, mf: MemFlags) -> &MemFlagsData {
489 &self.mem_flags[mf]
490 }
491}
492
493#[derive(Clone, PartialEq)]
498#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
499pub struct AliasRegionSet {
500 alias_regions: PrimaryMap<AliasRegion, AliasRegionData>,
501 dedupe_map: HashMap<u32, AliasRegion>,
502}
503
504impl Hash for AliasRegionSet {
505 fn hash<H: Hasher>(&self, state: &mut H) {
506 self.alias_regions.hash(state);
507 }
508}
509
510impl AliasRegionSet {
511 pub fn new() -> Self {
513 Self {
514 alias_regions: PrimaryMap::new(),
515 dedupe_map: HashMap::new(),
516 }
517 }
518
519 pub fn insert(&mut self, data: AliasRegionData) -> AliasRegion {
524 if let Some(&existing) = self.dedupe_map.get(&data.user_id) {
525 return existing;
526 }
527 let user_id = data.user_id;
528 let key = self.alias_regions.push(data);
529 self.dedupe_map.insert(user_id, key);
530 key
531 }
532
533 pub fn push(&mut self, data: AliasRegionData) -> AliasRegion {
538 let user_id = data.user_id;
539 let key = self.alias_regions.push(data);
540 self.dedupe_map.insert(user_id, key);
541 key
542 }
543
544 pub fn contains(&self, user_id: u32) -> bool {
547 self.dedupe_map.contains_key(&user_id)
548 }
549
550 pub fn is_valid(&self, ar: AliasRegion) -> bool {
552 self.alias_regions.is_valid(ar)
553 }
554
555 pub fn len(&self) -> usize {
557 self.alias_regions.len()
558 }
559
560 pub fn iter(&self) -> impl Iterator<Item = (AliasRegion, &AliasRegionData)> {
562 self.alias_regions.iter()
563 }
564
565 pub fn clear(&mut self) {
567 self.alias_regions.clear();
568 self.dedupe_map.clear();
569 }
570}
571
572impl Index<AliasRegion> for AliasRegionSet {
575 type Output = AliasRegionData;
576
577 fn index(&self, ar: AliasRegion) -> &AliasRegionData {
578 &self.alias_regions[ar]
579 }
580}
581
582#[cfg(test)]
583mod tests {
584 use super::*;
585 use cranelift_entity::EntityRef;
586
587 #[test]
588 fn roundtrip_traps() {
589 for trap in TrapCode::non_user_traps().iter().copied() {
590 let _flags = MemFlagsData::new().with_trap_code(Some(trap));
591 }
592 let _flags = MemFlagsData::new().with_trap_code(None);
593 }
594
595 #[test]
596 fn cannot_set_big_and_little() {
597 let _big = MemFlagsData::new().with_endianness(Endianness::Big);
598
599 let _little = MemFlagsData::new().with_endianness(Endianness::Little);
600 }
601
602 #[test]
603 fn only_one_region() {
604 let region0 = AliasRegion::new(0);
605 let region1 = AliasRegion::new(1);
606 let flags = MemFlagsData::new().with_alias_region(Some(region0));
607 assert_eq!(flags.alias_region(), Some(region0));
608
609 let flags = flags.with_alias_region(Some(region1));
610 assert_eq!(flags.alias_region(), Some(region1));
611
612 let flags = flags.with_alias_region(None);
613 assert_eq!(flags.alias_region(), None);
614 }
615
616 #[test]
617 fn clear_removes_entries() {
618 let mut set = MemFlagsSet::new();
619 let trusted = set.insert(MemFlagsData::trusted()).unwrap();
620 let custom = MemFlagsData::new()
621 .with_endianness(Endianness::Big)
622 .with_alias_region(Some(AliasRegion::new(0)));
623 let custom_key = set.insert(custom).unwrap();
624 assert!(set.is_valid(trusted));
625 assert!(set.is_valid(custom_key));
626
627 set.clear();
628
629 assert!(!set.is_valid(trusted));
630 assert!(!set.is_valid(custom_key));
631 let trusted = set.insert(MemFlagsData::trusted()).unwrap();
632 assert_eq!(set[trusted], MemFlagsData::trusted());
633 }
634}