diff --git a/src/api/EscargotPublic.cpp b/src/api/EscargotPublic.cpp index e59902326..6d66121f9 100644 --- a/src/api/EscargotPublic.cpp +++ b/src/api/EscargotPublic.cpp @@ -67,9 +67,11 @@ #include "runtime/BigIntObject.h" #include "runtime/SharedArrayBufferObject.h" #include "runtime/serialization/Serializer.h" -#include "codecache/CodeCache.h" #include "interpreter/ByteCode.h" #include "api/internal/ValueAdapter.h" +#if defined(ENABLE_CODE_CACHE) +#include "codecache/CodeCache.h" +#endif #if defined(ENABLE_WASM) #include "wasm/WASMOperations.h" #endif @@ -1244,75 +1246,83 @@ void VMInstanceRef::setMaxCompiledByteCodeSize(size_t s) toImpl(this)->setMaxCompiledByteCodeSize(s); } +#if defined(ENABLE_CODE_CACHE) bool VMInstanceRef::isCodeCacheEnabled() { -#if defined(ENABLE_CODE_CACHE) return true; -#else - return false; -#endif } size_t VMInstanceRef::codeCacheMinSourceLength() { -#if defined(ENABLE_CODE_CACHE) return toImpl(this)->codeCache()->minSourceLength(); -#else +} + +void VMInstanceRef::setCodeCacheMinSourceLength(size_t s) +{ + toImpl(this)->codeCache()->setMinSourceLength(s); +} + +size_t VMInstanceRef::codeCacheMaxCacheCount() +{ + return toImpl(this)->codeCache()->maxCacheCount(); +} + +void VMInstanceRef::setCodeCacheMaxCacheCount(size_t s) +{ + toImpl(this)->codeCache()->setMaxCacheCount(s); +} + +bool VMInstanceRef::codeCacheShouldLoadFunctionOnScriptLoading() +{ + return toImpl(this)->codeCache()->shouldLoadFunctionOnScriptLoading(); +} + +void VMInstanceRef::setCodeCacheShouldLoadFunctionOnScriptLoading(bool s) +{ + toImpl(this)->codeCache()->setShouldLoadFunctionOnScriptLoading(s); +} +#else // ENABLE_CODE_CACHE +bool VMInstanceRef::isCodeCacheEnabled() +{ + return false; +} + +size_t VMInstanceRef::codeCacheMinSourceLength() +{ ESCARGOT_LOG_ERROR("If you want to use this function, you should enable code cache"); RELEASE_ASSERT_NOT_REACHED(); -#endif } void VMInstanceRef::setCodeCacheMinSourceLength(size_t s) { -#if defined(ENABLE_CODE_CACHE) - toImpl(this)->codeCache()->setMinSourceLength(s); -#else ESCARGOT_LOG_ERROR("If you want to use this function, you should enable code cache"); RELEASE_ASSERT_NOT_REACHED(); -#endif } size_t VMInstanceRef::codeCacheMaxCacheCount() { -#if defined(ENABLE_CODE_CACHE) - return toImpl(this)->codeCache()->maxCacheCount(); -#else ESCARGOT_LOG_ERROR("If you want to use this function, you should enable code cache"); RELEASE_ASSERT_NOT_REACHED(); -#endif } void VMInstanceRef::setCodeCacheMaxCacheCount(size_t s) { -#if defined(ENABLE_CODE_CACHE) - toImpl(this)->codeCache()->setMaxCacheCount(s); -#else ESCARGOT_LOG_ERROR("If you want to use this function, you should enable code cache"); RELEASE_ASSERT_NOT_REACHED(); -#endif } bool VMInstanceRef::codeCacheShouldLoadFunctionOnScriptLoading() { -#if defined(ENABLE_CODE_CACHE) - return toImpl(this)->codeCache()->shouldLoadFunctionOnScriptLoading(); -#else ESCARGOT_LOG_ERROR("If you want to use this function, you should enable code cache"); RELEASE_ASSERT_NOT_REACHED(); -#endif } void VMInstanceRef::setCodeCacheShouldLoadFunctionOnScriptLoading(bool s) { -#if defined(ENABLE_CODE_CACHE) - toImpl(this)->codeCache()->setShouldLoadFunctionOnScriptLoading(s); -#else ESCARGOT_LOG_ERROR("If you want to use this function, you should enable code cache"); RELEASE_ASSERT_NOT_REACHED(); -#endif } - +#endif // ENABLE_CODE_CACHE #ifdef ESCARGOT_DEBUGGER diff --git a/src/codecache/CodeCache.cpp b/src/codecache/CodeCache.cpp index 49a08dad0..7993b2728 100644 --- a/src/codecache/CodeCache.cpp +++ b/src/codecache/CodeCache.cpp @@ -41,11 +41,11 @@ namespace Escargot { -static std::string makeCacheFilePath(const std::string& cacheDirPath, const CodeCacheScriptIdentifier& id) +static std::string createCacheFilePath(const std::string& cacheDirPath, const CodeCacheIndex& cacheIndex) { std::stringstream ss; ss << cacheDirPath; - id.makeCacheFilePath(ss); + cacheIndex.createCacheFileName(ss); return ss.str(); } @@ -54,6 +54,11 @@ void CodeCache::CodeCacheContext::reset() m_cacheFilePath.clear(); m_cacheEntry.reset(); + if (m_cacheFile) { + fclose(m_cacheFile); + m_cacheFile = nullptr; + } + if (m_cacheStringTable) { delete m_cacheStringTable; m_cacheStringTable = nullptr; @@ -279,6 +284,7 @@ void CodeCache::clear() m_cacheDirPath.clear(); m_cacheList.clear(); + m_cacheLRUList.clear(); if (m_cacheWriter) { delete m_cacheWriter; @@ -312,20 +318,19 @@ void CodeCache::reset() void CodeCache::setCacheEntry(const CodeCacheEntryChunk& entryChunk) { - CodeCacheItem item(entryChunk.m_scriptIdentifier, entryChunk.m_functionSourceIndex); #ifndef NDEBUG - auto iter = m_cacheList.find(item); + auto iter = m_cacheList.find(entryChunk.m_index); ASSERT(iter == m_cacheList.end()); #endif - m_cacheList.insert(std::make_pair(item, entryChunk.m_entry)); + m_cacheList.insert(std::make_pair(entryChunk.m_index, entryChunk.m_entry)); } -bool CodeCache::addCacheEntry(const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex, const CodeCacheEntry& entry) +bool CodeCache::addCacheEntry(const CodeCacheIndex& cacheIndex, const CodeCacheEntry& entry) { ASSERT(m_enabled); #ifndef NDEBUG - auto iter = m_cacheList.find(CodeCacheItem(scriptIdentifier, functionSourceIndex)); + auto iter = m_cacheList.find(cacheIndex); ASSERT(iter == m_cacheList.end()); #endif if (m_cacheLRUList.size() == m_maxCacheCount) { @@ -334,7 +339,7 @@ bool CodeCache::addCacheEntry(const CodeCacheScriptIdentifier& scriptIdentifier, } } - m_cacheList.insert(std::make_pair(CodeCacheItem(scriptIdentifier, functionSourceIndex), entry)); + m_cacheList.insert(std::make_pair(cacheIndex, entry)); return true; } @@ -346,7 +351,7 @@ bool CodeCache::removeLRUCacheEntry() #ifndef NDEBUG uint64_t currentTimeStamp = fastTickCount(); #endif - CodeCacheScriptIdentifier lruItem(0, 0); + CodeCacheIndex::ScriptID lruIndex; uint64_t lruTimeStamp = std::numeric_limits::max(); for (auto iter = m_cacheLRUList.begin(); iter != m_cacheLRUList.end(); iter++) { uint64_t timeStamp = iter->second; @@ -354,20 +359,20 @@ bool CodeCache::removeLRUCacheEntry() ASSERT(timeStamp <= currentTimeStamp); #endif if (lruTimeStamp > timeStamp) { - lruItem = iter->first; + lruIndex = iter->first; lruTimeStamp = timeStamp; } } - if (UNLIKELY(!removeCacheFile(lruItem))) { + if (UNLIKELY(!removeCacheFile(lruIndex))) { return false; } - size_t eraseReturn = m_cacheLRUList.erase(lruItem); + size_t eraseReturn = m_cacheLRUList.erase(lruIndex); ASSERT(eraseReturn == 1 && m_cacheLRUList.size() == m_maxCacheCount - 1); for (auto iter = m_cacheList.begin(); iter != m_cacheList.end();) { - if (iter->first.m_scriptIdentifier == lruItem) { + if (iter->first.scriptID() == lruIndex) { iter = m_cacheList.erase(iter); } else { iter++; @@ -375,34 +380,38 @@ bool CodeCache::removeLRUCacheEntry() } #ifndef NDEBUG - ESCARGOT_LOG_INFO("[CodeCache] removeLRUCacheEntry %zu_%zu done\n", lruItem.m_srcHash, lruItem.m_sourceCodeLength); + ESCARGOT_LOG_INFO("[CodeCache] removeLRUCacheEntry %zu_%zu done\n", lruIndex.m_srcHash, lruIndex.m_srcLength); #endif return true; } -bool CodeCache::removeCacheFile(const CodeCacheScriptIdentifier& scriptIdentifier) +bool CodeCache::removeCacheFile(const CodeCacheIndex::ScriptID& scriptID) { ASSERT(m_enabled); ASSERT(m_cacheDirPath.length()); + ASSERT(scriptID.m_srcHash && scriptID.m_srcLength); - std::string filePath = makeCacheFilePath(m_cacheDirPath, scriptIdentifier); + std::string filePath = createCacheFilePath(m_cacheDirPath, CodeCacheIndex(scriptID.m_srcHash, scriptID.m_srcLength, 0)); if (remove(filePath.data()) != 0) { ESCARGOT_LOG_ERROR("[CodeCache] can`t remove a cache file %s\n", filePath.data()); return false; } +#ifndef NDEBUG + ESCARGOT_LOG_INFO("[CodeCache] remove a cache file %s\n", filePath.data()); +#endif return true; } -std::pair CodeCache::searchCache(const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex) +std::pair CodeCache::searchCache(const CodeCacheIndex& cacheIndex) { - ASSERT(m_enabled); + ASSERT(m_enabled && cacheIndex.isValid()); CodeCacheEntry entry; bool cacheHit = false; - auto iter = m_cacheList.find(CodeCacheItem(scriptIdentifier, functionSourceIndex)); + auto iter = m_cacheList.find(cacheIndex); if (iter != m_cacheList.end()) { cacheHit = true; entry = iter->second; @@ -411,21 +420,124 @@ std::pair CodeCache::searchCache(const CodeCacheScriptIden return std::make_pair(cacheHit, entry); } -void CodeCache::prepareCacheLoading(Context* context, const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex, const CodeCacheEntry& entry) +bool CodeCache::loadGlobalCache(Context* context, const CodeCacheIndex& cacheIndex, const CodeCacheEntry& entry, Script* script) +{ + ASSERT(m_enabled && cacheIndex.isValid()); + + // load global CodeBlock and its related information + prepareCacheLoading(context, cacheIndex, entry); + + InterpretedCodeBlock* topCodeBlock = loadCodeBlockTree(context, script); + ByteCodeBlock* topByteCodeBlock = loadByteCodeBlock(context, topCodeBlock); + + if (!postCacheLoading()) { + return false; + } + + ASSERT(!!topCodeBlock && !!topByteCodeBlock); + script->m_topCodeBlock = topCodeBlock; + topCodeBlock->m_byteCodeBlock = topByteCodeBlock; + + ESCARGOT_LOG_INFO("[CodeCache] Load CodeCache Done (%s)\n", script->srcName()->toUTF8StringData().data()); + + return true; +} + +bool CodeCache::loadFunctionCache(Context* context, const CodeCacheIndex& cacheIndex, const CodeCacheEntry& entry, InterpretedCodeBlock* codeBlock) +{ + ASSERT(m_enabled && cacheIndex.isValid()); + + // load function CodeBlock and its related information + prepareCacheLoading(context, cacheIndex, entry); + + codeBlock->m_byteCodeBlock = loadByteCodeBlock(context, codeBlock); + + bool result = postCacheLoading(); + if (result) { + ESCARGOT_LOG_INFO("[CodeCache] Load CodeCache Done (%s: index %zu size %zu)\n", codeBlock->script()->srcName()->toNonGCUTF8StringData().data(), + codeBlock->functionStart().index, codeBlock->src().length()); + } + return result; +} + +bool CodeCache::storeGlobalCache(Context* context, const CodeCacheIndex& cacheIndex, InterpretedCodeBlock* topCodeBlock, CodeBlockCacheInfo* codeBlockCacheInfo, Node* programNode, bool inWith) +{ + ASSERT(m_enabled && cacheIndex.isValid()); + + // store global CodeBlock and its related information + prepareCacheWriting(cacheIndex); + + // For storing cache, CodeBlockTree is firstly saved + storeCodeBlockTree(topCodeBlock, codeBlockCacheInfo); + + // After CodeBlockTree, ByteCode and StringTable are stored sequentially + try { + topCodeBlock->m_byteCodeBlock = ByteCodeGenerator::generateByteCode(context, topCodeBlock, programNode, inWith, true); + } catch (const char* message) { + // handle failure + m_status = Status::FAILED; + postCacheWriting(cacheIndex); + throw message; + } + + bool result = postCacheWriting(cacheIndex); +#ifndef NDEBUG + if (result) { + ESCARGOT_LOG_INFO("[CodeCache] Store CodeCache Done (%s)\n", topCodeBlock->script()->srcName()->toUTF8StringData().data()); + } +#endif + return result; +} + +bool CodeCache::storeFunctionCache(Context* context, const CodeCacheIndex& cacheIndex, InterpretedCodeBlock* codeBlock, Node* functionNode) +{ + ASSERT(m_enabled && cacheIndex.isValid()); + + // store function ByteCodeBlock and its related information + prepareCacheWriting(cacheIndex); + + try { + codeBlock->m_byteCodeBlock = ByteCodeGenerator::generateByteCode(context, codeBlock, functionNode, false, true); + } catch (const char* message) { + // handle failure + m_status = Status::FAILED; + postCacheWriting(cacheIndex); + throw message; + } + + bool result = postCacheWriting(cacheIndex); +#ifndef NDEBUG + if (result) { + ESCARGOT_LOG_INFO("[CodeCache] Store CodeCache Done (%s: index %zu size %zu)\n", codeBlock->script()->srcName()->toNonGCUTF8StringData().data(), + codeBlock->functionStart().index, codeBlock->src().length()); + } +#endif + return result; +} + +void CodeCache::prepareCacheLoading(Context* context, const CodeCacheIndex& cacheIndex, const CodeCacheEntry& entry) { ASSERT(m_enabled && m_status == Status::READY); ASSERT(m_cacheDirPath.length()); ASSERT(!m_currentContext.m_cacheFilePath.length()); ASSERT(!m_currentContext.m_cacheStringTable); + ASSERT(cacheIndex.isValid()); m_status = Status::IN_PROGRESS; - m_currentContext.m_cacheFilePath = makeCacheFilePath(m_cacheDirPath, scriptIdentifier); + m_currentContext.m_cacheFilePath = createCacheFilePath(m_cacheDirPath, cacheIndex); m_currentContext.m_cacheEntry = entry; + FILE* dataFile = fopen(m_currentContext.m_cacheFilePath.data(), "rb"); + if (UNLIKELY(!dataFile)) { + ESCARGOT_LOG_ERROR("[CodeCache] can't open the cache data file %s\n", m_currentContext.m_cacheFilePath.data()); + m_status = Status::FAILED; + return; + } + m_currentContext.m_cacheFile = dataFile; m_currentContext.m_cacheStringTable = loadCacheStringTable(context); } -void CodeCache::prepareCacheWriting(const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex) +void CodeCache::prepareCacheWriting(const CodeCacheIndex& cacheIndex) { ASSERT(m_enabled && m_status == Status::READY); ASSERT(m_cacheDirPath.length()); @@ -434,47 +546,57 @@ void CodeCache::prepareCacheWriting(const CodeCacheScriptIdentifier& scriptIdent m_status = Status::IN_PROGRESS; - m_currentContext.m_cacheFilePath = makeCacheFilePath(m_cacheDirPath, scriptIdentifier); + m_currentContext.m_cacheFilePath = createCacheFilePath(m_cacheDirPath, cacheIndex); m_currentContext.m_cacheStringTable = new CacheStringTable(); + FILE* dataFile = fopen(m_currentContext.m_cacheFilePath.data(), "ab"); + if (UNLIKELY(!dataFile)) { + ESCARGOT_LOG_ERROR("[CodeCache] can't open the cache data file %s\n", m_currentContext.m_cacheFilePath.data()); + m_status = Status::FAILED; + return; + } + m_currentContext.m_cacheFile = dataFile; } bool CodeCache::postCacheLoading() { ASSERT(m_enabled); + reset(); + if (LIKELY(m_status == Status::FINISH)) { - reset(); m_status = Status::READY; - return true; } // failed to load cache clearAll(); - + m_status = Status::READY; return false; } -void CodeCache::postCacheWriting(const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex) +bool CodeCache::postCacheWriting(const CodeCacheIndex& cacheIndex) { ASSERT(m_enabled); if (LIKELY(m_status == Status::FINISH)) { // write time stamp - m_cacheLRUList[scriptIdentifier] = fastTickCount(); + m_cacheLRUList[cacheIndex.scriptID()] = fastTickCount(); - if (addCacheEntry(scriptIdentifier, functionSourceIndex, m_currentContext.m_cacheEntry)) { + if (addCacheEntry(cacheIndex, m_currentContext.m_cacheEntry)) { if (writeCacheList()) { reset(); m_status = Status::READY; - return; + return true; } } } // failed to write cache + reset(); clearAll(); + m_status = Status::READY; + return false; } void CodeCache::storeStringTable() @@ -561,8 +683,6 @@ CacheStringTable* CodeCache::loadCacheStringTable(Context* context) return nullptr; } - ASSERT(m_status == Status::IN_PROGRESS); - CodeCacheMetaInfo& metaInfo = m_currentContext.m_cacheEntry.m_metaInfos[(size_t)CodeCacheType::CACHE_STRING]; ASSERT(metaInfo.cacheType == CodeCacheType::CACHE_STRING); @@ -587,8 +707,6 @@ InterpretedCodeBlock* CodeCache::loadCodeBlockTree(Context* context, Script* scr return nullptr; } - ASSERT(m_status == Status::IN_PROGRESS); - CodeCacheMetaInfo& metaInfo = m_currentContext.m_cacheEntry.m_metaInfos[(size_t)CodeCacheType::CACHE_CODEBLOCK]; ASSERT(!!context); @@ -602,21 +720,23 @@ InterpretedCodeBlock* CodeCache::loadCodeBlockTree(Context* context, Script* scr return nullptr; } - // temporal vector to keep the loaded InterpretedCodeBlock in GC heap - Vector> tempCodeBlockVector; + ASSERT(GC_is_disabled()); + // temporal vector to keep the loaded InterpretedCodeBlock (GC is already disabled) + std::vector tempCodeBlockVector; // CodeCacheMetaInfo::codeBlockCount has the value of nodeCount for CACHE_CODEBLOCK size_t nodeCount = metaInfo.codeBlockCount; - tempCodeBlockVector.resizeFitWithUninitializedValues(nodeCount); + tempCodeBlockVector.reserve(nodeCount); for (size_t i = 0; i < nodeCount; i++) { InterpretedCodeBlock* codeBlock = m_cacheReader->loadInterpretedCodeBlock(context, script); - tempCodeBlockVector[i] = codeBlock; + tempCodeBlockVector.push_back(codeBlock); if (i == 0) { // GlobalCodeBlock is firstly stored and loaded topCodeBlock = codeBlock; } } + ASSERT(tempCodeBlockVector.size() == nodeCount); // link CodeBlock tree for (size_t i = 0; i < tempCodeBlockVector.size(); i++) { @@ -640,76 +760,9 @@ InterpretedCodeBlock* CodeCache::loadCodeBlockTree(Context* context, Script* scr // load bytecode of functions if (m_shouldLoadFunctionOnScriptLoading) { - FILE* dataFile = nullptr; - CodeCacheScriptIdentifier scriptIdentifier(script->sourceCodeHashValue(), script->sourceCode()->length()); - size_t loadedFunctionCount = 0; - for (size_t i = 0; i < tempCodeBlockVector.size(); i++) { - InterpretedCodeBlock* codeBlock = tempCodeBlockVector[i]; - auto result = searchCache(scriptIdentifier, codeBlock->functionStart().index); - if (result.first) { - if (!dataFile) { - dataFile = fopen(m_currentContext.m_cacheFilePath.data(), "rb"); - if (!dataFile) { - ESCARGOT_LOG_ERROR("[CodeCache] can't open the cache data file %s\n", m_currentContext.m_cacheFilePath.data()); - } - } - CodeCacheEntry& cacheEntry = result.second; - - CodeCacheMetaInfo& stringMetaInfo = cacheEntry.m_metaInfos[(size_t)CodeCacheType::CACHE_STRING]; - CodeCacheReader cacheReader; - - if (UNLIKELY(fseek(dataFile, stringMetaInfo.dataOffset, SEEK_SET) != 0)) { - ESCARGOT_LOG_ERROR("[CodeCache] can't seek the cache data file %s\n", m_currentContext.m_cacheFilePath.data()); - break; - } - - if (UNLIKELY(!cacheReader.loadData(dataFile, stringMetaInfo.dataSize))) { - ESCARGOT_LOG_ERROR("[CodeCache] load cache data of %s failed\n", m_currentContext.m_cacheFilePath.data()); - break; - } - - CacheStringTable* table = cacheReader.loadStringTable(context); - cacheReader.clearBuffer(); - CodeCacheMetaInfo& byteCodeMetaInfo = cacheEntry.m_metaInfos[(size_t)CodeCacheType::CACHE_BYTECODE]; - - cacheReader.setStringTable(table); - if (UNLIKELY(fseek(dataFile, byteCodeMetaInfo.dataOffset, SEEK_SET) != 0)) { - ESCARGOT_LOG_ERROR("[CodeCache] can't seek the cache data file %s\n", m_currentContext.m_cacheFilePath.data()); - break; - } - - if (UNLIKELY(!cacheReader.loadData(dataFile, byteCodeMetaInfo.dataSize))) { - ESCARGOT_LOG_ERROR("[CodeCache] load cache data of %s failed\n", m_currentContext.m_cacheFilePath.data()); - break; - } - - codeBlock->m_byteCodeBlock = cacheReader.loadByteCodeBlock(context, codeBlock); - cacheReader.clearBuffer(); - - if (LIKELY(codeBlock->m_byteCodeBlock != nullptr)) { -#ifndef NDEBUG - ESCARGOT_LOG_INFO("[CodeCache] Load CodeCache Done (%s: index %zu size %zu)\n", codeBlock->script()->srcName()->toNonGCUTF8StringData().data(), - codeBlock->functionStart().index, codeBlock->src().length()); -#endif - auto& currentCodeSizeTotal = context->vmInstance()->compiledByteCodeSize(); - ASSERT(currentCodeSizeTotal < std::numeric_limits::max()); - currentCodeSizeTotal += codeBlock->m_byteCodeBlock->memoryAllocatedSize(); - loadedFunctionCount++; - } - } - } - - if (dataFile) { - fclose(dataFile); - dataFile = nullptr; - } - - if (loadedFunctionCount) { - ESCARGOT_LOG_INFO("[CodeCache] Load function CodeCache Done (%s, %zu function(s))\n", topCodeBlock->script()->srcName()->toNonGCUTF8StringData().data(), loadedFunctionCount); - } + loadAllByteCodeBlockOfFunctions(context, tempCodeBlockVector, script); } - // clear tempCodeBlockVector.clear(); m_cacheReader->clearBuffer(); @@ -723,15 +776,13 @@ InterpretedCodeBlock* CodeCache::loadCodeBlockTree(Context* context, Script* scr return topCodeBlock; } -ByteCodeBlock* CodeCache::loadByteCodeBlock(Context* context, InterpretedCodeBlock* topCodeBlock) +ByteCodeBlock* CodeCache::loadByteCodeBlock(Context* context, InterpretedCodeBlock* codeBlock) { if (m_status != Status::IN_PROGRESS) { // Caching process failed in the previous stage return nullptr; } - ASSERT(m_status == Status::IN_PROGRESS); - CodeCacheMetaInfo& metaInfo = m_currentContext.m_cacheEntry.m_metaInfos[(size_t)CodeCacheType::CACHE_BYTECODE]; ASSERT(!!context); @@ -743,7 +794,7 @@ ByteCodeBlock* CodeCache::loadByteCodeBlock(Context* context, InterpretedCodeBlo return nullptr; } - ByteCodeBlock* block = m_cacheReader->loadByteCodeBlock(context, topCodeBlock); + ByteCodeBlock* block = m_cacheReader->loadByteCodeBlock(context, codeBlock); // clear and finish m_cacheReader->clearBuffer(); @@ -752,6 +803,64 @@ ByteCodeBlock* CodeCache::loadByteCodeBlock(Context* context, InterpretedCodeBlo return block; } +void CodeCache::loadAllByteCodeBlockOfFunctions(Context* context, std::vector& codeBlockVector, Script* script) +{ + // load CodeBlock of functions during loading of global code + ASSERT(m_enabled && m_status == Status::IN_PROGRESS); + ASSERT(m_currentContext.m_cacheFilePath.length() && m_currentContext.m_cacheFile); + FILE* dataFile = m_currentContext.m_cacheFile; + + size_t srcHash = script->sourceCodeHashValue(); + size_t srcLength = script->sourceCode()->length(); + + // hold the current context + CodeCacheContext previousContext = m_currentContext; + m_cacheReader->clearBuffer(); + + for (size_t i = 0; i < codeBlockVector.size(); i++) { + InterpretedCodeBlock* codeBlock = codeBlockVector[i]; + ASSERT(script == codeBlock->script()); + auto result = searchCache(CodeCacheIndex(srcHash, srcLength, codeBlock->functionStart().index)); + if (result.first) { + CodeCacheEntry& cacheEntry = result.second; + + // init context + m_currentContext.m_cacheEntry = cacheEntry; + m_currentContext.m_cacheStringTable = loadCacheStringTable(context); + + // load ByteCodeBlock + codeBlock->m_byteCodeBlock = loadByteCodeBlock(context, codeBlock); + + // finalize + if (m_currentContext.m_cacheStringTable) { + delete m_currentContext.m_cacheStringTable; + m_currentContext.m_cacheStringTable = nullptr; + } + + if (LIKELY(m_status == Status::FINISH)) { + m_status = Status::IN_PROGRESS; + } else { + ESCARGOT_LOG_ERROR("[CodeCache] load function cache data of %s failed\n", m_currentContext.m_cacheFilePath.data()); + break; + } + + if (LIKELY(codeBlock->m_byteCodeBlock != nullptr)) { +#ifndef NDEBUG + ESCARGOT_LOG_INFO("[CodeCache] Load CodeCache Done (%s: index %zu size %zu)\n", codeBlock->script()->srcName()->toNonGCUTF8StringData().data(), + codeBlock->functionStart().index, codeBlock->src().length()); +#endif + auto& currentCodeSizeTotal = context->vmInstance()->compiledByteCodeSize(); + ASSERT(currentCodeSizeTotal < std::numeric_limits::max()); + currentCodeSizeTotal += codeBlock->m_byteCodeBlock->memoryAllocatedSize(); + } + } + } + + // reset status + m_status = Status::IN_PROGRESS; + m_currentContext = previousContext; +} + bool CodeCache::writeCacheList() { ASSERT(m_enabled); @@ -787,7 +896,7 @@ bool CodeCache::writeCacheList() while (entryCount < listSize) { ASSERT(iter != m_cacheList.end()); - CodeCacheEntryChunk entryChunk(iter->first.m_scriptIdentifier, iter->first.m_functionSourceIndex, iter->second); + CodeCacheEntryChunk entryChunk(iter->first, iter->second); if (UNLIKELY(fwrite(&entryChunk, sizeof(CodeCacheEntryChunk), 1, listFile) != 1)) { ESCARGOT_LOG_ERROR("[CodeCache] fwrite of %s failed\n", cacheListFilePath.data()); fclose(listFile); @@ -812,9 +921,10 @@ bool CodeCache::writeCacheData(CodeCacheType type, size_t extraCount) { ASSERT(m_enabled); ASSERT(type == CodeCacheType::CACHE_CODEBLOCK || type == CodeCacheType::CACHE_BYTECODE || type == CodeCacheType::CACHE_STRING); - ASSERT(m_currentContext.m_cacheFilePath.length()); + ASSERT(!!m_currentContext.m_cacheFilePath.length()); + ASSERT(!!m_currentContext.m_cacheFile); - FILE* dataFile = nullptr; + FILE* dataFile = m_currentContext.m_cacheFile; // meta info CodeCacheMetaInfo meta(type, m_currentContext.m_cacheDataOffset, m_cacheWriter->bufferSize()); @@ -822,14 +932,6 @@ bool CodeCache::writeCacheData(CodeCacheType type, size_t extraCount) ASSERT(m_currentContext.m_cacheDataOffset == 0); // extraCount represents the total count of CodeBlocks used only for CodeBlockTree caching meta.codeBlockCount = extraCount; - dataFile = fopen(m_currentContext.m_cacheFilePath.data(), "wb"); - } else { - dataFile = fopen(m_currentContext.m_cacheFilePath.data(), "ab"); - } - - if (UNLIKELY(!dataFile)) { - ESCARGOT_LOG_ERROR("[CodeCache] can't open the cache data file %s\n", m_currentContext.m_cacheFilePath.data()); - return false; } // record correct position for function @@ -842,7 +944,6 @@ bool CodeCache::writeCacheData(CodeCacheType type, size_t extraCount) // write cache data if (UNLIKELY(fwrite(m_cacheWriter->bufferData(), sizeof(char), m_cacheWriter->bufferSize(), dataFile) != m_cacheWriter->bufferSize())) { ESCARGOT_LOG_ERROR("[CodeCache] fwrite of %s failed\n", m_currentContext.m_cacheFilePath.data()); - fclose(dataFile); m_cacheWriter->clearBuffer(); return false; } @@ -852,7 +953,6 @@ bool CodeCache::writeCacheData(CodeCacheType type, size_t extraCount) /* for performance issue, fsync is skipped for now fsync(fileno(dataFile)); */ - fclose(dataFile); m_currentContext.m_cacheDataOffset += m_cacheWriter->bufferSize(); m_cacheWriter->clearBuffer(); @@ -864,28 +964,21 @@ bool CodeCache::readCacheData(CodeCacheMetaInfo& metaInfo) ASSERT(m_enabled); ASSERT(metaInfo.cacheType == CodeCacheType::CACHE_CODEBLOCK || metaInfo.cacheType == CodeCacheType::CACHE_BYTECODE || metaInfo.cacheType == CodeCacheType::CACHE_STRING); ASSERT(!!m_currentContext.m_cacheFilePath.length()); + ASSERT(!!m_currentContext.m_cacheFile); size_t dataOffset = metaInfo.cacheType == CodeCacheType::CACHE_CODEBLOCK ? 0 : metaInfo.dataOffset; - FILE* dataFile = fopen(m_currentContext.m_cacheFilePath.data(), "rb"); - - if (UNLIKELY(!dataFile)) { - ESCARGOT_LOG_ERROR("[CodeCache] can't open the cache data file %s\n", m_currentContext.m_cacheFilePath.data()); - return false; - } + FILE* dataFile = m_currentContext.m_cacheFile; if (UNLIKELY(fseek(dataFile, dataOffset, SEEK_SET) != 0)) { ESCARGOT_LOG_ERROR("[CodeCache] can't seek the cache data file %s\n", m_currentContext.m_cacheFilePath.data()); - fclose(dataFile); return false; } if (UNLIKELY(!m_cacheReader->loadData(dataFile, metaInfo.dataSize))) { ESCARGOT_LOG_ERROR("[CodeCache] load cache data of %s failed\n", m_currentContext.m_cacheFilePath.data()); - fclose(dataFile); return false; } - fclose(dataFile); return true; } diff --git a/src/codecache/CodeCache.h b/src/codecache/CodeCache.h index c1251c1e7..28192c6ce 100644 --- a/src/codecache/CodeCache.h +++ b/src/codecache/CodeCache.h @@ -47,6 +47,7 @@ class CodeCacheReader; class CacheStringTable; class ByteCodeBlock; class InterpretedCodeBlock; +class Node; struct CodeBlockCacheInfo { CodeBlockCacheInfo() @@ -89,41 +90,70 @@ struct CodeCacheMetaInfo { size_t dataSize; }; -struct CodeCacheScriptIdentifier { - size_t m_srcHash; - size_t m_sourceCodeLength; +struct CodeCacheIndex { + size_t m_srcHash; // hash value of source code + size_t m_srcLength; // length of source code + size_t m_functionIndex; // index of function start position (SIZE_MAX for global code) - CodeCacheScriptIdentifier(size_t srcHash, size_t sourceCodeLength) + struct ScriptID { + size_t m_srcHash; + size_t m_srcLength; + + ScriptID() + : m_srcHash(0) + , m_srcLength(0) + { + } + + ScriptID(size_t srcHash, size_t srcLength) + : m_srcHash(srcHash) + , m_srcLength(srcLength) + { + ASSERT(srcHash && srcLength); + } + + bool operator==(const ScriptID& src) const + { + return m_srcHash == src.m_srcHash && m_srcLength == src.m_srcLength; + } + }; + + CodeCacheIndex() + : m_srcHash(0) + , m_srcLength(0) + , m_functionIndex(0) + { + } + + CodeCacheIndex(size_t srcHash, size_t srcLength, size_t funcIndex) : m_srcHash(srcHash) - , m_sourceCodeLength(sourceCodeLength) + , m_srcLength(srcLength) + , m_functionIndex(funcIndex) { + ASSERT(isValid()); } - void makeCacheFilePath(std::stringstream& ss) const + ScriptID scriptID() const { - ss << m_srcHash; - ss << '_'; - ss << m_sourceCodeLength; + ASSERT(isValid()); + return ScriptID(m_srcHash, m_srcLength); } - bool operator==(const CodeCacheScriptIdentifier& src) const + bool isValid() const { - return m_srcHash == src.m_srcHash && m_sourceCodeLength == src.m_sourceCodeLength; + return m_srcHash && m_srcLength; } -}; -struct CodeCacheItem { - CodeCacheScriptIdentifier m_scriptIdentifier; - Optional m_functionSourceIndex; - CodeCacheItem(CodeCacheScriptIdentifier scriptIdentifier, Optional functionSourceIndex) - : m_scriptIdentifier(scriptIdentifier) - , m_functionSourceIndex(functionSourceIndex) + void createCacheFileName(std::stringstream& ss) const { + ss << m_srcHash; + ss << '_'; + ss << m_srcLength; } - bool operator==(const CodeCacheItem& src) const + bool operator==(const CodeCacheIndex& src) const { - return m_scriptIdentifier == src.m_scriptIdentifier && m_functionSourceIndex == src.m_functionSourceIndex; + return m_srcHash == src.m_srcHash && m_srcLength == src.m_srcLength && m_functionIndex == src.m_functionIndex; } }; @@ -131,36 +161,37 @@ struct CodeCacheItem { namespace std { template <> -struct hash { - size_t operator()(Escargot::CodeCacheItem const& x) const +struct hash { + size_t operator()(Escargot::CodeCacheIndex const& x) const { - return x.m_scriptIdentifier.m_srcHash + (x.m_functionSourceIndex ? x.m_functionSourceIndex.value() : 0); + return x.m_srcHash + x.m_functionIndex; } }; template <> -struct equal_to { - bool operator()(Escargot::CodeCacheItem const& a, Escargot::CodeCacheItem const& b) const +struct equal_to { + bool operator()(Escargot::CodeCacheIndex const& a, Escargot::CodeCacheIndex const& b) const { return a == b; } }; template <> -struct hash { - size_t operator()(Escargot::CodeCacheScriptIdentifier const& x) const +struct hash { + size_t operator()(Escargot::CodeCacheIndex::ScriptID const& x) const { return x.m_srcHash; } }; template <> -struct equal_to { - bool operator()(Escargot::CodeCacheScriptIdentifier const& a, Escargot::CodeCacheScriptIdentifier const& b) const +struct equal_to { + bool operator()(Escargot::CodeCacheIndex::ScriptID const& a, Escargot::CodeCacheIndex::ScriptID const& b) const { return a == b; } }; + } // namespace std namespace Escargot { @@ -180,6 +211,8 @@ struct CodeCacheEntry { }; class CodeCache { + friend class ByteCodeGenerator; + public: enum class Status : uint8_t { NONE, @@ -191,7 +224,8 @@ class CodeCache { struct CodeCacheContext { CodeCacheContext() - : m_cacheStringTable(nullptr) + : m_cacheFile(nullptr) + , m_cacheStringTable(nullptr) , m_cacheDataOffset(0) { } @@ -200,25 +234,23 @@ class CodeCache { std::string m_cacheFilePath; // current cache data file path CodeCacheEntry m_cacheEntry; // current cache entry + FILE* m_cacheFile; // current cache data file CacheStringTable* m_cacheStringTable; // current CacheStringTable size_t m_cacheDataOffset; // current offset in cache data file }; struct CodeCacheEntryChunk { CodeCacheEntryChunk() - : m_scriptIdentifier(0, 0) { } - CodeCacheEntryChunk(const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex, const CodeCacheEntry& entry) - : m_scriptIdentifier(scriptIdentifier) - , m_functionSourceIndex(functionSourceIndex) + CodeCacheEntryChunk(const CodeCacheIndex& cacheIndex, const CodeCacheEntry& entry) + : m_index(cacheIndex) , m_entry(entry) { } - CodeCacheScriptIdentifier m_scriptIdentifier; - Optional m_functionSourceIndex; + CodeCacheIndex m_index; CodeCacheEntry m_entry; }; @@ -226,20 +258,12 @@ class CodeCache { ~CodeCache(); bool enabled() const { return m_enabled; } - std::pair searchCache(const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex); - - void prepareCacheLoading(Context* context, const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex, const CodeCacheEntry& entry); - void prepareCacheWriting(const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex); - bool postCacheLoading(); - void postCacheWriting(const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex); - - void storeStringTable(); - void storeCodeBlockTree(InterpretedCodeBlock* topCodeBlock, CodeBlockCacheInfo* codeBlockCacheInfo); - void storeByteCodeBlock(ByteCodeBlock* block); + std::pair searchCache(const CodeCacheIndex& cacheIndex); - CacheStringTable* loadCacheStringTable(Context* context); - InterpretedCodeBlock* loadCodeBlockTree(Context* context, Script* script); - ByteCodeBlock* loadByteCodeBlock(Context* context, InterpretedCodeBlock* topCodeBlock); + bool loadGlobalCache(Context* context, const CodeCacheIndex& cacheIndex, const CodeCacheEntry& entry, Script* script); + bool loadFunctionCache(Context* context, const CodeCacheIndex& cacheIndex, const CodeCacheEntry& entry, InterpretedCodeBlock* codeBlock); + bool storeGlobalCache(Context* context, const CodeCacheIndex& cacheIndex, InterpretedCodeBlock* topCodeBlock, CodeBlockCacheInfo* codeBlockCacheInfo, Node* programNode, bool inWith); + bool storeFunctionCache(Context* context, const CodeCacheIndex& cacheIndex, InterpretedCodeBlock* codeBlock, Node* functionNode); void clear(); @@ -255,9 +279,9 @@ class CodeCache { CodeCacheContext m_currentContext; // current CodeCache infos - typedef std::unordered_map, std::equal_to, std::allocator>> CodeCacheListMap; + typedef std::unordered_map, std::equal_to, std::allocator>> CodeCacheListMap; CodeCacheListMap m_cacheList; - typedef std::unordered_map CodeCacheLRUList; /* */ + typedef std::unordered_map, std::equal_to, std::allocator>> CodeCacheLRUList; /* */ CodeCacheLRUList m_cacheLRUList; CodeCacheWriter* m_cacheWriter; @@ -280,10 +304,23 @@ class CodeCache { void clearAll(); void reset(); void setCacheEntry(const CodeCacheEntryChunk& entryChunk); - bool addCacheEntry(const CodeCacheScriptIdentifier& scriptIdentifier, Optional functionSourceIndex, const CodeCacheEntry& entry); + bool addCacheEntry(const CodeCacheIndex& cacheIndex, const CodeCacheEntry& entry); bool removeLRUCacheEntry(); - bool removeCacheFile(const CodeCacheScriptIdentifier& scriptIdentifier); + bool removeCacheFile(const CodeCacheIndex::ScriptID& scriptID); + + void prepareCacheLoading(Context* context, const CodeCacheIndex& cacheIndex, const CodeCacheEntry& entry); + bool postCacheLoading(); + CacheStringTable* loadCacheStringTable(Context* context); + InterpretedCodeBlock* loadCodeBlockTree(Context* context, Script* script); + ByteCodeBlock* loadByteCodeBlock(Context* context, InterpretedCodeBlock* topCodeBlock); + void loadAllByteCodeBlockOfFunctions(Context* context, std::vector& codeBlockVector, Script* script); + + void prepareCacheWriting(const CodeCacheIndex& cacheIndex); + bool postCacheWriting(const CodeCacheIndex& cacheIndex); + void storeStringTable(); + void storeCodeBlockTree(InterpretedCodeBlock* topCodeBlock, CodeBlockCacheInfo* codeBlockCacheInfo); + void storeByteCodeBlock(ByteCodeBlock* block); void storeCodeBlockTreeNode(InterpretedCodeBlock* codeBlock, size_t& nodeCount); InterpretedCodeBlock* loadCodeBlockTreeNode(Script* script); diff --git a/src/codecache/CodeCacheReaderWriter.cpp b/src/codecache/CodeCacheReaderWriter.cpp index 92e0fd941..51119dce9 100644 --- a/src/codecache/CodeCacheReaderWriter.cpp +++ b/src/codecache/CodeCacheReaderWriter.cpp @@ -654,9 +654,10 @@ void CodeCacheReader::CacheBuffer::resize(size_t size) void CodeCacheReader::CacheBuffer::reset() { - free(m_buffer); - - m_buffer = nullptr; + if (m_buffer) { + free(m_buffer); + m_buffer = nullptr; + } m_capacity = 0; m_index = 0; } diff --git a/src/parser/Script.h b/src/parser/Script.h index 5fc269112..7044fcbdb 100644 --- a/src/parser/Script.h +++ b/src/parser/Script.h @@ -34,6 +34,9 @@ class Script : public gc { friend class ScriptParser; friend class GlobalObject; friend class ModuleNamespaceObject; +#if defined(ENABLE_CODE_CACHE) + friend class CodeCache; +#endif public: struct ModuleRequest { diff --git a/src/parser/ScriptParser.cpp b/src/parser/ScriptParser.cpp index fbecb691c..0a265ef4e 100644 --- a/src/parser/ScriptParser.cpp +++ b/src/parser/ScriptParser.cpp @@ -35,6 +35,37 @@ namespace Escargot { +#if defined(ENABLE_CODE_CACHE) +class CodeBlockCacheInfoHolder { +public: + CodeBlockCacheInfoHolder() + : m_parser(nullptr) + , m_cacheInfo(nullptr) + { + } + + ~CodeBlockCacheInfoHolder() + { + if (m_cacheInfo) { + m_parser->deleteCodeBlockCacheInfo(); + } + m_parser = nullptr; + m_cacheInfo = nullptr; + } + + void setCacheInfo(ScriptParser* parser, CodeBlockCacheInfo* cacheInfo) + { + m_parser = parser; + m_cacheInfo = cacheInfo; + parser->setCodeBlockCacheInfo(cacheInfo); + } + +private: + ScriptParser* m_parser; + CodeBlockCacheInfo* m_cacheInfo; +}; +#endif + ScriptParser::ScriptParser(Context* c) : m_context(c) #if defined(ENABLE_CODE_CACHE) @@ -288,6 +319,7 @@ void ScriptParser::setCodeBlockCacheInfo(CodeBlockCacheInfo* info) void ScriptParser::deleteCodeBlockCacheInfo() { + ASSERT(m_codeBlockCacheInfo); delete m_codeBlockCacheInfo; m_codeBlockCacheInfo = nullptr; } @@ -300,44 +332,39 @@ ScriptParser::InitializeScriptResult ScriptParser::initializeScript(String* orig #if defined(ENABLE_CODE_CACHE) UNUSED_PARAMETER(originSource); - CodeCacheScriptIdentifier scriptIdentifier(0, 0); + CodeCacheIndex cacheIndex; + CodeBlockCacheInfoHolder cacheInfoHolder; CodeCache* codeCache = m_context->vmInstance()->codeCache(); bool cacheable = codeCache->enabled() && needByteCodeGeneration && !isModule && !isEvalMode && srcName->length() && source->length() > codeCache->minSourceLength(); // Load caching if (cacheable) { ASSERT(!parentCodeBlock); - scriptIdentifier = CodeCacheScriptIdentifier(source->hashValue(), source->length()); - auto result = codeCache->searchCache(scriptIdentifier, Optional()); + // set m_functionIndex as SIZE_MAX for global code + cacheIndex = CodeCacheIndex(source->hashValue(), source->length(), SIZE_MAX); + auto result = codeCache->searchCache(cacheIndex); if (result.first) { GC_disable(); - Script* script = new Script(srcName, source, nullptr, originLineOffset, false, scriptIdentifier.m_srcHash); + Script* script = new Script(srcName, source, nullptr, originLineOffset, false, cacheIndex.m_srcHash); CodeCacheEntry& entry = result.second; - codeCache->prepareCacheLoading(m_context, scriptIdentifier, Optional(), entry); - // load CodeBlockTree - InterpretedCodeBlock* topCodeBlock = codeCache->loadCodeBlockTree(m_context, script); - // load global ByteCodeBlock - ByteCodeBlock* topByteBlock = codeCache->loadByteCodeBlock(m_context, topCodeBlock); - bool loadingDone = codeCache->postCacheLoading(); - cacheable = loadingDone; + bool loadingDone = codeCache->loadGlobalCache(m_context, cacheIndex, entry, script); GC_enable(); if (LIKELY(loadingDone)) { - ASSERT(!!topCodeBlock && !!topByteBlock); - script->m_topCodeBlock = topCodeBlock; - topCodeBlock->m_byteCodeBlock = topByteBlock; - ESCARGOT_LOG_INFO("[CodeCache] Load CodeCache Done (%s)\n", srcName->toUTF8StringData().data()); - ScriptParser::InitializeScriptResult result; result.script = script; return result; } + + // failed in loading the cache + // give up caching for this script + cacheable = false; } else { // prepare for caching - setCodeBlockCacheInfo(new CodeBlockCacheInfo()); + cacheInfoHolder.setCacheInfo(this, new CodeBlockCacheInfo()); } } #endif @@ -370,7 +397,7 @@ ScriptParser::InitializeScriptResult ScriptParser::initializeScript(String* orig script = new Script(srcName, source, programNode->moduleData(), originLineOffset, !parentCodeBlock #if defined(ENABLE_CODE_CACHE) , - scriptIdentifier.m_srcHash + cacheIndex.m_srcHash #endif ); if (parentCodeBlock) { @@ -394,11 +421,6 @@ ScriptParser::InitializeScriptResult ScriptParser::initializeScript(String* orig // reset ASTAllocator m_context->astAllocator().reset(); GC_enable(); -#if defined(ENABLE_CODE_CACHE) - if (cacheable) { - deleteCodeBlockCacheInfo(); - } -#endif ScriptParser::InitializeScriptResult result; result.parseErrorCode = orgError->errorCode; @@ -425,17 +447,7 @@ ScriptParser::InitializeScriptResult ScriptParser::initializeScript(String* orig #if defined(ENABLE_CODE_CACHE) // Store cache if (cacheable) { - codeCache->prepareCacheWriting(scriptIdentifier, Optional()); - - // For storing cache, CodeBlockTree is firstly saved - codeCache->storeCodeBlockTree(topCodeBlock, m_codeBlockCacheInfo); - - // After CodeBlockTree, ByteCode and StringTable are stored sequentially - topCodeBlock->m_byteCodeBlock = ByteCodeGenerator::generateByteCode(m_context, topCodeBlock, programNode, inWith, true); - - codeCache->postCacheWriting(scriptIdentifier, Optional()); - deleteCodeBlockCacheInfo(); - ESCARGOT_LOG_INFO("[CodeCache] Store CodeCache Done (%s)\n", srcName->toUTF8StringData().data()); + codeCache->storeGlobalCache(m_context, cacheIndex, topCodeBlock, m_codeBlockCacheInfo, programNode, inWith); } else { topCodeBlock->m_byteCodeBlock = ByteCodeGenerator::generateByteCode(m_context, topCodeBlock, programNode, inWith, false); } @@ -474,35 +486,29 @@ void ScriptParser::generateFunctionByteCode(ExecutionState& state, InterpretedCo #if defined(ENABLE_CODE_CACHE) CodeCache* codeCache = m_context->vmInstance()->codeCache(); + CodeCacheIndex cacheIndex; bool cacheable = codeCache->enabled() && codeBlock->src().length() > codeCache->minSourceLength(); - // Lode code from cache - CodeCacheScriptIdentifier scriptIdentifier(0, codeBlock->script()->sourceCode()->length()); - // loading source code hash value can cause computing hash value of entire source code - if (cacheable) { - scriptIdentifier.m_srcHash = codeBlock->script()->sourceCodeHashValue(); - } // Load cache if (cacheable) { - auto result = codeCache->searchCache(scriptIdentifier, codeBlock->functionStart().index); + // loading source code hash value can cause computing hash value of entire source code + cacheIndex = CodeCacheIndex(codeBlock->script()->sourceCodeHashValue(), codeBlock->script()->sourceCode()->length(), codeBlock->functionStart().index); + auto result = codeCache->searchCache(cacheIndex); if (result.first) { GC_disable(); CodeCacheEntry& entry = result.second; - codeCache->prepareCacheLoading(m_context, scriptIdentifier, codeBlock->functionStart().index, entry); - // load ByteCodeBlock - codeBlock->m_byteCodeBlock = codeCache->loadByteCodeBlock(m_context, codeBlock); - bool loadingDone = codeCache->postCacheLoading(); - cacheable = loadingDone; + bool loadingDone = codeCache->loadFunctionCache(m_context, cacheIndex, entry, codeBlock); + GC_enable(); if (LIKELY(loadingDone)) { -#ifndef NDEBUG - ESCARGOT_LOG_INFO("[CodeCache] Load CodeCache Done (%s: index %zu size %zu)\n", codeBlock->script()->srcName()->toNonGCUTF8StringData().data(), - codeBlock->functionStart().index, codeBlock->src().length()); -#endif return; } + + // failed in loading the cache + // give up caching for this function + cacheable = false; } } @@ -531,21 +537,13 @@ void ScriptParser::generateFunctionByteCode(ExecutionState& state, InterpretedCo #if defined(ENABLE_CODE_CACHE) // Store cache if (cacheable) { - codeCache->prepareCacheWriting(scriptIdentifier, codeBlock->functionStart().index); - codeBlock->m_byteCodeBlock = ByteCodeGenerator::generateByteCode(state.context(), codeBlock, functionNode, false, true); - codeCache->postCacheWriting(scriptIdentifier, codeBlock->functionStart().index); -#ifndef NDEBUG - ESCARGOT_LOG_INFO("[CodeCache] Store CodeCache Done (%s: index %zu size %zu)\n", codeBlock->script()->srcName()->toNonGCUTF8StringData().data(), - codeBlock->functionStart().index, codeBlock->src().length()); -#endif + codeCache->storeFunctionCache(state.context(), cacheIndex, codeBlock, functionNode); } else { codeBlock->m_byteCodeBlock = ByteCodeGenerator::generateByteCode(state.context(), codeBlock, functionNode); } #else codeBlock->m_byteCodeBlock = ByteCodeGenerator::generateByteCode(state.context(), codeBlock, functionNode); #endif - - } catch (const char* message) { // reset ASTAllocator m_context->astAllocator().reset();