зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1259180 - Compact arenas containing scripts r=terrence
This commit is contained in:
Родитель
d19790a5a2
Коммит
a49aa74ce1
|
@ -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
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче