merge mozilla-inbound to mozilla-central a=merge
authorIris Hsiao <ihsiao@mozilla.com>
Mon, 24 Apr 2017 11:35:45 +0800
changeset 354509 73752931e273091185e1e4b5231c28beed657cc8
parent 354505 933ced9c93e90cd1987c6b5f08dbada24eb2b781 (current diff)
parent 354508 06c7c56497ad4e34729d6e54da8408ad868ec8de (diff)
child 354510 c9c297494260ee73d12e139913cf53389c7564bc
child 354521 b38afd8b510996a135366739731ff53e4d2161fe
child 354610 e41a0de745aee09f4bd80cf09b60336ebf52abbb
push id41334
push userihsiao@mozilla.com
push dateMon, 24 Apr 2017 06:28:23 +0000
treeherderautoland@c9c297494260 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.0a1
first release with
nightly linux32
73752931e273 / 55.0a1 / 20170424100313 / files
nightly linux64
73752931e273 / 55.0a1 / 20170424100313 / files
nightly mac
73752931e273 / 55.0a1 / 20170424030211 / files
nightly win32
73752931e273 / 55.0a1 / 20170424030211 / files
nightly win64
73752931e273 / 55.0a1 / 20170424030211 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
browser/components/customizableui/content/panelUI.js
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -219,16 +219,23 @@ const PanelUI = {
   removeNotification(id) {
     let notifications;
     if (typeof id == "string") {
       notifications = this.notifications.filter(n => n.id == id);
     } else {
       // If it's not a string, assume RegExp
       notifications = this.notifications.filter(n => id.test(n.id));
     }
+    // _updateNotifications can be expensive if it forces attachment of XBL
+    // bindings that haven't been used yet, so return early if we haven't found
+    // any notification to remove, as callers may expect this removeNotification
+    // method to be a no-op for non-existent notifications.
+    if (!notifications.length) {
+      return;
+    }
 
     notifications.forEach(n => {
       this._removeNotification(n);
     });
     this._updateNotifications();
   },
 
   dismissNotification(id) {
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -1042,16 +1042,17 @@ JSCompartment::checkScriptMapsAfterMovin
 #endif
 
 void
 JSCompartment::purge()
 {
     dtoaCache.purge();
     newProxyCache.purge();
     lastCachedNativeIterator = nullptr;
+    objectGroups.purge();
 }
 
 void
 JSCompartment::clearTables()
 {
     global_.set(nullptr);
 
     // No scripts should have run in this compartment. This is used when
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -456,42 +456,42 @@ class ObjectGroupCompartment::NewTable :
 {
     using Table = js::GCHashSet<NewEntry, NewEntry, SystemAllocPolicy>;
     using Base = JS::WeakCache<Table>;
 
   public:
     explicit NewTable(Zone* zone) : Base(zone, Table()) {}
 };
 
+MOZ_ALWAYS_INLINE ObjectGroup*
+ObjectGroupCompartment::DefaultNewGroupCache::lookup(const Class* clasp, TaggedProto proto,
+                                                     JSObject* associated)
+{
+    if (group_ &&
+        associated_ == associated &&
+        group_->proto() == proto &&
+        (!clasp || group_->clasp() == clasp))
+    {
+        return group_;
+    }
+    return nullptr;
+}
+
 /* static */ ObjectGroup*
 ObjectGroup::defaultNewGroup(JSContext* cx, const Class* clasp,
                              TaggedProto proto, JSObject* associated)
 {
     MOZ_ASSERT_IF(associated, proto.isObject());
     MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject()));
 
     // A null lookup clasp is used for 'new' groups with an associated
     // function. The group starts out as a plain object but might mutate into an
     // unboxed plain object.
     MOZ_ASSERT_IF(!clasp, !!associated);
 
-    AutoEnterAnalysis enter(cx);
-
-    ObjectGroupCompartment::NewTable*& table = cx->compartment()->objectGroups.defaultNewTable;
-
-    if (!table) {
-        table = cx->new_<ObjectGroupCompartment::NewTable>(cx->zone());
-        if (!table || !table->init()) {
-            js_delete(table);
-            table = nullptr;
-            ReportOutOfMemory(cx);
-            return nullptr;
-        }
-    }
-
     if (associated && !associated->is<TypeDescr>()) {
         MOZ_ASSERT(!clasp);
         if (associated->is<JSFunction>()) {
 
             // Canonicalize new functions to use the original one associated with its script.
             JSFunction* fun = &associated->as<JSFunction>();
             if (fun->hasScript())
                 associated = fun->nonLazyScript()->functionNonDelazifying();
@@ -508,16 +508,35 @@ ObjectGroup::defaultNewGroup(JSContext* 
         } else {
             associated = nullptr;
         }
 
         if (!associated)
             clasp = &PlainObject::class_;
     }
 
+    ObjectGroupCompartment& groups = cx->compartment()->objectGroups;
+
+    if (ObjectGroup* group = groups.defaultNewGroupCache.lookup(clasp, proto, associated))
+        return group;
+
+    AutoEnterAnalysis enter(cx);
+
+    ObjectGroupCompartment::NewTable*& table = groups.defaultNewTable;
+
+    if (!table) {
+        table = cx->new_<ObjectGroupCompartment::NewTable>(cx->zone());
+        if (!table || !table->init()) {
+            js_delete(table);
+            table = nullptr;
+            ReportOutOfMemory(cx);
+            return nullptr;
+        }
+    }
+
     if (proto.isObject() && !proto.toObject()->isDelegate()) {
         RootedObject protoObj(cx, proto.toObject());
         if (!JSObject::setDelegate(cx, protoObj))
             return nullptr;
 
         // Objects which are prototypes of one another should be singletons, so
         // that their type information can be tracked more precisely. Limit
         // this group change to plain objects, to avoid issues with other types
@@ -531,16 +550,17 @@ ObjectGroup::defaultNewGroup(JSContext* 
     ObjectGroupCompartment::NewTable::AddPtr p =
         table->lookupForAdd(ObjectGroupCompartment::NewEntry::Lookup(clasp, proto, associated));
     if (p) {
         ObjectGroup* group = p->group;
         MOZ_ASSERT_IF(clasp, group->clasp() == clasp);
         MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_ ||
                               group->clasp() == &UnboxedPlainObject::class_);
         MOZ_ASSERT(group->proto() == proto);
+        groups.defaultNewGroupCache.put(group, associated);
         return group;
     }
 
     ObjectGroupFlags initialFlags = 0;
     if (proto.isDynamic() || (proto.isObject() && proto.toObject()->isNewGroupUnknown()))
         initialFlags = OBJECT_FLAG_DYNAMIC_MASK;
 
     Rooted<TaggedProto> protoRoot(cx, proto);
@@ -577,16 +597,17 @@ ObjectGroup::defaultNewGroup(JSContext* 
     } else if (clasp == &StringObject::class_) {
         AddTypePropertyId(cx, group, nullptr, NameToId(names.length), TypeSet::Int32Type());
     } else if (ErrorObject::isErrorClass(clasp)) {
         AddTypePropertyId(cx, group, nullptr, NameToId(names.fileName), TypeSet::StringType());
         AddTypePropertyId(cx, group, nullptr, NameToId(names.lineNumber), TypeSet::Int32Type());
         AddTypePropertyId(cx, group, nullptr, NameToId(names.columnNumber), TypeSet::Int32Type());
     }
 
+    groups.defaultNewGroupCache.put(group, associated);
     return group;
 }
 
 /* static */ ObjectGroup*
 ObjectGroup::lazySingletonGroup(JSContext* cx, const Class* clasp, TaggedProto proto)
 {
     MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
 
@@ -1676,27 +1697,29 @@ ObjectGroupCompartment::~ObjectGroupComp
 void
 ObjectGroupCompartment::removeDefaultNewGroup(const Class* clasp, TaggedProto proto,
                                               JSObject* associated)
 {
     auto p = defaultNewTable->lookup(NewEntry::Lookup(clasp, proto, associated));
     MOZ_RELEASE_ASSERT(p);
 
     defaultNewTable->get().remove(p);
+    defaultNewGroupCache.purge();
 }
 
 void
 ObjectGroupCompartment::replaceDefaultNewGroup(const Class* clasp, TaggedProto proto,
                                                JSObject* associated, ObjectGroup* group)
 {
     NewEntry::Lookup lookup(clasp, proto, associated);
 
     auto p = defaultNewTable->lookup(lookup);
     MOZ_RELEASE_ASSERT(p);
     defaultNewTable->get().remove(p);
+    defaultNewGroupCache.purge();
     {
         AutoEnterOOMUnsafeRegion oomUnsafe;
         if (!defaultNewTable->putNew(lookup, NewEntry(group, associated)))
             oomUnsafe.crash("Inconsistent object table");
     }
 }
 
 /* static */
@@ -1765,16 +1788,17 @@ ObjectGroupCompartment::clearTables()
             js_free(entry.types);
         }
         plainObjectTable->clear();
     }
     if (defaultNewTable && defaultNewTable->initialized())
         defaultNewTable->clear();
     if (lazyTable && lazyTable->initialized())
         lazyTable->clear();
+    defaultNewGroupCache.purge();
 }
 
 /* static */ bool
 ObjectGroupCompartment::PlainObjectTableSweepPolicy::needsSweep(PlainObjectKey* key,
                                                                 PlainObjectEntry* entry)
 {
     if (!(JS::GCPolicy<PlainObjectKey>::needsSweep(key) || entry->needsSweep(key->nproperties)))
         return false;
--- a/js/src/vm/ObjectGroup.h
+++ b/js/src/vm/ObjectGroup.h
@@ -561,16 +561,38 @@ class ObjectGroupCompartment
     friend class ObjectGroup;
 
     class NewTable;
 
     // Set of default 'new' or lazy groups in the compartment.
     NewTable* defaultNewTable;
     NewTable* lazyTable;
 
+    // Cache for defaultNewGroup. Purged on GC.
+    class DefaultNewGroupCache
+    {
+        ObjectGroup* group_;
+        JSObject* associated_;
+
+      public:
+        DefaultNewGroupCache() { purge(); }
+
+        void purge() {
+            group_ = nullptr;
+        }
+        void put(ObjectGroup* group, JSObject* associated) {
+            group_ = group;
+            associated_ = associated;
+        }
+
+        MOZ_ALWAYS_INLINE ObjectGroup* lookup(const Class* clasp, TaggedProto proto,
+                                              JSObject* associated);
+    };
+    DefaultNewGroupCache defaultNewGroupCache;
+
     struct ArrayObjectKey;
     using ArrayObjectTable = js::GCRekeyableHashMap<ArrayObjectKey,
                                                     ReadBarrieredObjectGroup,
                                                     ArrayObjectKey,
                                                     SystemAllocPolicy>;
 
     struct PlainObjectKey;
     struct PlainObjectEntry;
@@ -623,16 +645,20 @@ class ObjectGroupCompartment
                                 size_t* arrayGroupTables,
                                 size_t* plainObjectGroupTables,
                                 size_t* compartmentTables);
 
     void clearTables();
 
     void sweep(FreeOp* fop);
 
+    void purge() {
+        defaultNewGroupCache.purge();
+    }
+
 #ifdef JSGC_HASH_TABLE_CHECKS
     void checkTablesAfterMovingGC() {
         checkNewTableAfterMovingGC(defaultNewTable);
         checkNewTableAfterMovingGC(lazyTable);
     }
 #endif
 
     void fixupTablesAfterMovingGC() {
--- a/layout/xul/nsRootBoxFrame.cpp
+++ b/layout/xul/nsRootBoxFrame.cpp
@@ -108,21 +108,21 @@ protected:
 nsContainerFrame*
 NS_NewRootBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsRootBoxFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsRootBoxFrame)
 
-nsRootBoxFrame::nsRootBoxFrame(nsStyleContext* aContext):
-  nsBoxFrame(aContext, true)
+nsRootBoxFrame::nsRootBoxFrame(nsStyleContext* aContext)
+  : nsBoxFrame(aContext, true)
+  , mPopupSetFrame(nullptr)
+  , mDefaultTooltip(nullptr)
 {
-  mPopupSetFrame = nullptr;
-
   nsCOMPtr<nsBoxLayout> layout;
   NS_NewStackLayout(layout);
   SetXULLayoutManager(layout);
 }
 
 void
 nsRootBoxFrame::AppendFrames(ChildListID     aListID,
                              nsFrameList&    aFrameList)