Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type Intermediate representation #10

Merged
merged 45 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
12a809c
I should retire
Fernthedev Nov 13, 2024
f1cb7cc
More nonsense
Fernthedev Nov 14, 2024
5ae6a40
Destruction
Fernthedev Nov 14, 2024
a10c8ff
I'm going insane
Fernthedev Nov 14, 2024
714fa60
Things are looking ok
Fernthedev Nov 14, 2024
94c5a25
C++ implementation barebones
Fernthedev Nov 14, 2024
5301afe
Cpp barebones done, need to make it use CS data now
Fernthedev Nov 14, 2024
9e08dc5
Add basic method setup
Fernthedev Nov 14, 2024
e5974e0
Everything compiles, now time to fix
Fernthedev Nov 18, 2024
457b4f6
fmt and fix
Fernthedev Nov 18, 2024
2a900e1
CPP main
Fernthedev Nov 18, 2024
8a43c97
Add target enum
Fernthedev Nov 18, 2024
25ee3f7
C# metadata parsing working
Fernthedev Nov 18, 2024
5aede49
Warning fixes
Fernthedev Nov 19, 2024
d0248ff
Remove redundant field handling
Fernthedev Nov 19, 2024
384d987
Minor things
Fernthedev Nov 19, 2024
5ffce57
Preparing to rewrite name resolve
Fernthedev Nov 19, 2024
2ddeaa6
Type resolving
Fernthedev Nov 19, 2024
72491bf
Parent and interface should use ResolvedType
Fernthedev Nov 19, 2024
5fcd270
CPP name resolver conversion done
Fernthedev Nov 19, 2024
f825068
Partially implemented cs to cpp conversion
Fernthedev Nov 19, 2024
e6ad690
Format
Fernthedev Nov 19, 2024
339247b
More progress
Fernthedev Nov 20, 2024
918f4d7
Everything compiles, now to polish
Fernthedev Nov 21, 2024
4329d11
CS Value to String
Fernthedev Nov 21, 2024
0ebed51
Fixes for minor things
Fernthedev Nov 21, 2024
aff2386
Everything filling, no errors
Fernthedev Nov 21, 2024
4f3d400
Writing finished
Fernthedev Nov 21, 2024
f88c8cf
Include params
Fernthedev Nov 21, 2024
883be1e
Nested type and forward declare fix
Fernthedev Nov 21, 2024
a839b07
Don't add inherites for value types or enum types
Fernthedev Nov 21, 2024
504f72a
Prevent self include
Fernthedev Nov 22, 2024
cc4092c
Don't use ByRef in fields
Fernthedev Nov 22, 2024
b4adb35
Move handlers to C++, fix fields, fix includes and dependency ordering,
Fernthedev Nov 22, 2024
ae63fdb
No method data for generics
Fernthedev Nov 22, 2024
15ff3ee
Calculate offsets properly
Fernthedev Nov 22, 2024
9fe6c1f
Fix ByRef for certain types not applied
Fernthedev Nov 22, 2024
707a1be
Try to fix type sorting
Fernthedev Nov 22, 2024
6f7b6a4
Fix include condition
Fernthedev Nov 22, 2024
222c48c
Fix it finally
Fernthedev Nov 22, 2024
1aebff3
Add dependencies comment
Fernthedev Nov 22, 2024
178375a
Fix unnecessary hard includes
Fernthedev Nov 22, 2024
95e47e5
Il2CppObject as pointer
Fernthedev Nov 22, 2024
48ba9d6
Add docs
Fernthedev Nov 22, 2024
6162c19
Merge branch 'master' into type-ir
Fernthedev Nov 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ rayon = "1.8"
filesize = "0.2.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
bitflags = "2.6.0"

[profiles.release]
opt-level = 3
Expand Down
1 change: 1 addition & 0 deletions src/data/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod name_components;
pub mod type_resolver;
328 changes: 328 additions & 0 deletions src/data/type_resolver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,328 @@
use brocolib::{
global_metadata::{GenericParameterIndex, MethodIndex},
runtime_metadata::{Il2CppType, Il2CppTypeEnum, TypeData},
};

use itertools::Itertools;
use log::warn;

use crate::generate::{
cs_context_collection::TypeContextCollection,
cs_type::CsType,
cs_type_tag::CsTypeTag,
metadata::CordlMetadata,
type_extensions::{ParameterDefinitionExtensions, TypeDefinitionIndexExtensions},
};

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum TypeUsage {
// Method usage
Parameter,
ReturnType,

// References
Field,
Property,

// naming the CppType itself
TypeName,
GenericArg,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ResolvedTypeData {
Array(Box<ResolvedType>),
GenericInst(Box<ResolvedType>, Vec<(ResolvedType, bool)>),
GenericArg(GenericParameterIndex, u16), // points to class generic
GenericMethodArg(MethodIndex, GenericParameterIndex, u16), // points to method generic
Ptr(Box<ResolvedType>),
Type(CsTypeTag),
Primitive(Il2CppTypeEnum),
Blacklisted(CsTypeTag),
ByRef(Box<ResolvedType>),
ByRefConst(Box<ResolvedType>),
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ResolvedType {
pub data: ResolvedTypeData,
pub ty: usize,
}

pub struct TypeResolver<'a, 'b> {
pub cordl_metadata: &'a CordlMetadata<'b>,
pub collection: &'a TypeContextCollection,
}

impl<'a, 'b> TypeResolver<'a, 'b> {
pub fn resolve_type(
&self,
declaring_cs_type: &mut CsType,
to_resolve_idx: usize,
typ_usage: TypeUsage,
add_include: bool,
) -> ResolvedType {
let to_resolve = &self.cordl_metadata.metadata_registration.types[to_resolve_idx];
let data = self.resolve_type_recurse(
declaring_cs_type,
to_resolve,
to_resolve_idx,
typ_usage,
add_include,
);

ResolvedType {
data,
ty: to_resolve_idx,
}
}

/// [declaring_generic_inst_types] the generic instantiation of the declaring type
fn resolve_type_recurse(
&self,
declaring_cs_type: &mut CsType,
to_resolve: &Il2CppType,
to_resolve_idx: usize,
typ_usage: TypeUsage,
add_include: bool,
) -> ResolvedTypeData {
let typ_tag = to_resolve.data;
let metadata = self.cordl_metadata;

let ret = match to_resolve.ty {
// https://learn.microsoft.com/en-us/nimbusml/concepts/types
// https://en.cppreference.com/w/cpp/types/floating-point
Il2CppTypeEnum::I1
| Il2CppTypeEnum::U1
| Il2CppTypeEnum::I2
| Il2CppTypeEnum::U2
| Il2CppTypeEnum::I4
| Il2CppTypeEnum::U4
| Il2CppTypeEnum::I8
| Il2CppTypeEnum::U8
| Il2CppTypeEnum::R4
| Il2CppTypeEnum::R8
| Il2CppTypeEnum::Void
| Il2CppTypeEnum::Boolean
| Il2CppTypeEnum::Char
| Il2CppTypeEnum::String => {
declaring_cs_type
.requirements
.add_dependency_tag(CsTypeTag::from_type_data(
to_resolve.data,
self.cordl_metadata.metadata,
));
ResolvedTypeData::Primitive(to_resolve.ty)
}

Il2CppTypeEnum::Object
| Il2CppTypeEnum::Valuetype
| Il2CppTypeEnum::Class
| Il2CppTypeEnum::Typedbyref
// ptr types
| Il2CppTypeEnum::I
| Il2CppTypeEnum::U => self.resolve_ptr(typ_tag, declaring_cs_type, to_resolve, add_include),

// Single dimension array
Il2CppTypeEnum::Szarray => {
let generic = match to_resolve.data {
TypeData::TypeIndex(e) => {

self.resolve_type(
declaring_cs_type,
e,
typ_usage,
add_include
)
}

_ => panic!("Unknown type data for array {to_resolve:?}!"),
};

ResolvedTypeData::Array(Box::new(generic))
}
// multi dimensional array
Il2CppTypeEnum::Array => {
// FIXME: when stack further implements the TypeData::ArrayType we can actually implement this fully to be a multidimensional array, whatever that might mean
warn!("Multidimensional array was requested but this is not implemented, typ: {to_resolve:?}, instead returning Il2CppObject!");
ResolvedTypeData::Primitive(Il2CppTypeEnum::Object)
}
//
Il2CppTypeEnum::Mvar => match to_resolve.data {
TypeData::GenericParameterIndex(index) => {
let generic_param: &brocolib::global_metadata::Il2CppGenericParameter =
&metadata.metadata.global_metadata.generic_parameters[index];

let owner = generic_param.owner(metadata.metadata);
assert!(owner.is_method != u32::MAX);

let (_gen_idx, gen_param) = owner
.generic_parameters(metadata.metadata)
.iter()
.find_position(|&p| p.name_index == generic_param.name_index)
.unwrap();

let method_index = MethodIndex::new(owner.owner_index);

ResolvedTypeData::GenericMethodArg(method_index, index, gen_param.num)
}
_ => todo!(),
},
Il2CppTypeEnum::Var => match to_resolve.data {
// Il2CppMetadataGenericParameterHandle
TypeData::GenericParameterIndex(index) => {
let generic_param: &brocolib::global_metadata::Il2CppGenericParameter =
&metadata.metadata.global_metadata.generic_parameters[index];

let _owner = generic_param.owner(metadata.metadata);

ResolvedTypeData::GenericArg(index, generic_param.num)
}
_ => todo!(),
},
Il2CppTypeEnum::Genericinst => match to_resolve.data {
TypeData::GenericClassIndex(e) => {
let mr = &metadata.metadata_registration;
let generic_class = mr.generic_classes.get(e).unwrap();
let generic_inst = mr
.generic_insts
.get(generic_class.context.class_inst_idx.unwrap())
.unwrap();

let new_generic_inst_types = &generic_inst.types;

let generic_type_def = &mr.types[generic_class.type_index];
let TypeData::TypeDefinitionIndex(tdi) = generic_type_def.data else {
panic!()
};

if add_include {
let generic_tag = CsTypeTag::from_type_data(to_resolve.data, metadata.metadata);

// depend on both tdi and generic instantiation
declaring_cs_type.requirements.add_dependency_tag(tdi.into());
declaring_cs_type.requirements.add_dependency_tag(generic_tag);
}

let generic_resolved_args = new_generic_inst_types
// let generic_types_formatted = new_generic_inst_types
.iter()
.map(|gen_arg_t_idx| {
let gen_arg_ty = mr.types.get(*gen_arg_t_idx).unwrap();
// we must include if the type is a value type
let should_include = gen_arg_ty.valuetype && add_include;

let t =self.resolve_type(
declaring_cs_type,
*gen_arg_t_idx,
TypeUsage::GenericArg,
should_include
);
(t, should_include)
})
.collect_vec();


let generic_resolved_type = self.resolve_type(
declaring_cs_type,
generic_class.type_index,
typ_usage,
add_include
);

// add generics to type def
ResolvedTypeData::GenericInst(Box::new(generic_resolved_type), generic_resolved_args)
}

_ => panic!("Unknown type data for generic inst {to_resolve:?}!"),
},


Il2CppTypeEnum::Ptr => {
let ptr_type = match to_resolve.data {
TypeData::TypeIndex(e) => {
self.resolve_type(
declaring_cs_type,
e,
typ_usage,
add_include
)
}

_ => panic!("Unknown type data for array {to_resolve:?}!"),
};

ResolvedTypeData::Ptr(Box::new(ptr_type))
}
_ => panic!("/* UNKNOWN TYPE! {to_resolve:?} */"),
};

let byref_allowed = matches!(
typ_usage,
TypeUsage::Parameter
| TypeUsage::ReturnType
| TypeUsage::TypeName
| TypeUsage::GenericArg
);

if (to_resolve.is_param_out() || (to_resolve.byref && !to_resolve.valuetype))
&& byref_allowed
{
return ResolvedTypeData::ByRef(Box::new(ResolvedType {
ty: to_resolve_idx,
data: ret,
}));
}

if to_resolve.is_param_in() && byref_allowed {
return ResolvedTypeData::ByRefConst(Box::new(ResolvedType {
ty: to_resolve_idx,
data: ret,
}));
}

ret
}

fn resolve_ptr(
&self,
typ_tag: TypeData,
declaring_cs_type: &mut CsType,
to_resolve: &Il2CppType,
add_include: bool,
) -> ResolvedTypeData {
let metadata = self.cordl_metadata;
let ctx_collection = self.collection;
let typ_cpp_tag: CsTypeTag = typ_tag.into();
// Self
if typ_cpp_tag == declaring_cs_type.self_tag {
return ResolvedTypeData::Type(typ_cpp_tag);
}

if let TypeData::TypeDefinitionIndex(tdi) = to_resolve.data
&& metadata.blacklisted_types.contains(&tdi)
{
// blacklist if needed

return ResolvedTypeData::Blacklisted(typ_cpp_tag);
}

if add_include {
declaring_cs_type
.requirements
.add_dependency_tag(typ_cpp_tag);
}

let to_incl_cpp_ty = ctx_collection
.get_cs_type(to_resolve.data.into())
.unwrap_or_else(|| panic!("Unable to get type to include {:?}", to_resolve.data));

ResolvedTypeData::Type(to_incl_cpp_ty.self_tag)
}
}

impl ResolvedType {
pub fn get_type<'a>(&self, metadata: &CordlMetadata<'a>) -> &'a Il2CppType {
&metadata.metadata_registration.types[self.ty]
}
}
Loading
Loading