| /* | |
| Copyright 2019 Alain Dargelas | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| /* | |
| * File: PPCache.cpp | |
| * Author: alain | |
| * | |
| * Created on April 23, 2017, 8:49 PM | |
| */ | |
| #include "CommandLine/CommandLineParser.h" | |
| #include "ErrorReporting/ErrorContainer.h" | |
| #include "SourceCompile/SymbolTable.h" | |
| #include "SourceCompile/CompilationUnit.h" | |
| #include "SourceCompile/PreprocessFile.h" | |
| #include "SourceCompile/CompileSourceFile.h" | |
| #include "SourceCompile/Compiler.h" | |
| #include "Utils/StringUtils.h" | |
| #include "Utils/FileUtils.h" | |
| #include "Cache/Cache.h" | |
| #include "Cache/PPCache.h" | |
| #include "flatbuffers/util.h" | |
| #include <cstdio> | |
| #include <ctime> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <algorithm> | |
| #include "Package/Precompiled.h" | |
| using namespace SURELOG; | |
| PPCache::PPCache(PreprocessFile* pp) : m_pp(pp), m_isPrecompiled(false) {} | |
| PPCache::PPCache(const PPCache& orig) {} | |
| PPCache::~PPCache() {} | |
| static std::string FlbSchemaVersion = "1.0"; | |
| std::string PPCache::getCacheFileName_(std::string svFileName) { | |
| Precompiled* prec = Precompiled::getSingleton(); | |
| SymbolId cacheDirId = | |
| m_pp->getCompileSourceFile()->getCommandLineParser()->getCacheDir(); | |
| if (svFileName == "") svFileName = m_pp->getFileName(LINE1); | |
| std::string root = svFileName; | |
| root = StringUtils::getRootFileName(root); | |
| if (prec->isFilePrecompiled(root)) { | |
| std::string packageRepDir = m_pp->getSymbol(m_pp->getCompileSourceFile() | |
| ->getCommandLineParser() | |
| ->getPrecompiledDir()); | |
| cacheDirId = m_pp->getCompileSourceFile() | |
| ->getCommandLineParser() | |
| ->getSymbolTable() | |
| ->registerSymbol(packageRepDir); | |
| m_isPrecompiled = true; | |
| } | |
| std::string cacheDirName = m_pp->getSymbol(cacheDirId); | |
| Library* lib = m_pp->getLibrary(); | |
| std::string libName = lib->getName() + "/"; | |
| svFileName = StringUtils::getRootFileName(svFileName); | |
| std::string cacheFileName = cacheDirName + libName + svFileName + ".slpp"; | |
| FileUtils::mkDir(std::string(cacheDirName + libName).c_str()); | |
| return cacheFileName; | |
| } | |
| template <class T> | |
| static bool compareVectors(std::vector<T> a, std::vector<T> b) { | |
| std::sort(a.begin(), a.end()); | |
| std::sort(b.begin(), b.end()); | |
| return (a == b); | |
| } | |
| bool PPCache::restore_(std::string cacheFileName) { | |
| uint8_t* buffer_pointer = openFlatBuffers(cacheFileName); | |
| if (buffer_pointer == NULL) return false; | |
| const MACROCACHE::PPCache* ppcache = MACROCACHE::GetPPCache(buffer_pointer); | |
| const flatbuffers::Vector<flatbuffers::Offset<MACROCACHE::Macro>>* macros = | |
| ppcache->m_macros(); | |
| for (unsigned int i = 0; i < macros->Length(); i++) { | |
| const MACROCACHE::Macro* macro = macros->Get(i); | |
| std::vector<std::string> args; | |
| std::vector<std::string> tokens; | |
| for (unsigned int j = 0; j < macro->m_arguments()->Length(); j++) { | |
| args.push_back(macro->m_arguments()->Get(j)->c_str()); | |
| } | |
| for (unsigned int j = 0; j < macro->m_tokens()->Length(); j++) { | |
| tokens.push_back(macro->m_tokens()->Get(j)->c_str()); | |
| } | |
| m_pp->recordMacro(macro->m_name()->c_str(), macro->m_line(), | |
| macro->m_column(), args, tokens); | |
| } | |
| SymbolTable canonicalSymbols; | |
| restoreErrors(ppcache->m_errors(), ppcache->m_symbols(), canonicalSymbols, | |
| m_pp->getCompileSourceFile()->getErrorContainer(), | |
| m_pp->getCompileSourceFile()->getSymbolTable()); | |
| /* Restore `timescale directives */ | |
| const flatbuffers::Vector<flatbuffers::Offset<CACHE::TimeInfo>>* timeinfos = | |
| ppcache->m_timeInfo(); | |
| for (unsigned int i = 0; i < timeinfos->Length(); i++) { | |
| const CACHE::TimeInfo* fbtimeinfo = timeinfos->Get(i); | |
| TimeInfo timeInfo; | |
| timeInfo.m_type = (TimeInfo::Type)fbtimeinfo->m_type(); | |
| timeInfo.m_fileId = fbtimeinfo->m_fileId(); | |
| timeInfo.m_line = fbtimeinfo->m_line(); | |
| timeInfo.m_timeUnit = (TimeInfo::Unit)fbtimeinfo->m_timeUnit(); | |
| timeInfo.m_timeUnitValue = fbtimeinfo->m_timeUnitValue(); | |
| timeInfo.m_timePrecision = (TimeInfo::Unit)fbtimeinfo->m_timePrecision(); | |
| timeInfo.m_timePrecisionValue = fbtimeinfo->m_timePrecisionValue(); | |
| m_pp->getCompilationUnit()->recordTimeInfo(timeInfo); | |
| } | |
| auto includes = ppcache->m_includes(); | |
| if (includes) | |
| for (unsigned int i = 0; i < includes->Length(); i++) { | |
| auto include = includes->Get(i); | |
| restore_(getCacheFileName_(include->c_str())); | |
| } | |
| if (ppcache->m_body() && ppcache->m_body()->c_str()) { | |
| m_pp->append(ppcache->m_body()->c_str()); | |
| } | |
| delete[] buffer_pointer; | |
| return true; | |
| } | |
| bool PPCache::checkCacheIsValid_(std::string cacheFileName) { | |
| uint8_t* buffer_pointer = openFlatBuffers(cacheFileName); | |
| if (buffer_pointer == NULL) { | |
| delete[] buffer_pointer; | |
| return false; | |
| } | |
| if (!MACROCACHE::PPCacheBufferHasIdentifier(buffer_pointer)) { | |
| delete[] buffer_pointer; | |
| return false; | |
| } | |
| const MACROCACHE::PPCache* ppcache = MACROCACHE::GetPPCache(buffer_pointer); | |
| auto header = ppcache->m_header(); | |
| if (!m_isPrecompiled) { | |
| if (!checkIfCacheIsValid(header, FlbSchemaVersion, cacheFileName)) { | |
| delete[] buffer_pointer; | |
| return false; | |
| } | |
| /* Cache the include paths list */ | |
| auto includePathList = | |
| m_pp->getCompileSourceFile()->getCommandLineParser()->getIncludePaths(); | |
| std::vector<std::string> include_path_vec; | |
| for (auto path : includePathList) { | |
| std::string spath = m_pp->getSymbol(path); | |
| include_path_vec.push_back(spath); | |
| } | |
| std::vector<std::string> cache_include_path_vec; | |
| for (unsigned int i = 0; i < ppcache->m_cmd_include_paths()->Length(); | |
| i++) { | |
| const std::string path = ppcache->m_cmd_include_paths()->Get(i)->c_str(); | |
| cache_include_path_vec.push_back(path); | |
| } | |
| if (!compareVectors(include_path_vec, cache_include_path_vec)) { | |
| delete[] buffer_pointer; | |
| return false; | |
| } | |
| /* Cache the defines on the command line */ | |
| auto defineList = | |
| m_pp->getCompileSourceFile()->getCommandLineParser()->getDefineList(); | |
| std::vector<std::string> define_vec; | |
| for (auto definePair : defineList) { | |
| std::string spath = | |
| m_pp->getSymbol(definePair.first) + "=" + definePair.second; | |
| define_vec.push_back(spath); | |
| } | |
| std::vector<std::string> cache_define_vec; | |
| for (unsigned int i = 0; i < ppcache->m_cmd_define_options()->Length(); | |
| i++) { | |
| const std::string path = ppcache->m_cmd_define_options()->Get(i)->c_str(); | |
| cache_define_vec.push_back(path); | |
| } | |
| if (!compareVectors(define_vec, cache_define_vec)) { | |
| delete[] buffer_pointer; | |
| return false; | |
| } | |
| /* All includes*/ | |
| auto includes = ppcache->m_includes(); | |
| if (includes) | |
| for (unsigned int i = 0; i < includes->Length(); i++) { | |
| auto include = includes->Get(i); | |
| if (!checkCacheIsValid_(getCacheFileName_(include->c_str()))) { | |
| delete[] buffer_pointer; | |
| return false; | |
| } | |
| } | |
| } | |
| delete[] buffer_pointer; | |
| return true; | |
| } | |
| bool PPCache::restore() { | |
| bool cacheAllowed = | |
| m_pp->getCompileSourceFile()->getCommandLineParser()->cacheAllowed(); | |
| if (!cacheAllowed) return false; | |
| if (m_pp->isMacroBody()) return false; | |
| std::string cacheFileName = getCacheFileName_(); | |
| if (!checkCacheIsValid_(cacheFileName)) { | |
| return false; | |
| } | |
| return restore_(cacheFileName); | |
| } | |
| bool PPCache::save() { | |
| bool cacheAllowed = | |
| m_pp->getCompileSourceFile()->getCommandLineParser()->cacheAllowed(); | |
| if (!cacheAllowed) return false; | |
| std::string svFileName = m_pp->getFileName(LINE1); | |
| std::string origFileName = svFileName; | |
| std::string cacheFileName = getCacheFileName_(); | |
| if (m_pp->isMacroBody()) return false; | |
| flatbuffers::FlatBufferBuilder builder(1024); | |
| /* Create header section */ | |
| auto header = createHeader(builder, FlbSchemaVersion, origFileName); | |
| /* Cache the macro definitions */ | |
| const MacroStorage& macros = m_pp->getMacros(); | |
| std::vector<flatbuffers::Offset<MACROCACHE::Macro>> macro_vec; | |
| for (MacroStorage::const_iterator itr = macros.begin(); itr != macros.end(); | |
| itr++) { | |
| std::string macroName = (*itr).first; | |
| MacroInfo* info = (*itr).second; | |
| auto name = builder.CreateString(macroName); | |
| MACROCACHE::MacroType type = (info->m_type == MacroInfo::WITH_ARGS) | |
| ? MACROCACHE::MacroType_WITH_ARGS | |
| : MACROCACHE::MacroType_NO_ARGS; | |
| auto args = builder.CreateVectorOfStrings(info->m_arguments); | |
| auto tokens = builder.CreateVectorOfStrings(info->m_tokens); | |
| macro_vec.push_back(MACROCACHE::CreateMacro( | |
| builder, name, type, info->m_line, info->m_column, args, tokens)); | |
| } | |
| auto macroList = builder.CreateVector(macro_vec); | |
| /* Cache Included files */ | |
| std::vector<std::string> include_vec; | |
| std::set<PreprocessFile*> included; | |
| m_pp->collectIncludedFiles(included); | |
| for (std::set<PreprocessFile*>::iterator itr = included.begin(); | |
| itr != included.end(); itr++) { | |
| std::string svFileName = m_pp->getSymbol((*itr)->getRawFileId()); | |
| include_vec.push_back(svFileName); | |
| } | |
| auto includeList = builder.CreateVectorOfStrings(include_vec); | |
| /* Cache the body of the file */ | |
| auto body = builder.CreateString(m_pp->getPreProcessedFileContent()); | |
| /* Cache the errors and canonical symbols */ | |
| ErrorContainer* errorContainer = | |
| m_pp->getCompileSourceFile()->getErrorContainer(); | |
| SymbolId subjectFileId = m_pp->getFileId(LINE1); | |
| SymbolTable canonicalSymbols; | |
| auto errorSymbolPair = cacheErrors( | |
| builder, canonicalSymbols, errorContainer, | |
| m_pp->getCompileSourceFile()->getSymbolTable(), subjectFileId); | |
| /* Cache the include paths list */ | |
| auto includePathList = | |
| m_pp->getCompileSourceFile()->getCommandLineParser()->getIncludePaths(); | |
| std::vector<std::string> include_path_vec; | |
| for (auto path : includePathList) { | |
| std::string spath = m_pp->getSymbol(path); | |
| include_path_vec.push_back(spath); | |
| } | |
| auto incPaths = builder.CreateVectorOfStrings(include_path_vec); | |
| /* Cache the defines on the command line */ | |
| auto defineList = | |
| m_pp->getCompileSourceFile()->getCommandLineParser()->getDefineList(); | |
| std::vector<std::string> define_vec; | |
| for (auto definePair : defineList) { | |
| std::string spath = | |
| m_pp->getSymbol(definePair.first) + "=" + definePair.second; | |
| define_vec.push_back(spath); | |
| } | |
| auto defines = builder.CreateVectorOfStrings(define_vec); | |
| /* Cache the `timescale directives */ | |
| auto timeinfoList = m_pp->getCompilationUnit()->getTimeInfo(); | |
| std::vector<flatbuffers::Offset<CACHE::TimeInfo>> timeinfo_vec; | |
| for (auto info : timeinfoList) { | |
| if (info.m_fileId != m_pp->getFileId(0)) continue; | |
| auto timeInfo = CACHE::CreateTimeInfo( | |
| builder, info.m_type, | |
| canonicalSymbols.getId( | |
| m_pp->getCompileSourceFile()->getSymbolTable()->getSymbol( | |
| info.m_fileId)), | |
| info.m_line, info.m_timeUnit, info.m_timeUnitValue, | |
| info.m_timePrecision, info.m_timePrecisionValue); | |
| timeinfo_vec.push_back(timeInfo); | |
| } | |
| auto timeinfoFBList = builder.CreateVector(timeinfo_vec); | |
| /* Create Flatbuffers */ | |
| auto ppcache = MACROCACHE::CreatePPCache( | |
| builder, header, macroList, includeList, body, errorSymbolPair.first, | |
| errorSymbolPair.second, incPaths, defines, timeinfoFBList); | |
| FinishPPCacheBuffer(builder, ppcache); | |
| /* Save Flatbuffer */ | |
| bool status = saveFlatbuffers(builder, cacheFileName); | |
| return status; | |
| } |