author | Peter Van der Beken <peterv@propagandism.org> |
Thu, 26 May 2011 21:58:35 +0200 | |
changeset 78428 | d64ee71954761887cceb784b141b529c49a315b4 |
parent 78427 | 93037e2151f3f3c7cfbf4f6eba441dda26fdeb21 |
child 78429 | 1169117ea7f1b124aae3b2b66607aeed0af087e8 |
push id | 21294 |
push user | pvanderbeken@mozilla.com |
push date | Mon, 10 Oct 2011 08:58:09 +0000 |
treeherder | mozilla-central@432f3a96bc2b [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bz, jst, mrbkap |
bugs | 648801 |
milestone | 10.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
|
--- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1268,32 +1268,19 @@ public: aCache->SetPreservingWrapper(PR_TRUE); #ifdef DEBUG // Make sure the cycle collector will be able to traverse to the wrapper. CheckCCWrapperTraversal(aScriptObjectHolder, aCache); #endif } } static void ReleaseWrapper(nsISupports* aScriptObjectHolder, - nsWrapperCache* aCache) - { - if (aCache->PreservingWrapper()) { - DropJSObjects(aScriptObjectHolder); - aCache->SetPreservingWrapper(PR_FALSE); - } - } + nsWrapperCache* aCache); static void TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback, - void *aClosure) - { - if (aCache->PreservingWrapper()) { - aCallback(nsIProgrammingLanguage::JAVASCRIPT, - aCache->GetWrapperPreserveColor(), - "Preserved wrapper", aClosure); - } - } + void *aClosure); /** * Convert nsIContent::IME_STATUS_* to nsIWidget::IME_STATUS_* */ static PRUint32 GetWidgetStatusFromIMEStatus(PRUint32 aState); /* * Notify when the first XUL menu is opened and when the all XUL menus are
--- a/content/base/public/nsDOMEventTargetWrapperCache.h +++ b/content/base/public/nsDOMEventTargetWrapperCache.h @@ -85,17 +85,17 @@ public: return static_cast<nsDOMEventTargetWrapperCache*>(target); } void Init(JSContext* aCx = nsnull); protected: nsDOMEventTargetWrapperCache() : nsDOMEventTargetHelper(), nsWrapperCache() {} - virtual ~nsDOMEventTargetWrapperCache(); + virtual ~nsDOMEventTargetWrapperCache() {} }; #define NS_DECL_EVENT_HANDLER(_event) \ protected: \ nsRefPtr<nsDOMEventListenerWrapper> mOn##_event##Listener; \ public: #define NS_DECL_AND_IMPL_EVENT_HANDLER(_event) \
--- a/content/base/src/nsContentList.cpp +++ b/content/base/src/nsContentList.cpp @@ -73,20 +73,25 @@ using namespace mozilla::dom; nsBaseContentList::~nsBaseContentList() { } NS_IMPL_CYCLE_COLLECTION_CLASS(nsBaseContentList) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBaseContentList) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mElements) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBaseContentList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mElements) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsBaseContentList) + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_TRACE_END #define NS_CONTENT_LIST_INTERFACES(_class) \ NS_INTERFACE_TABLE_ENTRY(_class, nsINodeList) \ NS_INTERFACE_TABLE_ENTRY(_class, nsIDOMNodeList) DOMCI_DATA(NodeList, nsBaseContentList) // QueryInterface implementation for nsBaseContentList
--- a/content/base/src/nsContentList.h +++ b/content/base/src/nsContentList.h @@ -94,17 +94,17 @@ public: // nsINodeList virtual nsIContent* GetNodeAt(PRUint32 aIndex); virtual PRInt32 IndexOf(nsIContent* aContent); PRUint32 Length() const { return mElements.Count(); } - NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsBaseContentList, nsINodeList) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsBaseContentList) void AppendElement(nsIContent *aContent); void MaybeAppendElement(nsIContent* aContent) { if (aContent) AppendElement(aContent); }
--- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -198,16 +198,17 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_ #ifdef MOZ_MEDIA #include "nsHTMLMediaElement.h" #endif #include "nsDOMTouchEvent.h" #include "nsIScriptElement.h" #include "prdtoa.h" #include "mozilla/Preferences.h" +#include "nsWrapperCacheInlines.h" using namespace mozilla::dom; using namespace mozilla::layers; using namespace mozilla; const char kLoadAsData[] = "loadAsData"; static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1"; @@ -5798,8 +5799,40 @@ bool nsContentUtils::IsRequestFullScreen return !sTrustedFullScreenOnly || nsEventStateManager::IsHandlingUserInput(); } bool nsContentUtils::IsFullScreenKeyInputRestricted() { return sFullScreenKeyInputRestricted; } + +// static +void +nsContentUtils::ReleaseWrapper(nsISupports* aScriptObjectHolder, + nsWrapperCache* aCache) +{ + if (aCache->PreservingWrapper()) { + DropJSObjects(aScriptObjectHolder); + aCache->SetPreservingWrapper(false); + } + + aCache->ClearWrapperIfProxy(); +} + +// static +void +nsContentUtils::TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback, + void *aClosure) +{ + if (aCache->PreservingWrapper()) { + aCallback(nsIProgrammingLanguage::JAVASCRIPT, + aCache->GetWrapperPreserveColor(), + "Preserved wrapper", aClosure); + } + else { + JSObject *expando = aCache->GetExpandoObjectPreserveColor(); + if (expando) { + aCallback(nsIProgrammingLanguage::JAVASCRIPT, expando, "Expando object", + aClosure); + } + } +}
--- a/content/base/src/nsDOMAttribute.cpp +++ b/content/base/src/nsDOMAttribute.cpp @@ -55,16 +55,17 @@ #include "nsGkAtoms.h" #include "nsCOMArray.h" #include "nsNodeUtils.h" #include "nsEventListenerManager.h" #include "nsTextNode.h" #include "mozAutoDocUpdate.h" #include "nsMutationEvent.h" #include "nsPLDOMEvent.h" +#include "nsWrapperCacheInlines.h" using namespace mozilla::dom; //---------------------------------------------------------------------- bool nsDOMAttribute::sInitialized; nsDOMAttribute::nsDOMAttribute(nsDOMAttributeMap *aAttrMap, already_AddRefed<nsINodeInfo> aNodeInfo,
--- a/content/base/src/nsDOMDocumentType.cpp +++ b/content/base/src/nsDOMDocumentType.cpp @@ -46,16 +46,17 @@ #include "nsCOMPtr.h" #include "nsContentUtils.h" #include "nsDOMString.h" #include "nsNodeInfoManager.h" #include "nsIDocument.h" #include "nsIXPConnect.h" #include "nsIDOMDocument.h" #include "xpcpublic.h" +#include "nsWrapperCacheInlines.h" nsresult NS_NewDOMDocumentType(nsIDOMDocumentType** aDocType, nsNodeInfoManager *aNodeInfoManager, nsIAtom *aName, const nsAString& aPublicId, const nsAString& aSystemId, const nsAString& aInternalSubset)
--- a/content/base/src/nsDOMEventTargetWrapperCache.cpp +++ b/content/base/src/nsDOMEventTargetWrapperCache.cpp @@ -38,22 +38,17 @@ * ***** END LICENSE BLOCK ***** */ #include "nsContentUtils.h" #include "nsDOMEventTargetWrapperCache.h" #include "nsIDocument.h" #include "nsIJSContextStack.h" #include "nsServiceManagerUtils.h" #include "nsDOMJSUtils.h" - -nsDOMEventTargetWrapperCache::~nsDOMEventTargetWrapperCache() -{ - nsISupports *supports = static_cast<nsIDOMEventTarget*>(this); - nsContentUtils::ReleaseWrapper(supports, this); -} +#include "nsWrapperCacheInlines.h" NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMEventTargetWrapperCache) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMEventTargetWrapperCache) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMEventTargetWrapperCache,
--- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -200,16 +200,17 @@ #include "mozilla/dom/Link.h" #include "nsIHTMLDocument.h" #include "nsXULAppAPI.h" #include "nsDOMTouchEvent.h" #include "mozilla/Preferences.h" #include "imgILoader.h" +#include "nsWrapperCacheInlines.h" using namespace mozilla; using namespace mozilla::dom; typedef nsTArray<Link*> LinkArray; #ifdef PR_LOGGING
--- a/content/base/src/nsGenericDOMDataNode.cpp +++ b/content/base/src/nsGenericDOMDataNode.cpp @@ -61,16 +61,17 @@ #include "nsNodeUtils.h" #include "nsBindingManager.h" #include "nsCCUncollectableMarker.h" #include "mozAutoDocUpdate.h" #include "nsPLDOMEvent.h" #include "pldhash.h" #include "prprf.h" +#include "nsWrapperCacheInlines.h" using namespace mozilla; nsGenericDOMDataNode::nsGenericDOMDataNode(already_AddRefed<nsINodeInfo> aNodeInfo) : nsIContent(aNodeInfo) { NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::TEXT_NODE || mNodeInfo->NodeType() == nsIDOMNode::CDATA_SECTION_NODE ||
--- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -142,30 +142,43 @@ #include "mozAutoDocUpdate.h" #include "nsCSSParser.h" #include "prprf.h" #include "nsSVGFeatures.h" #include "nsDOMMemoryReporter.h" +#include "nsWrapperCacheInlines.h" #include "xpcpublic.h" using namespace mozilla::dom; namespace css = mozilla::css; NS_DEFINE_IID(kThisPtrOffsetsSID, NS_THISPTROFFSETS_SID); PRInt32 nsIContent::sTabFocusModel = eTabFocus_any; bool nsIContent::sTabFocusModelAppliesToXUL = false; PRUint32 nsMutationGuard::sMutationCount = 0; nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult); +void +nsWrapperCache::RemoveExpandoObject() +{ + JSObject *expando = GetExpandoObjectPreserveColor(); + if (expando) { + JSCompartment *compartment = js::GetObjectCompartment(expando); + xpc::CompartmentPrivate *priv = + static_cast<xpc::CompartmentPrivate *>(js_GetCompartmentPrivate(compartment)); + priv->RemoveDOMExpandoObject(expando); + } +} + //---------------------------------------------------------------------- nsINode::nsSlots::~nsSlots() { if (mChildNodes) { mChildNodes->DropReference(); NS_RELEASE(mChildNodes); } @@ -1512,26 +1525,38 @@ nsIContent::GetBaseURI() const } } return base.forget(); } //---------------------------------------------------------------------- -NS_IMPL_ADDREF(nsChildContentList) -NS_IMPL_RELEASE(nsChildContentList) +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList) + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsChildContentList) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsChildContentList) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsChildContentList) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsChildContentList) + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_INTERFACE_TABLE_HEAD(nsChildContentList) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsChildContentList) NS_INTERFACE_TABLE_ENTRY(nsChildContentList, nsINodeList) NS_INTERFACE_TABLE_ENTRY(nsChildContentList, nsIDOMNodeList) NS_OFFSET_AND_INTERFACE_TABLE_END NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsChildContentList) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeList) NS_INTERFACE_MAP_END JSObject* nsChildContentList::WrapObject(JSContext *cx, XPCWrappedNativeScope *scope) { return xpc::dom::NodeListBase::create(cx, scope, this); }
--- a/content/base/src/nsGenericElement.h +++ b/content/base/src/nsGenericElement.h @@ -98,17 +98,18 @@ class nsChildContentList : public nsINod { public: nsChildContentList(nsINode* aNode) : mNode(aNode) { SetIsProxy(); } - NS_DECL_ISUPPORTS + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsChildContentList) // nsWrapperCache virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope); // nsIDOMNodeList interface NS_DECL_NSIDOMNODELIST // nsINodeList interface
--- a/content/base/src/nsNodeUtils.cpp +++ b/content/base/src/nsNodeUtils.cpp @@ -59,17 +59,17 @@ #endif #include "nsBindingManager.h" #include "nsGenericHTMLElement.h" #ifdef MOZ_MEDIA #include "nsHTMLMediaElement.h" #endif // MOZ_MEDIA #include "nsImageLoadingContent.h" #include "jsgc.h" -#include "xpcpublic.h" +#include "nsWrapperCacheInlines.h" using namespace mozilla::dom; // This macro expects the ownerDocument of content_ to be in scope as // |nsIDocument* doc| // NOTE: AttributeChildRemoved doesn't use this macro but has a very similar use. // If you change how this macro behave please update AttributeChildRemoved. #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_) \ @@ -606,16 +606,19 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod // If reparenting moves us to a new compartment, preserving causes // problems. In that case, we release ourselves and re-preserve after // reparenting so we're sure to have the right JS object preserved. // We use a JSObject stack copy of the wrapper to protect it from GC // under ReparentWrappedNativeIfFound. if (aNode->PreservingWrapper()) { preservedWrapper = wrapper; nsContentUtils::ReleaseWrapper(aNode, aNode); + NS_ASSERTION(aNode->GetWrapper(), + "ReleaseWrapper cleared our wrapper, this code needs to " + "be changed to deal with that!"); } nsCOMPtr<nsIXPConnectJSObjectHolder> oldWrapper; rv = xpc->ReparentWrappedNativeIfFound(aCx, wrapper, aNewScope, aNode, getter_AddRefs(oldWrapper)); if (preservedWrapper) { nsContentUtils::PreserveWrapper(aNode, aNode);
--- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -497,16 +497,18 @@ #include "mozilla/dom/indexedDB/IDBIndex.h" #include "nsIIDBDatabaseException.h" #include "nsIDOMMediaQueryList.h" #include "nsDOMTouchEvent.h" #include "nsIDOMCustomEvent.h" +#include "nsWrapperCacheInlines.h" + using namespace mozilla; using namespace mozilla::dom; static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); static const char kDOMStringBundleURL[] = "chrome://global/locale/dom/dom.properties";
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -242,16 +242,17 @@ #include "mozilla/dom/StructuredCloneTags.h" #include "nsRefreshDriver.h" #include "mozAutoDocUpdate.h" #include "mozilla/Telemetry.h" #include "nsLocation.h" +#include "nsWrapperCacheInlines.h" #ifdef PR_LOGGING static PRLogModuleInfo* gDOMLeakPRLog; #endif static const char kStorageEnabled[] = "dom.storage.enabled"; using namespace mozilla;
--- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -10,17 +10,17 @@ * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Gecko DOM code. * * The Initial Developer of the Original Code is - * Mozilla Corporation. + * Mozilla Foundation. * Portions created by the Initial Developer are Copyright (C) 2008 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Peter Van der Beken <peterv@propagandism.org> * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -68,69 +68,62 @@ public: nsWrapperCache() : mWrapperPtrBits(0) { } ~nsWrapperCache() { NS_ASSERTION(!PreservingWrapper(), "Destroying cache with a preserved wrapper!"); + RemoveExpandoObject(); } /** * This getter clears the gray bit before handing out the JSObject which means * that the object is guaranteed to be kept alive past the next CC. * * Implemented in xpcpublic.h because we have to include some JS headers that * don't play nicely with the rest of the codebase. Include xpcpublic.h if you * need to call this method. */ - inline JSObject* GetWrapper() const; + JSObject* GetWrapper() const; /** * This getter does not change the color of the JSObject meaning that the * object returned is not guaranteed to be kept alive past the next CC. * * This should only be called if you are certain that the return value won't * be passed into a JS API function and that it won't be stored without being * rooted (or otherwise signaling the stored value to the CC). */ - JSObject* GetWrapperPreserveColor() const - { - return reinterpret_cast<JSObject*>(mWrapperPtrBits & ~kWrapperBitMask); - } + JSObject* GetWrapperPreserveColor() const; + + JSObject* GetExpandoObjectPreserveColor() const; - void SetWrapper(JSObject* aWrapper) - { - NS_ASSERTION(!PreservingWrapper(), "Clearing a preserved wrapper!"); - mWrapperPtrBits = reinterpret_cast<PtrBits>(aWrapper) | - (mWrapperPtrBits & WRAPPER_IS_PROXY); - } + void SetWrapper(JSObject* aWrapper); - void ClearWrapper() - { - NS_ASSERTION(!PreservingWrapper(), "Clearing a preserved wrapper!"); - mWrapperPtrBits = 0; - } + void ClearWrapper(); + void ClearWrapperIfProxy(); bool PreservingWrapper() { return (mWrapperPtrBits & WRAPPER_BIT_PRESERVED) != 0; } void SetIsProxy() { mWrapperPtrBits |= WRAPPER_IS_PROXY; } - bool IsProxy() + bool IsProxy() const { return (mWrapperPtrBits & WRAPPER_IS_PROXY) != 0; } + /** * Wrap the object corresponding to this wrapper cache. If non-null is * returned, the object has already been stored in the wrapper cache. */ virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope) { return nsnull; } @@ -140,16 +133,28 @@ private: { if(aPreserve) { mWrapperPtrBits |= WRAPPER_BIT_PRESERVED; } else { mWrapperPtrBits &= ~WRAPPER_BIT_PRESERVED; } } + JSObject *GetJSObjectFromBits() const + { + return reinterpret_cast<JSObject*>(mWrapperPtrBits & ~kWrapperBitMask); + } + void SetWrapperBits(void *aWrapper) + { + mWrapperPtrBits = reinterpret_cast<PtrBits>(aWrapper) | + (mWrapperPtrBits & WRAPPER_IS_PROXY); + } + void RemoveExpandoObject(); + + static JSObject *GetExpandoFromSlot(JSObject *obj); enum { WRAPPER_BIT_PRESERVED = 1 << 0 }; enum { WRAPPER_IS_PROXY = 1 << 1 }; enum { kWrapperBitMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_PROXY) }; PtrBits mWrapperPtrBits; };
new file mode 100644 --- /dev/null +++ b/dom/base/nsWrapperCacheInlines.h @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Gecko DOM code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Van der Beken <peterv@propagandism.org> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsWrapperCacheInline_h___ +#define nsWrapperCacheInline_h___ + +#include "nsWrapperCache.h" +#include "xpcprivate.h" + +inline JSObject* +nsWrapperCache::GetWrapperPreserveColor() const +{ + JSObject *obj = GetJSObjectFromBits(); + return !IsProxy() || !obj || js::IsProxy(obj) ? obj : nsnull; +} + +inline JSObject* +nsWrapperCache::GetWrapper() const +{ + JSObject* obj = GetWrapperPreserveColor(); + xpc_UnmarkGrayObject(obj); + return obj; +} + +inline void +nsWrapperCache::SetWrapper(JSObject* aWrapper) +{ + NS_ASSERTION(!PreservingWrapper(), "Clearing a preserved wrapper!"); + NS_ASSERTION(aWrapper, "Use ClearWrapper!"); + + JSObject *obj = GetJSObjectFromBits(); + if (obj && xpc::dom::isExpandoObject(obj)) { + NS_ASSERTION(xpc::dom::instanceIsProxy(aWrapper), + "We have an expando but this isn't a DOM proxy?"); + js::SetProxyExtra(aWrapper, xpc::dom::JSPROXYSLOT_EXPANDO, + js::ObjectValue(*obj)); + } + + SetWrapperBits(aWrapper); +} + +inline JSObject* +nsWrapperCache::GetExpandoObjectPreserveColor() const +{ + JSObject *obj = GetJSObjectFromBits(); + if (!obj) { + return NULL; + } + + if (!IsProxy()) { + // If we support non-proxy dom binding objects then this should be: + //return xpc::dom::isExpandoObject(obj) ? obj : js::GetSlot(obj, EXPANDO_SLOT); + return NULL; + } + + // FIXME unmark gray? + if (xpc::dom::instanceIsProxy(obj)) { + return GetExpandoFromSlot(obj); + } + + return xpc::dom::isExpandoObject(obj) ? obj : NULL; +} + +inline JSObject* +nsWrapperCache::GetExpandoFromSlot(JSObject *obj) +{ + NS_ASSERTION(xpc::dom::instanceIsProxy(obj), + "Asking for an expando but this isn't a DOM proxy?"); + const js::Value &v = js::GetProxyExtra(obj, xpc::dom::JSPROXYSLOT_EXPANDO); + return v.isUndefined() ? NULL : v.toObjectOrNull(); +} + +inline void +nsWrapperCache::ClearWrapper() +{ + NS_ASSERTION(!PreservingWrapper(), "Clearing a preserved wrapper!"); + JSObject *obj = GetJSObjectFromBits(); + if (!obj) { + return; + } + + JSObject *expando; + if (xpc::dom::instanceIsProxy(obj)) { + expando = GetExpandoFromSlot(obj); + } + else { + // If we support non-proxy dom binding objects then this should be: + //expando = js::GetSlot(obj, EXPANDO_SLOT); + expando = NULL; + } + + SetWrapperBits(expando); +} + +inline void +nsWrapperCache::ClearWrapperIfProxy() +{ + if (!IsProxy()) { + return; + } + + RemoveExpandoObject(); + + SetWrapperBits(NULL); +} + +#endif /* nsWrapperCache_h___ */
--- a/js/src/xpconnect/src/dombindings.cpp +++ b/js/src/xpconnect/src/dombindings.cpp @@ -42,16 +42,18 @@ #include "xpcquickstubs.h" #include "XPCWrapper.h" #include "WrapperFactory.h" #include "nsIDOMNode.h" #include "nsDOMClassInfo.h" #include "nsGlobalWindow.h" +#include "jsiter.h" +#include "nsWrapperCacheInlines.h" extern XPCNativeInterface* interfaces[]; using namespace js; namespace xpc { namespace dom { @@ -134,25 +136,25 @@ NodeList<T>::getNodeList(JSObject *obj) return static_cast<T *>(js::GetProxyPrivate(obj).toPrivate()); } template<class T> uint32 NodeList<T>::getProtoShape(JSObject *obj) { JS_ASSERT(js::IsProxy(obj) && js::GetProxyHandler(obj) == &NodeList<T>::instance); - return js::GetProxyExtra(obj, 0).toPrivateUint32(); + return js::GetProxyExtra(obj, JSPROXYSLOT_PROTOSHAPE).toPrivateUint32(); } template<class T> void NodeList<T>::setProtoShape(JSObject *obj, uint32 shape) { JS_ASSERT(js::IsProxy(obj) && js::GetProxyHandler(obj) == &NodeList<T>::instance); - js::SetProxyExtra(obj, 0, PrivateUint32Value(shape)); + js::SetProxyExtra(obj, JSPROXYSLOT_PROTOSHAPE, PrivateUint32Value(shape)); } template<class T> bool NodeList<T>::instanceIsNodeListObject(JSContext *cx, JSObject *obj, JSObject *callee) { if (XPCWrapper::IsSecurityWrapper(obj)) { if (callee && js::GetObjectGlobal(obj) == js::GetObjectGlobal(callee)) { @@ -299,22 +301,39 @@ NodeList<T>::create(JSContext *cx, XPCWr NS_ADDREF(aNodeList); setProtoShape(obj, -1); aWrapperCache->SetWrapper(obj); return obj; } +static JSObject * +getExpandoObject(JSObject *obj) +{ + NS_ASSERTION(instanceIsProxy(obj), "expected a DOM proxy object"); + Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); + return v.isUndefined() ? NULL : v.toObjectOrNull(); +} + template<class T> bool NodeList<T>::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, PropertyDescriptor *desc) { - // FIXME: expandos + JSObject *expando = getExpandoObject(proxy); + uintN flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED; + if (expando && !JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) + return false; + if (desc->obj) { + // Pretend the property lives on the wrapper. + desc->obj = proxy; + return true; + } + bool isNumber; int32 index = nsDOMClassInfo::GetArrayIndexFromId(cx, id, &isNumber); if (isNumber && index >= 0) { T *nodeList = getNodeList(proxy); nsIContent *result = nodeList->GetNodeAt(PRUint32(index)); if (result) { jsval v; if (!WrapObject(cx, proxy, result, result, &v)) @@ -342,45 +361,99 @@ NodeList<T>::getPropertyDescriptor(JSCon if (desc->obj) return true; if (WrapperFactory::IsXrayWrapper(proxy)) return resolveNativeName(cx, proxy, id, desc); return JS_GetPropertyDescriptorById(cx, js::GetObjectProto(proxy), id, JSRESOLVE_QUALIFIED, desc); } +JSClass ExpandoClass = { + "DOM proxy binding expando object", + JSCLASS_HAS_PRIVATE, + JS_PropertyStub, + JS_PropertyStub, + JS_PropertyStub, + JS_StrictPropertyStub, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub +}; + +template<class T> +JSObject * +NodeList<T>::ensureExpandoObject(JSContext *cx, JSObject *obj) +{ + NS_ASSERTION(instanceIsProxy(obj), "expected a DOM proxy object"); + JSObject *expando = getExpandoObject(obj); + if (!expando) { + expando = JS_NewObjectWithGivenProto(cx, &ExpandoClass, nsnull, + js::GetObjectParent(obj)); + if (!expando) + return NULL; + + JSCompartment *compartment = js::GetObjectCompartment(obj); + xpc::CompartmentPrivate *priv = + static_cast<xpc::CompartmentPrivate *>(js_GetCompartmentPrivate(compartment)); + if (!priv->RegisterDOMExpandoObject(expando)) + return NULL; + + js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando)); + expando->setPrivate(js::GetProxyPrivate(obj).toPrivate()); + } + return expando; +} + template<class T> bool NodeList<T>::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc) { - // FIXME: expandos - return true; + JSObject *expando = ensureExpandoObject(cx, proxy); + if (!expando) + return false; + + return JS_DefinePropertyById(cx, expando, id, desc->value, desc->getter, desc->setter, + desc->attrs); } template<class T> bool NodeList<T>::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props) { - // FIXME: expandos + JSObject *expando = getExpandoObject(proxy); + if (expando && !GetPropertyNames(cx, expando, JSITER_OWNONLY | JSITER_HIDDEN, &props)) + return false; + PRUint32 length; getNodeList(proxy)->GetLength(&length); JS_ASSERT(int32(length) >= 0); for (int32 i = 0; i < int32(length); ++i) { if (!props.append(INT_TO_JSID(i))) return false; } return true; } template<class T> bool NodeList<T>::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { - // FIXME: expandos + JSBool b = true; + + JSObject *expando; + if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = getExpandoObject(proxy))) { + jsval v; + if (!JS_DeletePropertyById2(cx, expando, id, &v) || + !JS_ValueToBoolean(cx, v, &b)) { + return false; + } + } + + *bp = !!b; return true; } template<class T> bool NodeList<T>::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props) { // FIXME: enumerate proto as well @@ -394,42 +467,42 @@ NodeList<T>::fix(JSContext *cx, JSObject vp->setUndefined(); return true; } template<class T> bool NodeList<T>::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { - // FIXME: expandos + JSObject *expando = getExpandoObject(proxy); + if (expando) { + JSBool b = JS_TRUE; + JSBool ok = JS_HasPropertyById(cx, expando, id, &b); + *bp = !!b; + if (!ok || *bp) + return ok; + } + bool isNumber; int32 index = nsDOMClassInfo::GetArrayIndexFromId(cx, id, &isNumber); if (isNumber && index >= 0) { if (getNodeList(proxy)->GetNodeAt(PRUint32(index))) { *bp = true; return true; } } *bp = false; return true; } template<class T> bool NodeList<T>::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { - if (!hasOwn(cx, proxy, id, bp)) - return false; - if (*bp) - return true; - JSBool found; - if (!JS_HasPropertyById(cx, js::GetObjectProto(proxy), id, &found)) - return false; - *bp = !!found; - return true; + return ProxyHandler::has(cx, proxy, id, bp); } template<class T> bool NodeList<T>::cacheProtoShape(JSContext *cx, JSObject *proxy, JSObject *proto) { JSPropertyDescriptor desc; if (!JS_GetPropertyDescriptorById(cx, proto, nsDOMClassInfo::sLength_id, JSRESOLVE_QUALIFIED, &desc)) @@ -501,17 +574,25 @@ NodeList<T>::resolveNativeName(JSContext return true; } template<class T> bool NodeList<T>::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp) { - // FIXME: expandos + JSObject *expando = getExpandoObject(proxy); + if (expando) { + JSBool hasProp; + if (!JS_HasPropertyById(cx, expando, id, &hasProp)) + return false; + if (hasProp) + return JS_GetPropertyById(cx, expando, id, vp); + } + bool isNumber; int32 index = nsDOMClassInfo::GetArrayIndexFromId(cx, id, &isNumber); if (isNumber && index >= 0) { T *nodeList = getNodeList(proxy); nsIContent *result = nodeList->GetNodeAt(PRUint32(index)); if (result) return WrapObject(cx, proxy, result, result, vp); } @@ -538,28 +619,26 @@ NodeList<T>::get(JSContext *cx, JSObject } return JS_GetPropertyById(cx, proto, id, vp); } template<class T> bool NodeList<T>::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, - Value *vp) + Value *vp) { - // FIXME: expandos - return true; + return ProxyHandler::set(cx, proxy, proxy, id, strict, vp); } template<class T> bool NodeList<T>::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props) { - // FIXME: expandos - return getOwnPropertyNames(cx, proxy, props); + return ProxyHandler::keys(cx, proxy, props); } template<class T> bool NodeList<T>::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp) { JS_ReportError(cx, "FIXME"); return false; @@ -587,17 +666,17 @@ NodeList<nsINodeList>::obj_toString(JSCo return JS_NewStringCopyZ(cx, "[object NodeList]"); } template<class T> void NodeList<T>::finalize(JSContext *cx, JSObject *proxy) { T *nodeList = getNodeList(proxy); - nsWrapperCache* cache; + nsWrapperCache *cache; CallQueryInterface(nodeList, &cache); if (cache) { cache->ClearWrapper(); } NS_RELEASE(nodeList); } }
--- a/js/src/xpconnect/src/dombindings.h +++ b/js/src/xpconnect/src/dombindings.h @@ -37,31 +37,24 @@ * * ***** END LICENSE BLOCK ***** */ #ifndef dombindings_h #define dombindings_h #include "jsapi.h" #include "jsproxy.h" +#include "xpcpublic.h" class nsINodeList; class nsIHTMLCollection; namespace xpc { namespace dom { -extern int HandlerFamily; -inline void* ProxyFamily() { return &HandlerFamily; } -inline bool instanceIsDOMProxy(JSObject *obj) -{ - return js::IsProxy(obj) && - js::GetProxyHandler(obj)->family() == ProxyFamily(); -} - class NodeListBase : public js::ProxyHandler { public: NodeListBase() : js::ProxyHandler(ProxyFamily()) {} static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope, nsINodeList *aNodeList); static JSObject *create(JSContext *cx, XPCWrappedNativeScope *scope, nsIHTMLCollection *aHTMLCollection, @@ -85,16 +78,18 @@ class NodeList : public NodeListBase { static Methods sProtoMethods[]; static bool instanceIsNodeListObject(JSContext *cx, JSObject *obj, JSObject *callee); static JSObject *getPrototype(JSContext *cx, XPCWrappedNativeScope *scope); static T *getNodeList(JSObject *obj); + static JSObject *ensureExpandoObject(JSContext *cx, JSObject *obj); + static uint32 getProtoShape(JSObject *obj); static void setProtoShape(JSObject *obj, uint32 shape); static JSBool length_getter(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); static JSBool item(JSContext *cx, uintN argc, jsval *vp); static JSBool namedItem(JSContext *cx, uintN argc, jsval *vp); static bool cacheProtoShape(JSContext *cx, JSObject *proxy, JSObject *proto);
--- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -62,16 +62,17 @@ #include "XrayWrapper.h" #include "WrapperFactory.h" #include "AccessCheck.h" #include "jsdIDebuggerService.h" #include "xpcquickstubs.h" #include "dombindings.h" +#include "nsWrapperCacheInlines.h" NS_IMPL_THREADSAFE_ISUPPORTS7(nsXPConnect, nsIXPConnect, nsISupportsWeakReference, nsIThreadObserver, nsIJSRuntimeService, nsIJSContextStack, nsIThreadJSContextStack, @@ -903,17 +904,17 @@ nsXPConnect::Traverse(void *p, nsCycleCo // XXX This test does seem fragile, we should probably whitelist classes // that do hold a strong reference, but that might not be possible. else if(clazz->flags & JSCLASS_HAS_PRIVATE && clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "xpc_GetJSPrivate(obj)"); cb.NoteXPCOMChild(static_cast<nsISupports*>(xpc_GetJSPrivate(obj))); } - else if(xpc::dom::instanceIsDOMProxy(obj)) + else if(xpc::dom::instanceIsProxy(obj)) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "js::GetProxyPrivate(obj)"); nsISupports *identity = static_cast<nsISupports*>(js::GetProxyPrivate(obj).toPrivate()); cb.NoteXPCOMChild(identity); } return NS_OK;
--- a/js/src/xpconnect/src/qsgen.py +++ b/js/src/xpconnect/src/qsgen.py @@ -1696,16 +1696,17 @@ stubTopTemplate = '''\ #include "prtypes.h" #include "nsID.h" #include "%s" #include "nscore.h" #include "nsCOMPtr.h" #include "nsDependentString.h" #include "xpcprivate.h" // for XPCCallContext #include "xpcquickstubs.h" +#include "nsWrapperCacheInlines.h" #include "jsbuiltins.h" ''' def writeStubFile(filename, headerFilename, conf, interfaces): print "Creating stub file", filename make_targets.append(filename) f = open(filename, 'w')
--- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -49,16 +49,17 @@ #include "XPCWrapper.h" #include "nsJSPrincipals.h" #include "nsWrapperCache.h" #include "WrapperFactory.h" #include "AccessCheck.h" #include "nsJSUtils.h" #include "dombindings.h" +#include "nsWrapperCacheInlines.h" //#define STRICT_CHECK_OF_UNICODE #ifdef STRICT_CHECK_OF_UNICODE #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF80)) #else // STRICT_CHECK_OF_UNICODE #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF00)) #endif // STRICT_CHECK_OF_UNICODE
--- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -255,16 +255,17 @@ ContextCallback(JSContext *cx, uintN ope } return JS_TRUE; } xpc::CompartmentPrivate::~CompartmentPrivate() { delete waiverWrapperMap; delete expandoMap; + delete domExpandoMap; MOZ_COUNT_DTOR(xpc::CompartmentPrivate); } static JSBool CompartmentCallback(JSContext *cx, JSCompartment *compartment, uintN op) { JS_ASSERT(op == JSCOMPARTMENT_DESTROY); @@ -423,22 +424,32 @@ TraceExpandos(XPCWrappedNative *wn, JSOb { if(wn->IsWrapperExpired()) return PL_DHASH_REMOVE; JS_CALL_OBJECT_TRACER(static_cast<JSTracer *>(aClosure), expando, "expando object"); return PL_DHASH_NEXT; } static PLDHashOperator +TraceDOMExpandos(nsPtrHashKey<JSObject> *expando, void *aClosure) +{ + JS_CALL_OBJECT_TRACER(static_cast<JSTracer *>(aClosure), expando->GetKey(), + "DOM expando object"); + return PL_DHASH_NEXT; +} + +static PLDHashOperator TraceCompartment(xpc::PtrAndPrincipalHashKey *aKey, JSCompartment *compartment, void *aClosure) { xpc::CompartmentPrivate *priv = (xpc::CompartmentPrivate *) JS_GetCompartmentPrivate(static_cast<JSTracer *>(aClosure)->context, compartment); if (priv->expandoMap) priv->expandoMap->Enumerate(TraceExpandos, aClosure); + if (priv->domExpandoMap) + priv->domExpandoMap->EnumerateEntries(TraceDOMExpandos, aClosure); return PL_DHASH_NEXT; } void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc) { JSContext *iter = nsnull, *acx; while ((acx = JS_ContextIterator(GetJSRuntime(), &iter))) { JS_ASSERT(acx->hasRunOption(JSOPTION_UNROOTED_GLOBAL)); @@ -525,32 +536,42 @@ XPCJSRuntime::SuspectWrappedNative(JSCon // Only record objects that might be part of a cycle as roots, unless // the callback wants all traces (a debug feature). if(xpc_IsGrayGCThing(obj) || cb.WantAllTraces()) cb.NoteRoot(nsIProgrammingLanguage::JAVASCRIPT, obj, nsXPConnect::GetXPConnect()); } static PLDHashOperator -SuspectExpandos(XPCWrappedNative *wrapper, JSObject *&expando, void *arg) +SuspectExpandos(XPCWrappedNative *wrapper, JSObject *expando, void *arg) { Closure* closure = static_cast<Closure*>(arg); XPCJSRuntime::SuspectWrappedNative(closure->cx, wrapper, *closure->cb); return PL_DHASH_NEXT; } static PLDHashOperator +SuspectDOMExpandos(nsPtrHashKey<JSObject> *expando, void *arg) +{ + Closure *closure = static_cast<Closure*>(arg); + closure->cb->NoteXPCOMRoot(static_cast<nsISupports*>(expando->GetKey()->getPrivate())); + return PL_DHASH_NEXT; +} + +static PLDHashOperator SuspectCompartment(xpc::PtrAndPrincipalHashKey *key, JSCompartment *compartment, void *arg) { Closure* closure = static_cast<Closure*>(arg); xpc::CompartmentPrivate *priv = (xpc::CompartmentPrivate *) JS_GetCompartmentPrivate(closure->cx, compartment); if (priv->expandoMap) - priv->expandoMap->Enumerate(SuspectExpandos, arg); + priv->expandoMap->EnumerateRead(SuspectExpandos, arg); + if (priv->domExpandoMap) + priv->domExpandoMap->EnumerateEntries(SuspectDOMExpandos, arg); return PL_DHASH_NEXT; } void XPCJSRuntime::AddXPConnectRoots(JSContext* cx, nsCycleCollectionTraversalCallback &cb) { // For all JS objects that are held by native objects but aren't held
--- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -4425,42 +4425,45 @@ namespace xpc { struct CompartmentPrivate { CompartmentPrivate(PtrAndPrincipalHashKey *key, bool wantXrays, bool cycleCollectionEnabled) : key(key), ptr(nsnull), wantXrays(wantXrays), cycleCollectionEnabled(cycleCollectionEnabled), waiverWrapperMap(nsnull), - expandoMap(nsnull) + expandoMap(nsnull), + domExpandoMap(nsnull) { MOZ_COUNT_CTOR(xpc::CompartmentPrivate); } CompartmentPrivate(nsISupports *ptr, bool wantXrays, bool cycleCollectionEnabled) : key(nsnull), ptr(ptr), wantXrays(wantXrays), cycleCollectionEnabled(cycleCollectionEnabled), waiverWrapperMap(nsnull), - expandoMap(nsnull) + expandoMap(nsnull), + domExpandoMap(nsnull) { MOZ_COUNT_CTOR(xpc::CompartmentPrivate); } ~CompartmentPrivate(); // NB: key and ptr are mutually exclusive. nsAutoPtr<PtrAndPrincipalHashKey> key; nsCOMPtr<nsISupports> ptr; bool wantXrays; bool cycleCollectionEnabled; JSObject2JSObjectMap *waiverWrapperMap; // NB: we don't want this map to hold a strong reference to the wrapper. nsDataHashtable<nsPtrHashKey<XPCWrappedNative>, JSObject *> *expandoMap; + nsTHashtable<nsPtrHashKey<JSObject> > *domExpandoMap; nsCString location; bool RegisterExpandoObject(XPCWrappedNative *wn, JSObject *expando) { if (!expandoMap) { expandoMap = new nsDataHashtable<nsPtrHashKey<XPCWrappedNative>, JSObject *>(); if (!expandoMap->Init(8)) return false; } @@ -4483,16 +4486,32 @@ struct CompartmentPrivate * This lookup clears the gray bit before handing out the JSObject which * means that the object is guaranteed to be kept alive past the next CC. */ JSObject *LookupExpandoObject(XPCWrappedNative *wn) { JSObject *obj = LookupExpandoObjectPreserveColor(wn); xpc_UnmarkGrayObject(obj); return obj; } + + bool RegisterDOMExpandoObject(JSObject *expando) { + if (!domExpandoMap) { + domExpandoMap = new nsTHashtable<nsPtrHashKey<JSObject> >(); + if(!domExpandoMap->Init(8)) + { + domExpandoMap = nsnull; + return false; + } + } + return domExpandoMap->PutEntry(expando); + } + void RemoveDOMExpandoObject(JSObject *expando) { + if(domExpandoMap) + domExpandoMap->RemoveEntry(expando); + } }; inline bool CompartmentParticipatesInCycleCollection(JSContext *cx, JSCompartment *compartment) { CompartmentPrivate *priv = static_cast<CompartmentPrivate *>(JS_GetCompartmentPrivate(cx, compartment)); NS_ASSERTION(priv, "This should never be null!");
--- a/js/src/xpconnect/src/xpcpublic.h +++ b/js/src/xpconnect/src/xpcpublic.h @@ -40,16 +40,17 @@ #ifndef xpcpublic_h #define xpcpublic_h #include "jsapi.h" #include "jsclass.h" #include "jsfriendapi.h" #include "jsgc.h" #include "jspubtd.h" +#include "jsproxy.h" #include "nsISupports.h" #include "nsIPrincipal.h" #include "nsWrapperCache.h" #include "nsStringGlue.h" #include "nsTArray.h" class nsIPrincipal; @@ -178,24 +179,16 @@ xpc_UnmarkGrayObjectRecursive(JSObject* // be reached through it. inline void xpc_UnmarkGrayObject(JSObject *obj) { if(obj && xpc_IsGrayGCThing(obj)) xpc_UnmarkGrayObjectRecursive(obj); } -inline JSObject* -nsWrapperCache::GetWrapper() const -{ - JSObject* obj = GetWrapperPreserveColor(); - xpc_UnmarkGrayObject(obj); - return obj; -} - class nsIMemoryMultiReporterCallback; namespace mozilla { namespace xpconnect { namespace memory { struct CompartmentStats { @@ -265,9 +258,33 @@ void ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix, nsIMemoryMultiReporterCallback *callback, nsISupports *closure); } // namespace memory } // namespace xpconnect } // namespace mozilla +namespace xpc { +namespace dom { + +extern int HandlerFamily; +inline void* ProxyFamily() { return &HandlerFamily; } +inline bool instanceIsProxy(JSObject *obj) +{ + return js::IsProxy(obj) && + js::GetProxyHandler(obj)->family() == ProxyFamily(); +} +extern JSClass ExpandoClass; +inline bool isExpandoObject(JSObject *obj) +{ + return js::GetObjectJSClass(obj) == &ExpandoClass; +} + +enum { + JSPROXYSLOT_PROTOSHAPE = 0, + JSPROXYSLOT_EXPANDO = 1 +}; + +} +} + #endif
--- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -39,17 +39,17 @@ * * ***** END LICENSE BLOCK ***** */ /* Wrapper object for reflecting native xpcom objects into JavaScript. */ #include "xpcprivate.h" #include "nsCRT.h" #include "XPCWrapper.h" -#include "nsWrapperCache.h" +#include "nsWrapperCacheInlines.h" #include "xpclog.h" #include "jstl.h" #include "nsINode.h" #include "xpcquickstubs.h" #include "jsproxy.h" #include "AccessCheck.h" #include "WrapperFactory.h" #include "dombindings.h"
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -38,16 +38,17 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* JavaScript JSClasses and JSOps for our Wrapped Native JS Objects. */ #include "xpcprivate.h" #include "XPCWrapper.h" +#include "nsWrapperCacheInlines.h" /***************************************************************************/ // All of the exceptions thrown into JS from this file go through here. // That makes this a nice place to set a breakpoint. static JSBool Throw(uintN errNum, JSContext* cx) {
--- a/js/src/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/src/xpconnect/wrappers/WrapperFactory.cpp @@ -251,17 +251,17 @@ GetWrappedNative(JSContext *cx, JSObject static bool CanXray(JSObject *obj, bool *proxy) { if (IS_WN_WRAPPER(obj) || js::GetObjectClass(obj)->ext.innerObject) { *proxy = false; return true; } - return (*proxy = dom::instanceIsDOMProxy(obj)); + return (*proxy = dom::instanceIsProxy(obj)); } JSObject * WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSObject *parent, uintN flags) { NS_ASSERTION(!IsWrapper(obj) || GetProxyHandler(obj) == &WaiveXrayWrapperWrapper ||