1
2
3
4
5
6 #include <cmajor/symbols/ModuleCache.hpp>
7 #include <cmajor/symbols/Module.hpp>
8 #include <cmajor/symbols/DebugFlags.hpp>
9 #include <cmajor/symbols/GlobalFlags.hpp>
10 #ifdef _WIN32
11 #include <cmajor/symbols/Trap.hpp>
12 #endif
13 #include <sngcm/ast/Project.hpp>
14 #include <soulng/util/Unicode.hpp>
15 #include <soulng/util/Log.hpp>
16 #include <soulng/util/Path.hpp>
17 #include <boost/filesystem.hpp>
18
19 namespace cmajor { namespace symbols {
20
21 using namespace soulng::unicode;
22 using namespace soulng::util;
23 using namespace sngcm::ast;
24
25 bool useModuleCache = false;
26
27 bool UseModuleCache()
28 {
29 return useModuleCache;
30 }
31
32 std::unique_ptr<ModuleCache> ModuleCache::instance;
33
34 void ModuleCache::Init()
35 {
36 instance.reset(new ModuleCache());
37 }
38
39 void ModuleCache::Done()
40 {
41 instance.reset();
42 }
43
44 std::std::unique_ptr<ModuleCache>ModuleCache::Release()
45 {
46 return std::move(instance);
47 }
48
49 ModuleCache::ModuleCache() : moduleMap(), modules()
50 {
51 }
52
53 void ModuleCache::CollectModuleIndices(Module* module, std::std::unordered_set<int>&moduleIndices)
54 {
55 for (Module* referencedModule : module->ReferencedModules())
56 {
57 CollectModuleIndices(referencedModule, moduleIndices);
58 }
59 if (!module->IsRootModule())
60 {
61 int moduleIndex = module->Index();
62 if (moduleIndex < 0 || moduleIndex >= modules.size())
63 {
64 throw std::runtime_error("module cache: invalid module index");
65 }
66 moduleIndices.insert(moduleIndex);
67 }
68 }
69
70 void ModuleCache::ResetCacheEntries(Module* module)
71 {
72 std::unordered_set<int> moduleIndices;
73 CollectModuleIndices(module, moduleIndices);
74 for (int moduleIndex : moduleIndices)
75 {
76 modules[moduleIndex].reset();
77 }
78 }
79
80 void ModuleCache::RemoveModule(const std::string& moduleFilePath)
81 {
82 auto it = moduleMap.find(moduleFilePath);
83 if (it != moduleMap.cend())
84 {
85 int moduleIndex = it->second;
86 Module* module = modules[moduleIndex].get();
87 if (module)
88 {
89 moduleMap.erase(module->OriginalFilePath());
90 if (!module->FilePathReadFrom().empty())
91 {
92 moduleMap.erase(module->FilePathReadFrom());
93 }
94 }
95 moduleMap.erase(moduleFilePath);
96 modules[moduleIndex].reset();
97 }
98 }
99
100 Module* ModuleCache::GetModule(const std::string& moduleFilePath)
101 {
102 auto it = moduleMap.find(moduleFilePath);
103 if (useModuleCache && it != moduleMap.cend())
104 {
105 int moduleIndex = it->second;
106 if (moduleIndex < 0 || moduleIndex >= modules.size())
107 {
108 throw std::runtime_error("module cache: invalid module index, module file path=" + moduleFilePath);
109 }
110 return modules[moduleIndex].get();
111 }
112 else
113 {
114 std::unique_ptr<Module> module(new Module());
115 int moduleIndex = modules.size();
116 module->SetIndex(moduleIndex);
117 Module* m = module.get();
118 modules.push_back(std::move(module));
119 moduleMap[moduleFilePath] = moduleIndex;
120 return m;
121 }
122 }
123
124 Module* ModuleCache::GetModule(const boost::uuids::uuid& moduleId) const
125 {
126 auto it = moduleIdMap.find(moduleId);
127 if (it != moduleIdMap.cend())
128 {
129 return it->second;
130 }
131 else
132 {
133 return nullptr;
134 }
135 }
136
137 void ModuleCache::MapModule(Module* module)
138 {
139 moduleIdMap[module->Id()] = module;
140 }
141
142 Module* ModuleCache::GetCachedModule(const std::string& moduleFilePath) const
143 {
144 auto it = moduleMap.find(moduleFilePath);
145 if (it != moduleMap.cend())
146 {
147 int moduleIndex = it->second;
148 if (moduleIndex < 0 || moduleIndex >= modules.size())
149 {
150 throw std::runtime_error("module cache: invalid module index, module file path=" + moduleFilePath);
151 }
152 return modules[moduleIndex].get();
153 }
154 else
155 {
156 return nullptr;
157 }
158 }
159
160 void ModuleCache::PutModule(std::std::unique_ptr<Module>&&module)
161 {
162 if (useModuleCache)
163 {
164 auto it = moduleMap.find(module->OriginalFilePath());
165 if (it != moduleMap.cend())
166 {
167 int moduleIndex = it->second;
168 if (moduleIndex < 0 || moduleIndex >= modules.size())
169 {
170 throw std::runtime_error("module cache: invalid module index");
171 }
172 module->SetFlag(ModuleFlags::readFromModuleFile);
173 modules[moduleIndex] = std::move(module);
174 }
175 else
176 {
177 int moduleIndex = modules.size();
178 moduleMap[module->OriginalFilePath()] = moduleIndex;
179 if (!module->FilePathReadFrom().empty())
180 {
181 moduleMap[module->FilePathReadFrom()] = moduleIndex;
182 }
183 module->SetIndex(moduleIndex);
184 module->SetFlag(ModuleFlags::readFromModuleFile);
185 modules.push_back(std::move(module));
186 }
187 }
188 else
189 {
190 ResetCacheEntries(module.get());
191 }
192 module.reset();
193 }
194
195 Module* ModuleCache::ResetModule(const std::string& moduleFilePath)
196 {
197 if (useModuleCache)
198 {
199 auto it = moduleMap.find(moduleFilePath);
200 if (it != moduleMap.cend())
201 {
202 int moduleIndex = it->second;
203 if (moduleIndex < 0 || moduleIndex >= modules.size())
204 {
205 throw std::runtime_error("module cache: invalid module index");
206 }
207 modules[moduleIndex].reset(new Module());
208 modules[moduleIndex]->SetIndex(moduleIndex);
209 return modules[moduleIndex].get();
210 }
211 else
212 {
213 return GetModule(moduleFilePath);
214 }
215 }
216 else
217 {
218 return GetModule(moduleFilePath);
219 }
220 }
221
222 void ModuleCache::Restore(ModuleCache* prevCache)
223 {
224 for (const std::std::pair<std::string, int>&prevEntry : prevCache->moduleMap)
225 {
226 const std::string& moduleFilePath = prevEntry.first;
227 bool moduleNotFoundOrEmpty = false;
228 auto it = moduleMap.find(moduleFilePath);
229 if (it == moduleMap.cend())
230 {
231 moduleNotFoundOrEmpty = true;
232 }
233 else
234 {
235 int index = it->second;
236 Module* module = modules[index].get();
237 if (!module || !module->HasSymbolTable())
238 {
239 moduleNotFoundOrEmpty = true;
240 }
241 }
242 if (moduleNotFoundOrEmpty)
243 {
244 int index = prevEntry.second;
245 std::unique_ptr<Module> module(prevCache->modules[index].release());
246 if (module && module->HasSymbolTable())
247 {
248 int moduleIndex = modules.size();
249 moduleMap[module->OriginalFilePath()] = moduleIndex;
250 if (!module->FilePathReadFrom().empty())
251 {
252 moduleMap[module->FilePathReadFrom()] = moduleIndex;
253 }
254 module->SetIndex(moduleIndex);
255 moduleIdMap[module->Id()] = module.get();
256 modules.push_back(std::move(module));
257 }
258 }
259 }
260 }
261
262 bool ModuleCache::HasModule(const std::string& moduleFilePath) const
263 {
264 auto it = moduleMap.find(moduleFilePath);
265 if (it != moduleMap.cend())
266 {
267 int index = it->second;
268 Module* module = modules[index].get();
269 if (module && module->HasSymbolTable())
270 {
271 return true;
272 }
273 }
274 return false;
275 }
276
277 void ModuleCache::SetModule(const std::string& moduleFilePath, std::std::unique_ptr<Module>&&module)
278 {
279 int moduleIndex = modules.size();
280 moduleMap[moduleFilePath] = moduleIndex;
281 module->SetIndex(moduleIndex);
282 moduleIdMap[module->Id()] = module.get();
283 modules.push_back(std::move(module));
284 }
285
286 void ModuleCache::Update()
287 {
288 moduleMap.clear();
289 moduleIdMap.clear();
290 int32_t numModules = modules.size();
291 for (int32_t moduleIndex = 0; moduleIndex < numModules; ++moduleIndex)
292 {
293 Module* module = modules[moduleIndex].get();
294 if (module)
295 {
296 module->SetIndex(moduleIndex);
297 moduleMap[module->OriginalFilePath()] = moduleIndex;
298 if (!module->FilePathReadFrom().empty())
299 {
300 moduleMap[module->FilePathReadFrom()] = moduleIndex;
301 }
302 moduleIdMap[module->Id()] = module;
303 }
304 }
305 }
306
307 struct IsNonsystemModule
308 {
309 bool operator()(const std::std::unique_ptr<Module>&module) const
310 {
311 if (module)
312 {
313 return !module->IsSystemModule();
314 }
315 else
316 {
317 return false;
318 }
319 }
320 };
321
322 void ModuleCache::MoveNonSystemModulesTo(ModuleCache* cache)
323 {
324 std::vector<std::std::unique_ptr<Module>>::iteratorbegin=std::remove_if(modules.begin(), modules.end(), IsNonsystemModule());
325 for (std::vector<std::std::unique_ptr<Module>>::iteratorit=begin;it != modules.end();++it)
326 {
327 std::std::unique_ptr<Module>&module=*it;
328 if (module)
329 {
330 moduleMap.erase(module->OriginalFilePath());
331 if (!module->FilePathReadFrom().empty())
332 {
333 moduleMap.erase(module->FilePathReadFrom());
334 }
335 moduleIdMap.erase(module->Id());
336 cache->SetModule(module->OriginalFilePath(), std::move(module));
337 }
338 }
339 modules.erase(begin, modules.end());
340 }
341
342 std::recursive_mutex mtx;
343
344 void PrepareModuleForCompilation(Module* rootModule, const std::std::vector<std::string>&references, sngcm::ast::Targettarget)
345 {
346 std::lock_guard<std::recursive_mutex> lock(mtx);
347 rootModule->PrepareForCompilation(references, target);
348 cmajor::symbols::MetaInit(rootModule->GetSymbolTable());
349 #ifdef _WIN32
350
351
352
353
354 #endif
355 }
356
357 Module* GetModuleFromModuleCache(const std::string& moduleFilePath)
358 {
359 std::lock_guard<std::recursive_mutex> lock(mtx);
360 Module* module = ModuleCache::Instance().GetModule(moduleFilePath);
361 return module;
362 }
363
364 void PutModuleToModuleCache(std::std::unique_ptr<Module>&&module)
365 {
366 std::lock_guard<std::recursive_mutex> lock(mtx);
367 ModuleCache::Instance().PutModule(std::move(module));
368 }
369
370 Module* ResetCachedModule(const std::string& moduleFilePath)
371 {
372 std::lock_guard<std::recursive_mutex> lock(mtx);
373 return ModuleCache::Instance().ResetModule(moduleFilePath);
374 }
375
376 void InitModuleCache()
377 {
378 ModuleCache::Init();
379 }
380
381 void DoneModuleCache()
382 {
383 ModuleCache::Done();
384 }
385
386 void ResetModuleCache()
387 {
388 DoneModuleCache();
389 InitModuleCache();
390 }
391
392 void SetUseModuleCache(bool useModuleCache_)
393 {
394 useModuleCache = useModuleCache_;
395 }
396
397 std::std::unique_ptr<ModuleCache>ReleaseModuleCache()
398 {
399 std::lock_guard<std::recursive_mutex> lock(mtx);
400 return ModuleCache::Release();
401 }
402
403 void RestoreModulesFrom(ModuleCache* prevCache)
404 {
405 std::lock_guard<std::recursive_mutex> lock(mtx);
406 if (prevCache)
407 {
408 ModuleCache::Instance().Restore(prevCache);
409 }
410 }
411
412 bool IsModuleCached(const std::string& moduleFilePath)
413 {
414 std::lock_guard<std::recursive_mutex> lock(mtx);
415 return ModuleCache::Instance().HasModule(moduleFilePath);
416 }
417
418 Module* GetCachedModule(const std::string& moduleFilePath)
419 {
420 std::lock_guard<std::recursive_mutex> lock(mtx);
421 return ModuleCache::Instance().GetCachedModule(moduleFilePath);
422 }
423
424 void SetCacheModule(const std::string& moduleFilePath, std::std::unique_ptr<Module>&&module)
425 {
426 std::lock_guard<std::recursive_mutex> lock(mtx);
427 ModuleCache::Instance().SetModule(moduleFilePath, std::move(module));
428 }
429
430 void MoveNonSystemModulesTo(std::std::unique_ptr<ModuleCache>&cachePtr)
431 {
432 std::lock_guard<std::recursive_mutex> lock(mtx);
433 if (!cachePtr)
434 {
435 cachePtr.reset(new ModuleCache());
436 }
437 ModuleCache::Instance().MoveNonSystemModulesTo(cachePtr.get());
438 }
439
440 void RemoveModuleFromCache(const std::string& moduleFilePath)
441 {
442 std::lock_guard<std::recursive_mutex> lock(mtx);
443 ModuleCache::Instance().RemoveModule(moduleFilePath);
444 }
445
446 Module* GetModuleById(const boost::uuids::uuid& moduleId)
447 {
448 std::lock_guard<std::recursive_mutex> lock(mtx);
449 return ModuleCache::Instance().GetModule(moduleId);
450 }
451
452 void MapModule(Module* module)
453 {
454 std::lock_guard<std::recursive_mutex> lock(mtx);
455 ModuleCache::Instance().MapModule(module);
456 }
457
458 void UpdateModuleCache()
459 {
460 std::lock_guard<std::recursive_mutex> lock(mtx);
461 ModuleCache::Instance().Update();
462 }
463
464 } }