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