Bug 822442. Keep track of DOM proxies in TI, like other DOM objects, so we can do the same call/get/set optimizaations with them. r=efaust
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 15 Apr 2014 22:58:45 -0400
changeset 197242 17f84a2187f2492639a7fdc0a2274bc854775821
parent 197241 af250d9dee47448af2793658296da623db840328
child 197243 a6ed5860261f4ab6eafdf42eeb1fb10b42b7707d
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs822442
milestone31.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 822442. Keep track of DOM proxies in TI, like other DOM objects, so we can do the same call/get/set optimizaations with them. r=efaust
js/public/Class.h
js/src/jit/MIR.cpp
js/src/jsinfer.cpp
js/src/vm/ProxyObject.cpp
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -474,16 +474,20 @@ struct Class
     bool isCallable() const {
         return this == js::FunctionClassPtr || call;
     }
 
     bool isProxy() const {
         return flags & JSCLASS_IS_PROXY;
     }
 
+    bool isDOMClass() const {
+        return flags & JSCLASS_IS_DOMJSCLASS;
+    }
+
     static size_t offsetOfFlags() { return offsetof(Class, flags); }
 };
 
 JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name));
 JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags));
 JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty));
 JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty));
 JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty));
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -3091,19 +3091,24 @@ PropertyReadNeedsTypeBarrier(types::Comp
                              types::TypeObjectKey *object, PropertyName *name,
                              types::TypeSet *observed)
 {
     // If the object being read from has types for the property which haven't
     // been observed at this access site, the read could produce a new type and
     // a barrier is needed. Note that this only covers reads from properties
     // which are accounted for by type information, i.e. native data properties
     // and elements.
-
-    if (object->unknownProperties() || observed->empty())
+    //
+    // We also need a barrier if the object is a proxy, because then all bets
+    // are off, just as if it has unknown properties.
+    if (object->unknownProperties() || observed->empty() ||
+        object->clasp()->isProxy())
+    {
         return true;
+    }
 
     jsid id = name ? NameToId(name) : JSID_VOID;
     types::HeapTypeSetKey property = object->property(id);
     if (property.maybeTypes() && !TypeSetIncludes(observed, MIRType_Value, property.maybeTypes()))
         return true;
 
     // Type information for global objects is not required to reflect the
     // initial 'undefined' value for properties, in particular global
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1758,17 +1758,17 @@ bool
 TemporaryTypeSet::isDOMClass()
 {
     if (unknownObject())
         return false;
 
     unsigned count = getObjectCount();
     for (unsigned i = 0; i < count; i++) {
         const Class *clasp = getObjectClass(i);
-        if (clasp && (!(clasp->flags & JSCLASS_IS_DOMJSCLASS) || clasp->isProxy()))
+        if (clasp && !clasp->isDOMClass())
             return false;
     }
 
     return count > 0;
 }
 
 bool
 TemporaryTypeSet::maybeCallable()
--- a/js/src/vm/ProxyObject.cpp
+++ b/js/src/vm/ProxyObject.cpp
@@ -24,19 +24,21 @@ ProxyObject::New(JSContext *cx, BaseProx
 
     JS_ASSERT(isValidProxyClass(clasp));
     JS_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
     JS_ASSERT_IF(parent, cx->compartment() == parent->compartment());
 
     /*
      * Eagerly mark properties unknown for proxies, so we don't try to track
      * their properties and so that we don't need to walk the compartment if
-     * their prototype changes later.
+     * their prototype changes later.  But don't do this for DOM proxies,
+     * because we want to be able to keep track of them in typesets in useful
+     * ways.
      */
-    if (proto.isObject() && !options.singleton()) {
+    if (proto.isObject() && !options.singleton() && !clasp->isDOMClass()) {
         RootedObject protoObj(cx, proto.toObject());
         if (!JSObject::setNewTypeUnknown(cx, clasp, protoObj))
             return nullptr;
     }
 
     NewObjectKind newKind = options.singleton() ? SingletonObject : GenericObject;
     gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
     if (handler->finalizeInBackground(priv))
@@ -44,18 +46,18 @@ ProxyObject::New(JSContext *cx, BaseProx
     RootedObject obj(cx, NewObjectWithGivenProto(cx, clasp, proto, parent, allocKind, newKind));
     if (!obj)
         return nullptr;
 
     Rooted<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
     proxy->initHandler(handler);
     proxy->initCrossCompartmentPrivate(priv);
 
-    /* Don't track types of properties of proxies. */
-    if (newKind != SingletonObject)
+    /* Don't track types of properties of non-DOM and non-singleton proxies. */
+    if (newKind != SingletonObject && !clasp->isDOMClass())
         MarkTypeObjectUnknownProperties(cx, proxy->type());
 
     return proxy;
 }
 
 void
 ProxyObject::initCrossCompartmentPrivate(HandleValue priv)
 {