Bug 1404741: Don't call mozJSComponentLoader::CompilationScope during URLPreloader critical section. r=mccr8

The URLPreloader's initialization code accesses the Omnijar cache off-main
thread. It can do so safely only as long as the main thread is blocked, or
running code which is guaranteed never to touch Omnijar, while its critical
section runs.

While that was guaranteed for previous versions of the code, some invariants
changed when we began using the component loader's shared global for initial
compilation. Once the global is created, we can safely use it to initialize
compilation. But creating the global invokes a large amount of Gecko code,
some of which touches Omnijar in the process.

MozReview-Commit-ID: 48WoIZtGPTo

--HG--
extra : rebase_source : 9bd5d884e32cfa59c022edb00078aac050acb20b
This commit is contained in:
Kris Maglione 2017-10-06 15:09:11 -07:00
Родитель dafafd391d
Коммит 30d4691c07
2 изменённых файлов: 12 добавлений и 7 удалений

Просмотреть файл

@ -416,13 +416,18 @@ ScriptPreloader::InitCache(const nsAString& basePath)
return Ok(); return Ok();
} }
// Grab the compilation scope before initializing the URLPreloader, since
// it's not safe to run component loader code during its critical section.
AutoSafeJSAPI jsapi;
JS::RootedObject scope(jsapi.cx(), CompilationScope(jsapi.cx()));
// Note: Code on the main thread *must not access Omnijar in any way* until // Note: Code on the main thread *must not access Omnijar in any way* until
// this AutoBeginReading guard is destroyed. // this AutoBeginReading guard is destroyed.
URLPreloader::AutoBeginReading abr; URLPreloader::AutoBeginReading abr;
MOZ_TRY(OpenCache()); MOZ_TRY(OpenCache());
return InitCacheInternal(); return InitCacheInternal(scope);
} }
Result<Ok, nsresult> Result<Ok, nsresult>
@ -445,7 +450,7 @@ ScriptPreloader::InitCache(const Maybe<ipc::FileDescriptor>& cacheFile, ScriptCa
} }
Result<Ok, nsresult> Result<Ok, nsresult>
ScriptPreloader::InitCacheInternal() ScriptPreloader::InitCacheInternal(JS::HandleObject scope)
{ {
auto size = mCacheData.size(); auto size = mCacheData.size();
@ -520,7 +525,7 @@ ScriptPreloader::InitCacheInternal()
cleanup.release(); cleanup.release();
} }
DecodeNextBatch(OFF_THREAD_FIRST_CHUNK_SIZE); DecodeNextBatch(OFF_THREAD_FIRST_CHUNK_SIZE, scope);
return Ok(); return Ok();
} }
@ -955,7 +960,7 @@ ScriptPreloader::MaybeFinishOffThreadDecode()
} }
void void
ScriptPreloader::DecodeNextBatch(size_t chunkSize) ScriptPreloader::DecodeNextBatch(size_t chunkSize, JS::HandleObject scope)
{ {
MOZ_ASSERT(mParsingSources.length() == 0); MOZ_ASSERT(mParsingSources.length() == 0);
MOZ_ASSERT(mParsingScripts.length() == 0); MOZ_ASSERT(mParsingScripts.length() == 0);
@ -1003,7 +1008,7 @@ ScriptPreloader::DecodeNextBatch(size_t chunkSize)
AutoSafeJSAPI jsapi; AutoSafeJSAPI jsapi;
JSContext* cx = jsapi.cx(); JSContext* cx = jsapi.cx();
JSAutoCompartment ac(cx, CompilationScope(cx)); JSAutoCompartment ac(cx, scope ? scope : CompilationScope(cx));
JS::CompileOptions options(cx, JSVERSION_DEFAULT); JS::CompileOptions options(cx, JSVERSION_DEFAULT);
options.setNoScriptRval(true) options.setNoScriptRval(true)

Просмотреть файл

@ -97,7 +97,7 @@ public:
} }
private: private:
Result<Ok, nsresult> InitCacheInternal(); Result<Ok, nsresult> InitCacheInternal(JS::HandleObject scope = nullptr);
public: public:
void Trace(JSTracer* trc); void Trace(JSTracer* trc);
@ -388,7 +388,7 @@ private:
// decodes it synchronously on the main thread, as appropriate. // decodes it synchronously on the main thread, as appropriate.
JSScript* WaitForCachedScript(JSContext* cx, CachedScript* script); JSScript* WaitForCachedScript(JSContext* cx, CachedScript* script);
void DecodeNextBatch(size_t chunkSize); void DecodeNextBatch(size_t chunkSize, JS::HandleObject scope = nullptr);
static void OffThreadDecodeCallback(void* token, void* context); static void OffThreadDecodeCallback(void* token, void* context);
void MaybeFinishOffThreadDecode(); void MaybeFinishOffThreadDecode();