Bug 1259180 - Compact arenas containing scripts r=terrence

This commit is contained in:
Jon Coppeard 2016-04-13 10:03:44 +01:00
Родитель d19790a5a2
Коммит a49aa74ce1
11 изменённых файлов: 170 добавлений и 37 удалений

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

@ -14,6 +14,7 @@
#include "js/Utility.h"
struct JSRuntime;
class JSTracer;
namespace js {
@ -173,6 +174,8 @@ class ProfileEntry
JS_FRIEND_API(jsbytecode*) pc() const volatile;
JS_FRIEND_API(void) setPC(jsbytecode* pc) volatile;
void trace(JSTracer* trc);
// The offset of a pc into a script's code can actually be 0, so to
// signify a nullptr pc, use a -1 index. This is checked against in
// pc() and setPC() to set/get the right pc.

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

@ -126,6 +126,7 @@ struct MovingTracer : JS::CallbackTracer
void onObjectEdge(JSObject** objp) override;
void onShapeEdge(Shape** shapep) override;
void onStringEdge(JSString** stringp) override;
void onScriptEdge(JSScript** scriptp) override;
void onChild(const JS::GCCellPtr& thing) override {
MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
}

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

@ -323,6 +323,8 @@ js::gc::GCRuntime::markRuntime(JSTracer* trc, TraceOrMarkRuntime traceOrMark)
jit::MarkJitActivations(rt, trc);
rt->spsProfiler.trace(trc);
if (!rt->isHeapMinorCollecting()) {
gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_EMBEDDING);

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

@ -633,8 +633,7 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t
// structures. It uses a HashMap instead of a WeakMap, so that we can keep
// the data alive for the JSScript::finalize call. Thus, we do not trace the
// keys of the HashMap to avoid adding a strong reference to the JSScript
// pointers. Additionally, we assert that the JSScripts have not been moved
// in JSCompartment::fixupAfterMovingGC.
// pointers.
//
// If the code coverage is either enabled with the --dump-bytecode command
// line option, or with the PCCount JSFriend API functions, then we mark the
@ -821,18 +820,7 @@ JSCompartment::fixupAfterMovingGC()
fixupInitialShapeTable();
objectGroups.fixupTablesAfterMovingGC();
dtoaCache.purge();
#ifdef DEBUG
// Assert that none of the JSScript pointers, which are used as key of the
// scriptCountsMap HashMap are moved. We do not mark these keys because we
// need weak references. We do not use a WeakMap because these entries would
// be collected before the JSScript::finalize calls which is used to
// summarized the content of the code coverage.
if (scriptCountsMap) {
for (ScriptCountsMap::Range r = scriptCountsMap->all(); !r.empty(); r.popFront())
MOZ_ASSERT(!IsForwarded(r.front().key()));
}
#endif
fixupScriptMapsAfterMovingGC();
}
void
@ -843,6 +831,59 @@ JSCompartment::fixupGlobal()
global_.set(MaybeForwarded(global));
}
void
JSCompartment::fixupScriptMapsAfterMovingGC()
{
// Map entries are removed by JSScript::finalize, but we need to update the
// script pointers here in case they are moved by the GC.
if (scriptCountsMap) {
for (ScriptCountsMap::Enum e(*scriptCountsMap); !e.empty(); e.popFront()) {
JSScript* script = e.front().key();
if (!IsAboutToBeFinalizedUnbarriered(&script) && script != e.front().key())
e.rekeyFront(script);
}
}
if (debugScriptMap) {
for (DebugScriptMap::Enum e(*debugScriptMap); !e.empty(); e.popFront()) {
JSScript* script = e.front().key();
if (!IsAboutToBeFinalizedUnbarriered(&script) && script != e.front().key())
e.rekeyFront(script);
}
}
}
#ifdef JSGC_HASH_TABLE_CHECKS
void
JSCompartment::checkScriptMapsAfterMovingGC()
{
if (scriptCountsMap) {
for (auto r = scriptCountsMap->all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
CheckGCThingAfterMovingGC(script);
auto ptr = scriptCountsMap->lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
if (debugScriptMap) {
for (auto r = debugScriptMap->all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
CheckGCThingAfterMovingGC(script);
DebugScript* ds = r.front().value();
for (uint32_t i = 0; i < ds->numSites; i++) {
BreakpointSite* site = ds->breakpoints[i];
if (site)
CheckGCThingAfterMovingGC(site->script);
}
auto ptr = debugScriptMap->lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
}
#endif
void
JSCompartment::purge()
{

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

@ -452,6 +452,7 @@ struct JSCompartment
void checkInitialShapesTableAfterMovingGC();
void checkWrapperMapAfterMovingGC();
void checkBaseShapeTableAfterMovingGC();
void checkScriptMapsAfterMovingGC();
#endif
/*
@ -604,6 +605,7 @@ struct JSCompartment
void fixupInitialShapeTable();
void fixupAfterMovingGC();
void fixupGlobal();
void fixupScriptMapsAfterMovingGC();
bool hasAllocationMetadataBuilder() const { return allocationMetadataBuilder; }
const js::AllocationMetadataBuilder* getAllocationMetadataBuilder() const {

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

@ -2044,6 +2044,7 @@ static const AllocKind AllocKindsToRelocate[] = {
AllocKind::OBJECT12_BACKGROUND,
AllocKind::OBJECT16,
AllocKind::OBJECT16_BACKGROUND,
AllocKind::SCRIPT,
AllocKind::SHAPE,
AllocKind::ACCESSOR_SHAPE,
AllocKind::FAT_INLINE_STRING,
@ -2403,6 +2404,14 @@ MovingTracer::onStringEdge(JSString** stringp)
*stringp = Forwarded(string);
}
void
MovingTracer::onScriptEdge(JSScript** scriptp)
{
JSScript* script = *scriptp;
if (IsForwarded(script))
*scriptp = Forwarded(script);
}
void
Zone::prepareForCompacting()
{
@ -2760,6 +2769,7 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone)
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
comp->fixupAfterMovingGC();
JSCompartment::fixupCrossCompartmentWrappersAfterMovingGC(&trc);
rt->spsProfiler.fixupStringsMapAfterMovingGC();
// Iterate through all cells that can contain relocatable pointers to update
// them. Since updating each cell is independent we try to parallelize this
@ -7363,6 +7373,7 @@ js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt)
* Check that internal hash tables no longer have any pointers to things
* that have been moved.
*/
rt->spsProfiler.checkStringsMapAfterMovingGC();
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
zone->checkUniqueIdTableAfterMovingGC();
@ -7378,6 +7389,7 @@ js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt)
c->checkInitialShapesTableAfterMovingGC();
c->checkWrapperMapAfterMovingGC();
c->checkBaseShapeTableAfterMovingGC();
c->checkScriptMapsAfterMovingGC();
if (c->debugScopes)
c->debugScopes->checkHashTablesAfterMovingGC(rt);
}

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

@ -1098,7 +1098,8 @@ struct MightBeForwarded
static const bool value = mozilla::IsBaseOf<JSObject, T>::value ||
mozilla::IsBaseOf<Shape, T>::value ||
mozilla::IsBaseOf<JSString, T>::value;
mozilla::IsBaseOf<JSString, T>::value ||
mozilla::IsBaseOf<JSScript, T>::value;
};
template <typename T>

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

@ -213,15 +213,15 @@ Bindings::initWithTemporaryStorage(ExclusiveContext* cx, MutableHandle<Bindings>
return true;
}
bool
Bindings::initTrivial(ExclusiveContext* cx)
/* static */ bool
Bindings::initTrivialForScript(ExclusiveContext* cx, HandleScript script)
{
Shape* shape = EmptyShape::getInitialShape(cx, &CallObject::class_, TaggedProto(nullptr),
CallObject::RESERVED_SLOTS,
BaseShape::QUALIFIED_VAROBJ | BaseShape::DELEGATE);
if (!shape)
return false;
callObjShape_.init(shape);
script->bindings.callObjShape_.init(shape);
return true;
}
@ -242,7 +242,7 @@ Bindings::clone(JSContext* cx, MutableHandle<Bindings> self,
uint8_t* dstScriptData, HandleScript srcScript)
{
/* The clone has the same bindingArray_ offset as 'src'. */
Handle<Bindings> src = Handle<Bindings>::fromMarkedLocation(&srcScript->bindings);
const Bindings& src = srcScript->bindings;
ptrdiff_t off = (uint8_t*)src.bindingArray() - srcScript->data;
MOZ_ASSERT(off >= 0);
MOZ_ASSERT(size_t(off) <= srcScript->dataSize());
@ -2942,7 +2942,7 @@ JSScript::partiallyInit(ExclusiveContext* cx, HandleScript script, uint32_t ncon
/* static */ bool
JSScript::fullyInitTrivial(ExclusiveContext* cx, Handle<JSScript*> script)
{
if (!script->bindings.initTrivial(cx))
if (!Bindings::initTrivialForScript(cx, script))
return false;
if (!partiallyInit(cx, script, 0, 0, 0, 0, 0, 0))

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

@ -284,7 +284,7 @@ class Bindings
bool isModule = false);
// Initialize a trivial Bindings with no slots and an empty callObjShape.
bool initTrivial(ExclusiveContext* cx);
static bool initTrivialForScript(ExclusiveContext* cx, HandleScript script);
// CompileScript parses and compiles one statement at a time, but the result
// is one Script object. There will be no vars or bindings, because those
@ -525,6 +525,7 @@ typedef HashMap<JSScript*,
class DebugScript
{
friend class ::JSScript;
friend struct ::JSCompartment;
/*
* When non-zero, compile script in single-step mode. The top bit is set and
@ -2011,24 +2012,37 @@ namespace js {
*/
class BindingIter
{
Handle<Bindings> bindings_;
Binding* bindingArray_;
uint32_t numArgs_;
uint32_t count_;
uint32_t i_;
uint32_t unaliasedLocal_;
friend class ::JSScript;
friend class Bindings;
void init(const Bindings& bindings) {
// Bindings contained in a JSScript may be moved by the GC. Copy the
// necessary fields into this object.
bindingArray_ = bindings.bindingArray();
numArgs_ = bindings.numArgs();
count_ = bindings.count();
}
public:
explicit BindingIter(Handle<Bindings> bindings)
: bindings_(bindings), i_(0), unaliasedLocal_(0)
{}
: i_(0), unaliasedLocal_(0)
{
init(bindings);
}
explicit BindingIter(const HandleScript& script)
: bindings_(Handle<Bindings>::fromMarkedLocation(&script->bindings)),
i_(0), unaliasedLocal_(0)
{}
explicit BindingIter(HandleScript script)
: i_(0), unaliasedLocal_(0)
{
init(script->bindings);
}
bool done() const { return i_ == bindings_.count(); }
bool done() const { return i_ == count_; }
explicit operator bool() const { return !done(); }
BindingIter& operator++() { (*this)++; return *this; }
@ -2046,7 +2060,7 @@ class BindingIter
// has no stack slot.
uint32_t frameIndex() const {
MOZ_ASSERT(!done());
if (i_ < bindings_.numArgs())
if (i_ < numArgs_)
return i_;
MOZ_ASSERT(!(*this)->aliased());
return unaliasedLocal_;
@ -2057,17 +2071,17 @@ class BindingIter
// both unaliased and aliased arguments.
uint32_t argIndex() const {
MOZ_ASSERT(!done());
MOZ_ASSERT(i_ < bindings_.numArgs());
MOZ_ASSERT(i_ < numArgs_);
return i_;
}
uint32_t argOrLocalIndex() const {
MOZ_ASSERT(!done());
return i_ < bindings_.numArgs() ? i_ : i_ - bindings_.numArgs();
return i_ < numArgs_ ? i_ : i_ - numArgs_;
}
uint32_t localIndex() const {
MOZ_ASSERT(!done());
MOZ_ASSERT(i_ >= bindings_.numArgs());
return i_ - bindings_.numArgs();
MOZ_ASSERT(i_ >= numArgs_);
return i_ - numArgs_;
}
bool isBodyLevelLexical() const {
MOZ_ASSERT(!done());
@ -2075,8 +2089,8 @@ class BindingIter
return binding.kind() != Binding::ARGUMENT;
}
const Binding& operator*() const { MOZ_ASSERT(!done()); return bindings_.bindingArray()[i_]; }
const Binding* operator->() const { MOZ_ASSERT(!done()); return &bindings_.bindingArray()[i_]; }
const Binding& operator*() const { MOZ_ASSERT(!done()); return bindingArray_[i_]; }
const Binding* operator->() const { MOZ_ASSERT(!done()); return &bindingArray_[i_]; }
};
/*

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

@ -305,8 +305,8 @@ void
SPSProfiler::pop()
{
MOZ_ASSERT(installed());
MOZ_ASSERT(*size_ > 0);
(*size_)--;
MOZ_ASSERT(*(int*)size_ >= 0);
}
/*
@ -364,6 +364,57 @@ SPSProfiler::allocProfileString(JSScript* script, JSFunction* maybeFun)
return cstr;
}
void
SPSProfiler::trace(JSTracer* trc)
{
if (stack_) {
size_t limit = Min(*size_, max_);
for (size_t i = 0; i < limit; i++)
stack_[i].trace(trc);
}
}
void
SPSProfiler::fixupStringsMapAfterMovingGC()
{
if (!strings.initialized())
return;
for (ProfileStringMap::Enum e(strings); !e.empty(); e.popFront()) {
JSScript* script = e.front().key();
if (IsForwarded(script)) {
script = Forwarded(script);
e.rekeyFront(script);
}
}
}
#ifdef JSGC_HASH_TABLE_CHECKS
void
SPSProfiler::checkStringsMapAfterMovingGC()
{
if (!strings.initialized())
return;
for (auto r = strings.all(); !r.empty(); r.popFront()) {
JSScript* script = r.front().key();
CheckGCThingAfterMovingGC(script);
auto ptr = strings.lookup(script);
MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &r.front());
}
}
#endif
void
ProfileEntry::trace(JSTracer* trc)
{
if (isJs()) {
JSScript* s = script();
TraceNullableRoot(trc, &s, "ProfileEntry script");
spOrScript = s;
}
}
SPSEntryMarker::SPSEntryMarker(JSRuntime* rt,
JSScript* script
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)

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

@ -203,6 +203,12 @@ class SPSProfiler
uint32_t* addressOfEnabled() {
return &enabled_;
}
void trace(JSTracer* trc);
void fixupStringsMapAfterMovingGC();
#ifdef JSGC_HASH_TABLE_CHECKS
void checkStringsMapAfterMovingGC();
#endif
};
/*