Skip to content

Commit a47597a

Browse files
committed
[MERGE chakra-core#5106 @boingoing] Support generating and using a cache of the initial parser state
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.
2 parents e432cc9 + 38bede8 commit a47597a

32 files changed

Lines changed: 1739 additions & 511 deletions

bin/ChakraCore/ChakraCore.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,5 @@ JsCreateEnhancedFunction
6767
JsSetHostPromiseRejectionTracker
6868

6969
JsGetProxyProperties
70+
JsSerializeParserState
71+
JsRunScriptWithParserState

bin/ch/ChakraRtInterface.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ bool ChakraRTInterface::LoadChakraDll(ArgInfo* argInfo, HINSTANCE *outLibrary)
157157
m_jsApiHooks.pfJsrtCreatePropertyId = (JsAPIHooks::JsrtCreatePropertyId)GetChakraCoreSymbol(library, "JsCreatePropertyId");
158158
m_jsApiHooks.pfJsrtCreateExternalArrayBuffer = (JsAPIHooks::JsrtCreateExternalArrayBuffer)GetChakraCoreSymbol(library, "JsCreateExternalArrayBuffer");
159159
m_jsApiHooks.pfJsrtGetProxyProperties = (JsAPIHooks::JsrtGetProxyProperties)GetChakraCoreSymbol(library, "JsGetProxyProperties");
160+
m_jsApiHooks.pfJsrtSerializeParserState = (JsAPIHooks::JsrtSerializeParserState)GetChakraCoreSymbol(library, "JsSerializeParserState");
161+
m_jsApiHooks.pfJsrtRunScriptWithParserState = (JsAPIHooks::JsrtRunScriptWithParserState)GetChakraCoreSymbol(library, "JsRunScriptWithParserState");
160162

161163
m_jsApiHooks.pfJsrtTTDCreateRecordRuntime = (JsAPIHooks::JsrtTTDCreateRecordRuntimePtr)GetChakraCoreSymbol(library, "JsTTDCreateRecordRuntime");
162164
m_jsApiHooks.pfJsrtTTDCreateReplayRuntime = (JsAPIHooks::JsrtTTDCreateReplayRuntimePtr)GetChakraCoreSymbol(library, "JsTTDCreateReplayRuntime");

bin/ch/ChakraRtInterface.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ struct JsAPIHooks
9090
typedef JsErrorCode(WINAPI *JsrtCreatePropertyId)(const char *name, size_t length, JsPropertyIdRef *propertyId);
9191
typedef JsErrorCode(WINAPI *JsrtGetProxyProperties)(JsValueRef object, bool* isProxy, JsValueRef* target, JsValueRef* handler);
9292

93+
typedef JsErrorCode(WINAPI *JsrtSerializeParserState)(JsValueRef script, JsValueRef *buffer, JsParseScriptAttributes parseAttributes);
94+
typedef JsErrorCode(WINAPI *JsrtRunScriptWithParserState)(JsValueRef script, JsSourceContext sourceContext, JsValueRef sourceUrl, JsParseScriptAttributes parseAttributes, JsValueRef parserState, JsValueRef *result);
95+
9396
typedef JsErrorCode(WINAPI *JsrtTTDCreateRecordRuntimePtr)(JsRuntimeAttributes attributes, bool enableDebugging, size_t snapInterval, size_t snapHistoryLength, TTDOpenResourceStreamCallback openResourceStream, JsTTDWriteBytesToStreamCallback writeBytesToStream, JsTTDFlushAndCloseStreamCallback flushAndCloseStream, JsThreadServiceCallback threadService, JsRuntimeHandle *runtime);
9497
typedef JsErrorCode(WINAPI *JsrtTTDCreateReplayRuntimePtr)(JsRuntimeAttributes attributes, const char* infoUri, size_t infoUriCount, bool enableDebugging, TTDOpenResourceStreamCallback openResourceStream, JsTTDReadBytesFromStreamCallback readBytesFromStream, JsTTDFlushAndCloseStreamCallback flushAndCloseStream, JsThreadServiceCallback threadService, JsRuntimeHandle *runtime);
9598
typedef JsErrorCode(WINAPI *JsrtTTDCreateContextPtr)(JsRuntimeHandle runtime, bool useRuntimeTTDMode, JsContextRef *newContext);
@@ -189,6 +192,8 @@ struct JsAPIHooks
189192
JsrtCreatePropertyId pfJsrtCreatePropertyId;
190193
JsrtCreateExternalArrayBuffer pfJsrtCreateExternalArrayBuffer;
191194
JsrtGetProxyProperties pfJsrtGetProxyProperties;
195+
JsrtSerializeParserState pfJsrtSerializeParserState;
196+
JsrtRunScriptWithParserState pfJsrtRunScriptWithParserState;
192197

193198
JsrtTTDCreateRecordRuntimePtr pfJsrtTTDCreateRecordRuntime;
194199
JsrtTTDCreateReplayRuntimePtr pfJsrtTTDCreateReplayRuntime;
@@ -422,6 +427,9 @@ class ChakraRTInterface
422427
static JsErrorCode WINAPI JsCreatePropertyId(const char *name, size_t length, JsPropertyIdRef *propertyId) { return HOOK_JS_API(CreatePropertyId(name, length, propertyId)); }
423428
static JsErrorCode WINAPI JsCreateExternalArrayBuffer(void *data, unsigned int byteLength, JsFinalizeCallback finalizeCallback, void *callbackState, JsValueRef *result) { return HOOK_JS_API(CreateExternalArrayBuffer(data, byteLength, finalizeCallback, callbackState, result)); }
424429
static JsErrorCode WINAPI JsGetProxyProperties(JsValueRef object, bool* isProxy, JsValueRef* target, JsValueRef* handler) { return HOOK_JS_API(GetProxyProperties(object, isProxy, target, handler)); }
430+
431+
static JsErrorCode WINAPI JsSerializeParserState(JsValueRef script, JsValueRef *buffer, JsParseScriptAttributes parseAttributes) { return HOOK_JS_API(SerializeParserState(script, buffer, parseAttributes)); }
432+
static JsErrorCode WINAPI JsRunScriptWithParserState(JsValueRef script, JsSourceContext sourceContext, JsValueRef sourceUrl, JsParseScriptAttributes parseAttributes, JsValueRef parserState, JsValueRef * result) { return HOOK_JS_API(RunScriptWithParserState(script, sourceContext, sourceUrl, parseAttributes, parserState, result)); }
425433
};
426434

427435
class AutoRestoreContext

bin/ch/HostConfigFlagsList.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
FLAG(BSTR, dbgbaseline, "Baseline file to compare debugger output", NULL)
88
FLAG(bool, DebugLaunch, "Create the test debugger and execute test in the debug mode", false)
99
FLAG(BSTR, GenerateLibraryByteCodeHeader, "Generate bytecode header file from library code", NULL)
10+
FLAG(bool, GenerateParserStateCache, "Parse source file to create parser state cache and write it to file or console", false)
11+
FLAG(bool, UseParserStateCache, "Create parser state cache while parsing and use it during script execution", false)
1012
FLAG(int, InspectMaxStringLength, "Max string length to dump in locals inspection", 16)
1113
FLAG(BSTR, Serialized, "If source is UTF8, deserializes from bytecode file", NULL)
1214
FLAG(bool, OOPJIT, "Run JIT in a separate process", false)

bin/ch/ch.cpp

Lines changed: 159 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,16 @@ HRESULT GetSerializedBuffer(LPCSTR fileContents, JsFinalizeCallback fileContentF
183183
return hr;
184184
}
185185

186+
HANDLE GetFileHandle(LPCWSTR filename)
187+
{
188+
if (filename != nullptr)
189+
{
190+
return CreateFile(filename, GENERIC_WRITE, FILE_SHARE_DELETE,
191+
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
192+
}
193+
return GetStdHandle(STD_OUTPUT_HANDLE);
194+
}
195+
186196
HRESULT CreateLibraryByteCodeHeader(LPCSTR contentsRaw, JsFinalizeCallback contentsRawFinalizeCallback, DWORD lengthBytes, LPCWSTR bcFullPath, LPCSTR libraryNameNarrow)
187197
{
188198
HANDLE bcFileHandle = nullptr;
@@ -220,19 +230,8 @@ HRESULT CreateLibraryByteCodeHeader(LPCSTR contentsRaw, JsFinalizeCallback conte
220230

221231
IfJsrtErrorHRLabel(ChakraRTInterface::JsGetArrayBufferStorage(bufferVal, &bcBuffer, &bcBufferSize), ErrorRunFinalize);
222232

223-
if (bcFullPath)
224-
{
225-
bcFileHandle = CreateFile(bcFullPath, GENERIC_WRITE, FILE_SHARE_DELETE,
226-
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
227-
}
228-
else
229-
{
230-
bcFileHandle = GetStdHandle(STD_OUTPUT_HANDLE);
231-
}
232-
if (bcFileHandle == INVALID_HANDLE_VALUE)
233-
{
234-
IfFailedGoLabel(E_FAIL, ErrorRunFinalize);
235-
}
233+
bcFileHandle = GetFileHandle(bcFullPath);
234+
IfFalseGo(bcFileHandle != INVALID_HANDLE_VALUE && bcFileHandle != nullptr);
236235

237236
IfFalseGoLabel(WriteFile(bcFileHandle, outputStr, (DWORD)strlen(outputStr), &written, nullptr), ErrorRunFinalize);
238237
IfFalseGoLabel(WriteFile(bcFileHandle, normalizedContent, (DWORD)normalizedContentStr.size(), &written, nullptr), ErrorRunFinalize);
@@ -316,7 +315,7 @@ static bool CHAKRA_CALLBACK DummyJsSerializedScriptLoadUtf8Source(
316315
return true;
317316
}
318317

319-
HRESULT RunScript(const char* fileName, LPCSTR fileContents, size_t fileLength, JsFinalizeCallback fileContentsFinalizeCallback, JsValueRef bufferValue, char *fullPath)
318+
HRESULT RunScript(const char* fileName, LPCSTR fileContents, size_t fileLength, JsFinalizeCallback fileContentsFinalizeCallback, JsValueRef bufferValue, char *fullPath, JsValueRef parserStateCache)
320319
{
321320
HRESULT hr = S_OK;
322321
MessageQueue * messageQueue = new MessageQueue();
@@ -397,18 +396,18 @@ HRESULT RunScript(const char* fileName, LPCSTR fileContents, size_t fileLength,
397396
IfJsErrorFailLogLabel(ChakraRTInterface::JsCreateString(fullPath,
398397
strlen(fullPath), &fname), ErrorRunFinalize);
399398

400-
if(bufferValue != nullptr)
399+
if (bufferValue != nullptr)
401400
{
402-
if(fileContents == nullptr)
401+
if (fileContents == nullptr)
403402
{
404403
// if we have no fileContents, no worry about freeing them, and the call is simple.
405404
runScript = ChakraRTInterface::JsRunSerialized(
406-
bufferValue,
407-
nullptr /*JsSerializedLoadScriptCallback*/,
408-
0 /*SourceContext*/,
409-
fname,
410-
nullptr /*result*/
411-
);
405+
bufferValue,
406+
nullptr /*JsSerializedLoadScriptCallback*/,
407+
0 /*SourceContext*/,
408+
fname,
409+
nullptr /*result*/
410+
);
412411
}
413412
else // fileContents != nullptr
414413
{
@@ -420,24 +419,40 @@ HRESULT RunScript(const char* fileName, LPCSTR fileContents, size_t fileLength,
420419

421420
// Now we can run our script, with this serializedCallbackInfo as the sourcecontext
422421
runScript = ChakraRTInterface::JsRunSerialized(
423-
bufferValue,
424-
DummyJsSerializedScriptLoadUtf8Source,
425-
reinterpret_cast<JsSourceContext>(&serializedCallbackInfo),
426-
// Use source ptr as sourceContext
427-
fname,
428-
nullptr /*result*/);
422+
bufferValue,
423+
DummyJsSerializedScriptLoadUtf8Source,
424+
reinterpret_cast<JsSourceContext>(&serializedCallbackInfo),
425+
// Use source ptr as sourceContext
426+
fname,
427+
nullptr /*result*/);
429428
// Now that we're down here, we can free the fileContents if they weren't sent into
430429
// a GC-managed object.
431-
if(!serializedCallbackInfo.freeingHandled)
430+
if (!serializedCallbackInfo.freeingHandled)
432431
{
433-
if(fileContentsFinalizeCallback != nullptr)
432+
if (fileContentsFinalizeCallback != nullptr)
434433
{
435434
fileContentsFinalizeCallback((void*)fileContents);
436435
}
437436
}
438437
}
439438
}
440-
else // bufferValue == nullptr
439+
else if (parserStateCache != nullptr)
440+
{
441+
JsValueRef scriptSource;
442+
IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
443+
(unsigned int)fileLength,
444+
fileContentsFinalizeCallback, (void*)fileContents, &scriptSource));
445+
446+
// TODO: Support TTD
447+
runScript = ChakraRTInterface::JsRunScriptWithParserState(
448+
scriptSource,
449+
WScriptJsrt::GetNextSourceContext(),
450+
fname,
451+
JsParseScriptAttributeNone,
452+
parserStateCache,
453+
nullptr);
454+
}
455+
else // bufferValue == nullptr && parserStateCache == nullptr
441456
{
442457
JsValueRef scriptSource;
443458
IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
@@ -584,6 +599,108 @@ static HRESULT CreateRuntime(JsRuntimeHandle *runtime)
584599
return hr;
585600
}
586601

602+
HRESULT GetParserStateBuffer(LPCSTR fileContents, JsFinalizeCallback fileContentsFinalizeCallback, JsValueRef *parserStateBuffer)
603+
{
604+
HRESULT hr = S_OK;
605+
JsValueRef scriptSource = nullptr;
606+
607+
IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
608+
(unsigned int)strlen(fileContents), fileContentsFinalizeCallback, (void*)fileContents, &scriptSource));
609+
610+
IfJsErrorFailLog(ChakraRTInterface::JsSerializeParserState(scriptSource, parserStateBuffer, JsParseScriptAttributeNone));
611+
612+
Error:
613+
return hr;
614+
}
615+
616+
HRESULT CreateParserState(LPCSTR fileContents, size_t fileLength, JsFinalizeCallback fileContentsFinalizeCallback, LPCWSTR fullPath)
617+
{
618+
HRESULT hr = S_OK;
619+
HANDLE fileHandle = nullptr;
620+
JsValueRef parserStateBuffer = nullptr;
621+
BYTE *buffer = nullptr;
622+
unsigned int bufferSize = 0;
623+
624+
IfFailedGoLabel(GetParserStateBuffer(fileContents, fileContentsFinalizeCallback, &parserStateBuffer), Error);
625+
IfJsErrorFailLog(ChakraRTInterface::JsGetArrayBufferStorage(parserStateBuffer, &buffer, &bufferSize));
626+
627+
fileHandle = GetFileHandle(fullPath);
628+
IfFalseGo(fileHandle != INVALID_HANDLE_VALUE && fileHandle != nullptr);
629+
630+
for (unsigned int i = 0; i < bufferSize; i++)
631+
{
632+
const unsigned int BYTES_PER_LINE = 32;
633+
DWORD written = 0;
634+
char scratch[3];
635+
auto scratchLen = sizeof(scratch);
636+
int num = _snprintf_s(scratch, scratchLen, _countof(scratch), "%02X", buffer[i]);
637+
Assert(num == 2);
638+
IfFalseGo(WriteFile(fileHandle, scratch, (DWORD)(scratchLen - 1), &written, nullptr));
639+
640+
// Add line breaks so this block can be readable
641+
if (i % BYTES_PER_LINE == (BYTES_PER_LINE - 1) && i < bufferSize - 1)
642+
{
643+
IfFalseGo(WriteFile(fileHandle, "\n", 1, &written, nullptr));
644+
}
645+
}
646+
647+
Error:
648+
if (fileHandle != nullptr)
649+
{
650+
CloseHandle(fileHandle);
651+
}
652+
return hr;
653+
}
654+
655+
HRESULT CreateParserStateAndRunScript(const char* fileName, LPCSTR fileContents, size_t fileLength, JsFinalizeCallback fileContentsFinalizeCallback, char *fullPath)
656+
{
657+
HRESULT hr = S_OK;
658+
JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
659+
JsContextRef context = JS_INVALID_REFERENCE, current = JS_INVALID_REFERENCE;
660+
JsValueRef bufferVal;
661+
662+
// We don't want this to free fileContents when it completes, so the finalizeCallback is nullptr
663+
IfFailedGoLabel(GetParserStateBuffer(fileContents, nullptr, &bufferVal), ErrorRunFinalize);
664+
665+
// Bytecode buffer is created in one runtime and will be executed on different runtime.
666+
IfFailedGoLabel(CreateRuntime(&runtime), ErrorRunFinalize);
667+
chRuntime = runtime;
668+
669+
IfJsErrorFailLogLabel(ChakraRTInterface::JsCreateContext(runtime, &context), ErrorRunFinalize);
670+
IfJsErrorFailLogLabel(ChakraRTInterface::JsGetCurrentContext(&current), ErrorRunFinalize);
671+
IfJsErrorFailLogLabel(ChakraRTInterface::JsSetCurrentContext(context), ErrorRunFinalize);
672+
673+
// Initialized the WScript object on the new context
674+
if (!WScriptJsrt::Initialize())
675+
{
676+
IfFailedGoLabel(E_FAIL, ErrorRunFinalize);
677+
}
678+
679+
// This is our last call to use fileContents, so pass in the finalizeCallback
680+
IfFailGo(RunScript(fileName, fileContents, fileLength, fileContentsFinalizeCallback, nullptr, fullPath, bufferVal));
681+
682+
if (false)
683+
{
684+
ErrorRunFinalize:
685+
if (fileContentsFinalizeCallback != nullptr)
686+
{
687+
fileContentsFinalizeCallback((void*)fileContents);
688+
}
689+
}
690+
Error:
691+
if (current != JS_INVALID_REFERENCE)
692+
{
693+
ChakraRTInterface::JsSetCurrentContext(current);
694+
}
695+
696+
if (runtime != JS_INVALID_RUNTIME_HANDLE)
697+
{
698+
ChakraRTInterface::JsDisposeRuntime(runtime);
699+
}
700+
701+
return hr;
702+
}
703+
587704
HRESULT CreateAndRunSerializedScript(const char* fileName, LPCSTR fileContents, size_t fileLength, JsFinalizeCallback fileContentsFinalizeCallback, char *fullPath)
588705
{
589706
HRESULT hr = S_OK;
@@ -610,7 +727,7 @@ HRESULT CreateAndRunSerializedScript(const char* fileName, LPCSTR fileContents,
610727
}
611728

612729
// This is our last call to use fileContents, so pass in the finalizeCallback
613-
IfFailGo(RunScript(fileName, fileContents, fileLength, fileContentsFinalizeCallback, bufferVal, fullPath));
730+
IfFailGo(RunScript(fileName, fileContents, fileLength, fileContentsFinalizeCallback, bufferVal, fullPath, nullptr));
614731

615732
if(false)
616733
{
@@ -662,7 +779,7 @@ HRESULT ExecuteTest(const char* fileName)
662779
IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateContext(runtime, true, &context));
663780
IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
664781

665-
IfFailGo(RunScript(fileName, fileContents, lengthBytes, WScriptJsrt::FinalizeFree, nullptr, nullptr));
782+
IfFailGo(RunScript(fileName, fileContents, lengthBytes, WScriptJsrt::FinalizeFree, nullptr, nullptr, nullptr));
666783

667784
unsigned int rcount = 0;
668785
IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(nullptr));
@@ -783,9 +900,17 @@ HRESULT ExecuteTest(const char* fileName)
783900
{
784901
CreateAndRunSerializedScript(fileName, fileContents, lengthBytes, WScriptJsrt::FinalizeFree, fullPath);
785902
}
903+
else if (HostConfigFlags::flags.GenerateParserStateCacheIsEnabled)
904+
{
905+
CreateParserState(fileContents, lengthBytes, WScriptJsrt::FinalizeFree, nullptr);
906+
}
907+
else if (HostConfigFlags::flags.UseParserStateCacheIsEnabled)
908+
{
909+
CreateParserStateAndRunScript(fileName, fileContents, lengthBytes, WScriptJsrt::FinalizeFree, fullPath);
910+
}
786911
else
787912
{
788-
IfFailGo(RunScript(fileName, fileContents, lengthBytes, WScriptJsrt::FinalizeFree, nullptr, fullPath));
913+
IfFailGo(RunScript(fileName, fileContents, lengthBytes, WScriptJsrt::FinalizeFree, nullptr, fullPath, nullptr));
789914
}
790915
}
791916
Error:

lib/Common/ConfigFlagsList.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ PHASE(All)
434434
#define DEFAULT_CONFIG_HybridFgJit (false)
435435
#define DEFAULT_CONFIG_HybridFgJitBgQueueLengthThreshold (32)
436436
#define DEFAULT_CONFIG_Prejit (false)
437+
#define DEFAULT_CONFIG_ParserStateCache (true)
437438
#define DEFAULT_CONFIG_DeferTopLevelTillFirstCall (true)
438439
#define DEFAULT_CONFIG_DirectCallTelemetryStats (false)
439440
#define DEFAULT_CONFIG_errorStackTrace (true)
@@ -995,6 +996,7 @@ FLAGNR(NumberTrioSet, StatementDebugBreak, "Index of the statement where you wa
995996
FLAGNR(Phases, DebugBreakOnPhaseBegin, "Break into debugger at the beginning of given phase for listed function", )
996997

997998
FLAGNR(Boolean, DebugWindow , "Send console output to debugger window", false)
999+
FLAGNR(Boolean, ParserStateCache , "Enable creation of parser state cache", DEFAULT_CONFIG_ParserStateCache)
9981000
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)
9991001
FLAGNR(Number, DeferParse , "Minimum size of defer-parsed script (non-zero only: use /nodeferparse do disable", 0)
10001002
FLAGNR(Boolean, DirectCallTelemetryStats, "Enables logging stats for direct call telemetry", DEFAULT_CONFIG_DirectCallTelemetryStats)

lib/Common/Memory/AutoPtr.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,24 @@ class AutoDiscardPTR : public BasePtr<T>
220220
}
221221
}
222222
};
223+
224+
template <typename T>
225+
class AutoCoTaskMemFreePtr : public BasePtr<T>
226+
{
227+
public:
228+
AutoCoTaskMemFreePtr(T* ptr) : BasePtr<T>(ptr) {}
229+
~AutoCoTaskMemFreePtr()
230+
{
231+
Clear();
232+
}
233+
234+
private:
235+
void Clear()
236+
{
237+
if (this->ptr != nullptr)
238+
{
239+
CoTaskMemFree(this->ptr);
240+
this->ptr = nullptr;
241+
}
242+
}
243+
};

0 commit comments

Comments
 (0)