Skip to content

Commit 37ef106

Browse files
committed
Reuse the deserialized buffer when serializing parser state cache
We serialize the parser state cache after either deserializing from the cache stream or generating bytecode and serializing that. If we succeeded to deserialize the parser state cache from a buffer retrieved from the cache stream, we can avoid serializing the bytecode into a buffer again.
1 parent 939ab74 commit 37ef106

File tree

2 files changed

+49
-18
lines changed

2 files changed

+49
-18
lines changed

lib/Runtime/Base/ScriptContext.cpp

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,14 +2126,20 @@ namespace Js
21262126
_In_ bool isCesu8,
21272127
_In_opt_ NativeModule* nativeModule,
21282128
_Out_ Js::ParseableFunctionInfo ** func,
2129+
_Out_ byte** parserStateCacheBuffer,
2130+
_Out_ DWORD* parserStateCacheByteCount,
21292131
_In_ Js::SimpleDataCacheWrapper* pDataCache)
21302132
{
21312133
HRESULT hr = E_FAIL;
21322134

21332135
Assert(pDataCache != nullptr);
21342136
Assert(func != nullptr);
2137+
Assert(parserStateCacheBuffer != nullptr);
2138+
Assert(parserStateCacheByteCount != nullptr);
21352139

21362140
*func = nullptr;
2141+
*parserStateCacheBuffer = nullptr;
2142+
*parserStateCacheByteCount = 0;
21372143

21382144
#ifdef ENABLE_WININET_PROFILE_DATA_CACHE
21392145
// Find the parser state block in the read stream and get the size of the block in bytes.
@@ -2190,13 +2196,17 @@ namespace Js
21902196

21912197
if (FAILED(hr))
21922198
{
2199+
AdeleteArray(alloc, byteCount, buffer);
2200+
21932201
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Failed to deserialize parser state cache (hr = 0x%08lx) for '%s'\n"), hr, url);
21942202
return hr;
21952203
}
21962204

21972205
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Successfully deserialized parser state cache for '%s'\n"), url);
21982206

21992207
*func = functionBody->GetParseableFunctionInfo();
2208+
*parserStateCacheBuffer = buffer;
2209+
*parserStateCacheByteCount = byteCount;
22002210
#endif
22012211

22022212
return hr;
@@ -2207,6 +2217,8 @@ namespace Js
22072217
_In_ size_t cbLength,
22082218
_In_ SRCINFO *srcInfo,
22092219
_In_ Js::ParseableFunctionInfo* func,
2220+
_In_ byte* parserStateCacheBuffer,
2221+
_In_ DWORD parserStateCacheByteCount,
22102222
_In_ Js::SimpleDataCacheWrapper* pDataCache)
22112223
{
22122224
HRESULT hr = E_FAIL;
@@ -2215,38 +2227,51 @@ namespace Js
22152227
Assert(pDataCache != nullptr);
22162228

22172229
#ifdef ENABLE_WININET_PROFILE_DATA_CACHE
2218-
byte* parserStateCacheBuffer = nullptr;
2219-
DWORD parserStateCacheSize = 0;
2230+
byte* serialzeParserStateCacheBuffer = parserStateCacheBuffer;
2231+
DWORD serialzeParserStateCacheSize = parserStateCacheByteCount;
22202232
DWORD dwFlags = GENERATE_BYTE_CODE_PARSER_STATE;
22212233
DebugOnly(auto url = !srcInfo->sourceContextInfo->isHostDynamicDocument ? srcInfo->sourceContextInfo->url : this->GetUrl());
22222234

2223-
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Trying to serialize parser state cache for '%s'\n"), url);
2235+
// If we already have a parser state cache serialized into a buffer, we should skip creating it again
2236+
if (parserStateCacheBuffer == nullptr)
2237+
{
2238+
Assert(serialzeParserStateCacheSize == 0);
22242239

2225-
BEGIN_TEMP_ALLOCATOR(tempAllocator, this, _u("ByteCodeSerializer"));
2226-
hr = Js::ByteCodeSerializer::SerializeToBuffer(this,
2227-
tempAllocator, (DWORD)cbLength, pszSrc, func->GetFunctionBody(),
2228-
func->GetHostSrcInfo(), true, &parserStateCacheBuffer,
2229-
&parserStateCacheSize, dwFlags);
2230-
END_TEMP_ALLOCATOR(tempAllocator, this);
2240+
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Trying to serialize parser state cache for '%s'\n"), url);
22312241

2232-
if (FAILED(hr))
2242+
BEGIN_TEMP_ALLOCATOR(tempAllocator, this, _u("ByteCodeSerializer"));
2243+
hr = Js::ByteCodeSerializer::SerializeToBuffer(this,
2244+
tempAllocator, (DWORD)cbLength, pszSrc, func->GetFunctionBody(),
2245+
func->GetHostSrcInfo(), true, &serialzeParserStateCacheBuffer,
2246+
&serialzeParserStateCacheSize, dwFlags);
2247+
END_TEMP_ALLOCATOR(tempAllocator, this);
2248+
2249+
if (FAILED(hr))
2250+
{
2251+
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Failed to serialize parser state cache (hr = 0x%08lx) for '%s'\n"), hr, url);
2252+
return hr;
2253+
}
2254+
2255+
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Successfully serialized parser state cache for '%s'\n"), url);
2256+
}
2257+
else
22332258
{
2234-
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Failed to serialize parser state cache (hr = 0x%08lx) for '%s'\n"), hr, url);
2235-
return hr;
2259+
Assert(serialzeParserStateCacheSize != 0);
2260+
2261+
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Skip serializing parser state cache since deserialized cache is available for '%s'\n"), url);
22362262
}
22372263

2238-
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Successfully serialized parser state cache for '%s'\n"), url);
2239-
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Trying to write parser state cache (%lu bytes) to stream for '%s'\n"), parserStateCacheSize, url);
2264+
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Trying to write parser state cache (%lu bytes) to stream for '%s'\n"), serialzeParserStateCacheSize, url);
22402265

2241-
hr = pDataCache->StartBlock(Js::SimpleDataCacheWrapper::BlockType_ParserState, parserStateCacheSize);
2266+
hr = pDataCache->StartBlock(Js::SimpleDataCacheWrapper::BlockType_ParserState, serialzeParserStateCacheSize);
22422267

22432268
if (FAILED(hr))
22442269
{
22452270
OUTPUT_TRACE_DEBUGONLY(Js::DataCachePhase, _u(" Failed to write a block to the parser state cache data stream (hr = 0x%08lx) for '%s'\n"), hr, url);
22462271
return hr;
22472272
}
22482273

2249-
hr = pDataCache->WriteArray(parserStateCacheBuffer, parserStateCacheSize);
2274+
hr = pDataCache->WriteArray(serialzeParserStateCacheBuffer, serialzeParserStateCacheSize);
22502275

22512276
if (FAILED(hr))
22522277
{
@@ -2287,10 +2312,12 @@ namespace Js
22872312
&& CONFIG_FLAG(ParserStateCache)
22882313
&& pDataCache != nullptr
22892314
&& !this->IsScriptContextInDebugMode();
2315+
byte* parserStateCacheBuffer = nullptr;
2316+
DWORD parserStateCacheByteCount = 0;
22902317

22912318
if (fUseParserStateCache)
22922319
{
2293-
hr = TryDeserializeParserState(grfscr, cchLength, srcInfo, utf8SourceInfo, sourceIndex, isCesu8, nullptr, func, pDataCache);
2320+
hr = TryDeserializeParserState(grfscr, cchLength, srcInfo, utf8SourceInfo, sourceIndex, isCesu8, nullptr, func, &parserStateCacheBuffer, &parserStateCacheByteCount, pDataCache);
22942321
#ifdef ENABLE_WININET_PROFILE_DATA_CACHE
22952322
// ERROR_WRITE_PROTECT indicates we cannot cache this script for whatever reason.
22962323
// Disable generating and serializing the parser state cache.
@@ -2339,7 +2366,7 @@ namespace Js
23392366
if (fUseParserStateCache)
23402367
{
23412368
Assert(*func != nullptr);
2342-
TrySerializeParserState(pszSrc, cbLength, srcInfo, *func, pDataCache);
2369+
TrySerializeParserState(pszSrc, cbLength, srcInfo, *func, parserStateCacheBuffer, parserStateCacheByteCount, pDataCache);
23432370
}
23442371
}
23452372
#ifdef ENABLE_SCRIPT_DEBUGGING

lib/Runtime/Base/ScriptContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,13 +1298,17 @@ namespace Js
12981298
_In_ bool isCesu8,
12991299
_In_opt_ NativeModule* nativeModule,
13001300
_Out_ Js::ParseableFunctionInfo ** func,
1301+
_Out_ byte** parserStateCacheBuffer,
1302+
_Out_ DWORD* parserStateCacheByteCount,
13011303
_In_ Js::SimpleDataCacheWrapper* pDataCache);
13021304

13031305
HRESULT TrySerializeParserState(
13041306
_In_ LPCUTF8 pszSrc,
13051307
_In_ size_t cbLength,
13061308
_In_ SRCINFO *srcInfo,
13071309
_In_ Js::ParseableFunctionInfo* func,
1310+
_In_ byte* parserStateCacheBuffer,
1311+
_In_ DWORD parserStateCacheByteCount,
13081312
_In_ Js::SimpleDataCacheWrapper* pDataCache);
13091313

13101314
HRESULT CompileUTF8Core(

0 commit comments

Comments
 (0)