Преглед изворни кода

Enable Deferred Parsing for Background Parse

This change turns on Deferred Parsing in BGParseManager, which will reduce the amount of time needed to parse in the background. Appropriate flags are added in calls inside BGParseManager and BGParseWorkItem.
Also, in order to serialize defer parsed bytecode, ScriptContext::CompileUTF8Core refactors the Parser object outside of the call because the serializer needs state from the parser to complete.
Thomas Moore (CHAKRA) пре 7 година
родитељ
комит
5af7feb652

+ 1 - 0
bin/ch/HostConfigFlagsList.h

@@ -19,5 +19,6 @@ FLAG(bool, TraceHostCallback,               "Output traces for host callbacks",
 FLAG(bool, Test262,                         "load Test262 harness", false)
 FLAG(bool, TrackRejectedPromises,           "Enable tracking of unhandled promise rejections", false)
 FLAG(BSTR, CustomConfigFile,                "Custom config file to be used to pass in additional flags to Chakra", NULL)
+FLAG(bool, ExecuteWithBgParse,              "[No-op] Load script with bgparse (note: requires bgparse to be on as well)", false)
 #undef FLAG
 #endif

+ 1 - 1
lib/Common/ConfigFlagsList.h

@@ -971,7 +971,7 @@ FLAGR (NumberSet, BailOutByteCode     , "Byte code location to insert BailOut. U
 #endif
 FLAGNR(Boolean, Benchmark             , "Disable security code which introduce variability in benchmarks", false)
 FLAGR (Boolean, BgJit                 , "Background JIT. Disable to force heuristic-based foreground JITting. (default: true)", true)
-FLAGR (Boolean, BgParse               , "Background Parse. Disable to force all parsing to occur on UI thread. (default: false)", false)
+FLAGR (Boolean, BgParse               , "Background Parse. Disable to force all parsing to occur on UI thread. (default: true)", true)
 FLAGNR(Number,  BgJitDelay            , "Delay to wait for speculative jitting before starting script execution", DEFAULT_CONFIG_BgJitDelay)
 FLAGNR(Number,  BgJitDelayFgBuffer    , "When speculatively jitting in the foreground thread, do so for (BgJitDelay - BgJitDelayBuffer) milliseconds", DEFAULT_CONFIG_BgJitDelayFgBuffer)
 FLAGNR(Number,  BgJitPendingFuncCap   , "Disable delay if pending function count larger then cap", DEFAULT_CONFIG_BgJitPendingFuncCap)

+ 110 - 31
lib/Parser/BGParseManager.cpp

@@ -14,9 +14,13 @@
 #include "Base/ScriptContext.h"
 #include "ByteCodeSerializer.h"
 
+#define BGPARSE_FLAGS (fscrGlobalCode | fscrWillDeferFncParse | fscrCanDeferFncParse | fscrCreateParserState)
+
 // Global, process singleton
 BGParseManager* BGParseManager::s_BGParseManager = nullptr;
 DWORD           BGParseManager::s_lastCookie = 0;
+DWORD           BGParseManager::s_completed = 0;
+DWORD           BGParseManager::s_failed = 0;
 CriticalSection BGParseManager::s_staticMemberLock;
 
 // Static member management
@@ -49,6 +53,17 @@ DWORD BGParseManager::GetNextCookie()
     return ++s_lastCookie;
 }
 
+DWORD BGParseManager::IncCompleted()
+{
+    AutoCriticalSection lock(&s_staticMemberLock);
+    return ++s_completed;
+}
+DWORD BGParseManager::IncFailed()
+{
+    AutoCriticalSection lock(&s_staticMemberLock);
+    return ++s_failed;
+}
+
 
 // Note: runs on any thread
 BGParseManager::BGParseManager()
@@ -217,7 +232,16 @@ HRESULT BGParseManager::GetInputFromCookie(DWORD cookie, LPCUTF8* ppszSrc, size_
 
 // Deserializes the background parse results into this thread
 // Note: *must* run on a UI/Execution thread with an available ScriptContext
-HRESULT BGParseManager::GetParseResults(Js::ScriptContext* scriptContextUI, DWORD cookie, LPCUTF8 pszSrc, SRCINFO const * pSrcInfo, Js::ParseableFunctionInfo** ppFunc, CompileScriptException* pse, size_t& srcLength)
+HRESULT BGParseManager::GetParseResults(
+    Js::ScriptContext* scriptContextUI,
+    DWORD cookie,
+    LPCUTF8 pszSrc,
+    SRCINFO const * pSrcInfo,
+    Js::ParseableFunctionInfo** ppFunc,
+    CompileScriptException* pse,
+    size_t& srcLength,
+    Js::Utf8SourceInfo* utf8SourceInfo,
+    uint& sourceIndex)
 {
     // TODO: Is there a way to cache the environment from which serialization begins to
     // determine whether or not deserialization will succeed? Specifically, being able
@@ -232,25 +256,20 @@ HRESULT BGParseManager::GetParseResults(Js::ScriptContext* scriptContextUI, DWOR
     {
         // Synchronously wait for the job to complete
         workitem->WaitForCompletion();
+        
+        Js::FunctionBody* functionBody = nullptr;
+        hr = workitem->DeserializeParseResults(scriptContextUI, pszSrc, pSrcInfo, utf8SourceInfo, &functionBody, srcLength, sourceIndex);
+        (*ppFunc) = functionBody;
+        workitem->TransferCSE(pse);
 
-        Field(Js::FunctionBody*) functionBody = nullptr;
-        hr = workitem->GetParseHR();
         if (hr == S_OK)
         {
-            srcLength = workitem->GetParseSourceLength();
-            hr = Js::ByteCodeSerializer::DeserializeFromBuffer(
-                scriptContextUI,
-                0, // flags
-                (const byte *)pszSrc,
-                pSrcInfo,
-                workitem->GetReturnBuffer(),
-                nullptr, // nativeModule
-                &functionBody
-            );
+            BGParseManager::IncCompleted();
+        }
+        else
+        {
+            BGParseManager::IncFailed();
         }
-
-        *ppFunc = functionBody;
-        workitem->TransferCSE(pse);
     }
 
     if (PHASE_TRACE1(Js::BgParsePhase))
@@ -475,27 +494,42 @@ void BGParseWorkItem::ParseUTF8Core(Js::ScriptContext* scriptContext)
     }
 
     SRCINFO si = {
-        /* sourceContextInfo   */ sourceContextInfo,
-        /* dlnHost             */ 0,
-        /* ulColumnHost        */ 0,
-        /* lnMinHost           */ 0,
-        /* ichMinHost          */ 0,
-        /* ichLimHost          */ (ULONG)0,
-        /* ulCharOffset        */ 0,
-        /* mod                 */ 0,
-        /* grfsi               */ 0
+        sourceContextInfo,
+        0, // dlnHost
+        0, // ulColumnHost
+        0, // lnMinHost
+        0, // ichMinHost
+        static_cast<ULONG>(cb / sizeof(utf8char_t)), // ichLimHost
+        0, // ulCharOffset
+        kmodGlobal, // mod
+        0 // grfsi
     };
 
-    // Currently always called from a try-catch
     ENTER_PINNED_SCOPE(Js::Utf8SourceInfo, sourceInfo);
-    sourceInfo = Js::Utf8SourceInfo::NewWithNoCopy(scriptContext, (LPUTF8)this->script, (int32)this->cb, static_cast<int32>(this->cb), &si, false);
-    LEAVE_PINNED_SCOPE();
+    sourceInfo = Js::Utf8SourceInfo::NewWithNoCopy(scriptContext, (LPUTF8)this->script, (int32)this->cb, static_cast<int32>(this->cb), &si, false);    
 
-    // what's a better name for "fIsOriginalUtf8Source?" what if i want to say "isutf8source" but not "isoriginal"?
     charcount_t cchLength = 0;
     uint sourceIndex = 0;
     Js::ParseableFunctionInfo * func = nullptr;
-    this->parseHR = scriptContext->CompileUTF8Core(sourceInfo, &si, true, this->script, this->cb, fscrGlobalCode, &this->cse, cchLength, this->parseSourceLength, sourceIndex, &func, nullptr);
+
+    Parser ps(scriptContext);
+    this->parseHR = scriptContext->CompileUTF8Core(
+        ps,
+        sourceInfo,
+        &si,
+        true, // fOriginalUtf8Code
+        this->script,
+        this->cb,
+        BGPARSE_FLAGS,
+        &this->cse,
+        cchLength,
+        this->parseSourceLength,
+        sourceIndex,
+        &func,
+        nullptr // pDataCache
+    );
+
+
     if (this->parseHR == S_OK)
     {
         BEGIN_TEMP_ALLOCATOR(tempAllocator, scriptContext, _u("BGParseWorkItem"));
@@ -510,7 +544,7 @@ void BGParseWorkItem::ParseUTF8Core(Js::ScriptContext* scriptContext)
             true, // allocateBuffer
             &this->bufferReturn,
             &this->bufferReturnBytes,
-            0
+            GENERATE_BYTE_CODE_PARSER_STATE
         );
         END_TEMP_ALLOCATOR(tempAllocator, scriptContext);
         Assert(this->parseHR == S_OK);
@@ -520,6 +554,51 @@ void BGParseWorkItem::ParseUTF8Core(Js::ScriptContext* scriptContext)
         Assert(this->cse.ei.bstrSource != nullptr);
         Assert(func == nullptr);
     }
+
+    LEAVE_PINNED_SCOPE();
+}
+
+// Deserializes the background parse results into this thread
+// Note: *must* run on a UI/Execution thread with an available ScriptContext
+HRESULT BGParseWorkItem::DeserializeParseResults(
+    Js::ScriptContext* scriptContextUI,
+    LPCUTF8 pszSrc,
+    SRCINFO const * pSrcInfo,
+    Js::Utf8SourceInfo* utf8SourceInfo,
+    Js::FunctionBody** functionBodyReturn,
+    size_t& srcLength,
+    uint& sourceIndex
+)
+{
+    HRESULT hr = this->parseHR;
+    if (hr == S_OK)
+    {
+        srcLength = this->parseSourceLength;
+        sourceIndex = scriptContextUI->SaveSourceNoCopy(utf8SourceInfo, (int)srcLength, false /*isCesu8*/);
+        Assert(sourceIndex != Js::Constants::InvalidSourceIndex);
+
+        Field(Js::FunctionBody*) functionBody = nullptr;
+        hr = Js::ByteCodeSerializer::DeserializeFromBuffer(
+            scriptContextUI,
+            BGPARSE_FLAGS,
+            (const byte *)pszSrc,
+            pSrcInfo,
+            this->bufferReturn,
+            nullptr, // nativeModule
+            &functionBody,
+            sourceIndex
+        );
+
+        if (hr == S_OK)
+        {
+            // The buffer is now owned by the output of DeserializeFromBuffer
+            (*functionBodyReturn) = functionBody;
+            this->bufferReturn = nullptr;
+            this->bufferReturnBytes = 0;
+        }
+    }
+
+    return hr;
 }
 
 void BGParseWorkItem::CreateCompletionEvent()

+ 16 - 4
lib/Parser/BGParseManager.h

@@ -48,6 +48,8 @@ public:
     static BGParseManager* GetBGParseManager();
     static void DeleteBGParseManager();
     static DWORD GetNextCookie();
+    static DWORD IncCompleted();
+    static DWORD IncFailed();
 
     HRESULT QueueBackgroundParse(LPCUTF8 pszSrc, size_t cbLength, char16 *fullPath, DWORD* dwBgParseCookie);
     HRESULT GetInputFromCookie(DWORD cookie, LPCUTF8* ppszSrc, size_t* pcbLength);
@@ -58,7 +60,9 @@ public:
         SRCINFO const * pSrcInfo,
         Js::ParseableFunctionInfo** ppFunc,
         CompileScriptException* pse,
-        size_t& srcLength
+        size_t& srcLength,
+        Js::Utf8SourceInfo* utf8SourceInfo,
+        uint& sourceIndex
     );
     bool DiscardParseResults(DWORD cookie, void* buffer);
 
@@ -81,6 +85,8 @@ private:
     JsUtil::DoublyLinkedList<BGParseWorkItem> workitemsProcessed;
 
     static DWORD s_lastCookie;
+    static DWORD s_completed;
+    static DWORD s_failed;
     static BGParseManager* s_BGParseManager;
     static CriticalSection s_staticMemberLock;
 };
@@ -100,6 +106,15 @@ public:
     ~BGParseWorkItem();
 
     void ParseUTF8Core(Js::ScriptContext* scriptContext);
+    HRESULT DeserializeParseResults(
+        Js::ScriptContext* scriptContextUI,
+        LPCUTF8 pszSrc,
+        SRCINFO const * pSrcInfo,
+        Js::Utf8SourceInfo* utf8SourceInfo,
+        Js::FunctionBody** functionBodyReturn,
+        size_t& srcLength,
+        uint& sourceIndex
+    );
     void TransferCSE(CompileScriptException* pse);
 
     void CreateCompletionEvent();
@@ -112,9 +127,6 @@ public:
     DWORD GetCookie() const { return cookie; }
     const byte* GetScriptSrc() const { return script; }
     size_t GetScriptLength() const { return cb; }
-    byte * GetReturnBuffer() const{ return bufferReturn; }
-    HRESULT GetParseHR() const { return parseHR; }
-    size_t GetParseSourceLength() const { return parseSourceLength; }
 
 private:
     // This cookie is the public identifier for this parser work

+ 1 - 1
lib/Runtime/Base/ScriptContext.cpp

@@ -2260,6 +2260,7 @@ namespace Js
     }
 
     HRESULT ScriptContext::CompileUTF8Core(
+        __in Parser& ps,
         __in Js::Utf8SourceInfo* utf8SourceInfo,
         __in SRCINFO *srcInfo,
         __in BOOL fOriginalUTF8Code,
@@ -2275,7 +2276,6 @@ namespace Js
     )
     {
         HRESULT hr = E_FAIL;
-        Parser ps(this);
         (*func) = nullptr;
         srcLength = cchLength;
 

+ 1 - 0
lib/Runtime/Base/ScriptContext.h

@@ -1308,6 +1308,7 @@ private:
             _In_ Js::SimpleDataCacheWrapper* pDataCache);
 
         HRESULT CompileUTF8Core(
+            __in Parser& ps,
             __in Js::Utf8SourceInfo* utf8SourceInfo,
             __in SRCINFO *srcInfo,
             __in BOOL fOriginalUTF8Code,

+ 7 - 0
test/Math/rlexe.xml

@@ -102,6 +102,13 @@
       <baseline>sin.baseline</baseline>
     </default>
   </test>
+  <test>
+    <default>
+      <files>sin.js</files>
+      <baseline>sin.baseline</baseline>
+      <compile-flags>-ExecuteWithBgParse</compile-flags>
+    </default>
+  </test>
   <test>
     <default>
       <files>sqrt.js</files>

+ 7 - 0
test/Object/rlexe.xml

@@ -42,6 +42,13 @@
       <baseline>Object.baseline</baseline>
     </default>
   </test>
+  <test>
+    <default>
+      <files>Object.js</files>
+      <baseline>Object.baseline</baseline>
+      <compile-flags>-ExecuteWithBgParse</compile-flags>
+    </default>
+  </test>
   <test>
     <default>
       <files>null.js</files>

+ 6 - 0
test/Optimizer/rlexe.xml

@@ -915,6 +915,12 @@
       <files>test127.js</files>
     </default>
   </test>
+  <test>
+    <default>
+      <files>test127.js</files>
+      <compile-flags>-ExecuteWithBgParse</compile-flags>
+    </default>
+  </test>
   <test>
     <default>
       <files>test128.js</files>

+ 7 - 0
test/Strings/rlexe.xml

@@ -212,6 +212,13 @@
       <baseline>long_concatstr.baseline</baseline>
     </default>
   </test>
+  <test>
+    <default>
+      <files>long_concatstr.js</files>
+      <baseline>long_concatstr.baseline</baseline>
+      <compile-flags>-ExecuteWithBgParse</compile-flags>
+    </default>
+  </test>
   <test>
     <default>
       <files>StringTagFunctions.js</files>

+ 8 - 0
test/es6/rlexe.xml

@@ -507,6 +507,14 @@
       <compile-flags> -ES6Unicode</compile-flags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>normalize.js</files>
+      <baseline>normalize.baseline</baseline>
+      <tags>exclude_noicu</tags>
+      <compile-flags>-ES6Unicode -ExecuteWithBgParse</compile-flags>
+    </default>
+  </test>
   <test>
     <default>
       <files>normalizeProp.js</files>