You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Merge pull request chakra-core#5106 from boingoing:SerializeParserState4
Adds the concept of a parser state cache which is conceptually the state of the parser after running an initial upfront parse. This parser state is built on top of the existing bytecode serialization code and can (basically) be thought of as the bytecode for all initially non-defer-parsed functions as well as stubs for all defer-parsed functions. When we deserialize this parser state, we hydrate the defer-parse functions and executing them will perform a full parse of the original source like an ordinary defer-parse function would be handled without the serialization step. Because of this defer-parse scenario, the parser state cache is not a standalone bytecode format like the buffers produced by the existing bytecode serialization APIs such as `JsSerialize` and reusing the generated parser state requires the original script text as well.
There are two new Jsrt APIs which allow hosts to use this functionality:
```cpp
CHAKRA_API
JsSerializeParserState(
_In_ JsValueRef scriptVal,
_Out_ JsValueRef *bufferVal,
_In_ JsParseScriptAttributes parseAttributes);
CHAKRA_API
JsRunScriptWithParserState(
_In_ JsValueRef script,
_In_ JsSourceContext sourceContext,
_In_ JsValueRef sourceUrl,
_In_ JsParseScriptAttributes parseAttributes,
_In_ JsValueRef parserState,
_Out_ JsValueRef * result);
```
`JsSerializeParserState` parses a script and returns the parser state cache via the `bufferVal` output parameter. The format of the parser state cache is runtime-independent and may be reused in any runtime.
`JsRunScriptWithParserState` takes in a parser state cache created via `JsSerializeParserState` and the same script and executes the script, returning the result.
Exposes the `-GenerateParserStateCache` ch.exe flag which exercises `JsSerializeParserState`. With this flag, ch.exe generates the parser state cache for the passed-in file and prints the returned buffer to the console. This switch is diagnostic in nature and is not intended to be used in a unit test or as a replacement for a tool calling `JsSerializeParserState` directly.
Adds one other ch.exe flag `-UseParserStateCache` which generates the parser state cache via `JsSerializeParserState` and then immediately uses the cache to execute the script via `JsRunScriptWithParserState`. This switch is meant as a way to exercise compatibility for the parser state cache set of features and is similar to the `-ForceSerialized` flag.
Also adds one config flag to control creation of the parser state cache. This flag (`-ParserStateCache`) is enabled by default in this PR.
Majority of the work for this feature is in refactoring the various parsing pipelines and plumbing-in additional arguments when needed. ScriptContext.h/cpp probably contain the majority of these changes. The next biggest part is probably the bytecode serialization changes to handle serializing and deserializing defer-parse functions and deferred stubs.
The parser state cache is written to (and read from) the same data cache we use for the startup function bitvector which uses the `IActiveScriptDataCache` interface. The interface is wrapped by two helper classes in `SourceDynamicProfileManager`, `SourceDynamicProfileManager::SimpleStreamReader` and `SourceDynamicProfileManager::SimpleStreamWriter` which act to read/write the data cache contents. These existing structures are not sufficient to support the addition of our parser state cache so I have added the (slightly less simple) `SimpleDataCacheWrapper` class. This wrapper allows us to write multiple blocks of data into the stream and supports seeking through the stream to find and read blocks of a specified type.
Parser state cache is turned off in debug scenarios, currently. To enable it we would need to have the data cache store both debug and non-debug bytecode or come up with another solution. In the medium-term, we can get away with just disabling the feature in debug modes.
@@ -995,6 +996,7 @@ FLAGNR(NumberTrioSet, StatementDebugBreak, "Index of the statement where you wa
995
996
FLAGNR(Phases, DebugBreakOnPhaseBegin, "Break into debugger at the beginning of given phase for listed function", )
996
997
997
998
FLAGNR(Boolean, DebugWindow , "Send console output to debugger window", false)
999
+
FLAGNR(Boolean, ParserStateCache , "Enable creation of parser state cache", DEFAULT_CONFIG_ParserStateCache)
998
1000
FLAGNR(Boolean, DeferTopLevelTillFirstCall , "Enable tracking of deferred top level functions in a script file, until the first function of the script context is parsed.", DEFAULT_CONFIG_DeferTopLevelTillFirstCall)
999
1001
FLAGNR(Number, DeferParse , "Minimum size of defer-parsed script (non-zero only: use /nodeferparse do disable", 0)
1000
1002
FLAGNR(Boolean, DirectCallTelemetryStats, "Enables logging stats for direct call telemetry", DEFAULT_CONFIG_DirectCallTelemetryStats)
0 commit comments