зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1020012 - Consolidate ScriptSources with the same source, r=luke.
This commit is contained in:
Родитель
1ad1ef7739
Коммит
3ba0ec8938
|
@ -351,7 +351,8 @@ struct RuntimeSizes
|
||||||
macro(_, _, temporary) \
|
macro(_, _, temporary) \
|
||||||
macro(_, _, interpreterStack) \
|
macro(_, _, interpreterStack) \
|
||||||
macro(_, _, mathCache) \
|
macro(_, _, mathCache) \
|
||||||
macro(_, _, sourceDataCache) \
|
macro(_, _, uncompressedSourceCache) \
|
||||||
|
macro(_, _, compressedSourceSet) \
|
||||||
macro(_, _, scriptData) \
|
macro(_, _, scriptData) \
|
||||||
|
|
||||||
RuntimeSizes()
|
RuntimeSizes()
|
||||||
|
|
|
@ -1285,7 +1285,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
|
||||||
JS_ASSERT(lazy->source()->hasSourceData());
|
JS_ASSERT(lazy->source()->hasSourceData());
|
||||||
|
|
||||||
// Parse and compile the script from source.
|
// Parse and compile the script from source.
|
||||||
SourceDataCache::AutoHoldEntry holder;
|
UncompressedSourceCache::AutoHoldEntry holder;
|
||||||
const jschar *chars = lazy->source()->chars(cx, holder);
|
const jschar *chars = lazy->source()->chars(cx, holder);
|
||||||
if (!chars)
|
if (!chars)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -2949,7 +2949,7 @@ PurgeRuntime(JSRuntime *rt)
|
||||||
rt->scopeCoordinateNameCache.purge();
|
rt->scopeCoordinateNameCache.purge();
|
||||||
rt->newObjectCache.purge();
|
rt->newObjectCache.purge();
|
||||||
rt->nativeIterCache.purge();
|
rt->nativeIterCache.purge();
|
||||||
rt->sourceDataCache.purge();
|
rt->uncompressedSourceCache.purge();
|
||||||
rt->evalCache.clear();
|
rt->evalCache.clear();
|
||||||
|
|
||||||
if (!rt->hasActiveCompilations())
|
if (!rt->hasActiveCompilations())
|
||||||
|
|
|
@ -1369,13 +1369,13 @@ JSScript::sourceData(JSContext *cx)
|
||||||
return scriptSource()->substring(cx, sourceStart(), sourceEnd());
|
return scriptSource()->substring(cx, sourceStart(), sourceEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceDataCache::AutoHoldEntry::AutoHoldEntry()
|
UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry()
|
||||||
: cache_(nullptr), source_(nullptr), charsToFree_(nullptr)
|
: cache_(nullptr), source_(nullptr), charsToFree_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SourceDataCache::AutoHoldEntry::holdEntry(SourceDataCache *cache, ScriptSource *source)
|
UncompressedSourceCache::AutoHoldEntry::holdEntry(UncompressedSourceCache *cache, ScriptSource *source)
|
||||||
{
|
{
|
||||||
// Initialise the holder for a specific cache and script source. This will
|
// 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.
|
// hold on to the cached source chars in the event that the cache is purged.
|
||||||
|
@ -1385,7 +1385,7 @@ SourceDataCache::AutoHoldEntry::holdEntry(SourceDataCache *cache, ScriptSource *
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SourceDataCache::AutoHoldEntry::deferDelete(const jschar *chars)
|
UncompressedSourceCache::AutoHoldEntry::deferDelete(const jschar *chars)
|
||||||
{
|
{
|
||||||
// Take ownership of source chars now the cache is being purged. Remove our
|
// Take ownership of source chars now the cache is being purged. Remove our
|
||||||
// reference to the ScriptSource which might soon be destroyed.
|
// reference to the ScriptSource which might soon be destroyed.
|
||||||
|
@ -1395,7 +1395,7 @@ SourceDataCache::AutoHoldEntry::deferDelete(const jschar *chars)
|
||||||
charsToFree_ = chars;
|
charsToFree_ = chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceDataCache::AutoHoldEntry::~AutoHoldEntry()
|
UncompressedSourceCache::AutoHoldEntry::~AutoHoldEntry()
|
||||||
{
|
{
|
||||||
// The holder is going out of scope. If it has taken ownership of cached
|
// The holder is going out of scope. If it has taken ownership of cached
|
||||||
// chars then delete them, otherwise unregister ourself with the cache.
|
// chars then delete them, otherwise unregister ourself with the cache.
|
||||||
|
@ -1409,7 +1409,7 @@ SourceDataCache::AutoHoldEntry::~AutoHoldEntry()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SourceDataCache::holdEntry(AutoHoldEntry &holder, ScriptSource *ss)
|
UncompressedSourceCache::holdEntry(AutoHoldEntry &holder, ScriptSource *ss)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!holder_);
|
JS_ASSERT(!holder_);
|
||||||
holder.holdEntry(this, ss);
|
holder.holdEntry(this, ss);
|
||||||
|
@ -1417,14 +1417,14 @@ SourceDataCache::holdEntry(AutoHoldEntry &holder, ScriptSource *ss)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SourceDataCache::releaseEntry(AutoHoldEntry &holder)
|
UncompressedSourceCache::releaseEntry(AutoHoldEntry &holder)
|
||||||
{
|
{
|
||||||
JS_ASSERT(holder_ == &holder);
|
JS_ASSERT(holder_ == &holder);
|
||||||
holder_ = nullptr;
|
holder_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const jschar *
|
const jschar *
|
||||||
SourceDataCache::lookup(ScriptSource *ss, AutoHoldEntry &holder)
|
UncompressedSourceCache::lookup(ScriptSource *ss, AutoHoldEntry &holder)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!holder_);
|
JS_ASSERT(!holder_);
|
||||||
if (!map_)
|
if (!map_)
|
||||||
|
@ -1437,7 +1437,7 @@ SourceDataCache::lookup(ScriptSource *ss, AutoHoldEntry &holder)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SourceDataCache::put(ScriptSource *ss, const jschar *str, AutoHoldEntry &holder)
|
UncompressedSourceCache::put(ScriptSource *ss, const jschar *str, AutoHoldEntry &holder)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!holder_);
|
JS_ASSERT(!holder_);
|
||||||
|
|
||||||
|
@ -1461,7 +1461,7 @@ SourceDataCache::put(ScriptSource *ss, const jschar *str, AutoHoldEntry &holder)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SourceDataCache::purge()
|
UncompressedSourceCache::purge()
|
||||||
{
|
{
|
||||||
if (!map_)
|
if (!map_)
|
||||||
return;
|
return;
|
||||||
|
@ -1481,7 +1481,7 @@ SourceDataCache::purge()
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
SourceDataCache::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()) {
|
||||||
|
@ -1495,7 +1495,7 @@ SourceDataCache::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||||
}
|
}
|
||||||
|
|
||||||
const jschar *
|
const jschar *
|
||||||
ScriptSource::chars(JSContext *cx, SourceDataCache::AutoHoldEntry &holder)
|
ScriptSource::chars(JSContext *cx, UncompressedSourceCache::AutoHoldEntry &holder)
|
||||||
{
|
{
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
case DataUncompressed:
|
case DataUncompressed:
|
||||||
|
@ -1503,7 +1503,7 @@ ScriptSource::chars(JSContext *cx, SourceDataCache::AutoHoldEntry &holder)
|
||||||
|
|
||||||
case DataCompressed: {
|
case DataCompressed: {
|
||||||
#ifdef USE_ZLIB
|
#ifdef USE_ZLIB
|
||||||
if (const jschar *decompressed = cx->runtime()->sourceDataCache.lookup(this, holder))
|
if (const jschar *decompressed = cx->runtime()->uncompressedSourceCache.lookup(this, holder))
|
||||||
return decompressed;
|
return decompressed;
|
||||||
|
|
||||||
const size_t nbytes = sizeof(jschar) * (length_ + 1);
|
const size_t nbytes = sizeof(jschar) * (length_ + 1);
|
||||||
|
@ -1520,7 +1520,7 @@ ScriptSource::chars(JSContext *cx, SourceDataCache::AutoHoldEntry &holder)
|
||||||
|
|
||||||
decompressed[length_] = 0;
|
decompressed[length_] = 0;
|
||||||
|
|
||||||
if (!cx->runtime()->sourceDataCache.put(this, decompressed, holder)) {
|
if (!cx->runtime()->uncompressedSourceCache.put(this, decompressed, holder)) {
|
||||||
JS_ReportOutOfMemory(cx);
|
JS_ReportOutOfMemory(cx);
|
||||||
js_free(decompressed);
|
js_free(decompressed);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -1532,6 +1532,9 @@ ScriptSource::chars(JSContext *cx, SourceDataCache::AutoHoldEntry &holder)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DataParent:
|
||||||
|
return parent()->chars(cx, holder);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
MOZ_CRASH();
|
MOZ_CRASH();
|
||||||
}
|
}
|
||||||
|
@ -1541,7 +1544,7 @@ JSFlatString *
|
||||||
ScriptSource::substring(JSContext *cx, uint32_t start, uint32_t stop)
|
ScriptSource::substring(JSContext *cx, uint32_t start, uint32_t stop)
|
||||||
{
|
{
|
||||||
JS_ASSERT(start <= stop);
|
JS_ASSERT(start <= stop);
|
||||||
SourceDataCache::AutoHoldEntry holder;
|
UncompressedSourceCache::AutoHoldEntry holder;
|
||||||
const jschar *chars = this->chars(cx, holder);
|
const jschar *chars = this->chars(cx, holder);
|
||||||
if (!chars)
|
if (!chars)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -1561,7 +1564,7 @@ ScriptSource::setSource(const jschar *chars, size_t length, bool ownsChars /* =
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ScriptSource::setCompressedSource(void *raw, size_t nbytes)
|
ScriptSource::setCompressedSource(JSRuntime *maybert, void *raw, size_t nbytes, HashNumber hash)
|
||||||
{
|
{
|
||||||
JS_ASSERT(dataType == DataMissing || dataType == DataUncompressed);
|
JS_ASSERT(dataType == DataMissing || dataType == DataUncompressed);
|
||||||
if (dataType == DataUncompressed && ownsUncompressedChars())
|
if (dataType == DataUncompressed && ownsUncompressedChars())
|
||||||
|
@ -1570,6 +1573,33 @@ ScriptSource::setCompressedSource(void *raw, size_t nbytes)
|
||||||
dataType = DataCompressed;
|
dataType = DataCompressed;
|
||||||
data.compressed.raw = raw;
|
data.compressed.raw = raw;
|
||||||
data.compressed.nbytes = nbytes;
|
data.compressed.nbytes = nbytes;
|
||||||
|
data.compressed.hash = hash;
|
||||||
|
|
||||||
|
if (maybert)
|
||||||
|
updateCompressedSourceSet(maybert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ScriptSource::updateCompressedSourceSet(JSRuntime *rt)
|
||||||
|
{
|
||||||
|
JS_ASSERT(dataType == DataCompressed);
|
||||||
|
JS_ASSERT(!inCompressedSourceSet);
|
||||||
|
|
||||||
|
CompressedSourceSet::AddPtr p = rt->compressedSourceSet.lookupForAdd(this);
|
||||||
|
if (p) {
|
||||||
|
// There is another ScriptSource with the same compressed data.
|
||||||
|
// Mark that ScriptSource as the parent and use it for all attempts to
|
||||||
|
// get the source for this ScriptSource.
|
||||||
|
ScriptSource *parent = *p;
|
||||||
|
parent->incref();
|
||||||
|
|
||||||
|
js_free(compressedData());
|
||||||
|
dataType = DataParent;
|
||||||
|
data.parent = parent;
|
||||||
|
} else {
|
||||||
|
if (rt->compressedSourceSet.add(p, this))
|
||||||
|
inCompressedSourceSet = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1688,6 +1718,7 @@ SourceCompressionTask::work()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compressedBytes = comp.outWritten();
|
compressedBytes = comp.outWritten();
|
||||||
|
compressedHash = CompressedSourceHasher::computeHash(compressed, compressedBytes);
|
||||||
#else
|
#else
|
||||||
MOZ_CRASH();
|
MOZ_CRASH();
|
||||||
#endif
|
#endif
|
||||||
|
@ -1701,6 +1732,8 @@ SourceCompressionTask::work()
|
||||||
|
|
||||||
ScriptSource::~ScriptSource()
|
ScriptSource::~ScriptSource()
|
||||||
{
|
{
|
||||||
|
JS_ASSERT_IF(inCompressedSourceSet, dataType == DataCompressed);
|
||||||
|
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
case DataUncompressed:
|
case DataUncompressed:
|
||||||
if (ownsUncompressedChars())
|
if (ownsUncompressedChars())
|
||||||
|
@ -1708,9 +1741,21 @@ ScriptSource::~ScriptSource()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DataCompressed:
|
case DataCompressed:
|
||||||
|
// Script source references are only manipulated on the main thread,
|
||||||
|
// except during off thread parsing when the source may be created
|
||||||
|
// and used exclusively by the thread doing the parse. In this case the
|
||||||
|
// ScriptSource might be destroyed while off the main thread, but it
|
||||||
|
// will not have been added to the runtime's compressed source set
|
||||||
|
// until the parse is finished on the main thread.
|
||||||
|
if (inCompressedSourceSet)
|
||||||
|
TlsPerThreadData.get()->runtimeFromMainThread()->compressedSourceSet.remove(this);
|
||||||
js_free(compressedData());
|
js_free(compressedData());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DataParent:
|
||||||
|
parent()->decref();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1753,7 +1798,22 @@ ScriptSource::performXDR(XDRState<mode> *xdr)
|
||||||
if (!xdr->codeUint32(&length_))
|
if (!xdr->codeUint32(&length_))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint32_t compressedLength = (dataType == DataCompressed) ? compressedBytes() : 0;
|
uint32_t compressedLength;
|
||||||
|
if (mode == XDR_ENCODE) {
|
||||||
|
switch (dataType) {
|
||||||
|
case DataUncompressed:
|
||||||
|
compressedLength = 0;
|
||||||
|
break;
|
||||||
|
case DataCompressed:
|
||||||
|
compressedLength = compressedBytes();
|
||||||
|
break;
|
||||||
|
case DataParent:
|
||||||
|
compressedLength = parent()->compressedBytes();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!xdr->codeUint32(&compressedLength))
|
if (!xdr->codeUint32(&compressedLength))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1776,11 +1836,25 @@ ScriptSource::performXDR(XDRState<mode> *xdr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compressedLength)
|
if (compressedLength)
|
||||||
setCompressedSource(p, compressedLength);
|
setCompressedSource(xdr->cx()->runtime(), p, compressedLength,
|
||||||
|
CompressedSourceHasher::computeHash(p, compressedLength));
|
||||||
else
|
else
|
||||||
setSource((const jschar *) p, length_);
|
setSource((const jschar *) p, length_);
|
||||||
} else {
|
} else {
|
||||||
void *p = compressedLength ? compressedData() : (void *) uncompressedChars();
|
void *p;
|
||||||
|
switch (dataType) {
|
||||||
|
case DataUncompressed:
|
||||||
|
p = (void *) uncompressedChars();
|
||||||
|
break;
|
||||||
|
case DataCompressed:
|
||||||
|
p = compressedData();
|
||||||
|
break;
|
||||||
|
case DataParent:
|
||||||
|
p = parent()->compressedData();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
if (!xdr->codeBytes(p, byteLen))
|
if (!xdr->codeBytes(p, byteLen))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3874,7 +3948,7 @@ LazyScriptHashPolicy::match(JSScript *script, const Lookup &lookup)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceDataCache::AutoHoldEntry holder;
|
UncompressedSourceCache::AutoHoldEntry holder;
|
||||||
|
|
||||||
const jschar *scriptChars = script->scriptSource()->chars(cx, holder);
|
const jschar *scriptChars = script->scriptSource()->chars(cx, holder);
|
||||||
if (!scriptChars)
|
if (!scriptChars)
|
||||||
|
|
|
@ -339,7 +339,7 @@ typedef HashMap<JSScript *,
|
||||||
|
|
||||||
class ScriptSource;
|
class ScriptSource;
|
||||||
|
|
||||||
class SourceDataCache
|
class UncompressedSourceCache
|
||||||
{
|
{
|
||||||
typedef HashMap<ScriptSource *,
|
typedef HashMap<ScriptSource *,
|
||||||
const jschar *,
|
const jschar *,
|
||||||
|
@ -350,17 +350,17 @@ class SourceDataCache
|
||||||
// Hold an entry in the source data cache and prevent it from being purged on GC.
|
// Hold an entry in the source data cache and prevent it from being purged on GC.
|
||||||
class AutoHoldEntry
|
class AutoHoldEntry
|
||||||
{
|
{
|
||||||
SourceDataCache *cache_;
|
UncompressedSourceCache *cache_;
|
||||||
ScriptSource *source_;
|
ScriptSource *source_;
|
||||||
const jschar *charsToFree_;
|
const jschar *charsToFree_;
|
||||||
public:
|
public:
|
||||||
explicit AutoHoldEntry();
|
explicit AutoHoldEntry();
|
||||||
~AutoHoldEntry();
|
~AutoHoldEntry();
|
||||||
private:
|
private:
|
||||||
void holdEntry(SourceDataCache *cache, ScriptSource *source);
|
void holdEntry(UncompressedSourceCache *cache, ScriptSource *source);
|
||||||
void deferDelete(const jschar *chars);
|
void deferDelete(const jschar *chars);
|
||||||
ScriptSource *source() const { return source_; }
|
ScriptSource *source() const { return source_; }
|
||||||
friend class SourceDataCache;
|
friend class UncompressedSourceCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -368,7 +368,7 @@ class SourceDataCache
|
||||||
AutoHoldEntry *holder_;
|
AutoHoldEntry *holder_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SourceDataCache() : map_(nullptr), holder_(nullptr) {}
|
UncompressedSourceCache() : map_(nullptr), holder_(nullptr) {}
|
||||||
|
|
||||||
const jschar *lookup(ScriptSource *ss, AutoHoldEntry &asp);
|
const jschar *lookup(ScriptSource *ss, AutoHoldEntry &asp);
|
||||||
bool put(ScriptSource *ss, const jschar *chars, AutoHoldEntry &asp);
|
bool put(ScriptSource *ss, const jschar *chars, AutoHoldEntry &asp);
|
||||||
|
@ -396,7 +396,8 @@ class ScriptSource
|
||||||
enum {
|
enum {
|
||||||
DataMissing,
|
DataMissing,
|
||||||
DataUncompressed,
|
DataUncompressed,
|
||||||
DataCompressed
|
DataCompressed,
|
||||||
|
DataParent
|
||||||
} dataType;
|
} dataType;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -408,7 +409,10 @@ class ScriptSource
|
||||||
struct {
|
struct {
|
||||||
void *raw;
|
void *raw;
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
|
HashNumber hash;
|
||||||
} compressed;
|
} compressed;
|
||||||
|
|
||||||
|
ScriptSource *parent;
|
||||||
} data;
|
} data;
|
||||||
|
|
||||||
uint32_t length_;
|
uint32_t length_;
|
||||||
|
@ -450,6 +454,9 @@ class ScriptSource
|
||||||
bool argumentsNotIncluded_:1;
|
bool argumentsNotIncluded_:1;
|
||||||
bool hasIntroductionOffset_:1;
|
bool hasIntroductionOffset_:1;
|
||||||
|
|
||||||
|
// Whether this is in the runtime's set of compressed ScriptSources.
|
||||||
|
bool inCompressedSourceSet:1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ScriptSource()
|
explicit ScriptSource()
|
||||||
: refs(0),
|
: refs(0),
|
||||||
|
@ -464,7 +471,8 @@ class ScriptSource
|
||||||
introductionType_(nullptr),
|
introductionType_(nullptr),
|
||||||
sourceRetrievable_(false),
|
sourceRetrievable_(false),
|
||||||
argumentsNotIncluded_(false),
|
argumentsNotIncluded_(false),
|
||||||
hasIntroductionOffset_(false)
|
hasIntroductionOffset_(false),
|
||||||
|
inCompressedSourceSet(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~ScriptSource();
|
~ScriptSource();
|
||||||
|
@ -482,6 +490,7 @@ class ScriptSource
|
||||||
void setSourceRetrievable() { sourceRetrievable_ = true; }
|
void setSourceRetrievable() { sourceRetrievable_ = true; }
|
||||||
bool sourceRetrievable() const { return sourceRetrievable_; }
|
bool sourceRetrievable() const { return sourceRetrievable_; }
|
||||||
bool hasSourceData() const { return dataType != DataMissing; }
|
bool hasSourceData() const { return dataType != DataMissing; }
|
||||||
|
bool hasCompressedSource() const { return dataType == DataCompressed; }
|
||||||
size_t length() const {
|
size_t length() const {
|
||||||
JS_ASSERT(hasSourceData());
|
JS_ASSERT(hasSourceData());
|
||||||
return length_;
|
return length_;
|
||||||
|
@ -490,7 +499,7 @@ class ScriptSource
|
||||||
JS_ASSERT(hasSourceData());
|
JS_ASSERT(hasSourceData());
|
||||||
return argumentsNotIncluded_;
|
return argumentsNotIncluded_;
|
||||||
}
|
}
|
||||||
const jschar *chars(JSContext *cx, SourceDataCache::AutoHoldEntry &asp);
|
const jschar *chars(JSContext *cx, UncompressedSourceCache::AutoHoldEntry &asp);
|
||||||
JSFlatString *substring(JSContext *cx, uint32_t start, uint32_t stop);
|
JSFlatString *substring(JSContext *cx, uint32_t start, uint32_t stop);
|
||||||
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||||
JS::ScriptSourceInfo *info) const;
|
JS::ScriptSourceInfo *info) const;
|
||||||
|
@ -515,8 +524,19 @@ class ScriptSource
|
||||||
return data.compressed.nbytes;
|
return data.compressed.nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashNumber compressedHash() const {
|
||||||
|
JS_ASSERT(dataType == DataCompressed);
|
||||||
|
return data.compressed.hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptSource *parent() const {
|
||||||
|
JS_ASSERT(dataType == DataParent);
|
||||||
|
return data.parent;
|
||||||
|
}
|
||||||
|
|
||||||
void setSource(const jschar *chars, size_t length, bool ownsChars = true);
|
void setSource(const jschar *chars, size_t length, bool ownsChars = true);
|
||||||
void setCompressedSource(void *raw, size_t nbytes);
|
void setCompressedSource(JSRuntime *maybert, void *raw, size_t nbytes, HashNumber hash);
|
||||||
|
void updateCompressedSourceSet(JSRuntime *rt);
|
||||||
bool ensureOwnsSource(ExclusiveContext *cx);
|
bool ensureOwnsSource(ExclusiveContext *cx);
|
||||||
|
|
||||||
// XDR handling
|
// XDR handling
|
||||||
|
@ -581,6 +601,27 @@ class ScriptSourceHolder
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CompressedSourceHasher
|
||||||
|
{
|
||||||
|
typedef ScriptSource *Lookup;
|
||||||
|
|
||||||
|
static HashNumber computeHash(const void *data, size_t nbytes) {
|
||||||
|
return mozilla::HashBytes(data, nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HashNumber hash(const ScriptSource *ss) {
|
||||||
|
return ss->compressedHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool match(const ScriptSource *a, const ScriptSource *b) {
|
||||||
|
return a->compressedBytes() == b->compressedBytes() &&
|
||||||
|
a->compressedHash() == b->compressedHash() &&
|
||||||
|
!memcmp(a->compressedData(), b->compressedData(), a->compressedBytes());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef HashSet<ScriptSource *, CompressedSourceHasher, SystemAllocPolicy> CompressedSourceSet;
|
||||||
|
|
||||||
class ScriptSourceObject : public JSObject
|
class ScriptSourceObject : public JSObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -702,6 +702,11 @@ GlobalHelperThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void
|
||||||
|
|
||||||
// The NewScript hook needs to be called for all compiled scripts.
|
// The NewScript hook needs to be called for all compiled scripts.
|
||||||
CallNewScriptHookForAllScripts(cx, script);
|
CallNewScriptHookForAllScripts(cx, script);
|
||||||
|
|
||||||
|
// Update the compressed source table with the result. This is normally
|
||||||
|
// called by setCompressedSource when compilation occurs on the main thread.
|
||||||
|
if (script->scriptSource()->hasCompressedSource())
|
||||||
|
script->scriptSource()->updateCompressedSourceSet(rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return script;
|
return script;
|
||||||
|
@ -990,7 +995,8 @@ SourceCompressionTask::complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == Success) {
|
if (result == Success) {
|
||||||
ss->setCompressedSource(compressed, compressedBytes);
|
ss->setCompressedSource(cx->isJSContext() ? cx->asJSContext()->runtime() : nullptr,
|
||||||
|
compressed, compressedBytes, compressedHash);
|
||||||
|
|
||||||
// Update memory accounting.
|
// Update memory accounting.
|
||||||
cx->updateMallocCounter(ss->computedSizeOfData());
|
cx->updateMallocCounter(ss->computedSizeOfData());
|
||||||
|
|
|
@ -482,11 +482,12 @@ struct SourceCompressionTask
|
||||||
} result;
|
} result;
|
||||||
void *compressed;
|
void *compressed;
|
||||||
size_t compressedBytes;
|
size_t compressedBytes;
|
||||||
|
HashNumber compressedHash;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SourceCompressionTask(ExclusiveContext *cx)
|
explicit SourceCompressionTask(ExclusiveContext *cx)
|
||||||
: cx(cx), ss(nullptr), abort_(false),
|
: cx(cx), ss(nullptr), abort_(false),
|
||||||
result(OOM), compressed(nullptr), compressedBytes(0)
|
result(OOM), compressed(nullptr), compressedBytes(0), compressedHash(0)
|
||||||
{
|
{
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
helperThread = nullptr;
|
helperThread = nullptr;
|
||||||
|
|
|
@ -312,6 +312,9 @@ JSRuntime::init(uint32_t maxbytes)
|
||||||
if (!evalCache.init())
|
if (!evalCache.init())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!compressedSourceSet.init())
|
||||||
|
return false;
|
||||||
|
|
||||||
/* The garbage collector depends on everything before this point being initialized. */
|
/* The garbage collector depends on everything before this point being initialized. */
|
||||||
gcInitialized = true;
|
gcInitialized = true;
|
||||||
|
|
||||||
|
@ -511,7 +514,9 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim
|
||||||
|
|
||||||
rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
|
rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
|
||||||
|
|
||||||
rtSizes->sourceDataCache += sourceDataCache.sizeOfExcludingThis(mallocSizeOf);
|
rtSizes->uncompressedSourceCache += uncompressedSourceCache.sizeOfExcludingThis(mallocSizeOf);
|
||||||
|
|
||||||
|
rtSizes->compressedSourceSet += compressedSourceSet.sizeOfExcludingThis(mallocSizeOf);
|
||||||
|
|
||||||
rtSizes->scriptData += scriptDataTable().sizeOfExcludingThis(mallocSizeOf);
|
rtSizes->scriptData += scriptDataTable().sizeOfExcludingThis(mallocSizeOf);
|
||||||
for (ScriptDataTable::Range r = scriptDataTable().all(); !r.empty(); r.popFront())
|
for (ScriptDataTable::Range r = scriptDataTable().all(); !r.empty(); r.popFront())
|
||||||
|
|
|
@ -1091,10 +1091,11 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||||
js::ScopeCoordinateNameCache scopeCoordinateNameCache;
|
js::ScopeCoordinateNameCache scopeCoordinateNameCache;
|
||||||
js::NewObjectCache newObjectCache;
|
js::NewObjectCache newObjectCache;
|
||||||
js::NativeIterCache nativeIterCache;
|
js::NativeIterCache nativeIterCache;
|
||||||
js::SourceDataCache sourceDataCache;
|
js::UncompressedSourceCache uncompressedSourceCache;
|
||||||
js::EvalCache evalCache;
|
js::EvalCache evalCache;
|
||||||
js::LazyScriptCache lazyScriptCache;
|
js::LazyScriptCache lazyScriptCache;
|
||||||
|
|
||||||
|
js::CompressedSourceSet compressedSourceSet;
|
||||||
js::DateTimeInfo dateTimeInfo;
|
js::DateTimeInfo dateTimeInfo;
|
||||||
|
|
||||||
// Pool of maps used during parse/emit. This may be modified by threads
|
// Pool of maps used during parse/emit. This may be modified by threads
|
||||||
|
|
|
@ -2374,9 +2374,13 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
|
||||||
KIND_HEAP, rtStats.runtime.mathCache,
|
KIND_HEAP, rtStats.runtime.mathCache,
|
||||||
"The math cache.");
|
"The math cache.");
|
||||||
|
|
||||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/source-data-cache"),
|
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/uncompressed-source-cache"),
|
||||||
KIND_HEAP, rtStats.runtime.sourceDataCache,
|
KIND_HEAP, rtStats.runtime.uncompressedSourceCache,
|
||||||
"The source data cache, which holds decompressed script source code.");
|
"The uncompressed source code cache.");
|
||||||
|
|
||||||
|
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/compressed-source-sets"),
|
||||||
|
KIND_HEAP, rtStats.runtime.compressedSourceSet,
|
||||||
|
"The table indexing compressed source code in the runtime.");
|
||||||
|
|
||||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/script-data"),
|
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/script-data"),
|
||||||
KIND_HEAP, rtStats.runtime.scriptData,
|
KIND_HEAP, rtStats.runtime.scriptData,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче