Skip to content

Commit

Permalink
feat(ast_codegen): add alignment and size data to the schema. (#4615)
Browse files Browse the repository at this point in the history
This PR generates the layouts in the schema but doesn't use it to reorder.
  • Loading branch information
rzvxa committed Aug 3, 2024
1 parent 3f53b6f commit 0c52c0d
Show file tree
Hide file tree
Showing 11 changed files with 3,038 additions and 9 deletions.
2,249 changes: 2,249 additions & 0 deletions crates/oxc_ast/src/generated/assert_layouts.rs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions crates/oxc_ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub mod syntax_directed_operations;
mod trivia;

mod generated {
#[cfg(test)]
pub mod assert_layouts;
pub mod ast_builder;
pub mod ast_kind;
pub mod span;
Expand Down
61 changes: 58 additions & 3 deletions tasks/ast_codegen/src/defs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{REnum, RStruct, RType};
use crate::{schema::Inherit, util::TypeExt, TypeName};
use crate::{layout::KnownLayout, schema::Inherit, util::TypeExt, TypeName};
use quote::ToTokens;
use serde::Serialize;

Expand All @@ -9,11 +9,26 @@ pub enum TypeDef {
Enum(EnumDef),
}

impl TypeDef {
pub fn name(&self) -> &String {
match self {
Self::Struct(it) => &it.name,
Self::Enum(it) => &it.name,
}
}
}

#[derive(Debug, Serialize)]
pub struct StructDef {
pub name: TypeName,
pub fields: Vec<FieldDef>,
pub has_lifetime: bool,
pub size_64: usize,
pub align_64: usize,
pub offsets_64: Option<Vec<usize>>,
pub size_32: usize,
pub align_32: usize,
pub offsets_32: Option<Vec<usize>>,
}

#[derive(Debug, Serialize)]
Expand All @@ -23,6 +38,12 @@ pub struct EnumDef {
/// For `@inherits` inherited enum variants
pub inherits: Vec<EnumInheritDef>,
pub has_lifetime: bool,
pub size_64: usize,
pub align_64: usize,
pub offsets_64: Option<Vec<usize>>,
pub size_32: usize,
pub align_32: usize,
pub offsets_32: Option<Vec<usize>>,
}

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

impl From<&REnum> for EnumDef {
fn from(it @ REnum { item, meta }: &REnum) -> Self {
let (size_64, align_64, offsets_64) = meta
.layout_64
.clone()
.layout()
.map_or_else(|| panic!("Uncalculated layout on {}!", item.ident), KnownLayout::unpack);
let (size_32, align_32, offsets_32) = meta
.layout_32
.clone()
.layout()
.map_or_else(|| panic!("Uncalculated layout on {}!", item.ident), KnownLayout::unpack);
Self {
name: it.ident().to_string(),
variants: item.variants.iter().map(Into::into).collect(),
has_lifetime: item.generics.lifetimes().count() > 0,
inherits: meta.inherits.iter().map(Into::into).collect(),
has_lifetime: item.generics.lifetimes().count() > 0,

size_64,
align_64,
offsets_64,
size_32,
align_32,
offsets_32,
}
}
}

impl From<&RStruct> for StructDef {
fn from(it @ RStruct { item, .. }: &RStruct) -> Self {
fn from(it @ RStruct { item, meta }: &RStruct) -> Self {
let (size_64, align_64, offsets_64) = meta
.layout_64
.clone()
.layout()
.map_or_else(|| panic!("Uncalculated layout on {}!", item.ident), KnownLayout::unpack);
let (size_32, align_32, offsets_32) = meta
.layout_32
.clone()
.layout()
.map_or_else(|| panic!("Uncalculated layout on {}!", item.ident), KnownLayout::unpack);
Self {
name: it.ident().to_string(),
fields: item.fields.iter().map(Into::into).collect(),
has_lifetime: item.generics.lifetimes().count() > 0,

size_64,
align_64,
offsets_64,
size_32,
align_32,
offsets_32,
}
}
}
Expand Down
118 changes: 118 additions & 0 deletions tasks/ast_codegen/src/generators/assert_layouts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{PathArguments, Type};

use crate::{
defs::{FieldDef, TypeDef},
output, CodegenCtx, Generator, GeneratorOutput,
};

use super::{define_generator, generated_header};

define_generator! {
pub struct AssertLayouts;
}

impl Generator for AssertLayouts {
fn name(&self) -> &'static str {
stringify!(AssertLayouts)
}

fn generate(&mut self, ctx: &CodegenCtx) -> GeneratorOutput {
let (assertions_64, assertions_32) = ctx
.schema
.borrow()
.definitions
.iter()
.map(|def| {
let typ =
ctx.find(def.name()).and_then(|ty| ty.borrow().as_type()).map(|mut ty| {
if let Type::Path(ty) = &mut ty {
if let Some(seg) = ty.path.segments.first_mut() {
seg.arguments = PathArguments::None;
}
}
ty
});
let typ = typ.unwrap();
assert_type(&typ, def)
})
.collect::<(Vec<TokenStream>, Vec<TokenStream>)>();

let header = generated_header!();

GeneratorOutput::Stream((
output(crate::AST_CRATE, "assert_layouts.rs"),
quote! {
#header

use std::mem::{align_of, offset_of, size_of};

endl!();

use crate::ast::*;

endl!();

#[cfg(target_pointer_width = "64")]
const _: () = { #(#assertions_64)* };
endl!();

#[cfg(target_pointer_width = "32")]
const _: () = { #(#assertions_32)* };
endl!();

#[cfg(not(any(target_pointer_width = "64", target_pointer_width = "32")))]
const _: () = panic!("Platforms with pointer width other than 64 or 32 bit are not supported");
},
))
}
}

fn assert_type(ty: &Type, def: &TypeDef) -> (TokenStream, TokenStream) {
match def {
TypeDef::Struct(def) => (
with_offsets_assertion(
assert_size_align(ty, def.size_64, def.align_64),
ty,
&def.fields,
def.offsets_64.as_deref(),
),
with_offsets_assertion(
assert_size_align(ty, def.size_32, def.align_32),
ty,
&def.fields,
def.offsets_64.as_deref(),
),
),
TypeDef::Enum(def) => (
assert_size_align(ty, def.size_64, def.align_64),
assert_size_align(ty, def.size_32, def.align_32),
),
}
}

fn assert_size_align(ty: &Type, size: usize, align: usize) -> TokenStream {
quote! {
assert!(size_of::<#ty>() == #size);
assert!(align_of::<#ty>() == #align);
}
}

fn with_offsets_assertion(
mut tk: TokenStream,
ty: &Type,
fields: &[FieldDef],
offsets: Option<&[usize]>,
) -> TokenStream {
let Some(offsets) = offsets else { return tk };

let assertions = fields.iter().zip(offsets).map(|(field, offset)| {
let field = field.name.as_ref().map(|it| format_ident!("{it}"));
quote! {
assert!(offset_of!(#ty, #field) == #offset);
}
});
tk.extend(assertions);
tk
}
2 changes: 2 additions & 0 deletions tasks/ast_codegen/src/generators/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod assert_layouts;
mod ast_builder;
mod ast_kind;
mod impl_get_span;
Expand Down Expand Up @@ -39,6 +40,7 @@ macro_rules! generated_header {
pub(crate) use generated_header;
pub(crate) use insert;

pub use assert_layouts::AssertLayouts;
pub use ast_builder::AstBuilderGenerator;
pub use ast_kind::AstKindGenerator;
pub use impl_get_span::ImplGetSpanGenerator;
Expand Down
Loading

0 comments on commit 0c52c0d

Please sign in to comment.