Bug 1843030 - Part 4: Add PreallocatedCompilationGCOutput. r=nbp

Differential Revision: https://phabricator.services.mozilla.com/D183462
This commit is contained in:
Tooru Fujisawa
2023-07-14 08:27:01 +00:00
parent 6da2acfdfa
commit c58cfb22df
8 changed files with 91 additions and 46 deletions

View File

@@ -95,9 +95,9 @@ nsresult JSExecutionContext::JoinOffThread(
MOZ_ASSERT(!mWantsReturnValue); MOZ_ASSERT(!mWantsReturnValue);
JS::Rooted<JS::InstantiationStorage> storage(mCx); JS::InstantiationStorage storage;
RefPtr<JS::Stencil> stencil = RefPtr<JS::Stencil> stencil =
JS::FinishOffThreadStencil(mCx, *aOffThreadToken, storage.address()); JS::FinishOffThreadStencil(mCx, *aOffThreadToken, &storage);
*aOffThreadToken = nullptr; // Mark the token as having been finished. *aOffThreadToken = nullptr; // Mark the token as having been finished.
if (!stencil) { if (!stencil) {
mSkip = true; mSkip = true;
@@ -105,7 +105,7 @@ nsresult JSExecutionContext::JoinOffThread(
return mRv; return mRv;
} }
return InstantiateStencil(std::move(stencil), storage.address()); return InstantiateStencil(std::move(stencil), &storage);
} }
template <typename Unit> template <typename Unit>

View File

@@ -149,10 +149,9 @@ nsresult ModuleLoader::CompileFetchedModule(
JSContext* aCx, JS::Handle<JSObject*> aGlobal, JS::CompileOptions& aOptions, JSContext* aCx, JS::Handle<JSObject*> aGlobal, JS::CompileOptions& aOptions,
ModuleLoadRequest* aRequest, JS::MutableHandle<JSObject*> aModuleOut) { ModuleLoadRequest* aRequest, JS::MutableHandle<JSObject*> aModuleOut) {
if (aRequest->GetScriptLoadContext()->mWasCompiledOMT) { if (aRequest->GetScriptLoadContext()->mWasCompiledOMT) {
JS::Rooted<JS::InstantiationStorage> storage(aCx); JS::InstantiationStorage storage;
RefPtr<JS::Stencil> stencil = JS::FinishOffThreadStencil( RefPtr<JS::Stencil> stencil = JS::FinishOffThreadStencil(
aCx, aRequest->GetScriptLoadContext()->mOffThreadToken, aCx, aRequest->GetScriptLoadContext()->mOffThreadToken, &storage);
storage.address());
aRequest->GetScriptLoadContext()->mOffThreadToken = nullptr; aRequest->GetScriptLoadContext()->mOffThreadToken = nullptr;
@@ -162,7 +161,7 @@ nsresult ModuleLoader::CompileFetchedModule(
JS::InstantiateOptions instantiateOptions(aOptions); JS::InstantiateOptions instantiateOptions(aOptions);
aModuleOut.set(JS::InstantiateModuleStencil(aCx, instantiateOptions, aModuleOut.set(JS::InstantiateModuleStencil(aCx, instantiateOptions,
stencil, storage.address())); stencil, &storage));
if (!aModuleOut) { if (!aModuleOut) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }

View File

@@ -39,6 +39,7 @@ namespace frontend {
struct CompilationStencil; struct CompilationStencil;
struct CompilationGCOutput; struct CompilationGCOutput;
struct CompilationInput; struct CompilationInput;
struct PreallocatedCompilationGCOutput;
} // namespace frontend } // namespace frontend
} // namespace js } // namespace js
@@ -61,9 +62,9 @@ struct InstantiationStorage {
private: private:
// Owned CompilationGCOutput. // Owned CompilationGCOutput.
// //
// This uses raw pointer instead of UniquePtr because CompilationGCOutput // This uses raw pointer instead of UniquePtr because
// is opaque. // PreallocatedCompilationGCOutput is opaque.
js::frontend::CompilationGCOutput* gcOutput_ = nullptr; js::frontend::PreallocatedCompilationGCOutput* gcOutput_ = nullptr;
friend JS_PUBLIC_API JSScript* InstantiateGlobalStencil( friend JS_PUBLIC_API JSScript* InstantiateGlobalStencil(
JSContext* cx, const InstantiateOptions& options, Stencil* stencil, JSContext* cx, const InstantiateOptions& options, Stencil* stencil,
@@ -94,8 +95,6 @@ struct InstantiationStorage {
public: public:
bool isValid() const { return !!gcOutput_; } bool isValid() const { return !!gcOutput_; }
void trace(JSTracer* trc);
}; };
} // namespace JS } // namespace JS

View File

@@ -74,6 +74,7 @@ namespace frontend {
struct CompilationInput; struct CompilationInput;
struct CompilationStencil; struct CompilationStencil;
struct CompilationGCOutput; struct CompilationGCOutput;
struct PreallocatedCompilationGCOutput;
class ScriptStencilIterable; class ScriptStencilIterable;
struct InputName; struct InputName;
class ScopeBindingCache; class ScopeBindingCache;
@@ -1213,6 +1214,10 @@ struct CompilationStencil {
[[nodiscard]] static bool prepareForInstantiate( [[nodiscard]] static bool prepareForInstantiate(
FrontendContext* fc, CompilationAtomCache& atomCache, FrontendContext* fc, CompilationAtomCache& atomCache,
const CompilationStencil& stencil, CompilationGCOutput& gcOutput); const CompilationStencil& stencil, CompilationGCOutput& gcOutput);
[[nodiscard]] static bool prepareForInstantiate(
FrontendContext* fc, CompilationAtomCache& atomCache,
const CompilationStencil& stencil,
PreallocatedCompilationGCOutput& gcOutput);
[[nodiscard]] static bool instantiateStencils( [[nodiscard]] static bool instantiateStencils(
JSContext* cx, CompilationInput& input, const CompilationStencil& stencil, JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
@@ -1661,6 +1666,38 @@ struct PreAllocateableGCArray {
void trace(JSTracer* trc); void trace(JSTracer* trc);
}; };
struct CompilationGCOutput;
// Pre-allocated storage for CompilationGCOutput.
struct PreallocatedCompilationGCOutput {
private:
PreAllocateableGCArray<JSFunction*>::Preallocated functions;
PreAllocateableGCArray<js::Scope*>::Preallocated scopes;
friend struct CompilationGCOutput;
public:
PreallocatedCompilationGCOutput() = default;
[[nodiscard]] bool allocate(FrontendContext* fc, size_t scriptDataLength,
size_t scopeDataLength) {
if (!functions.allocate(scriptDataLength)) {
ReportOutOfMemory(fc);
return false;
}
if (!scopes.allocate(scopeDataLength)) {
ReportOutOfMemory(fc);
return false;
}
return true;
}
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
return functions.sizeOfExcludingThis(mallocSizeOf) +
scopes.sizeOfExcludingThis(mallocSizeOf);
}
};
// The output of GC allocation from stencil. // The output of GC allocation from stencil.
struct CompilationGCOutput { struct CompilationGCOutput {
// The resulting outermost script for the compilation powered // The resulting outermost script for the compilation powered
@@ -1722,9 +1759,7 @@ struct CompilationGCOutput {
return scopes[index]; return scopes[index];
} }
// Allocate output arrays. This may be called before instantiate to do // Allocate output arrays.
// allocations ahead of time (off thread). The stencil instantiation code will
// also run this to ensure the arrays are ready.
[[nodiscard]] bool ensureAllocated(FrontendContext* fc, [[nodiscard]] bool ensureAllocated(FrontendContext* fc,
size_t scriptDataLength, size_t scriptDataLength,
size_t scopeDataLength) { size_t scopeDataLength) {
@@ -1743,6 +1778,12 @@ struct CompilationGCOutput {
return true; return true;
} }
// Steal output arrays' buffer.
void steal(PreallocatedCompilationGCOutput&& pre) {
functions.steal(std::move(pre.functions));
scopes.steal(std::move(pre.scopes));
}
// A variant of `ensureAllocated` that sets a base index for the function and // A variant of `ensureAllocated` that sets a base index for the function and
// scope arrays. This is used when instantiating only a subset of the stencil. // scope arrays. This is used when instantiating only a subset of the stencil.
// Currently this only applies to self-hosted delazification. The ranges // Currently this only applies to self-hosted delazification. The ranges

View File

@@ -213,7 +213,8 @@ bool JS::PrepareForInstantiate(JS::FrontendContext* fc,
MOZ_ASSERT(isGCSafe(compileStorage.getInput())); MOZ_ASSERT(isGCSafe(compileStorage.getInput()));
if (!storage.gcOutput_) { if (!storage.gcOutput_) {
storage.gcOutput_ = storage.gcOutput_ =
fc->getAllocator()->new_<js::frontend::CompilationGCOutput>(); fc->getAllocator()
->new_<js::frontend::PreallocatedCompilationGCOutput>();
if (!storage.gcOutput_) { if (!storage.gcOutput_) {
return false; return false;
} }

View File

@@ -1814,12 +1814,6 @@ void CompilationGCOutput::trace(JSTracer* trc) {
scopes.trace(trc); scopes.trace(trc);
} }
void JS::InstantiationStorage::trace(JSTracer* trc) {
if (gcOutput_) {
gcOutput_->trace(trc);
}
}
RegExpObject* RegExpStencil::createRegExp( RegExpObject* RegExpStencil::createRegExp(
JSContext* cx, const CompilationAtomCache& atomCache) const { JSContext* cx, const CompilationAtomCache& atomCache) const {
Rooted<JSAtom*> atom(cx, atomCache.getExistingAtomAt(cx, atom_)); Rooted<JSAtom*> atom(cx, atomCache.getExistingAtomAt(cx, atom_));
@@ -2892,6 +2886,19 @@ bool CompilationStencil::prepareForInstantiate(
return atomCache.allocate(fc, stencil.parserAtomData.size()); return atomCache.allocate(fc, stencil.parserAtomData.size());
} }
/* static */
bool CompilationStencil::prepareForInstantiate(
FrontendContext* fc, CompilationAtomCache& atomCache,
const CompilationStencil& stencil,
PreallocatedCompilationGCOutput& gcOutput) {
if (!gcOutput.allocate(fc, stencil.scriptData.size(),
stencil.scopeData.size())) {
return false;
}
return atomCache.allocate(fc, stencil.parserAtomData.size());
}
bool CompilationStencil::serializeStencils(JSContext* cx, bool CompilationStencil::serializeStencils(JSContext* cx,
CompilationInput& input, CompilationInput& input,
JS::TranscodeBuffer& buf, JS::TranscodeBuffer& buf,
@@ -5467,12 +5474,14 @@ JS_PUBLIC_API JSScript* JS::InstantiateGlobalStencil(
options.copyTo(compileOptions); options.copyTo(compileOptions);
Rooted<CompilationInput> input(cx, CompilationInput(compileOptions)); Rooted<CompilationInput> input(cx, CompilationInput(compileOptions));
Rooted<CompilationGCOutput> gcOutput(cx); Rooted<CompilationGCOutput> gcOutput(cx);
CompilationGCOutput& output = storage ? *storage->gcOutput_ : gcOutput.get(); if (storage) {
gcOutput.get().steal(std::move(*storage->gcOutput_));
}
if (!InstantiateStencils(cx, input.get(), *stencil, output)) { if (!InstantiateStencils(cx, input.get(), *stencil, gcOutput.get())) {
return nullptr; return nullptr;
} }
return output.script; return gcOutput.get().script;
} }
JS_PUBLIC_API bool JS::StencilIsBorrowed(Stencil* stencil) { JS_PUBLIC_API bool JS::StencilIsBorrowed(Stencil* stencil) {
@@ -5489,12 +5498,14 @@ JS_PUBLIC_API JSObject* JS::InstantiateModuleStencil(
compileOptions.setModule(); compileOptions.setModule();
Rooted<CompilationInput> input(cx, CompilationInput(compileOptions)); Rooted<CompilationInput> input(cx, CompilationInput(compileOptions));
Rooted<CompilationGCOutput> gcOutput(cx); Rooted<CompilationGCOutput> gcOutput(cx);
CompilationGCOutput& output = storage ? *storage->gcOutput_ : gcOutput.get(); if (storage) {
gcOutput.get().steal(std::move(*storage->gcOutput_));
}
if (!InstantiateStencils(cx, input.get(), *stencil, output)) { if (!InstantiateStencils(cx, input.get(), *stencil, gcOutput.get())) {
return nullptr; return nullptr;
} }
return output.module; return gcOutput.get().module;
} }
JS::TranscodeResult JS::EncodeStencil(JSContext* cx, JS::Stencil* stencil, JS::TranscodeResult JS::EncodeStencil(JSContext* cx, JS::Stencil* stencil,

View File

@@ -411,15 +411,13 @@ BEGIN_TEST(testStencil_OffThreadWithInstantiationStorage) {
lock.wait(); lock.wait();
} }
JS::Rooted<JS::InstantiationStorage> storage(cx); JS::InstantiationStorage storage;
RefPtr<JS::Stencil> stencil = RefPtr<JS::Stencil> stencil = JS::FinishOffThreadStencil(cx, token, &storage);
JS::FinishOffThreadStencil(cx, token, storage.address());
CHECK(stencil); CHECK(stencil);
JS::InstantiateOptions instantiateOptions(options); JS::InstantiateOptions instantiateOptions(options);
JS::RootedScript script( JS::RootedScript script(cx, JS::InstantiateGlobalStencil(
cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil, cx, instantiateOptions, stencil, &storage));
storage.address()));
CHECK(script); CHECK(script);
JS::RootedValue rval(cx); JS::RootedValue rval(cx);
@@ -514,15 +512,14 @@ BEGIN_TEST(testStencil_OffThreadModuleWithInstantiationStorage) {
lock.wait(); lock.wait();
} }
JS::Rooted<JS::InstantiationStorage> storage(cx); JS::InstantiationStorage storage;
RefPtr<JS::Stencil> stencil = RefPtr<JS::Stencil> stencil = JS::FinishOffThreadStencil(cx, token, &storage);
JS::FinishOffThreadStencil(cx, token, storage.address());
CHECK(stencil); CHECK(stencil);
JS::InstantiateOptions instantiateOptions(options); JS::InstantiateOptions instantiateOptions(options);
JS::RootedObject moduleObject( JS::RootedObject moduleObject(
cx, JS::InstantiateModuleStencil(cx, instantiateOptions, stencil, cx,
storage.address())); JS::InstantiateModuleStencil(cx, instantiateOptions, stencil, &storage));
CHECK(moduleObject); CHECK(moduleObject);
JS::RootedValue rval(cx); JS::RootedValue rval(cx);
@@ -677,17 +674,15 @@ BEGIN_TEST(testStencil_OffThreadDecodeWithInstantiationStorage) {
} }
} }
JS::Rooted<JS::InstantiationStorage> storage(cx); JS::InstantiationStorage storage;
RefPtr<JS::Stencil> stencil = RefPtr<JS::Stencil> stencil = JS::FinishOffThreadStencil(cx, token, &storage);
JS::FinishOffThreadStencil(cx, token, storage.address());
CHECK(stencil); CHECK(stencil);
CHECK(!JS::StencilIsBorrowed(stencil)); CHECK(!JS::StencilIsBorrowed(stencil));
JS::InstantiateOptions instantiateOptions; JS::InstantiateOptions instantiateOptions;
JS::RootedScript script( JS::RootedScript script(cx, JS::InstantiateGlobalStencil(
cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil, cx, instantiateOptions, stencil, &storage));
storage.address()));
CHECK(script); CHECK(script);
JS::RootedValue rval(cx); JS::RootedValue rval(cx);

View File

@@ -561,7 +561,6 @@ void ParseTask::trace(JSTracer* trc) {
} }
compileStorage_.trace(trc); compileStorage_.trace(trc);
instantiationStorage_.trace(trc);
} }
size_t ParseTask::sizeOfExcludingThis( size_t ParseTask::sizeOfExcludingThis(