Bug 1348095 part 3. Cache the proto of an Xray on its holder, so we don't have to keep re-wrapping it. r=bholley
☠☠ backed out by 42b182f3367e ☠ ☠
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 23 Mar 2017 03:06:25 -0400
changeset 348939 8ba41a1bd062a484ed24a5a25758c13eb57b8429
parent 348938 3efe3c6f4e7fbe7164df59562e43ada7706407ea
child 348940 3ccb231829a94c8d5aff22222ecfe0ef1f1d50a7
push id88364
push userbzbarsky@mozilla.com
push dateThu, 23 Mar 2017 07:06:40 +0000
treeherdermozilla-inbound@3ccb231829a9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1348095
milestone55.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 1348095 part 3. Cache the proto of an Xray on its holder, so we don't have to keep re-wrapping it. r=bholley MozReview-Commit-ID: I78AoSB3TNW
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -2405,26 +2405,45 @@ XrayWrapper<Base, Traits>::getPrototype(
     RootedObject expando(cx);
     if (!Traits::singleton.getExpandoObject(cx, target, wrapper, &expando))
         return false;
 
     // We want to keep the Xray's prototype distinct from that of content, but
     // only if there's been a set. If there's not an expando, or the expando
     // slot is |undefined|, hand back the default proto, appropriately wrapped.
 
-    RootedValue v(cx);
     if (expando) {
-        JSAutoCompartment ac(cx, expando);
-        v = JS_GetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE);
+        RootedValue v(cx);
+        { // Scope for JSAutoCompartment
+            JSAutoCompartment ac(cx, expando);
+            v = JS_GetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE);
+        }
+        if (!v.isUndefined()) {
+            protop.set(v.toObjectOrNull());
+            return JS_WrapObject(cx, protop);
+        }
     }
-    if (v.isUndefined())
-        return getPrototypeHelper(cx, wrapper, target, protop);
+
+    // Check our holder, and cache there if we don't have it cached already.
+    RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper));
+    if (!holder)
+        return false;
 
-    protop.set(v.toObjectOrNull());
-    return JS_WrapObject(cx, protop);
+    Value cached = js::GetReservedSlot(holder,
+                                       Traits::HOLDER_SLOT_CACHED_PROTO);
+    if (cached.isUndefined()) {
+        if (!getPrototypeHelper(cx, wrapper, target, protop))
+            return false;
+
+        js::SetReservedSlot(holder, Traits::HOLDER_SLOT_CACHED_PROTO,
+                            ObjectOrNullValue(protop));
+    } else {
+        protop.set(cached.toObjectOrNull());
+    }
+    return true;
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::setPrototype(JSContext* cx, JS::HandleObject wrapper,
                                         JS::HandleObject proto, JS::ObjectOpResult& result) const
 {
     // Do this only for non-SecurityWrapper-inheriting |Base|. See the comment