wasm: Cache objects via data hash (XXH3)

This commit is contained in:
Luke Street 2025-03-21 08:27:19 -06:00
parent 311de887ec
commit 7b00a9e9f2
7 changed files with 60 additions and 14 deletions

15
Cargo.lock generated
View File

@ -3280,7 +3280,7 @@ dependencies = [
[[package]] [[package]]
name = "objdiff-cli" name = "objdiff-cli"
version = "3.0.0-beta.4" version = "3.0.0-beta.5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"argp", "argp",
@ -3303,7 +3303,7 @@ dependencies = [
[[package]] [[package]]
name = "objdiff-core" name = "objdiff-core"
version = "3.0.0-beta.4" version = "3.0.0-beta.5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arm-attr", "arm-attr",
@ -3356,7 +3356,7 @@ dependencies = [
[[package]] [[package]]
name = "objdiff-gui" name = "objdiff-gui"
version = "3.0.0-beta.4" version = "3.0.0-beta.5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cfg-if", "cfg-if",
@ -3392,7 +3392,7 @@ dependencies = [
[[package]] [[package]]
name = "objdiff-wasm" name = "objdiff-wasm"
version = "3.0.0-beta.4" version = "3.0.0-beta.5"
dependencies = [ dependencies = [
"log", "log",
"objdiff-core", "objdiff-core",
@ -3400,6 +3400,7 @@ dependencies = [
"talc", "talc",
"wit-bindgen", "wit-bindgen",
"wit-deps", "wit-deps",
"xxhash-rust",
] ]
[[package]] [[package]]
@ -6547,6 +6548,12 @@ version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
[[package]]
name = "xxhash-rust"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3"
[[package]] [[package]]
name = "yaxpeax-arch" name = "yaxpeax-arch"
version = "0.3.2" version = "0.3.2"

View File

@ -14,7 +14,7 @@ strip = "debuginfo"
codegen-units = 1 codegen-units = 1
[workspace.package] [workspace.package]
version = "3.0.0-beta.4" version = "3.0.0-beta.5"
authors = ["Luke Street <luke@street.dev>"] authors = ["Luke Street <luke@street.dev>"]
edition = "2024" edition = "2024"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"

View File

@ -25,6 +25,7 @@ std = ["objdiff-core/std"]
[dependencies] [dependencies]
log = { version = "0.4", default-features = false } log = { version = "0.4", default-features = false }
regex = { version = "1.11", default-features = false, features = ["unicode-case"] } regex = { version = "1.11", default-features = false, features = ["unicode-case"] }
xxhash-rust = { version = "0.8", default-features = false, features = ["xxh3"] }
[dependencies.objdiff-core] [dependencies.objdiff-core]
path = "../objdiff-core" path = "../objdiff-core"

View File

@ -1,12 +1,12 @@
{ {
"name": "objdiff-wasm", "name": "objdiff-wasm",
"version": "3.0.0-beta.4", "version": "3.0.0-beta.5",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "objdiff-wasm", "name": "objdiff-wasm",
"version": "3.0.0-beta.4", "version": "3.0.0-beta.5",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^1.9.3", "@biomejs/biome": "^1.9.3",

View File

@ -1,6 +1,6 @@
{ {
"name": "objdiff-wasm", "name": "objdiff-wasm",
"version": "3.0.0-beta.4", "version": "3.0.0-beta.5",
"description": "A local diffing tool for decompilation projects.", "description": "A local diffing tool for decompilation projects.",
"author": { "author": {
"name": "Luke Street", "name": "Luke Street",

View File

@ -1,6 +1,6 @@
use alloc::{ use alloc::{
format, format,
rc::Rc, rc::{Rc, Weak},
str::FromStr, str::FromStr,
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
@ -9,6 +9,7 @@ use core::cell::RefCell;
use objdiff_core::{diff, obj}; use objdiff_core::{diff, obj};
use regex::{Regex, RegexBuilder}; use regex::{Regex, RegexBuilder};
use xxhash_rust::xxh3::xxh3_64;
use super::logging; use super::logging;
@ -41,8 +42,7 @@ impl Guest for Component {
fn version() -> String { env!("CARGO_PKG_VERSION").to_string() } fn version() -> String { env!("CARGO_PKG_VERSION").to_string() }
} }
#[repr(transparent)] struct ResourceObject(Rc<obj::Object>, u64);
struct ResourceObject(Rc<obj::Object>);
struct ResourceObjectDiff(Rc<obj::Object>, diff::ObjectDiff); struct ResourceObjectDiff(Rc<obj::Object>, diff::ObjectDiff);
@ -421,13 +421,49 @@ impl GuestDiffConfig for ResourceDiffConfig {
} }
} }
struct CachedObject(Weak<obj::Object>, u64);
struct ObjectCache(RefCell<Vec<CachedObject>>);
impl ObjectCache {
#[inline]
const fn new() -> Self { Self(RefCell::new(Vec::new())) }
}
impl core::ops::Deref for ObjectCache {
type Target = RefCell<Vec<CachedObject>>;
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 { impl GuestObject for ResourceObject {
fn parse(data: Vec<u8>, diff_config: DiffConfigBorrow) -> Result<Object, String> { fn parse(data: Vec<u8>, diff_config: DiffConfigBorrow) -> Result<Object, String> {
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::<ResourceDiffConfig>().0.borrow(); let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
obj::read::parse(&data, &diff_config) let obj = Rc::new(obj::read::parse(&data, &diff_config).map_err(|e| e.to_string())?);
.map(|o| Object::new(ResourceObject(Rc::new(o)))) OBJECT_CACHE.borrow_mut().push(CachedObject(Rc::downgrade(&obj), hash));
.map_err(|e| e.to_string()) Ok(Object::new(ResourceObject(obj, hash)))
} }
fn hash(&self) -> u64 { self.1 }
} }
impl GuestObjectDiff for ResourceObjectDiff { impl GuestObjectDiff for ResourceObjectDiff {

View File

@ -20,6 +20,8 @@ interface diff {
data: list<u8>, data: list<u8>,
config: borrow<diff-config>, config: borrow<diff-config>,
) -> result<object, string>; ) -> result<object, string>;
hash: func() -> u64;
} }
resource object-diff { resource object-diff {