Bug 1723715 part 1 - Add GlobalObjectData and use it for emptyGlobalScope. r=jonco

Differential Revision: https://phabricator.services.mozilla.com/D121981
This commit is contained in:
Jan de Mooij 2021-08-09 15:25:04 +00:00
parent ad486327b2
commit 1c8f0d1a67
9 changed files with 84 additions and 10 deletions

View File

@ -186,6 +186,7 @@ struct ClassInfo {
MACRO(Objects, MallocHeap, objectsMallocHeapSlots) \
MACRO(Objects, MallocHeap, objectsMallocHeapElementsNormal) \
MACRO(Objects, MallocHeap, objectsMallocHeapElementsAsmJS) \
MACRO(Objects, MallocHeap, objectsMallocHeapGlobalData) \
MACRO(Objects, MallocHeap, objectsMallocHeapMisc) \
MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \
MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \

View File

@ -143,7 +143,8 @@ enum class GCAbortReason {
_(FinalizationRecordVector) \
_(ZoneAllocPolicy) \
_(SharedArrayRawBuffer) \
_(XDRBufferElements)
_(XDRBufferElements) \
_(GlobalObjectData)
#define JS_FOR_EACH_MEMORY_USE(_) \
JS_FOR_EACH_PUBLIC_MEMORY_USE(_) \

View File

@ -208,8 +208,8 @@ bool JS::ObjectOpResult::reportError(JSContext* cx, HandleObject obj,
if (ErrorTakesObjectArgument(code_)) {
JSObject* unwrapped = js::CheckedUnwrapStatic(obj);
const char* name = unwrapped ? unwrapped->getClass()->name : "Object";
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, code_,
name, propName.get());
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, code_, name,
propName.get());
return false;
}
@ -1798,6 +1798,8 @@ JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global) {
// know the global is live.
globalRealm->traceGlobal(trc);
globalObj->traceData(trc);
if (JSTraceOp trace = globalRealm->creationOptions().getTrace()) {
trace(trc, global);
}

View File

@ -650,10 +650,21 @@ GlobalObject* GlobalObject::createInternal(JSContext* cx,
if (!emptyGlobalScope) {
return nullptr;
}
global->setReservedSlot(EMPTY_GLOBAL_SCOPE,
PrivateGCThingValue(emptyGlobalScope));
cx->realm()->initGlobal(*global, *lexical);
{
auto data = cx->make_unique<GlobalObjectData>();
if (!data) {
return nullptr;
}
data->emptyGlobalScope.init(emptyGlobalScope);
// Note: it's important for the realm's global to be initialized at the
// same time as the global's GlobalObjectData, because we free the global's
// data when Realm::global_ is cleared.
cx->realm()->initGlobal(*global, *lexical);
InitReservedSlot(global, GLOBAL_DATA_SLOT, data.release(),
MemoryUse::GlobalObjectData);
}
if (!JSObject::setQualifiedVarObj(cx, global)) {
return nullptr;
@ -709,9 +720,7 @@ GlobalLexicalEnvironmentObject& GlobalObject::lexicalEnvironment() const {
}
GlobalScope& GlobalObject::emptyGlobalScope() const {
const Value& v = getReservedSlot(EMPTY_GLOBAL_SCOPE);
MOZ_ASSERT(v.isPrivateGCThing() && v.traceKind() == JS::TraceKind::Scope);
return static_cast<Scope*>(v.toGCThing())->as<GlobalScope>();
return *data().emptyGlobalScope;
}
/* static */
@ -1136,3 +1145,13 @@ JSObject* GlobalObject::createAsyncIteratorPrototype(
global->setReservedSlot(ASYNC_ITERATOR_PROTO, ObjectValue(*proto));
return proto;
}
void GlobalObject::releaseData(JSFreeOp* fop) {
GlobalObjectData* data = maybeData();
setReservedSlot(GLOBAL_DATA_SLOT, PrivateValue(nullptr));
fop->delete_(this, data, MemoryUse::GlobalObjectData);
}
void GlobalObjectData::trace(JSTracer* trc) {
TraceEdge(trc, &emptyGlobalScope, "global-empty-scope");
}

View File

@ -54,6 +54,23 @@ class GlobalLexicalEnvironmentObject;
class PlainObject;
class RegExpStatics;
// Data attached to a GlobalObject. This is freed when clearing the Realm's
// global_ only because this way we don't need to add a finalizer to all
// GlobalObject JSClasses.
class GlobalObjectData {
friend class js::GlobalObject;
GlobalObjectData(const GlobalObjectData&) = delete;
void operator=(const GlobalObjectData&) = delete;
public:
GlobalObjectData() = default;
HeapPtr<GlobalScope*> emptyGlobalScope;
void trace(JSTracer* trc);
};
/*
* Global object slots are reserved as follows:
*
@ -97,7 +114,7 @@ class GlobalObject : public NativeObject {
THROWTYPEERROR,
/* One-off properties stored after slots for built-ins. */
EMPTY_GLOBAL_SCOPE,
GLOBAL_DATA_SLOT,
ITERATOR_PROTO,
ARRAY_ITERATOR_PROTO,
STRING_ITERATOR_PROTO,
@ -148,10 +165,29 @@ class GlobalObject : public NativeObject {
return APPLICATION_SLOTS + JSProto_LIMIT + key;
}
GlobalObjectData* maybeData() {
Value v = getReservedSlot(GLOBAL_DATA_SLOT);
return static_cast<GlobalObjectData*>(v.toPrivate());
}
const GlobalObjectData* maybeData() const {
Value v = getReservedSlot(GLOBAL_DATA_SLOT);
return static_cast<const GlobalObjectData*>(v.toPrivate());
}
GlobalObjectData& data() { return *maybeData(); }
const GlobalObjectData& data() const { return *maybeData(); }
public:
GlobalLexicalEnvironmentObject& lexicalEnvironment() const;
GlobalScope& emptyGlobalScope() const;
void traceData(JSTracer* trc) { data().trace(trc); }
void releaseData(JSFreeOp* fop);
size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const {
return mallocSizeOf(maybeData());
}
void setOriginalEval(JSObject* evalobj) {
MOZ_ASSERT(getReservedSlot(EVAL).isUndefined());
setReservedSlot(EVAL, ObjectValue(*evalobj));

View File

@ -3573,6 +3573,9 @@ void JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
ArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info);
} else if (is<SharedArrayBufferObject>()) {
SharedArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info);
} else if (is<GlobalObject>()) {
info->objectsMallocHeapGlobalData +=
as<GlobalObject>().sizeOfData(mallocSizeOf);
} else if (is<WeakCollectionObject>()) {
info->objectsMallocHeapMisc +=
as<WeakCollectionObject>().sizeOfExcludingThis(mallocSizeOf);

View File

@ -362,6 +362,10 @@ void Realm::sweepAfterMinorGC() {
void Realm::traceWeakSavedStacks(JSTracer* trc) { savedStacks_.traceWeak(trc); }
void Realm::traceWeakObjects(JSTracer* trc) {
// If the global is dead, free its GlobalObjectData.
if (zone_->isGCSweeping() && globalIsAboutToBeFinalized()) {
global_.unbarrieredGet()->releaseData(runtime_->defaultFreeOp());
}
TraceWeakEdge(trc, &global_, "Realm::global_");
TraceWeakEdge(trc, &lexicalEnv_, "Realm::lexicalEnv_");
}
@ -445,6 +449,7 @@ void Realm::purge() {
}
void Realm::clearTables() {
global_.unbarrieredGet()->releaseData(runtime_->defaultFreeOp());
global_.set(nullptr);
lexicalEnv_.set(nullptr);

View File

@ -44,6 +44,7 @@ class JitRealm;
class AutoRestoreRealmDebugMode;
class GlobalObject;
class GlobalObjectData;
class GlobalLexicalEnvironmentObject;
class MapObject;
class NonSyntacticLexicalEnvironmentObject;

View File

@ -1689,6 +1689,12 @@ static void ReportClassStats(const ClassInfo& classInfo, const nsACString& path,
"asm.js array buffer elements allocated in the malloc heap.");
}
if (classInfo.objectsMallocHeapGlobalData > 0) {
REPORT_BYTES(path + "objects/malloc-heap/global-data"_ns, KIND_HEAP,
classInfo.objectsMallocHeapGlobalData,
"Data for global objects.");
}
if (classInfo.objectsMallocHeapMisc > 0) {
REPORT_BYTES(path + "objects/malloc-heap/misc"_ns, KIND_HEAP,
classInfo.objectsMallocHeapMisc, "Miscellaneous object data.");