Bug 1459067 - Part 1: Allow storing BinASTSource in ScriptSource. (r=jorendorff)

--HG--
extra : rebase_source : 4a46ad0a57c3b6a79bd2783ab93a5f9218d58056
This commit is contained in:
Eric Faust 2018-10-02 01:16:51 -07:00
Родитель 92171122b5
Коммит 4c746e2845
7 изменённых файлов: 116 добавлений и 22 удалений

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

@ -676,6 +676,9 @@ frontend::CompileGlobalBinASTScript(JSContext* cx, LifoAlloc& alloc, const ReadO
return nullptr;
}
if (!sourceObj->source()->setBinASTSourceCopy(cx, src, len))
return nullptr;
RootedScript script(cx, JSScript::Create(cx, options, sourceObj, 0, len, 0, len));
if (!script) {

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

@ -4102,7 +4102,7 @@ JS_DecompileScript(JSContext* cx, HandleScript script)
if (fun) {
return JS_DecompileFunction(cx, fun);
}
bool haveSource = script->scriptSource()->hasSourceData();
bool haveSource = script->scriptSource()->hasSourceText();
if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) {
return nullptr;
}

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

@ -7800,11 +7800,11 @@ class DebuggerSourceGetTextMatcher
ReturnType match(HandleScriptSourceObject sourceObject) {
ScriptSource* ss = sourceObject->source();
bool hasSourceData = ss->hasSourceData();
if (!ss->hasSourceData() && !JSScript::loadSource(cx_, ss, &hasSourceData)) {
bool hasSourceText = ss->hasSourceText();
if (!ss->hasSourceText() && !JSScript::loadSource(cx_, ss, &hasSourceText)) {
return nullptr;
}
if (!hasSourceData) {
if (!hasSourceText) {
return NewStringCopyZ<CanGC>(cx_, "[no source]");
}

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

@ -1051,7 +1051,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource)
// that eval returns lambda, not function statement.
bool addParentheses = haveSource && isToSource && (fun->isLambda() && !fun->isArrow());
if (haveSource && !script->scriptSource()->hasSourceData() &&
if (haveSource && !script->scriptSource()->hasSourceText() &&
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
{
return nullptr;
@ -1783,7 +1783,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
// This is lazy canonical-function.
MOZ_ASSERT(lazy->scriptSource()->hasSourceData());
MOZ_ASSERT(lazy->scriptSource()->hasSourceText());
// Parse and compile the script from source.
size_t lazyLength = lazy->sourceEnd() - lazy->sourceStart();

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

@ -1543,7 +1543,7 @@ ScriptSourceObject::initElementProperties(JSContext* cx, HandleScriptSourceObjec
/* static */ bool
JSScript::loadSource(JSContext* cx, ScriptSource* ss, bool* worked)
{
MOZ_ASSERT(!ss->hasSourceData());
MOZ_ASSERT(!ss->hasSourceText());
*worked = false;
if (!cx->runtime()->sourceHook.ref() || !ss->sourceRetrievable()) {
return true;
@ -1567,14 +1567,14 @@ JSScript::loadSource(JSContext* cx, ScriptSource* ss, bool* worked)
/* static */ JSFlatString*
JSScript::sourceData(JSContext* cx, HandleScript script)
{
MOZ_ASSERT(script->scriptSource()->hasSourceData());
MOZ_ASSERT(script->scriptSource()->hasSourceText());
return script->scriptSource()->substring(cx, script->sourceStart(), script->sourceEnd());
}
bool
JSScript::appendSourceDataForToString(JSContext* cx, StringBuffer& buf)
{
MOZ_ASSERT(scriptSource()->hasSourceData());
MOZ_ASSERT(scriptSource()->hasSourceText());
return scriptSource()->appendSubstring(cx, buf, toStringStart(), toStringEnd());
}
@ -1936,6 +1936,45 @@ ScriptSource::setSource(JSContext* cx, UniqueTwoByteChars&& source, size_t lengt
return true;
}
#if defined(JS_BUILD_BINAST)
MOZ_MUST_USE bool
ScriptSource::setBinASTSourceCopy(JSContext* cx, const uint8_t* buf, size_t len)
{
auto &cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
auto deduped = cache.getOrCreate(reinterpret_cast<const char *>(buf), len);
if (!deduped) {
ReportOutOfMemory(cx);
return false;
}
MOZ_ASSERT(data.is<Missing>());
data = SourceType(BinAST(std::move(*deduped)));
return true;
}
MOZ_MUST_USE bool
ScriptSource::setBinASTSource(JSContext* cx, UniqueChars&& buf, size_t len)
{
auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
auto deduped = cache.getOrCreate(std::move(buf), len);
if (!deduped) {
ReportOutOfMemory(cx);
return false;
}
MOZ_ASSERT(data.is<Missing>());
data = SourceType(BinAST(std::move(*deduped)));
return true;
}
const uint8_t*
ScriptSource::binASTSource()
{
MOZ_ASSERT(hasBinASTSource());
return reinterpret_cast<const uint8_t*>(data.as<BinAST>().string.chars());
}
#endif /* JS_BUILD_BINAST */
void
ScriptSource::setSource(SharedImmutableTwoByteString&& string)
{
@ -2021,7 +2060,7 @@ ScriptSource::setCompressedSource(SharedImmutableString&& raw, size_t uncompress
bool
ScriptSource::setSourceCopy(JSContext* cx, SourceBufferHolder& srcBuf)
{
MOZ_ASSERT(!hasSourceData());
MOZ_ASSERT(!hasSourceText());
JSRuntime* runtime = cx->zone()->runtimeFromAnyThread();
auto& cache = runtime->sharedImmutableStrings();
@ -2239,6 +2278,10 @@ ScriptSource::performXDR(XDRState<mode>* xdr)
return c.raw.length();
}
size_t match(BinAST&) {
return 0;
}
size_t match(Missing&) {
MOZ_CRASH("Missing source data in ScriptSource::performXDR");
return 0;
@ -2255,20 +2298,27 @@ ScriptSource::performXDR(XDRState<mode>* xdr)
return (void*) c.raw.chars();
}
void* match(BinAST& b) {
return (void*) b.string.chars();
}
void* match(Missing&) {
MOZ_CRASH("Missing source data in ScriptSource::performXDR");
return nullptr;
}
};
uint8_t hasSource = hasSourceData();
uint8_t hasSource = hasSourceText();
MOZ_TRY(xdr->codeUint8(&hasSource));
uint8_t hasBinSource = hasBinASTSource();
MOZ_TRY(xdr->codeUint8(&hasBinSource));
uint8_t retrievable = sourceRetrievable_;
MOZ_TRY(xdr->codeUint8(&retrievable));
sourceRetrievable_ = retrievable;
if (hasSource && !sourceRetrievable_) {
if ((hasSource || hasBinSource) && !sourceRetrievable_) {
uint32_t len = 0;
if (mode == XDR_ENCODE) {
len = length();
@ -2282,7 +2332,7 @@ ScriptSource::performXDR(XDRState<mode>* xdr)
}
MOZ_TRY(xdr->codeUint32(&compressedLength));
size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
size_t byteLen = hasBinSource ? len : compressedLength ? compressedLength : (len * sizeof(char16_t));
if (mode == XDR_DECODE) {
auto bytes = xdr->cx()->template make_pod_array<char>(Max<size_t>(byteLen, 1));
if (!bytes) {
@ -2290,7 +2340,16 @@ ScriptSource::performXDR(XDRState<mode>* xdr)
}
MOZ_TRY(xdr->codeBytes(bytes.get(), byteLen));
if (compressedLength) {
if (hasBinSource) {
#if defined(JS_BUILD_BINAST)
if (!setBinASTSource(xdr->cx(), std::move(bytes), len)) {
return xdr->fail(JS::TranscodeResult_Throw);
}
#else
MOZ_ASSERT(mode != XDR_ENCODE);
return xdr->fail(JS::TranscodeResult_Throw);
#endif /* JS_BUILD_BINAST */
} else if (compressedLength) {
if (!setCompressedSource(xdr->cx(), std::move(bytes), byteLen, len)) {
return xdr->fail(JS::TranscodeResult_Throw);
}
@ -2367,7 +2426,7 @@ ScriptSource::performXDR(XDRState<mode>* xdr)
}
// Note the content of sources decoded when recording or replaying.
if (mode == XDR_DECODE && hasSourceData() && mozilla::recordreplay::IsRecordingOrReplaying()) {
if (mode == XDR_DECODE && hasSourceText() && mozilla::recordreplay::IsRecordingOrReplaying()) {
UncompressedSourceCache::AutoHoldEntry holder;
ScriptSource::PinnedChars chars(xdr->cx(), this, holder, 0, length());
if (!chars.get()) {

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

@ -430,7 +430,15 @@ class ScriptSource
{ }
};
using SourceType = mozilla::Variant<Missing, Uncompressed, Compressed>;
struct BinAST
{
SharedImmutableString string;
explicit BinAST(SharedImmutableString&& str)
: string(std::move(str))
{ }
};
using SourceType = mozilla::Variant<Missing, Uncompressed, Compressed, BinAST>;
SourceType data;
// If the GC attempts to call setCompressedSource with PinnedChars
@ -495,7 +503,7 @@ class ScriptSource
mozilla::TimeStamp parseEnded_;
// True if we can call JSRuntime::sourceHook to load the source on
// demand. If sourceRetrievable_ and hasSourceData() are false, it is not
// demand. If sourceRetrievable_ and hasSourceText() are false, it is not
// possible to get source at all.
bool sourceRetrievable_:1;
bool hasIntroductionOffset_:1;
@ -555,7 +563,8 @@ class ScriptSource
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>(); }
bool hasSourceText() const { return hasUncompressedSource() || hasCompressedSource(); }
bool hasBinASTSource() const { return data.is<BinAST>(); }
bool hasUncompressedSource() const { return data.is<Uncompressed>(); }
bool hasCompressedSource() const { return data.is<Compressed>(); }
@ -570,13 +579,17 @@ class ScriptSource
return c.uncompressedLength;
}
size_t match(const BinAST& b) {
return b.string.length();
}
size_t match(const Missing& m) {
MOZ_CRASH("ScriptSource::length on a missing source");
return 0;
}
};
MOZ_ASSERT(hasSourceData());
MOZ_ASSERT(hasSourceText() || hasBinASTSource());
return data.match(LengthMatcher());
}
@ -606,6 +619,25 @@ class ScriptSource
size_t sourceLength);
void setCompressedSource(SharedImmutableString&& raw, size_t sourceLength);
#if defined(JS_BUILD_BINAST)
/*
* Do not take ownership of the given `buf`. Store the canonical, shared
* and de-duplicated version. If there is no extant shared version of
* `buf`, make a copy.
*/
MOZ_MUST_USE bool setBinASTSourceCopy(JSContext* cx, const uint8_t* buf, size_t len);
/*
* Take ownership of the given `buf` and return the canonical, shared and
* de-duplicated version.
*/
MOZ_MUST_USE bool setBinASTSource(JSContext* cx, UniqueChars&& buf, size_t len);
const uint8_t* binASTSource();
#endif /* JS_BUILD_BINAST */
// XDR handling
template <XDRMode mode>
MOZ_MUST_USE XDRResult performXDR(XDRState<mode>* xdr);

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

@ -6682,7 +6682,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me
// Source discarding is allowed to affect JS semantics because it is never
// enabled for normal JS content.
bool haveSource = source->hasSourceData();
bool haveSource = source->hasSourceText();
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
return false;
}
@ -7618,7 +7618,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool isToSource)
return nullptr;
}
bool haveSource = source->hasSourceData();
bool haveSource = source->hasSourceText();
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
return nullptr;
}
@ -7669,7 +7669,7 @@ js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun)
return nullptr;
}
bool haveSource = source->hasSourceData();
bool haveSource = source->hasSourceText();
if (!haveSource && !JSScript::loadSource(cx, source, &haveSource)) {
return nullptr;
}