From 5909fbe828da4ff704a8a73d1fdda8f110d12eaa Mon Sep 17 00:00:00 2001 From: "jst%netscape.com" Date: Sat, 27 Apr 2002 00:03:47 +0000 Subject: [PATCH] Fixing one more part of the DOM performance bug 118933. Cache the properties 'document' and 'window' on the global object in JS to avoid needing to go through XPConnect every time these are accessed. 2x speedup on some DOM testcases where the bulk of the time we spend is in the JS engine and XPConnect. r=peterv@netscape.com, sr=vidur@netscape.com --- dom/src/base/nsDOMClassInfo.cpp | 78 ++++++++++++++++++++++++++++++--- dom/src/base/nsDOMClassInfo.h | 6 +++ dom/src/base/nsGlobalWindow.cpp | 19 ++++++-- 3 files changed, 93 insertions(+), 10 deletions(-) diff --git a/dom/src/base/nsDOMClassInfo.cpp b/dom/src/base/nsDOMClassInfo.cpp index 0b2c68d091b..4101eb29d4d 100644 --- a/dom/src/base/nsDOMClassInfo.cpp +++ b/dom/src/base/nsDOMClassInfo.cpp @@ -839,6 +839,8 @@ JSString *nsDOMClassInfo::sOpen_id = nsnull; JSString *nsDOMClassInfo::sItem_id = nsnull; JSString *nsDOMClassInfo::sEnumerate_id = nsnull; JSString *nsDOMClassInfo::sNavigator_id = nsnull; +JSString *nsDOMClassInfo::sDocument_id = nsnull; +JSString *nsDOMClassInfo::sWindow_id = nsnull; const JSClass *nsDOMClassInfo::sObjectClass = nsnull; @@ -913,6 +915,8 @@ nsDOMClassInfo::DefineStaticJSStrings(JSContext *cx) sItem_id = ::JS_InternString(cx, "item"); sEnumerate_id = ::JS_InternString(cx, "enumerateProperties"); sNavigator_id = ::JS_InternString(cx, "navigator"); + sDocument_id = ::JS_InternString(cx, "document"); + sWindow_id = ::JS_InternString(cx, "window"); return NS_OK; } @@ -2666,6 +2670,8 @@ nsDOMClassInfo::ShutDown() sItem_id = jsnullstring; sEnumerate_id = jsnullstring; sNavigator_id = jsnullstring; + sDocument_id = jsnullstring; + sWindow_id = jsnullstring; NS_IF_RELEASE(sXPConnect); NS_IF_RELEASE(sSecMan); @@ -2769,10 +2775,13 @@ nsWindowSH::doCheckPropertyAccess(JSContext *cx, JSObject *obj, jsval id, return NS_OK; } - // Don't check when getting the Components property, - // since we check its properties anyway. This will help performance. + // Don't check when getting the document, window, or Components + // property, since we check its properties anyway. This will help + // performance. if (accessMode == nsIXPCSecurityManager::ACCESS_GET_PROPERTY && - id == STRING_TO_JSVAL(sComponents_id)) { + (id == STRING_TO_JSVAL(sDocument_id) || + id == STRING_TO_JSVAL(sWindow_id) || + id == STRING_TO_JSVAL(sComponents_id))) { return NS_OK; } @@ -2977,8 +2986,9 @@ nsWindowSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_OK; } - nsresult rv = doCheckPropertyAccess(cx, obj, id, wrapper, - nsIXPCSecurityManager::ACCESS_SET_PROPERTY); + nsresult rv = + doCheckPropertyAccess(cx, obj, id, wrapper, + nsIXPCSecurityManager::ACCESS_SET_PROPERTY); if (NS_FAILED(rv)) { // Security check failed. The security manager set a JS @@ -2996,8 +3006,9 @@ nsWindowSH::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, PRBool *_retval) { - nsresult rv = doCheckPropertyAccess(cx, obj, id, wrapper, - nsIXPCSecurityManager::ACCESS_SET_PROPERTY); + nsresult rv = + doCheckPropertyAccess(cx, obj, id, wrapper, + nsIXPCSecurityManager::ACCESS_SET_PROPERTY); if (NS_FAILED(rv)) { // Security check failed. The security manager set a JS @@ -3565,6 +3576,31 @@ nsWindowSH::GlobalResolve(nsISupports *native, JSContext *cx, JSObject *obj, return rv; } +// static +nsresult +nsWindowSH::CacheDocumentProperty(JSContext *cx, JSObject *obj, + nsIDOMWindow *window) +{ + nsCOMPtr document; + nsresult rv = window->GetDocument(getter_AddRefs(document)); + NS_ENSURE_SUCCESS(rv, rv); + + jsval v; + rv = WrapNative(cx, obj, document, NS_GET_IID(nsIDOMDocument), &v); + NS_ENSURE_SUCCESS(rv, rv); + + NS_NAMED_LITERAL_STRING(doc_str, "document"); + + if (!::JS_DefineUCProperty(cx, obj, NS_REINTERPRET_CAST(const jschar *, + doc_str.get()), + doc_str.Length(), v, nsnull, + nsnull, JSPROP_READONLY)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + NS_IMETHODIMP nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsval id, PRUint32 flags, @@ -3777,6 +3813,34 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_OK; } + + if (str == sDocument_id) { + nsCOMPtr window(do_QueryInterface(native)); + NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED); + + rv = CacheDocumentProperty(cx, obj, window); + NS_ENSURE_SUCCESS(rv, rv); + + *objp = obj; + + return NS_OK; + } + + if (str == sWindow_id) { + jsval v; + rv = WrapNative(cx, obj, native, NS_GET_IID(nsIDOMWindow), &v); + NS_ENSURE_SUCCESS(rv, rv); + + if (!::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), + ::JS_GetStringLength(str), v, nsnull, + nsnull, JSPROP_READONLY)) { + return NS_ERROR_FAILURE; + } + + *objp = obj; + + return NS_OK; + } } return nsEventRecieverSH::NewResolve(wrapper, cx, obj, id, flags, objp, diff --git a/dom/src/base/nsDOMClassInfo.h b/dom/src/base/nsDOMClassInfo.h index fb80f36e6b0..693ce0f3baa 100644 --- a/dom/src/base/nsDOMClassInfo.h +++ b/dom/src/base/nsDOMClassInfo.h @@ -45,6 +45,7 @@ #include "jsapi.h" #include "nsIScriptSecurityManager.h" +class nsIDOMWindow; class nsIDOMNSHTMLOptionCollection; class nsIPluginInstance; class nsIForm; @@ -233,6 +234,8 @@ protected: static JSString *sItem_id; static JSString *sEnumerate_id; static JSString *sNavigator_id; + static JSString *sDocument_id; + static JSString *sWindow_id; static const JSClass *sObjectClass; @@ -323,6 +326,9 @@ public: NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj); + static nsresult CacheDocumentProperty(JSContext *cx, JSObject *obj, + nsIDOMWindow *window); + static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { return new nsWindowSH(aData); diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index 2bdbe63bc7f..f192118707a 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -479,7 +479,9 @@ GlobalWindowImpl::SetNewDocument(nsIDOMDocument* aDocument, // not doing this unless there's a new document prevents a closed window's // JS properties from going away (that's good) and causes everything, // and I mean everything, to be leaked (that's bad) - ::JS_ClearScope((JSContext *)mContext->GetNativeContext(), mJSObject); + + ::JS_ClearScope((JSContext *)mContext->GetNativeContext(), + mJSObject); mIsScopeClear = PR_TRUE; } @@ -498,8 +500,19 @@ GlobalWindowImpl::SetNewDocument(nsIDOMDocument* aDocument, mDocument = aDocument; - if (mDocument && mContext && mIsScopeClear) { - mContext->InitContext(this); + if (mDocument && mContext) { + if (mIsScopeClear) { + mContext->InitContext(this); + } else if (mJSObject) { + // If we didn't clear the scope (i.e. the old document was + // about:blank) then we need to update the cached document + // property on the window to reflect the new document and not + // the old one. + + JSContext *cx = (JSContext *)mContext->GetNativeContext(); + + nsWindowSH::CacheDocumentProperty(cx, mJSObject, this); + } } // Clear our mutation bitfield.