Skip to content

Commit 0c52c0d

Browse files
committed
feat(ast_codegen): add alignment and size data to the schema. (#4615)
This PR generates the layouts in the schema but doesn't use it to reorder.
1 parent 3f53b6f commit 0c52c0d

File tree

11 files changed

+3038
-9
lines changed

11 files changed

+3038
-9
lines changed

crates/oxc_ast/src/generated/assert_layouts.rs

Lines changed: 2249 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: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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 std::mem::{align_of, offset_of, size_of};
50+
51+
endl!();
52+
53+
use crate::ast::*;
54+
55+
endl!();
56+
57+
#[cfg(target_pointer_width = "64")]
58+
const _: () = { #(#assertions_64)* };
59+
endl!();
60+
61+
#[cfg(target_pointer_width = "32")]
62+
const _: () = { #(#assertions_32)* };
63+
endl!();
64+
65+
#[cfg(not(any(target_pointer_width = "64", target_pointer_width = "32")))]
66+
const _: () = panic!("Platforms with pointer width other than 64 or 32 bit are not supported");
67+
},
68+
))
69+
}
70+
}
71+
72+
fn assert_type(ty: &Type, def: &TypeDef) -> (TokenStream, TokenStream) {
73+
match def {
74+
TypeDef::Struct(def) => (
75+
with_offsets_assertion(
76+
assert_size_align(ty, def.size_64, def.align_64),
77+
ty,
78+
&def.fields,
79+
def.offsets_64.as_deref(),
80+
),
81+
with_offsets_assertion(
82+
assert_size_align(ty, def.size_32, def.align_32),
83+
ty,
84+
&def.fields,
85+
def.offsets_64.as_deref(),
86+
),
87+
),
88+
TypeDef::Enum(def) => (
89+
assert_size_align(ty, def.size_64, def.align_64),
90+
assert_size_align(ty, def.size_32, def.align_32),
91+
),
92+
}
93+
}
94+
95+
fn assert_size_align(ty: &Type, size: usize, align: usize) -> TokenStream {
96+
quote! {
97+
assert!(size_of::<#ty>() == #size);
98+
assert!(align_of::<#ty>() == #align);
99+
}
100+
}
101+
102+
fn with_offsets_assertion(
103+
mut tk: TokenStream,
104+
ty: &Type,
105+
fields: &[FieldDef],
106+
offsets: Option<&[usize]>,
107+
) -> TokenStream {
108+
let Some(offsets) = offsets else { return tk };
109+
110+
let assertions = fields.iter().zip(offsets).map(|(field, offset)| {
111+
let field = field.name.as_ref().map(|it| format_ident!("{it}"));
112+
quote! {
113+
assert!(offset_of!(#ty, #field) == #offset);
114+
}
115+
});
116+
tk.extend(assertions);
117+
tk
118+
}

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)