use std::sync::{
Arc, RwLock,
atomic::{AtomicBool, Ordering},
};
use concatenated_module_entries::*;
pub use determine_export_assignments::DetermineExportAssignmentsKey;
use determine_export_assignments::*;
use get_exports_type::*;
use get_mode::*;
use get_side_effects_connection_state::*;
use module_graph_hash::*;
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
use swc_core::atoms::Atom;
use crate::{
ConcatenationEntry, ConnectionState, DependencyId, ExportInfo, ExportsType, ModuleIdentifier,
RuntimeKey,
};
pub type ModuleGraphCacheArtifact = Arc<ModuleGraphCacheArtifactInner>;
#[derive(Debug, Default)]
pub struct ModuleGraphCacheArtifactInner {
freezed: AtomicBool,
get_mode_cache: GetModeCache,
determine_export_assignments_cache: DetermineExportAssignmentsCache,
get_exports_type_cache: GetExportsTypeCache,
get_side_effects_connection_state_cache: GetSideEffectsConnectionStateCache,
concatenated_module_entries: ConcatenatedModuleEntriesCache,
module_graph_hash_cache: ModuleGraphHashCache,
}
impl ModuleGraphCacheArtifactInner {
pub fn freeze(&self) {
self.get_mode_cache.freeze();
self.determine_export_assignments_cache.freeze();
self.get_exports_type_cache.freeze();
self.get_side_effects_connection_state_cache.freeze();
self.concatenated_module_entries.freeze();
self.module_graph_hash_cache.freeze();
self.freezed.store(true, Ordering::Release);
}
pub fn unfreeze(&self) {
self.freezed.store(false, Ordering::Release);
}
pub fn cached_get_exports_type<F: FnOnce() -> ExportsType>(
&self,
key: GetExportsTypeCacheKey,
f: F,
) -> ExportsType {
if !self.freezed.load(Ordering::Acquire) {
return f();
}
match self.get_exports_type_cache.get(&key) {
Some(value) => value,
None => {
let value = f();
self.get_exports_type_cache.set(key, value);
value
}
}
}
pub fn cached_get_mode<F: FnOnce() -> ExportMode>(
&self,
key: GetModeCacheKey,
f: F,
) -> ExportMode {
if !self.freezed.load(Ordering::Acquire) {
return f();
}
match self.get_mode_cache.get(&key) {
Some(value) => value,
None => {
let value = f();
self.get_mode_cache.set(key, value.clone());
value
}
}
}
pub fn cached_determine_export_assignments<F: FnOnce() -> DetermineExportAssignmentsValue>(
&self,
key: DetermineExportAssignmentsKey,
f: F,
) -> DetermineExportAssignmentsValue {
if !self.freezed.load(Ordering::Acquire) {
return f();
}
match self.determine_export_assignments_cache.get(&key) {
Some(value) => value,
None => {
let value = f();
self
.determine_export_assignments_cache
.set(key, value.clone());
value
}
}
}
pub fn cached_get_side_effects_connection_state<F: FnOnce() -> ConnectionState>(
&self,
key: ModuleIdentifier,
f: F,
) -> ConnectionState {
if !self.freezed.load(Ordering::Acquire) {
return f();
}
match self.get_side_effects_connection_state_cache.get(&key) {
Some(value) => value,
None => {
let value = f();
self.get_side_effects_connection_state_cache.set(key, value);
value
}
}
}
pub fn cached_concatenated_module_entries<F: FnOnce() -> Vec<ConcatenationEntry>>(
&self,
key: ConcatenatedModuleEntriesCacheKey,
f: F,
) -> Vec<ConcatenationEntry> {
if !self.freezed.load(Ordering::Acquire) {
return f();
}
match self.concatenated_module_entries.get(&key) {
Some(value) => value,
None => {
let value = f();
self.concatenated_module_entries.set(key, value.clone());
value
}
}
}
pub fn cached_module_graph_hash<F: FnOnce() -> u64>(
&self,
key: ModuleGraphHashCacheKey,
f: F,
) -> u64 {
if !self.freezed.load(Ordering::Acquire) {
return f();
}
match self.module_graph_hash_cache.get(&key) {
Some(value) => value,
None => {
let value = f();
self.module_graph_hash_cache.set(key, value);
value
}
}
}
}
pub(super) mod module_graph_hash {
use rspack_util::fx_hash::FxDashMap;
use crate::{ModuleIdentifier, RuntimeKey};
pub type ModuleGraphHashCacheKey = (ModuleIdentifier, Option<RuntimeKey>);
#[derive(Debug, Default)]
pub struct ModuleGraphHashCache {
cache: FxDashMap<ModuleGraphHashCacheKey, u64>,
}
impl ModuleGraphHashCache {
pub fn freeze(&self) {
self.cache.clear();
}
pub fn get(&self, key: &ModuleGraphHashCacheKey) -> Option<u64> {
self.cache.get(key).map(|v| *v.value())
}
pub fn set(&self, key: ModuleGraphHashCacheKey, value: u64) {
self.cache.insert(key, value);
}
}
}
pub(super) mod concatenated_module_entries {
use rspack_util::fx_hash::FxDashMap;
use super::*;
use crate::ModuleIdentifier;
pub type ConcatenatedModuleEntriesCacheKey = (ModuleIdentifier, Option<RuntimeKey>);
#[derive(Debug, Default)]
pub struct ConcatenatedModuleEntriesCache {
cache: FxDashMap<ConcatenatedModuleEntriesCacheKey, Vec<ConcatenationEntry>>,
}
impl ConcatenatedModuleEntriesCache {
pub fn freeze(&self) {
self.cache.clear();
}
pub fn get(&self, key: &ConcatenatedModuleEntriesCacheKey) -> Option<Vec<ConcatenationEntry>> {
self.cache.get(key).map(|v| v.value().clone())
}
pub fn set(&self, key: ConcatenatedModuleEntriesCacheKey, value: Vec<ConcatenationEntry>) {
self.cache.insert(key, value);
}
}
}
pub(super) mod get_side_effects_connection_state {
use rspack_collections::IdentifierDashMap;
use crate::{ConnectionState, ModuleIdentifier};
#[derive(Debug, Default)]
pub struct GetSideEffectsConnectionStateCache {
cache: IdentifierDashMap<ConnectionState>,
}
impl GetSideEffectsConnectionStateCache {
pub fn freeze(&self) {
self.cache.clear();
}
pub fn get(&self, key: &ModuleIdentifier) -> Option<ConnectionState> {
self.cache.get(key).map(|v| *v.value())
}
pub fn set(&self, key: ModuleIdentifier, value: ConnectionState) {
self.cache.insert(key, value);
}
}
}
pub(super) mod get_exports_type {
use rspack_collections::IdentifierDashMap;
use crate::{ExportsType, ModuleIdentifier};
pub type GetExportsTypeCacheKey = (ModuleIdentifier, bool);
#[derive(Debug, Default)]
pub struct GetExportsTypeCache {
strict_cache: IdentifierDashMap<ExportsType>,
dynamic_cache: IdentifierDashMap<ExportsType>,
}
impl GetExportsTypeCache {
pub fn freeze(&self) {
self.strict_cache.clear();
self.dynamic_cache.clear();
}
pub fn get(&self, key: &GetExportsTypeCacheKey) -> Option<ExportsType> {
let (module_identifier, strict) = key;
if *strict {
self.strict_cache.get(module_identifier).map(|x| *x)
} else {
self.dynamic_cache.get(module_identifier).map(|x| *x)
}
}
pub fn set(&self, key: GetExportsTypeCacheKey, value: ExportsType) {
let (module_identifier, strict) = key;
if strict {
self.strict_cache.insert(module_identifier, value);
} else {
self.dynamic_cache.insert(module_identifier, value);
}
}
}
}
pub(super) mod get_mode {
use super::*;
pub type GetModeCacheKey = (DependencyId, Option<RuntimeKey>);
#[derive(Debug, Default)]
pub struct GetModeCache {
cache: RwLock<HashMap<GetModeCacheKey, ExportMode>>,
}
impl GetModeCache {
pub fn freeze(&self) {
self.cache.write().expect("should get lock").clear();
}
pub fn get(&self, key: &GetModeCacheKey) -> Option<ExportMode> {
let inner = self.cache.read().expect("should get lock");
inner.get(key).cloned()
}
pub fn set(&self, key: GetModeCacheKey, value: ExportMode) {
self
.cache
.write()
.expect("should get lock")
.insert(key, value);
}
}
}
pub(super) mod determine_export_assignments {
use super::*;
use crate::ModuleIdentifier;
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum DetermineExportAssignmentsKey {
All(ModuleIdentifier),
Other(DependencyId),
}
pub type DetermineExportAssignmentsValue = (Vec<Atom>, Vec<usize>);
#[derive(Debug, Default)]
pub struct DetermineExportAssignmentsCache {
cache: RwLock<HashMap<DetermineExportAssignmentsKey, DetermineExportAssignmentsValue>>,
}
impl DetermineExportAssignmentsCache {
pub fn freeze(&self) {
self.cache.write().expect("should get lock").clear();
}
pub fn get(
&self,
key: &DetermineExportAssignmentsKey,
) -> Option<DetermineExportAssignmentsValue> {
let inner = self.cache.read().expect("should get lock");
inner.get(key).cloned()
}
pub fn set(&self, key: DetermineExportAssignmentsKey, value: DetermineExportAssignmentsValue) {
self
.cache
.write()
.expect("should get lock")
.insert(key, value);
}
}
}
#[derive(Debug, Clone)]
pub struct NormalReexportItem {
pub name: Atom,
pub ids: Vec<Atom>,
pub hidden: bool,
pub checked: bool,
pub export_info: ExportInfo,
}
#[derive(Debug, Clone)]
pub enum ExportMode {
Missing,
LazyMake,
Unused(ExportModeUnused),
EmptyStar(ExportModeEmptyStar),
ReexportDynamicDefault(ExportModeReexportDynamicDefault),
ReexportNamedDefault(ExportModeReexportNamedDefault),
ReexportNamespaceObject(ExportModeReexportNamespaceObject),
ReexportFakeNamespaceObject(ExportModeFakeNamespaceObject),
ReexportUndefined(ExportModeReexportUndefined),
NormalReexport(ExportModeNormalReexport),
DynamicReexport(Box<ExportModeDynamicReexport>),
}
#[derive(Debug, Clone)]
pub struct ExportModeUnused {
pub name: Atom,
}
#[derive(Debug, Clone)]
pub struct ExportModeEmptyStar {
pub hidden: Option<HashSet<Atom>>,
}
#[derive(Debug, Clone)]
pub struct ExportModeReexportDynamicDefault {
pub name: Atom,
}
#[derive(Debug, Clone)]
pub struct ExportModeReexportNamedDefault {
pub name: Atom,
pub partial_namespace_export_info: ExportInfo,
}
#[derive(Debug, Clone)]
pub struct ExportModeReexportNamespaceObject {
pub name: Atom,
pub partial_namespace_export_info: ExportInfo,
}
#[derive(Debug, Clone)]
pub struct ExportModeFakeNamespaceObject {
pub name: Atom,
pub fake_type: u8,
pub partial_namespace_export_info: ExportInfo,
}
#[derive(Debug, Clone)]
pub struct ExportModeReexportUndefined {
pub name: Atom,
}
#[derive(Debug, Clone)]
pub struct ExportModeNormalReexport {
pub items: Vec<NormalReexportItem>,
}
#[derive(Debug, Clone)]
pub struct ExportModeDynamicReexport {
pub ignored: HashSet<Atom>,
pub hidden: Option<HashSet<Atom>>,
}
#[derive(Debug, Default)]
pub struct StarReexportsInfo {
pub exports: Option<HashSet<Atom>>,
pub checked: Option<HashSet<Atom>>,
pub ignored_exports: HashSet<Atom>,
pub hidden: Option<HashSet<Atom>>,
}