Bug 1348134 - Stop eagerly compressing ScriptSources. (r=jonco)

This commit is contained in:
Shu-yu Guo 2017-04-12 14:13:20 -07:00
Родитель 1196244596
Коммит 8f1a38f1dd
9 изменённых файлов: 8 добавлений и 122 удалений

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

@ -43,9 +43,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
SourceBufferHolder& sourceBuffer,
HandleScope enclosingScope);
// Call setters for optional arguments.
void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor);
JSScript* compileGlobalScript(ScopeKind scopeKind);
JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
ModuleObject* compileModule();
@ -59,7 +56,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
JSScript* compileScript(HandleObject environment, SharedContext* sc);
bool checkLength();
bool createScriptSource(const Maybe<uint32_t>& parameterListEnd);
bool maybeCompressSource();
bool canLazilyParse();
bool createParser();
bool createSourceAndParser(const Maybe<uint32_t>& parameterListEnd = Nothing());
@ -67,7 +63,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
bool handleParseFailure(const Directives& newDirectives);
bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment);
bool maybeCompleteCompressSource();
AutoKeepAtoms keepAtoms;
@ -81,9 +76,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
RootedScriptSource sourceObject;
ScriptSource* scriptSource;
Maybe<SourceCompressionTask> maybeSourceCompressor;
SourceCompressionTask* sourceCompressor;
Maybe<UsedNameTracker> usedNames;
Maybe<Parser<SyntaxParseHandler>> syntaxParser;
Maybe<Parser<FullParseHandler>> parser;
@ -172,7 +164,6 @@ BytecodeCompiler::BytecodeCompiler(JSContext* cx,
enclosingScope(cx, enclosingScope),
sourceObject(cx),
scriptSource(nullptr),
sourceCompressor(nullptr),
directives(options.strictOption),
startPosition(keepAtoms),
script(cx)
@ -180,12 +171,6 @@ BytecodeCompiler::BytecodeCompiler(JSContext* cx,
MOZ_ASSERT(sourceBuffer.get());
}
void
BytecodeCompiler::maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor)
{
this->sourceCompressor = sourceCompressor;
}
bool
BytecodeCompiler::checkLength()
{
@ -212,23 +197,12 @@ BytecodeCompiler::createScriptSource(const Maybe<uint32_t>& parameterListEnd)
return false;
scriptSource = sourceObject->source();
return true;
}
bool
BytecodeCompiler::maybeCompressSource()
{
if (!sourceCompressor) {
maybeSourceCompressor.emplace(cx);
sourceCompressor = maybeSourceCompressor.ptr();
}
if (!cx->compartment()->behaviors().discardSource()) {
if (options.sourceIsLazy) {
if (options.sourceIsLazy)
scriptSource->setSourceRetrievable();
} else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceCompressor)) {
else if (!scriptSource->setSourceCopy(cx, sourceBuffer))
return false;
}
}
return true;
@ -263,7 +237,6 @@ BytecodeCompiler::createParser()
parser.emplace(cx, alloc, options, sourceBuffer.get(), sourceBuffer.length(),
/* foldConstants = */ true, *usedNames, syntaxParser.ptrOr(nullptr), nullptr);
parser->sct = sourceCompressor;
parser->ss = scriptSource;
if (!parser->checkOptions())
return false;
@ -276,7 +249,6 @@ bool
BytecodeCompiler::createSourceAndParser(const Maybe<uint32_t>& parameterListEnd /* = Nothing() */)
{
return createScriptSource(parameterListEnd) &&
maybeCompressSource() &&
createParser();
}
@ -341,12 +313,6 @@ BytecodeCompiler::deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObj
return true;
}
bool
BytecodeCompiler::maybeCompleteCompressSource()
{
return !maybeSourceCompressor || maybeSourceCompressor->complete();
}
JSScript*
BytecodeCompiler::compileScript(HandleObject environment, SharedContext* sc)
{
@ -394,9 +360,6 @@ BytecodeCompiler::compileScript(HandleObject environment, SharedContext* sc)
usedNames->reset();
}
if (!maybeCompleteCompressSource())
return nullptr;
// We have just finished parsing the source. Inform the source so that we
// can compute statistics (e.g. how much time our functions remain lazy).
script->scriptSource()->recordParseEnded();
@ -462,9 +425,6 @@ BytecodeCompiler::compileModule()
module->setInitialEnvironment(env);
if (!maybeCompleteCompressSource())
return nullptr;
MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
return module;
}
@ -517,9 +477,6 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
if (!NameFunctions(cx, fn))
return false;
if (!maybeCompleteCompressSource())
return false;
return true;
}
@ -597,13 +554,11 @@ JSScript*
frontend::CompileGlobalScript(JSContext* cx, LifoAlloc& alloc, ScopeKind scopeKind,
const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf,
SourceCompressionTask* extraSct,
ScriptSourceObject** sourceObjectOut)
{
MOZ_ASSERT(scopeKind == ScopeKind::Global || scopeKind == ScopeKind::NonSyntactic);
BytecodeCompiler compiler(cx, alloc, options, srcBuf, /* enclosingScope = */ nullptr);
AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
compiler.maybeSetSourceCompressor(extraSct);
return compiler.compileGlobalScript(scopeKind);
}
@ -612,12 +567,10 @@ frontend::CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
HandleObject environment, HandleScope enclosingScope,
const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf,
SourceCompressionTask* extraSct,
ScriptSourceObject** sourceObjectOut)
{
BytecodeCompiler compiler(cx, alloc, options, srcBuf, enclosingScope);
AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
compiler.maybeSetSourceCompressor(extraSct);
return compiler.compileEvalScript(environment, enclosingScope);
}

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

@ -23,7 +23,6 @@ class LazyScript;
class LifoAlloc;
class ModuleObject;
class ScriptSourceObject;
struct SourceCompressionTask;
namespace frontend {
@ -35,7 +34,6 @@ JSScript*
CompileGlobalScript(JSContext* cx, LifoAlloc& alloc, ScopeKind scopeKind,
const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf,
SourceCompressionTask* extraSct = nullptr,
ScriptSourceObject** sourceObjectOut = nullptr);
JSScript*
@ -43,7 +41,6 @@ CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
HandleObject scopeChain, HandleScope enclosingScope,
const ReadOnlyCompileOptions& options,
SourceBufferHolder& srcBuf,
SourceCompressionTask* extraSct = nullptr,
ScriptSourceObject** sourceObjectOut = nullptr);
ModuleObject*

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

@ -782,7 +782,6 @@ ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc,
traceListHead(nullptr),
pc(nullptr),
usedNames(usedNames),
sct(nullptr),
ss(nullptr),
keepAtoms(cx),
foldConstants(foldConstants),
@ -9169,7 +9168,7 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::stringLiteral()
{
return handler.newStringLiteral(stopStringCompression(), pos());
return handler.newStringLiteral(tokenStream.currentToken().atom(), pos());
}
template <typename ParseHandler>
@ -9181,7 +9180,7 @@ Parser<ParseHandler>::noSubstitutionTaggedTemplate()
return handler.newRawUndefinedLiteral(pos());
}
return handler.newTemplateStringLiteral(stopStringCompression(), pos());
return handler.newTemplateStringLiteral(tokenStream.currentToken().atom(), pos());
}
template <typename ParseHandler>
@ -9191,20 +9190,7 @@ Parser<ParseHandler>::noSubstitutionUntaggedTemplate()
if (!tokenStream.checkForInvalidTemplateEscapeError())
return null();
return handler.newTemplateStringLiteral(stopStringCompression(), pos());
}
template <typename ParseHandler>
JSAtom * Parser<ParseHandler>::stopStringCompression() {
JSAtom* atom = tokenStream.currentToken().atom();
// Large strings are fast to parse but slow to compress. Stop compression on
// them, so we don't wait for a long time for compression to finish at the
// end of compilation.
const size_t HUGE_STRING = 50000;
if (sct && sct->active() && atom->length() >= HUGE_STRING)
sct->abort();
return atom;
return handler.newTemplateStringLiteral(tokenStream.currentToken().atom(), pos());
}
template <typename ParseHandler>

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

@ -770,9 +770,6 @@ class ParserBase : public StrictModeGetter
// For tracking used names in this parsing session.
UsedNameTracker& usedNames;
/* Compression token for aborting. */
SourceCompressionTask* sct;
ScriptSource* ss;
/* Root atoms and objects allocated for the parsed tree. */
@ -1087,8 +1084,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
private:
Parser* thisForCtor() { return this; }
JSAtom* stopStringCompression();
Node stringLiteral();
Node noSubstitutionTaggedTemplate();
Node noSubstitutionUntaggedTemplate();

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

@ -4589,9 +4589,8 @@ Evaluate(JSContext* cx, ScopeKind scopeKind, HandleObject env,
MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(env), scopeKind == ScopeKind::NonSyntactic);
options.setIsRunOnce(true);
SourceCompressionTask sct(cx);
RootedScript script(cx, frontend::CompileGlobalScript(cx, cx->tempLifoAlloc(),
scopeKind, options, srcBuf, &sct));
scopeKind, options, srcBuf));
if (!script)
return false;
@ -4599,8 +4598,6 @@ Evaluate(JSContext* cx, ScopeKind scopeKind, HandleObject env,
bool result = Execute(cx, script, *env,
options.noScriptRval ? nullptr : rval.address());
if (!sct.complete())
result = false;
// After evaluation, the compiled script will not be run again.
// script->ensureRanAnalysis allocated 1 analyze::Bytecode for every opcode

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

@ -1789,8 +1789,7 @@ ScriptSource::setCompressedSource(SharedImmutableString&& raw, size_t uncompress
}
bool
ScriptSource::setSourceCopy(JSContext* cx, SourceBufferHolder& srcBuf,
SourceCompressionTask* task)
ScriptSource::setSourceCopy(JSContext* cx, SourceBufferHolder& srcBuf)
{
MOZ_ASSERT(!hasSourceData());
@ -1806,35 +1805,6 @@ ScriptSource::setSourceCopy(JSContext* cx, SourceBufferHolder& srcBuf,
}
setSource(mozilla::Move(*deduped));
// There are several cases where source compression is not a good idea:
// - If the script is tiny, then compression will save little or no space.
// - If there is only one core, then compression will contend with JS
// execution (which hurts benchmarketing).
// - If the source contains a giant string, then parsing will finish much
// faster than compression which increases latency (this case is handled
// in Parser::stringLiteral).
//
// Lastly, since the parsing thread will eventually perform a blocking wait
// on the compression task's thread, require that there are at least 2
// helper threads:
// - If we are on a helper thread, there must be another helper thread to
// execute our compression task.
// - If we are on the active thread, there must be at least two helper
// threads since at most one helper thread can be blocking on the active
// thread (see HelperThreadState::canStartParseTask) which would cause a
// deadlock if there wasn't a second helper thread that could make
// progress on our compression task.
bool canCompressOffThread =
HelperThreadState().cpuCount > 1 &&
HelperThreadState().threadCount >= 2 &&
CanUseExtraThreads();
const size_t TINY_SCRIPT = 256;
if (TINY_SCRIPT <= srcBuf.length() && canCompressOffThread) {
task->ss = this;
if (!StartOffThreadCompression(cx, task))
return false;
}
return true;
}
@ -1874,9 +1844,6 @@ SourceCompressionTask::work()
bool cont = true;
bool reallocated = false;
while (cont) {
if (abort_)
return Aborted;
switch (comp.compressMore()) {
case Compressor::CONTINUE:
break;

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

@ -485,9 +485,7 @@ class ScriptSource
MOZ_MUST_USE bool initFromOptions(JSContext* cx,
const ReadOnlyCompileOptions& options,
const mozilla::Maybe<uint32_t>& parameterListEnd = mozilla::Nothing());
MOZ_MUST_USE bool setSourceCopy(JSContext* cx,
JS::SourceBufferHolder& srcBuf,
SourceCompressionTask* tok);
MOZ_MUST_USE bool setSourceCopy(JSContext* cx, JS::SourceBufferHolder& srcBuf);
void setSourceRetrievable() { sourceRetrievable_ = true; }
bool sourceRetrievable() const { return sourceRetrievable_; }
bool hasSourceData() const { return !data.is<Missing>(); }

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

@ -380,7 +380,6 @@ ScriptParseTask::parse(JSContext* cx)
SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership);
script = frontend::CompileGlobalScript(cx, alloc, ScopeKind::Global,
options, srcBuf,
/* extraSct = */ nullptr,
/* sourceObjectOut = */ &sourceObject);
}

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

@ -674,10 +674,6 @@ struct SourceCompressionTask
ScriptSource* ss;
// Atomic flag to indicate to a helper thread that it should abort
// compression on the source.
mozilla::Atomic<bool, mozilla::Relaxed> abort_;
// Stores the result of the compression.
enum ResultType {
OOM,
@ -692,7 +688,6 @@ struct SourceCompressionTask
: helperThread(nullptr)
, cx(cx)
, ss(nullptr)
, abort_(false)
, result(OOM)
{}
@ -703,7 +698,6 @@ struct SourceCompressionTask
ResultType work();
bool complete();
void abort() { abort_ = true; }
bool active() const { return !!ss; }
ScriptSource* source() { return ss; }
};