Open Bug 1752590 Opened 3 years ago Updated 3 years ago

Defer JS::EncodeStencil from WriteCachedStencil to cache file generation step

Categories

(Core :: JavaScript Engine, enhancement, P3)

enhancement

Tracking

()

People

(Reporter: arai, Unassigned)

References

(Blocks 1 open bug)

Details

mozJSComponentLoader::ObjectForLocation and EvalStencil supports both ScriptPreloader and StartupCache as cache storage:

https://searchfox.org/mozilla-central/rev/7056a708787621758bef9793a93aa7ca8375eeef/js/xpconnect/loader/mozJSComponentLoader.cpp#847-866

nsresult mozJSComponentLoader::ObjectForLocation(...) {
...
  ScriptPreloader::GetSingleton().NoteStencil(nativePath, cachePath, stencil);
...
  if (storeIntoStartupCache) {
...
    rv = WriteCachedStencil(cache, cachePath, cx, stencil);

https://searchfox.org/mozilla-central/rev/7056a708787621758bef9793a93aa7ca8375eeef/js/xpconnect/loader/mozJSSubScriptLoader.cpp#193-200

static bool EvalStencil(...) {
...
    nsCString uriStr;
    if (storeIntoPreloadCache && NS_SUCCEEDED(uri->GetSpec(uriStr))) {
      ScriptPreloader::GetSingleton().NoteStencil(uriStr, cachePath, stencil);
    }

    if (storeIntoStartupCache) {
      JSAutoRealm ar(cx, script);
      WriteCachedStencil(StartupCache::GetSingleton(), cachePath, cx, stencil);
    }

ScriptPreloader performs JS::EncodeStencil when writing cache:

https://searchfox.org/mozilla-central/rev/7056a708787621758bef9793a93aa7ca8375eeef/js/xpconnect/loader/ScriptPreloader.cpp#628

void ScriptPreloader::PrepareCacheWriteInternal() {
...
  for (auto& script : IterHash(mScripts, Match<ScriptStatus::Saved>())) {
...
    if (!script->mSize && !script->XDREncode(jsapi.cx())) {

https://searchfox.org/mozilla-central/rev/7056a708787621758bef9793a93aa7ca8375eeef/js/xpconnect/loader/ScriptPreloader.cpp#1183

bool ScriptPreloader::CachedStencil::XDREncode(JSContext* cx) {
...
  JS::TranscodeResult code = JS::EncodeStencil(cx, mStencil, Buffer());

But StartupCache performs JS::EncodeStencil immediately

https://searchfox.org/mozilla-central/rev/7056a708787621758bef9793a93aa7ca8375eeef/js/xpconnect/loader/mozJSLoaderUtils.cpp#57

nsresult WriteCachedStencil(StartupCache* cache, nsACString& uri, JSContext* cx,
                            JS::Stencil* stencil) {
  JS::TranscodeBuffer buffer;
  JS::TranscodeResult code = JS::EncodeStencil(cx, stencil, buffer);
...
  nsresult rv =
      cache->PutBuffer(PromiseFlatCString(uri).get(), std::move(buf), size);

Now we can hold stencil without much affecting VM/GC, the JS::EncodeStencil can be deferred until when StartupCache writes cache file,
so that it usually happens off-main thread, on idle time:

https://searchfox.org/mozilla-central/rev/bc996a6e952887b39dfb4cdd17c592b0c1774d6f/startupcache/StartupCache.cpp#524-527

Result<Ok, nsresult> StartupCache::WriteToDisk() {
...
  nsTArray<std::pair<const nsCString*, StartupCacheEntry*>> entries;
  for (auto iter = mTable.iter(); !iter.done(); iter.next()) {
    if (iter.get().value().mRequested) {
      entries.AppendElement(
          std::make_pair(&iter.get().key(), &iter.get().value()));
...
  for (auto& e : entries) {
    auto value = e.second;
    value->mOffset = offset;
    Span<const char> result;
    MOZ_TRY_VAR(result,
                ctx.BeginCompressing(writeSpan).mapErr(MapLZ4ErrorToNsresult));
    MOZ_TRY(Write(fd, result.Elements(), result.Length()));
    offset += result.Length();

    for (size_t i = 0; i < value->mUncompressedSize; i += chunkSize) {
      size_t size = std::min(chunkSize, value->mUncompressedSize - i);
      char* uncompressed = value->mData.get() + i;
      MOZ_TRY_VAR(result, ctx.ContinueCompressing(Span(uncompressed, size))
                              .mapErr(MapLZ4ErrorToNsresult));
      MOZ_TRY(Write(fd, result.Elements(), result.Length()));
      offset += result.Length();
    }
You need to log in before you can comment on or make changes to this bug.