1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  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* modulestd::std::unordered_set<int>&moduleIndices)
 54 {
 55     for (Module* referencedModule : module->ReferencedModules())
 56     {
 57         CollectModuleIndices(referencedModulemoduleIndices);
 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(modulemoduleIndices);
 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::stringint>&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& moduleFilePathstd::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(beginmodules.end());
340 }
341 
342 std::recursive_mutex mtx;
343 
344 void PrepareModuleForCompilation(Module* rootModuleconst std::std::vector<std::string>&referencessngcm::ast::Targettarget)
345 {
346     std::lock_guard<std::recursive_mutex> lock(mtx);
347     rootModule->PrepareForCompilation(referencestarget);
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& moduleFilePathstd::std::unique_ptr<Module>&&module)
425 {
426     std::lock_guard<std::recursive_mutex> lock(mtx);
427     ModuleCache::Instance().SetModule(moduleFilePathstd::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 } } // namespace cmajor::symbols