Bug 1454352 - Add APIs for parallel decoding of BinAST data r=jonco
authorEric Faust <efaustbmo@gmail.com>
Thu, 10 May 2018 13:26:16 +0100
changeset 417719 91ced8101f99044842e7e532edd9b45e54c35bc5
parent 417718 184216421caa824bd1b8aa3015ec99481c342fed
child 417720 635bea9e749d77888d28f422c7ef4b1862e078c4
push id33977
push userncsoregi@mozilla.com
push dateThu, 10 May 2018 16:43:24 +0000
treeherdermozilla-central@17db33b6a124 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1454352
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1454352 - Add APIs for parallel decoding of BinAST data r=jonco
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/vm/HelperThreads.cpp
js/src/vm/HelperThreads.h
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -617,25 +617,25 @@ frontend::CompileGlobalScript(JSContext*
     assertException.reset();
     return script;
 }
 
 #if defined(JS_BUILD_BINAST)
 
 JSScript*
 frontend::CompileGlobalBinASTScript(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
-                                    const uint8_t* src, size_t len)
+                                    const uint8_t* src, size_t len, ScriptSourceObject** sourceObjectOut)
 {
     AutoAssertReportedException assertException(cx);
 
     frontend::UsedNameTracker usedNames(cx);
     if (!usedNames.init())
         return nullptr;
 
-    RootedObject sourceObj(cx, CreateScriptSourceObject(cx, options));
+    RootedScriptSourceObject sourceObj(cx, CreateScriptSourceObject(cx, options));
 
     if (!sourceObj)
         return nullptr;
 
     RootedScript script(cx, JSScript::Create(cx, options, sourceObj, 0, len, 0, len));
 
     if (!script)
         return nullptr;
@@ -656,16 +656,19 @@ frontend::CompileGlobalBinASTScript(JSCo
 
     ParseNode *pn = parsed.unwrap();
     if (!bce.emitScript(pn))
         return nullptr;
 
     if (!NameFunctions(cx, pn))
         return nullptr;
 
+    if (sourceObjectOut)
+        *sourceObjectOut = sourceObj;
+
     assertException.reset();
     return script;
 }
 
 #endif // JS_BUILD_BINAST
 
 JSScript*
 frontend::CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -36,17 +36,18 @@ CompileGlobalScript(JSContext* cx, LifoA
                     SourceBufferHolder& srcBuf,
                     ScriptSourceObject** sourceObjectOut = nullptr);
 
 #if defined(JS_BUILD_BINAST)
 
 JSScript*
 CompileGlobalBinASTScript(JSContext *cx, LifoAlloc& alloc,
                           const ReadOnlyCompileOptions& options,
-                          const uint8_t* src, size_t len);
+                          const uint8_t* src, size_t len,
+                          ScriptSourceObject** sourceObjectOut = nullptr);
 
 #endif // JS_BUILD_BINAST
 
 JSScript*
 CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
                   HandleObject scopeChain, HandleScope enclosingScope,
                   const ReadOnlyCompileOptions& options,
                   SourceBufferHolder& srcBuf,
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4243,16 +4243,32 @@ JS::DecodeBinAST(JSContext* cx, const Re
 {
     FileContents fileContents(cx);
     if (!ReadCompleteFile(cx, file, fileContents))
         return nullptr;
 
     return DecodeBinAST(cx, options, fileContents.begin(), fileContents.length());
 }
 
+JS_PUBLIC_API(bool)
+JS::DecodeBinASTOffThread(JSContext* cx, const ReadOnlyCompileOptions& options,
+                          const uint8_t* buf, size_t length,
+                          OffThreadCompileCallback callback, void* callbackData)
+{
+    return StartOffThreadDecodeBinAST(cx, options, buf, length, callback, callbackData);
+}
+
+JS_PUBLIC_API(JSScript*)
+JS::FinishOffThreadBinASTDecode(JSContext* cx, void* token)
+{
+    MOZ_ASSERT(cx);
+    MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
+    return HelperThreadState().finishBinASTDecodeTask(cx, token);
+}
+
 #endif /* JS_BUILD_BINAST */
 
 enum class OffThread {
     Compile, Decode,
 };
 
 static bool
 CanDoOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t length, OffThread what)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4236,16 +4236,24 @@ namespace JS {
 extern JS_PUBLIC_API(JSScript*)
 DecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
              FILE* file);
 
 extern JS_PUBLIC_API(JSScript*)
 DecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
              const uint8_t* buf, size_t length);
 
+extern JS_PUBLIC_API(bool)
+DecodeBinASTOffThread(JSContext* cx, const ReadOnlyCompileOptions& options,
+                      const uint8_t* buf, size_t length,
+                      OffThreadCompileCallback callback, void* callbackData);
+
+extern JS_PUBLIC_API(JSScript*)
+FinishOffThreadBinASTDecode(JSContext* cx, void* token);
+
 } /* namespace JS */
 
 #endif /* JS_BUILD_BINAST */
 
 extern JS_PUBLIC_API(bool)
 JS_CheckForInterrupt(JSContext* cx);
 
 /*
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -529,16 +529,41 @@ ScriptDecodeTask::parse(JSContext* cx)
     MOZ_ASSERT(bool(resultScript) == res.isOk());
     if (res.isOk()) {
         scripts.infallibleAppend(resultScript);
         if (sourceObject)
             sourceObjects.infallibleAppend(sourceObject);
     }
 }
 
+#if defined(JS_BUILD_BINAST)
+
+BinASTDecodeTask::BinASTDecodeTask(JSContext* cx, const uint8_t* buf, size_t length,
+                                   JS::OffThreadCompileCallback callback, void* callbackData)
+  : ParseTask(ParseTaskKind::BinAST, cx, callback, callbackData),
+    data(buf, length)
+{}
+
+void
+BinASTDecodeTask::parse(JSContext* cx)
+{
+    RootedScriptSourceObject sourceObject(cx);
+
+    JSScript* script = frontend::CompileGlobalBinASTScript(cx, alloc, options,
+                                                           data.begin().get(), data.length(),
+                                                           &sourceObject.get());
+    if (script) {
+        scripts.infallibleAppend(script);
+        if (sourceObject)
+            sourceObjects.infallibleAppend(sourceObject);
+    }
+}
+
+#endif /* JS_BUILD_BINAST */
+
 MultiScriptsDecodeTask::MultiScriptsDecodeTask(JSContext* cx, JS::TranscodeSources& sources,
                                                JS::OffThreadCompileCallback callback,
                                                void* callbackData)
   : ParseTask(ParseTaskKind::MultiScriptsDecode, cx, callback, callbackData),
     sources(&sources)
 {}
 
 void
@@ -833,16 +858,34 @@ js::StartOffThreadDecodeMultiScripts(JSC
     task = cx->new_<MultiScriptsDecodeTask>(cx, sources, callback, callbackData);
     if (!task || !StartOffThreadParseTask(cx, task, options))
         return false;
 
     task.forget();
     return true;
 }
 
+#if defined(JS_BUILD_BINAST)
+
+bool
+js::StartOffThreadDecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
+                               const uint8_t* buf, size_t length,
+                               JS::OffThreadCompileCallback callback, void *callbackData)
+{
+    ScopedJSDeletePtr<ParseTask> task;
+    task = cx->new_<BinASTDecodeTask>(cx, buf, length, callback, callbackData);
+    if (!task || !StartOffThreadParseTask(cx, task, options))
+        return false;
+
+    task.forget();
+    return true;
+}
+
+#endif /* JS_BUILD_BINAST */
+
 void
 js::EnqueuePendingParseTasksAfterGC(JSRuntime* rt)
 {
     MOZ_ASSERT(!OffThreadParsingMustWaitForGC(rt));
 
     GlobalHelperThreadState::ParseTaskVector newTasks;
     {
         AutoLockHelperThreadState lock;
@@ -1725,16 +1768,28 @@ GlobalHelperThreadState::finishScriptPar
 JSScript*
 GlobalHelperThreadState::finishScriptDecodeTask(JSContext* cx, void* token)
 {
     JSScript* script = finishParseTask(cx, ParseTaskKind::ScriptDecode, token);
     MOZ_ASSERT_IF(script, script->isGlobalCode());
     return script;
 }
 
+#if defined(JS_BUILD_BINAST)
+
+JSScript*
+GlobalHelperThreadState::finishBinASTDecodeTask(JSContext* cx, void* token)
+{
+    JSScript* script = finishParseTask(cx, ParseTaskKind::BinAST, token);
+    MOZ_ASSERT_IF(script, script->isGlobalCode());
+    return script;
+}
+
+#endif /* JS_BUILD_BINAST */
+
 bool
 GlobalHelperThreadState::finishMultiScriptsDecodeTask(JSContext* cx, void* token, MutableHandle<ScriptVector> scripts)
 {
     return finishParseTask(cx, ParseTaskKind::MultiScriptsDecode, token, scripts);
 }
 
 JSObject*
 GlobalHelperThreadState::finishModuleParseTask(JSContext* cx, void* token)
--- a/js/src/vm/HelperThreads.h
+++ b/js/src/vm/HelperThreads.h
@@ -44,16 +44,17 @@ namespace wasm {
   struct Tier2GeneratorTask;
 } // namespace wasm
 
 enum class ParseTaskKind
 {
     Script,
     Module,
     ScriptDecode,
+    BinAST,
     MultiScriptsDecode
 };
 
 namespace wasm {
 
 struct CompileTask;
 typedef Fifo<CompileTask*, 0, SystemAllocPolicy> CompileTaskPtrFifo;
 
@@ -302,16 +303,20 @@ class GlobalHelperThreadState
 
     void trace(JSTracer* trc, js::gc::AutoTraceSession& session);
 
     JSScript* finishScriptParseTask(JSContext* cx, void* token);
     JSScript* finishScriptDecodeTask(JSContext* cx, void* token);
     bool finishMultiScriptsDecodeTask(JSContext* cx, void* token, MutableHandle<ScriptVector> scripts);
     JSObject* finishModuleParseTask(JSContext* cx, void* token);
 
+#if defined(JS_BUILD_BINAST)
+    JSScript* finishBinASTDecodeTask(JSContext* cx, void* token);
+#endif
+
     bool hasActiveThreads(const AutoLockHelperThreadState&);
     void waitForAllThreads();
     void waitForAllThreadsLocked(AutoLockHelperThreadState&);
 
     template <typename T>
     bool checkTaskThreadLimit(size_t maxThreads, bool isMaster = false) const;
 
   private:
@@ -590,16 +595,25 @@ StartOffThreadParseModule(JSContext* cx,
                           const char16_t* chars, size_t length,
                           JS::OffThreadCompileCallback callback, void* callbackData);
 
 bool
 StartOffThreadDecodeScript(JSContext* cx, const ReadOnlyCompileOptions& options,
                            const JS::TranscodeRange& range,
                            JS::OffThreadCompileCallback callback, void* callbackData);
 
+#if defined(JS_BUILD_BINAST)
+
+bool
+StartOffThreadDecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
+                           const uint8_t* buf, size_t length,
+                           JS::OffThreadCompileCallback callback, void* callbackData);
+
+#endif /* JS_BUILD_BINAST */
+
 bool
 StartOffThreadDecodeMultiScripts(JSContext* cx, const ReadOnlyCompileOptions& options,
                                  JS::TranscodeSources& sources,
                                  JS::OffThreadCompileCallback callback, void* callbackData);
 
 /*
  * Called at the end of GC to enqueue any Parse tasks that were waiting on an
  * atoms-zone GC to finish.
@@ -724,16 +738,29 @@ struct ScriptDecodeTask : public ParseTa
 {
     const JS::TranscodeRange range;
 
     ScriptDecodeTask(JSContext* cx, const JS::TranscodeRange& range,
                      JS::OffThreadCompileCallback callback, void* callbackData);
     void parse(JSContext* cx) override;
 };
 
+#if defined(JS_BUILD_BINAST)
+
+struct BinASTDecodeTask : public ParseTask
+{
+    mozilla::Range<const uint8_t> data;
+
+    BinASTDecodeTask(JSContext* cx, const uint8_t* buf, size_t length,
+                     JS::OffThreadCompileCallback callback, void* callbackData);
+    void parse(JSContext* cx) override;
+};
+
+#endif /* JS_BUILD_BINAST */
+
 struct MultiScriptsDecodeTask : public ParseTask
 {
     JS::TranscodeSources* sources;
 
     MultiScriptsDecodeTask(JSContext* cx, JS::TranscodeSources& sources,
                            JS::OffThreadCompileCallback callback, void* callbackData);
     void parse(JSContext* cx) override;
 };