Skip to content

Commit

Permalink
perf(span): align Span same as usize
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Jan 6, 2025
1 parent cd0c2dc commit 2135503
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 48 deletions.
76 changes: 38 additions & 38 deletions crates/oxc_ast/src/generated/assert_layouts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ use crate::ast::*;

#[cfg(target_pointer_width = "64")]
const _: () = {
assert!(size_of::<BooleanLiteral>() == 12usize);
assert!(align_of::<BooleanLiteral>() == 4usize);
assert!(size_of::<BooleanLiteral>() == 16usize);
assert!(align_of::<BooleanLiteral>() == 8usize);
assert!(offset_of!(BooleanLiteral, span) == 0usize);
assert!(offset_of!(BooleanLiteral, value) == 8usize);

assert!(size_of::<NullLiteral>() == 8usize);
assert!(align_of::<NullLiteral>() == 4usize);
assert!(align_of::<NullLiteral>() == 8usize);
assert!(offset_of!(NullLiteral, span) == 0usize);

assert!(size_of::<NumericLiteral>() == 40usize);
Expand Down Expand Up @@ -88,7 +88,7 @@ const _: () = {
assert!(offset_of!(LabelIdentifier, name) == 8usize);

assert!(size_of::<ThisExpression>() == 8usize);
assert!(align_of::<ThisExpression>() == 4usize);
assert!(align_of::<ThisExpression>() == 8usize);
assert!(offset_of!(ThisExpression, span) == 0usize);

assert!(size_of::<ArrayExpression>() == 56usize);
Expand All @@ -101,7 +101,7 @@ const _: () = {
assert!(align_of::<ArrayExpressionElement>() == 8usize);

assert!(size_of::<Elision>() == 8usize);
assert!(align_of::<Elision>() == 4usize);
assert!(align_of::<Elision>() == 8usize);
assert!(offset_of!(Elision, span) == 0usize);

assert!(size_of::<ObjectExpression>() == 56usize);
Expand Down Expand Up @@ -312,7 +312,7 @@ const _: () = {
assert!(offset_of!(SequenceExpression, expressions) == 8usize);

assert!(size_of::<Super>() == 8usize);
assert!(align_of::<Super>() == 4usize);
assert!(align_of::<Super>() == 8usize);
assert!(offset_of!(Super, span) == 0usize);

assert!(size_of::<AwaitExpression>() == 24usize);
Expand Down Expand Up @@ -375,7 +375,7 @@ const _: () = {
assert!(offset_of!(VariableDeclarator, definite) == 64usize);

assert!(size_of::<EmptyStatement>() == 8usize);
assert!(align_of::<EmptyStatement>() == 4usize);
assert!(align_of::<EmptyStatement>() == 8usize);
assert!(offset_of!(EmptyStatement, span) == 0usize);

assert!(size_of::<ExpressionStatement>() == 24usize);
Expand Down Expand Up @@ -499,7 +499,7 @@ const _: () = {
assert!(offset_of!(CatchParameter, pattern) == 8usize);

assert!(size_of::<DebuggerStatement>() == 8usize);
assert!(align_of::<DebuggerStatement>() == 4usize);
assert!(align_of::<DebuggerStatement>() == 8usize);
assert!(offset_of!(DebuggerStatement, span) == 0usize);

assert!(size_of::<BindingPattern>() == 32usize);
Expand Down Expand Up @@ -898,59 +898,59 @@ const _: () = {
assert!(align_of::<TSTupleElement>() == 8usize);

assert!(size_of::<TSAnyKeyword>() == 8usize);
assert!(align_of::<TSAnyKeyword>() == 4usize);
assert!(align_of::<TSAnyKeyword>() == 8usize);
assert!(offset_of!(TSAnyKeyword, span) == 0usize);

assert!(size_of::<TSStringKeyword>() == 8usize);
assert!(align_of::<TSStringKeyword>() == 4usize);
assert!(align_of::<TSStringKeyword>() == 8usize);
assert!(offset_of!(TSStringKeyword, span) == 0usize);

assert!(size_of::<TSBooleanKeyword>() == 8usize);
assert!(align_of::<TSBooleanKeyword>() == 4usize);
assert!(align_of::<TSBooleanKeyword>() == 8usize);
assert!(offset_of!(TSBooleanKeyword, span) == 0usize);

assert!(size_of::<TSNumberKeyword>() == 8usize);
assert!(align_of::<TSNumberKeyword>() == 4usize);
assert!(align_of::<TSNumberKeyword>() == 8usize);
assert!(offset_of!(TSNumberKeyword, span) == 0usize);

assert!(size_of::<TSNeverKeyword>() == 8usize);
assert!(align_of::<TSNeverKeyword>() == 4usize);
assert!(align_of::<TSNeverKeyword>() == 8usize);
assert!(offset_of!(TSNeverKeyword, span) == 0usize);

assert!(size_of::<TSIntrinsicKeyword>() == 8usize);
assert!(align_of::<TSIntrinsicKeyword>() == 4usize);
assert!(align_of::<TSIntrinsicKeyword>() == 8usize);
assert!(offset_of!(TSIntrinsicKeyword, span) == 0usize);

assert!(size_of::<TSUnknownKeyword>() == 8usize);
assert!(align_of::<TSUnknownKeyword>() == 4usize);
assert!(align_of::<TSUnknownKeyword>() == 8usize);
assert!(offset_of!(TSUnknownKeyword, span) == 0usize);

assert!(size_of::<TSNullKeyword>() == 8usize);
assert!(align_of::<TSNullKeyword>() == 4usize);
assert!(align_of::<TSNullKeyword>() == 8usize);
assert!(offset_of!(TSNullKeyword, span) == 0usize);

assert!(size_of::<TSUndefinedKeyword>() == 8usize);
assert!(align_of::<TSUndefinedKeyword>() == 4usize);
assert!(align_of::<TSUndefinedKeyword>() == 8usize);
assert!(offset_of!(TSUndefinedKeyword, span) == 0usize);

assert!(size_of::<TSVoidKeyword>() == 8usize);
assert!(align_of::<TSVoidKeyword>() == 4usize);
assert!(align_of::<TSVoidKeyword>() == 8usize);
assert!(offset_of!(TSVoidKeyword, span) == 0usize);

assert!(size_of::<TSSymbolKeyword>() == 8usize);
assert!(align_of::<TSSymbolKeyword>() == 4usize);
assert!(align_of::<TSSymbolKeyword>() == 8usize);
assert!(offset_of!(TSSymbolKeyword, span) == 0usize);

assert!(size_of::<TSThisType>() == 8usize);
assert!(align_of::<TSThisType>() == 4usize);
assert!(align_of::<TSThisType>() == 8usize);
assert!(offset_of!(TSThisType, span) == 0usize);

assert!(size_of::<TSObjectKeyword>() == 8usize);
assert!(align_of::<TSObjectKeyword>() == 4usize);
assert!(align_of::<TSObjectKeyword>() == 8usize);
assert!(offset_of!(TSObjectKeyword, span) == 0usize);

assert!(size_of::<TSBigIntKeyword>() == 8usize);
assert!(align_of::<TSBigIntKeyword>() == 4usize);
assert!(align_of::<TSBigIntKeyword>() == 8usize);
assert!(offset_of!(TSBigIntKeyword, span) == 0usize);

assert!(size_of::<TSTypeReference>() == 32usize);
Expand Down Expand Up @@ -1272,7 +1272,7 @@ const _: () = {
assert!(offset_of!(JSDocNonNullableType, postfix) == 24usize);

assert!(size_of::<JSDocUnknownType>() == 8usize);
assert!(align_of::<JSDocUnknownType>() == 4usize);
assert!(align_of::<JSDocUnknownType>() == 8usize);
assert!(offset_of!(JSDocUnknownType, span) == 0usize);

assert!(size_of::<JSXElement>() == 56usize);
Expand Down Expand Up @@ -1303,11 +1303,11 @@ const _: () = {
assert!(offset_of!(JSXFragment, children) == 24usize);

assert!(size_of::<JSXOpeningFragment>() == 8usize);
assert!(align_of::<JSXOpeningFragment>() == 4usize);
assert!(align_of::<JSXOpeningFragment>() == 8usize);
assert!(offset_of!(JSXOpeningFragment, span) == 0usize);

assert!(size_of::<JSXClosingFragment>() == 8usize);
assert!(align_of::<JSXClosingFragment>() == 4usize);
assert!(align_of::<JSXClosingFragment>() == 8usize);
assert!(offset_of!(JSXClosingFragment, span) == 0usize);

assert!(size_of::<JSXElementName>() == 16usize);
Expand Down Expand Up @@ -1337,7 +1337,7 @@ const _: () = {
assert!(align_of::<JSXExpression>() == 8usize);

assert!(size_of::<JSXEmptyExpression>() == 8usize);
assert!(align_of::<JSXEmptyExpression>() == 4usize);
assert!(align_of::<JSXEmptyExpression>() == 8usize);
assert!(offset_of!(JSXEmptyExpression, span) == 0usize);

assert!(size_of::<JSXAttributeItem>() == 16usize);
Expand Down Expand Up @@ -1385,7 +1385,7 @@ const _: () = {
assert!(align_of::<CommentPosition>() == 1usize);

assert!(size_of::<Comment>() == 16usize);
assert!(align_of::<Comment>() == 4usize);
assert!(align_of::<Comment>() == 8usize);
assert!(offset_of!(Comment, span) == 0usize);
assert!(offset_of!(Comment, attached_to) == 8usize);
assert!(offset_of!(Comment, kind) == 12usize);
Expand Down Expand Up @@ -1415,7 +1415,7 @@ const _: () = {
assert!(align_of::<UpdateOperator>() == 1usize);

assert!(size_of::<Span>() == 8usize);
assert!(align_of::<Span>() == 4usize);
assert!(align_of::<Span>() == 8usize);
assert!(offset_of!(Span, start) == 0usize);
assert!(offset_of!(Span, end) == 4usize);

Expand Down Expand Up @@ -1449,8 +1449,8 @@ const _: () = {
assert!(size_of::<Term>() == 16usize);
assert!(align_of::<Term>() == 8usize);

assert!(size_of::<BoundaryAssertion>() == 12usize);
assert!(align_of::<BoundaryAssertion>() == 4usize);
assert!(size_of::<BoundaryAssertion>() == 16usize);
assert!(align_of::<BoundaryAssertion>() == 8usize);
assert!(offset_of!(BoundaryAssertion, span) == 0usize);
assert!(offset_of!(BoundaryAssertion, kind) == 8usize);

Expand All @@ -1475,16 +1475,16 @@ const _: () = {
assert!(offset_of!(Quantifier, body) == 40usize);

assert!(size_of::<Character>() == 16usize);
assert!(align_of::<Character>() == 4usize);
assert!(align_of::<Character>() == 8usize);
assert!(offset_of!(Character, span) == 0usize);
assert!(offset_of!(Character, kind) == 8usize);
assert!(offset_of!(Character, value) == 12usize);

assert!(size_of::<CharacterKind>() == 1usize);
assert!(align_of::<CharacterKind>() == 1usize);

assert!(size_of::<CharacterClassEscape>() == 12usize);
assert!(align_of::<CharacterClassEscape>() == 4usize);
assert!(size_of::<CharacterClassEscape>() == 16usize);
assert!(align_of::<CharacterClassEscape>() == 8usize);
assert!(offset_of!(CharacterClassEscape, span) == 0usize);
assert!(offset_of!(CharacterClassEscape, kind) == 8usize);

Expand All @@ -1500,7 +1500,7 @@ const _: () = {
assert!(offset_of!(UnicodePropertyEscape, value) == 32usize);

assert!(size_of::<Dot>() == 8usize);
assert!(align_of::<Dot>() == 4usize);
assert!(align_of::<Dot>() == 8usize);
assert!(offset_of!(Dot, span) == 0usize);

assert!(size_of::<CharacterClass>() == 48usize);
Expand All @@ -1518,7 +1518,7 @@ const _: () = {
assert!(align_of::<CharacterClassContents>() == 8usize);

assert!(size_of::<CharacterClassRange>() == 40usize);
assert!(align_of::<CharacterClassRange>() == 4usize);
assert!(align_of::<CharacterClassRange>() == 8usize);
assert!(offset_of!(CharacterClassRange, span) == 0usize);
assert!(offset_of!(CharacterClassRange, min) == 8usize);
assert!(offset_of!(CharacterClassRange, max) == 24usize);
Expand Down Expand Up @@ -1548,7 +1548,7 @@ const _: () = {
assert!(offset_of!(IgnoreGroup, body) == 24usize);

assert!(size_of::<Modifiers>() == 16usize);
assert!(align_of::<Modifiers>() == 4usize);
assert!(align_of::<Modifiers>() == 8usize);
assert!(offset_of!(Modifiers, span) == 0usize);
assert!(offset_of!(Modifiers, enabling) == 8usize);
assert!(offset_of!(Modifiers, disabling) == 11usize);
Expand All @@ -1559,8 +1559,8 @@ const _: () = {
assert!(offset_of!(Modifier, multiline) == 1usize);
assert!(offset_of!(Modifier, sticky) == 2usize);

assert!(size_of::<IndexedReference>() == 12usize);
assert!(align_of::<IndexedReference>() == 4usize);
assert!(size_of::<IndexedReference>() == 16usize);
assert!(align_of::<IndexedReference>() == 8usize);
assert!(offset_of!(IndexedReference, span) == 0usize);
assert!(offset_of!(IndexedReference, index) == 8usize);

Expand Down
80 changes: 72 additions & 8 deletions crates/oxc_span/src/span/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::ops::{Index, IndexMut, Range};
use std::{
fmt::{self, Debug},
hash::{Hash, Hasher},
ops::{Index, IndexMut, Range},
};

use miette::{LabeledSpan, SourceOffset, SourceSpan};

Expand All @@ -9,6 +13,18 @@ pub use types::Span;
/// An Empty span useful for creating AST nodes.
pub const SPAN: Span = Span::new(0, 0);

/// Zero-sized type which has pointer alignment (8 on 64-bit, 4 on 32-bit).
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
struct PointerAlign([usize; 0]);

impl PointerAlign {
#[inline]
const fn new() -> Self {
Self([])
}
}

impl Span {
/// Create a new [`Span`] from a start and end position.
///
Expand All @@ -19,7 +35,7 @@ impl Span {
///
#[inline]
pub const fn new(start: u32, end: u32) -> Self {
Self { start, end }
Self { start, end, _align: PointerAlign::new() }
}

/// Create a new empty [`Span`] that starts and ends at an offset position.
Expand All @@ -34,7 +50,7 @@ impl Span {
/// assert_eq!(fifth, Span::new(5, 5));
/// ```
pub fn empty(at: u32) -> Self {
Self { start: at, end: at }
Self::new(at, at)
}

/// Create a new [`Span`] starting at `start` and covering `size` bytes.
Expand Down Expand Up @@ -362,6 +378,23 @@ impl From<Span> for LabeledSpan {
}
}

// Skip hashing `_align` field
impl Hash for Span {
#[inline] // We exclusively use `FxHasher`, which produces small output hashing `u32`s
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.start.hash(hasher);
self.end.hash(hasher);
}
}

// Skip `_align` field in `Debug` output
#[expect(clippy::missing_fields_in_debug)]
impl Debug for Span {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Span").field("start", &self.start).field("end", &self.end).finish()
}
}

/// Get the span for an AST node
pub trait GetSpan {
/// Get the [`Span`] for an AST node
Expand Down Expand Up @@ -413,13 +446,29 @@ mod test {
}

#[test]
#[expect(clippy::items_after_statements)]
fn test_hash() {
use std::hash::{DefaultHasher, Hash, Hasher};
let mut first = DefaultHasher::new();
let mut second = DefaultHasher::new();
Span::new(0, 5).hash(&mut first);
Span::new(0, 5).hash(&mut second);
assert_eq!(first.finish(), second.finish());
fn hash<T: Hash>(value: T) -> u64 {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
hasher.finish()
}

let first_hash = hash(Span::new(0, 5));
let second_hash = hash(Span::new(0, 5));
assert_eq!(first_hash, second_hash);

// Check `_align` field does not alter hash
#[derive(Hash)]
#[repr(C)]
struct PlainSpan {
start: u32,
end: u32,
}

let plain_hash = hash(PlainSpan { start: 0, end: 5 });
assert_eq!(plain_hash, first_hash);
}

#[test]
Expand Down Expand Up @@ -481,3 +530,18 @@ mod test {
let _ = span.shrink(5);
}
}

#[cfg(test)]
mod size_asserts {
use std::mem::{align_of, size_of};

use super::Span;

const _: () = assert!(size_of::<Span>() == 8);

#[cfg(target_pointer_width = "64")]
const _: () = assert!(align_of::<Span>() == 8);

#[cfg(not(target_pointer_width = "64"))]
const _: () = assert!(align_of::<Span>() == 4);
}
Loading

0 comments on commit 2135503

Please sign in to comment.