Backed out changeset e4590851081d (bug 1269451) for slowing down debug mochitests and causing frequent oranges as a result.

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2016-05-10 22:35:57 -04:00
Родитель 9978fb20b2
Коммит c3a556622b
3 изменённых файлов: 162 добавлений и 68 удалений

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

@ -1437,11 +1437,12 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
MOZ_ASSERT(lazy->scriptSource()->hasSourceData()); MOZ_ASSERT(lazy->scriptSource()->hasSourceData());
// Parse and compile the script from source. // Parse and compile the script from source.
auto text = lazy->scriptSource()->sourceText(cx); UncompressedSourceCache::AutoHoldEntry holder;
if (!text) const char16_t* chars = lazy->scriptSource()->chars(cx, holder);
if (!chars)
return false; return false;
const char16_t* lazyStart = text->chars() + lazy->begin(); const char16_t* lazyStart = chars + lazy->begin();
size_t lazyLength = lazy->end() - lazy->begin(); size_t lazyLength = lazy->end() - lazy->begin();
if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength)) { if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength)) {

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

@ -1812,19 +1812,73 @@ JSScript::sourceData(JSContext* cx)
return scriptSource()->substring(cx, sourceStart(), sourceEnd()); return scriptSource()->substring(cx, sourceStart(), sourceEnd());
} }
mozilla::Maybe<SharedImmutableTwoByteString> UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
UncompressedSourceCache::lookup(ScriptSource* ss) : cache_(nullptr), source_(nullptr)
{ {
}
void
UncompressedSourceCache::AutoHoldEntry::holdEntry(UncompressedSourceCache* cache, ScriptSource* source)
{
// Initialise the holder for a specific cache and script source. This will
// hold on to the cached source chars in the event that the cache is purged.
MOZ_ASSERT(!cache_ && !source_ && !charsToFree_);
cache_ = cache;
source_ = source;
}
void
UncompressedSourceCache::AutoHoldEntry::deferDelete(UniqueTwoByteChars chars)
{
// Take ownership of source chars now the cache is being purged. Remove our
// reference to the ScriptSource which might soon be destroyed.
MOZ_ASSERT(cache_ && source_ && !charsToFree_);
cache_ = nullptr;
source_ = nullptr;
charsToFree_ = Move(chars);
}
UncompressedSourceCache::AutoHoldEntry::~AutoHoldEntry()
{
if (cache_) {
MOZ_ASSERT(source_);
cache_->releaseEntry(*this);
}
}
void
UncompressedSourceCache::holdEntry(AutoHoldEntry& holder, ScriptSource* ss)
{
MOZ_ASSERT(!holder_);
holder.holdEntry(this, ss);
holder_ = &holder;
}
void
UncompressedSourceCache::releaseEntry(AutoHoldEntry& holder)
{
MOZ_ASSERT(holder_ == &holder);
holder_ = nullptr;
}
const char16_t*
UncompressedSourceCache::lookup(ScriptSource* ss, AutoHoldEntry& holder)
{
MOZ_ASSERT(!holder_);
if (!map_) if (!map_)
return mozilla::Nothing(); return nullptr;
if (Map::Ptr p = map_->lookup(ss)) if (Map::Ptr p = map_->lookup(ss)) {
return mozilla::Some(p->value().clone()); holdEntry(holder, ss);
return mozilla::Nothing(); return p->value().get();
}
return nullptr;
} }
bool bool
UncompressedSourceCache::put(ScriptSource* ss, SharedImmutableTwoByteString&& str) UncompressedSourceCache::put(ScriptSource* ss, UniqueTwoByteChars str, AutoHoldEntry& holder)
{ {
MOZ_ASSERT(!holder_);
if (!map_) { if (!map_) {
UniquePtr<Map> map = MakeUnique<Map>(); UniquePtr<Map> map = MakeUnique<Map>();
if (!map || !map->init()) if (!map || !map->init())
@ -1833,7 +1887,11 @@ UncompressedSourceCache::put(ScriptSource* ss, SharedImmutableTwoByteString&& st
map_ = Move(map); map_ = Move(map);
} }
return map_->put(ss, Move(str)); if (!map_->put(ss, Move(str)))
return false;
holdEntry(holder, ss);
return true;
} }
void void
@ -1842,6 +1900,13 @@ UncompressedSourceCache::purge()
if (!map_) if (!map_)
return; return;
for (Map::Range r = map_->all(); !r.empty(); r.popFront()) {
if (holder_ && r.front().key() == holder_->source()) {
holder_->deferDelete(Move(r.front().value()));
holder_ = nullptr;
}
}
map_.reset(); map_.reset();
} }
@ -1849,39 +1914,45 @@ size_t
UncompressedSourceCache::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) UncompressedSourceCache::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
{ {
size_t n = 0; size_t n = 0;
if (map_ && !map_->empty()) if (map_ && !map_->empty()) {
n += map_->sizeOfIncludingThis(mallocSizeOf); n += map_->sizeOfIncludingThis(mallocSizeOf);
for (Map::Range r = map_->all(); !r.empty(); r.popFront())
n += mallocSizeOf(r.front().value().get());
}
return n; return n;
} }
mozilla::Maybe<SharedImmutableTwoByteString> const char16_t*
ScriptSource::sourceText(JSContext* cx) ScriptSource::chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& holder)
{ {
struct SourceTextMatcher struct CharsMatcher
{ {
using ReturnType = mozilla::Maybe<SharedImmutableTwoByteString>; using ReturnType = const char16_t*;
JSContext* cx; JSContext* cx;
ScriptSource& ss; ScriptSource& ss;
UncompressedSourceCache::AutoHoldEntry& holder;
explicit SourceTextMatcher(JSContext* cx, ScriptSource& ss) explicit CharsMatcher(JSContext* cx, ScriptSource& ss,
UncompressedSourceCache::AutoHoldEntry& holder)
: cx(cx) : cx(cx)
, ss(ss) , ss(ss)
, holder(holder)
{ } { }
ReturnType match(Uncompressed& u) { ReturnType match(Uncompressed& u) {
return mozilla::Some(u.string.clone()); return u.string.chars();
} }
ReturnType match(Compressed& c) { ReturnType match(Compressed& c) {
if (auto decompressed = cx->runtime()->uncompressedSourceCache.lookup(&ss)) if (const char16_t* decompressed = cx->runtime()->uncompressedSourceCache.lookup(&ss, holder))
return mozilla::Some(mozilla::Move(*decompressed)); return decompressed;
const size_t lengthWithNull = ss.length() + 1; const size_t lengthWithNull = ss.length() + 1;
UniqueTwoByteChars decompressed(js_pod_malloc<char16_t>(lengthWithNull)); UniqueTwoByteChars decompressed(js_pod_malloc<char16_t>(lengthWithNull));
if (!decompressed) { if (!decompressed) {
ReportOutOfMemory(cx); JS_ReportOutOfMemory(cx);
return mozilla::Nothing(); return nullptr;
} }
if (!DecompressString((const unsigned char*) ss.compressedData(), if (!DecompressString((const unsigned char*) ss.compressedData(),
@ -1889,44 +1960,43 @@ ScriptSource::sourceText(JSContext* cx)
reinterpret_cast<unsigned char*>(decompressed.get()), reinterpret_cast<unsigned char*>(decompressed.get()),
lengthWithNull * sizeof(char16_t))) lengthWithNull * sizeof(char16_t)))
{ {
ReportOutOfMemory(cx); JS_ReportOutOfMemory(cx);
return mozilla::Nothing(); return nullptr;
} }
decompressed[ss.length()] = 0; decompressed[ss.length()] = 0;
auto& strings = cx->runtime()->sharedImmutableStrings();
auto deduped = strings.getOrCreate(mozilla::Move(decompressed), ss.length());
if (!deduped) {
ReportOutOfMemory(cx);
return mozilla::Nothing();
}
// Decompressing a huge script is expensive. With lazy parsing and // Decompressing a huge script is expensive. With lazy parsing and
// relazification, this can happen repeatedly, so conservatively go // relazification, this can happen repeatedly, so conservatively go
// back to storing the data uncompressed to avoid wasting too much // back to storing the data uncompressed to avoid wasting too much
// time yo-yoing back and forth between compressed and uncompressed. // time yo-yoing back and forth between compressed and uncompressed.
const size_t HUGE_SCRIPT = 5 * 1024 * 1024; const size_t HUGE_SCRIPT = 5 * 1024 * 1024;
if (lengthWithNull > HUGE_SCRIPT) { if (lengthWithNull > HUGE_SCRIPT) {
ss.data = SourceType(Uncompressed(deduped->clone())); auto& strings = cx->runtime()->sharedImmutableStrings();
return mozilla::Some(mozilla::Move(*deduped)); auto str = strings.getOrCreate(mozilla::Move(decompressed), ss.length());
if (!str) {
JS_ReportOutOfMemory(cx);
return nullptr;
}
ss.data = SourceType(Uncompressed(mozilla::Move(*str)));
return ss.uncompressedChars();
} }
if (!cx->runtime()->uncompressedSourceCache.put(&ss, deduped->clone())) { ReturnType ret = decompressed.get();
ReportOutOfMemory(cx); if (!cx->runtime()->uncompressedSourceCache.put(&ss, Move(decompressed), holder)) {
return mozilla::Nothing(); JS_ReportOutOfMemory(cx);
return nullptr;
} }
return ret;
return mozilla::Some(mozilla::Move(*deduped));
} }
ReturnType match(Missing&) { ReturnType match(Missing&) {
MOZ_CRASH("ScriptSource::sourceText() on ScriptSource with SourceType = Missing"); MOZ_CRASH("ScriptSource::chars() on ScriptSource with SourceType = Missing");
return mozilla::Nothing(); return nullptr;
} }
}; };
SourceTextMatcher cm(cx, *this); CharsMatcher cm(cx, *this, holder);
return data.match(cm); return data.match(cm);
} }
@ -1934,20 +2004,22 @@ JSFlatString*
ScriptSource::substring(JSContext* cx, uint32_t start, uint32_t stop) ScriptSource::substring(JSContext* cx, uint32_t start, uint32_t stop)
{ {
MOZ_ASSERT(start <= stop); MOZ_ASSERT(start <= stop);
auto text = sourceText(cx); UncompressedSourceCache::AutoHoldEntry holder;
if (!text) const char16_t* chars = this->chars(cx, holder);
if (!chars)
return nullptr; return nullptr;
return NewStringCopyN<CanGC>(cx, text->chars() + start, stop - start); return NewStringCopyN<CanGC>(cx, chars + start, stop - start);
} }
JSFlatString* JSFlatString*
ScriptSource::substringDontDeflate(JSContext* cx, uint32_t start, uint32_t stop) ScriptSource::substringDontDeflate(JSContext* cx, uint32_t start, uint32_t stop)
{ {
MOZ_ASSERT(start <= stop); MOZ_ASSERT(start <= stop);
auto text = sourceText(cx); UncompressedSourceCache::AutoHoldEntry holder;
if (!text) const char16_t* chars = this->chars(cx, holder);
if (!chars)
return nullptr; return nullptr;
return NewStringCopyNDontDeflate<CanGC>(cx, text->chars() + start, stop - start); return NewStringCopyNDontDeflate<CanGC>(cx, chars + start, stop - start);
} }
MOZ_MUST_USE bool MOZ_MUST_USE bool
@ -4396,17 +4468,19 @@ LazyScriptHashPolicy::match(JSScript* script, const Lookup& lookup)
return false; return false;
} }
auto scriptText = script->scriptSource()->sourceText(cx); UncompressedSourceCache::AutoHoldEntry holder;
if (!scriptText)
const char16_t* scriptChars = script->scriptSource()->chars(cx, holder);
if (!scriptChars)
return false; return false;
auto lazyText = lazy->scriptSource()->sourceText(cx); const char16_t* lazyChars = lazy->scriptSource()->chars(cx, holder);
if (!lazyText) if (!lazyChars)
return false; return false;
size_t begin = script->sourceStart(); size_t begin = script->sourceStart();
size_t length = script->sourceEnd() - begin; size_t length = script->sourceEnd() - begin;
return !memcmp(scriptText->chars() + begin, lazyText->chars() + begin, length); return !memcmp(scriptChars + begin, lazyChars + begin, length);
} }
void void

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

@ -10,8 +10,6 @@
#define jsscript_h #define jsscript_h
#include "mozilla/Atomics.h" #include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h" #include "mozilla/PodOperations.h"
#include "mozilla/Variant.h" #include "mozilla/Variant.h"
@ -578,20 +576,45 @@ class ScriptSource;
class UncompressedSourceCache class UncompressedSourceCache
{ {
using Map = HashMap<ScriptSource*, typedef HashMap<ScriptSource*,
SharedImmutableTwoByteString, UniqueTwoByteChars,
DefaultHasher<ScriptSource*>, DefaultHasher<ScriptSource*>,
SystemAllocPolicy>; SystemAllocPolicy> Map;
UniquePtr<Map> map_;
public: public:
UncompressedSourceCache() { } // Hold an entry in the source data cache and prevent it from being purged on GC.
class AutoHoldEntry
{
UncompressedSourceCache* cache_;
ScriptSource* source_;
UniqueTwoByteChars charsToFree_;
public:
explicit AutoHoldEntry();
~AutoHoldEntry();
private:
void holdEntry(UncompressedSourceCache* cache, ScriptSource* source);
void deferDelete(UniqueTwoByteChars chars);
ScriptSource* source() const { return source_; }
friend class UncompressedSourceCache;
};
private:
UniquePtr<Map> map_;
AutoHoldEntry* holder_;
public:
UncompressedSourceCache() : holder_(nullptr) {}
const char16_t* lookup(ScriptSource* ss, AutoHoldEntry& asp);
bool put(ScriptSource* ss, UniqueTwoByteChars chars, AutoHoldEntry& asp);
MOZ_MUST_USE mozilla::Maybe<SharedImmutableTwoByteString> lookup(ScriptSource* ss);
bool put(ScriptSource* ss, SharedImmutableTwoByteString&& chars);
void purge(); void purge();
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
private:
void holdEntry(AutoHoldEntry& holder, ScriptSource* ss);
void releaseEntry(AutoHoldEntry& holder);
}; };
class ScriptSource class ScriptSource
@ -741,11 +764,7 @@ class ScriptSource
MOZ_ASSERT(hasSourceData()); MOZ_ASSERT(hasSourceData());
return argumentsNotIncluded_; return argumentsNotIncluded_;
} }
const char16_t* chars(JSContext* cx, UncompressedSourceCache::AutoHoldEntry& asp);
// Get a handle on the underlying source text. Returns mozilla::Nothing on
// OOM failure.
MOZ_MUST_USE mozilla::Maybe<SharedImmutableTwoByteString> sourceText(JSContext* cx);
JSFlatString* substring(JSContext* cx, uint32_t start, uint32_t stop); JSFlatString* substring(JSContext* cx, uint32_t start, uint32_t stop);
JSFlatString* substringDontDeflate(JSContext* cx, uint32_t start, uint32_t stop); JSFlatString* substringDontDeflate(JSContext* cx, uint32_t start, uint32_t stop);
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,