blob: 7bfbfe832dd870f4b744e081ca00066498c47aec [file] [log] [blame]
/*
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;
}