Fix for bug 838269 (Support cross-global |... instanceof DOMInterface|). r=bz.
authorPeter Van der Beken <peterv@propagandism.org>
Tue, 08 Jan 2013 19:05:36 +0100
changeset 131955 9a12a0f8c8beb183201fddcb993b84159f9f7520
parent 131954 d7996e9773fda31b77707fdca80940caf771d5e4
child 131956 88361e96d89fac2ae50761a193c8b61e984d01ea
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs838269
milestone21.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
Fix for bug 838269 (Support cross-global |... instanceof DOMInterface|). r=bz.
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/bindings/Configuration.py
dom/bindings/DOMJSClass.h
dom/bindings/test/TestBindingHeader.h
dom/bindings/test/TestCodeGen.webidl
dom/bindings/test/TestExampleGen.webidl
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1487,10 +1487,40 @@ GlobalObject::GlobalObject(JSContext* aC
 WorkerGlobalObject::WorkerGlobalObject(JSContext* aCx, JSObject* aObject)
   : mGlobalJSObject(aCx),
     mCx(aCx)
 {
   Maybe<JSAutoCompartment> ac;
   mGlobalJSObject = GetGlobalObject<false>(aCx, aObject, ac);
 }
 
+JSBool
+InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSObject* instance,
+                     JSBool* bp)
+{
+  const DOMIfaceAndProtoJSClass* clasp =
+    DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
+
+  const DOMClass* domClass = GetDOMClass(instance);
+
+  MOZ_ASSERT(!domClass || clasp->mPrototypeID != prototypes::id::_ID_Count,
+             "Why do we have a hasInstance hook if we don't have a prototype "
+             "ID?");
+  *bp = domClass &&
+        domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID;
+
+  return true;
+}
+
+JSBool
+InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue vp,
+                     JSBool* bp)
+{
+  if (!vp.isObject()) {
+    *bp = false;
+    return true;
+  }
+
+  return InterfaceHasInstance(cx, obj, js::UnwrapObject(&vp.toObject()), bp);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1679,12 +1679,24 @@ void SetXrayExpandoChain(JSObject *obj, 
  */
 bool
 NativeToString(JSContext* cx, JSObject* wrapper, JSObject* obj, const char* pre,
                const char* post, JS::Value* v);
 
 nsresult
 ReparentWrapper(JSContext* aCx, JSObject* aObj);
 
+/**
+ * Used to implement the hasInstance hook of an interface object.
+ *
+ * instance should not be a security wrapper.
+ */
+JSBool
+InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSObject* instance,
+                     JSBool* bp);
+JSBool
+InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue vp,
+                     JSBool* bp);
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -15,21 +15,16 @@
 #                  non-worker non-external-or-callback interfaces, to
 #                  "mozilla::dom::workers::InterfaceName" for worker
 #                  non-external interfaces, to 'nsIDOM' followed by the
 #                  interface name for non-worker external-or-callback
 #                  interfaces, and to "JSObject" for worker external-or-callback
 #                  interfaces.
 #   * headerFile - The file in which the nativeType is declared (defaults
 #                  to an educated guess).
-#   * castable - Indicates whether the value in the wrapper can be cast to
-#                nativeType, or whether it needs to be QI-ed (defaults to True
-#                for everything but callback interfaces and external interfaces,
-#                for which it defaults to false and is not allowed to be set
-#                at all).
 #   * concrete - Indicates whether there exist objects with this interface as
 #                their primary interface.  Always False for callback interfaces.
 #                defaults to True otherwise.
 #   * prefable - Indicates whether this bindings should be disabled if the
 #                global pref for Web IDL bindings is set to false.  This is a
 #                risk mitigation strategy and it will cause all of the Web IDL
 #                bindings marked as prefable to fall back to the xpconnect
 #                bindings in case something goes wrong.  This defaults to False.
@@ -152,36 +147,27 @@ DOMInterfaces = {
         'mozFillRule': 'fillRule'
     }
 },
 
 'CaretPosition' : {
     'nativeType': 'nsDOMCaretPosition',
 },
 
-'CDATASection': {
-    'hasInstanceInterface': 'nsIDOMCDATASection',
-},
-
 'CharacterData': {
     'nativeType': 'nsGenericDOMDataNode',
-    'hasInstanceInterface': 'nsIDOMCharacterData',
     'concrete': False
 },
 
 'ClientRectList': {
     'nativeType': 'nsClientRectList',
     'headerFile': 'nsClientRect.h',
     'resultNotAddRefed': [ 'item' ]
 },
 
-'Comment': {
-    'hasInstanceInterface': 'nsIDOMComment',
-},
-
 'CSS': {
     'concrete': False,
 },
 
 'CSS2Properties': {
   'nativeType': 'nsDOMCSSDeclaration'
 },
 
@@ -194,31 +180,29 @@ DOMInterfaces = {
   'nativeType': 'nsICSSDeclaration'
 },
 
 "CSSValue": {
   "concrete": False
 },
 
 "CSSValueList": {
-  "nativeType": "nsDOMCSSValueList",
-  "hasInstanceInterface": "nsIDOMCSSValueList"
+  "nativeType": "nsDOMCSSValueList"
 },
 
 'DelayNode': [
 {
     'resultNotAddRefed': [ 'delayTime' ],
     'wrapperCache': False
 }],
 
 'Document': [
 {
     'nativeType': 'nsIDocument',
     'hasXPConnectImpls': True,
-    'hasInstanceInterface': 'nsIDOMDocument',
     'resultNotAddRefed': [ 'implementation', 'doctype', 'documentElement',
                            'getElementById', 'adoptNode', 'defaultView',
                            'activeElement', 'currentScript',
                            'mozFullScreenElement', 'mozPointerLockElement',
                            'styleSheets', 'styleSheetSets', 'elementFromPoint',
                            'querySelector', 'getAnonymousNodes',
                            'getAnonymousElementByAtribute', 'getBindingParent'
                            ]
@@ -232,20 +216,16 @@ DOMInterfaces = {
 'DOMParser': {
     'nativeType': 'nsDOMParser',
 },
 
 'DocumentFragment': {
     'resultNotAddRefed': [ 'querySelector' ]
 },
 
-'DocumentType': {
-    'hasInstanceInterface': 'nsIDOMDocumentType'
-},
-
 'DOMSettableTokenList': {
     'nativeType': 'nsDOMSettableTokenList',
     'binaryNames': {
         '__stringifier': 'Stringify'
     }
 },
 
 'DOMStringMap': {
@@ -276,17 +256,16 @@ DOMInterfaces = {
     'binaryNames': {
         'release': 'getRelease'
     },
     'wrapperCache': False
 },
 
 'Element': {
     'hasXPConnectImpls': True,
-    'hasInstanceInterface': 'nsIDOMElement',
     'resultNotAddRefed': [
         'classList', 'attributes', 'children', 'firstElementChild',
         'lastElementChild', 'previousElementSibling', 'nextElementSibling',
         'getAttributeNode', 'getAttributeNodeNS', 'querySelector'
     ]
 },
 
 'Event': [
@@ -299,17 +278,16 @@ DOMInterfaces = {
     'nativeType': 'nsIDOMEventListener'
 },
 {
     'workers': True,
 }],
 
 'EventTarget': [
 {
-    'hasInstanceInterface': 'nsIDOMEventTarget',
     'hasXPConnectImpls': True,
     'concrete': False,
 },
 {
     'workers': True,
     'concrete': False
 }],
 
@@ -342,231 +320,122 @@ DOMInterfaces = {
     'nativeType': 'JSObject'
 }],
 
 'GainNode': {
     'resultNotAddRefed': [ 'gain' ],
     'wrapperCache': False
 },
 
-'HTMLAreaElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLAreaElement',
-},
-
 'HTMLAnchorElement': {
     'binaryNames': {
         '__stringifier': 'Stringify'
     },
-    'hasInstanceInterface': 'nsIDOMHTMLAnchorElement',
 },
 
 'HTMLBaseElement': {
     'nativeType': 'mozilla::dom::HTMLSharedElement'
 },
 
-'HTMLBodyElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLBodyElement',
-},
-
-'HTMLBRElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLBRElement',
-},
-
-'HTMLButtonElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLButtonElement',
-},
-
 'HTMLCollection': {
     'nativeType': 'nsIHTMLCollection',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'HTMLDataListElement': {
     'resultNotAddRefed': [
         'options'
     ]
 },
 
 'HTMLDirectoryElement': {
     'nativeType': 'mozilla::dom::HTMLSharedElement'
 },
 
-'HTMLDivElement': {
-  'hasInstanceInterface': 'nsIDOMHTMLDivElement',
-},
-
 'HTMLDListElement': {
     'nativeType' : 'mozilla::dom::HTMLSharedListElement'
 },
 
 'HTMLDocument': {
     'nativeType': 'nsHTMLDocument',
     'register': False,
     'hasXPConnectImpls': True,
-    'hasInstanceInterface': 'nsIDOMHTMLDocument',
     'resultNotAddRefed': [ 'body', 'head', 'images', 'embeds', 'plugins',
                            'links', 'forms', 'scripts', 'anchors', 'applets' ],
     'implicitJSContext': [ 'open', 'write', 'writeln' ]
 },
 
 'HTMLElement': {
     'nativeType': 'nsGenericHTMLElement',
     'hasXPConnectImpls': True,
-    'hasInstanceInterface': 'nsIDOMHTMLElement',
     'resultNotAddRefed': [
         'itemType', 'itemRef', 'itemProp', 'properties', 'contextMenu', 'style',
         'offsetParent'
     ]
 },
 
-'HTMLFieldSetElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLFieldSetElement',
-},
-
-'HTMLFrameSetElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLFrameSetElement',
-},
-
 'HTMLHeadElement': {
     'nativeType': 'mozilla::dom::HTMLSharedElement'
 },
 
-'HTMLHeadingElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLHeadingElement',
-},
-
-'HTMLHRElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLHRElement',
-},
-
 'HTMLHtmlElement': {
     'nativeType': 'mozilla::dom::HTMLSharedElement'
 },
 
-'HTMLImageElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLImageElement',
-},
-
 'HTMLLabelElement': {
     'resultNotAddRefed': [
         'form', 'control'
     ],
-    'hasInstanceInterface': 'nsIDOMHTMLLabelElement',
-},
-
-'HTMLLIElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLLIElement',
-},
-
-'HTMLLinkElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLLinkElement',
-},
-
-'HTMLMapElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLMapElement',
-},
-
-'HTMLMetaElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLMetaElement',
-},
-
-'HTMLMeterElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLMeterElement',
-},
-
-'HTMLModElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLModElement',
 },
 
 'HTMLOListElement': {
-    'nativeType' : 'mozilla::dom::HTMLSharedListElement',
-    'hasInstanceInterface': 'nsIDOMHTMLOListElement'
-},
-
-'HTMLOptGroupElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLOptGroupElement',
+    'nativeType' : 'mozilla::dom::HTMLSharedListElement'
 },
 
 'HTMLOptionsCollection': {
     'nativeType': 'nsHTMLOptionCollection',
     'headerFile': 'nsHTMLSelectElement.h',
     'resultNotAddRefed': [ 'item' ],
     'binaryNames': {
         '__indexedsettercreator': 'SetOption'
     }
 },
 
-'HTMLOutputElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLOutputElement',
-},
-
-'HTMLParagraphElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLParagraphElement',
-},
-
 'HTMLParamElement': {
     'nativeType': 'mozilla::dom::HTMLSharedElement'
 },
 
-'HTMLPreElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLPreElement',
-},
-
-'HTMLProgressElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLProgressElement',
-},
-
 'HTMLPropertiesCollection': {
     'headerFile': 'HTMLPropertiesCollection.h',
     'resultNotAddRefed': [ 'item', 'namedItem', 'names' ]
 },
 
 'HTMLQuoteElement': {
     'nativeType': 'mozilla::dom::HTMLSharedElement'
 },
 
-'HTMLScriptElement': {
-  'hasInstanceInterface': 'nsIDOMHTMLScriptElement',
-},
-
-'HTMLSourceElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLSourceElement',
-},
-
-'HTMLTableCellElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLTableCellElement'
-},
-
-'HTMLTableColElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLTableColElement'
-},
-
 'HTMLTableElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLTableElement',
     'resultNotAddRefed': [
         'caption', 'tHead', 'tFoot', 'tBodies', 'rows'
     ]
 },
 
 'HTMLTableRowElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLTableRowElement',
     'resultNotAddRefed': [
         'cells'
     ]
 },
 
 'HTMLTableSectionElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLTableSectionElement',
     'resultNotAddRefed': [
         'rows'
     ]
 },
 
 'HTMLStyleElement': {
-    'hasInstanceInterface': 'nsIDOMHTMLStyleElement',
     'resultNotAddRefed': [
         'sheet'
     ]
 },
 
 'HTMLUListElement': {
     'nativeType' : 'mozilla::dom::HTMLSharedListElement'
 },
@@ -596,20 +465,16 @@ DOMInterfaces = {
 'Location': {
     # NOTE: Before you turn on codegen for Location, make sure all the
     # Unforgeable stuff is dealt with.
     'nativeType': 'nsIDOMLocation',
     'skipGen': True,
     'register': False
 },
 
-'MediaError': {
-    'hasInstanceInterface': 'nsIDOMMediaError',
-},
-
 'MediaStream': [{
     'headerFile': 'DOMMediaStream.h',
     'nativeType': 'mozilla::DOMMediaStream'
 },
 {
     'nativeType': 'JSObject',
     'workers': True,
     'skipGen': True
@@ -648,17 +513,16 @@ DOMInterfaces = {
     'resultNotAddRefed': [ 'target', 'addedNodes', 'removedNodes',
                            'previousSibling', 'nextSibling' ]
 },
 
 'Node': {
     'nativeType': 'nsINode',
     'concrete': False,
     'hasXPConnectImpls': True,
-    'hasInstanceInterface': 'nsIDOMNode',
     'resultNotAddRefed': [ 'ownerDocument', 'parentNode', 'parentElement',
                            'childNodes', 'firstChild', 'lastChild',
                            'previousSibling', 'nextSibling', 'insertBefore',
                            'appendChild', 'replaceChild', 'removeChild',
                            'attributes' ]
 },
 
 'NodeFilter': {
@@ -699,20 +563,16 @@ DOMInterfaces = {
 },
 
 'PerformanceNavigation': {
     'nativeType': 'nsPerformanceNavigation',
     'headerFile': 'nsPerformance.h',
     'nativeOwnership': 'refcounted'
 },
 
-'ProcessingInstruction': {
-    'hasInstanceInterface': 'nsIDOMProcessingInstruction',
-},
-
 'PropertyNodeList': {
     'headerFile': 'HTMLPropertiesCollection.h',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'Rect': {
     "nativeType": "nsDOMCSSRect",
     'resultNotAddRefed': [ "top", "right", "bottom", "left" ]
@@ -723,20 +583,16 @@ DOMInterfaces = {
     "nativeType": "nsDOMCSSRGBColor",
     'resultNotAddRefed': [ "alpha", "blue", "green", "red" ]
 },
 
 'Screen': {
     'nativeType': 'nsScreen',
 },
 
-'SVGAElement': {
-  'hasInstanceInterface': 'nsIDOMSVGAElement',
-},
-
 'SVGAnimatedLengthList': {
     'nativeType': 'mozilla::DOMSVGAnimatedLengthList',
     'headerFile': 'DOMSVGAnimatedLengthList.h'
 },
 
 'SVGAnimatedNumberList': {
     'nativeType': 'mozilla::DOMSVGAnimatedNumberList',
     'headerFile': 'DOMSVGAnimatedNumberList.h'
@@ -759,17 +615,16 @@ DOMInterfaces = {
 
 'SVGComponentTransferFunctionElement': {
     'concrete': False,
 },
 
 'SVGElement': {
     'nativeType': 'nsSVGElement',
     'hasXPConnectImpls': True,
-    'hasInstanceInterface': 'nsIDOMSVGElement',
     'resultNotAddRefed': ['ownerSVGElement', 'viewportElement', 'style']
 },
 
 'SVGFEFuncAElement': {
     'headerFile': 'mozilla/dom/SVGComponentTransferFunctionElement.h',
 },
 
 'SVGFEFuncBElement': {
@@ -788,20 +643,16 @@ DOMInterfaces = {
     'concrete': False,
     'resultNotAddRefed': ['nearestViewportElement', 'farthestViewportElement']
 },
 
 'SVGGradientElement': {
     'concrete': False,
 },
 
-'SVGImageElement': {
-    'hasInstanceInterface': 'nsIDOMSVGImageElement',
-},
-
 'SVGLengthList': {
     'nativeType': 'mozilla::DOMSVGLengthList',
     'headerFile': 'DOMSVGLengthList.h',
     'resultNotAddRefed': [ 'getItem' ]
 },
 
 'SVGLinearGradientElement': {
     'headerFile': 'mozilla/dom/SVGGradientElement.h',
@@ -943,20 +794,16 @@ DOMInterfaces = {
 'SVGTextContentElement': {
     'concrete': False
 },
 
 'SVGTextPositioningElement': {
     'concrete': False
 },
 
-'SVGTitleElement': {
-  'hasInstanceInterface': 'nsIDOMSVGTitleElement',
-},
-
 'SVGTransform': {
     'nativeType': 'mozilla::DOMSVGTransform',
     'headerFile': 'DOMSVGTransform.h',
     'resultNotAddRefed': [ 'matrix' ]
 },
 
 'SVGTransformList': {
     'nativeType': 'mozilla::DOMSVGTransformList',
@@ -965,17 +812,16 @@ DOMInterfaces = {
 },
 
 'SVGSVGElement': {
     'resultNotAddRefed': [ 'getElementById' ]
 },
 
 'Text': {
     'nativeType': 'nsTextNode',
-    'hasInstanceInterface': 'nsIDOMText',
 },
 
 'TextDecoder': [
 {
     'nativeOwnership': 'refcounted',
 },
 {
     'workers': True,
@@ -1146,18 +992,17 @@ DOMInterfaces = {
 'XPathEvaluator': {
     'nativeType': 'nsXPathEvaluator',
     'headerFile': 'nsXPathEvaluator.h',
     'wrapperCache': False
 },
 
 'XULElement': {
     'nativeType': 'nsXULElement',
-    'resultNotAddRefed': [ 'controllers', 'style' ],
-    'hasInstanceInterface': 'nsIDOMXULElement',
+    'resultNotAddRefed': [ 'controllers', 'style' ]
 },
 
 ####################################
 # Test Interfaces of various sorts #
 ####################################
 
 'TestInterface' : {
         # Keep this in sync with TestExampleInterface
@@ -1178,22 +1023,16 @@ DOMInterfaces = {
                          '__stringifier' : 'Stringify' }
         },
 
 'TestChildInterface' : {
         'headerFile': 'TestBindingHeader.h',
         'register': False,
         },
 
-'TestNonCastableInterface' : {
-        'headerFile': 'TestBindingHeader.h',
-        'register': False,
-        'castable': False
-        },
-
 'TestExternalInterface' : {
         'nativeType': 'mozilla::dom::TestExternalInterface',
         'headerFile': 'TestBindingHeader.h',
         'register': False
         },
 
 'TestNonWrapperCacheInterface' : {
         'headerFile': 'TestBindingHeader.h',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -178,25 +178,38 @@ DOMJSClass Class = {
   },
 %s
 };
 """ % (self.descriptor.interface.identifier.name,
        ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers and self.descriptor.wrapperCache else 'JS_PropertyStub',
        FINALIZE_HOOK_NAME, traceHook,
        CGIndenter(CGGeneric(DOMClass(self.descriptor))).define())
 
+def PrototypeIDAndDepth(descriptor):
+    prototypeID = "prototypes::id::"
+    if descriptor.interface.hasInterfacePrototypeObject():
+        prototypeID += descriptor.interface.identifier.name
+        if descriptor.workers:
+            prototypeID += "_workers"
+        depth = "PrototypeTraits<%s>::Depth" % prototypeID
+    else:
+        prototypeID += "_ID_Count"
+        depth = "0"
+    return (prototypeID, depth)
+
 class CGPrototypeJSClass(CGThing):
     def __init__(self, descriptor, properties):
         CGThing.__init__(self)
         self.descriptor = descriptor
         self.properties = properties
     def declare(self):
         # We're purely for internal consumption
         return ""
     def define(self):
+        (prototypeID, depth) = PrototypeIDAndDepth(self.descriptor)
         return """static DOMIfaceAndProtoJSClass PrototypeClass = {
   {
     "%sPrototype",
     JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
     JS_PropertyStub,       /* addProperty */
     JS_PropertyStub,       /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
@@ -208,38 +221,49 @@ class CGPrototypeJSClass(CGThing):
     nullptr,               /* call */
     nullptr,               /* hasInstance */
     nullptr,               /* construct */
     nullptr,               /* trace */
     JSCLASS_NO_INTERNAL_MEMBERS
   },
   eInterfacePrototype,
   %s,
-  "[object %sPrototype]"
+  "[object %sPrototype]",
+  %s,
+  %s
 };
 """ % (self.descriptor.interface.identifier.name,
        NativePropertyHooks(self.descriptor),
-       self.descriptor.interface.identifier.name)
+       self.descriptor.interface.identifier.name,
+       prototypeID, depth)
+
+def NeedsGeneratedHasInstance(descriptor):
+    return descriptor.hasXPConnectImpls or descriptor.interface.isConsequential()
 
 class CGInterfaceObjectJSClass(CGThing):
     def __init__(self, descriptor, properties):
         CGThing.__init__(self)
         self.descriptor = descriptor
         self.properties = properties
     def declare(self):
         # We're purely for internal consumption
         return ""
     def define(self):
-        if not self.descriptor.hasInstanceInterface:
-            return ""
         if self.descriptor.interface.ctor():
             ctorname = CONSTRUCT_HOOK_NAME
         else:
             ctorname = "ThrowingConstructor"
-        hasinstance = HASINSTANCE_HOOK_NAME
+        if NeedsGeneratedHasInstance(self.descriptor):
+            assert self.descriptor.interface.hasInterfacePrototypeObject()
+            hasinstance = HASINSTANCE_HOOK_NAME
+        elif self.descriptor.interface.hasInterfacePrototypeObject():
+            hasinstance = "InterfaceHasInstance"
+        else:
+            hasinstance = "nullptr"
+        (prototypeID, depth) = PrototypeIDAndDepth(self.descriptor)
         return """
 static DOMIfaceAndProtoJSClass InterfaceObjectClass = {
   {
     "Function",
     JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2),
     JS_PropertyStub,       /* addProperty */
     JS_PropertyStub,       /* delProperty */
     JS_PropertyStub,       /* getProperty */
@@ -252,20 +276,23 @@ static DOMIfaceAndProtoJSClass Interface
     %s, /* call */
     %s, /* hasInstance */
     %s, /* construct */
     nullptr,               /* trace */
     JSCLASS_NO_INTERNAL_MEMBERS
   },
   eInterface,
   %s,
-  "function %s() {\\n    [native code]\\n}"
+  "function %s() {\\n    [native code]\\n}",
+  %s,
+  %s
 };
 """ % (ctorname, hasinstance, ctorname, NativePropertyHooks(self.descriptor),
-       self.descriptor.interface.identifier.name)
+       self.descriptor.interface.identifier.name,
+       prototypeID, depth)
 
 class CGList(CGThing):
     """
     Generate code for a list of GCThings.  Just concatenates them together, with
     an optional joiner string.  "\n" is a common joiner.
     """
     def __init__(self, children, joiner=""):
         CGThing.__init__(self)
@@ -441,19 +468,19 @@ class CGHeaders(CGWrapper):
                 ancestors.append(iface.parent)
                 iface = iface.parent
         interfaceDeps.extend(ancestors)
         bindingIncludes = set(self.getDeclarationFilename(d) for d in interfaceDeps)
 
         # Grab all the implementation declaration files we need.
         implementationIncludes = set(d.headerFile for d in descriptors)
 
-        # Grab the includes for the things that involve hasInstanceInterface
-        hasInstanceIncludes = set(d.hasInstanceInterface + ".h" for d
-                                  in descriptors if d.hasInstanceInterface)
+        # Grab the includes for the things that involve XPCOM interfaces
+        hasInstanceIncludes = set("nsIDOM" + d.interface.identifier.name + ".h" for d
+                                  in descriptors if NeedsGeneratedHasInstance(d))
 
         # Now find all the things we'll need as arguments because we
         # need to wrap or unwrap them.
         bindingHeaders = set()
         def addHeadersForType(t, descriptor=None, dictionary=None):
             """
             Add the relevant headers for this type.  We use descriptor and
             dictionary, if passed, to decide what to do with interface types.
@@ -930,60 +957,43 @@ class CGClassConstructHookHolder(CGGener
 class CGClassHasInstanceHook(CGAbstractStaticMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'),
                 Argument('JSMutableHandleValue', 'vp'), Argument('JSBool*', 'bp')]
         CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
                                         'JSBool', args)
 
     def define(self):
-        if not self.descriptor.hasInstanceInterface:
+        if not NeedsGeneratedHasInstance(self.descriptor):
             return ""
         return CGAbstractStaticMethod.define(self)
 
     def definition_body(self):
         return self.generate_code()
 
     def generate_code(self):
         assert self.descriptor.nativeOwnership == 'nsisupports'
         return """  if (!vp.isObject()) {
     *bp = false;
     return true;
   }
 
-  jsval protov;
-  if (!JS_GetProperty(cx, obj, "prototype", &protov))
-    return false;
-  if (!protov.isObject()) {
-    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE,
-                         "%s");
-    return false;
-  }
-  JSObject *objProto = &protov.toObject();
-
-  JSObject* instance = &vp.toObject();
-  JSObject* proto;
-  if (!JS_GetPrototype(cx, instance, &proto))
-    return false;
-  while (proto) {
-    if (proto == objProto) {
-      *bp = true;
-      return true;
-    }
-    if (!JS_GetPrototype(cx, proto, &proto))
-      return false;
+  JSObject* instance = js::UnwrapObject(&vp.toObject());
+
+  bool ok = InterfaceHasInstance(cx, obj, instance, bp);
+  if (!ok || *bp) {
+    return ok;
   }
 
   // FIXME Limit this to chrome by checking xpc::AccessCheck::isChrome(obj).
   nsISupports* native =
     nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, instance);
-  nsCOMPtr<%s> qiResult = do_QueryInterface(native);
+  nsCOMPtr<nsIDOM%s> qiResult = do_QueryInterface(native);
   *bp = !!qiResult;
-  return true;
-""" % (self.descriptor.name, self.descriptor.hasInstanceInterface)
+  return true;""" % self.descriptor.interface.identifier.name
 
 def isChromeOnly(m):
     return m.getExtendedAttribute("ChromeOnly")
 
 class PropertyDefiner:
     """
     A common superclass for defining things on prototype objects.
 
@@ -1468,22 +1478,20 @@ class CGCreateInterfaceObjectsMethod(CGA
 
         if needInterfacePrototypeObject:
             protoClass = "&PrototypeClass.mBase"
             protoCache = "&protoAndIfaceArray[prototypes::id::%s]" % self.descriptor.name
         else:
             protoClass = "nullptr"
             protoCache = "nullptr"
         if needInterfaceObject:
-            if self.descriptor.hasInstanceInterface:
-                interfaceClass = "&InterfaceObjectClass.mBase"
-            elif self.descriptor.interface.isCallback():
+            if self.descriptor.interface.isCallback():
                 interfaceClass = "js::Jsvalify(&js::ObjectClass)"
             else:
-                interfaceClass = "nullptr"
+                interfaceClass = "&InterfaceObjectClass.mBase"
             interfaceCache = "&protoAndIfaceArray[constructors::id::%s]" % self.descriptor.name
         else:
             interfaceClass = "nullptr"
             interfaceCache = "nullptr"
 
         if self.descriptor.concrete:
             if self.descriptor.proxy:
                 domClass = "&Class"
@@ -1846,18 +1854,16 @@ class CastableObjectUnwrapper():
     """
     A class for unwrapping an object named by the "source" argument
     based on the passed-in descriptor and storing it in a variable
     called by the name in the "target" argument.
 
     codeOnFailure is the code to run if unwrapping fails.
     """
     def __init__(self, descriptor, source, target, codeOnFailure):
-        assert descriptor.castable
-
         self.substitution = { "type" : descriptor.nativeType,
                               "protoID" : "prototypes::id::" + descriptor.name,
                               "source" : source,
                               "target" : target,
                               "codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure), 4).define() }
         if descriptor.hasXPConnectImpls:
             # We don't use xpc_qsUnwrapThis because it will always throw on
             # unwrap failure, whereas we want to control whether we throw or
@@ -2536,45 +2542,41 @@ for (uint32_t i = 0; i < length; ++i) {
                 declType = typePtr
         else:
             if forceOwningType:
                 declType = "OwningNonNull<" + typeName + ">"
             else:
                 declType = "NonNull<" + typeName + ">"
 
         templateBody = ""
-        if descriptor.castable:
+        if descriptor.interface.isCallback():
+            templateBody += str(CallbackObjectUnwrapper(
+                    descriptor,
+                    "&${val}.toObject()",
+                    "${declName}",
+                    exceptionCode,
+                    codeOnFailure=failureCode))
+        elif not descriptor.skipGen and not descriptor.interface.isConsequential() and not descriptor.interface.isExternal():
             if descriptor.prefable and not descriptor.hasXPConnectImpls:
                 raise TypeError("We don't support prefable castable object "
                                 "arguments (like %s), because we don't know "
                                 "how to handle them being preffed off" %
                                 descriptor.interface.identifier.name)
-            if descriptor.interface.isConsequential():
-                raise TypeError("Consequential interface %s being used as an "
-                                "argument but flagged as castable" %
-                                descriptor.interface.identifier.name)
             if failureCode is not None:
                 templateBody += str(CastableObjectUnwrapper(
                         descriptor,
                         "&${val}.toObject()",
                         "${declName}",
                         failureCode))
             else:
                 templateBody += str(FailureFatalCastableObjectUnwrapper(
                         descriptor,
                         "&${val}.toObject()",
                         "${declName}",
                         exceptionCode))
-        elif descriptor.interface.isCallback():
-            templateBody += str(CallbackObjectUnwrapper(
-                    descriptor,
-                    "&${val}.toObject()",
-                    "${declName}",
-                    exceptionCode,
-                    codeOnFailure=failureCode))
         elif descriptor.workers:
             templateBody += "${declName} = &${val}.toObject();"
         else:
             # Either external, or new-binding non-castable.  We always have a
             # holder for these, because we don't actually know whether we have
             # to addref when unwrapping or not.  So we just pass an
             # getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release
             # it'll put a non-null pointer in there.
@@ -4212,24 +4214,16 @@ class CGSetterCall(CGPerSignatureCall):
         # We have no return value
         return "\nreturn true;"
     def getArgc(self):
         return "1"
     def getArgvDecl(self):
         # We just get our stuff from our last arg no matter what
         return ""
 
-class FakeCastableDescriptor():
-    def __init__(self, descriptor):
-        self.castable = True
-        self.workers = descriptor.workers
-        self.nativeType = descriptor.nativeType
-        self.name = descriptor.name
-        self.hasXPConnectImpls = descriptor.hasXPConnectImpls
-
 class CGAbstractBindingMethod(CGAbstractStaticMethod):
     """
     Common class to generate the JSNatives for all our methods, getters, and
     setters.  This will generate the function declaration and unwrap the
     |this| object.  Subclasses are expected to override the generate_code
     function to do the rest of the work.  This function should return a
     CGThing which is already properly indented.
     """
@@ -4249,17 +4243,17 @@ class CGAbstractBindingMethod(CGAbstract
         getThis = CGGeneric("""js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
 if (!obj) {
   return false;
 }
 
 %s* self;""" % self.descriptor.nativeType)
         unwrapThis = CGGeneric(
             str(CastableObjectUnwrapper(
-                        FakeCastableDescriptor(self.descriptor),
+                        self.descriptor,
                         "obj", "self", self.unwrapFailureCode)))
         return CGList([ CGIndenter(getThis), CGIndenter(unwrapThis),
                         self.generate_code() ], "\n").define()
 
     def generate_code(self):
         assert(False) # Override me
 
 class CGAbstractStaticBindingMethod(CGAbstractStaticMethod):
@@ -6413,17 +6407,18 @@ class CGDescriptor(CGThing):
         cgThings.append(CGGeneric(define=str(properties)))
         cgThings.append(CGNativeProperties(descriptor, properties))
 
         cgThings.append(CGNativePropertyHooks(descriptor, properties))
 
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGClassConstructHook(descriptor))
             cgThings.append(CGClassHasInstanceHook(descriptor))
-            cgThings.append(CGInterfaceObjectJSClass(descriptor, properties))
+            if not descriptor.interface.isCallback():
+                cgThings.append(CGInterfaceObjectJSClass(descriptor, properties))
             if descriptor.needsConstructHookHolder():
                 cgThings.append(CGClassConstructHookHolder(descriptor))
 
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGPrototypeJSClass(descriptor, properties))
 
         cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
         if descriptor.interface.hasInterfacePrototypeObject():
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -202,17 +202,16 @@ class Descriptor(DescriptorProvider):
                 nativeTypeDefault = "mozilla::dom::" + ifaceName
         else:
             if self.workers:
                 nativeTypeDefault = "mozilla::dom::workers::" + ifaceName
             else:
                 nativeTypeDefault = "mozilla::dom::" + ifaceName
 
         self.nativeType = desc.get('nativeType', nativeTypeDefault)
-        self.hasInstanceInterface = desc.get('hasInstanceInterface', None)
 
         # Do something sane for JSObject
         if self.nativeType == "JSObject":
             headerDefault = "jsapi.h"
         elif self.interface.isCallback():
             # A copy of CGHeaders.getDeclarationFilename; we can't
             # import it here, sadly.
             # Use our local version of the header, not the exported one, so that
@@ -224,26 +223,16 @@ class Descriptor(DescriptorProvider):
                 headerDefault = "mozilla/dom/workers/bindings/%s.h" % ifaceName
             else:
                 headerDefault = self.nativeType
                 headerDefault = headerDefault.replace("::", "/") + ".h"
         self.headerFile = desc.get('headerFile', headerDefault)
 
         self.skipGen = desc.get('skipGen', False)
 
-        if (self.interface.isCallback() or self.interface.isExternal() or
-            self.skipGen):
-            if 'castable' in desc:
-                raise TypeError("%s is external or callback or skipGen but has "
-                                "a castable setting" %
-                                self.interface.identifier.name)
-            self.castable = False
-        else:
-            self.castable = desc.get('castable', True)
-
         self.notflattened = desc.get('notflattened', False)
         self.register = desc.get('register', True)
 
         self.hasXPConnectImpls = desc.get('hasXPConnectImpls', False)
 
         # If we're concrete, we need to crawl our ancestor interfaces and mark
         # them as having a concrete descendant.
         self.concrete = (not self.interface.isExternal() and
@@ -435,17 +424,17 @@ class Descriptor(DescriptorProvider):
     def supportsIndexedProperties(self):
         return self.operations['IndexedGetter'] is not None
 
     def supportsNamedProperties(self):
         return self.operations['NamedGetter'] is not None
 
     def needsConstructHookHolder(self):
         assert self.interface.hasInterfaceObject()
-        return not self.hasInstanceInterface and not self.interface.isCallback()
+        return False
 
 # Some utility methods
 def getTypesFromDescriptor(descriptor):
     """
     Get all argument and return types for all members of the descriptor
     """
     members = [m for m in descriptor.interface.members]
     if descriptor.interface.ctor():
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -203,16 +203,19 @@ struct DOMIfaceAndProtoJSClass
   DOMObjectType mType;
 
   const NativePropertyHooks* mNativeHooks;
 
   // The value to return for toString() on this interface or interface prototype
   // object.
   const char* mToString;
 
+  const prototypes::ID mPrototypeID;
+  const uint32_t mDepth;
+
   static const DOMIfaceAndProtoJSClass* FromJSClass(const JSClass* base) {
     MOZ_ASSERT(base->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS);
     return reinterpret_cast<const DOMIfaceAndProtoJSClass*>(base);
   }
   static const DOMIfaceAndProtoJSClass* FromJSClass(const js::Class* base) {
     return FromJSClass(Jsvalify(base));
   }
 
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -14,32 +14,16 @@
 #include "nsCOMPtr.h"
 // We don't export TestCodeGenBinding.h, but it's right in our parent dir.
 #include "../TestCodeGenBinding.h"
 #include "mozilla/dom/UnionTypes.h"
 
 namespace mozilla {
 namespace dom {
 
-// IID for the TestNonCastableInterface
-#define NS_TEST_NONCASTABLE_INTERFACE_IID \
-{ 0x7c9f8ee2, 0xc9bf, 0x46ca, \
- { 0xa0, 0xa9, 0x03, 0xa8, 0xd6, 0x30, 0x0e, 0xde } }
-
-class TestNonCastableInterface : public nsISupports,
-                                 public nsWrapperCache
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_TEST_NONCASTABLE_INTERFACE_IID)
-  NS_DECL_ISUPPORTS
-
-  // We need a GetParentObject to make binding codegen happy
-  virtual nsISupports* GetParentObject();
-};
-
 // IID for nsRenamedInterface
 #define NS_RENAMED_INTERFACE_IID \
 { 0xd4b19ef3, 0xe68b, 0x4e3f, \
  { 0x94, 0xbc, 0xc9, 0xde, 0x3a, 0x69, 0xb0, 0xe8 } }
 
 class nsRenamedInterface : public nsISupports,
                            public nsWrapperCache
 {
@@ -120,17 +104,17 @@ public:
   already_AddRefed<TestInterface>
     Constructor(const GlobalObject&, uint32_t, const Nullable<bool>&,
                 ErrorResult&);
   static
   already_AddRefed<TestInterface>
     Constructor(const GlobalObject&, TestInterface*, ErrorResult&);
   static
   already_AddRefed<TestInterface>
-    Constructor(const GlobalObject&, TestNonCastableInterface&, ErrorResult&);
+    Constructor(const GlobalObject&, uint32_t, IndirectlyImplementedInterface&, ErrorResult&);
   /*  static
   already_AddRefed<TestInterface>
     Constructor(const GlobalObject&, uint32_t, uint32_t,
                 const TestInterfaceOrOnlyForUseInConstructor&, ErrorResult&);
   */
   
   // Integer types
   int8_t ReadonlyByte();
@@ -255,30 +239,30 @@ public:
 
   already_AddRefed<TestNonWrapperCacheInterface> ReceiveNonWrapperCacheInterface();
   already_AddRefed<TestNonWrapperCacheInterface> ReceiveNullableNonWrapperCacheInterface();
   void ReceiveNonWrapperCacheInterfaceSequence(nsTArray<nsRefPtr<TestNonWrapperCacheInterface> >&);
   void ReceiveNullableNonWrapperCacheInterfaceSequence(nsTArray<nsRefPtr<TestNonWrapperCacheInterface> >&);
   void ReceiveNonWrapperCacheInterfaceNullableSequence(Nullable<nsTArray<nsRefPtr<TestNonWrapperCacheInterface> > >&);
   void ReceiveNullableNonWrapperCacheInterfaceNullableSequence(Nullable<nsTArray<nsRefPtr<TestNonWrapperCacheInterface> > >&);
 
-  already_AddRefed<TestNonCastableInterface> ReceiveOther();
-  already_AddRefed<TestNonCastableInterface> ReceiveNullableOther();
-  TestNonCastableInterface* ReceiveWeakOther();
-  TestNonCastableInterface* ReceiveWeakNullableOther();
-  void PassOther(TestNonCastableInterface&);
-  void PassOther2(NonNull<TestNonCastableInterface>&);
-  void PassNullableOther(TestNonCastableInterface*);
-  already_AddRefed<TestNonCastableInterface> NonNullOther();
-  void SetNonNullOther(TestNonCastableInterface&);
-  already_AddRefed<TestNonCastableInterface> GetNullableOther();
-  void SetNullableOther(TestNonCastableInterface*);
-  void PassOptionalOther(const Optional<TestNonCastableInterface*>&);
-  void PassOptionalNonNullOther(const Optional<NonNull<TestNonCastableInterface> >&);
-  void PassOptionalOtherWithDefault(TestNonCastableInterface*);
+  already_AddRefed<IndirectlyImplementedInterface> ReceiveOther();
+  already_AddRefed<IndirectlyImplementedInterface> ReceiveNullableOther();
+  IndirectlyImplementedInterface* ReceiveWeakOther();
+  IndirectlyImplementedInterface* ReceiveWeakNullableOther();
+  void PassOther(IndirectlyImplementedInterface&);
+  void PassOther2(NonNull<IndirectlyImplementedInterface>&);
+  void PassNullableOther(IndirectlyImplementedInterface*);
+  already_AddRefed<IndirectlyImplementedInterface> NonNullOther();
+  void SetNonNullOther(IndirectlyImplementedInterface&);
+  already_AddRefed<IndirectlyImplementedInterface> GetNullableOther();
+  void SetNullableOther(IndirectlyImplementedInterface*);
+  void PassOptionalOther(const Optional<IndirectlyImplementedInterface*>&);
+  void PassOptionalNonNullOther(const Optional<NonNull<IndirectlyImplementedInterface> >&);
+  void PassOptionalOtherWithDefault(IndirectlyImplementedInterface*);
 
   already_AddRefed<TestExternalInterface> ReceiveExternal();
   already_AddRefed<TestExternalInterface> ReceiveNullableExternal();
   TestExternalInterface* ReceiveWeakExternal();
   TestExternalInterface* ReceiveWeakNullableExternal();
   void PassExternal(TestExternalInterface*);
   void PassExternal2(TestExternalInterface*);
   void PassNullableExternal(TestExternalInterface*);
@@ -619,18 +603,18 @@ private:
   void PassOptionalLong(Optional<int32_t>&) MOZ_DELETE;
   void PassOptionalLongLong(Optional<int64_t>&) MOZ_DELETE;
   void PassOptionalOctet(Optional<uint8_t>&) MOZ_DELETE;
   void PassOptionalUnsignedShort(Optional<uint16_t>&) MOZ_DELETE;
   void PassOptionalUnsignedLong(Optional<uint32_t>&) MOZ_DELETE;
   void PassOptionalUnsignedLongLong(Optional<uint64_t>&) MOZ_DELETE;
   void PassOptionalSelf(Optional<TestInterface*> &) MOZ_DELETE;
   void PassOptionalNonNullSelf(Optional<NonNull<TestInterface> >&) MOZ_DELETE;
-  void PassOptionalOther(Optional<TestNonCastableInterface*>&);
-  void PassOptionalNonNullOther(Optional<NonNull<TestNonCastableInterface> >&);
+  void PassOptionalOther(Optional<IndirectlyImplementedInterface*>&);
+  void PassOptionalNonNullOther(Optional<NonNull<IndirectlyImplementedInterface> >&);
   void PassOptionalExternal(Optional<TestExternalInterface*>&) MOZ_DELETE;
   void PassOptionalNonNullExternal(Optional<TestExternalInterface*>&) MOZ_DELETE;
   void PassOptionalSequence(Optional<Sequence<int32_t> >&) MOZ_DELETE;
   void PassOptionalNullableSequence(Optional<Nullable<Sequence<int32_t> > >&) MOZ_DELETE;
   void PassOptionalObjectSequence(Optional<Sequence<OwningNonNull<TestInterface> > >&) MOZ_DELETE;
   void PassOptionalArrayBuffer(Optional<ArrayBuffer>&) MOZ_DELETE;
   void PassOptionalNullableArrayBuffer(Optional<ArrayBuffer*>&) MOZ_DELETE;
   void PassOptionalEnum(Optional<TestEnum>&) MOZ_DELETE;
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -5,19 +5,16 @@
  */
 
 typedef long myLong;
 typedef TestInterface AnotherNameForTestInterface;
 typedef TestInterface? NullableTestInterface;
 
 interface TestExternalInterface;
 
-interface TestNonCastableInterface {
-};
-
 interface TestRenamedInterface {
 };
 
 callback interface TestCallbackInterface {
   readonly attribute long foo;
   attribute DOMString bar;
   void doSomething();
   long doSomethingElse(DOMString arg, TestInterface otherArg);
@@ -87,17 +84,17 @@ TestInterface implements ImplementedInte
 // This interface is only for use in the constructor below
 interface OnlyForUseInConstructor {
 };
 
 [Constructor,
  Constructor(DOMString str),
  Constructor(unsigned long num, boolean? boolArg),
  Constructor(TestInterface? iface),
- Constructor(TestNonCastableInterface iface)
+ Constructor(long arg1, IndirectlyImplementedInterface iface)
  // , Constructor(long arg1, long arg2, (TestInterface or OnlyForUseInConstructor) arg3)
  ]
 interface TestInterface {
   // Integer types
   // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
@@ -219,31 +216,31 @@ interface TestInterface {
   [Creator]
   sequence<TestNonWrapperCacheInterface?> receiveNullableNonWrapperCacheInterfaceSequence();
   [Creator]
   sequence<TestNonWrapperCacheInterface>? receiveNonWrapperCacheInterfaceNullableSequence();
   [Creator]
   sequence<TestNonWrapperCacheInterface?>? receiveNullableNonWrapperCacheInterfaceNullableSequence();
 
   // Non-castable interface types
-  TestNonCastableInterface receiveOther();
-  TestNonCastableInterface? receiveNullableOther();
-  TestNonCastableInterface receiveWeakOther();
-  TestNonCastableInterface? receiveWeakNullableOther();
-  // A verstion to test for casting to TestNonCastableInterface&
-  void passOther(TestNonCastableInterface arg);
+  IndirectlyImplementedInterface receiveOther();
+  IndirectlyImplementedInterface? receiveNullableOther();
+  IndirectlyImplementedInterface receiveWeakOther();
+  IndirectlyImplementedInterface? receiveWeakNullableOther();
+  // A verstion to test for casting to IndirectlyImplementedInterface&
+  void passOther(IndirectlyImplementedInterface arg);
   // A version we can use to test for the exact type passed in
-  void passOther2(TestNonCastableInterface arg);
-  void passNullableOther(TestNonCastableInterface? arg);
-  attribute TestNonCastableInterface nonNullOther;
-  attribute TestNonCastableInterface? nullableOther;
+  void passOther2(IndirectlyImplementedInterface arg);
+  void passNullableOther(IndirectlyImplementedInterface? arg);
+  attribute IndirectlyImplementedInterface nonNullOther;
+  attribute IndirectlyImplementedInterface? nullableOther;
   // Optional arguments
-  void passOptionalOther(optional TestNonCastableInterface? arg);
-  void passOptionalNonNullOther(optional TestNonCastableInterface arg);
-  void passOptionalOtherWithDefault(optional TestNonCastableInterface? arg = null);
+  void passOptionalOther(optional IndirectlyImplementedInterface? arg);
+  void passOptionalNonNullOther(optional IndirectlyImplementedInterface arg);
+  void passOptionalOtherWithDefault(optional IndirectlyImplementedInterface? arg = null);
 
   // External interface types
   TestExternalInterface receiveExternal();
   TestExternalInterface? receiveNullableExternal();
   TestExternalInterface receiveWeakExternal();
   TestExternalInterface? receiveWeakNullableExternal();
   // A verstion to test for casting to TestExternalInterface&
   void passExternal(TestExternalInterface arg);
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -2,17 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 [Constructor,
  Constructor(DOMString str),
  Constructor(unsigned long num, boolean? boolArg),
  Constructor(TestInterface? iface),
- Constructor(TestNonCastableInterface iface)
+ Constructor(long arg1, IndirectlyImplementedInterface iface)
  // , Constructor(long arg1, long arg2, (TestInterface or OnlyForUseInConstructor) arg3)
  ]
 interface TestExampleInterface {
   // Integer types
   // XXXbz add tests for throwing versions of all the integer stuff
   readonly attribute byte readonlyByte;
   attribute byte writableByte;
   void passByte(byte arg);
@@ -134,31 +134,31 @@ interface TestExampleInterface {
   [Creator]
   sequence<TestNonWrapperCacheInterface?> receiveNullableNonWrapperCacheInterfaceSequence();
   [Creator]
   sequence<TestNonWrapperCacheInterface>? receiveNonWrapperCacheInterfaceNullableSequence();
   [Creator]
   sequence<TestNonWrapperCacheInterface?>? receiveNullableNonWrapperCacheInterfaceNullableSequence();
 
   // Non-castable interface types
-  TestNonCastableInterface receiveOther();
-  TestNonCastableInterface? receiveNullableOther();
-  TestNonCastableInterface receiveWeakOther();
-  TestNonCastableInterface? receiveWeakNullableOther();
-  // A verstion to test for casting to TestNonCastableInterface&
-  void passOther(TestNonCastableInterface arg);
+  IndirectlyImplementedInterface receiveOther();
+  IndirectlyImplementedInterface? receiveNullableOther();
+  IndirectlyImplementedInterface receiveWeakOther();
+  IndirectlyImplementedInterface? receiveWeakNullableOther();
+  // A verstion to test for casting to IndirectlyImplementedInterface&
+  void passOther(IndirectlyImplementedInterface arg);
   // A version we can use to test for the exact type passed in
-  void passOther2(TestNonCastableInterface arg);
-  void passNullableOther(TestNonCastableInterface? arg);
-  attribute TestNonCastableInterface nonNullOther;
-  attribute TestNonCastableInterface? nullableOther;
+  void passOther2(IndirectlyImplementedInterface arg);
+  void passNullableOther(IndirectlyImplementedInterface? arg);
+  attribute IndirectlyImplementedInterface nonNullOther;
+  attribute IndirectlyImplementedInterface? nullableOther;
   // Optional arguments
-  void passOptionalOther(optional TestNonCastableInterface? arg);
-  void passOptionalNonNullOther(optional TestNonCastableInterface arg);
-  void passOptionalOtherWithDefault(optional TestNonCastableInterface? arg = null);
+  void passOptionalOther(optional IndirectlyImplementedInterface? arg);
+  void passOptionalNonNullOther(optional IndirectlyImplementedInterface arg);
+  void passOptionalOtherWithDefault(optional IndirectlyImplementedInterface? arg = null);
 
   // External interface types
   TestExternalInterface receiveExternal();
   TestExternalInterface? receiveNullableExternal();
   TestExternalInterface receiveWeakExternal();
   TestExternalInterface? receiveWeakNullableExternal();
   // A verstion to test for casting to TestExternalInterface&
   void passExternal(TestExternalInterface arg);