Skip to content

Commit

Permalink
Metadata generation progress (#2516)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored May 23, 2023
1 parent bb852f2 commit a900999
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 94 deletions.
2 changes: 1 addition & 1 deletion crates/libs/bindgen/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ fn gen_link(gen: &Gen, signature: &Signature, cfg: &Cfg) -> TokenStream {

let return_type = gen.return_sig(signature);

let vararg = if gen.sys && signature.vararg {
let vararg = if gen.sys && signature.call_flags.contains(MethodCallAttributes::VARARG) {
"...".into()
} else {
quote! {}
Expand Down
6 changes: 6 additions & 0 deletions crates/libs/metadata/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ impl MethodImplAttributes {
pub const PRESERVE_SIG: Self = Self(0x80);
}

flags!(MethodCallAttributes, u8);
impl MethodCallAttributes {
pub const HASTHIS: Self = Self(0x20);
pub const VARARG: Self = Self(0x05);
}

flags!(ParamAttributes, u16);
impl ParamAttributes {
pub const INPUT: Self = Self(0x1);
Expand Down
12 changes: 12 additions & 0 deletions crates/libs/metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,15 @@ macro_rules! flags {
}

pub(crate) use flags;

#[derive(Copy, Clone, Debug)]
pub enum Integer {
U8(u8),
I8(i8),
U16(u16),
I16(i16),
U32(u32),
I32(i32),
U64(u64),
I64(i64),
}
25 changes: 10 additions & 15 deletions crates/libs/metadata/src/reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub use type_name::*;

macro_rules! tables {
($($name:ident,)*) => ($(
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
pub struct $name(pub Row);
)*)
}
Expand Down Expand Up @@ -112,6 +112,7 @@ pub enum TypeKind {
Delegate,
}

#[derive(Debug)]
pub enum Value {
Bool(bool),
U8(u8),
Expand All @@ -129,22 +130,11 @@ pub enum Value {
Enum(TypeDef, Integer),
}

pub enum Integer {
U8(u8),
I8(i8),
U16(u16),
I16(i16),
U32(u32),
I32(i32),
U64(u64),
I64(i64),
}

pub struct Signature {
pub def: MethodDef,
pub params: Vec<SignatureParam>,
pub return_type: Type,
pub vararg: bool,
pub call_flags: MethodCallAttributes,
}

pub struct SignatureParam {
Expand Down Expand Up @@ -303,6 +293,11 @@ impl<'a> Reader<'a> {
// Attribute table queries
//

pub fn attribute_type_name(&self, row: Attribute) -> TypeName {
let AttributeType::MemberRef(row) = self.row_decode(row.0, 1);
let MemberRefParent::TypeRef(row) = self.row_decode(row.0, 0);
self.type_ref_type_name(row)
}
pub fn attribute_name(&self, row: Attribute) -> &str {
let AttributeType::MemberRef(row) = self.row_decode(row.0, 1);
let MemberRefParent::TypeRef(row) = self.row_decode(row.0, 0);
Expand Down Expand Up @@ -607,7 +602,7 @@ impl<'a> Reader<'a> {
}
pub fn method_def_signature(&self, row: MethodDef, generics: &[Type]) -> Signature {
let mut blob = self.row_blob(row.0, 4);
let vararg = blob.read_usize() == 0x05;
let call_flags = MethodCallAttributes(blob.read_usize() as _);
let _param_count = blob.read_usize();
let mut return_type = self.type_from_blob(&mut blob, None, generics);

Expand Down Expand Up @@ -707,7 +702,7 @@ impl<'a> Reader<'a> {
}
}

Signature { def: row, params, return_type, vararg }
Signature { def: row, params, return_type, call_flags }
}
pub fn method_def_extern_abi(&self, def: MethodDef) -> &'static str {
let impl_map = self.method_def_impl_map(def).expect("ImplMap not found");
Expand Down
6 changes: 6 additions & 0 deletions crates/libs/metadata/src/reader/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ impl Row {
Self { row: self.row + 1, table: self.table, file: self.file }
}
}

impl std::fmt::Debug for Row {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Row").field(&self.file).field(&self.table).field(&self.row).finish()
}
}
17 changes: 12 additions & 5 deletions crates/libs/metadata/src/writer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,10 @@ impl Type {
}

#[derive(Debug)]
pub struct Attribute {}
pub struct Attribute {
ty: TypeRef,
args: Vec<(String, Value)>,
}

#[derive(Default, Debug)]
pub struct Field {
Expand All @@ -193,15 +196,15 @@ pub struct Param {
#[derive(Default, Debug)]
pub struct Method {
flags: MethodAttributes,
call_flags: MethodCallAttributes,
name: String,
params: Vec<Param>,
return_type: Param,
//attributes: Vec<Attribute>,
attributes: Vec<Attribute>,
//impl_flags: MethodImplAttributes,
vararg: bool,
}

#[derive(Debug)]
#[derive(Clone, Debug)]
pub enum Value {
Bool(bool),
U8(u8),
Expand All @@ -215,6 +218,8 @@ pub enum Value {
F32(f32),
F64(f64),
String(String),
TypeName(String),
Enum(String, Integer),
}

impl Value {
Expand All @@ -233,6 +238,7 @@ impl Value {
Self::F32(_) => ELEMENT_TYPE_R4 as _,
Self::F64(_) => ELEMENT_TYPE_R8 as _,
Self::String(_) => ELEMENT_TYPE_STRING as _,
_ => todo!(),
}
}
fn to_expr(&self) -> String {
Expand All @@ -249,6 +255,7 @@ impl Value {
Self::F32(value) => format!("{value}f32"),
Self::F64(value) => format!("{value}f64"),
Self::String(value) => value.clone(),
_ => todo!(),
}
}
fn neg(&self) -> Self {
Expand All @@ -265,7 +272,7 @@ impl Value {
Self::I64(value) => Self::I64(value.neg()),
Self::F32(value) => Self::F32(value.neg()),
Self::F64(value) => Self::F64(value.neg()),
Self::String(value) => Self::String(value.clone()),
_ => todo!(),
}
}
}
59 changes: 41 additions & 18 deletions crates/libs/metadata/src/writer/winmd/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,28 @@ pub fn read_winmd(module: &mut Module, paths: &[String], filter: &Filter) -> Res

fn read_type_def(reader: &reader::Reader, ty: reader::TypeDef) -> Result<TypeDef> {
let mut result = TypeDef { flags: reader.type_def_flags(ty), ..Default::default() };

// TODO: need to support loose typing for System.* types
// result.attributes = read_attributes(reader, reader.type_def_attributes(ty))?;
result.extends = reader.type_def_extends(ty).map(|extends| TypeRef { namespace: extends.namespace.to_string(), name: extends.name.to_string(), ..Default::default() });

for method in reader.type_def_methods(ty) {
let flags = reader.method_def_flags(method);
let sig = reader.method_def_signature(method, &[]);
let name = reader.method_def_name(method).to_string();
let mut params = vec![];

for param in sig.params {
let flags = reader.param_flags(param.def);
let name = reader.param_name(param.def).to_string();
let ty = read_type(reader, &param.ty)?;
params.push(Param { flags, name, ty });
}
if result.flags.contains(TypeAttributes::INTERFACE) || !result.flags.contains(TypeAttributes::WINRT) {
for method in reader.type_def_methods(ty) {
let flags = reader.method_def_flags(method);
let sig = reader.method_def_signature(method, &[]);
let name = reader.method_def_name(method).to_string();
let attributes = read_attributes(reader, reader.method_def_attributes(method))?;
let mut params = vec![];

for param in sig.params {
let flags = reader.param_flags(param.def);
let name = reader.param_name(param.def).to_string();
let ty = read_type(reader, &param.ty)?;
params.push(Param { flags, name, ty });
}

let return_type = Param { ty: read_type(reader, &sig.return_type)?, ..Default::default() };
result.methods.push(Method { flags, name, params, return_type, ..Default::default() });
let return_type = Param { ty: read_type(reader, &sig.return_type)?, ..Default::default() };
result.methods.push(Method { flags, name, params, return_type, attributes, ..Default::default() });
}
}

for field in reader.type_def_fields(ty) {
Expand All @@ -51,7 +55,7 @@ fn read_type_def(reader: &reader::Reader, ty: reader::TypeDef) -> Result<TypeDef

let value = if flags.contains(FieldAttributes::LITERAL) {
let constant = reader.field_constant(field).unwrap();
read_value(&reader.constant_value(constant)).ok()
read_value(reader, &reader.constant_value(constant)).ok()
} else {
None
};
Expand All @@ -62,7 +66,25 @@ fn read_type_def(reader: &reader::Reader, ty: reader::TypeDef) -> Result<TypeDef
Ok(result)
}

fn read_value(value: &reader::Value) -> Result<Value> {
fn read_attributes(reader: &reader::Reader, attributes: impl Iterator<Item = reader::Attribute>) -> Result<Vec<Attribute>> {
let mut result = vec![];

for attribute in attributes {
let ty = reader.attribute_type_name(attribute);
let ty = TypeRef { namespace: ty.namespace.to_string(), name: ty.name.to_string(), generics: vec![] };
let mut args = vec![];

for (name, value) in reader.attribute_args(attribute) {
args.push((name, read_value(reader, &value)?));
}

result.push(Attribute { ty, args });
}

Ok(result)
}

fn read_value(reader: &reader::Reader, value: &reader::Value) -> Result<Value> {
match value {
reader::Value::Bool(value) => Ok(Value::Bool(*value)),
reader::Value::U8(value) => Ok(Value::U8(*value)),
Expand All @@ -76,7 +98,8 @@ fn read_value(value: &reader::Value) -> Result<Value> {
reader::Value::F32(value) => Ok(Value::F32(*value)),
reader::Value::F64(value) => Ok(Value::F64(*value)),
reader::Value::String(value) => Ok(Value::String(value.clone())),
_ => todo!(),
reader::Value::TypeDef(def) => Ok(Value::TypeName(format!("{}", reader.type_def_type_name(*def)))),
reader::Value::Enum(def, value) => Ok(Value::Enum(format!("{}", reader.type_def_type_name(*def)), *value)),
}
}

Expand Down
8 changes: 6 additions & 2 deletions crates/libs/metadata/src/writer/winmd/write/file.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use super::*;
use std::mem::*;

pub fn write(mut tables: Vec<u8>, mut strings: Vec<u8>, mut blobs: Vec<u8>) -> Vec<u8> {
pub fn write(mut tables: Vec<u8>, mut strings: Vec<u8>, mut blobs: Vec<u8>) -> Result<Vec<u8>> {
if [tables.len(), strings.len(), blobs.len()].iter().any(|len| *len > u32::MAX as _) {
return Err(Error::new("heap too large"));
}

unsafe {
let mut guids = vec![0; 16]; // zero guid
let size_of_streams = tables.len() + guids.len() + strings.len() + blobs.len();
Expand Down Expand Up @@ -106,7 +110,7 @@ pub fn write(mut tables: Vec<u8>, mut strings: Vec<u8>, mut blobs: Vec<u8>) -> V
assert_eq!(clr.MetaData.Size as usize, buffer.len() - metadata_offset);
assert_eq!(size_of_image, buffer.len());

buffer
Ok(buffer)
}
}

Expand Down
Loading

0 comments on commit a900999

Please sign in to comment.