Skip to content

Commit 01338e2

Browse files
committed
feat(ast_codegen): add alignment and size data to the schema.
1 parent 3f53b6f commit 01338e2

File tree

11 files changed

+3026
-9
lines changed

11 files changed

+3026
-9
lines changed

crates/oxc_ast/src/generated/assert_layouts.rs

Lines changed: 2245 additions & 0 deletions
Large diffs are not rendered by default.

crates/oxc_ast/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pub mod syntax_directed_operations;
3737
mod trivia;
3838

3939
mod generated {
40+
#[cfg(test)]
41+
pub mod assert_layouts;
4042
pub mod ast_builder;
4143
pub mod ast_kind;
4244
pub mod span;

tasks/ast_codegen/src/defs.rs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{REnum, RStruct, RType};
2-
use crate::{schema::Inherit, util::TypeExt, TypeName};
2+
use crate::{layout::KnownLayout, schema::Inherit, util::TypeExt, TypeName};
33
use quote::ToTokens;
44
use serde::Serialize;
55

@@ -9,11 +9,26 @@ pub enum TypeDef {
99
Enum(EnumDef),
1010
}
1111

12+
impl TypeDef {
13+
pub fn name(&self) -> &String {
14+
match self {
15+
Self::Struct(it) => &it.name,
16+
Self::Enum(it) => &it.name,
17+
}
18+
}
19+
}
20+
1221
#[derive(Debug, Serialize)]
1322
pub struct StructDef {
1423
pub name: TypeName,
1524
pub fields: Vec<FieldDef>,
1625
pub has_lifetime: bool,
26+
pub size_64: usize,
27+
pub align_64: usize,
28+
pub offsets_64: Option<Vec<usize>>,
29+
pub size_32: usize,
30+
pub align_32: usize,
31+
pub offsets_32: Option<Vec<usize>>,
1732
}
1833

1934
#[derive(Debug, Serialize)]
@@ -23,6 +38,12 @@ pub struct EnumDef {
2338
/// For `@inherits` inherited enum variants
2439
pub inherits: Vec<EnumInheritDef>,
2540
pub has_lifetime: bool,
41+
pub size_64: usize,
42+
pub align_64: usize,
43+
pub offsets_64: Option<Vec<usize>>,
44+
pub size_32: usize,
45+
pub align_32: usize,
46+
pub offsets_32: Option<Vec<usize>>,
2647
}
2748

2849
#[derive(Debug, Serialize)]
@@ -57,21 +78,55 @@ impl From<&RType> for Option<TypeDef> {
5778

5879
impl From<&REnum> for EnumDef {
5980
fn from(it @ REnum { item, meta }: &REnum) -> Self {
81+
let (size_64, align_64, offsets_64) = meta
82+
.layout_64
83+
.clone()
84+
.layout()
85+
.map_or_else(|| panic!("Uncalculated layout on {}!", item.ident), KnownLayout::unpack);
86+
let (size_32, align_32, offsets_32) = meta
87+
.layout_32
88+
.clone()
89+
.layout()
90+
.map_or_else(|| panic!("Uncalculated layout on {}!", item.ident), KnownLayout::unpack);
6091
Self {
6192
name: it.ident().to_string(),
6293
variants: item.variants.iter().map(Into::into).collect(),
63-
has_lifetime: item.generics.lifetimes().count() > 0,
6494
inherits: meta.inherits.iter().map(Into::into).collect(),
95+
has_lifetime: item.generics.lifetimes().count() > 0,
96+
97+
size_64,
98+
align_64,
99+
offsets_64,
100+
size_32,
101+
align_32,
102+
offsets_32,
65103
}
66104
}
67105
}
68106

69107
impl From<&RStruct> for StructDef {
70-
fn from(it @ RStruct { item, .. }: &RStruct) -> Self {
108+
fn from(it @ RStruct { item, meta }: &RStruct) -> Self {
109+
let (size_64, align_64, offsets_64) = meta
110+
.layout_64
111+
.clone()
112+
.layout()
113+
.map_or_else(|| panic!("Uncalculated layout on {}!", item.ident), KnownLayout::unpack);
114+
let (size_32, align_32, offsets_32) = meta
115+
.layout_32
116+
.clone()
117+
.layout()
118+
.map_or_else(|| panic!("Uncalculated layout on {}!", item.ident), KnownLayout::unpack);
71119
Self {
72120
name: it.ident().to_string(),
73121
fields: item.fields.iter().map(Into::into).collect(),
74122
has_lifetime: item.generics.lifetimes().count() > 0,
123+
124+
size_64,
125+
align_64,
126+
offsets_64,
127+
size_32,
128+
align_32,
129+
offsets_32,
75130
}
76131
}
77132
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use proc_macro2::TokenStream;
2+
use quote::{format_ident, quote};
3+
use syn::{PathArguments, Type};
4+
5+
use crate::{
6+
defs::{FieldDef, TypeDef},
7+
output, CodegenCtx, Generator, GeneratorOutput,
8+
};
9+
10+
use super::{define_generator, generated_header};
11+
12+
define_generator! {
13+
pub struct AssertLayouts;
14+
}
15+
16+
impl Generator for AssertLayouts {
17+
fn name(&self) -> &'static str {
18+
stringify!(AssertLayouts)
19+
}
20+
21+
fn generate(&mut self, ctx: &CodegenCtx) -> GeneratorOutput {
22+
let (assertions_64, assertions_32) = ctx
23+
.schema
24+
.borrow()
25+
.definitions
26+
.iter()
27+
.map(|def| {
28+
let typ =
29+
ctx.find(def.name()).and_then(|ty| ty.borrow().as_type()).map(|mut ty| {
30+
if let Type::Path(ty) = &mut ty {
31+
if let Some(seg) = ty.path.segments.first_mut() {
32+
seg.arguments = PathArguments::None;
33+
}
34+
}
35+
ty
36+
});
37+
let typ = typ.unwrap();
38+
assert_type(&typ, def)
39+
})
40+
.collect::<(Vec<TokenStream>, Vec<TokenStream>)>();
41+
42+
let header = generated_header!();
43+
44+
GeneratorOutput::Stream((
45+
output(crate::AST_CRATE, "assert_layouts.rs"),
46+
quote! {
47+
#header
48+
49+
use crate::ast::*;
50+
51+
endl!();
52+
53+
#[cfg(target_pointer_width = "64")]
54+
const _: () = { #(#assertions_64)* };
55+
#[cfg(target_pointer_width = "32")]
56+
const _: () = { #(#assertions_32)* };
57+
#[cfg(not(any(target_pointer_width = "64", target_pointer_width = "32")))]
58+
const _: () = panic!("Platforms with pointer width other than 64 or 32 bit are not supported");
59+
},
60+
))
61+
}
62+
}
63+
64+
fn assert_type(ty: &Type, def: &TypeDef) -> (TokenStream, TokenStream) {
65+
match def {
66+
TypeDef::Struct(def) => (
67+
with_offsets_assertion(
68+
assert_size_align(ty, def.size_64, def.align_64),
69+
ty,
70+
&def.fields,
71+
def.offsets_64.as_deref(),
72+
),
73+
with_offsets_assertion(
74+
assert_size_align(ty, def.size_32, def.align_32),
75+
ty,
76+
&def.fields,
77+
def.offsets_64.as_deref(),
78+
),
79+
),
80+
TypeDef::Enum(def) => (
81+
assert_size_align(ty, def.size_64, def.align_64),
82+
assert_size_align(ty, def.size_32, def.align_32),
83+
),
84+
}
85+
}
86+
87+
fn assert_size_align(ty: &Type, size: usize, align: usize) -> TokenStream {
88+
quote! {
89+
assert!(size_of::<#ty>() == #size);
90+
assert!(align_of::<#ty>() == #align);
91+
}
92+
}
93+
94+
fn with_offsets_assertion(
95+
mut tk: TokenStream,
96+
ty: &Type,
97+
fields: &[FieldDef],
98+
offsets: Option<&[usize]>,
99+
) -> TokenStream {
100+
let Some(offsets) = offsets else { return tk };
101+
102+
let assertions = fields.iter().zip(offsets).map(|(field, offset)| {
103+
let field = field.name.as_ref().map(|it| format_ident!("{it}"));
104+
quote! {
105+
assert!(std::mem::offset_of!(#ty, #field) == #offset);
106+
}
107+
});
108+
tk.extend(assertions);
109+
tk
110+
}

tasks/ast_codegen/src/generators/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod assert_layouts;
12
mod ast_builder;
23
mod ast_kind;
34
mod impl_get_span;
@@ -39,6 +40,7 @@ macro_rules! generated_header {
3940
pub(crate) use generated_header;
4041
pub(crate) use insert;
4142

43+
pub use assert_layouts::AssertLayouts;
4244
pub use ast_builder::AstBuilderGenerator;
4345
pub use ast_kind::AstKindGenerator;
4446
pub use impl_get_span::ImplGetSpanGenerator;

0 commit comments

Comments
 (0)