Bug 1724693 part 3 - Move VarNamesSet from Realm to GlobalObjectData. r=jonco
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 14 Aug 2021 13:02:47 +0000
changeset 588993 aa6483129f44a2f2157bea796f0aa82435502958
parent 588992 49601cf5c6b644c8b21337169aabeb8be48f3b74
child 588994 18fc1360f9ca6a3aebba2000fd430f18d60dfa75
push id148070
push userjdemooij@mozilla.com
push dateSat, 14 Aug 2021 13:05:23 +0000
treeherderautoland@aa6483129f44 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1724693
milestone93.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1724693 part 3 - Move VarNamesSet from Realm to GlobalObjectData. r=jonco This lets us remove the weak tracing code. Also fixes a memory reporting issue: the reporter we had for this set wasn't hooked up in Gecko. Differential Revision: https://phabricator.services.mozilla.com/D122108
js/public/MemoryMetrics.h
js/src/gc/GC.cpp
js/src/vm/EnvironmentObject.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
js/src/vm/Interpreter.cpp
js/src/vm/JSObject.cpp
js/src/vm/MemoryMetrics.cpp
js/src/vm/Realm.cpp
js/src/vm/Realm.h
js/xpconnect/src/XPCJSRuntime.cpp
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -176,26 +176,27 @@ struct InefficientNonFlatteningStringHas
 #define ADD_TO_SERVO_SIZES(tabKind, servoKind, mSize) \
   sizes->add(JS::ServoSizes::servoKind, mSize);
 
 }  // namespace js
 
 namespace JS {
 
 struct ClassInfo {
-#define FOR_EACH_SIZE(MACRO)                                  \
-  MACRO(Objects, GCHeapUsed, objectsGCHeap)                   \
-  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)       \
-  MACRO(Objects, NonHeap, objectsNonHeapElementsWasm)         \
+#define FOR_EACH_SIZE(MACRO)                                     \
+  MACRO(Objects, GCHeapUsed, objectsGCHeap)                      \
+  MACRO(Objects, MallocHeap, objectsMallocHeapSlots)             \
+  MACRO(Objects, MallocHeap, objectsMallocHeapElementsNormal)    \
+  MACRO(Objects, MallocHeap, objectsMallocHeapElementsAsmJS)     \
+  MACRO(Objects, MallocHeap, objectsMallocHeapGlobalData)        \
+  MACRO(Objects, MallocHeap, objectsMallocHeapGlobalVarNamesSet) \
+  MACRO(Objects, MallocHeap, objectsMallocHeapMisc)              \
+  MACRO(Objects, NonHeap, objectsNonHeapElementsNormal)          \
+  MACRO(Objects, NonHeap, objectsNonHeapElementsShared)          \
+  MACRO(Objects, NonHeap, objectsNonHeapElementsWasm)            \
   MACRO(Objects, NonHeap, objectsNonHeapCodeWasm)
 
   ClassInfo() = default;
 
   void add(const ClassInfo& other) { FOR_EACH_SIZE(ADD_OTHER_SIZE); }
 
   void subtract(const ClassInfo& other) { FOR_EACH_SIZE(SUB_OTHER_SIZE); }
 
@@ -737,17 +738,16 @@ struct RealmStats {
   MACRO(Other, MallocHeap, baselineStubsFallback)          \
   MACRO(Other, MallocHeap, ionData)                        \
   MACRO(Other, MallocHeap, jitScripts)                     \
   MACRO(Other, MallocHeap, realmObject)                    \
   MACRO(Other, MallocHeap, realmTables)                    \
   MACRO(Other, MallocHeap, innerViewsTable)                \
   MACRO(Other, MallocHeap, objectMetadataTable)            \
   MACRO(Other, MallocHeap, savedStacksSet)                 \
-  MACRO(Other, MallocHeap, varNamesSet)                    \
   MACRO(Other, MallocHeap, nonSyntacticLexicalScopesTable) \
   MACRO(Other, MallocHeap, jitRealm)
 
   RealmStats() = default;
   RealmStats(RealmStats&& other) = default;
 
   RealmStats(const RealmStats&) = delete;  // disallow copying
 
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -2579,17 +2579,16 @@ void GCRuntime::sweepZoneAfterCompacting
 
   if (jit::JitZone* jitZone = zone->jitZone()) {
     jitZone->traceWeak(trc);
   }
 
   for (RealmsInZoneIter r(zone); !r.done(); r.next()) {
     r->traceWeakRegExps(trc);
     r->traceWeakSavedStacks(trc);
-    r->tracekWeakVarNames(trc);
     r->traceWeakObjects(trc);
     r->traceWeakSelfHostingScriptSource(trc);
     r->sweepDebugEnvironments();
     r->traceWeakEdgesInJitRealm(trc);
     r->traceWeakObjectRealm(trc);
     r->traceWeakTemplateObjects(trc);
   }
 }
@@ -5490,20 +5489,16 @@ void GCRuntime::updateAtomsBitmap() {
     // zone bitmap, so it is conservative to just not call it.
   }
 
   atomMarking.markAtomsUsedByUncollectedZones(rt);
 
   // For convenience sweep these tables non-incrementally as part of bitmap
   // sweeping; they are likely to be much smaller than the main atoms table.
   rt->symbolRegistry().sweep();
-  SweepingTracer trc(rt);
-  for (RealmsIter realm(this); !realm.done(); realm.next()) {
-    realm->tracekWeakVarNames(&trc);
-  }
 }
 
 void GCRuntime::sweepCCWrappers() {
   AutoSetThreadIsSweeping threadIsSweeping;  // This can touch all zones.
   for (SweepGroupZonesIter zone(this); !zone.done(); zone.next()) {
     zone->sweepAllCrossCompartmentWrappers();
   }
 }
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -3441,17 +3441,17 @@ bool js::GetThisValueForDebuggerSuspende
 
 bool js::CheckLexicalNameConflict(
     JSContext* cx, Handle<ExtensibleLexicalEnvironmentObject*> lexicalEnv,
     HandleObject varObj, HandlePropertyName name) {
   const char* redeclKind = nullptr;
   RootedId id(cx, NameToId(name));
   mozilla::Maybe<PropertyInfo> prop;
   if (varObj->is<GlobalObject>() &&
-      varObj->as<GlobalObject>().realm()->isInVarNames(name)) {
+      varObj->as<GlobalObject>().isInVarNames(name)) {
     // ES 15.1.11 step 5.a
     redeclKind = "var";
   } else if ((prop = lexicalEnv->lookup(cx, name))) {
     // ES 15.1.11 step 5.b
     redeclKind = prop->writable() ? "let" : "const";
   } else if (varObj->is<NativeObject>() &&
              (prop = varObj->as<NativeObject>().lookup(cx, name))) {
     // Faster path for ES 15.1.11 step 5.c-d when the shape can be found
@@ -3574,17 +3574,17 @@ static bool InitGlobalOrEvalDeclarations
             (obj2 != varObj && varObj->is<GlobalObject>())) {
           if (!DefineDataProperty(cx, varObj, name, UndefinedHandleValue,
                                   attrs)) {
             return false;
           }
         }
 
         if (varObj->is<GlobalObject>()) {
-          if (!varObj->as<GlobalObject>().realm()->addToVarNames(cx, name)) {
+          if (!varObj->as<GlobalObject>().addToVarNames(cx, name)) {
             return false;
           }
         }
 
         break;
       }
 
       case BindingKind::Const:
@@ -3652,17 +3652,17 @@ static bool InitHoistedFunctionDeclarati
                                          : JSPROP_ENUMERATE | JSPROP_PERMANENT;
 
     if (prop.isNotFound() || pobj != varObj) {
       if (!DefineDataProperty(cx, varObj, name, rval, attrs)) {
         return false;
       }
 
       if (varObj->is<GlobalObject>()) {
-        if (!varObj->as<GlobalObject>().realm()->addToVarNames(cx, name)) {
+        if (!varObj->as<GlobalObject>().addToVarNames(cx, name)) {
           return false;
         }
       }
 
       // Done processing this function.
       continue;
     }
 
@@ -3684,17 +3684,17 @@ static bool InitHoistedFunctionDeclarati
       } else {
         MOZ_ASSERT(propInfo.isDataProperty());
         MOZ_ASSERT(propInfo.writable());
         MOZ_ASSERT(propInfo.enumerable());
       }
 
       // Careful: the presence of a shape, even one appearing to derive from
       // a variable declaration, doesn't mean it's in [[VarNames]].
-      if (!varObj->as<GlobalObject>().realm()->addToVarNames(cx, name)) {
+      if (!varObj->as<GlobalObject>().addToVarNames(cx, name)) {
         return false;
       }
     }
 
     /*
      * Non-global properties, and global properties which we aren't simply
      * redefining, must be set.  First, this preserves their attributes.
      * Second, this will produce warnings and/or errors as necessary if the
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -656,17 +656,17 @@ GlobalObject* GlobalObject::createIntern
   if (!obj) {
     return nullptr;
   }
 
   Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
   MOZ_ASSERT(global->isUnqualifiedVarObj());
 
   {
-    auto data = cx->make_unique<GlobalObjectData>();
+    auto data = cx->make_unique<GlobalObjectData>(cx->zone());
     if (!data) {
       return nullptr;
     }
     // 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);
     InitReservedSlot(global, GLOBAL_DATA_SLOT, data.release(),
@@ -922,16 +922,27 @@ RegExpStatics* GlobalObject::getRegExpSt
       return nullptr;
     }
     global->data().regExpStatics = std::move(statics);
   }
 
   return global->data().regExpStatics.get();
 }
 
+bool GlobalObject::addToVarNames(JSContext* cx, JS::Handle<JSAtom*> name) {
+  MOZ_ASSERT(name);
+
+  if (!data().varNames.put(name)) {
+    ReportOutOfMemory(cx);
+    return false;
+  }
+
+  return true;
+}
+
 /* static */
 NativeObject* GlobalObject::getIntrinsicsHolder(JSContext* cx,
                                                 Handle<GlobalObject*> global) {
   if (NativeObject* holder = global->data().intrinsicsHolder) {
     return holder;
   }
 
   Rooted<NativeObject*> intrinsicsHolder(
@@ -1145,17 +1156,24 @@ JSObject* GlobalObject::createAsyncItera
 }
 
 void GlobalObject::releaseData(JSFreeOp* fop) {
   GlobalObjectData* data = maybeData();
   setReservedSlot(GLOBAL_DATA_SLOT, PrivateValue(nullptr));
   fop->delete_(this, data, MemoryUse::GlobalObjectData);
 }
 
+GlobalObjectData::GlobalObjectData(Zone* zone) : varNames(zone) {}
+
 void GlobalObjectData::trace(JSTracer* trc) {
+  // Atoms are always tenured.
+  if (!JS::RuntimeHeapIsMinorCollecting()) {
+    varNames.trace(trc);
+  }
+
   for (auto& ctorWithProto : builtinConstructors) {
     TraceNullableEdge(trc, &ctorWithProto.constructor, "global-builtin-ctor");
     TraceNullableEdge(trc, &ctorWithProto.prototype,
                       "global-builtin-ctor-proto");
   }
 
   for (auto& proto : builtinProtos) {
     TraceNullableEdge(trc, &proto, "global-builtin-proto");
@@ -1174,16 +1192,20 @@ void GlobalObjectData::trace(JSTracer* t
 
   TraceNullableEdge(trc, &arrayShapeWithDefaultProto, "global-array-shape");
 
   if (regExpStatics) {
     regExpStatics->trace(trc);
   }
 }
 
-size_t GlobalObjectData::sizeOfIncludingThis(
-    mozilla::MallocSizeOf mallocSizeOf) const {
-  size_t size = mallocSizeOf(this);
+void GlobalObjectData::addSizeOfIncludingThis(
+    mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo* info) const {
+  info->objectsMallocHeapGlobalData += mallocSizeOf(this);
+
   if (regExpStatics) {
-    size += regExpStatics->sizeOfIncludingThis(mallocSizeOf);
+    info->objectsMallocHeapGlobalData +=
+        regExpStatics->sizeOfIncludingThis(mallocSizeOf);
   }
-  return size;
+
+  info->objectsMallocHeapGlobalVarNamesSet +=
+      varNames.shallowSizeOfExcludingThis(mallocSizeOf);
 }
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -60,17 +60,26 @@ class RegExpStatics;
 // GlobalObject JSClasses.
 class GlobalObjectData {
   friend class js::GlobalObject;
 
   GlobalObjectData(const GlobalObjectData&) = delete;
   void operator=(const GlobalObjectData&) = delete;
 
  public:
-  GlobalObjectData() = default;
+  explicit GlobalObjectData(Zone* zone);
+
+  // The global environment record's [[VarNames]] list that contains all
+  // names declared using FunctionDeclaration, GeneratorDeclaration, and
+  // VariableDeclaration declarations in global code in this global's realm.
+  // Names are only removed from this list by a |delete IdentifierReference|
+  // that successfully removes that global property.
+  using VarNamesSet =
+      GCHashSet<HeapPtr<JSAtom*>, DefaultHasher<JSAtom*>, ZoneAllocPolicy>;
+  VarNamesSet varNames;
 
   // The original values for built-in constructors (with their prototype
   // objects) based on JSProtoKey.
   //
   // This is necessary to implement spec language speaking in terms of "the
   // original Array prototype object", or "as if by the expression new Array()"
   // referring to the original Array constructor. The actual (writable and even
   // deletable) Object, Array, &c. properties are not stored here.
@@ -141,17 +150,18 @@ class GlobalObjectData {
 
   // Global state for regular expressions.
   UniquePtr<RegExpStatics> regExpStatics;
 
   // Whether the |globalThis| property has been resolved on the global object.
   bool globalThisResolved = false;
 
   void trace(JSTracer* trc);
-  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+  void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
+                              JS::ClassInfo* info) const;
 
   static constexpr size_t offsetOfLexicalEnvironment() {
     static_assert(sizeof(lexicalEnvironment) == sizeof(uintptr_t),
                   "JIT code assumes field is pointer-sized");
     return offsetof(GlobalObjectData, lexicalEnvironment);
   }
 };
 
@@ -207,18 +217,21 @@ class GlobalObject : public NativeObject
   GlobalLexicalEnvironmentObject& lexicalEnvironment() {
     return *data().lexicalEnvironment;
   }
   GlobalScope& emptyGlobalScope() const;
 
   void traceData(JSTracer* trc) { data().trace(trc); }
   void releaseData(JSFreeOp* fop);
 
-  size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const {
-    return maybeData() ? data().sizeOfIncludingThis(mallocSizeOf) : 0;
+  void addSizeOfData(mozilla::MallocSizeOf mallocSizeOf,
+                     JS::ClassInfo* info) const {
+    if (maybeData()) {
+      data().addSizeOfIncludingThis(mallocSizeOf, info);
+    }
   }
 
   void setOriginalEval(JSFunction* evalFun) {
     MOZ_ASSERT(!data().eval);
     data().eval.init(evalFun);
   }
 
   bool hasConstructor(JSProtoKey key) const {
@@ -882,16 +895,24 @@ class GlobalObject : public NativeObject
 
   static bool getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global,
                               MutableHandleObject eval);
 
   // Infallibly test whether the given value is the eval function for this
   // global.
   bool valueIsEval(const Value& val);
 
+  void removeFromVarNames(JSAtom* name) { data().varNames.remove(name); }
+
+  // Whether the given name is in [[VarNames]].
+  bool isInVarNames(JSAtom* name) { return data().varNames.has(name); }
+
+  // Add a name to [[VarNames]].  Reports OOM on failure.
+  [[nodiscard]] bool addToVarNames(JSContext* cx, JS::Handle<JSAtom*> name);
+
   // Implemented in vm/Iteration.cpp.
   static bool initIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
   template <ProtoKind Kind, const JSClass* ProtoClass,
             const JSFunctionSpec* Methods>
   static bool initObjectIteratorProto(JSContext* cx,
                                       Handle<GlobalObject*> global,
                                       HandleAtom tag);
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -4832,17 +4832,17 @@ bool js::DeleteNameOperation(JSContext* 
   }
 
   bool status = result.ok();
   res.setBoolean(status);
 
   if (status) {
     // Deleting a name from the global object removes it from [[VarNames]].
     if (pobj == scope && scope->is<GlobalObject>()) {
-      scope->as<GlobalObject>().realm()->removeFromVarNames(name);
+      scope->as<GlobalObject>().removeFromVarNames(name);
     }
   }
 
   return true;
 }
 
 bool js::ImplicitThisOperation(JSContext* cx, HandleObject scopeObj,
                                HandlePropertyName name,
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -3558,18 +3558,17 @@ void JSObject::addSizeOfExcludingThis(mo
   } else if (is<PropertyIteratorObject>()) {
     info->objectsMallocHeapMisc +=
         as<PropertyIteratorObject>().sizeOfMisc(mallocSizeOf);
   } else if (is<ArrayBufferObject>()) {
     ArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info);
   } else if (is<SharedArrayBufferObject>()) {
     SharedArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info);
   } else if (is<GlobalObject>()) {
-    info->objectsMallocHeapGlobalData +=
-        as<GlobalObject>().sizeOfData(mallocSizeOf);
+    as<GlobalObject>().addSizeOfData(mallocSizeOf, info);
   } else if (is<WeakCollectionObject>()) {
     info->objectsMallocHeapMisc +=
         as<WeakCollectionObject>().sizeOfExcludingThis(mallocSizeOf);
   }
 #ifdef JS_HAS_CTYPES
   else {
     // This must be the last case.
     info->objectsMallocHeapMisc += ctypes::SizeOfDataIfCDataObject(
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -232,18 +232,18 @@ static void StatsRealmCallback(JSContext
   rtStats->initExtraRealmStats(realm, &realmStats, nogc);
 
   realm->setRealmStats(&realmStats);
 
   // Measure the realm object itself, and things hanging off it.
   realm->addSizeOfIncludingThis(
       rtStats->mallocSizeOf_, &realmStats.realmObject, &realmStats.realmTables,
       &realmStats.innerViewsTable, &realmStats.objectMetadataTable,
-      &realmStats.savedStacksSet, &realmStats.varNamesSet,
-      &realmStats.nonSyntacticLexicalScopesTable, &realmStats.jitRealm);
+      &realmStats.savedStacksSet, &realmStats.nonSyntacticLexicalScopesTable,
+      &realmStats.jitRealm);
 }
 
 static void StatsArenaCallback(JSRuntime* rt, void* data, gc::Arena* arena,
                                JS::TraceKind traceKind, size_t thingSize,
                                const JS::AutoRequireNoGC& nogc) {
   RuntimeStats* rtStats = static_cast<StatsClosure*>(data)->rtStats;
 
   // The admin space includes (a) the header fields and (b) the padding
--- a/js/src/vm/Realm.cpp
+++ b/js/src/vm/Realm.cpp
@@ -55,17 +55,16 @@ ObjectRealm::~ObjectRealm() {
 
 Realm::Realm(Compartment* comp, const JS::RealmOptions& options)
     : JS::shadow::Realm(comp),
       zone_(comp->zone()),
       runtime_(comp->runtimeFromMainThread()),
       creationOptions_(options.creationOptions()),
       behaviors_(options.behaviors()),
       objects_(zone_),
-      varNames_(zone_),
       randomKeyGenerator_(runtime_->forkRandomKeyGenerator()),
       debuggers_(zone_),
       wasm(runtime_) {
   MOZ_ASSERT_IF(creationOptions_.mergeable(),
                 creationOptions_.invisibleToDebugger());
 
   runtime_->numRealms++;
 }
@@ -253,39 +252,23 @@ ObjectRealm::getNonSyntacticLexicalEnvir
   }
   JSObject* lexicalEnv = nonSyntacticLexicalEnvironments_->lookup(key);
   if (!lexicalEnv) {
     return nullptr;
   }
   return &lexicalEnv->as<NonSyntacticLexicalEnvironmentObject>();
 }
 
-bool Realm::addToVarNames(JSContext* cx, JS::Handle<JSAtom*> name) {
-  MOZ_ASSERT(name);
-
-  if (varNames_.put(name)) {
-    return true;
-  }
-
-  ReportOutOfMemory(cx);
-  return false;
-}
-
 void Realm::traceGlobal(JSTracer* trc) {
   // Trace things reachable from the realm's global. Note that these edges
   // must be swept too in case the realm is live but the global is not.
 
   savedStacks_.trace(trc);
 
   DebugAPI::traceFromRealm(trc, this);
-
-  // Atoms are always tenured.
-  if (!JS::RuntimeHeapIsMinorCollecting()) {
-    varNames_.trace(trc);
-  }
 }
 
 void ObjectRealm::trace(JSTracer* trc) {
   if (objectMetadataTable) {
     objectMetadataTable->trace(trc);
   }
 
   if (nonSyntacticLexicalEnvironments_) {
@@ -408,18 +391,16 @@ void ObjectRealm::traceWeakNativeIterato
     ni = next;
   }
 }
 
 void Realm::traceWeakObjectRealm(JSTracer* trc) {
   objects_.traceWeakNativeIterators(trc);
 }
 
-void Realm::tracekWeakVarNames(JSTracer* trc) { varNames_.traceWeak(trc); }
-
 void Realm::traceWeakTemplateObjects(JSTracer* trc) {
   TraceWeakEdge(trc, &mappedArgumentsTemplate_,
                 "Realm::mappedArgumentsTemplate_");
   TraceWeakEdge(trc, &unmappedArgumentsTemplate_,
                 "Realm::unmappedArgumentsTemplate_");
   TraceWeakEdge(trc, &iterResultTemplate_, "Realm::iterResultTemplate_");
   TraceWeakEdge(trc, &iterResultWithoutPrototypeTemplate_,
                 "Realm::iterResultWithoutPrototypeTemplate_");
@@ -452,17 +433,16 @@ void Realm::clearTables() {
   // No scripts should have run in this realm. This is used when merging
   // a realm that has been used off thread into another realm and zone.
   compartment()->assertNoCrossCompartmentWrappers();
   MOZ_ASSERT(!jitRealm_);
   MOZ_ASSERT(!debugEnvs_);
   MOZ_ASSERT(objects_.enumerators->next() == objects_.enumerators);
 
   savedStacks_.clear();
-  varNames_.clear();
 }
 
 // Check to see if this individual realm is recording allocations. Debuggers or
 // runtimes can try and record allocations, so this method can check to see if
 // any initialization is needed.
 bool Realm::isRecordingAllocations() { return !!allocationMetadataBuilder_; }
 
 void Realm::setAllocationMetadataBuilder(
@@ -615,28 +595,27 @@ void ObjectRealm::addSizeOfExcludingThis
         map->sizeOfIncludingThis(mallocSizeOf);
   }
 }
 
 void Realm::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                    size_t* realmObject, size_t* realmTables,
                                    size_t* innerViewsArg,
                                    size_t* objectMetadataTablesArg,
-                                   size_t* savedStacksSet, size_t* varNamesSet,
+                                   size_t* savedStacksSet,
                                    size_t* nonSyntacticLexicalEnvironmentsArg,
                                    size_t* jitRealm) {
   *realmObject += mallocSizeOf(this);
   wasm.addSizeOfExcludingThis(mallocSizeOf, realmTables);
 
   objects_.addSizeOfExcludingThis(mallocSizeOf, innerViewsArg,
                                   objectMetadataTablesArg,
                                   nonSyntacticLexicalEnvironmentsArg);
 
   *savedStacksSet += savedStacks_.sizeOfExcludingThis(mallocSizeOf);
-  *varNamesSet += varNames_.shallowSizeOfExcludingThis(mallocSizeOf);
 
   if (jitRealm_) {
     *jitRealm += jitRealm_->sizeOfIncludingThis(mallocSizeOf);
   }
 }
 
 mozilla::HashCodeScrambler Realm::randomHashCodeScrambler() {
   return mozilla::HashCodeScrambler(randomKeyGenerator_.next(),
--- a/js/src/vm/Realm.h
+++ b/js/src/vm/Realm.h
@@ -306,26 +306,16 @@ class JS::Realm : public JS::shadow::Rea
 
   friend struct ::JSContext;
   js::WeakHeapPtrGlobalObject global_;
 
   // Note: this is private to enforce use of ObjectRealm::get(obj).
   js::ObjectRealm objects_;
   friend js::ObjectRealm& js::ObjectRealm::get(const JSObject*);
 
-  // The global environment record's [[VarNames]] list that contains all
-  // names declared using FunctionDeclaration, GeneratorDeclaration, and
-  // VariableDeclaration declarations in global code in this realm.
-  // Names are only removed from this list by a |delete IdentifierReference|
-  // that successfully removes that global property.
-  using VarNamesSet =
-      GCHashSet<js::WeakHeapPtr<JSAtom*>, js::DefaultHasher<JSAtom*>,
-                js::ZoneAllocPolicy>;
-  VarNamesSet varNames_;
-
   friend class js::AutoSetNewObjectMetadata;
   js::NewObjectMetadataState objectMetadataState_{js::ImmediateMetadata()};
 
   // Random number generator for Math.random().
   mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG>
       randomNumberGenerator_;
 
   // Random number generator for randomHashCodeScrambler().
@@ -461,17 +451,17 @@ class JS::Realm : public JS::shadow::Rea
   [[nodiscard]] bool init(JSContext* cx, JSPrincipals* principals);
   void destroy(JSFreeOp* fop);
   void clearTables();
 
   void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
                               size_t* realmObject, size_t* realmTables,
                               size_t* innerViewsArg,
                               size_t* objectMetadataTablesArg,
-                              size_t* savedStacksSet, size_t* varNamesSet,
+                              size_t* savedStacksSet,
                               size_t* nonSyntacticLexicalEnvironmentsArg,
                               size_t* jitRealm);
 
   JS::Zone* zone() { return zone_; }
   const JS::Zone* zone() const { return zone_; }
 
   JSRuntime* runtimeFromMainThread() const {
     MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
@@ -549,25 +539,16 @@ class JS::Realm : public JS::shadow::Rea
 
   void clearScriptCounts();
   void clearScriptLCov();
 
   void purge();
 
   void fixupAfterMovingGC(JSTracer* trc);
 
-  // Add a name to [[VarNames]].  Reports OOM on failure.
-  [[nodiscard]] bool addToVarNames(JSContext* cx, JS::Handle<JSAtom*> name);
-  void tracekWeakVarNames(JSTracer* trc);
-
-  void removeFromVarNames(JS::Handle<JSAtom*> name) { varNames_.remove(name); }
-
-  // Whether the given name is in [[VarNames]].
-  bool isInVarNames(JS::Handle<JSAtom*> name) { return varNames_.has(name); }
-
   void enter() { enterRealmDepthIgnoringJit_++; }
   void leave() {
     MOZ_ASSERT(enterRealmDepthIgnoringJit_ > 0);
     enterRealmDepthIgnoringJit_--;
   }
   bool hasBeenEnteredIgnoringJit() const {
     return enterRealmDepthIgnoringJit_ > 0;
   }
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1690,16 +1690,22 @@ static void ReportClassStats(const Class
   }
 
   if (classInfo.objectsMallocHeapGlobalData > 0) {
     REPORT_BYTES(path + "objects/malloc-heap/global-data"_ns, KIND_HEAP,
                  classInfo.objectsMallocHeapGlobalData,
                  "Data for global objects.");
   }
 
+  if (classInfo.objectsMallocHeapGlobalVarNamesSet > 0) {
+    REPORT_BYTES(path + "objects/malloc-heap/global-varnames-set"_ns, KIND_HEAP,
+                 classInfo.objectsMallocHeapGlobalVarNamesSet,
+                 "Set of global names.");
+  }
+
   if (classInfo.objectsMallocHeapMisc > 0) {
     REPORT_BYTES(path + "objects/malloc-heap/misc"_ns, KIND_HEAP,
                  classInfo.objectsMallocHeapMisc, "Miscellaneous object data.");
   }
 
   if (classInfo.objectsNonHeapElementsNormal > 0) {
     REPORT_BYTES(path + "objects/non-heap/elements/normal"_ns, KIND_NONHEAP,
                  classInfo.objectsNonHeapElementsNormal,