Backed out 6 changesets (bug 1088228) for static analysis bustage
authorWes Kocher <wkocher@mozilla.com>
Thu, 30 Oct 2014 16:24:02 -0700
changeset 213246 a37fedd51b7d388a8401467c3fbb020cd8c2b2a1
parent 213245 90f7e5edc3670e22b2429930684d1967d812d4f1
child 213247 6742368cd098145f52a3012adbbeac6f1fdc2b46
child 213328 6bd2071b373f808c04a37fb29c5ea9e5ed89def9
push id51180
push userkwierso@gmail.com
push dateThu, 30 Oct 2014 23:24:09 +0000
treeherdermozilla-inbound@a37fedd51b7d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1088228
milestone36.0a1
backs out13ecff8001149ea961c4490af1a99fe03195d1d9
de692c3335f2c67402d155a6b512cab4b7b88e70
2d449a2b4e1cc684f316f2ad116e352497f6798e
49ac8f33ab70633088ef1121f9646d5dac9294a6
920d50e84a17f9198e05b559314751da78b1bcf5
55f4818378e45014be126d54b1c236a4cdb844c0
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
Backed out 6 changesets (bug 1088228) for static analysis bustage Backed out changeset 13ecff800114 (bug 1088228) Backed out changeset de692c3335f2 (bug 1088228) Backed out changeset 2d449a2b4e1c (bug 1088228) Backed out changeset 49ac8f33ab70 (bug 1088228) Backed out changeset 920d50e84a17 (bug 1088228) Backed out changeset 55f4818378e4 (bug 1088228)
dom/base/Element.cpp
dom/base/Element.h
dom/base/nsIDocument.h
dom/base/nsINode.cpp
dom/base/nsINode.h
dom/base/nsJSUtils.cpp
dom/base/nsJSUtils.h
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/events/EventListenerManager.cpp
dom/html/HTMLLegendElement.cpp
dom/html/HTMLLegendElement.h
dom/html/nsGenericHTMLElement.cpp
dom/html/nsGenericHTMLElement.h
dom/xbl/nsXBLProtoImplMethod.cpp
dom/xbl/nsXBLPrototypeHandler.cpp
dom/xul/nsXULElement.h
js/src/jsapi.cpp
js/src/jsapi.h
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -495,23 +495,16 @@ Element::WrapObject(JSContext *aCx)
           NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler));
       }
     }
   }
 
   return obj;
 }
 
-/* virtual */
-nsINode*
-Element::GetScopeChainParent() const
-{
-  return OwnerDoc();
-}
-
 nsDOMTokenList*
 Element::ClassList()
 {
   Element::nsDOMSlots* slots = DOMSlots();
 
   if (!slots->mClassList) {
     slots->mClassList = new nsDOMTokenList(this, nsGkAtoms::_class);
   }
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -134,18 +134,18 @@ class AnimationPlayer;
 class Link;
 class UndoManager;
 class DOMRect;
 class DOMRectList;
 class DestinationInsertionPointList;
 
 // IID for the dom::Element interface
 #define NS_ELEMENT_IID \
-{ 0x31d3f3fb, 0xcdf8, 0x4e40, \
- { 0xb7, 0x09, 0x1a, 0x11, 0x43, 0x93, 0x61, 0x71 } }
+{ 0xaa79cb98, 0xc785, 0x44c5, \
+  { 0x80, 0x80, 0x2e, 0x5f, 0x0c, 0xa5, 0xbd, 0x63 } }
 
 class Element : public FragmentOrElement
 {
 public:
 #ifdef MOZILLA_INTERNAL_API
   explicit Element(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo) :
     FragmentOrElement(aNodeInfo),
     mState(NS_EVENT_STATE_MOZ_READONLY)
@@ -956,18 +956,16 @@ public:
                            nsIDOMHTMLCollection** aResult);
   nsresult
     GetElementsByClassName(const nsAString& aClassNames,
                            nsIDOMHTMLCollection** aResult);
   void GetClassList(nsISupports** aClassList);
 
   virtual JSObject* WrapObject(JSContext *aCx) MOZ_FINAL MOZ_OVERRIDE;
 
-  nsINode* GetScopeChainParent() const MOZ_OVERRIDE;
-
   /**
    * Locate an nsIEditor rooted at this content node, if there is one.
    */
   nsIEditor* GetEditorInternal();
 
   /**
    * Helper method for NS_IMPL_BOOL_ATTR macro.
    * Gets value of boolean attribute. Only works for attributes in null
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -131,18 +131,18 @@ template<typename> class OwningNonNull;
 template<typename> class Sequence;
 
 template<typename, typename> class CallbackObjectHolder;
 typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
 } // namespace dom
 } // namespace mozilla
 
 #define NS_IDOCUMENT_IID \
-{ 0x6bbf1955, 0xd9c4, 0x4d61, \
- { 0xbf, 0x75, 0x1b, 0xba, 0x55, 0xf7, 0x99, 0xc2 } }
+{ 0xbab5b447, 0x7e23, 0x4cdd, \
+  { 0xac, 0xe5, 0xaa, 0x04, 0x26, 0x87, 0x2b, 0x97 } }
 
 // Enum for requesting a particular type of document when creating a doc
 enum DocumentFlavor {
   DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant
   DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true
   DocumentFlavorSVG, // SVGDocument
   DocumentFlavorPlain, // Just a Document
 };
@@ -2872,16 +2872,12 @@ inline nsINode*
 nsINode::OwnerDocAsNode() const
 {
   return OwnerDoc();
 }
 
 inline mozilla::dom::ParentObject
 nsINode::GetParentObject() const
 {
-  mozilla::dom::ParentObject p(OwnerDoc());
-    // Note that mUseXBLScope is a no-op for chrome, and other places where we
-    // don't use XBL scopes.
-  p.mUseXBLScope = IsInAnonymousSubtree() && !IsAnonymousContentInSVGUseSubtree();
-  return p;
+  return GetParentObjectInternal(OwnerDoc());
 }
 
 #endif /* nsIDocument_h___ */
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -2747,13 +2747,8 @@ nsINode::GetParentElementCrossingShadowR
 
 bool
 nsINode::HasBoxQuadsSupport(JSContext* aCx, JSObject* /* unused */)
 {
   return xpc::AccessCheck::isChrome(js::GetContextCompartment(aCx)) ||
          Preferences::GetBool("layout.css.getBoxQuads.enabled");
 }
 
-nsINode*
-nsINode::GetScopeChainParent() const
-{
-  return nullptr;
-}
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -243,18 +243,18 @@ private:
 
 // Categories of node properties
 // 0 is global.
 #define DOM_USER_DATA         1
 #define SMIL_MAPPED_ATTR_ANIMVAL 2
 
 // IID for the nsINode interface
 #define NS_INODE_IID \
-{ 0x66972940, 0x1d1b, 0x4d15, \
- { 0x93, 0x11, 0x96, 0x72, 0x84, 0x2e, 0xc7, 0x27 } }
+{ 0x8deda3f4, 0x0f45, 0x497a, \
+  { 0x89, 0x7c, 0xe6, 0x09, 0x12, 0x8a, 0xad, 0xd8 } }
 
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
  * nsIContent and nsIDocument share.  An instance of this interface has a list
  * of nsIContent children and provides access to them.
  */
 class nsINode : public mozilla::dom::EventTarget
 {
@@ -377,27 +377,31 @@ public:
 protected:
   /**
    * WrapNode is called from WrapObject to actually wrap this node, WrapObject
    * does some additional checks and fix-up that's common to all nodes. WrapNode
    * should just call the DOM binding's Wrap function.
    */
   virtual JSObject* WrapNode(JSContext *aCx) = 0;
 
+  // Subclasses that wish to override the parent behavior should return the
+  // result of GetParentObjectIntenral, which handles the XBL scope stuff.
+  //
+  mozilla::dom::ParentObject GetParentObjectInternal(nsINode* aNativeParent) const {
+    mozilla::dom::ParentObject p(aNativeParent);
+    // Note that mUseXBLScope is a no-op for chrome, and other places where we
+    // don't use XBL scopes.
+    p.mUseXBLScope = IsInAnonymousSubtree() && !IsAnonymousContentInSVGUseSubtree();
+    return p;
+  }
+
 public:
   mozilla::dom::ParentObject GetParentObject() const; // Implemented in nsIDocument.h
 
   /**
-   * Return the scope chain parent for this node, for use in things
-   * like event handler compilation.  Returning null means to use the
-   * global object as the scope chain parent.
-   */
-  virtual nsINode* GetScopeChainParent() const;
-
-  /**
    * Return whether the node is an Element node
    */
   bool IsElement() const {
     return GetBoolFlag(NodeIsElement);
   }
 
   /**
    * Return this node as an Element.  Should only be used for nodes
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -22,18 +22,16 @@
 #include "nsPIDOMWindow.h"
 #include "GeckoProfiler.h"
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 #include "nsJSPrincipals.h"
 #include "xpcpublic.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
 
-#include "mozilla/dom/BindingUtils.h"
-#include "mozilla/dom/Element.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 using namespace mozilla::dom;
 
 bool
 nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
                               uint32_t* aLineno)
 {
@@ -310,37 +308,16 @@ nsJSUtils::EvaluateString(JSContext* aCx
 {
   EvaluateOptions options;
   options.setNeedResult(false);
   JS::RootedValue unused(aCx);
   return EvaluateString(aCx, aSrcBuf, aScopeObject, aCompileOptions,
                         options, &unused, aOffThreadToken);
 }
 
-/* static */
-bool
-nsJSUtils::GetScopeChainForElement(JSContext* aCx,
-                                   mozilla::dom::Element* aElement,
-                                   JS::AutoObjectVector& aScopeChain)
-{
-  for (nsINode* cur = aElement; cur; cur = cur->GetScopeChainParent()) {
-    JS::RootedValue val(aCx);
-    if (!WrapNewBindingObject(aCx, cur, &val)) {
-      return false;
-    }
-
-    if (!aScopeChain.append(&val.toObject())) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-
 //
 // nsDOMJSUtils.h
 //
 
 JSObject* GetDefaultScopeFromJSContext(JSContext *cx)
 {
   // DOM JSContexts don't store their default compartment object on
   // the cx, so in those cases we need to fetch it via the scx
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -20,17 +20,16 @@
 #include "nsString.h"
 
 class nsIScriptContext;
 class nsIScriptGlobalObject;
 
 namespace mozilla {
 namespace dom {
 class AutoJSAPI;
-class Element;
 }
 }
 
 class nsJSUtils
 {
 public:
   static bool GetCallingLocation(JSContext* aContext, const char* *aFilename,
                                  uint32_t* aLineno);
@@ -115,21 +114,16 @@ public:
                                  void **aOffThreadToken = nullptr);
 
   static nsresult EvaluateString(JSContext* aCx,
                                  JS::SourceBufferHolder& aSrcBuf,
                                  JS::Handle<JSObject*> aScopeObject,
                                  JS::CompileOptions &aCompileOptions,
                                  void **aOffThreadToken = nullptr);
 
-  // Returns false if an exception got thrown on aCx.  Passing a null
-  // aElement is allowed; that wil produce an empty aScopeChain.
-  static bool GetScopeChainForElement(JSContext* aCx,
-                                      mozilla::dom::Element* aElement,
-                                      JS::AutoObjectVector& aScopeChain);
 };
 
 class MOZ_STACK_CLASS AutoDontReportUncaught {
   JSContext* mContext;
   bool mWasSet;
 
 public:
   explicit AutoDontReportUncaught(JSContext* aContext) : mContext(aContext) {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1499,27 +1499,44 @@ WrapNativeParent(JSContext* cx, T* p, ns
 // things like the nsWrapperCache for it.
 template<typename T>
 static inline JSObject*
 WrapNativeParent(JSContext* cx, const T& p)
 {
   return WrapNativeParent(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
 }
 
+// A way to differentiate between nodes, which use the parent object
+// returned by native->GetParentObject(), and all other objects, which
+// just use the parent's global.
+static inline JSObject*
+GetRealParentObject(void* aParent, JSObject* aParentObject)
+{
+  return aParentObject ?
+    js::GetGlobalForObjectCrossCompartment(aParentObject) : nullptr;
+}
+
+static inline JSObject*
+GetRealParentObject(Element* aParent, JSObject* aParentObject)
+{
+  return aParentObject;
+}
+
 HAS_MEMBER(GetParentObject)
 
 template<typename T, bool WrapperCached=HasGetParentObjectMember<T>::Value>
 struct GetParentObject
 {
   static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
   {
     MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
     T* native = UnwrapDOMObject<T>(obj);
-    JSObject* wrappedParent = WrapNativeParent(cx, native->GetParentObject());
-    return wrappedParent ? js::GetGlobalForObjectCrossCompartment(wrappedParent) : nullptr;
+    return
+      GetRealParentObject(native,
+                          WrapNativeParent(cx, native->GetParentObject()));
   }
 };
 
 template<typename T>
 struct GetParentObject<T, false>
 {
   static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
   {
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -3064,49 +3064,51 @@ class CGConstructorEnabled(CGAbstractMet
                                         pre="return ", post=";\n", reindent=True)
         else:
           conditionsWrapper = CGGeneric("return true;\n")
 
         body.append(conditionsWrapper)
         return body.define()
 
 
-def CreateBindingJSObject(descriptor, properties):
+def CreateBindingJSObject(descriptor, properties, parent):
     # We don't always need to root obj, but there are a variety
     # of cases where we do, so for simplicity, just always root it.
     objDecl = "JS::Rooted<JSObject*> obj(aCx);\n"
     if descriptor.proxy:
-        create = dedent(
+        create = fill(
             """
             JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aObject));
             js::ProxyOptions options;
             options.setClass(&Class.mBase);
             obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(),
-                                 proxyPrivateVal, proto, global, options);
+                                 proxyPrivateVal, proto, ${parent}, options);
             if (!obj) {
               return nullptr;
             }
 
-            """)
+            """,
+            parent=parent)
         if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
             create += dedent("""
                 js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO,
                                   JS::PrivateValue(&aObject->mExpandoAndGeneration));
 
                 """)
     else:
-        create = dedent(
-            """
-            obj = JS_NewObject(aCx, Class.ToJSClass(), proto, global);
+        create = fill(
+            """
+            obj = JS_NewObject(aCx, Class.ToJSClass(), proto, ${parent});
             if (!obj) {
               return nullptr;
             }
 
             js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
-            """)
+            """,
+            parent=parent)
     create = objDecl + create
 
     if descriptor.nativeOwnership == 'refcounted':
         create += "NS_ADDREF(aObject);\n"
     else:
         create += dedent("""
             // Make sure the native objects inherit from NonRefcountedDOMObject so that we
             // log their ctor and dtor.
@@ -3247,48 +3249,51 @@ class CGWrapWithCacheMethod(CGAbstractMe
     def definition_body(self):
         return fill(
             """
             $*{assertion}
 
             MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
                        "nsISupports must be on our primary inheritance chain");
 
-            JS::Rooted<JSObject*> parent(aCx, WrapNativeParent(aCx, aObject->GetParentObject()));
+            JS::Rooted<JSObject*> parent(aCx,
+              GetRealParentObject(aObject,
+                                  WrapNativeParent(aCx, aObject->GetParentObject())));
             if (!parent) {
               return nullptr;
             }
 
             // That might have ended up wrapping us already, due to the wonders
             // of XBL.  Check for that, and bail out as needed.  Scope so we don't
             // collide with the "obj" we declare in CreateBindingJSObject.
             {
               JSObject* obj = aCache->GetWrapper();
               if (obj) {
                 return obj;
               }
             }
 
             JSAutoCompartment ac(aCx, parent);
-            JS::Rooted<JSObject*> global(aCx, js::GetGlobalForObjectCrossCompartment(parent));
+            JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, parent));
             JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx, global);
             if (!proto) {
               return nullptr;
             }
 
-            $*{createObject}
+            $*{parent}
 
             $*{unforgeable}
 
             aCache->SetWrapper(obj);
             $*{slots}
             return obj;
             """,
             assertion=AssertInheritanceChain(self.descriptor),
-            createObject=CreateBindingJSObject(self.descriptor, self.properties),
+            parent=CreateBindingJSObject(self.descriptor, self.properties,
+                                         "parent"),
             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
             slots=InitMemberSlots(self.descriptor, True))
 
 
 class CGWrapMethod(CGAbstractMethod):
     def __init__(self, descriptor):
         # XXX can we wrap if we don't have an interface prototype object?
         assert descriptor.interface.hasInterfacePrototypeObject()
@@ -3324,25 +3329,26 @@ class CGWrapNonWrapperCacheMethod(CGAbst
             $*{assertions}
 
             JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
             JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx, global);
             if (!proto) {
               return nullptr;
             }
 
-            $*{createObject}
+            $*{global_}
 
             $*{unforgeable}
 
             $*{slots}
             return obj;
             """,
             assertions=AssertInheritanceChain(self.descriptor),
-            createObject=CreateBindingJSObject(self.descriptor, self.properties),
+            global_=CreateBindingJSObject(self.descriptor, self.properties,
+                                          "global"),
             unforgeable=InitUnforgeableProperties(self.descriptor, self.properties),
             slots=InitMemberSlots(self.descriptor, False))
 
 
 class CGWrapGlobalMethod(CGAbstractMethod):
     """
     Create a wrapper JSObject for a global.  The global must implement
     nsWrapperCache.
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -858,43 +858,50 @@ EventListenerManager::CompileEventHandle
     JSAutoCompartment ac(cx, wrapScope);
     nsresult rv = nsContentUtils::WrapNative(cx, mTarget, &v,
                                              /* aAllowWrapping = */ false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
+  JS::AutoObjectVector scopeChain(cx);
+  { // scope for curScope
+    // We append all the non-globals on our desired scope chain.
+    JS::Rooted<JSObject*> curScope(cx, &v.toObject());
+    while (curScope && !JS_IsGlobalObject(curScope)) {
+      if (!scopeChain.append(curScope)) {
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+      curScope = JS_GetParent(curScope);
+    }
+  }
+
   if (addonId) {
     JS::Rooted<JSObject*> vObj(cx, &v.toObject());
     JS::Rooted<JSObject*> addonScope(cx, xpc::GetAddonScope(cx, vObj, addonId));
     if (!addonScope) {
       return NS_ERROR_FAILURE;
     }
     JSAutoCompartment ac(cx, addonScope);
+    for (size_t i = 0; i < scopeChain.length(); ++i) {
+      if (!JS_WrapObject(cx, scopeChain[i])) {
+        return NS_ERROR_FAILURE;
+      }
+    }
 
-    // Wrap our event target into the addon scope, since that's where we want to
-    // do all our work.
+    // And wrap v as well, since scopeChain might be empty so we can't
+    // reliably use it to enter a compartment.
     if (!JS_WrapValue(cx, &v)) {
       return NS_ERROR_FAILURE;
     }
   }
   JS::Rooted<JSObject*> target(cx, &v.toObject());
   JSAutoCompartment ac(cx, target);
 
-  // Now that we've entered the compartment we actually care about, create our
-  // scope chain.  Note that we start with |element|, not aElement, because
-  // mTarget is different from aElement in the <body> case, where mTarget is a
-  // Window, and in that case we do not want the scope chain to include the body
-  // or the document.
-  JS::AutoObjectVector scopeChain(cx);
-  if (!nsJSUtils::GetScopeChainForElement(cx, element, scopeChain)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
   nsDependentAtomString str(attrName);
   // Most of our names are short enough that we don't even have to malloc
   // the JS string stuff, so don't worry about playing games with
   // refcounting XPCOM stringbuffers.
   JS::Rooted<JSString*> jsStr(cx, JS_NewUCStringCopyN(cx,
                                                       str.BeginReading(),
                                                       str.Length()));
   NS_ENSURE_TRUE(jsStr, NS_ERROR_OUT_OF_MEMORY);
--- a/dom/html/HTMLLegendElement.cpp
+++ b/dom/html/HTMLLegendElement.cpp
@@ -17,17 +17,17 @@ namespace dom {
 
 HTMLLegendElement::~HTMLLegendElement()
 {
 }
 
 NS_IMPL_ELEMENT_CLONE(HTMLLegendElement)
 
 nsIContent*
-HTMLLegendElement::GetFieldSet() const
+HTMLLegendElement::GetFieldSet()
 {
   nsIContent* parent = GetParent();
 
   if (parent && parent->IsHTML(nsGkAtoms::fieldset)) {
     return parent;
   }
 
   return nullptr;
--- a/dom/html/HTMLLegendElement.h
+++ b/dom/html/HTMLLegendElement.h
@@ -49,17 +49,17 @@ public:
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify) MOZ_OVERRIDE;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const MOZ_OVERRIDE;
 
-  Element* GetFormElement() const
+  Element* GetFormElement()
   {
     nsCOMPtr<nsIFormControl> fieldsetControl = do_QueryInterface(GetFieldSet());
 
     return fieldsetControl ? fieldsetControl->GetFormElement() : nullptr;
   }
 
   /**
    * WebIDL Interface
@@ -72,30 +72,30 @@ public:
     GetHTMLAttr(nsGkAtoms::align, aAlign);
   }
 
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
 
-  nsINode* GetScopeChainParent() const MOZ_OVERRIDE
-  {
+  ParentObject GetParentObject() {
     Element* form = GetFormElement();
-    return form ? form : nsGenericHTMLElement::GetScopeChainParent();
+    return form ? GetParentObjectInternal(form)
+                : nsGenericHTMLElement::GetParentObject();
   }
 
 protected:
   virtual ~HTMLLegendElement();
 
   virtual JSObject* WrapNode(JSContext* aCx) MOZ_OVERRIDE;
 
   /**
    * Get the fieldset content element that contains this legend.
    * Returns null if there is no fieldset containing this legend.
    */
-  nsIContent* GetFieldSet() const;
+  nsIContent* GetFieldSet();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLLegendElement_h */
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -1891,20 +1891,24 @@ nsGenericHTMLFormElement::~nsGenericHTML
   // Check that this element doesn't know anything about its form at this point.
   NS_ASSERTION(!mForm, "mForm should be null at this point!");
 }
 
 NS_IMPL_ISUPPORTS_INHERITED(nsGenericHTMLFormElement,
                             nsGenericHTMLElement,
                             nsIFormControl)
 
-nsINode*
-nsGenericHTMLFormElement::GetScopeChainParent() const
+mozilla::dom::ParentObject
+nsGenericHTMLFormElement::GetParentObject() const
 {
-  return mForm ? mForm : nsGenericHTMLElement::GetScopeChainParent();
+  // We use the parent chain to implement the scope for event handlers.
+  if (mForm) {
+    return GetParentObjectInternal(mForm);
+  }
+  return nsGenericHTMLElement::GetParentObject();
 }
 
 bool
 nsGenericHTMLFormElement::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~(eCONTENT | eHTML_FORM_CONTROL));
 }
 
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -1240,17 +1240,17 @@ ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPE
 class nsGenericHTMLFormElement : public nsGenericHTMLElement,
                                  public nsIFormControl
 {
 public:
   explicit nsGenericHTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   NS_DECL_ISUPPORTS_INHERITED
 
-  nsINode* GetScopeChainParent() const MOZ_OVERRIDE;
+  mozilla::dom::ParentObject GetParentObject() const;
 
   virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE;
   virtual void SaveSubtreeState() MOZ_OVERRIDE;
 
   // nsIFormControl
   virtual mozilla::dom::HTMLFieldSetElement* GetFieldSet();
   virtual mozilla::dom::Element* GetFormElement() MOZ_OVERRIDE;
   mozilla::dom::HTMLFormElement* GetForm() const
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -264,17 +264,16 @@ nsXBLProtoImplMethod::Write(nsIObjectOut
   }
 
   return NS_OK;
 }
 
 nsresult
 nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement, JSAddonId* aAddonId)
 {
-  MOZ_ASSERT(aBoundElement->IsElement());
   NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
 
   if (!GetCompiledMethod()) {
     // Nothing to do here
     return NS_OK;
   }
 
   // Get the script context the same way
@@ -291,46 +290,47 @@ nsXBLProtoImplAnonymousMethod::Execute(n
 
   // We are going to run script via JS::Call, so we need a script entry point,
   // but as this is XBL related it does not appear in the HTML spec.
   dom::AutoEntryScript aes(global);
   JSContext* cx = aes.cx();
 
   JS::Rooted<JSObject*> globalObject(cx, global->GetGlobalJSObject());
 
+  JS::Rooted<JS::Value> v(cx);
+  nsresult rv = nsContentUtils::WrapNative(cx, aBoundElement, &v);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  JS::Rooted<JSObject*> thisObject(cx, &v.toObject());
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, aAddonId));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   JSAutoCompartment ac(cx, scopeObject);
-  JS::AutoObjectVector scopeChain(cx);
-  if (!nsJSUtils::GetScopeChainForElement(cx, aBoundElement->AsElement(),
-                                          scopeChain)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  MOZ_ASSERT(scopeChain.length() != 0);
+  if (!JS_WrapObject(cx, &thisObject))
+      return NS_ERROR_OUT_OF_MEMORY;
 
-  // Clone the function object, using our scope chain (for backwards
-  // compat to the days when this was an event handler).
+  // Clone the function object, using thisObject as the parent so "this" is in
+  // the scope chain of the resulting function (for backwards compat to the
+  // days when this was an event handler).
   JS::Rooted<JSObject*> jsMethodObject(cx, GetCompiledMethod());
-  JS::Rooted<JSObject*> method(cx, JS::CloneFunctionObject(cx, jsMethodObject,
-                                                           scopeChain));
+  JS::Rooted<JSObject*> method(cx, ::JS_CloneFunctionObject(cx, jsMethodObject, thisObject));
   if (!method)
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Now call the method
 
   // Check whether script is enabled.
   bool scriptAllowed = nsContentUtils::GetSecurityManager()->
                          ScriptAllowed(js::GetGlobalForObjectCrossCompartment(method));
 
   bool ok = true;
   if (scriptAllowed) {
     JS::Rooted<JS::Value> retval(cx);
     JS::Rooted<JS::Value> methodVal(cx, JS::ObjectValue(*method));
-    ok = ::JS::Call(cx, scopeChain[0], methodVal, JS::HandleValueArray::empty(), &retval);
+    ok = ::JS::Call(cx, thisObject, methodVal, JS::HandleValueArray::empty(), &retval);
   }
 
   if (!ok) {
     // If a constructor or destructor threw an exception, it doesn't stop
     // anything else.  We just report it.  Note that we need to set aside the
     // frame chain here, since the constructor invocation is not related to
     // whatever is on the stack right now, really.
     nsJSUtils::ReportPendingException(cx);
--- a/dom/xbl/nsXBLPrototypeHandler.cpp
+++ b/dom/xbl/nsXBLPrototypeHandler.cpp
@@ -39,17 +39,16 @@
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "nsXBLEventHandler.h"
 #include "nsXBLSerialize.h"
 #include "nsJSUtils.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/JSEventHandler.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/dom/Element.h"
 #include "mozilla/dom/EventHandlerBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "xpcpublic.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 uint32_t nsXBLPrototypeHandler::gRefCnt = 0;
@@ -296,25 +295,26 @@ nsXBLPrototypeHandler::ExecuteHandler(Ev
   // First, enter our XBL scope. This is where the generic handler should have
   // been compiled, above.
   JSAutoCompartment ac(cx, scopeObject);
   JS::Rooted<JSObject*> genericHandler(cx, handler.get());
   bool ok = JS_WrapObject(cx, &genericHandler);
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   MOZ_ASSERT(!js::IsCrossCompartmentWrapper(genericHandler));
 
-  // Build a scope chain in the XBL scope.
-  nsRefPtr<Element> targetElement = do_QueryObject(scriptTarget);
-  JS::AutoObjectVector scopeChain(cx);
-  ok = nsJSUtils::GetScopeChainForElement(cx, targetElement, scopeChain);
-  NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
+  // Wrap the native into the XBL scope. This creates a reflector in the document
+  // scope if one doesn't already exist, and potentially wraps it cross-
+  // compartment into our scope (via aAllowWrapping=true).
+  JS::Rooted<JS::Value> targetV(cx, JS::UndefinedValue());
+  rv = nsContentUtils::WrapNative(cx, scriptTarget, &targetV);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  // Next, clone the generic handler with our desired scope chain.
-  JS::Rooted<JSObject*> bound(cx, JS::CloneFunctionObject(cx, genericHandler,
-                                                          scopeChain));
+  // Next, clone the generic handler to be parented to the target.
+  JS::Rooted<JSObject*> target(cx, &targetV.toObject());
+  JS::Rooted<JSObject*> bound(cx, JS_CloneFunctionObject(cx, genericHandler, target));
   NS_ENSURE_TRUE(bound, NS_ERROR_FAILURE);
 
   nsRefPtr<EventHandlerNonNull> handlerCallback =
     new EventHandlerNonNull(bound, /* aIncumbentGlobal = */ nullptr);
 
   TypedEventHandler typedHandler(handlerCallback);
 
   // Execute it.
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -601,21 +601,24 @@ public:
       GetElementsByAttributeNS(const nsAString& aNamespaceURI,
                                const nsAString& aAttribute,
                                const nsAString& aValue,
                                mozilla::ErrorResult& rv);
     // Style() inherited from nsStyledElement
     already_AddRefed<nsFrameLoader> GetFrameLoader();
     void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& rv);
 
-    nsINode* GetScopeChainParent() const MOZ_OVERRIDE
+    // For XUL, the parent is the parent element, if any
+    mozilla::dom::ParentObject GetParentObject() const
     {
-        // For XUL, the parent is the parent element, if any
         Element* parent = GetParentElement();
-        return parent ? parent : nsStyledElement::GetScopeChainParent();
+        if (parent) {
+          return GetParentObjectInternal(parent);
+        }
+        return nsStyledElement::GetParentObject();
     }
 
 protected:
     ~nsXULElement();
 
     // This can be removed if EnsureContentsGenerated dies.
     friend class nsNSElementTearoff;
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3914,31 +3914,16 @@ JS_CloneFunctionObject(JSContext *cx, Ha
     if (fun->isNative() && IsAsmJSModuleNative(fun->native())) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT);
         return nullptr;
     }
 
     return CloneFunctionObject(cx, fun, parent, fun->getAllocKind());
 }
 
-namespace JS {
-
-JS_PUBLIC_API(JSObject *)
-CloneFunctionObject(JSContext *cx, HandleObject funobj, AutoObjectVector &scopeChain)
-{
-    RootedObject dynamicScope(cx);
-    RootedObject unusedStaticScope(cx);
-    if (!CreateScopeObjectsForScopeChain(cx, scopeChain, &dynamicScope, &unusedStaticScope))
-        return nullptr;
-
-    return JS_CloneFunctionObject(cx, funobj, dynamicScope);
-}
-
-} // namespace JS
-
 JS_PUBLIC_API(JSObject *)
 JS_GetFunctionObject(JSFunction *fun)
 {
     return fun;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_GetFunctionId(JSFunction *fun)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3529,28 +3529,16 @@ JS_DefineFunctionById(JSContext *cx, JS:
 
 /*
  * Clone a top-level function into a new scope. This function will dynamically
  * fail if funobj was lexically nested inside some other function.
  */
 extern JS_PUBLIC_API(JSObject *)
 JS_CloneFunctionObject(JSContext *cx, JS::Handle<JSObject*> funobj, JS::Handle<JSObject*> parent);
 
-namespace JS {
-
-/*
- * As above, but providing an explicit scope chain.  scopeChain must not include
- * the global object on it; that's implicit.  It needs to contain the other
- * objects that should end up on the clone's scope chain.
- */
-extern JS_PUBLIC_API(JSObject *)
-CloneFunctionObject(JSContext *cx, HandleObject funobj, AutoObjectVector &scopeChain);
-
-} // namespace JS
-
 /*
  * Given a buffer, return false if the buffer might become a valid
  * javascript statement with the addition of more lines.  Otherwise return
  * true.  The intent is to support interactive compilation - accumulate
  * lines in a buffer until JS_BufferIsCompilableUnit is true, then pass it to
  * the compiler.
  */
 extern JS_PUBLIC_API(bool)