From 0d813230068520299ca2099886145ee8c14eb247 Mon Sep 17 00:00:00 2001 From: Lucy Date: Sun, 24 May 2026 19:21:30 -0400 Subject: [PATCH 1/2] adds a version struct helper --- auxtools-impl/src/lib.rs | 7 + auxtools-impl/src/versioned_struct.rs | 296 ++++++++++++ auxtools/src/bytecode_manager.rs | 4 +- auxtools/src/list.rs | 8 +- auxtools/src/proc.rs | 6 +- auxtools/src/raw_types/procs.rs | 629 +++++++++----------------- 6 files changed, 538 insertions(+), 412 deletions(-) create mode 100644 auxtools-impl/src/versioned_struct.rs diff --git a/auxtools-impl/src/lib.rs b/auxtools-impl/src/lib.rs index f9d89a6..145481c 100644 --- a/auxtools-impl/src/lib.rs +++ b/auxtools-impl/src/lib.rs @@ -1,3 +1,5 @@ +mod versioned_struct; + use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, spanned::Spanned, Lit}; @@ -21,6 +23,11 @@ fn from_signature(s: String) -> Vec> { .collect() } +#[proc_macro_attribute] +pub fn versioned(attr: TokenStream, item: TokenStream) -> TokenStream { + versioned_struct::versioned(attr.into(), item.into()).into() +} + #[proc_macro] pub fn convert_signature(input: TokenStream) -> TokenStream { let string = parse_macro_input!(input as Lit); diff --git a/auxtools-impl/src/versioned_struct.rs b/auxtools-impl/src/versioned_struct.rs new file mode 100644 index 0000000..067130c --- /dev/null +++ b/auxtools-impl/src/versioned_struct.rs @@ -0,0 +1,296 @@ +use proc_macro2::{Span, TokenStream}; +use quote::{format_ident, quote}; +use syn::{ + parse::{Parse, ParseStream}, + punctuated::Punctuated, + spanned::Spanned, + Attribute, Expr, Field, Fields, Ident, ItemStruct, Token, Visibility +}; + +// --- Input types --- + +struct VersionVariant { + name: Ident, + condition: Option +} + +struct VersionedArgs { + variants: Vec +} + +// --- Field annotation types --- + +enum FieldVersionInfo { + AllVersions, + OnlyIn(Ident) +} + +struct VersionedField { + field: Field, + version_info: FieldVersionInfo +} + +// --- Parsing --- + +impl Parse for VersionVariant { + fn parse(input: ParseStream) -> syn::Result { + let name: Ident = input.parse()?; + let condition = if input.peek(Token![if]) { + input.parse::()?; + Some(input.parse()?) + } else { + None + }; + Ok(Self { name, condition }) + } +} + +impl Parse for VersionedArgs { + fn parse(input: ParseStream) -> syn::Result { + let variants = Punctuated::::parse_terminated(input)?.into_iter().collect(); + Ok(Self { variants }) + } +} + +// --- Field processing --- + +fn extract_field_version_info(field: &mut Field) -> FieldVersionInfo { + let mut result = FieldVersionInfo::AllVersions; + field.attrs.retain(|attr| { + if attr.path().is_ident("only_in") { + if let Ok(variant) = attr.parse_args::() { + result = FieldVersionInfo::OnlyIn(variant); + return false; + } + } + true + }); + result +} + +fn extract_versioned_fields(input: &mut ItemStruct) -> Result, syn::Error> { + let Fields::Named(ref mut fields) = input.fields else { + return Err(syn::Error::new( + input.fields.span(), + "#[versioned] only supports structs with named fields" + )); + }; + Ok(fields + .named + .iter_mut() + .map(|field| { + let version_info = extract_field_version_info(field); + VersionedField { + field: field.clone(), + version_info + } + }) + .collect()) +} + +// --- Validation --- + +fn validate_variants(variants: &[VersionVariant]) -> Option { + if variants.len() < 2 { + return Some(syn::Error::new(Span::call_site(), "#[versioned] requires at least 2 variants")); + } + if variants.last().unwrap().condition.is_some() { + return Some(syn::Error::new( + variants.last().unwrap().name.span(), + "the last variant must be the fallback (no `if` condition)" + )); + } + for v in &variants[..variants.len() - 1] { + if v.condition.is_none() { + return Some(syn::Error::new(v.name.span(), "only the last variant can omit the `if` condition")); + } + } + None +} + +// --- Code generation --- + +fn field_to_tokens(field: &Field) -> TokenStream { + let attrs = &field.attrs; + let vis = &field.vis; + let ident = &field.ident; + let ty = &field.ty; + quote! { + #(#attrs)* + #vis #ident: #ty + } +} + +fn variant_inner_name(struct_ident: &Ident, variant: &VersionVariant) -> Ident { + format_ident!("{}{}", struct_ident, variant.name) +} + +fn variant_field_name(variant: &VersionVariant) -> Ident { + format_ident!("{}", variant.name.to_string().to_lowercase()) +} + +fn generate_variant_struct(struct_ident: &Ident, struct_attrs: &[Attribute], variant: &VersionVariant, fields: &[VersionedField]) -> TokenStream { + let inner_name = variant_inner_name(struct_ident, variant); + let variant_name = &variant.name; + + let variant_fields = fields.iter().filter_map(|vf| match &vf.version_info { + FieldVersionInfo::AllVersions => Some(field_to_tokens(&vf.field)), + FieldVersionInfo::OnlyIn(v) if v == variant_name => Some(field_to_tokens(&vf.field)), + FieldVersionInfo::OnlyIn(_) => None + }); + + quote! { + #[allow(dead_code)] + #[derive(Copy, Clone)] + #(#struct_attrs)* + struct #inner_name { + #(#variant_fields,)* + } + } +} + +fn generate_union(struct_ident: &Ident, vis: &Visibility, attrs: &[Attribute], variants: &[VersionVariant]) -> TokenStream { + let union_fields = variants.iter().map(|v| { + let field_name = variant_field_name(v); + let inner_name = variant_inner_name(struct_ident, v); + quote! { #field_name: #inner_name } + }); + + quote! { + #(#attrs)* + #vis union #struct_ident { + #(#union_fields,)* + } + } +} + +fn build_dispatch_chain(variants: &[VersionVariant], helper_names: &[Ident]) -> TokenStream { + let fallback = helper_names.last().unwrap(); + let mut chain = quote! { Self::#fallback }; + + for (variant, helper) in variants[..variants.len() - 1].iter().zip(&helper_names[..helper_names.len() - 1]).rev() { + let cond = variant.condition.as_ref().unwrap(); + chain = quote! { + if #cond { Self::#helper } else { #chain } + }; + } + + chain +} + +fn generate_field_accessor(struct_ident: &Ident, field: &Field, variants: &[VersionVariant]) -> TokenStream { + let field_name = field.ident.as_ref().unwrap(); + let field_ty = &field.ty; + + let helper_names: Vec = variants + .iter() + .map(|v| format_ident!("__versioned_{}_{}", field_name, variant_field_name(v))) + .collect(); + + let dispatch = build_dispatch_chain(variants, &helper_names); + + let helpers = variants.iter().zip(&helper_names).map(|(v, helper_name)| { + let union_field = variant_field_name(v); + quote! { + #[inline(never)] + fn #helper_name(this: &Self) -> #field_ty { + unsafe { this.#union_field.#field_name } + } + } + }); + + quote! { + pub fn #field_name(&self) -> #field_ty { + static REDIRECT: ::std::sync::OnceLock #field_ty> = + ::std::sync::OnceLock::new(); + REDIRECT.get_or_init(|| unsafe { #dispatch })(self) + } + #(#helpers)* + } +} + +fn generate_field_ptr_accessor(struct_ident: &Ident, field: &Field, variants: &[VersionVariant]) -> TokenStream { + let field_name = field.ident.as_ref().unwrap(); + let field_ty = &field.ty; + let ptr_name = format_ident!("{}_ptr", field_name); + + let helper_names: Vec = variants + .iter() + .map(|v| format_ident!("__versioned_{}_{}_ptr", field_name, variant_field_name(v))) + .collect(); + + let dispatch = build_dispatch_chain(variants, &helper_names); + + let helpers = variants.iter().zip(&helper_names).map(|(v, helper_name)| { + let union_field = variant_field_name(v); + quote! { + #[inline(never)] + fn #helper_name(this: &mut Self) -> *mut #field_ty { + unsafe { ::std::ptr::addr_of_mut!(this.#union_field.#field_name) } + } + } + }); + + quote! { + pub fn #ptr_name(&mut self) -> *mut #field_ty { + static REDIRECT: ::std::sync::OnceLock *mut #field_ty> = + ::std::sync::OnceLock::new(); + REDIRECT.get_or_init(|| unsafe { #dispatch })(self) + } + #(#helpers)* + } +} + +fn generate_impl(struct_ident: &Ident, variants: &[VersionVariant], fields: &[VersionedField]) -> TokenStream { + let pub_all_fields: Vec<_> = fields + .iter() + .filter(|vf| matches!(vf.version_info, FieldVersionInfo::AllVersions) && matches!(vf.field.vis, Visibility::Public(_))) + .collect(); + + let value_accessors = pub_all_fields.iter().map(|vf| generate_field_accessor(struct_ident, &vf.field, variants)); + let ptr_accessors = pub_all_fields + .iter() + .map(|vf| generate_field_ptr_accessor(struct_ident, &vf.field, variants)); + + quote! { + impl #struct_ident { + #(#value_accessors)* + #(#ptr_accessors)* + } + } +} + +// --- Entry point --- + +pub fn versioned(attr: TokenStream, item: TokenStream) -> TokenStream { + let args = match syn::parse2::(attr) { + Ok(a) => a, + Err(e) => return e.to_compile_error() + }; + let mut input = match syn::parse2::(item) { + Ok(i) => i, + Err(e) => return e.to_compile_error() + }; + + if let Some(err) = validate_variants(&args.variants) { + return err.to_compile_error(); + } + + let fields = match extract_versioned_fields(&mut input) { + Ok(f) => f, + Err(e) => return e.to_compile_error() + }; + + let variant_structs = args + .variants + .iter() + .map(|v| generate_variant_struct(&input.ident, &input.attrs, v, &fields)); + let union_def = generate_union(&input.ident, &input.vis, &input.attrs, &args.variants); + let impl_block = generate_impl(&input.ident, &args.variants, &fields); + + quote! { + #(#variant_structs)* + #union_def + #impl_block + } +} diff --git a/auxtools/src/bytecode_manager.rs b/auxtools/src/bytecode_manager.rs index a29f0d9..7b0eacd 100644 --- a/auxtools/src/bytecode_manager.rs +++ b/auxtools/src/bytecode_manager.rs @@ -59,7 +59,7 @@ pub fn shutdown() { let proc = Proc::from_id(id).unwrap(); unsafe { - raw_types::misc::set_bytecode((*proc.entry).metadata.get_bytecode(), ptr, len); + raw_types::misc::set_bytecode((*proc.entry).metadata.bytecode(), ptr, len); } } @@ -104,6 +104,6 @@ pub fn set_bytecode(proc: &Proc, mut bytecode: Vec) { let len = u16::try_from(len).unwrap(); unsafe { - raw_types::misc::set_bytecode((*proc.entry).metadata.get_bytecode(), ptr, len); + raw_types::misc::set_bytecode((*proc.entry).metadata.bytecode(), ptr, len); } } diff --git a/auxtools/src/list.rs b/auxtools/src/list.rs index 0e94646..9fdb306 100644 --- a/auxtools/src/list.rs +++ b/auxtools/src/list.rs @@ -19,7 +19,7 @@ impl List { /// Creates a new empty list. pub fn new() -> Self { - Self::with_size(0) + Self::default() } /// Creates a new list filled with `capacity` nulls. @@ -160,3 +160,9 @@ impl From<&List> for Value { list.value.clone() } } + +impl Default for List { + fn default() -> Self { + Self::with_size(0) + } +} diff --git a/auxtools/src/proc.rs b/auxtools/src/proc.rs index c9db1b3..0ecd703 100644 --- a/auxtools/src/proc.rs +++ b/auxtools/src/proc.rs @@ -80,14 +80,14 @@ impl Proc { pub fn parameter_names(&self) -> Vec { unsafe { - let (data, count) = raw_types::misc::get_parameters((*self.entry).metadata.get_parameters()); + let (data, count) = raw_types::misc::get_parameters((*self.entry).metadata.parameters()); (0..count).map(|i| StringRef::from_variable_id((*data.add(i)).name)).collect() } } pub fn local_names(&self) -> Vec { unsafe { - let (names, count) = raw_types::misc::get_locals((*self.entry).metadata.get_locals()); + let (names, count) = raw_types::misc::get_locals((*self.entry).metadata.locals()); (0..count).map(|i| StringRef::from_variable_id(*names.add(i))).collect() } } @@ -97,7 +97,7 @@ impl Proc { } pub unsafe fn bytecode_mut_ptr(&self) -> (*mut u32, u16) { - raw_types::misc::get_bytecode((*self.entry).metadata.get_bytecode()) + raw_types::misc::get_bytecode((*self.entry).metadata.bytecode()) } pub unsafe fn bytecode(&self) -> &[u32] { diff --git a/auxtools/src/raw_types/procs.rs b/auxtools/src/raw_types/procs.rs index 55efb84..34e46d4 100644 --- a/auxtools/src/raw_types/procs.rs +++ b/auxtools/src/raw_types/procs.rs @@ -1,5 +1,5 @@ #![allow(clippy::missing_const_for_fn)] -use std::sync::OnceLock; +use auxtools_impl::versioned; use super::{misc, strings, values}; @@ -18,88 +18,15 @@ pub struct ProcEntry { pub metadata: ProcMetadata } +#[versioned( + Pre1630 if crate::version::BYOND_VERSION_MINOR <= 1627, + Post1630, +)] #[repr(C)] -pub union ProcMetadata { - pub pre1630: BytecodePre1630, - pub post1630: BytecodePost1630 -} - -impl ProcMetadata { - pub fn get_bytecode(&self) -> misc::BytecodeId { - static REDIRECT: OnceLock misc::BytecodeId> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match crate::version::BYOND_VERSION_MINOR { - ..=1627 => Self::get_bytecode_pre1630, - _ => Self::get_bytecode_post1630 - } - })(self) - } - - #[inline(never)] - fn get_bytecode_pre1630(this: &Self) -> misc::BytecodeId { - unsafe { this.pre1630.bytecode } - } - - #[inline(never)] - fn get_bytecode_post1630(this: &Self) -> misc::BytecodeId { - unsafe { this.post1630.bytecode } - } - - pub fn get_locals(&self) -> misc::LocalsId { - static REDIRECT: OnceLock misc::LocalsId> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match crate::version::BYOND_VERSION_MINOR { - ..=1627 => Self::get_locals_pre1630, - _ => Self::get_locals_post1630 - } - })(self) - } - - #[inline(never)] - fn get_locals_pre1630(this: &Self) -> misc::LocalsId { - unsafe { this.pre1630.locals } - } - - #[inline(never)] - fn get_locals_post1630(this: &Self) -> misc::LocalsId { - unsafe { this.post1630.locals } - } - - pub fn get_parameters(&self) -> misc::ParametersId { - static REDIRECT: OnceLock misc::ParametersId> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match crate::version::BYOND_VERSION_MINOR { - ..=1627 => Self::get_parameters_pre1630, - _ => Self::get_parameters_post1630 - } - })(self) - } - - #[inline(never)] - fn get_parameters_pre1630(this: &Self) -> misc::ParametersId { - unsafe { this.pre1630.parameters } - } - - #[inline(never)] - fn get_parameters_post1630(this: &Self) -> misc::ParametersId { - unsafe { this.post1630.parameters } - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct BytecodePre1630 { - pub bytecode: misc::BytecodeId, - pub locals: misc::LocalsId, - pub parameters: misc::ParametersId -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct BytecodePost1630 { +pub struct ProcMetadata { + #[only_in(Post1630)] unk_2: u32, pub bytecode: misc::BytecodeId, - // Bytecode moved by 4 bytes in 1630 pub locals: misc::LocalsId, pub parameters: misc::ParametersId } @@ -112,371 +39,79 @@ pub struct ProcInstance { pub usr: values::Value, pub src: values::Value, pub context: *mut ExecutionContext, - argslist_idx: values::ValueData, + pub argslist_idx: values::ValueData, unk_1: u32, unk_2: u32, inner: ProcInstanceInner } impl ProcInstance { - #[inline(never)] - fn args_count_pre516(this: &Self) -> u32 { - unsafe { this.inner.pre516.args_count } - } - - #[inline(never)] - fn args_count_post516(this: &Self) -> u32 { - unsafe { this.inner.post516.args_count } - } - pub fn args_count(&self) -> u32 { - static REDIRECT: OnceLock u32> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match crate::version::BYOND_VERSION_MAJOR { - ..516 => Self::args_count_pre516, - _ => Self::args_count_post516 - } - })(self) - } - - #[inline(never)] - fn args_pre516(this: &Self) -> *mut values::Value { - unsafe { this.inner.pre516.args } - } - - #[inline(never)] - fn args_post516(this: &Self) -> *mut values::Value { - unsafe { this.inner.post516.args } + self.inner.args_count() } pub fn args(&self) -> *mut values::Value { - static REDIRECT: OnceLock *mut values::Value> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match crate::version::BYOND_VERSION_MAJOR { - ..516 => Self::args_pre516, - _ => Self::args_post516 - } - })(self) - } - - #[inline(never)] - fn time_to_resume_pre516(this: &Self) -> u32 { - unsafe { this.inner.pre516.time_to_resume } - } - - #[inline(never)] - fn time_to_resume_post516(this: &Self) -> u32 { - unsafe { this.inner.post516.time_to_resume } + self.inner.args() } pub fn time_to_resume(&self) -> u32 { - static REDIRECT: OnceLock u32> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match crate::version::BYOND_VERSION_MAJOR { - ..516 => Self::time_to_resume_pre516, - _ => Self::time_to_resume_post516 - } - })(self) + self.inner.time_to_resume() } } -#[repr(C)] -union ProcInstanceInner { - pre516: ProcInstanceInnerPre516, - post516: ProcInstanceInnerPost516 -} +#[versioned( + Pre516 if crate::version::BYOND_VERSION_MAJOR < 516, + Post516, +)] #[repr(C)] -#[derive(Copy, Clone)] -struct ProcInstanceInnerPre516 { - args_count: u32, - args: *mut values::Value, +struct ProcInstanceInner { + #[only_in(Post516)] + unk_pre: u32, + pub args_count: u32, + pub args: *mut values::Value, + #[only_in(Pre516)] unk_3: [u8; 0x58], - time_to_resume: u32 -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct ProcInstanceInnerPost516 { - unk_3: u32, - args_count: u32, - args: *mut values::Value, + #[only_in(Post516)] unk_4: [u8; 0x58], - time_to_resume: u32 + pub time_to_resume: u32 } +#[versioned( + Pre1668 if crate::version::BYOND_VERSION_MAJOR <= 515 || (crate::version::BYOND_VERSION_MAJOR == 516 && crate::version::BYOND_VERSION_MINOR <= 1667), + Post1668, +)] #[repr(C)] -pub union ExecutionContext { - pub pre1668: ExecutionContextPre1668, - pub post1668: ExecutionContextPost1668, -} - -impl ExecutionContext { - pub fn proc_instance(&self) -> *mut ProcInstance { - static REDIRECT: OnceLock *mut ProcInstance> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match (crate::version::BYOND_VERSION_MAJOR, crate::version::BYOND_VERSION_MINOR) { - (..=515, _) | (516, ..=1667) => Self::proc_instance_pre1668, - _ => Self::proc_instance_post1668, - } - })(self) - } - - #[inline(never)] - fn proc_instance_pre1668(this: &Self) -> *mut ProcInstance { - unsafe { this.pre1668.proc_instance } - } - - #[inline(never)] - fn proc_instance_post1668(this: &Self) -> *mut ProcInstance { - unsafe { this.post1668.proc_instance } - } - - pub fn parent_context(&self) -> *mut ExecutionContext { - static REDIRECT: OnceLock *mut ExecutionContext> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match (crate::version::BYOND_VERSION_MAJOR, crate::version::BYOND_VERSION_MINOR) { - (..=515, _) | (516, ..=1667) => Self::parent_context_pre1668, - _ => Self::parent_context_post1668, - } - })(self) - } - - #[inline(never)] - fn parent_context_pre1668(this: &Self) -> *mut ExecutionContext { - unsafe { this.pre1668.parent_context } - } - - #[inline(never)] - fn parent_context_post1668(this: &Self) -> *mut ExecutionContext { - unsafe { this.post1668.parent_context } - } - - pub fn filename(&self) -> strings::StringId { - static REDIRECT: OnceLock strings::StringId> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match (crate::version::BYOND_VERSION_MAJOR, crate::version::BYOND_VERSION_MINOR) { - (..=515, _) | (516, ..=1667) => Self::filename_pre1668, - _ => Self::filename_post1668, - } - })(self) - } - - #[inline(never)] - fn filename_pre1668(this: &Self) -> strings::StringId { - unsafe { this.pre1668.filename } - } - - #[inline(never)] - fn filename_post1668(this: &Self) -> strings::StringId { - unsafe { this.post1668.filename } - } - - pub fn line(&self) -> u32 { - static REDIRECT: OnceLock u32> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match (crate::version::BYOND_VERSION_MAJOR, crate::version::BYOND_VERSION_MINOR) { - (..=515, _) | (516, ..=1667) => Self::line_pre1668, - _ => Self::line_post1668, - } - })(self) - } - - #[inline(never)] - fn line_pre1668(this: &Self) -> u32 { - unsafe { this.pre1668.line } - } - - #[inline(never)] - fn line_post1668(this: &Self) -> u32 { - unsafe { this.post1668.line } - } - - pub fn bytecode(&self) -> *mut u32 { - static REDIRECT: OnceLock *mut u32> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match (crate::version::BYOND_VERSION_MAJOR, crate::version::BYOND_VERSION_MINOR) { - (..=515, _) | (516, ..=1667) => Self::bytecode_pre1668, - _ => Self::bytecode_post1668, - } - })(self) - } - - #[inline(never)] - fn bytecode_pre1668(this: &Self) -> *mut u32 { - unsafe { this.pre1668.bytecode } - } - - #[inline(never)] - fn bytecode_post1668(this: &Self) -> *mut u32 { - unsafe { this.post1668.bytecode } - } - - pub fn bytecode_offset(&self) -> u16 { - static REDIRECT: OnceLock u16> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match (crate::version::BYOND_VERSION_MAJOR, crate::version::BYOND_VERSION_MINOR) { - (..=515, _) | (516, ..=1667) => Self::bytecode_offset_pre1668, - _ => Self::bytecode_offset_post1668, - } - })(self) - } - - #[inline(never)] - fn bytecode_offset_pre1668(this: &Self) -> u16 { - unsafe { this.pre1668.bytecode_offset } - } - - #[inline(never)] - fn bytecode_offset_post1668(this: &Self) -> u16 { - unsafe { this.post1668.bytecode_offset } - } - - pub fn dot(&self) -> values::Value { - static REDIRECT: OnceLock values::Value> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match (crate::version::BYOND_VERSION_MAJOR, crate::version::BYOND_VERSION_MINOR) { - (..=515, _) | (516, ..=1667) => Self::dot_pre1668, - _ => Self::dot_post1668, - } - })(self) - } - - #[inline(never)] - fn dot_pre1668(this: &Self) -> values::Value { - unsafe { this.pre1668.dot } - } - - #[inline(never)] - fn dot_post1668(this: &Self) -> values::Value { - unsafe { this.post1668.dot } - } - - pub fn dot_ptr(&mut self) -> *mut values::Value { - static REDIRECT: OnceLock *mut values::Value> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match (crate::version::BYOND_VERSION_MAJOR, crate::version::BYOND_VERSION_MINOR) { - (..=515, _) | (516, ..=1667) => Self::dot_ptr_pre1668, - _ => Self::dot_ptr_post1668, - } - })(self) - } - - #[inline(never)] - fn dot_ptr_pre1668(this: &mut Self) -> *mut values::Value { - unsafe { &mut this.pre1668.dot as *mut values::Value } - } - - #[inline(never)] - fn dot_ptr_post1668(this: &mut Self) -> *mut values::Value { - unsafe { &mut this.post1668.dot as *mut values::Value } - } - - pub fn locals(&self) -> *mut values::Value { - static REDIRECT: OnceLock *mut values::Value> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match (crate::version::BYOND_VERSION_MAJOR, crate::version::BYOND_VERSION_MINOR) { - (..=515, _) | (516, ..=1667) => Self::locals_pre1668, - _ => Self::locals_post1668, - } - })(self) - } - - #[inline(never)] - fn locals_pre1668(this: &Self) -> *mut values::Value { - unsafe { this.pre1668.locals } - } - - #[inline(never)] - fn locals_post1668(this: &Self) -> *mut values::Value { - unsafe { this.post1668.locals } - } - - pub fn locals_count(&self) -> u16 { - static REDIRECT: OnceLock u16> = OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { - match (crate::version::BYOND_VERSION_MAJOR, crate::version::BYOND_VERSION_MINOR) { - (..=515, _) | (516, ..=1667) => Self::locals_count_pre1668, - _ => Self::locals_count_post1668, - } - })(self) - } - - #[inline(never)] - fn locals_count_pre1668(this: &Self) -> u16 { - unsafe { this.pre1668.locals_count } - } - - #[inline(never)] - fn locals_count_post1668(this: &Self) -> u16 { - unsafe { this.post1668.locals_count } - } -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct ExecutionContextPre1668 { +pub struct ExecutionContext { pub proc_instance: *mut ProcInstance, pub parent_context: *mut ExecutionContext, pub filename: strings::StringId, pub line: u32, pub bytecode: *mut u32, pub bytecode_offset: u16, - test_flag: u8, + pub test_flag: u8, unk_0: u8, cached_datum: values::Value, - unk_1: [u8; 0x10], + #[only_in(Pre1668)] + unk_1_pre: [u8; 0x10], + #[only_in(Post1668)] + unk_1_post: [u8; 0x14], pub dot: values::Value, pub locals: *mut values::Value, - stack: *mut values::Value, + pub stack: *mut values::Value, pub locals_count: u16, - stack_size: u16, + pub stack_size: u16, unk_2: u32, - current_iterator: *mut values::Value, - iterator_allocated: u32, - iterator_length: u32, - iterator_index: u32, + pub current_iterator: *mut values::Value, + pub iterator_allocated: u32, + pub iterator_length: u32, + pub iterator_index: u32, unk_3: u32, unk_4: [u8; 0x03], - iterator_filtered_type: u8, + pub iterator_filtered_type: u8, unk_5: u8, unk_6: u8, unk_7: u8, - infinite_loop_count: u32, - unk_8: [u8; 0x02], - paused: u8, - unk_9: [u8; 0x33], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct ExecutionContextPost1668 { - pub proc_instance: *mut ProcInstance, - pub parent_context: *mut ExecutionContext, - pub filename: strings::StringId, - pub line: u32, - pub bytecode: *mut u32, - pub bytecode_offset: u16, - test_flag: u8, - unk_0: u8, - cached_datum: values::Value, - unk_1: [u8; 0x14], - pub dot: values::Value, - pub locals: *mut values::Value, - stack: *mut values::Value, - pub locals_count: u16, - stack_size: u16, - unk_2: u32, - current_iterator: *mut values::Value, - iterator_allocated: u32, - iterator_length: u32, - iterator_index: u32, - unk_3: u32, - unk_4: [u8; 0x03], - iterator_filtered_type: u8, - unk_5: u8, - unk_6: u8, - unk_7: u8, - infinite_loop_count: u32, + pub infinite_loop_count: u32, unk_8: [u8; 0x02], paused: u8, unk_9: [u8; 0x33] @@ -493,3 +128,185 @@ pub struct SuspendedProcs { pub back: usize, pub capacity: usize } + +#[cfg(test)] +mod layout_tests { + use std::mem::{offset_of, size_of}; + + use super::{misc, strings, values}; + + // Reference structs: verbatim copies of the original hand-written variants, + // kept here so that any accidental layout change in the macro output is caught. + + #[repr(C)] + #[derive(Copy, Clone)] + struct RefProcMetadataPre1630 { + bytecode: misc::BytecodeId, + locals: misc::LocalsId, + parameters: misc::ParametersId + } + + #[repr(C)] + #[derive(Copy, Clone)] + struct RefProcMetadataPost1630 { + unk_2: u32, + bytecode: misc::BytecodeId, + locals: misc::LocalsId, + parameters: misc::ParametersId + } + + #[repr(C)] + #[derive(Copy, Clone)] + struct RefProcInstanceInnerPre516 { + args_count: u32, + args: *mut values::Value, + unk_3: [u8; 0x58], + time_to_resume: u32 + } + + #[repr(C)] + #[derive(Copy, Clone)] + struct RefProcInstanceInnerPost516 { + unk_3: u32, + args_count: u32, + args: *mut values::Value, + unk_4: [u8; 0x58], + time_to_resume: u32 + } + + #[repr(C)] + #[derive(Copy, Clone)] + struct RefExecutionContextPre1668 { + proc_instance: *mut super::ProcInstance, + parent_context: *mut super::ExecutionContext, + filename: strings::StringId, + line: u32, + bytecode: *mut u32, + bytecode_offset: u16, + test_flag: u8, + unk_0: u8, + cached_datum: values::Value, + unk_1: [u8; 0x10], + dot: values::Value, + locals: *mut values::Value, + stack: *mut values::Value, + locals_count: u16, + stack_size: u16, + unk_2: u32, + current_iterator: *mut values::Value, + iterator_allocated: u32, + iterator_length: u32, + iterator_index: u32, + unk_3: u32, + unk_4: [u8; 0x03], + iterator_filtered_type: u8, + unk_5: u8, + unk_6: u8, + unk_7: u8, + infinite_loop_count: u32, + unk_8: [u8; 0x02], + paused: u8, + unk_9: [u8; 0x33] + } + + #[repr(C)] + #[derive(Copy, Clone)] + struct RefExecutionContextPost1668 { + proc_instance: *mut super::ProcInstance, + parent_context: *mut super::ExecutionContext, + filename: strings::StringId, + line: u32, + bytecode: *mut u32, + bytecode_offset: u16, + test_flag: u8, + unk_0: u8, + cached_datum: values::Value, + unk_1: [u8; 0x14], + dot: values::Value, + locals: *mut values::Value, + stack: *mut values::Value, + locals_count: u16, + stack_size: u16, + unk_2: u32, + current_iterator: *mut values::Value, + iterator_allocated: u32, + iterator_length: u32, + iterator_index: u32, + unk_3: u32, + unk_4: [u8; 0x03], + iterator_filtered_type: u8, + unk_5: u8, + unk_6: u8, + unk_7: u8, + infinite_loop_count: u32, + unk_8: [u8; 0x02], + paused: u8, + unk_9: [u8; 0x33] + } + + #[test] + fn proc_metadata_pre1630() { + type Gen = super::ProcMetadataPre1630; + type Ref = RefProcMetadataPre1630; + assert_eq!(size_of::(), size_of::()); + assert_eq!(offset_of!(Gen, bytecode), offset_of!(Ref, bytecode)); + assert_eq!(offset_of!(Gen, locals), offset_of!(Ref, locals)); + assert_eq!(offset_of!(Gen, parameters), offset_of!(Ref, parameters)); + } + + #[test] + fn proc_metadata_post1630() { + type Gen = super::ProcMetadataPost1630; + type Ref = RefProcMetadataPost1630; + assert_eq!(size_of::(), size_of::()); + assert_eq!(offset_of!(Gen, bytecode), offset_of!(Ref, bytecode)); + assert_eq!(offset_of!(Gen, locals), offset_of!(Ref, locals)); + assert_eq!(offset_of!(Gen, parameters), offset_of!(Ref, parameters)); + } + + #[test] + fn proc_instance_inner_pre516() { + type Gen = super::ProcInstanceInnerPre516; + type Ref = RefProcInstanceInnerPre516; + assert_eq!(size_of::(), size_of::()); + assert_eq!(offset_of!(Gen, args_count), offset_of!(Ref, args_count)); + assert_eq!(offset_of!(Gen, args), offset_of!(Ref, args)); + assert_eq!(offset_of!(Gen, time_to_resume), offset_of!(Ref, time_to_resume)); + } + + #[test] + fn proc_instance_inner_post516() { + type Gen = super::ProcInstanceInnerPost516; + type Ref = RefProcInstanceInnerPost516; + assert_eq!(size_of::(), size_of::()); + assert_eq!(offset_of!(Gen, args_count), offset_of!(Ref, args_count)); + assert_eq!(offset_of!(Gen, args), offset_of!(Ref, args)); + assert_eq!(offset_of!(Gen, time_to_resume), offset_of!(Ref, time_to_resume)); + } + + #[test] + fn execution_context_pre1668() { + type Gen = super::ExecutionContextPre1668; + type Ref = RefExecutionContextPre1668; + assert_eq!(size_of::(), size_of::()); + assert_eq!(offset_of!(Gen, proc_instance), offset_of!(Ref, proc_instance)); + assert_eq!(offset_of!(Gen, filename), offset_of!(Ref, filename)); + assert_eq!(offset_of!(Gen, bytecode), offset_of!(Ref, bytecode)); + assert_eq!(offset_of!(Gen, dot), offset_of!(Ref, dot)); + assert_eq!(offset_of!(Gen, locals), offset_of!(Ref, locals)); + assert_eq!(offset_of!(Gen, locals_count), offset_of!(Ref, locals_count)); + } + + #[test] + fn execution_context_post1668() { + type Gen = super::ExecutionContextPost1668; + type Ref = RefExecutionContextPost1668; + assert_eq!(size_of::(), size_of::()); + assert_eq!(offset_of!(Gen, proc_instance), offset_of!(Ref, proc_instance)); + assert_eq!(offset_of!(Gen, filename), offset_of!(Ref, filename)); + assert_eq!(offset_of!(Gen, bytecode), offset_of!(Ref, bytecode)); + assert_eq!(offset_of!(Gen, dot), offset_of!(Ref, dot)); + assert_eq!(offset_of!(Gen, locals), offset_of!(Ref, locals)); + assert_eq!(offset_of!(Gen, locals_count), offset_of!(Ref, locals_count)); + } +} From f1334c5997a2dfca2abc2c12a57899164277a7df Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 26 May 2026 02:07:49 -0400 Subject: [PATCH 2/2] should address sophie's concerns, will double check this in a bit (it's 2 am lol) --- auxcov/src/codecov.rs | 9 +- auxtools-impl/src/versioned_struct.rs | 155 ++++++++++++++---------- auxtools/src/bytecode_manager.rs | 6 +- auxtools/src/debug.rs | 16 +-- auxtools/src/proc.rs | 6 +- auxtools/src/raw_types/procs.rs | 6 +- debug_server/src/instruction_hooking.rs | 22 ++-- debug_server/src/mem_profiler.rs | 2 +- debug_server/src/server.rs | 12 +- 9 files changed, 133 insertions(+), 101 deletions(-) diff --git a/auxcov/src/codecov.rs b/auxcov/src/codecov.rs index 24aec81..51aefb1 100644 --- a/auxcov/src/codecov.rs +++ b/auxcov/src/codecov.rs @@ -119,13 +119,13 @@ impl Tracker { // returns true if we need to pause pub fn process_dbg_line(&mut self, ctx: &raw_types::procs::ExecutionContext, proc_instance: &raw_types::procs::ProcInstance) { - if ctx.line() == 0 || !ctx.filename().valid() { + if *ctx.line() == 0 || !ctx.filename().valid() { return; } - let filename_id = ctx.filename(); + let filename_id = *ctx.filename(); let proc_map_index = proc_instance.proc.0 as usize; - let line = ctx.line() as usize; + let line = *ctx.line() as usize; let mut known_file_name: Option = None; for context in &mut self.contexts { @@ -206,7 +206,8 @@ impl InstructionHook for Tracker { let proc_instance_ref; unsafe { ctx_ref = &*ctx; - proc_instance_ref = &*ctx_ref.proc_instance(); + let instance_ptr: *mut raw_types::procs::ProcInstance = *ctx_ref.proc_instance(); + proc_instance_ref = &*instance_ptr; } self.process_dbg_line(ctx_ref, proc_instance_ref); diff --git a/auxtools-impl/src/versioned_struct.rs b/auxtools-impl/src/versioned_struct.rs index 067130c..9e44b90 100644 --- a/auxtools-impl/src/versioned_struct.rs +++ b/auxtools-impl/src/versioned_struct.rs @@ -164,98 +164,114 @@ fn generate_union(struct_ident: &Ident, vis: &Visibility, attrs: &[Attribute], v } } -fn build_dispatch_chain(variants: &[VersionVariant], helper_names: &[Ident]) -> TokenStream { +fn build_dispatch_chain(struct_ident: &Ident, variants: &[VersionVariant], helper_names: &[Ident]) -> TokenStream { let fallback = helper_names.last().unwrap(); - let mut chain = quote! { Self::#fallback }; + let mut chain = quote! { #struct_ident::#fallback }; for (variant, helper) in variants[..variants.len() - 1].iter().zip(&helper_names[..helper_names.len() - 1]).rev() { let cond = variant.condition.as_ref().unwrap(); chain = quote! { - if #cond { Self::#helper } else { #chain } + if #cond { #struct_ident::#helper } else { #chain } }; } chain } -fn generate_field_accessor(struct_ident: &Ident, field: &Field, variants: &[VersionVariant]) -> TokenStream { +fn generate_field_statics(struct_ident: &Ident, field: &Field, variants: &[VersionVariant]) -> TokenStream { let field_name = field.ident.as_ref().unwrap(); let field_ty = &field.ty; - - let helper_names: Vec = variants - .iter() - .map(|v| format_ident!("__versioned_{}_{}", field_name, variant_field_name(v))) - .collect(); - - let dispatch = build_dispatch_chain(variants, &helper_names); - - let helpers = variants.iter().zip(&helper_names).map(|(v, helper_name)| { - let union_field = variant_field_name(v); - quote! { - #[inline(never)] - fn #helper_name(this: &Self) -> #field_ty { - unsafe { this.#union_field.#field_name } - } - } - }); + let static_name = format_ident!("__VERSIONED_{}_{}", struct_ident, field_name); + let static_name_mut = format_ident!("__VERSIONED_MUT_{}_{}", struct_ident, field_name); + let fallback = variants.last().unwrap(); + let fallback_fn = format_ident!("__versioned_{}_{}", field_name, variant_field_name(fallback)); + let fallback_fn_mut = format_ident!("__versioned_{}_{}_mut", field_name, variant_field_name(fallback)); quote! { - pub fn #field_name(&self) -> #field_ty { - static REDIRECT: ::std::sync::OnceLock #field_ty> = - ::std::sync::OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { #dispatch })(self) - } - #(#helpers)* + #[allow(non_upper_case_globals)] + static mut #static_name: fn(&#struct_ident) -> &#field_ty = #struct_ident::#fallback_fn; + #[allow(non_upper_case_globals)] + static mut #static_name_mut: fn(&mut #struct_ident) -> &mut #field_ty = #struct_ident::#fallback_fn_mut; } } -fn generate_field_ptr_accessor(struct_ident: &Ident, field: &Field, variants: &[VersionVariant]) -> TokenStream { - let field_name = field.ident.as_ref().unwrap(); - let field_ty = &field.ty; - let ptr_name = format_ident!("{}_ptr", field_name); +fn generate_init_fn(struct_ident: &Ident, pub_fields: &[&VersionedField], variants: &[VersionVariant]) -> TokenStream { + let init_fn_name = format_ident!("__versioned_init_{}", struct_ident.to_string().to_lowercase()); - let helper_names: Vec = variants + let assignments: Vec<_> = pub_fields .iter() - .map(|v| format_ident!("__versioned_{}_{}_ptr", field_name, variant_field_name(v))) - .collect(); - - let dispatch = build_dispatch_chain(variants, &helper_names); - - let helpers = variants.iter().zip(&helper_names).map(|(v, helper_name)| { - let union_field = variant_field_name(v); - quote! { - #[inline(never)] - fn #helper_name(this: &mut Self) -> *mut #field_ty { - unsafe { ::std::ptr::addr_of_mut!(this.#union_field.#field_name) } + .map(|vf| { + let field_name = vf.field.ident.as_ref().unwrap(); + let static_name = format_ident!("__VERSIONED_{}_{}", struct_ident, field_name); + let static_name_mut = format_ident!("__VERSIONED_MUT_{}_{}", struct_ident, field_name); + + let helper_names: Vec = variants + .iter() + .map(|v| format_ident!("__versioned_{}_{}", field_name, variant_field_name(v))) + .collect(); + let helper_names_mut: Vec = variants + .iter() + .map(|v| format_ident!("__versioned_{}_{}_mut", field_name, variant_field_name(v))) + .collect(); + + let dispatch = build_dispatch_chain(struct_ident, variants, &helper_names); + let dispatch_mut = build_dispatch_chain(struct_ident, variants, &helper_names_mut); + + quote! { + #static_name = #dispatch; + #static_name_mut = #dispatch_mut; } - } - }); + }) + .collect(); quote! { - pub fn #ptr_name(&mut self) -> *mut #field_ty { - static REDIRECT: ::std::sync::OnceLock *mut #field_ty> = - ::std::sync::OnceLock::new(); - REDIRECT.get_or_init(|| unsafe { #dispatch })(self) + fn #init_fn_name() -> Result<(), String> { + unsafe { + #(#assignments)* + } + Ok(()) } - #(#helpers)* + crate::inventory::submit!(crate::init::PartialInitFunc(#init_fn_name)); } } -fn generate_impl(struct_ident: &Ident, variants: &[VersionVariant], fields: &[VersionedField]) -> TokenStream { - let pub_all_fields: Vec<_> = fields - .iter() - .filter(|vf| matches!(vf.version_info, FieldVersionInfo::AllVersions) && matches!(vf.field.vis, Visibility::Public(_))) - .collect(); +fn generate_impl(struct_ident: &Ident, variants: &[VersionVariant], pub_fields: &[&VersionedField]) -> TokenStream { + let methods = pub_fields.iter().map(|vf| { + let field = &vf.field; + let field_name = field.ident.as_ref().unwrap(); + let field_ty = &field.ty; + let field_name_mut = format_ident!("{}_mut", field_name); + let static_name = format_ident!("__VERSIONED_{}_{}", struct_ident, field_name); + let static_name_mut = format_ident!("__VERSIONED_MUT_{}_{}", struct_ident, field_name); + + let helpers = variants.iter().map(|v| { + let helper_name = format_ident!("__versioned_{}_{}", field_name, variant_field_name(v)); + let helper_name_mut = format_ident!("__versioned_{}_{}_mut", field_name, variant_field_name(v)); + let union_field = variant_field_name(v); + quote! { + fn #helper_name(this: &Self) -> &#field_ty { + unsafe { &this.#union_field.#field_name } + } + fn #helper_name_mut(this: &mut Self) -> &mut #field_ty { + unsafe { &mut this.#union_field.#field_name } + } + } + }); - let value_accessors = pub_all_fields.iter().map(|vf| generate_field_accessor(struct_ident, &vf.field, variants)); - let ptr_accessors = pub_all_fields - .iter() - .map(|vf| generate_field_ptr_accessor(struct_ident, &vf.field, variants)); + quote! { + #(#helpers)* + pub fn #field_name(&self) -> &#field_ty { + unsafe { #static_name(self) } + } + pub fn #field_name_mut(&mut self) -> &mut #field_ty { + unsafe { #static_name_mut(self) } + } + } + }); quote! { impl #struct_ident { - #(#value_accessors)* - #(#ptr_accessors)* + #(#methods)* } } } @@ -281,16 +297,31 @@ pub fn versioned(attr: TokenStream, item: TokenStream) -> TokenStream { Err(e) => return e.to_compile_error() }; + let pub_all_fields: Vec<&VersionedField> = fields + .iter() + .filter(|vf| matches!(vf.version_info, FieldVersionInfo::AllVersions) && matches!(vf.field.vis, Visibility::Public(_))) + .collect(); + let variant_structs = args .variants .iter() .map(|v| generate_variant_struct(&input.ident, &input.attrs, v, &fields)); let union_def = generate_union(&input.ident, &input.vis, &input.attrs, &args.variants); - let impl_block = generate_impl(&input.ident, &args.variants, &fields); + let field_statics = pub_all_fields + .iter() + .map(|vf| generate_field_statics(&input.ident, &vf.field, &args.variants)); + let init_fn = if pub_all_fields.is_empty() { + quote! {} + } else { + generate_init_fn(&input.ident, &pub_all_fields, &args.variants) + }; + let impl_block = generate_impl(&input.ident, &args.variants, &pub_all_fields); quote! { #(#variant_structs)* #union_def + #(#field_statics)* + #init_fn #impl_block } } diff --git a/auxtools/src/bytecode_manager.rs b/auxtools/src/bytecode_manager.rs index 7b0eacd..6b90015 100644 --- a/auxtools/src/bytecode_manager.rs +++ b/auxtools/src/bytecode_manager.rs @@ -33,7 +33,7 @@ pub fn init() { fn get_active_bytecode_ptrs() -> HashSet<*mut u32> { fn visit(dst: &mut HashSet<*mut u32>, frames: Vec) { for frame in frames { - let ptr = unsafe { (*frame.context).bytecode() }; + let ptr = unsafe { *(*frame.context).bytecode() }; dst.insert(ptr); } @@ -59,7 +59,7 @@ pub fn shutdown() { let proc = Proc::from_id(id).unwrap(); unsafe { - raw_types::misc::set_bytecode((*proc.entry).metadata.bytecode(), ptr, len); + raw_types::misc::set_bytecode(*(*proc.entry).metadata.bytecode(), ptr, len); } } @@ -104,6 +104,6 @@ pub fn set_bytecode(proc: &Proc, mut bytecode: Vec) { let len = u16::try_from(len).unwrap(); unsafe { - raw_types::misc::set_bytecode((*proc.entry).metadata.bytecode(), ptr, len); + raw_types::misc::set_bytecode(*(*proc.entry).metadata.bytecode(), ptr, len); } } diff --git a/auxtools/src/debug.rs b/auxtools/src/debug.rs index edea0bd..6f036c9 100644 --- a/auxtools/src/debug.rs +++ b/auxtools/src/debug.rs @@ -25,16 +25,16 @@ pub struct CallStacks { impl StackFrame { unsafe fn from_context(context: *mut procs::ExecutionContext) -> StackFrame { - let instance = (*context).proc_instance(); + let instance = *(*context).proc_instance(); let proc = Proc::from_id((*instance).proc).unwrap(); - let offset = (*context).bytecode_offset(); + let offset = *(*context).bytecode_offset(); let param_names = proc.parameter_names(); let local_names = proc.local_names(); let usr = Value::from_raw((*instance).usr); let src = Value::from_raw((*instance).src); - let dot = Value::from_raw((*context).dot()); + let dot = Value::from_raw(*(*context).dot()); // Make sure to handle arguments/locals with no names (when there are more // values than names) @@ -45,11 +45,11 @@ impl StackFrame { }) .collect(); - let locals = (0..(*context).locals_count()) + let locals = (0..*(*context).locals_count()) .map(|i| { ( local_names.get(i as usize).unwrap().clone(), - Value::from_raw(*((*context).locals()).add(i as usize)) + Value::from_raw(*(*(*context).locals()).add(i as usize)) ) }) .collect(); @@ -58,8 +58,8 @@ impl StackFrame { let mut file_name = None; let mut line_number = None; if (*context).filename().valid() { - file_name = Some(StringRef::from_id((*context).filename())); - line_number = Some((*context).line()); + file_name = Some(StringRef::from_id(*(*context).filename())); + line_number = Some(*(*context).line()); } // TODO: When set this? For all sleepers? @@ -125,7 +125,7 @@ impl CallStacks { unsafe { frames.push(StackFrame::from_context(context)); - context = (*context).parent_context(); + context = *(*context).parent_context(); } } diff --git a/auxtools/src/proc.rs b/auxtools/src/proc.rs index 0ecd703..63b10c7 100644 --- a/auxtools/src/proc.rs +++ b/auxtools/src/proc.rs @@ -80,14 +80,14 @@ impl Proc { pub fn parameter_names(&self) -> Vec { unsafe { - let (data, count) = raw_types::misc::get_parameters((*self.entry).metadata.parameters()); + let (data, count) = raw_types::misc::get_parameters(*(*self.entry).metadata.parameters()); (0..count).map(|i| StringRef::from_variable_id((*data.add(i)).name)).collect() } } pub fn local_names(&self) -> Vec { unsafe { - let (names, count) = raw_types::misc::get_locals((*self.entry).metadata.locals()); + let (names, count) = raw_types::misc::get_locals(*(*self.entry).metadata.locals()); (0..count).map(|i| StringRef::from_variable_id(*names.add(i))).collect() } } @@ -97,7 +97,7 @@ impl Proc { } pub unsafe fn bytecode_mut_ptr(&self) -> (*mut u32, u16) { - raw_types::misc::get_bytecode((*self.entry).metadata.bytecode()) + raw_types::misc::get_bytecode(*(*self.entry).metadata.bytecode()) } pub unsafe fn bytecode(&self) -> &[u32] { diff --git a/auxtools/src/raw_types/procs.rs b/auxtools/src/raw_types/procs.rs index 34e46d4..6e91551 100644 --- a/auxtools/src/raw_types/procs.rs +++ b/auxtools/src/raw_types/procs.rs @@ -47,15 +47,15 @@ pub struct ProcInstance { impl ProcInstance { pub fn args_count(&self) -> u32 { - self.inner.args_count() + *self.inner.args_count() } pub fn args(&self) -> *mut values::Value { - self.inner.args() + *self.inner.args() } pub fn time_to_resume(&self) -> u32 { - self.inner.time_to_resume() + *self.inner.time_to_resume() } } diff --git a/debug_server/src/instruction_hooking.rs b/debug_server/src/instruction_hooking.rs index b590422..e1834ed 100644 --- a/debug_server/src/instruction_hooking.rs +++ b/debug_server/src/instruction_hooking.rs @@ -76,7 +76,7 @@ lazy_static! { fn is_generated_proc(ctx: *mut raw_types::procs::ExecutionContext) -> bool { unsafe { - let instance = (*ctx).proc_instance(); + let instance = *(*ctx).proc_instance(); if let Some(proc) = Proc::from_id((*instance).proc) { return proc.path.ends_with("(init)"); } @@ -120,25 +120,25 @@ fn handle_breakpoint(ctx: *mut raw_types::procs::ExecutionContext, reason: Break ContinueKind::StepOver { stack_id } => { let ctx = get_proc_ctx(stack_id); DebuggerAction::StepOver { - target: ProcInstanceRef::new(unsafe { (*ctx).proc_instance() }) + target: ProcInstanceRef::new(unsafe { *(*ctx).proc_instance() }) } } ContinueKind::StepInto { stack_id } => { let ctx = get_proc_ctx(stack_id); DebuggerAction::StepInto { - parent: ProcInstanceRef::new(unsafe { (*ctx).proc_instance() }) + parent: ProcInstanceRef::new(unsafe { *(*ctx).proc_instance() }) } } ContinueKind::StepOut { stack_id } => { unsafe { // Just continue the code if we've got no parent let ctx = get_proc_ctx(stack_id); - let parent = (*ctx).parent_context(); + let parent = *(*ctx).parent_context(); if parent.is_null() { DebuggerAction::None } else { DebuggerAction::StepOut { - target: ProcInstanceRef::new((*parent).proc_instance()) + target: ProcInstanceRef::new(*(*parent).proc_instance()) } } } @@ -151,11 +151,11 @@ fn proc_instance_is_in_stack(mut ctx: *mut raw_types::procs::ExecutionContext, p let mut found = false; while !ctx.is_null() { - if proc_ref.is((*ctx).proc_instance()) { + if proc_ref.is(*(*ctx).proc_instance()) { found = true; break; } - ctx = (*ctx).parent_context(); + ctx = *(*ctx).parent_context(); } found @@ -220,7 +220,7 @@ impl InstructionHook for Server { } } - let opcode_ptr = unsafe { (*ctx).bytecode().add((*ctx).bytecode_offset() as usize) }; + let opcode_ptr = unsafe { (*(*ctx).bytecode()).add(*(*ctx).bytecode_offset() as usize) }; let opcode = unsafe { *opcode_ptr }; let is_dbgline = opcode == OPCODE_DBGLINE; @@ -248,7 +248,7 @@ impl InstructionHook for Server { // 1) The target context has disappeared - this means it has returned or runtimed // 2) We're inside the target context and on a DbgLine instruction DebuggerAction::StepOver { target } => { - if is_dbgline && target.is((*ctx).proc_instance()) { + if is_dbgline && target.is(*(*ctx).proc_instance()) { CURRENT_ACTION = DebuggerAction::BreakOnNext; } else { // If the context isn't in any stacks, it has just returned. Break! @@ -267,7 +267,7 @@ impl InstructionHook for Server { // 3) We're inside the parent context and on a DbgLine instruction DebuggerAction::StepInto { parent } => { if !is_generated_proc(ctx) { - let is_in_parent = parent.is((*ctx).proc_instance()); + let is_in_parent = parent.is(*(*ctx).proc_instance()); if is_dbgline && is_in_parent { CURRENT_ACTION = DebuggerAction::BreakOnNext; @@ -291,7 +291,7 @@ impl InstructionHook for Server { // Just breaks the moment we're in the target instance DebuggerAction::StepOut { target } => { if !is_generated_proc(ctx) { - if target.is((*ctx).proc_instance()) { + if target.is(*(*ctx).proc_instance()) { CURRENT_ACTION = DebuggerAction::None; CURRENT_ACTION = handle_breakpoint(ctx, BreakpointReason::Step); did_breakpoint = true; diff --git a/debug_server/src/mem_profiler.rs b/debug_server/src/mem_profiler.rs index b4c1f9a..e449037 100644 --- a/debug_server/src/mem_profiler.rs +++ b/debug_server/src/mem_profiler.rs @@ -227,7 +227,7 @@ impl State { return None; } - let instance = (*ctx).proc_instance(); + let instance = *(*ctx).proc_instance(); if instance.is_null() { return None; } diff --git a/debug_server/src/server.rs b/debug_server/src/server.rs index cb99782..41883e3 100644 --- a/debug_server/src/server.rs +++ b/debug_server/src/server.rs @@ -843,9 +843,9 @@ impl Server { unsafe { match slot { ArgType::Dot => { - let dot_ptr = (*ctx).dot_ptr(); - let _ = Value::from_raw_owned(*dot_ptr); - *dot_ptr = value.raw; + let dot = (*ctx).dot_mut(); + let _ = Value::from_raw_owned(*dot); + *dot = value.raw; } ArgType::Usr => { let _ = Value::from_raw_owned((*instance).usr); @@ -862,7 +862,7 @@ impl Server { (*arg) = value.raw; } ArgType::Local(idx) => { - let locals = (*ctx).locals(); + let locals = *(*ctx).locals(); let local = locals.add(*idx as usize); let _ = Value::from_raw_owned(*local); (*local) = value.raw; @@ -1066,8 +1066,8 @@ impl Server { // Exit now if this is a conditional breakpoint and the condition doesn't pass! if reason == BreakpointReason::Breakpoint { - let proc = unsafe { (*(*_ctx).proc_instance()).proc }; - let offset = unsafe { (*_ctx).bytecode_offset() }; + let proc = unsafe { (*(*(*_ctx).proc_instance())).proc }; + let offset = unsafe { *(*_ctx).bytecode_offset() }; let condition = self.conditional_breakpoints.get(&(proc, offset)).cloned(); if let Some(condition) = condition {