use std::collections::HashSet;
use super::*;
use crate::value::VmMutex;
struct SharedModuleInstance {
source_identity: (usize, usize),
provenance: ModuleProvenance,
denied_builtins: Arc<HashSet<String>>,
loaded: Arc<LoadedModule>,
}
impl SharedModuleInstance {
fn matches(
&self,
source_identity: (usize, usize),
provenance: ModuleProvenance,
denied: &Arc<HashSet<String>>,
) -> bool {
self.source_identity == source_identity
&& self.provenance == provenance
&& (Arc::ptr_eq(&self.denied_builtins, denied) || *self.denied_builtins == **denied)
}
}
#[derive(Default)]
pub(crate) struct SharedModuleInstanceStore {
entries: VmMutex<BTreeMap<PathBuf, Vec<SharedModuleInstance>>>,
#[cfg(test)]
instantiations: VmMutex<BTreeMap<PathBuf, usize>>,
}
impl SharedModuleInstanceStore {
#[cfg(test)]
pub(crate) fn instantiation_count(&self, synthetic: &Path) -> usize {
self.instantiations
.lock()
.get(synthetic)
.copied()
.unwrap_or(0)
}
}
fn source_identity(source: &'static str) -> (usize, usize) {
(source.as_ptr() as usize, source.len())
}
impl Vm {
pub(super) fn shared_module_instance(
&self,
synthetic: &Path,
source: &'static str,
) -> Option<Arc<LoadedModule>> {
let identity = source_identity(source);
let entries = self.shared_module_instances.entries.lock();
entries
.get(synthetic)?
.iter()
.find(|entry| entry.matches(identity, self.module_provenance, &self.denied_builtins))
.map(|entry| Arc::clone(&entry.loaded))
}
pub(super) fn publish_shared_module_instance(
&self,
synthetic: &Path,
source: &'static str,
artifact: &PreparedModuleArtifact,
loaded: &Arc<LoadedModule>,
) {
#[cfg(test)]
{
*self
.shared_module_instances
.instantiations
.lock()
.entry(synthetic.to_path_buf())
.or_default() += 1;
}
if artifact.provenance != ModuleProvenance::EmbeddedStdlib
|| loaded._module_state.lock().has_mutable_binding()
{
return;
}
let identity = source_identity(source);
let mut entries = self.shared_module_instances.entries.lock();
let imports_are_stored = artifact.imports.iter().all(|import| {
let Some(dependency) = self
.cache_key_for_import(&import.path)
.ok()
.and_then(|key| self.module_cache.get(&key).map(|dep| (key, dep)))
else {
return false;
};
entries.get(&dependency.0).is_some_and(|slots| {
slots
.iter()
.any(|entry| Arc::ptr_eq(&entry.loaded, dependency.1))
})
});
if !imports_are_stored {
return;
}
let slots = entries.entry(synthetic.to_path_buf()).or_default();
if slots
.iter()
.any(|entry| entry.matches(identity, self.module_provenance, &self.denied_builtins))
{
return;
}
slots.push(SharedModuleInstance {
source_identity: identity,
provenance: self.module_provenance,
denied_builtins: Arc::clone(&self.denied_builtins),
loaded: Arc::clone(loaded),
});
}
}