1use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
2use std::{
3 collections::HashMap,
4 ops::{Deref, DerefMut},
5 path::PathBuf,
6 sync::Arc,
7 time::SystemTime,
8};
9use sway_error::{
10 error::CompileError,
11 warning::{CompileInfo, CompileWarning},
12};
13use sway_types::{IdentUnique, ProgramId, SourceId, Spanned};
14
15use crate::{
16 decl_engine::{DeclId, DeclRef},
17 language::ty::{TyFunctionDecl, TyFunctionSig, TyModule},
18 namespace, Engines, Programs,
19};
20
21#[derive(Debug, Clone, Hash, PartialEq, Eq)]
22pub struct ModuleCacheKey {
23 pub path: Arc<PathBuf>,
24 pub include_tests: bool,
25}
26
27impl ModuleCacheKey {
28 pub fn new(path: Arc<PathBuf>, include_tests: bool) -> Self {
29 Self {
30 path,
31 include_tests,
32 }
33 }
34}
35
36#[derive(Clone, Debug)]
37pub struct ModuleCommonInfo {
38 pub path: Arc<PathBuf>,
39 pub hash: u64,
40 pub include_tests: bool,
41 pub dependencies: Vec<Arc<PathBuf>>,
42}
43
44#[derive(Clone, Debug)]
45pub struct ParsedModuleInfo {
46 pub modified_time: Option<SystemTime>,
47 pub version: Option<u64>,
48}
49
50#[derive(Clone, Debug)]
51pub struct TypedModuleInfo {
52 pub module: Arc<TyModule>,
53 pub namespace_module: Arc<namespace::Module>,
54 pub version: Option<u64>,
55}
56
57#[derive(Clone, Debug)]
58pub struct ModuleCacheEntry {
59 pub common: ModuleCommonInfo,
60 pub parsed: ParsedModuleInfo,
61 pub typed: Option<TypedModuleInfo>,
62}
63
64impl ModuleCacheEntry {
65 pub fn new(common: ModuleCommonInfo, parsed: ParsedModuleInfo) -> Self {
66 Self {
67 common,
68 parsed,
69 typed: None,
70 }
71 }
72
73 pub fn is_typed(&self) -> bool {
74 self.typed.is_some()
75 }
76
77 pub fn set_typed(&mut self, typed: TypedModuleInfo) {
78 self.typed = Some(typed);
79 }
80
81 pub fn update_common(&mut self, new_common: ModuleCommonInfo) {
82 self.common = new_common;
83 }
84
85 pub fn update_parsed(&mut self, new_parsed: ParsedModuleInfo) {
86 self.parsed = new_parsed;
87 }
88
89 pub fn update_parsed_and_common(
90 &mut self,
91 new_common: ModuleCommonInfo,
92 new_parsed: ParsedModuleInfo,
93 ) {
94 self.common = new_common;
95 self.parsed = new_parsed;
96 }
97}
98
99#[derive(Debug, Default, Clone)]
100pub struct ModuleCacheMap(HashMap<ModuleCacheKey, ModuleCacheEntry>);
101
102impl Deref for ModuleCacheMap {
103 type Target = HashMap<ModuleCacheKey, ModuleCacheEntry>;
104 fn deref(&self) -> &Self::Target {
105 &self.0
106 }
107}
108
109impl DerefMut for ModuleCacheMap {
110 fn deref_mut(&mut self) -> &mut Self::Target {
111 &mut self.0
112 }
113}
114
115impl ModuleCacheMap {
116 pub fn update_entry(
117 &mut self,
118 key: &ModuleCacheKey,
119 new_common: ModuleCommonInfo,
120 new_parsed: ParsedModuleInfo,
121 ) {
122 if let Some(entry) = self.get_mut(key) {
123 entry.update_parsed_and_common(new_common, new_parsed);
124 } else {
125 self.insert(key.clone(), ModuleCacheEntry::new(new_common, new_parsed));
126 }
127 }
128}
129
130pub type ProgramsCacheMap = HashMap<Arc<PathBuf>, ProgramsCacheEntry>;
131pub type FunctionsCacheMap = HashMap<(IdentUnique, String), FunctionCacheEntry>;
132
133#[derive(Clone, Debug)]
134pub struct ProgramsCacheEntry {
135 pub path: Arc<PathBuf>,
136 pub programs: Programs,
137 pub handler_data: (Vec<CompileError>, Vec<CompileWarning>, Vec<CompileInfo>),
138}
139
140#[derive(Clone, Debug)]
141pub struct FunctionCacheEntry {
142 pub fn_decl: DeclRef<DeclId<TyFunctionDecl>>,
143}
144
145#[derive(Debug, Default)]
146pub struct QueryEngine {
147 programs_cache: CowCache<ProgramsCacheMap>,
149 pub module_cache: CowCache<ModuleCacheMap>,
150 function_cache: CowCache<FunctionsCacheMap>,
152}
153
154impl Clone for QueryEngine {
155 fn clone(&self) -> Self {
156 Self {
157 programs_cache: CowCache::new(self.programs_cache.read().clone()),
158 module_cache: CowCache::new(self.module_cache.read().clone()),
159 function_cache: CowCache::new(self.function_cache.read().clone()),
160 }
161 }
162}
163
164impl QueryEngine {
165 pub fn update_or_insert_parsed_module_cache_entry(&self, entry: ModuleCacheEntry) {
166 let path = entry.common.path.clone();
167 let include_tests = entry.common.include_tests;
168 let key = ModuleCacheKey::new(path, include_tests);
169 let mut cache = self.module_cache.write();
170 cache.update_entry(&key, entry.common, entry.parsed);
171 }
172
173 pub fn update_typed_module_cache_entry(&self, key: &ModuleCacheKey, entry: TypedModuleInfo) {
174 let mut cache = self.module_cache.write();
175 cache.get_mut(key).unwrap().set_typed(entry);
176 }
177
178 pub fn get_programs_cache_entry(&self, path: &Arc<PathBuf>) -> Option<ProgramsCacheEntry> {
179 let cache = self.programs_cache.read();
180 cache.get(path).cloned()
181 }
182
183 pub fn insert_programs_cache_entry(&self, entry: ProgramsCacheEntry) {
184 let mut cache = self.programs_cache.write();
185 cache.insert(entry.path.clone(), entry);
186 }
187
188 pub fn get_function(
189 &self,
190 engines: &Engines,
191 ident: &IdentUnique,
192 sig: TyFunctionSig,
193 ) -> Option<DeclRef<DeclId<TyFunctionDecl>>> {
194 let cache = self.function_cache.read();
195 cache
196 .get(&(ident.clone(), sig.get_type_str(engines)))
197 .map(|s| s.fn_decl.clone())
198 }
199
200 pub fn insert_function(
201 &self,
202 engines: &Engines,
203 ident: IdentUnique,
204 sig: TyFunctionSig,
205 fn_decl: DeclRef<DeclId<TyFunctionDecl>>,
206 ) {
207 let mut cache = self.function_cache.write();
208 cache.insert(
209 (ident, sig.get_type_str(engines)),
210 FunctionCacheEntry { fn_decl },
211 );
212 }
213
214 pub fn clear_module(&mut self, source_id: &SourceId) {
216 self.function_cache
217 .write()
218 .retain(|(ident, _), _| (ident.span().source_id() != Some(source_id)));
219 }
220
221 pub fn clear_program(&mut self, program_id: &ProgramId) {
223 self.function_cache.write().retain(|(ident, _), _| {
224 ident
225 .span()
226 .source_id()
227 .is_none_or(|id| id.program_id() != *program_id)
228 });
229 }
230
231 pub fn commit(&self) {
233 self.programs_cache.commit();
234 self.module_cache.commit();
235 self.function_cache.commit();
236 }
237}
238
239#[derive(Debug, Default)]
250pub struct CowCache<T: Clone> {
251 inner: Arc<RwLock<T>>,
252 local: RwLock<Option<T>>,
253}
254
255impl<T: Clone> CowCache<T> {
256 pub fn new(value: T) -> Self {
260 Self {
261 inner: Arc::new(RwLock::new(value)),
262 local: RwLock::new(None),
263 }
264 }
265
266 pub fn read(&self) -> impl Deref<Target = T> + '_ {
273 if self.local.read().is_some() {
274 ReadGuard::Local(self.local.read())
275 } else {
276 ReadGuard::Shared(self.inner.read())
277 }
278 }
279
280 pub fn write(&self) -> impl DerefMut<Target = T> + '_ {
285 let mut local = self.local.write();
286 if local.is_none() {
287 *local = Some(self.inner.read().clone());
288 }
289 WriteGuard(local)
290 }
291
292 pub fn commit(&self) {
297 if let Some(local) = self.local.write().take() {
298 *self.inner.write() = local;
299 }
300 }
301}
302
303enum ReadGuard<'a, T: Clone> {
305 Local(RwLockReadGuard<'a, Option<T>>),
306 Shared(RwLockReadGuard<'a, T>),
307}
308
309impl<T: Clone> Deref for ReadGuard<'_, T> {
310 type Target = T;
311
312 fn deref(&self) -> &Self::Target {
313 match self {
314 ReadGuard::Local(r) => r.as_ref().unwrap(),
315 ReadGuard::Shared(guard) => guard.deref(),
316 }
317 }
318}
319
320struct WriteGuard<'a, T: Clone>(RwLockWriteGuard<'a, Option<T>>);
322
323impl<T: Clone> Deref for WriteGuard<'_, T> {
324 type Target = T;
325
326 fn deref(&self) -> &Self::Target {
327 self.0.as_ref().unwrap()
328 }
329}
330
331impl<T: Clone> DerefMut for WriteGuard<'_, T> {
332 fn deref_mut(&mut self) -> &mut Self::Target {
333 self.0.as_mut().unwrap()
334 }
335}