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]]
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"

View File

@ -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 <luke@street.dev>"]
edition = "2024"
license = "MIT OR Apache-2.0"

View File

@ -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"

View File

@ -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",

View File

@ -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",

View File

@ -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<obj::Object>);
struct ResourceObject(Rc<obj::Object>, u64);
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 {
fn parse(data: Vec<u8>, diff_config: DiffConfigBorrow) -> Result<Object, String> {
let diff_config = diff_config.get::<ResourceDiffConfig>().0.borrow();
obj::read::parse(&data, &diff_config)
.map(|o| Object::new(ResourceObject(Rc::new(o))))
.map_err(|e| e.to_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 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 {

View File

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