Bug 1010658 part 1. Stop using the DOMClass stored in DOM_PROTO_INSTANCE_CLASS_SLOT for doing type checks in the jit, and do them directly on the instance classes instead. r=efaust
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 19 May 2014 16:37:59 -0400
changeset 203034 5d52c012effdd9cc727b940a2b5c8988105bd33f
parent 203033 3602db87fac35d7961b9e3e45fd9d63273850532
child 203035 a200f79a7b8fcec1902639e8898f1a48825a7be2
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1010658
milestone32.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 1010658 part 1. Stop using the DOMClass stored in DOM_PROTO_INSTANCE_CLASS_SLOT for doing type checks in the jit, and do them directly on the instance classes instead. r=efaust
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/crashtests/1010658-1.html
dom/bindings/crashtests/1010658-2.html
dom/bindings/crashtests/crashtests.list
js/src/jit/IonBuilder.cpp
js/src/jsfriendapi.h
js/src/shell/js.cpp
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -768,25 +768,23 @@ TryPreserveWrapper(JSObject* obj)
 
   // If this DOMClass is not cycle collected, then it isn't wrappercached,
   // so it does not need to be preserved. If it is cycle collected, then
   // we can't tell if it is wrappercached or not, so we just return false.
   const DOMClass* domClass = GetDOMClass(obj);
   return domClass && !domClass->mParticipant;
 }
 
-// Can only be called with the immediate prototype of the instance object. Can
-// only be called on the prototype of an object known to be a DOM instance.
+// Can only be called with a DOM JSClass.
 bool
-InstanceClassHasProtoAtDepth(JSObject* protoObject, uint32_t protoID,
-                             uint32_t depth)
+InstanceClassHasProtoAtDepth(const js::Class* clasp,
+                             uint32_t protoID, uint32_t depth)
 {
-  const DOMClass* domClass = static_cast<const DOMClass*>(
-    js::GetReservedSlot(protoObject, DOM_PROTO_INSTANCE_CLASS_SLOT).toPrivate());
-  return (uint32_t)domClass->mInterfaceChain[depth] == protoID;
+  const DOMClass& domClass = DOMJSClass::FromJSClass(clasp)->mClass;
+  return static_cast<uint32_t>(domClass.mInterfaceChain[depth]) == protoID;
 }
 
 // Only set allowNativeWrapper to false if you really know you need it, if in
 // doubt use true. Setting it to false disables security wrappers.
 bool
 XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
                    xpcObjectHelper& helper, const nsIID* iid,
                    bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval)
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1180,21 +1180,20 @@ ClearWrapper(T* p, void*)
 // the object can only be obtained by JS once, or they cannot be meaningfully
 // owned from the native side.
 //
 // This operation will return false only for non-nsISupports cycle-collected
 // objects, because we cannot determine if they are wrappercached or not.
 bool
 TryPreserveWrapper(JSObject* obj);
 
-// Can only be called with the immediate prototype of the instance object. Can
-// only be called on the prototype of an object known to be a DOM instance.
+// Can only be called with a DOM JSClass.
 bool
-InstanceClassHasProtoAtDepth(JSObject* protoObject, uint32_t protoID,
-                             uint32_t depth);
+InstanceClassHasProtoAtDepth(const js::Class* clasp,
+                             uint32_t protoID, uint32_t depth);
 
 // Only set allowNativeWrapper to false if you really know you need it, if in
 // doubt use true. Setting it to false disables security wrappers.
 bool
 XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
                    xpcObjectHelper& helper, const nsIID* iid,
                    bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
 
new file mode 100644
--- /dev/null
+++ b/dom/bindings/crashtests/1010658-1.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+/*
+user_pref("dom.window_experimental_bindings", true);
+*/
+
+function boom()
+{
+    window.__proto__ = null;
+    for (var i = 0; i < 10000; ++i) {
+        self.document;
+    }
+}
+
+</script></head>
+
+<body onload="boom();"></body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/bindings/crashtests/1010658-2.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+/*
+user_pref("dom.window_experimental_bindings", true);
+*/
+
+function boom()
+{
+    window.__proto__ = function(){};
+    for (var i = 0; i < 10000; ++i) {
+        self.document;
+    }
+}
+
+</script></head>
+
+<body onload="boom();"></body>
+</html>
--- a/dom/bindings/crashtests/crashtests.list
+++ b/dom/bindings/crashtests/crashtests.list
@@ -3,8 +3,10 @@ load 822340-1.html
 load 822340-2.html
 load 832899.html
 load 860591.html
 load 860551.html
 load 862610.html
 load 862092.html
 load 869038.html
 load 949940.html
+load 1010658-1.html
+load 1010658-2.html
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5193,32 +5193,29 @@ IonBuilder::testShouldDOMCall(types::Typ
                               JSFunction *func, JSJitInfo::OpType opType)
 {
     if (!func->isNative() || !func->jitInfo())
         return false;
 
     // If all the DOM objects flowing through are legal with this
     // property, we can bake in a call to the bottom half of the DOM
     // accessor
-    DOMInstanceClassMatchesProto instanceChecker =
+    DOMInstanceClassHasProtoAtDepth instanceChecker =
         compartment->runtime()->DOMcallbacks()->instanceClassMatchesProto;
 
     const JSJitInfo *jinfo = func->jitInfo();
     if (jinfo->type() != opType)
         return false;
 
     for (unsigned i = 0; i < inTypes->getObjectCount(); i++) {
         types::TypeObjectKey *curType = inTypes->getObject(i);
         if (!curType)
             continue;
 
-        if (!curType->hasTenuredProto())
-            return false;
-        JSObject *proto = curType->proto().toObjectOrNull();
-        if (!instanceChecker(proto, jinfo->protoID, jinfo->depth))
+        if (!instanceChecker(curType->clasp(), jinfo->protoID, jinfo->depth))
             return false;
     }
 
     return true;
 }
 
 static bool
 ArgumentTypesMatch(MDefinition *def, types::StackTypeSet *calleeTypes)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -920,19 +920,20 @@ SetActivityCallback(JSRuntime *rt, Activ
 
 extern JS_FRIEND_API(const JSStructuredCloneCallbacks *)
 GetContextStructuredCloneCallbacks(JSContext *cx);
 
 extern JS_FRIEND_API(bool)
 IsContextRunningJS(JSContext *cx);
 
 typedef bool
-(* DOMInstanceClassMatchesProto)(JSObject *protoObject, uint32_t protoID, uint32_t depth);
+(* DOMInstanceClassHasProtoAtDepth)(const Class *instanceClass,
+                                    uint32_t protoID, uint32_t depth);
 struct JSDOMCallbacks {
-    DOMInstanceClassMatchesProto instanceClassMatchesProto;
+    DOMInstanceClassHasProtoAtDepth instanceClassMatchesProto;
 };
 typedef struct JSDOMCallbacks DOMCallbacks;
 
 extern JS_FRIEND_API(void)
 SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks);
 
 extern JS_FRIEND_API(const DOMCallbacks *)
 GetDOMCallbacks(JSRuntime *rt);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5394,17 +5394,17 @@ dom_constructor(JSContext* cx, unsigned 
 
     InitDOMObject(domObj);
 
     args.rval().setObject(*domObj);
     return true;
 }
 
 static bool
-InstanceClassHasProtoAtDepth(JSObject *protoObject, uint32_t protoID, uint32_t depth)
+InstanceClassHasProtoAtDepth(const Class *clasp, uint32_t protoID, uint32_t depth)
 {
     /* There's only a single (fake) DOM object in the shell, so just return true. */
     return true;
 }
 
 class ScopedFileDesc
 {
     intptr_t fd_;