From 7b00a9e9f2939b25a757f0bb431efc8aca4decf4 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 21 Mar 2025 08:27:19 -0600 Subject: [PATCH] wasm: Cache objects via data hash (XXH3) --- Cargo.lock | 15 ++++++++--- Cargo.toml | 2 +- objdiff-wasm/Cargo.toml | 1 + objdiff-wasm/package-lock.json | 4 +-- objdiff-wasm/package.json | 2 +- objdiff-wasm/src/api.rs | 48 +++++++++++++++++++++++++++++----- objdiff-wasm/wit/objdiff.wit | 2 ++ 7 files changed, 60 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a865e05..10d30a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3280,7 +3280,7 @@ dependencies = [ [[package]] name = "objdiff-cli" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" dependencies = [ "anyhow", "argp", @@ -3303,7 +3303,7 @@ dependencies = [ [[package]] name = "objdiff-core" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" dependencies = [ "anyhow", "arm-attr", @@ -3356,7 +3356,7 @@ dependencies = [ [[package]] name = "objdiff-gui" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" dependencies = [ "anyhow", "cfg-if", @@ -3392,7 +3392,7 @@ dependencies = [ [[package]] name = "objdiff-wasm" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" dependencies = [ "log", "objdiff-core", @@ -3400,6 +3400,7 @@ dependencies = [ "talc", "wit-bindgen", "wit-deps", + "xxhash-rust", ] [[package]] @@ -6547,6 +6548,12 @@ version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "yaxpeax-arch" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index 2ff7a1a..22754ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ strip = "debuginfo" codegen-units = 1 [workspace.package] -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" authors = ["Luke Street "] edition = "2024" license = "MIT OR Apache-2.0" diff --git a/objdiff-wasm/Cargo.toml b/objdiff-wasm/Cargo.toml index bd2aa52..8432f40 100644 --- a/objdiff-wasm/Cargo.toml +++ b/objdiff-wasm/Cargo.toml @@ -25,6 +25,7 @@ std = ["objdiff-core/std"] [dependencies] log = { version = "0.4", default-features = false } regex = { version = "1.11", default-features = false, features = ["unicode-case"] } +xxhash-rust = { version = "0.8", default-features = false, features = ["xxh3"] } [dependencies.objdiff-core] path = "../objdiff-core" diff --git a/objdiff-wasm/package-lock.json b/objdiff-wasm/package-lock.json index 55bc6d9..b8ca332 100644 --- a/objdiff-wasm/package-lock.json +++ b/objdiff-wasm/package-lock.json @@ -1,12 +1,12 @@ { "name": "objdiff-wasm", - "version": "3.0.0-beta.4", + "version": "3.0.0-beta.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "objdiff-wasm", - "version": "3.0.0-beta.4", + "version": "3.0.0-beta.5", "license": "MIT OR Apache-2.0", "devDependencies": { "@biomejs/biome": "^1.9.3", diff --git a/objdiff-wasm/package.json b/objdiff-wasm/package.json index 5fafd7a..46c11a8 100644 --- a/objdiff-wasm/package.json +++ b/objdiff-wasm/package.json @@ -1,6 +1,6 @@ { "name": "objdiff-wasm", - "version": "3.0.0-beta.4", + "version": "3.0.0-beta.5", "description": "A local diffing tool for decompilation projects.", "author": { "name": "Luke Street", diff --git a/objdiff-wasm/src/api.rs b/objdiff-wasm/src/api.rs index 3b28f2f..1fea05c 100644 --- a/objdiff-wasm/src/api.rs +++ b/objdiff-wasm/src/api.rs @@ -1,6 +1,6 @@ use alloc::{ format, - rc::Rc, + rc::{Rc, Weak}, str::FromStr, string::{String, ToString}, vec::Vec, @@ -9,6 +9,7 @@ use core::cell::RefCell; use objdiff_core::{diff, obj}; use regex::{Regex, RegexBuilder}; +use xxhash_rust::xxh3::xxh3_64; use super::logging; @@ -41,8 +42,7 @@ impl Guest for Component { fn version() -> String { env!("CARGO_PKG_VERSION").to_string() } } -#[repr(transparent)] -struct ResourceObject(Rc); +struct ResourceObject(Rc, u64); struct ResourceObjectDiff(Rc, diff::ObjectDiff); @@ -421,13 +421,49 @@ impl GuestDiffConfig for ResourceDiffConfig { } } +struct CachedObject(Weak, u64); + +struct ObjectCache(RefCell>); + +impl ObjectCache { + #[inline] + const fn new() -> Self { Self(RefCell::new(Vec::new())) } +} + +impl core::ops::Deref for ObjectCache { + type Target = RefCell>; + + fn deref(&self) -> &Self::Target { &self.0 } +} + +// Assume single-threaded environment +unsafe impl Sync for ObjectCache {} + +static OBJECT_CACHE: ObjectCache = ObjectCache::new(); + impl GuestObject for ResourceObject { fn parse(data: Vec, diff_config: DiffConfigBorrow) -> Result { + let hash = xxh3_64(&data); + let mut cached = None; + OBJECT_CACHE.borrow_mut().retain(|c| { + if c.0.strong_count() == 0 { + return false; + } + if c.1 == hash { + cached = c.0.upgrade(); + } + true + }); + if let Some(obj) = cached { + return Ok(Object::new(ResourceObject(obj, hash))); + } let diff_config = diff_config.get::().0.borrow(); - obj::read::parse(&data, &diff_config) - .map(|o| Object::new(ResourceObject(Rc::new(o)))) - .map_err(|e| e.to_string()) + let obj = Rc::new(obj::read::parse(&data, &diff_config).map_err(|e| e.to_string())?); + OBJECT_CACHE.borrow_mut().push(CachedObject(Rc::downgrade(&obj), hash)); + Ok(Object::new(ResourceObject(obj, hash))) } + + fn hash(&self) -> u64 { self.1 } } impl GuestObjectDiff for ResourceObjectDiff { diff --git a/objdiff-wasm/wit/objdiff.wit b/objdiff-wasm/wit/objdiff.wit index 939e7ee..8a614e5 100644 --- a/objdiff-wasm/wit/objdiff.wit +++ b/objdiff-wasm/wit/objdiff.wit @@ -20,6 +20,8 @@ interface diff { data: list, config: borrow, ) -> result; + + hash: func() -> u64; } resource object-diff {