From 10b119e0333f7dd40cb28a98f4fd0094542915f1 Mon Sep 17 00:00:00 2001 From: kalpak <307643502+kalpakprod@users.noreply.github.com> Date: Wed, 21 Oct 2026 01:38:34 +0400 Subject: [PATCH] Runtime: reuse a cached import binding only for the (library, nid) it was resolved for Import slots are per-corpus ordinals, so two corpora reuse the same slot numbers for different imports. Store the (library, nid) in each cached binding and re-resolve on mismatch. --- include/psprecomp/runtime.hpp | 10 +++++++++- src/runtime.cpp | 12 ++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/psprecomp/runtime.hpp b/include/psprecomp/runtime.hpp index d922300..3516412 100644 --- a/include/psprecomp/runtime.hpp +++ b/include/psprecomp/runtime.hpp @@ -203,7 +203,15 @@ class Runtime : public CorpusRuntime { std::unordered_map> hle_; std::unordered_map native_fast_paths_; - std::vector import_bindings_; + // Import slots are per-corpus ordinals: two corpora reuse the same slot + // numbers for different imports, so a cached entry names the (library, + // nid) it was resolved for and is only reused for that pair. + struct ImportBinding { + const HleFunction *function{}; + std::string library; + std::uint32_t nid{}; + }; + std::vector import_bindings_; std::filesystem::path game_root_; bool stopped_{}; std::string stop_reason_; diff --git a/src/runtime.cpp b/src/runtime.cpp index c3c33a6..1214a3c 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -152,7 +152,7 @@ Runtime::Runtime(std::uint32_t ram_size) // Most commercial PSP titles use a few hundred import stubs. Seed a small // binding table so first use of a late-numbered import does not reallocate // in the middle of guest execution; larger profiles can still grow it. - import_bindings_.resize(256u, nullptr); + import_bindings_.resize(256u); hle_histogram_enabled_ = std::getenv("PSPRECOMP_HLE_HISTOGRAM") != nullptr; #if defined(PSPRECOMP_AOT_PRODUCTION_FASTPATHS) track_dispatch_counters_ = false; @@ -1276,7 +1276,11 @@ void Runtime::invoke_import_cached(std::uint32_t slot, std::string_view library, std::uint32_t nid, AllegrexContext &ctx) { if (hle_histogram_enabled_) ++hle_histogram_[hle_key(library, nid)]; - const HleFunction *bound = slot < import_bindings_.size() ? import_bindings_[slot] : nullptr; + const HleFunction *bound = nullptr; + if (slot < import_bindings_.size()) { + const ImportBinding &cached = import_bindings_[slot]; + if (cached.function != nullptr && cached.nid == nid && cached.library == library) bound = cached.function; + } if (bound == nullptr) { const auto library_it = hle_.find(library); const auto function_it = library_it != hle_.end() @@ -1287,9 +1291,9 @@ void Runtime::invoke_import_cached(std::uint32_t slot, std::string_view library, stop("Missing HLE import " + library_name + "::" + name); return; } - if (slot >= import_bindings_.size()) import_bindings_.resize(static_cast(slot) + 1u, nullptr); + if (slot >= import_bindings_.size()) import_bindings_.resize(static_cast(slot) + 1u); bound = &function_it->second; - import_bindings_[slot] = bound; + import_bindings_[slot] = ImportBinding{bound, std::string(library), nid}; } (*bound)(*this, ctx);