From 18397aa44096df6ae7480f71a490239803128ce8 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 22 Jan 2014 18:50:32 +0100 Subject: [PATCH 01/59] Bug 958119 - Some cleanup for XPConnect. r=gabor --- js/xpconnect/loader/mozJSComponentLoader.cpp | 12 ++--- js/xpconnect/loader/mozJSSubScriptLoader.cpp | 27 +++++------ js/xpconnect/loader/mozJSSubScriptLoader.h | 8 ++-- js/xpconnect/src/XPCJSID.cpp | 40 ++++++++-------- js/xpconnect/src/XPCShellImpl.cpp | 24 +++++----- js/xpconnect/src/nsXPConnect.cpp | 48 ++++++++++---------- js/xpconnect/src/xpcpublic.h | 4 +- js/xpconnect/wrappers/WrapperFactory.cpp | 2 +- 8 files changed, 81 insertions(+), 84 deletions(-) diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index 6650f56209be..1b5e25cb6847 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -171,8 +171,8 @@ File(JSContext *cx, unsigned argc, Value *vp) return false; } - nsXPConnect* xpc = nsXPConnect::XPConnect(); - JSObject* glob = CurrentGlobalOrNull(cx); + nsXPConnect *xpc = nsXPConnect::XPConnect(); + JSObject *glob = CurrentGlobalOrNull(cx); nsCOMPtr holder; rv = xpc->WrapNativeToJSVal(cx, glob, native, nullptr, @@ -206,8 +206,8 @@ Blob(JSContext *cx, unsigned argc, Value *vp) return false; } - nsXPConnect* xpc = nsXPConnect::XPConnect(); - JSObject* glob = CurrentGlobalOrNull(cx); + nsXPConnect *xpc = nsXPConnect::XPConnect(); + JSObject *glob = CurrentGlobalOrNull(cx); nsCOMPtr holder; rv = xpc->WrapNativeToJSVal(cx, glob, native, nullptr, @@ -1141,9 +1141,9 @@ mozJSComponentLoader::Import(const nsACString& registryLocation, /* [noscript] JSObjectPtr importInto(in AUTF8String registryLocation, in JSObjectPtr targetObj); */ NS_IMETHODIMP -mozJSComponentLoader::ImportInto(const nsACString & aLocation, +mozJSComponentLoader::ImportInto(const nsACString &aLocation, JSObject *aTargetObj, - nsAXPCNativeCallContext * cc, + nsAXPCNativeCallContext *cc, JSObject **_retval) { JSContext *callercx; diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.cpp b/js/xpconnect/loader/mozJSSubScriptLoader.cpp index f5df37fc6987..ef2b496e3551 100644 --- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp +++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp @@ -93,25 +93,22 @@ ReportError(JSContext *cx, const char *msg) nsresult mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObjArg, - const nsAString& charset, const char *uriStr, + const nsAString &charset, const char *uriStr, nsIIOService *serv, nsIPrincipal *principal, bool reuseGlobal, JSScript **scriptp, JSFunction **functionp) { RootedObject target_obj(cx, targetObjArg); - nsCOMPtr chan; - nsCOMPtr instream; - JSErrorReporter er; - *scriptp = nullptr; *functionp = nullptr; - nsresult rv; // Instead of calling NS_OpenURI, we create the channel ourselves and call // SetContentType, to avoid expensive MIME type lookups (bug 632490). - rv = NS_NewChannel(getter_AddRefs(chan), uri, serv, - nullptr, nullptr, nsIRequest::LOAD_NORMAL); + nsCOMPtr chan; + nsCOMPtr instream; + nsresult rv = NS_NewChannel(getter_AddRefs(chan), uri, serv, + nullptr, nullptr, nsIRequest::LOAD_NORMAL); if (NS_SUCCEEDED(rv)) { chan->SetContentType(NS_LITERAL_CSTRING("application/javascript")); rv = chan->Open(getter_AddRefs(instream)); @@ -139,7 +136,7 @@ mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObj /* set our own error reporter so we can report any bad things as catchable * exceptions, including the source/line number */ - er = JS_SetErrorReporter(cx, xpc::SystemErrorReporter); + JSErrorReporter er = JS_SetErrorReporter(cx, xpc::SystemErrorReporter); JS::CompileOptions options(cx); options.setPrincipals(nsJSPrincipals::get(principal)) @@ -183,9 +180,9 @@ mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObj } NS_IMETHODIMP -mozJSSubScriptLoader::LoadSubScript(const nsAString& url, +mozJSSubScriptLoader::LoadSubScript(const nsAString &url, HandleValue target, - const nsAString& charset, + const nsAString &charset, JSContext *cx, MutableHandleValue retval) { @@ -208,7 +205,7 @@ mozJSSubScriptLoader::LoadSubScript(const nsAString& url, NS_IMETHODIMP -mozJSSubScriptLoader::LoadSubScriptWithOptions(const nsAString& url, +mozJSSubScriptLoader::LoadSubScriptWithOptions(const nsAString &url, HandleValue optionsVal, JSContext *cx, MutableHandleValue retval) @@ -222,8 +219,8 @@ mozJSSubScriptLoader::LoadSubScriptWithOptions(const nsAString& url, } nsresult -mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url, - LoadSubScriptOptions& options, +mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString &url, + LoadSubScriptOptions &options, JSContext *cx, MutableHandleValue retval) { @@ -242,7 +239,7 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url, } RootedObject targetObj(cx); - mozJSComponentLoader* loader = mozJSComponentLoader::Get(); + mozJSComponentLoader *loader = mozJSComponentLoader::Get(); rv = loader->FindTargetObject(cx, &targetObj); NS_ENSURE_SUCCESS(rv, rv); diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.h b/js/xpconnect/loader/mozJSSubScriptLoader.h index 1c1579b6c8db..3a0822206a9b 100644 --- a/js/xpconnect/loader/mozJSSubScriptLoader.h +++ b/js/xpconnect/loader/mozJSSubScriptLoader.h @@ -33,14 +33,14 @@ public: private: nsresult ReadScript(nsIURI *uri, JSContext *cx, JSObject *target_obj, - const nsAString& charset, const char *uriStr, + const nsAString &charset, const char *uriStr, nsIIOService *serv, nsIPrincipal *principal, bool reuseGlobal, JSScript **scriptp, JSFunction **functionp); - nsresult DoLoadSubScriptWithOptions(const nsAString& url, - LoadSubScriptOptions& options, - JSContext* cx, + nsresult DoLoadSubScriptWithOptions(const nsAString &url, + LoadSubScriptOptions &options, + JSContext *cx, JS::MutableHandle retval); nsCOMPtr mSystemPrincipal; diff --git a/js/xpconnect/src/XPCJSID.cpp b/js/xpconnect/src/XPCJSID.cpp index 203f5eb1f14b..ec367198762b 100644 --- a/js/xpconnect/src/XPCJSID.cpp +++ b/js/xpconnect/src/XPCJSID.cpp @@ -538,7 +538,7 @@ xpc::HasInstance(JSContext *cx, HandleObject objArg, const nsID *iid, bool *bp) /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */ NS_IMETHODIMP nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper, - JSContext * cx, JSObject * /* unused */, + JSContext *cx, JSObject * /* unused */, HandleValue val, bool *bp, bool *_retval) { *bp = false; @@ -671,7 +671,7 @@ GetWrapperObject(MutableHandleObject obj) /* nsISupports createInstance (); */ NS_IMETHODIMP -nsJSCID::CreateInstance(HandleValue iidval, JSContext* cx, +nsJSCID::CreateInstance(HandleValue iidval, JSContext *cx, uint8_t optionalArgc, MutableHandleValue retval) { if (!mDetails.IsValid()) @@ -714,8 +714,8 @@ nsJSCID::CreateInstance(HandleValue iidval, JSContext* cx, /* nsISupports getService (); */ NS_IMETHODIMP -nsJSCID::GetService(HandleValue iidval, JSContext* cx, - uint8_t optionalArgc, MutableHandleValue retval) +nsJSCID::GetService(HandleValue iidval, JSContext *cx, uint8_t optionalArgc, + MutableHandleValue retval) { if (!mDetails.IsValid()) return NS_ERROR_XPC_BAD_CID; @@ -726,7 +726,7 @@ nsJSCID::GetService(HandleValue iidval, JSContext* cx, return NS_ERROR_UNEXPECTED; } - nsIXPCSecurityManager* sm; + nsIXPCSecurityManager *sm; sm = nsXPConnect::XPConnect()->GetDefaultSecurityManager(); if (sm && NS_FAILED(sm->CanCreateInstance(cx, mDetails.ID()))) { MOZ_ASSERT(JS_IsExceptionPending(cx), @@ -735,7 +735,7 @@ nsJSCID::GetService(HandleValue iidval, JSContext* cx, } // If an IID was passed in then use it - const nsID* iid = GetIIDArg(optionalArgc, iidval, cx); + const nsID *iid = GetIIDArg(optionalArgc, iidval, cx); if (!iid) return NS_ERROR_XPC_BAD_IID; @@ -750,22 +750,19 @@ nsJSCID::GetService(HandleValue iidval, JSContext* cx, if (NS_FAILED(rv) || !srvc) return NS_ERROR_XPC_GS_RETURNED_FAILURE; - RootedObject instJSObj(cx); nsCOMPtr holder; rv = nsXPConnect::XPConnect()->WrapNative(cx, obj, srvc, *iid, getter_AddRefs(holder)); - if (NS_FAILED(rv) || !holder || - // Assign, not compare - !(instJSObj = holder->GetJSObject())) + if (NS_FAILED(rv) || !holder || !holder->GetJSObject()) return NS_ERROR_XPC_CANT_CREATE_WN; - retval.setObject(*instJSObj); + retval.setObject(*holder->GetJSObject()); return NS_OK; } /* bool construct (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in uint32_t argc, in JSValPtr argv, in JSValPtr vp); */ NS_IMETHODIMP nsJSCID::Construct(nsIXPConnectWrappedNative *wrapper, - JSContext * cx, JSObject * objArg, + JSContext *cx, JSObject *objArg, const CallArgs &args, bool *_retval) { RootedObject obj(cx, objArg); @@ -785,24 +782,24 @@ nsJSCID::Construct(nsIXPConnectWrappedNative *wrapper, /* bool hasInstance (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval val, out bool bp); */ NS_IMETHODIMP nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper, - JSContext * cx, JSObject * /* unused */, + JSContext *cx, JSObject * /* unused */, HandleValue val, bool *bp, bool *_retval) { *bp = false; nsresult rv = NS_OK; - if (!JSVAL_IS_PRIMITIVE(val)) { + if (val.isObject()) { // we have a JSObject RootedObject obj(cx, &val.toObject()); MOZ_ASSERT(obj, "when is an object not an object?"); // is this really a native xpcom object with a wrapper? - nsIClassInfo* ci = nullptr; + nsIClassInfo *ci = nullptr; obj = FindObjectForHasInstance(cx, obj); if (!obj || !IS_WN_REFLECTOR(obj)) return rv; - if (XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj)) + if (XPCWrappedNative *other_wrapper = XPCWrappedNative::Get(obj)) ci = other_wrapper->GetClassInfo(); // We consider CID equality to be the thing that matters here. @@ -813,6 +810,7 @@ nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper, *bp = cid.Equals(mDetails.ID()); } } + return rv; } @@ -826,7 +824,7 @@ xpc_NewIDObject(JSContext *cx, HandleObject jsobj, const nsID& aID) nsCOMPtr iid = nsJSID::NewID(aID); if (iid) { - nsXPConnect* xpc = nsXPConnect::XPConnect(); + nsXPConnect *xpc = nsXPConnect::XPConnect(); if (xpc) { nsCOMPtr holder; nsresult rv = xpc->WrapNative(cx, jsobj, @@ -843,13 +841,13 @@ xpc_NewIDObject(JSContext *cx, HandleObject jsobj, const nsID& aID) // note: returned pointer is only valid while |obj| remains alive! const nsID* -xpc_JSObjectToID(JSContext *cx, JSObject* obj) +xpc_JSObjectToID(JSContext *cx, JSObject *obj) { if (!cx || !obj) return nullptr; // NOTE: this call does NOT addref - XPCWrappedNative* wrapper = nullptr; + XPCWrappedNative *wrapper = nullptr; obj = js::CheckedUnwrap(obj); if (obj && IS_WN_REFLECTOR(obj)) wrapper = XPCWrappedNative::Get(obj); @@ -863,11 +861,11 @@ xpc_JSObjectToID(JSContext *cx, JSObject* obj) } bool -xpc_JSObjectIsID(JSContext *cx, JSObject* obj) +xpc_JSObjectIsID(JSContext *cx, JSObject *obj) { MOZ_ASSERT(cx && obj, "bad param"); // NOTE: this call does NOT addref - XPCWrappedNative* wrapper = nullptr; + XPCWrappedNative *wrapper = nullptr; obj = js::CheckedUnwrap(obj); if (obj && IS_WN_REFLECTOR(obj)) wrapper = XPCWrappedNative::Get(obj); diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index 279e8e79fff8..1f100c4e4de7 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -538,25 +538,27 @@ Parent(JSContext *cx, unsigned argc, jsval *vp) } static bool -Atob(JSContext *cx, unsigned argc, jsval *vp) +Atob(JSContext *cx, unsigned argc, Value *vp) { - if (!argc) + CallArgs args = CallArgsFromVp(argc, vp); + if (!args.length()) return true; - return xpc::Base64Decode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp)); + return xpc::Base64Decode(cx, args[0], args.rval()); } static bool -Btoa(JSContext *cx, unsigned argc, jsval *vp) +Btoa(JSContext *cx, unsigned argc, Value *vp) { - if (!argc) - return true; + CallArgs args = CallArgsFromVp(argc, vp); + if (!args.length()) + return true; - return xpc::Base64Encode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp)); + return xpc::Base64Encode(cx, args[0], args.rval()); } static bool -Blob(JSContext *cx, unsigned argc, jsval *vp) +Blob(JSContext *cx, unsigned argc, Value *vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); @@ -582,7 +584,7 @@ Blob(JSContext *cx, unsigned argc, jsval *vp) return false; } - JSObject* global = JS::CurrentGlobalOrNull(cx); + JSObject *global = JS::CurrentGlobalOrNull(cx); rv = xpc->WrapNativeToJSVal(cx, global, native, nullptr, &NS_GET_IID(nsISupports), true, args.rval()); @@ -595,7 +597,7 @@ Blob(JSContext *cx, unsigned argc, jsval *vp) } static bool -File(JSContext *cx, unsigned argc, jsval *vp) +File(JSContext *cx, unsigned argc, Value *vp) { JS::CallArgs args = CallArgsFromVp(argc, vp); @@ -621,7 +623,7 @@ File(JSContext *cx, unsigned argc, jsval *vp) return false; } - JSObject* global = JS::CurrentGlobalOrNull(cx); + JSObject *global = JS::CurrentGlobalOrNull(cx); rv = xpc->WrapNativeToJSVal(cx, global, native, nullptr, &NS_GET_IID(nsISupports), true, args.rval()); diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 19137da2caa5..63452974bda7 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -573,11 +573,11 @@ nsXPConnect::WrapNative(JSContext * aJSContext, /* void wrapNativeToJSVal (in JSContextPtr aJSContext, in JSObjectPtr aScope, in nsISupports aCOMObj, in nsIIDPtr aIID, out jsval aVal, out nsIXPConnectJSObjectHolder aHolder); */ NS_IMETHODIMP -nsXPConnect::WrapNativeToJSVal(JSContext * aJSContext, - JSObject * aScopeArg, +nsXPConnect::WrapNativeToJSVal(JSContext *aJSContext, + JSObject *aScopeArg, nsISupports *aCOMObj, nsWrapperCache *aCache, - const nsIID * aIID, + const nsIID *aIID, bool aAllowWrapping, MutableHandleValue aVal) { @@ -616,7 +616,7 @@ nsXPConnect::WrapJS(JSContext * aJSContext, NS_IMETHODIMP nsXPConnect::JSValToVariant(JSContext *cx, HandleValue aJSVal, - nsIVariant ** aResult) + nsIVariant **aResult) { NS_PRECONDITION(aResult, "bad param"); @@ -629,10 +629,10 @@ nsXPConnect::JSValToVariant(JSContext *cx, /* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */ NS_IMETHODIMP nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter, - JSContext * aJSContext, - JSObject * aJSObjArg, - const nsIID & aIID, - void * *result) + JSContext *aJSContext, + JSObject *aJSObjArg, + const nsIID &aIID, + void **result) { MOZ_ASSERT(aOuter, "bad param"); MOZ_ASSERT(aJSContext, "bad param"); @@ -673,8 +673,8 @@ nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext, /* nsISupports getNativeOfWrapper(in JSContextPtr aJSContext, in JSObjectPtr aJSObj); */ NS_IMETHODIMP_(nsISupports*) -nsXPConnect::GetNativeOfWrapper(JSContext * aJSContext, - JSObject * aJSObj) +nsXPConnect::GetNativeOfWrapper(JSContext *aJSContext, + JSObject *aJSObj) { MOZ_ASSERT(aJSContext, "bad param"); MOZ_ASSERT(aJSObj, "bad param"); @@ -1331,10 +1331,9 @@ nsXPConnect::HoldObject(JSContext *aJSContext, JSObject *aObjectArg, namespace xpc { NS_EXPORT_(bool) -Base64Encode(JSContext *cx, JS::Value val, JS::Value *out) +Base64Encode(JSContext *cx, HandleValue val, MutableHandleValue out) { MOZ_ASSERT(cx); - MOZ_ASSERT(out); JS::RootedValue root(cx, val); xpc_qsACString encodedString(cx, root, &root, false, @@ -1353,15 +1352,14 @@ Base64Encode(JSContext *cx, JS::Value val, JS::Value *out) if (!str) return false; - *out = STRING_TO_JSVAL(str); + out.setString(str); return true; } NS_EXPORT_(bool) -Base64Decode(JSContext *cx, JS::Value val, JS::Value *out) +Base64Decode(JSContext *cx, HandleValue val, MutableHandleValue out) { MOZ_ASSERT(cx); - MOZ_ASSERT(out); JS::RootedValue root(cx, val); xpc_qsACString encodedString(cx, root, &root, false, @@ -1380,7 +1378,7 @@ Base64Decode(JSContext *cx, JS::Value val, JS::Value *out) if (!str) return false; - *out = STRING_TO_JSVAL(str); + out.setString(str); return true; } @@ -1419,12 +1417,12 @@ nsXPConnect::GetTelemetryValue(JSContext *cx, MutableHandleValue rval) unsigned attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT; size_t i = JS_SetProtoCalled(cx); - RootedValue v(cx, DOUBLE_TO_JSVAL(i)); + RootedValue v(cx, DoubleValue(i)); if (!JS_DefineProperty(cx, obj, "setProto", v, nullptr, nullptr, attrs)) return NS_ERROR_OUT_OF_MEMORY; i = JS_GetCustomIteratorCount(cx); - v = DOUBLE_TO_JSVAL(i); + v.setDouble(i); if (!JS_DefineProperty(cx, obj, "customIter", v, nullptr, nullptr, attrs)) return NS_ERROR_OUT_OF_MEMORY; @@ -1652,21 +1650,23 @@ JS_EXPORT_API(void) DumpCompleteHeap() namespace xpc { bool -Atob(JSContext *cx, unsigned argc, jsval *vp) +Atob(JSContext *cx, unsigned argc, Value *vp) { - if (!argc) + CallArgs args = CallArgsFromVp(argc, vp); + if (!args.length()) return true; - return xpc::Base64Decode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp)); + return xpc::Base64Decode(cx, args[0], args.rval()); } bool -Btoa(JSContext *cx, unsigned argc, jsval *vp) +Btoa(JSContext *cx, unsigned argc, Value *vp) { - if (!argc) + CallArgs args = CallArgsFromVp(argc, vp); + if (!args.length()) return true; - return xpc::Base64Encode(cx, JS_ARGV(cx, vp)[0], &JS_RVAL(cx, vp)); + return xpc::Base64Encode(cx, args[0], args.rval()); } bool diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index aae293bf1322..9a3165a5145c 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -247,8 +247,8 @@ private: namespace xpc { // If these functions return false, then an exception will be set on cx. -NS_EXPORT_(bool) Base64Encode(JSContext *cx, JS::Value val, JS::Value *out); -NS_EXPORT_(bool) Base64Decode(JSContext *cx, JS::Value val, JS::Value *out); +NS_EXPORT_(bool) Base64Encode(JSContext *cx, JS::HandleValue val, JS::MutableHandleValue out); +NS_EXPORT_(bool) Base64Decode(JSContext *cx, JS::HandleValue val, JS::MutableHandleValue out); /** * Convert an nsString to jsval, returning true on success. diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index 9cd99b7ce5a4..2bedffa7fad6 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -285,7 +285,7 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope, &NS_GET_IID(nsISupports), false, &v); NS_ENSURE_SUCCESS(rv, nullptr); - obj = JSVAL_TO_OBJECT(v); + obj.set(&v.toObject()); MOZ_ASSERT(IS_WN_REFLECTOR(obj), "bad object"); // Because the underlying native didn't have a PreCreate hook, we had From b97f2606bc43c38b8cbed10dca502af35d407040 Mon Sep 17 00:00:00 2001 From: Alexandre Poirot Date: Wed, 22 Jan 2014 10:06:29 -0800 Subject: [PATCH 02/59] Bug 961655 - Ensure that webapps-registry-ready event is fired, even if the Webapps registry is initialized before shell.html is loaded. r=fabrice --- b2g/chrome/content/shell.js | 16 +++++++--------- dom/apps/src/Webapps.jsm | 12 ++++++++++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index d48980d86352..40e90f6e40d6 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -28,6 +28,9 @@ Cu.import('resource://gre/modules/FxAccountsMgmtService.jsm'); Cu.import('resource://gre/modules/DownloadsAPI.jsm'); +Cu.import('resource://gre/modules/Webapps.jsm'); +DOMApplicationRegistry.allAppsLaunchable = true; + XPCOMUtils.defineLazyServiceGetter(Services, 'env', '@mozilla.org/process/environment;1', 'nsIEnvironment'); @@ -268,7 +271,6 @@ var shell = { alert(msg); return; } - let manifestURL = this.manifestURL; // Date: Wed, 22 Jan 2014 10:08:48 -0800 Subject: [PATCH 03/59] bug 962229 - suppress spurious error messages about webapps.json not found on Fennec firstrun; r=fabrice --HG-- extra : amend_source : 5ddf753e11f7d3a7d120d1db5f0700db810a2a8a --- dom/apps/src/Webapps.jsm | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm index e4258236a6ba..b98e64d4fcef 100755 --- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -979,9 +979,17 @@ this.DOMApplicationRegistry = { channel.contentType = "application/json"; NetUtil.asyncFetch(channel, function(aStream, aResult) { if (!Components.isSuccessCode(aResult)) { + deferred.resolve(null); + + if (aResult == Cr.NS_ERROR_FILE_NOT_FOUND) { + // We expect this under certain circumstances, like for webapps.json + // on firstrun, so we return early without reporting an error. + return; + } + Cu.reportError("DOMApplicationRegistry: Could not read from json file " + aPath); - deferred.resolve(null); + return; } try { From 2ef3639bf3f6a15a98f2be8657eb8a0fb075b94d Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Fri, 17 Jan 2014 17:39:02 -0600 Subject: [PATCH 04/59] Bug 916564 - Move countFinalSourceNotes to a better place (r=jorendorff) --HG-- extra : rebase_source : c0b10f87f1e10499586fed2e4fa570edfcaaf510 --- js/src/frontend/BytecodeEmitter.cpp | 55 +++++++++++++++-------------- js/src/frontend/BytecodeEmitter.h | 34 +----------------- 2 files changed, 29 insertions(+), 60 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index ddb0b47696bd..d8146bbb3df6 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -6740,36 +6740,37 @@ SetSrcNoteOffset(ExclusiveContext *cx, BytecodeEmitter *bce, unsigned index, uns return true; } -#ifdef DEBUG_notme -#define DEBUG_srcnotesize -#endif - -#ifdef DEBUG_srcnotesize -#define NBINS 10 -static uint32_t hist[NBINS]; - -static void -DumpSrcNoteSizeHist() +/* + * Finish taking source notes in cx's notePool, copying final notes to the new + * stable store allocated by the caller and passed in via notes. Return false + * on malloc failure, which means this function reported an error. + * + * Use this to compute the number of jssrcnotes to allocate and pass in via + * notes. This method knows a lot about details of FinishTakingSrcNotes, so + * DON'T CHANGE js::frontend::FinishTakingSrcNotes WITHOUT CHECKING WHETHER + * THIS METHOD NEEDS CORRESPONDING CHANGES! + */ +ptrdiff_t +BytecodeEmitter::countFinalSourceNotes() { - static FILE *fp; - int i, n; - - if (!fp) { - fp = fopen("/tmp/srcnotes.hist", "w"); - if (!fp) - return; - setvbuf(fp, nullptr, _IONBF, 0); + ptrdiff_t diff = prologOffset() - prolog.lastNoteOffset; + ptrdiff_t cnt = prolog.notes.length() + main.notes.length() + 1; + if (prolog.notes.length() && prolog.currentLine != firstLine) { + if (diff > SN_DELTA_MASK) + cnt += JS_HOWMANY(diff - SN_DELTA_MASK, SN_XDELTA_MASK); + cnt += 2 + ((firstLine > SN_3BYTE_OFFSET_MASK) << 1); + } else if (diff > 0) { + if (main.notes.length()) { + jssrcnote *sn = main.notes.begin(); + diff -= SN_IS_XDELTA(sn) + ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK) + : SN_DELTA_MASK - (*sn & SN_DELTA_MASK); + } + if (diff > 0) + cnt += JS_HOWMANY(diff, SN_XDELTA_MASK); } - fprintf(fp, "SrcNote size histogram:\n"); - for (i = 0; i < NBINS; i++) { - fprintf(fp, "%4u %4u ", JS_BIT(i), hist[i]); - for (n = (int) JS_HOWMANY(hist[i], 10); n > 0; --n) - fputc('*', fp); - fputc('\n', fp); - } - fputc('\n', fp); + return cnt; } -#endif /* * Fill in the storage at notes with prolog and main srcnotes; the space at diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index df0ff0de2d88..b0ea85e53e98 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -216,7 +216,7 @@ struct BytecodeEmitter unsigned currentLine() const { return current->currentLine; } unsigned lastColumn() const { return current->lastColumn; } - inline ptrdiff_t countFinalSourceNotes(); + ptrdiff_t countFinalSourceNotes(); bool reportError(ParseNode *pn, unsigned errorNumber, ...); bool reportStrictWarning(ParseNode *pn, unsigned errorNumber, ...); @@ -282,38 +282,6 @@ AddToSrcNoteDelta(ExclusiveContext *cx, BytecodeEmitter *bce, jssrcnote *sn, ptr bool FinishTakingSrcNotes(ExclusiveContext *cx, BytecodeEmitter *bce, jssrcnote *notes); -/* - * Finish taking source notes in cx's notePool, copying final notes to the new - * stable store allocated by the caller and passed in via notes. Return false - * on malloc failure, which means this function reported an error. - * - * Use this to compute the number of jssrcnotes to allocate and pass in via - * notes. This method knows a lot about details of FinishTakingSrcNotes, so - * DON'T CHANGE js::frontend::FinishTakingSrcNotes WITHOUT CHECKING WHETHER - * THIS METHOD NEEDS CORRESPONDING CHANGES! - */ -inline ptrdiff_t -BytecodeEmitter::countFinalSourceNotes() -{ - ptrdiff_t diff = prologOffset() - prolog.lastNoteOffset; - ptrdiff_t cnt = prolog.notes.length() + main.notes.length() + 1; - if (prolog.notes.length() && prolog.currentLine != firstLine) { - if (diff > SN_DELTA_MASK) - cnt += JS_HOWMANY(diff - SN_DELTA_MASK, SN_XDELTA_MASK); - cnt += 2 + ((firstLine > SN_3BYTE_OFFSET_MASK) << 1); - } else if (diff > 0) { - if (main.notes.length()) { - jssrcnote *sn = main.notes.begin(); - diff -= SN_IS_XDELTA(sn) - ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK) - : SN_DELTA_MASK - (*sn & SN_DELTA_MASK); - } - if (diff > 0) - cnt += JS_HOWMANY(diff, SN_XDELTA_MASK); - } - return cnt; -} - } /* namespace frontend */ } /* namespace js */ From 4fed24046792a9a02b2f022867f7de3c08921242 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Fri, 17 Jan 2014 17:40:41 -0600 Subject: [PATCH 05/59] Bug 916564 - Expand source notes to hold 31-bit offsets (r=jorendorff) --HG-- extra : rebase_source : bf350f233c514d6a97273d2ee23ce68476ae3b79 --- js/src/frontend/BytecodeEmitter.cpp | 39 ++++++++++++++++++----------- js/src/frontend/SourceNotes.h | 12 ++++----- js/src/jsopcode.h | 4 +-- js/src/jsscript.cpp | 5 +--- 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index d8146bbb3df6..4a93ea6a66a8 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -314,6 +314,12 @@ EmitBackPatchOp(ExclusiveContext *cx, BytecodeEmitter *bce, ptrdiff_t *lastp) return EmitJump(cx, bce, JSOP_BACKPATCH, delta); } +static inline unsigned +LengthOfSetLine(unsigned line) +{ + return 1 /* SN_SETLINE */ + (line > SN_4BYTE_OFFSET_MASK ? 4 : 1); +} + /* Updates line number notes, not column notes. */ static inline bool UpdateLineNumberNotes(ExclusiveContext *cx, BytecodeEmitter *bce, uint32_t offset) @@ -336,7 +342,7 @@ UpdateLineNumberNotes(ExclusiveContext *cx, BytecodeEmitter *bce, uint32_t offse */ bce->current->currentLine = line; bce->current->lastColumn = 0; - if (delta >= (unsigned)(2 + ((line > SN_3BYTE_OFFSET_MASK)<<1))) { + if (delta >= LengthOfSetLine(line)) { if (NewSrcNote2(cx, bce, SRC_SETLINE, (ptrdiff_t)line) < 0) return false; } else { @@ -6712,8 +6718,8 @@ SetSrcNoteOffset(ExclusiveContext *cx, BytecodeEmitter *bce, unsigned index, uns JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA); JS_ASSERT((int) which < js_SrcNoteSpec[SN_TYPE(sn)].arity); for (sn++; which; sn++, which--) { - if (*sn & SN_3BYTE_OFFSET_FLAG) - sn += 2; + if (*sn & SN_4BYTE_OFFSET_FLAG) + sn += 3; } /* @@ -6721,19 +6727,21 @@ SetSrcNoteOffset(ExclusiveContext *cx, BytecodeEmitter *bce, unsigned index, uns * the offset has already been inflated (in which case, we need to stay big * to not break the srcnote encoding if this isn't the last srcnote). */ - if (offset > (ptrdiff_t)SN_3BYTE_OFFSET_MASK || (*sn & SN_3BYTE_OFFSET_FLAG)) { + if (offset > (ptrdiff_t)SN_4BYTE_OFFSET_MASK || (*sn & SN_4BYTE_OFFSET_FLAG)) { /* Maybe this offset was already set to a three-byte value. */ - if (!(*sn & SN_3BYTE_OFFSET_FLAG)) { + if (!(*sn & SN_4BYTE_OFFSET_FLAG)) { /* Insert two dummy bytes that will be overwritten shortly. */ jssrcnote dummy = 0; if (!(sn = notes.insert(sn, dummy)) || + !(sn = notes.insert(sn, dummy)) || !(sn = notes.insert(sn, dummy))) { js_ReportOutOfMemory(cx); return false; } } - *sn++ = (jssrcnote)(SN_3BYTE_OFFSET_FLAG | (offset >> 16)); + *sn++ = (jssrcnote)(SN_4BYTE_OFFSET_FLAG | (offset >> 24)); + *sn++ = (jssrcnote)(offset >> 16); *sn++ = (jssrcnote)(offset >> 8); } *sn = (jssrcnote)offset; @@ -6758,7 +6766,7 @@ BytecodeEmitter::countFinalSourceNotes() if (prolog.notes.length() && prolog.currentLine != firstLine) { if (diff > SN_DELTA_MASK) cnt += JS_HOWMANY(diff - SN_DELTA_MASK, SN_XDELTA_MASK); - cnt += 2 + ((firstLine > SN_3BYTE_OFFSET_MASK) << 1); + cnt += LengthOfSetLine(firstLine); } else if (diff > 0) { if (main.notes.length()) { jssrcnote *sn = main.notes.begin(); @@ -7033,8 +7041,8 @@ js_SrcNoteLength(jssrcnote *sn) arity = SrcNoteArity(sn); for (base = sn++; arity; sn++, arity--) { - if (*sn & SN_3BYTE_OFFSET_FLAG) - sn += 2; + if (*sn & SN_4BYTE_OFFSET_FLAG) + sn += 3; } return sn - base; } @@ -7046,13 +7054,14 @@ js_GetSrcNoteOffset(jssrcnote *sn, unsigned which) JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA); JS_ASSERT((int) which < SrcNoteArity(sn)); for (sn++; which; sn++, which--) { - if (*sn & SN_3BYTE_OFFSET_FLAG) - sn += 2; + if (*sn & SN_4BYTE_OFFSET_FLAG) + sn += 3; } - if (*sn & SN_3BYTE_OFFSET_FLAG) { - return (ptrdiff_t)(((uint32_t)(sn[0] & SN_3BYTE_OFFSET_MASK) << 16) - | (sn[1] << 8) - | sn[2]); + if (*sn & SN_4BYTE_OFFSET_FLAG) { + return (ptrdiff_t)(((uint32_t)(sn[0] & SN_4BYTE_OFFSET_MASK) << 24) + | (sn[1] << 16) + | (sn[2] << 8) + | sn[3]); } return (ptrdiff_t)*sn; } diff --git a/js/src/frontend/SourceNotes.h b/js/src/frontend/SourceNotes.h index 86b5e9a4f2a5..1d3c6140468e 100644 --- a/js/src/frontend/SourceNotes.h +++ b/js/src/frontend/SourceNotes.h @@ -130,11 +130,11 @@ SN_IS_TERMINATOR(jssrcnote *sn) /* * Offset fields follow certain notes and are frequency-encoded: an offset in - * [0,0x7f] consumes one byte, an offset in [0x80,0x7fffff] takes three, and + * [0,0x7f] consumes one byte, an offset in [0x80,0x7fffffff] takes four, and * the high bit of the first byte is set. */ -#define SN_3BYTE_OFFSET_FLAG 0x80 -#define SN_3BYTE_OFFSET_MASK 0x7f +#define SN_4BYTE_OFFSET_FLAG 0x80 +#define SN_4BYTE_OFFSET_MASK 0x7f /* * Negative SRC_COLSPAN offsets are rare, but can arise with for(;;) loops and @@ -143,13 +143,13 @@ SN_IS_TERMINATOR(jssrcnote *sn) * failures are bugs to fix. * * Source note offsets in general must be non-negative and less than 0x800000, - * per the above SN_3BYTE_* definitions. To encode negative colspans, we bias + * per the above SN_4BYTE_* definitions. To encode negative colspans, we bias * them by the offset domain size and restrict non-negative colspans to less * than half this domain. */ -#define SN_COLSPAN_DOMAIN ptrdiff_t(SN_3BYTE_OFFSET_FLAG << 16) +#define SN_COLSPAN_DOMAIN ptrdiff_t(1 << 23) -#define SN_MAX_OFFSET ((size_t)((ptrdiff_t)SN_3BYTE_OFFSET_FLAG << 16) - 1) +#define SN_MAX_OFFSET ((size_t)((ptrdiff_t)SN_4BYTE_OFFSET_FLAG << 24) - 1) #define SN_LENGTH(sn) ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \ : js_SrcNoteLength(sn)) diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index 109183ada3cd..ec7990c393e9 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -187,8 +187,8 @@ SET_UINT32_INDEX(jsbytecode *pc, uint32_t index) (pc)[3] = (jsbytecode)(uint32_t(i) >> 8), \ (pc)[4] = (jsbytecode)uint32_t(i)) -/* Index limit is determined by SN_3BYTE_OFFSET_FLAG, see frontend/BytecodeEmitter.h. */ -#define INDEX_LIMIT_LOG2 23 +/* Index limit is determined by SN_4BYTE_OFFSET_FLAG, see frontend/BytecodeEmitter.h. */ +#define INDEX_LIMIT_LOG2 31 #define INDEX_LIMIT (uint32_t(1) << INDEX_LIMIT_LOG2) #define ARGC_HI(argc) UINT16_HI(argc) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 75dc31b83757..7ded63e01612 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2281,16 +2281,13 @@ js::PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp) return PCToLineNumber(script->lineno(), script->notes(), script->code(), pc, columnp); } -/* The line number limit is the same as the jssrcnote offset limit. */ -#define SN_LINE_LIMIT (SN_3BYTE_OFFSET_FLAG << 16) - jsbytecode * js_LineNumberToPC(JSScript *script, unsigned target) { ptrdiff_t offset = 0; ptrdiff_t best = -1; unsigned lineno = script->lineno(); - unsigned bestdiff = SN_LINE_LIMIT; + unsigned bestdiff = SN_MAX_OFFSET; for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { /* * Exact-match only if offset is not in the prolog; otherwise use From 1ea10a6b418a4e637b5d3e569f12a0c3eae089ec Mon Sep 17 00:00:00 2001 From: Mihai Tabara Date: Fri, 17 Jan 2014 12:04:02 -0500 Subject: [PATCH 06/59] Bug 961108 - make dumpScreen always write to a file in MOZ_UPLOAD_DIR. r=ted,jmaher --- build/automation.py.in | 44 +--------------------------------- build/automationutils.py | 52 +++++++++++++--------------------------- 2 files changed, 18 insertions(+), 78 deletions(-) diff --git a/build/automation.py.in b/build/automation.py.in index 793dc52c07bb..09de4d49e4b9 100644 --- a/build/automation.py.in +++ b/build/automation.py.in @@ -634,50 +634,8 @@ class Automation(object): return self.haveDumpedScreen = True; + automationutils.dumpScreen(utilityPath) - # Need to figure out what tool and whether it write to a file or stdout - if self.UNIXISH: - utility = [os.path.join(utilityPath, "screentopng")] - imgoutput = 'stdout' - elif self.IS_MAC: - utility = ['/usr/sbin/screencapture', '-C', '-x', '-t', 'png'] - imgoutput = 'file' - elif self.IS_WIN32: - utility = [os.path.join(utilityPath, "screenshot.exe")] - imgoutput = 'file' - - # Run the capture correctly for the type of capture - try: - if imgoutput == 'file': - tmpfd, imgfilename = tempfile.mkstemp(prefix='mozilla-test-fail_') - os.close(tmpfd) - dumper = self.Process(utility + [imgfilename]) - elif imgoutput == 'stdout': - dumper = self.Process(utility, bufsize=-1, - stdout=subprocess.PIPE, close_fds=True) - except OSError, err: - self.log.info("Failed to start %s for screenshot: %s", - utility[0], err.strerror) - return - - # Check whether the capture utility ran successfully - dumper_out, dumper_err = dumper.communicate() - if dumper.returncode != 0: - self.log.info("%s exited with code %d", utility, dumper.returncode) - return - - try: - if imgoutput == 'stdout': - image = dumper_out - elif imgoutput == 'file': - with open(imgfilename, 'rb') as imgfile: - image = imgfile.read() - except IOError, err: - self.log.info("Failed to read image from %s", imgoutput) - - import base64 - encoded = base64.b64encode(image) - self.log.info("SCREENSHOT: data:image/png;base64,%s", encoded) def killAndGetStack(self, processPID, utilityPath, debuggerInfo): """Kill the process, preferrably in a way that gets us a stack trace. diff --git a/build/automationutils.py b/build/automationutils.py index 612bf237a541..092dd41838a9 100644 --- a/build/automationutils.py +++ b/build/automationutils.py @@ -484,58 +484,40 @@ def environment(xrePath, env=None, crashreporter=True, debugger=False, dmdPath=N return env - def dumpScreen(utilityPath): - """dumps the screen to the log file as a data URI""" + """dumps a screenshot of the entire screen to a directory specified by + the MOZ_UPLOAD_DIR environment variable""" + import mozfile - # Need to figure out what tool and whether it write to a file or stdout + # Need to figure out which OS-dependent tool to use if mozinfo.isUnix: utility = [os.path.join(utilityPath, "screentopng")] - imgoutput = 'stdout' elif mozinfo.isMac: utility = ['/usr/sbin/screencapture', '-C', '-x', '-t', 'png'] - imgoutput = 'file' elif mozinfo.isWin: utility = [os.path.join(utilityPath, "screenshot.exe")] - imgoutput = 'file' - else: - log.warn("Unable to dump screen on platform '%s'", sys.platform) - # Run the capture correctly for the type of capture - kwargs = {'stdout': subprocess.PIPE} - if imgoutput == 'file': - tmpfd, imgfilename = tempfile.mkstemp(prefix='mozilla-test-fail_') - os.close(tmpfd) - utility.append(imgfilename) - elif imgoutput == 'stdout': - kwargs.update(dict(bufsize=-1, close_fds=True)) + # Get dir where to write the screenshot file + parent_dir = os.environ.get('MOZ_UPLOAD_DIR', None) + if not parent_dir: + log.info('Failed to retrieve MOZ_UPLOAD_DIR env var') + return + + # Run the capture try: - dumper = subprocess.Popen(utility, **kwargs) + with mozfile.NamedTemporaryFile(suffix='.png', + prefix='mozilla-test-fail-screenshot_', + dir=parent_dir, + delete=False) as f: + returncode = subprocess.call(utility + [f.name]) except OSError, err: log.info("Failed to start %s for screenshot: %s", utility[0], err.strerror) return # Check whether the capture utility ran successfully - stdout, _ = dumper.communicate() - returncode = dumper.poll() - if returncode: + if returncode != 0: log.info("%s exited with code %d", utility, returncode) - return - - try: - if imgoutput == 'stdout': - image = stdout - elif imgoutput == 'file': - with open(imgfilename, 'rb') as imgfile: - image = imgfile.read() - except IOError, err: - log.info("Failed to read image from %s", imgoutput) - - encoded = base64.b64encode(image) - uri = "data:image/png;base64,%s" % encoded - log.info("SCREENSHOT: %s", uri) - return uri class ShutdownLeaks(object): """ From 3bf6ebd317b74ecc780c5d16affb4bb8604caf81 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Thu, 17 Oct 2013 15:07:55 -0400 Subject: [PATCH 07/59] Bug 927355 - Print fractional milliseconds in event tracer samples. r=bsmedberg --- toolkit/xre/EventTracer.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/toolkit/xre/EventTracer.cpp b/toolkit/xre/EventTracer.cpp index a6dd0e29652e..0efd2031f1e8 100644 --- a/toolkit/xre/EventTracer.cpp +++ b/toolkit/xre/EventTracer.cpp @@ -45,7 +45,8 @@ * When an event servicing time exceeds the threshold, a line of the form: * MOZ_EVENT_TRACE sample * will be output, where is the number of milliseconds that - * it took for the event to be serviced. + * it took for the event to be serviced. Duration may contain a fractional + * component. */ #include "GeckoProfiler.h" @@ -125,7 +126,8 @@ void TracerThread(void *arg) } if (threadArgs->mLogTracing) { - fprintf(log, "MOZ_EVENT_TRACE start %llu\n", PR_Now() / PR_USEC_PER_MSEC); + long long now = PR_Now() / PR_USEC_PER_MSEC; + fprintf(log, "MOZ_EVENT_TRACE start %llu\n", now); } while (!sExit) { @@ -139,10 +141,11 @@ void TracerThread(void *arg) if (FireAndWaitForTracerEvent()) { TimeDuration duration = TimeStamp::Now() - start; // Only report samples that exceed our measurement threshold. + long long now = PR_Now() / PR_USEC_PER_MSEC; if (threadArgs->mLogTracing && duration.ToMilliseconds() > threshold) { - fprintf(log, "MOZ_EVENT_TRACE sample %llu %d\n", - PR_Now() / PR_USEC_PER_MSEC, - int(duration.ToSecondsSigDigits() * 1000)); + fprintf(log, "MOZ_EVENT_TRACE sample %llu %lf\n", + now, + duration.ToMilliseconds()); } if (next_sleep > duration.ToMilliseconds()) { @@ -161,7 +164,8 @@ void TracerThread(void *arg) } if (threadArgs->mLogTracing) { - fprintf(log, "MOZ_EVENT_TRACE stop %llu\n", PR_Now() / PR_USEC_PER_MSEC); + long long now = PR_Now() / PR_USEC_PER_MSEC; + fprintf(log, "MOZ_EVENT_TRACE stop %llu\n", now); } if (log != stdout) From ff6f1fd401b1cb71874f3f5dbf1890bfa2457081 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 12 Dec 2013 16:17:35 -0500 Subject: [PATCH 08/59] Bug 942164 - Store weak references to imgRequest consumers. r=seth --- image/src/imgRequest.cpp | 2 +- image/src/imgRequestProxy.h | 4 +- image/src/imgStatusTracker.cpp | 93 ++++++++++++++++++++++++---------- image/src/imgStatusTracker.h | 12 ++--- 4 files changed, 75 insertions(+), 36 deletions(-) diff --git a/image/src/imgRequest.cpp b/image/src/imgRequest.cpp index 67529d330fd1..b570496f0197 100644 --- a/image/src/imgRequest.cpp +++ b/image/src/imgRequest.cpp @@ -637,7 +637,7 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt PR_LOG(GetImgLog(), PR_LOG_WARNING, ("[this=%p] imgRequest::OnStartRequest -- " "RetargetDeliveryTo rv %d=%s\n", - this, NS_SUCCEEDED(rv) ? "succeeded" : "failed", rv)); + this, rv, NS_SUCCEEDED(rv) ? "succeeded" : "failed")); } return NS_OK; diff --git a/image/src/imgRequestProxy.h b/image/src/imgRequestProxy.h index 1fc41f0606e1..95f1ba94b84f 100644 --- a/image/src/imgRequestProxy.h +++ b/image/src/imgRequestProxy.h @@ -7,6 +7,7 @@ #ifndef imgRequestProxy_h__ #define imgRequestProxy_h__ +#include "mozilla/WeakPtr.h" #include "imgIRequest.h" #include "nsISecurityInfoProvider.h" @@ -43,7 +44,8 @@ class ImageURL; class imgRequestProxy : public imgIRequest, public nsISupportsPriority, public nsISecurityInfoProvider, - public nsITimedChannel + public nsITimedChannel, + public mozilla::SupportsWeakPtr { public: typedef mozilla::image::ImageURL ImageURL; diff --git a/image/src/imgStatusTracker.cpp b/image/src/imgStatusTracker.cpp index b4fd8147d976..bfcc2fbcfe03 100644 --- a/image/src/imgStatusTracker.cpp +++ b/image/src/imgStatusTracker.cpp @@ -18,6 +18,7 @@ #include "mozilla/Services.h" using namespace mozilla::image; +using mozilla::WeakPtr; class imgStatusTrackerObserver : public imgDecoderObserver { @@ -143,7 +144,7 @@ public: } private: - mozilla::WeakPtr mTracker; + WeakPtr mTracker; }; // imgStatusTracker methods @@ -357,17 +358,17 @@ imgStatusTracker::NotifyCurrentState(imgRequestProxy* proxy) #define NOTIFY_IMAGE_OBSERVERS(func) \ do { \ - nsTObserverArray::ForwardIterator iter(proxies); \ + ProxyArray::ForwardIterator iter(proxies); \ while (iter.HasMore()) { \ - nsRefPtr proxy = iter.GetNext(); \ - if (!proxy->NotificationsDeferred()) { \ + nsRefPtr proxy = iter.GetNext().get(); \ + if (proxy && !proxy->NotificationsDeferred()) { \ proxy->func; \ } \ } \ } while (false); /* static */ void -imgStatusTracker::SyncNotifyState(nsTObserverArray& proxies, +imgStatusTracker::SyncNotifyState(ProxyArray& proxies, bool hasImage, uint32_t state, nsIntRect& dirtyRect, bool hadLastPart) { @@ -505,13 +506,13 @@ imgStatusTracker::SyncNotifyDifference(const ImageStatusDiff& diff) mInvalidRect.SetEmpty(); if (diff.unblockedOnload) { - nsTObserverArray::ForwardIterator iter(mConsumers); + ProxyArray::ForwardIterator iter(mConsumers); while (iter.HasMore()) { // Hold on to a reference to this proxy, since notifying the state can // cause it to disappear. - nsRefPtr proxy = iter.GetNext(); + nsRefPtr proxy = iter.GetNext().get(); - if (!proxy->NotificationsDeferred()) { + if (proxy && !proxy->NotificationsDeferred()) { SendUnblockOnload(proxy); } } @@ -550,8 +551,8 @@ imgStatusTracker::SyncNotify(imgRequestProxy* proxy) r = mImage->FrameRect(imgIContainer::FRAME_CURRENT); } - nsTObserverArray array; - array.AppendElement(proxy); + ProxyArray array; + array.AppendElement(proxy->asWeakPtr()); SyncNotifyState(array, !!mImage, mState, r, mHadLastPart); } @@ -582,7 +583,7 @@ void imgStatusTracker::AddConsumer(imgRequestProxy* aConsumer) { MOZ_ASSERT(NS_IsMainThread()); - mConsumers.AppendElementUnlessExists(aConsumer); + mConsumers.AppendElementUnlessExists(aConsumer->asWeakPtr()); } // XXX - The last argument should go away. @@ -610,6 +611,20 @@ imgStatusTracker::RemoveConsumer(imgRequestProxy* aConsumer, nsresult aStatus) return removed; } +bool +imgStatusTracker::FirstConsumerIs(imgRequestProxy* aConsumer) +{ + MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only"); + ProxyArray::ForwardIterator iter(mConsumers); + while (iter.HasMore()) { + nsRefPtr proxy = iter.GetNext().get(); + if (proxy) { + return proxy.get() == aConsumer; + } + } + return false; +} + void imgStatusTracker::RecordCancel() { @@ -781,9 +796,12 @@ imgStatusTracker::OnUnlockedDraw() { MOZ_ASSERT(NS_IsMainThread()); RecordUnlockedDraw(); - nsTObserverArray::ForwardIterator iter(mConsumers); + ProxyArray::ForwardIterator iter(mConsumers); while (iter.HasMore()) { - SendUnlockedDraw(iter.GetNext()); + nsRefPtr proxy = iter.GetNext().get(); + if (proxy) { + SendUnlockedDraw(proxy); + } } } @@ -838,9 +856,12 @@ imgStatusTracker::OnStartRequest() { MOZ_ASSERT(NS_IsMainThread()); RecordStartRequest(); - nsTObserverArray::ForwardIterator iter(mConsumers); + ProxyArray::ForwardIterator iter(mConsumers); while (iter.HasMore()) { - SendStartRequest(iter.GetNext()); + nsRefPtr proxy = iter.GetNext().get(); + if (proxy) { + SendStartRequest(proxy); + } } } @@ -909,9 +930,12 @@ imgStatusTracker::OnStopRequest(bool aLastPart, RecordStopRequest(aLastPart, aStatus); /* notify the kids */ - nsTObserverArray::ForwardIterator srIter(mConsumers); + ProxyArray::ForwardIterator srIter(mConsumers); while (srIter.HasMore()) { - SendStopRequest(srIter.GetNext(), aLastPart, aStatus); + nsRefPtr proxy = srIter.GetNext().get(); + if (proxy) { + SendStopRequest(proxy, aLastPart, aStatus); + } } if (NS_FAILED(aStatus) && !preexistingError) { @@ -926,9 +950,12 @@ imgStatusTracker::OnDiscard() RecordDiscard(); /* notify the kids */ - nsTObserverArray::ForwardIterator iter(mConsumers); + ProxyArray::ForwardIterator iter(mConsumers); while (iter.HasMore()) { - SendDiscard(iter.GetNext()); + nsRefPtr proxy = iter.GetNext().get(); + if (proxy) { + SendDiscard(proxy); + } } } @@ -939,9 +966,12 @@ imgStatusTracker::FrameChanged(const nsIntRect* aDirtyRect) RecordFrameChanged(aDirtyRect); /* notify the kids */ - nsTObserverArray::ForwardIterator iter(mConsumers); + ProxyArray::ForwardIterator iter(mConsumers); while (iter.HasMore()) { - SendFrameChanged(iter.GetNext(), aDirtyRect); + nsRefPtr proxy = iter.GetNext().get(); + if (proxy) { + SendFrameChanged(proxy, aDirtyRect); + } } } @@ -952,9 +982,12 @@ imgStatusTracker::OnStopFrame() RecordStopFrame(); /* notify the kids */ - nsTObserverArray::ForwardIterator iter(mConsumers); + ProxyArray::ForwardIterator iter(mConsumers); while (iter.HasMore()) { - SendStopFrame(iter.GetNext()); + nsRefPtr proxy = iter.GetNext().get(); + if (proxy) { + SendStopFrame(proxy); + } } } @@ -970,9 +1003,12 @@ imgStatusTracker::OnDataAvailable() return; } // Notify any imgRequestProxys that are observing us that we have an Image. - nsTObserverArray::ForwardIterator iter(mConsumers); + ProxyArray::ForwardIterator iter(mConsumers); while (iter.HasMore()) { - iter.GetNext()->SetHasImage(); + nsRefPtr proxy = iter.GetNext().get(); + if (proxy) { + proxy->SetHasImage(); + } } } @@ -1021,9 +1057,12 @@ imgStatusTracker::MaybeUnblockOnload() RecordUnblockOnload(); - nsTObserverArray::ForwardIterator iter(mConsumers); + ProxyArray::ForwardIterator iter(mConsumers); while (iter.HasMore()) { - SendUnblockOnload(iter.GetNext()); + nsRefPtr proxy = iter.GetNext().get(); + if (proxy) { + SendUnblockOnload(proxy); + } } } diff --git a/image/src/imgStatusTracker.h b/image/src/imgStatusTracker.h index d70fdbef97d8..c9199f736d6f 100644 --- a/image/src/imgStatusTracker.h +++ b/image/src/imgStatusTracker.h @@ -9,7 +9,6 @@ class imgDecoderObserver; class imgIContainer; -class imgRequestProxy; class imgStatusNotifyRunnable; class imgRequestNotifyRunnable; class imgStatusTrackerObserver; @@ -21,6 +20,7 @@ class nsIRunnable; #include "nsTObserverArray.h" #include "nsThreadUtils.h" #include "nsRect.h" +#include "imgRequestProxy.h" namespace mozilla { namespace image { @@ -173,10 +173,7 @@ public: // This is intentionally non-general because its sole purpose is to support an // some obscure network priority logic in imgRequest. That stuff could probably // be improved, but it's too scary to mess with at the moment. - bool FirstConsumerIs(imgRequestProxy* aConsumer) { - MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only"); - return mConsumers.SafeElementAt(0, nullptr) == aConsumer; - } + bool FirstConsumerIs(imgRequestProxy* aConsumer); void AdoptConsumers(imgStatusTracker* aTracker) { MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only"); @@ -295,6 +292,7 @@ public: nsIntRect GetInvalidRect() const { return mInvalidRect; } private: + typedef nsTObserverArray> ProxyArray; friend class imgStatusNotifyRunnable; friend class imgRequestNotifyRunnable; friend class imgStatusTrackerObserver; @@ -306,7 +304,7 @@ private: // Main thread only, since imgRequestProxy calls are expected on the main // thread, and mConsumers is not threadsafe. - static void SyncNotifyState(nsTObserverArray& proxies, + static void SyncNotifyState(ProxyArray& proxies, bool hasImage, uint32_t state, nsIntRect& dirtyRect, bool hadLastPart); @@ -322,7 +320,7 @@ private: // List of proxies attached to the image. Each proxy represents a consumer // using the image. Array and/or individual elements should only be accessed // on the main thread. - nsTObserverArray mConsumers; + ProxyArray mConsumers; mozilla::RefPtr mTrackerObserver; From 394d08efea1f42d2c8bce71b78e34a1b999ab5b1 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Tue, 21 Jan 2014 16:24:18 -0500 Subject: [PATCH 09/59] Bug 947337 - Small refactoring to reduce an unnecessary codepath. r=botond --- gfx/layers/ipc/AsyncPanZoomController.cpp | 32 ++++++++++------------- gfx/layers/ipc/AsyncPanZoomController.h | 2 +- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index 4b57e6c8520f..965e0403f472 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -1338,8 +1338,12 @@ void AsyncPanZoomController::ScheduleComposite() { } void AsyncPanZoomController::RequestContentRepaint() { - mFrameMetrics.mDisplayPort = - CalculatePendingDisplayPort(mFrameMetrics, + RequestContentRepaint(mFrameMetrics); +} + +void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics) { + aFrameMetrics.mDisplayPort = + CalculatePendingDisplayPort(aFrameMetrics, GetVelocityVector(), GetAccelerationVector(), mPaintThrottler.AverageDuration().ToSeconds()); @@ -1348,32 +1352,24 @@ void AsyncPanZoomController::RequestContentRepaint() { // request since it's a pointless paint. CSSRect oldDisplayPort = mLastPaintRequestMetrics.mDisplayPort + mLastPaintRequestMetrics.mScrollOffset; - CSSRect newDisplayPort = mFrameMetrics.mDisplayPort - + mFrameMetrics.mScrollOffset; + CSSRect newDisplayPort = aFrameMetrics.mDisplayPort + + aFrameMetrics.mScrollOffset; if (fabsf(oldDisplayPort.x - newDisplayPort.x) < EPSILON && fabsf(oldDisplayPort.y - newDisplayPort.y) < EPSILON && fabsf(oldDisplayPort.width - newDisplayPort.width) < EPSILON && fabsf(oldDisplayPort.height - newDisplayPort.height) < EPSILON && fabsf(mLastPaintRequestMetrics.mScrollOffset.x - - mFrameMetrics.mScrollOffset.x) < EPSILON && + aFrameMetrics.mScrollOffset.x) < EPSILON && fabsf(mLastPaintRequestMetrics.mScrollOffset.y - - mFrameMetrics.mScrollOffset.y) < EPSILON && - mFrameMetrics.mZoom == mLastPaintRequestMetrics.mZoom && - fabsf(mFrameMetrics.mViewport.width - mLastPaintRequestMetrics.mViewport.width) < EPSILON && - fabsf(mFrameMetrics.mViewport.height - mLastPaintRequestMetrics.mViewport.height) < EPSILON) { + aFrameMetrics.mScrollOffset.y) < EPSILON && + aFrameMetrics.mZoom == mLastPaintRequestMetrics.mZoom && + fabsf(aFrameMetrics.mViewport.width - mLastPaintRequestMetrics.mViewport.width) < EPSILON && + fabsf(aFrameMetrics.mViewport.height - mLastPaintRequestMetrics.mViewport.height) < EPSILON) { return; } SendAsyncScrollEvent(); - ScheduleContentRepaint(mFrameMetrics); -} - -void -AsyncPanZoomController::ScheduleContentRepaint(FrameMetrics &aFrameMetrics) { - // This message is compressed, so fire whether or not we already have a paint - // queued up. We need to know whether or not a paint was requested anyways, - // for the purposes of content calling window.scrollTo(). nsRefPtr controller = GetGeckoContentController(); if (controller) { APZC_LOG_FM(aFrameMetrics, "%p requesting content repaint", this); @@ -1697,7 +1693,7 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect) { // Schedule a repaint now, so the new displayport will be painted before the // animation finishes. - ScheduleContentRepaint(endZoomToMetrics); + RequestContentRepaint(endZoomToMetrics); } } diff --git a/gfx/layers/ipc/AsyncPanZoomController.h b/gfx/layers/ipc/AsyncPanZoomController.h index 1612c435e812..7f6c9ddc1055 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.h +++ b/gfx/layers/ipc/AsyncPanZoomController.h @@ -482,7 +482,7 @@ protected: * Tell the paint throttler to request a content repaint with the given * metrics. (Helper function used by RequestContentRepaint.) */ - void ScheduleContentRepaint(FrameMetrics &aFrameMetrics); + void RequestContentRepaint(FrameMetrics& aFrameMetrics); /** * Advances a fling by an interpolated amount based on the passed in |aDelta|. From f9b3dd70c247e213d8c84b7b90258f17ba6f85cf Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Tue, 21 Jan 2014 16:26:57 -0500 Subject: [PATCH 10/59] Bug 947337 - Track the last metrics actually sent to Gecko after coming out of the throttler. r=botond --- gfx/layers/ipc/AsyncPanZoomController.cpp | 28 +++++++++++++++-------- gfx/layers/ipc/AsyncPanZoomController.h | 10 ++++++++ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index 965e0403f472..793642f45a8d 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -1370,6 +1370,19 @@ void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics) } SendAsyncScrollEvent(); + mPaintThrottler.PostTask( + FROM_HERE, + NewRunnableMethod(this, + &AsyncPanZoomController::DispatchRepaintRequest, + aFrameMetrics), + GetFrameTime()); + + aFrameMetrics.mPresShellId = mLastContentPaintMetrics.mPresShellId; + mLastPaintRequestMetrics = aFrameMetrics; +} + +void +AsyncPanZoomController::DispatchRepaintRequest(const FrameMetrics& aFrameMetrics) { nsRefPtr controller = GetGeckoContentController(); if (controller) { APZC_LOG_FM(aFrameMetrics, "%p requesting content repaint", this); @@ -1377,15 +1390,9 @@ void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics) LogRendertraceRect(GetGuid(), "requested displayport", "yellow", aFrameMetrics.mDisplayPort + aFrameMetrics.mScrollOffset); - mPaintThrottler.PostTask( - FROM_HERE, - NewRunnableMethod(controller.get(), - &GeckoContentController::RequestContentRepaint, - aFrameMetrics), - GetFrameTime()); + controller->RequestContentRepaint(aFrameMetrics); + mLastDispatchedPaintMetrics = aFrameMetrics; } - aFrameMetrics.mPresShellId = mLastContentPaintMetrics.mPresShellId; - mLastPaintRequestMetrics = aFrameMetrics; } void @@ -1553,15 +1560,18 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri } if (aIsFirstPaint || isDefault) { + // Initialize our internal state to something sane when the content + // that was just painted is something we knew nothing about previously mPaintThrottler.ClearHistory(); mPaintThrottler.SetMaxDurations(gNumPaintDurationSamples); mX.CancelTouch(); mY.CancelTouch(); + SetState(NOTHING); mFrameMetrics = aLayerMetrics; + mLastDispatchedPaintMetrics = aLayerMetrics; ShareCompositorFrameMetrics(); - SetState(NOTHING); } else { // If we're not taking the aLayerMetrics wholesale we still need to pull // in some things into our local mFrameMetrics because these things are diff --git a/gfx/layers/ipc/AsyncPanZoomController.h b/gfx/layers/ipc/AsyncPanZoomController.h index 7f6c9ddc1055..292cd07aa103 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.h +++ b/gfx/layers/ipc/AsyncPanZoomController.h @@ -484,6 +484,11 @@ protected: */ void RequestContentRepaint(FrameMetrics& aFrameMetrics); + /** + * Actually send the next pending paint request to gecko. + */ + void DispatchRepaintRequest(const FrameMetrics& aFrameMetrics); + /** * Advances a fling by an interpolated amount based on the passed in |aDelta|. * This should be called whenever sampling the content transform for this @@ -635,6 +640,11 @@ private: // that we're not requesting a paint of the same thing that's already drawn. // If we don't do this check, we don't get a ShadowLayersUpdated back. FrameMetrics mLastPaintRequestMetrics; + // The last metrics that we actually sent to Gecko. This allows us to transform + // inputs into a coordinate space that Gecko knows about. This assumes the pipe + // through which input events and repaint requests are sent to Gecko operates + // in a FIFO manner. + FrameMetrics mLastDispatchedPaintMetrics; nsTArray mTouchQueue; From e96508ffe788bcd8547f0a48d077718b689221cd Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Tue, 21 Jan 2014 16:27:20 -0500 Subject: [PATCH 11/59] Bug 947337 - Ensure the transform of input to Gecko space accounts for inflight paint requests. r=botond --- gfx/layers/composite/APZCTreeManager.cpp | 39 ++++++++++++++++------- gfx/layers/ipc/AsyncPanZoomController.cpp | 8 +++++ gfx/layers/ipc/AsyncPanZoomController.h | 9 ++++++ 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/gfx/layers/composite/APZCTreeManager.cpp b/gfx/layers/composite/APZCTreeManager.cpp index 6292f65f0de2..54041f145b0a 100644 --- a/gfx/layers/composite/APZCTreeManager.cpp +++ b/gfx/layers/composite/APZCTreeManager.cpp @@ -880,7 +880,7 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& a /* This function sets the aTransformToApzcOut and aTransformToGeckoOut out-parameters to some useful transformations that input events may need applied. This is best illustrated with an example. Consider a chain of layers, L, M, N, O, P, Q, R. Layer L - is the layer that corresponds to the returned APZC instance, and layer R is the root + is the layer that corresponds to the argument |aApzc|, and layer R is the root of the layer tree. Layer M is the parent of L, N is the parent of M, and so on. When layer L is displayed to the screen by the compositor, the set of transforms that are applied to L are (in order from top to bottom): @@ -918,8 +918,15 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& a Next, if we want user inputs sent to gecko for event-dispatching, we will need to strip out all of the async transforms that are involved in this chain. This is because async transforms are stored only in the compositor and gecko does not account for them when - doing display-list-based hit-testing for event dispatching. Therefore, given a user input - in screen space, the following transforms need to be applied (in order from top to bottom): + doing display-list-based hit-testing for event dispatching. + Furthermore, because these input events are processed by Gecko in a FIFO queue that + includes other things (specifically paint requests), it is possible that by time the + input event reaches gecko, it will have painted something else. Therefore, we need to + apply another transform to the input events to account for the possible disparity between + what we know gecko last painted and the last paint request we sent to gecko. Let this + transform be represented by LD, MD, ... RD. + Therefore, given a user input in screen space, the following transforms need to be applied + (in order from top to bottom): RC.Inverse() RN.Inverse() RT.Inverse() @@ -930,28 +937,36 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& a LC.Inverse() LN.Inverse() LT.Inverse() + LD LC + MD MC ... + RD RC This sequence can be simplified and refactored to the following: aTransformToApzcOut LT.Inverse() + LD LC + MD MC ... + RD RC Since aTransformToApzcOut is already one of the out-parameters, we set aTransformToGeckoOut - to the remaining transforms (LT.Inverse() * LC * ... * RC), so that the caller code can + to the remaining transforms (LT.Inverse() * LD * ... * RC), so that the caller code can combine it with aTransformToApzcOut to get the final transform required in this case. Note that for many of these layers, there will be no AsyncPanZoomController attached, and so the async transform will be the identity transform. So, in the example above, if layers - L and P have APZC instances attached, MT, MN, NT, NN, OT, ON, QT, QN, RT and RN will be - identity transforms. + L and P have APZC instances attached, MT, MN, MD, NT, NN, ND, OT, ON, OD, QT, QN, QD, RT, + RN and RD will be identity transforms. Additionally, for space-saving purposes, each APZC instance stores its layer's individual CSS transform and the accumulation of CSS transforms to its parent APZC. So the APZC for layer L would store LC and (MC * NC * OC), and the layer P would store PC and (QC * RC). + The APZC instances track the last dispatched paint request and so are able to calculate LD and + PD using those internally stored values. The APZCs also obviously have LT, LN, PT, and PN, so all of the above transformation combinations required can be generated. */ @@ -978,8 +993,8 @@ APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& // aTransformToApzcOut is initialized to OC.Inverse() * NC.Inverse() * MC.Inverse() * LC.Inverse() * LN.Inverse() aTransformToApzcOut = ancestorUntransform * aApzc->GetCSSTransform().Inverse() * nontransientAsyncTransform.Inverse(); - // aTransformToGeckoOut is initialized to LT.Inverse() * LC * MC * NC * OC - aTransformToGeckoOut = transientAsyncUntransform * aApzc->GetCSSTransform() * aApzc->GetAncestorTransform(); + // aTransformToGeckoOut is initialized to LT.Inverse() * LD * LC * MC * NC * OC + aTransformToGeckoOut = transientAsyncUntransform * aApzc->GetTransformToLastDispatchedPaint() * aApzc->GetCSSTransform() * aApzc->GetAncestorTransform(); for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) { // ancestorUntransform is updated to RC.Inverse() * QC.Inverse() when parent == P @@ -991,12 +1006,12 @@ APZCTreeManager::GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& // aTransformToApzcOut is RC.Inverse() * QC.Inverse() * PC.Inverse() * PA.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse() * LC.Inverse() * LN.Inverse() aTransformToApzcOut = untransformSinceLastApzc * aTransformToApzcOut; - // aTransformToGeckoOut is LT.Inverse() * LC * MC * NC * OC * PC * QC * RC - aTransformToGeckoOut = aTransformToGeckoOut * parent->GetCSSTransform() * parent->GetAncestorTransform(); + // aTransformToGeckoOut is LT.Inverse() * LD * LC * MC * NC * OC * PD * PC * QC * RC + aTransformToGeckoOut = aTransformToGeckoOut * parent->GetTransformToLastDispatchedPaint() * parent->GetCSSTransform() * parent->GetAncestorTransform(); // The above values for aTransformToApzcOut and aTransformToGeckoOut when parent == P match - // the required output as explained in the comment above GetTargetAPZC. Note that any missing terms - // are async transforms that are guaranteed to be identity transforms. + // the required output as explained in the comment above this method. Note that any missing + // terms are guaranteed to be identity transforms. } } diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index 793642f45a8d..e530ba67353d 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -1533,6 +1533,14 @@ gfx3DMatrix AsyncPanZoomController::GetNontransientAsyncTransform() { 1.0f); } +gfx3DMatrix AsyncPanZoomController::GetTransformToLastDispatchedPaint() { + ReentrantMonitorAutoEnter lock(mMonitor); + CSSPoint scrollChange = mLastContentPaintMetrics.mScrollOffset - mLastDispatchedPaintMetrics.mScrollOffset; + float zoomChange = mLastContentPaintMetrics.mZoom.scale / mLastDispatchedPaintMetrics.mZoom.scale; + return gfx3DMatrix::Translation(scrollChange.x, scrollChange.y, 0) * + gfx3DMatrix::ScalingMatrix(zoomChange, zoomChange, 1); +} + void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) { ReentrantMonitorAutoEnter lock(mMonitor); diff --git a/gfx/layers/ipc/AsyncPanZoomController.h b/gfx/layers/ipc/AsyncPanZoomController.h index 292cd07aa103..cb57e650cb9e 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.h +++ b/gfx/layers/ipc/AsyncPanZoomController.h @@ -222,6 +222,15 @@ public: */ gfx3DMatrix GetNontransientAsyncTransform(); + /** + * Returns the transform to take something from the coordinate space of the + * last thing we know gecko painted, to the coordinate space of the last thing + * we asked gecko to paint. In cases where that last request has not yet been + * processed, this is needed to transform input events properly into a space + * gecko will understand. + */ + gfx3DMatrix GetTransformToLastDispatchedPaint(); + /** * Recalculates the displayport. Ideally, this should paint an area bigger * than the composite-to dimensions so that when you scroll down, you don't From 8681b20afc7e3871b5b217ad0b4a717d7a954b6f Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Wed, 22 Jan 2014 13:37:30 -0500 Subject: [PATCH 12/59] Bug 947337 - Update APZC tests to exercise the newly introduced transform. r=botond --- .../gtest/TestAsyncPanZoomController.cpp | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index 858e41db40f2..c9f12e695079 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -221,6 +221,8 @@ void DoPanTest(bool aShouldTriggerScroll, bool aShouldUseTouchAction, uint32_t a EXPECT_EQ(pointOut, ScreenPoint()); EXPECT_EQ(viewTransformOut, ViewTransform()); + + apzc->Destroy(); } static void @@ -315,6 +317,8 @@ TEST(AsyncPanZoomController, Pinch) { EXPECT_EQ(fm.mZoom.scale, 1.0f); EXPECT_EQ(fm.mScrollOffset.x, 880); EXPECT_EQ(fm.mScrollOffset.y, 0); + + apzc->Destroy(); } TEST(AsyncPanZoomController, PinchWithTouchActionNone) { @@ -878,9 +882,13 @@ TEST(APZCTreeManager, HitTesting2) { // of -50 to be set on the root layer. int time = 0; // Silence GMock warnings about "uninteresting mock function calls". - EXPECT_CALL(*mcc, PostDelayedTask(_,_)).Times(1); + EXPECT_CALL(*mcc, PostDelayedTask(_,_)).Times(AtLeast(1)); EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1)); EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1); + + // This first pan will move the APZC by 50 pixels, and dispatch a paint request. + // Since this paint request is in the queue to Gecko, transformToGecko will + // take it into account. ApzcPan(apzcroot, manager, time, 100, 50); // Hit where layers[3] used to be. It should now hit the root. @@ -888,18 +896,44 @@ TEST(APZCTreeManager, HitTesting2) { EXPECT_EQ(apzcroot, hit.get()); // transformToApzc doesn't unapply the root's own async transform EXPECT_EQ(gfxPoint(75, 75), transformToApzc.Transform(gfxPoint(75, 75))); - // but transformToGecko does - EXPECT_EQ(gfxPoint(75, 125), transformToGecko.Transform(gfxPoint(75, 75))); + // and transformToGecko unapplies it and then reapplies it, because by the + // time the event being transformed reaches Gecko the new paint request will + // have been handled. + EXPECT_EQ(gfxPoint(75, 75), transformToGecko.Transform(gfxPoint(75, 75))); // Hit where layers[1] used to be and where layers[3] should now be. hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko); EXPECT_EQ(apzc3, hit.get()); // transformToApzc unapplies both layers[2]'s css transform and the root's - // async trasnform + // async transform EXPECT_EQ(gfxPoint(12.5, 75), transformToApzc.Transform(gfxPoint(25, 25))); - // transformToGecko reapplies the css transform only (since Gecko doesn't - // know about async transforms) - EXPECT_EQ(gfxPoint(25, 75), transformToGecko.Transform(gfxPoint(12.5, 75))); + // transformToGecko reapplies both the css transform and the async transform + // because we have already issued a paint request with it. + EXPECT_EQ(gfxPoint(25, 25), transformToGecko.Transform(gfxPoint(12.5, 75))); + + // This second pan will move the APZC by another 50 pixels but since the paint + // request dispatched above has not "completed", we will not dispatch another + // one yet. Now we have an async transform on top of the pending paint request + // transform. + ApzcPan(apzcroot, manager, time, 100, 50); + + // Hit where layers[3] used to be. It should now hit the root. + hit = GetTargetAPZC(manager, ScreenPoint(75, 75), transformToApzc, transformToGecko); + EXPECT_EQ(apzcroot, hit.get()); + // transformToApzc doesn't unapply the root's own async transform + EXPECT_EQ(gfxPoint(75, 75), transformToApzc.Transform(gfxPoint(75, 75))); + // transformToGecko unapplies the full async transform of -100 pixels, and then + // reapplies the "D" transform of -50 leading to an overall adjustment of +50 + EXPECT_EQ(gfxPoint(75, 125), transformToGecko.Transform(gfxPoint(75, 75))); + + // Hit where layers[1] used to be. It should now hit the root. + hit = GetTargetAPZC(manager, ScreenPoint(25, 25), transformToApzc, transformToGecko); + EXPECT_EQ(apzcroot, hit.get()); + // transformToApzc doesn't unapply the root's own async transform + EXPECT_EQ(gfxPoint(25, 25), transformToApzc.Transform(gfxPoint(25, 25))); + // transformToGecko unapplies the full async transform of -100 pixels, and then + // reapplies the "D" transform of -50 leading to an overall adjustment of +50 + EXPECT_EQ(gfxPoint(25, 75), transformToGecko.Transform(gfxPoint(25, 25))); manager->ClearTree(); } From 94c8fcfd47515bd5c508070b4b381a4f12ddeda1 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 21 Jan 2014 09:36:03 -0500 Subject: [PATCH 13/59] Bug 962080 - fix maybe-uninitialized variable warning in IonBuilder.cpp; r=jandem --- js/src/jit/IonBuilder.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index b719508668d1..88f3a9b1b12e 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -4100,6 +4100,8 @@ IonBuilder::selectInliningTargets(ObjectVector &targets, CallInfo &callInfo, Boo case InliningDecision_Inline: inlineable = true; break; + default: + MOZ_ASSUME_UNREACHABLE("Unhandled InliningDecision value!"); } // Enforce a maximum inlined bytecode limit at the callsite. From 32330dffbc171e101eca97927409df4e7a2bf02a Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Wed, 22 Jan 2014 10:54:28 -0800 Subject: [PATCH 14/59] Bug 962441: Add regression test for Debugger.prototype.findScripts finding incompletely initialized JSScripts. r=shu --- js/src/jit-test/tests/debug/Debugger-findScripts-19.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 js/src/jit-test/tests/debug/Debugger-findScripts-19.js diff --git a/js/src/jit-test/tests/debug/Debugger-findScripts-19.js b/js/src/jit-test/tests/debug/Debugger-findScripts-19.js new file mode 100644 index 000000000000..0983c0ecac73 --- /dev/null +++ b/js/src/jit-test/tests/debug/Debugger-findScripts-19.js @@ -0,0 +1,5 @@ +var g = newGlobal(); +var dbg = new Debugger(g); +try { g.eval('function drag(ev) {'); } catch (ex) { } +for (s of dbg.findScripts()) + s.lineCount; From bce6fbe34703dfd9b45aab964938b40e9146c1e8 Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Tue, 21 Jan 2014 13:31:31 -0500 Subject: [PATCH 15/59] Bug 941136 - getUrl not matching webdriver command getCurrentUrl. r=dburns --- .../marionette/client/marionette/marionette.py | 18 ++++++++++++++---- testing/marionette/marionette-listener.js | 8 ++++---- testing/marionette/marionette-server.js | 16 ++++++++++++---- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index 47f8cc115e3b..863826766103 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -870,10 +870,20 @@ class Marionette(object): return response def get_url(self): - ''' - Returns the url of the active page in the browser. - ''' - response = self._send_message('getUrl', 'value') + """Get a string representing the current URL. + + On Desktop this returns a string representation of the URL of + the current top level browsing context. This is equivalent to + document.location.href. + + When in the context of the chrome, this returns the canonical + URL of the current resource. + + :returns: string representation of URL + + """ + + response = self._send_message("getCurrentUrl", "value") return response def get_window_type(self): diff --git a/testing/marionette/marionette-listener.js b/testing/marionette/marionette-listener.js index 0b939f0b6dd0..3f8a0c475c13 100644 --- a/testing/marionette/marionette-listener.js +++ b/testing/marionette/marionette-listener.js @@ -131,7 +131,7 @@ function startListeners() { addMessageListenerId("Marionette:actionChain", actionChain); addMessageListenerId("Marionette:multiAction", multiAction); addMessageListenerId("Marionette:goUrl", goUrl); - addMessageListenerId("Marionette:getUrl", getUrl); + addMessageListenerId("Marionette:getCurrentUrl", getCurrentUrl); addMessageListenerId("Marionette:getTitle", getTitle); addMessageListenerId("Marionette:getPageSource", getPageSource); addMessageListenerId("Marionette:goBack", goBack); @@ -234,7 +234,7 @@ function deleteSession(msg) { removeMessageListenerId("Marionette:goUrl", goUrl); removeMessageListenerId("Marionette:getTitle", getTitle); removeMessageListenerId("Marionette:getPageSource", getPageSource); - removeMessageListenerId("Marionette:getUrl", getUrl); + removeMessageListenerId("Marionette:getCurrentUrl", getCurrentUrl); removeMessageListenerId("Marionette:goBack", goBack); removeMessageListenerId("Marionette:goForward", goForward); removeMessageListenerId("Marionette:refresh", refresh); @@ -1237,9 +1237,9 @@ function goUrl(msg) { } /** - * Get the current URI + * Get URL of the top level browsing context. */ -function getUrl(msg) { +function getCurrentUrl(msg) { sendResponse({value: curFrame.location.href}, msg.json.command_id); } diff --git a/testing/marionette/marionette-server.js b/testing/marionette/marionette-server.js index b040b13f9ebe..dbad77bfff86 100644 --- a/testing/marionette/marionette-server.js +++ b/testing/marionette/marionette-server.js @@ -1079,15 +1079,22 @@ MarionetteServerConnection.prototype = { }, /** - * Gets current url + * Get a string representing the current URL. + * + * On Desktop this returns a string representation of the URL of the + * current top level browsing context. This is equivalent to + * document.location.href. + * + * When in the context of the chrome, this returns the canonical URL + * of the current resource. */ - getUrl: function MDA_getUrl() { + getCurrentUrl: function MDA_getCurrentUrl() { this.command_id = this.getCommandId(); if (this.context == "chrome") { this.sendResponse(this.getCurrentWindow().location.href, this.command_id); } else { - this.sendAsync("getUrl", {}, this.command_id); + this.sendAsync("getCurrentUrl", {}, this.command_id); } }, @@ -2375,7 +2382,8 @@ MarionetteServerConnection.prototype.requestTypes = { "getWindowType": MarionetteServerConnection.prototype.getWindowType, "getPageSource": MarionetteServerConnection.prototype.getPageSource, "goUrl": MarionetteServerConnection.prototype.goUrl, - "getUrl": MarionetteServerConnection.prototype.getUrl, + "getCurrentUrl": MarionetteServerConnection.prototype.getCurrentUrl, + "getUrl": MarionetteServerConnection.prototype.getCurrentUrl, // deprecated "goBack": MarionetteServerConnection.prototype.goBack, "goForward": MarionetteServerConnection.prototype.goForward, "refresh": MarionetteServerConnection.prototype.refresh, From cca4fe0a18a06cbb21f3a06a3f4c828fe8c6f64f Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Wed, 22 Jan 2014 14:04:04 -0500 Subject: [PATCH 16/59] Bug 941132 - getElementPosition not matching webdriver command. r=dburns --- .../marionette/client/marionette/marionette.py | 15 +++++++++++---- testing/marionette/marionette-listener.js | 10 +++++----- testing/marionette/marionette-server.js | 17 +++++++++++++---- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index 863826766103..87c53bc228b1 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -148,10 +148,17 @@ class HTMLElement(object): @property def location(self): - ''' - A dictionary with the x and y location of an element - ''' - return self.marionette._send_message('getElementPosition', 'value', id=self.id) + """Get an element's location on the page. + + The returned point will contain the x and y coordinates of the + top left-hand corner of the given element. The point (0,0) + refers to the upper-left corner of the document. + + :returns: a dictionary containing x and y as entries + + """ + + return self.marionette._send_message("getElementLocation", "value", id=self.id) def value_of_css_property(self, property_name): ''' diff --git a/testing/marionette/marionette-listener.js b/testing/marionette/marionette-listener.js index 3f8a0c475c13..3d142bb1ab25 100644 --- a/testing/marionette/marionette-listener.js +++ b/testing/marionette/marionette-listener.js @@ -151,7 +151,7 @@ function startListeners() { addMessageListenerId("Marionette:isElementEnabled", isElementEnabled); addMessageListenerId("Marionette:isElementSelected", isElementSelected); addMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement); - addMessageListenerId("Marionette:getElementPosition", getElementPosition); + addMessageListenerId("Marionette:getElementLocation", getElementLocation); addMessageListenerId("Marionette:clearElement", clearElement); addMessageListenerId("Marionette:switchToFrame", switchToFrame); addMessageListenerId("Marionette:deleteSession", deleteSession); @@ -251,7 +251,7 @@ function deleteSession(msg) { removeMessageListenerId("Marionette:isElementEnabled", isElementEnabled); removeMessageListenerId("Marionette:isElementSelected", isElementSelected); removeMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement); - removeMessageListenerId("Marionette:getElementPosition", getElementPosition); + removeMessageListenerId("Marionette:getElementLocation", getElementLocation); removeMessageListenerId("Marionette:clearElement", clearElement); removeMessageListenerId("Marionette:switchToFrame", switchToFrame); removeMessageListenerId("Marionette:deleteSession", deleteSession); @@ -1708,11 +1708,11 @@ function sendKeysToElement(msg) { } /** - * Get the position of an element + * Get the element's top left-hand corner point. */ -function getElementPosition(msg) { +function getElementLocation(msg) { let command_id = msg.json.command_id; - try{ + try { let el = elementManager.getKnownElement(msg.json.id, curFrame); let rect = el.getBoundingClientRect(); diff --git a/testing/marionette/marionette-server.js b/testing/marionette/marionette-server.js index dbad77bfff86..0078cb83c9bb 100644 --- a/testing/marionette/marionette-server.js +++ b/testing/marionette/marionette-server.js @@ -1907,10 +1907,18 @@ MarionetteServerConnection.prototype = { } }, - getElementPosition: function MDA_getElementPosition(aRequest) { + /** + * Get an element's location on the page. + * + * The returned point will contain the x and y coordinates of the + * top left-hand corner of the given element. The point (0,0) + * refers to the upper-left corner of the document. + * + * @return a point containing x and y coordinates as properties + */ + getElementLocation: function MDA_getElementLocation(aRequest) { this.command_id = this.getCommandId(); - this.sendAsync("getElementPosition", - { id:aRequest.parameters.id }, + this.sendAsync("getElementLocation", {id: aRequest.parameters.id}, this.command_id); }, @@ -2376,7 +2384,8 @@ MarionetteServerConnection.prototype.requestTypes = { "isElementEnabled": MarionetteServerConnection.prototype.isElementEnabled, "isElementSelected": MarionetteServerConnection.prototype.isElementSelected, "sendKeysToElement": MarionetteServerConnection.prototype.sendKeysToElement, - "getElementPosition": MarionetteServerConnection.prototype.getElementPosition, + "getElementLocation": MarionetteServerConnection.prototype.getElementLocation, + "getElementPosition": MarionetteServerConnection.prototype.getElementLocation, // deprecated "clearElement": MarionetteServerConnection.prototype.clearElement, "getTitle": MarionetteServerConnection.prototype.getTitle, "getWindowType": MarionetteServerConnection.prototype.getWindowType, From acd1fd0eeb7ec4d27e7a979ae1588cb84205d0de Mon Sep 17 00:00:00 2001 From: Andreas Tolfsen Date: Tue, 21 Jan 2014 13:31:32 -0500 Subject: [PATCH 17/59] Bug 961792 - Break iteration when browser is found. r=mdas The iteration used to look up the current window's server-assigned unique identifier in Marionette continues after the response has been sent. This is unnecessary and a potential synchronization problem because the client only expects a single response. --- testing/marionette/marionette-server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/marionette/marionette-server.js b/testing/marionette/marionette-server.js index 0078cb83c9bb..f9bae7ff9c41 100644 --- a/testing/marionette/marionette-server.js +++ b/testing/marionette/marionette-server.js @@ -1177,6 +1177,7 @@ MarionetteServerConnection.prototype = { for (let i in this.browsers) { if (this.curBrowser == this.browsers[i]) { this.sendResponse(i, this.command_id); + return; } } }, From 4ec75602b7f9b480aaa76571673cd0df768646eb Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Tue, 21 Jan 2014 16:27:01 -0500 Subject: [PATCH 18/59] Bug 916813 - Fix a crash during a layer dump. r=nical --- gfx/layers/composite/TextureHost.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp index 5777a469c34b..ab873a4561c1 100644 --- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -249,8 +249,13 @@ TextureHost::PrintInfo(nsACString& aTo, const char* aPrefix) { aTo += aPrefix; aTo += nsPrintfCString("%s (0x%p)", Name(), this); - AppendToString(aTo, GetSize(), " [size=", "]"); - AppendToString(aTo, GetFormat(), " [format=", "]"); + // Note: the TextureHost needs to be locked before it is safe to call + // GetSize() and GetFormat() on it. + if (Lock()) { + AppendToString(aTo, GetSize(), " [size=", "]"); + AppendToString(aTo, GetFormat(), " [format=", "]"); + Unlock(); + } AppendToString(aTo, mFlags, " [flags=", "]"); } From b35c1e7891efaf94795da68a63c52e973855d19e Mon Sep 17 00:00:00 2001 From: Ali Akhtarzada Date: Wed, 22 Jan 2014 14:12:02 -0500 Subject: [PATCH 19/59] Bug 962288 - Don't call DeprecatedGetAsSurface unless it's Cairo. r=mattwoodrow Changeset from Bug 959123 caused a performance decrease because DeprecatedGetAsSurface was being called on an image that may not be a CAIRO_SURFACE. --- gfx/layers/d3d10/ImageLayerD3D10.cpp | 4 ++-- gfx/layers/d3d9/ImageLayerD3D9.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gfx/layers/d3d10/ImageLayerD3D10.cpp b/gfx/layers/d3d10/ImageLayerD3D10.cpp index 84fc8a7ade17..3f13300e4068 100644 --- a/gfx/layers/d3d10/ImageLayerD3D10.cpp +++ b/gfx/layers/d3d10/ImageLayerD3D10.cpp @@ -213,14 +213,14 @@ ImageLayerD3D10::RenderLayer() ID3D10EffectTechnique *technique; nsRefPtr keyedMutex; - nsRefPtr surf = image->DeprecatedGetAsSurface(); if (image->GetFormat() == ImageFormat::CAIRO_SURFACE || image->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP || image->GetFormat() == ImageFormat::REMOTE_IMAGE_DXGI_TEXTURE || image->GetFormat() == ImageFormat::D3D9_RGB32_TEXTURE) { NS_ASSERTION(image->GetFormat() != ImageFormat::CAIRO_SURFACE || - !surf || surf->GetContentType() != GFX_CONTENT_ALPHA, + !static_cast(image)->DeprecatedGetAsSurface().get() || + static_cast(image)->DeprecatedGetAsSurface().get()->GetContentType() != GFX_CONTENT_ALPHA, "Image layer has alpha image"); bool hasAlpha = false; diff --git a/gfx/layers/d3d9/ImageLayerD3D9.cpp b/gfx/layers/d3d9/ImageLayerD3D9.cpp index 3a23540fe1ec..fe3a5136c690 100644 --- a/gfx/layers/d3d9/ImageLayerD3D9.cpp +++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp @@ -414,9 +414,9 @@ ImageLayerD3D9::RenderLayer() image->GetFormat() == REMOTE_IMAGE_BITMAP || image->GetFormat() == D3D9_RGB32_TEXTURE) { - nsRefPtr surf = image->DeprecatedGetAsSurface(); NS_ASSERTION(image->GetFormat() != CAIRO_SURFACE || - !surf || surf->GetContentType() != GFX_CONTENT_ALPHA, + !static_cast(image)->DeprecatedGetAsSurface().get() || + static_cast(image)->DeprecatedGetAsSurface().get()->GetContentType() != GFX_CONTENT_ALPHA, "Image layer has alpha image"); bool hasAlpha = false; From 5052fd5d63170c4f640867937149984177889ba7 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 22 Jan 2014 14:37:10 -0500 Subject: [PATCH 20/59] Bug 958576 part 1. Create a binding_detail namespace and move AutoSequence to it. r=peterv Note that we can't name this namespace "detail", because then we'd have both ::mozilla::detail and ::mozilla::dom::detail namespaces in the tree and various template name lookups that look for "detail::Foo" would get confused, and the code would not compile. C++ strikes again. --- content/canvas/src/CanvasRenderingContext2D.cpp | 3 ++- content/canvas/src/CanvasRenderingContext2D.h | 2 +- dom/bindings/BindingUtils.h | 4 ++++ dom/bindings/Codegen.py | 8 ++++---- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp index ffe5928c7866..e418615d6a20 100644 --- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -2943,7 +2943,8 @@ CanvasRenderingContext2D::SetMozDashOffset(double mozDashOffset) } void -CanvasRenderingContext2D::SetLineDash(const mozilla::dom::AutoSequence& aSegments) { +CanvasRenderingContext2D::SetLineDash(const Sequence& aSegments) +{ FallibleTArray& dash = CurrentState().dash; dash.Clear(); diff --git a/content/canvas/src/CanvasRenderingContext2D.h b/content/canvas/src/CanvasRenderingContext2D.h index deb441c6eb9e..f39b1658acbf 100644 --- a/content/canvas/src/CanvasRenderingContext2D.h +++ b/content/canvas/src/CanvasRenderingContext2D.h @@ -338,7 +338,7 @@ public: void SetMozDash(JSContext* cx, const JS::Value& mozDash, mozilla::ErrorResult& error); - void SetLineDash(const mozilla::dom::AutoSequence& mSegments); + void SetLineDash(const Sequence& mSegments); void GetLineDash(nsTArray& mSegments) const; void SetLineDashOffset(double mOffset); diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 4eab4bbac307..820158f1df49 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1597,6 +1597,8 @@ template void DoTraceSequence(JSTracer* trc, InfallibleTArray& seq); // Class for simple sequence arguments, only used internally by codegen. +namespace binding_detail { + template class AutoSequence : public AutoFallibleTArray { @@ -1610,6 +1612,8 @@ public: } }; +} // namespace binding_detail + // Class used to trace sequences, with specializations for various // sequence types. template ${holderName}(cx, &${declName});\n" % @@ -9258,7 +9258,7 @@ if (""", isStruct=True) return CGList([struct, - CGNamespace.build(['dictionary_detail'], + CGNamespace.build(['binding_detail'], fastStruct)], "\n") From 3146ee0f7a76ad9b443e97d1ba2377f69bb90000 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 22 Jan 2014 14:37:10 -0500 Subject: [PATCH 21/59] Bug 958576 part 2. Move FakeDependentString to the binding_detail namespace. r=peterv I took the opportunity to move away from the NonNull hack we had for string arguments, since just passing in a FakeDependentString works fine and callees are now less likely to declare their arg as being of that type. In the process of doing that, I ran into what looks like a substantive bug in the "owning union with string default value" case: We were doing mValue.mString.Value() without ever having constructed mValue.mString! --- .../html/content/src/nsGenericHTMLElement.cpp | 2 +- dom/bindings/BindingDeclarations.h | 4 +++- dom/bindings/BindingUtils.h | 6 ++++- dom/bindings/Codegen.py | 24 ++++++++++++------- dom/events/nsJSEventListener.cpp | 2 +- 5 files changed, 25 insertions(+), 13 deletions(-) diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index 7d7b77d5c526..7829c9a860e8 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -3154,7 +3154,7 @@ nsGenericHTMLElement::SetItemValue(JSContext* aCx, JS::Value aValue, return; } - FakeDependentString string; + binding_detail::FakeDependentString string; JS::Rooted value(aCx, aValue); if (!ConvertJSValueToString(aCx, value, &value, eStringify, eStringify, string)) { aError.Throw(NS_ERROR_UNEXPECTED); diff --git a/dom/bindings/BindingDeclarations.h b/dom/bindings/BindingDeclarations.h index 996cd033ded6..fce3a5605eb8 100644 --- a/dom/bindings/BindingDeclarations.h +++ b/dom/bindings/BindingDeclarations.h @@ -322,7 +322,9 @@ public: // internal strings. So we just have to forward-declare it and reimplement its // ToAStringPtr. +namespace binding_detail { struct FakeDependentString; +} // namespace binding_detail template<> class Optional @@ -344,7 +346,7 @@ public: // If this code ever goes away, remove the comment pointing to it in the // FakeDependentString class in BindingUtils.h. - void operator=(const FakeDependentString* str) + void operator=(const binding_detail::FakeDependentString* str) { MOZ_ASSERT(str); mStr = reinterpret_cast(str); diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 820158f1df49..4bb9c60c6bb8 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1456,6 +1456,8 @@ AppendNamedPropertyIds(JSContext* cx, JS::Handle proxy, nsTArray& names, bool shadowPrototypeProperties, JS::AutoIdVector& props); +namespace binding_detail { + // A struct that has the same layout as an nsDependentString but much // faster constructor and destructor behavior struct FakeDependentString { @@ -1533,6 +1535,8 @@ private: }; }; +} // namespace binding_detail + enum StringificationBehavior { eStringify, eEmpty, @@ -1545,7 +1549,7 @@ ConvertJSValueToString(JSContext* cx, JS::Handle v, JS::MutableHandle pval, StringificationBehavior nullBehavior, StringificationBehavior undefinedBehavior, - FakeDependentString& result) + binding_detail::FakeDependentString& result) { JSString *s; if (v.isString()) { diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 803e910bf33a..27e83f5ffb7c 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -3636,7 +3636,7 @@ for (uint32_t i = 0; i < length; ++i) { assignString = "${declName} = str" return JSToNativeConversionInfo( "{\n" - " FakeDependentString str;\n" + " binding_detail::FakeDependentString str;\n" "%s\n" " %s;\n" "}\n" % ( @@ -3646,16 +3646,20 @@ for (uint32_t i = 0; i < length; ++i) { if isOptional: declType = "Optional" + holderType = CGGeneric("binding_detail::FakeDependentString") + conversionCode = ("%s\n" + "${declName} = &${holderName};" % + getConversionCode("${holderName}")) else: - declType = "NonNull" + declType = "binding_detail::FakeDependentString" + holderType = None + conversionCode = getConversionCode("${declName}") # No need to deal with optional here; we handled it already return JSToNativeConversionInfo( - ("%s\n" - "${declName} = &${holderName};" % - getConversionCode("${holderName}")), + conversionCode, declType=CGGeneric(declType), - holderType=CGGeneric("FakeDependentString")) + holderType=holderType) if type.isByteString(): assert not isEnforceRange and not isClamp @@ -6942,7 +6946,7 @@ class CGUnionStruct(CGThing): [Argument("const nsString::char_type*", "aData"), Argument("nsString::size_type", "aLength")], inline=True, bodyInHeader=True, - body="mValue.mString.Value().Assign(aData, aLength);")) + body="SetAsString().Assign(aData, aLength);")) body = string.Template('MOZ_ASSERT(Is${name}(), "Wrong type!");\n' 'mValue.m${name}.Destroy();\n' @@ -7141,7 +7145,7 @@ class CGUnionConversionStruct(CGThing): [Argument("const nsDependentString::char_type*", "aData"), Argument("nsDependentString::size_type", "aLength")], inline=True, bodyInHeader=True, - body="mStringHolder.SetData(aData, aLength);")) + body="SetAsString().SetData(aData, aLength);")) if vars["holderType"] is not None: members.append(ClassMember("m%sHolder" % vars["name"], @@ -7965,7 +7969,7 @@ class CGProxyNamedOperation(CGProxySpecialOperation): # seems like probable overkill. return ("JS::Rooted nameVal(cx);\n" + idDecl + - ("FakeDependentString %s;\n" % argName) + + ("binding_detail::FakeDependentString %s;\n" % argName) + unwrapString + ("\n" "\n" @@ -11601,6 +11605,8 @@ struct PrototypeTraits; includes.add("mozilla/dom/OwningNonNull.h") includes.add("mozilla/dom/UnionMember.h") includes.add("mozilla/dom/BindingDeclarations.h") + # Need BindingUtils.h for FakeDependentString + includes.add("mozilla/dom/BindingUtils.h") implincludes.add("mozilla/dom/PrimitiveConversions.h") # Wrap all of that in our namespaces. diff --git a/dom/events/nsJSEventListener.cpp b/dom/events/nsJSEventListener.cpp index b68b312e47ca..62fceedbdb38 100644 --- a/dom/events/nsJSEventListener.cpp +++ b/dom/events/nsJSEventListener.cpp @@ -173,7 +173,7 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent) (scriptEvent->message == NS_LOAD_ERROR || scriptEvent->typeString.EqualsLiteral("error"))) { errorMsg = scriptEvent->errorMsg; - msgOrEvent.SetAsString() = static_cast(&errorMsg); + msgOrEvent.SetAsString().SetData(errorMsg.Data(), errorMsg.Length()); file = scriptEvent->fileName; fileName = &file; From ef95954bd2879a3031105fdccb6cabaab50c14c2 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 22 Jan 2014 14:37:11 -0500 Subject: [PATCH 22/59] Bug 962605. Enable baseline jit in xpcshell. r=bholley --- js/xpconnect/src/XPCShellImpl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index 1f100c4e4de7..30e333f86fbf 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -1458,6 +1458,9 @@ XRE_XPCShellMain(int argc, char **argv, char **envp) return 1; } + // Ion not enabled yet here because of bug 931861. + JS::ContextOptionsRef(cx).setBaseline(true); + argc--; argv++; ProcessArgsForCompartment(cx, argv, argc); From d4180132b8370c9db9b537a8ba31667851a576e4 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 14 Jan 2014 13:20:32 -0800 Subject: [PATCH 23/59] Bug 959806 - Make the analysis explain why it believes a type to be a gc type, r=terrence --- js/src/devtools/rootAnalysis/analyzeRoots.js | 4 +- .../devtools/rootAnalysis/computeGCTypes.js | 104 ++++++++++++++---- 2 files changed, 86 insertions(+), 22 deletions(-) diff --git a/js/src/devtools/rootAnalysis/analyzeRoots.js b/js/src/devtools/rootAnalysis/analyzeRoots.js index 4da950c831e5..750e04378723 100644 --- a/js/src/devtools/rootAnalysis/analyzeRoots.js +++ b/js/src/devtools/rootAnalysis/analyzeRoots.js @@ -52,9 +52,9 @@ var gcPointers = {}; text = snarf(gcTypesFile).split("\n"); for (var line of text) { - if (match = /GCThing: (.*)/.exec(line)) + if (match = /^GCThing: (.*)/.exec(line)) gcThings[match[1]] = true; - if (match = /GCPointer: (.*)/.exec(line)) + if (match = /^GCPointer: (.*)/.exec(line)) gcPointers[match[1]] = true; } text = null; diff --git a/js/src/devtools/rootAnalysis/computeGCTypes.js b/js/src/devtools/rootAnalysis/computeGCTypes.js index 346ce801bbbf..f1f540d6e448 100644 --- a/js/src/devtools/rootAnalysis/computeGCTypes.js +++ b/js/src/devtools/rootAnalysis/computeGCTypes.js @@ -11,38 +11,39 @@ function processCSU(csu, body) return; for (var field of body.DataField) { var type = field.Field.Type; + var fieldName = field.Field.Name[0]; if (type.Kind == "Pointer") { var target = type.Type; if (target.Kind == "CSU") - addNestedPointer(csu, target.Name); + addNestedPointer(csu, target.Name, fieldName); } if (type.Kind == "CSU") { // Ignore nesting in classes which are AutoGCRooters. We only consider // types with fields that may not be properly rooted. if (type.Name == "JS::AutoGCRooter" || type.Name == "JS::CustomAutoRooter") return; - addNestedStructure(csu, type.Name); + addNestedStructure(csu, type.Name, fieldName); } } } -function addNestedStructure(csu, inner) +var structureParents = {}; // Map from field => list of +var pointerParents = {}; // Map from field => list of + +function addNestedStructure(csu, inner, field) { if (!(inner in structureParents)) structureParents[inner] = []; - structureParents[inner].push(csu); + structureParents[inner].push([ csu, field ]); } -function addNestedPointer(csu, inner) +function addNestedPointer(csu, inner, field) { if (!(inner in pointerParents)) pointerParents[inner] = []; - pointerParents[inner].push(csu); + pointerParents[inner].push([ csu, field ]); } -var structureParents = {}; -var pointerParents = {}; - var xdb = xdbLibrary(); xdb.open("src_comp.xdb"); @@ -60,32 +61,66 @@ for (var csuIndex = minStream; csuIndex <= maxStream; csuIndex++) { xdb.free_string(data); } -function addGCType(name) +var gcTypes = {}; // map from parent struct => Set of GC typed children +var gcPointers = {}; // map from parent struct => Set of GC typed children +var gcFields = {}; + +function addGCType(name, child, why) { + if (!why) + why = ''; + if (!child) + child = 'annotation'; + if (isRootedTypeName(name)) return; - print("GCThing: " + name); + if (!(name in gcTypes)) + gcTypes[name] = Set(); + gcTypes[name].add(why); + + if (!(name in gcFields)) + gcFields[name] = Map(); + gcFields[name].set(why, child); + if (name in structureParents) { - for (var holder of structureParents[name]) - addGCType(holder); + for (var field of structureParents[name]) { + var [ holder, fieldName ] = field; + addGCType(holder, name, fieldName); + } } if (name in pointerParents) { - for (var holder of pointerParents[name]) - addGCPointer(holder); + for (var field of pointerParents[name]) { + var [ holder, fieldName ] = field; + addGCPointer(holder, name, fieldName); + } } } -function addGCPointer(name) +function addGCPointer(name, child, why) { - // Ignore types which are properly rooted. + if (!why) + why = ''; + if (!child) + child = 'annotation'; + + // Ignore types that are properly rooted. if (isRootedPointerTypeName(name)) return; - print("GCPointer: " + name); + if (!(name in gcPointers)) + gcPointers[name] = Set(); + gcPointers[name].add(why); + + if (!(name in gcFields)) + gcFields[name] = Map(); + gcFields[name].set(why, child); + if (name in structureParents) { - for (var holder of structureParents[name]) - addGCPointer(holder); + for (var field of structureParents[name]) { + var [ holder, fieldName ] = field; + addGCPointer(holder, name, fieldName); + } } } @@ -98,3 +133,32 @@ addGCType('js::LazyScript'); addGCType('js::ion::IonCode'); addGCPointer('JS::Value'); addGCPointer('jsid'); + +function explain(csu, indent, seen) { + if (!seen) + seen = Set(); + seen.add(csu); + if (!(csu in gcFields)) + return; + if (gcFields[csu].has('')) { + print(indent + "because I said so"); + return; + } + for (var [ field, child ] of gcFields[csu]) { + var inherit = ""; + if (field == "field:0") + inherit = " (probably via inheritance)"; + print(indent + "contains field '" + field + "' of type " + child + inherit); + if (!seen.has(child)) + explain(child, indent + " ", seen); + } +} + +for (var csu in gcTypes) { + print("GCThing: " + csu); + explain(csu, " "); +} +for (var csu in gcPointers) { + print("GCPointer: " + csu); + explain(csu, " "); +} From 9f7287162433ca831ba45ff84630bc15bc567544 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Wed, 22 Jan 2014 11:52:44 -0800 Subject: [PATCH 24/59] Bug 960342 - Add a RootedGeneric general class, r=terrence --- js/public/RootingAPI.h | 55 +++++++++++++++++++++++++++++++++++++++ js/src/gc/RootMarking.cpp | 7 +++++ js/src/jspubtd.h | 1 + 3 files changed, 63 insertions(+) diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index 2df52442a5f2..26d442eb023f 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -917,6 +917,61 @@ class SkipRoot MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; +/* + * RootedGeneric allows a class to instantiate its own Rooted type by + * including the following two methods: + * + * static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; } + * void trace(JSTracer *trc); + * + * The trace() method must trace all of the class's fields. + * + * Implementation: + * + * RootedGeneric works by placing a pointer to its 'rooter' field into the + * usual list of rooters when it is instantiated. When marking, it backs up + * from this pointer to find a vtable containing a type-appropriate trace() + * method. + */ +template +class JS_PUBLIC_API(RootedGeneric) +{ + public: + JS::Rooted rooter; + SkipRoot skip; + + RootedGeneric(js::ContextFriendFields *cx) + : rooter(cx), skip(cx, rooter.address()) + { + } + + RootedGeneric(js::ContextFriendFields *cx, const GCType &initial) + : rooter(cx, initial), skip(cx, rooter.address()) + { + } + + virtual inline void trace(JSTracer *trc); + + operator const GCType&() const { return rooter.get(); } + GCType operator->() const { return rooter.get(); } +}; + +template +inline void RootedGeneric::trace(JSTracer *trc) +{ + rooter->trace(trc); +} + +// We will instantiate RootedGeneric in RootMarking.cpp, and MSVC will +// notice that void*s have no trace() method defined on them and complain (even +// though it's never called.) MSVC's complaint is not unreasonable, so +// specialize for void*. +template <> +inline void RootedGeneric::trace(JSTracer *trc) +{ + MOZ_ASSUME_UNREACHABLE("RootedGeneric::trace()"); +} + /* Interface substitute for Rooted which does not root the variable's memory. */ template class FakeRooted : public RootedBase diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index a8016d44ed7e..50bc98644ce3 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -65,6 +65,13 @@ MarkExactStackRoot(JSTracer *trc, Rooted *rooter, ThingRootKind kind) case THING_ROOT_PROPERTY_ID: MarkIdRoot(trc, &((js::PropertyId *)addr)->asId(), "exact-propertyid"); break; case THING_ROOT_BINDINGS: ((Bindings *)addr)->trace(trc); break; case THING_ROOT_PROPERTY_DESCRIPTOR: ((JSPropertyDescriptor *)addr)->trace(trc); break; + case THING_ROOT_CUSTOM: { + // 'rooter' is a member within a class containing a vtable. Back up + // to the vtable and call trace() through it. + const size_t rooterOffset = offsetof(RootedGeneric, rooter); + reinterpret_cast< RootedGeneric* >(uintptr_t(rooter) - rooterOffset)->trace(trc); + break; + } default: MOZ_ASSUME_UNREACHABLE("Invalid THING_ROOT kind"); break; } } diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 852ef0c1afdd..898436e0c7ad 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -310,6 +310,7 @@ enum ThingRootKind THING_ROOT_TYPE, THING_ROOT_BINDINGS, THING_ROOT_PROPERTY_DESCRIPTOR, + THING_ROOT_CUSTOM, THING_ROOT_LIMIT }; From 193fe092cd8701f8bb07af7cccc8573d8886e1fe Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Wed, 22 Jan 2014 11:52:44 -0800 Subject: [PATCH 25/59] Bug 960342 - Convert StackBaseShape from AutoRooter to RootedGeneric, r=terrence --- js/src/vm/Shape-inl.h | 8 -------- js/src/vm/Shape.cpp | 38 +++++++++++++++++++------------------- js/src/vm/Shape.h | 20 +++++--------------- 3 files changed, 24 insertions(+), 42 deletions(-) diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 1846ec819cf6..4617d3395b90 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -234,14 +234,6 @@ AutoRooterGetterSetter::AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t at MOZ_GUARD_OBJECT_NOTIFIER_INIT; } -inline -StackBaseShape::AutoRooter::AutoRooter(ThreadSafeContext *cx, const StackBaseShape *base_ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) - : CustomAutoRooter(cx), base(base_), skip(cx, base_) -{ - MOZ_GUARD_OBJECT_NOTIFIER_INIT; -} - inline StackShape::AutoRooter::AutoRooter(ThreadSafeContext *cx, const StackShape *shape_ MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 41c465fc8c9f..531bf1ad0065 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -306,7 +306,7 @@ ShapeTable::grow(ThreadSafeContext *cx) } /* static */ Shape * -Shape::replaceLastProperty(ExclusiveContext *cx, const StackBaseShape &base, +Shape::replaceLastProperty(ExclusiveContext *cx, StackBaseShape &base, TaggedProto proto, HandleShape shape) { JS_ASSERT(!shape->inDictionary()); @@ -546,7 +546,7 @@ ShouldConvertToDictionary(JSObject *obj) template static inline UnownedBaseShape * GetOrLookupUnownedBaseShape(typename ExecutionModeTraits::ExclusiveContextType cx, - const StackBaseShape &base) + StackBaseShape &base) { if (mode == ParallelExecution) return BaseShape::lookupUnowned(cx, base); @@ -1439,28 +1439,28 @@ StackBaseShape::match(UnownedBaseShape *key, const StackBaseShape *lookup) } void -StackBaseShape::AutoRooter::trace(JSTracer *trc) +StackBaseShape::trace(JSTracer *trc) { - if (base->parent) { - gc::MarkObjectRoot(trc, (JSObject**)&base->parent, - "StackBaseShape::AutoRooter parent"); + if (parent) { + gc::MarkObjectRoot(trc, (JSObject**)&parent, + "StackBaseShape parent"); } - if (base->metadata) { - gc::MarkObjectRoot(trc, (JSObject**)&base->metadata, - "StackBaseShape::AutoRooter metadata"); + if (metadata) { + gc::MarkObjectRoot(trc, (JSObject**)&metadata, + "StackBaseShape metadata"); } - if ((base->flags & BaseShape::HAS_GETTER_OBJECT) && base->rawGetter) { - gc::MarkObjectRoot(trc, (JSObject**)&base->rawGetter, - "StackBaseShape::AutoRooter getter"); + if ((flags & BaseShape::HAS_GETTER_OBJECT) && rawGetter) { + gc::MarkObjectRoot(trc, (JSObject**)&rawGetter, + "StackBaseShape getter"); } - if ((base->flags & BaseShape::HAS_SETTER_OBJECT) && base->rawSetter) { - gc::MarkObjectRoot(trc, (JSObject**)&base->rawSetter, - "StackBaseShape::AutoRooter setter"); + if ((flags & BaseShape::HAS_SETTER_OBJECT) && rawSetter) { + gc::MarkObjectRoot(trc, (JSObject**)&rawSetter, + "StackBaseShape setter"); } } /* static */ UnownedBaseShape* -BaseShape::getUnowned(ExclusiveContext *cx, const StackBaseShape &base) +BaseShape::getUnowned(ExclusiveContext *cx, StackBaseShape &base) { BaseShapeSet &table = cx->compartment()->baseShapes; @@ -1471,17 +1471,17 @@ BaseShape::getUnowned(ExclusiveContext *cx, const StackBaseShape &base) if (p) return *p; - StackBaseShape::AutoRooter root(cx, &base); + RootedGeneric root(cx, &base); BaseShape *nbase_ = js_NewGCBaseShape(cx); if (!nbase_) return nullptr; - new (nbase_) BaseShape(base); + new (nbase_) BaseShape(*root); UnownedBaseShape *nbase = static_cast(nbase_); - if (!p.add(cx, table, &base, nbase)) + if (!p.add(cx, table, root, nbase)) return nullptr; return nbase; diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index d81da1d0af36..227b00f829b2 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -715,7 +715,7 @@ class BaseShape : public gc::BarrieredCell * Lookup base shapes from the compartment's baseShapes table, adding if * not already found. */ - static UnownedBaseShape* getUnowned(ExclusiveContext *cx, const StackBaseShape &base); + static UnownedBaseShape* getUnowned(ExclusiveContext *cx, StackBaseShape &base); /* * Lookup base shapes from the compartment's baseShapes table, returning @@ -847,19 +847,9 @@ struct StackBaseShape static inline HashNumber hash(const StackBaseShape *lookup); static inline bool match(UnownedBaseShape *key, const StackBaseShape *lookup); - class AutoRooter : private JS::CustomAutoRooter - { - public: - inline AutoRooter(ThreadSafeContext *cx, const StackBaseShape *base_ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - - private: - virtual void trace(JSTracer *trc); - - const StackBaseShape *base; - SkipRoot skip; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - }; + // For RootedGeneric + static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; } + void trace(JSTracer *trc); }; inline @@ -961,7 +951,7 @@ class Shape : public gc::BarrieredCell } /* Replace the base shape of the last shape in a non-dictionary lineage with base. */ - static Shape *replaceLastProperty(ExclusiveContext *cx, const StackBaseShape &base, + static Shape *replaceLastProperty(ExclusiveContext *cx, StackBaseShape &base, TaggedProto proto, HandleShape shape); /* From edd13ec3e96cdf8d355e070dd633de135077a458 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Wed, 22 Jan 2014 11:52:44 -0800 Subject: [PATCH 26/59] Bug 960342 - Convert StackShape from AutoRooter to RootedGeneric, r=terrence --- js/src/gc/RootMarking.cpp | 8 ++++---- js/src/jsobj.cpp | 12 ++++++------ js/src/jspropertytree.cpp | 14 +++++++------- js/src/jspropertytree.h | 2 +- js/src/vm/Shape-inl.h | 8 -------- js/src/vm/Shape.cpp | 24 ++++++++++++------------ js/src/vm/Shape.h | 16 +++------------- 7 files changed, 33 insertions(+), 51 deletions(-) diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 50bc98644ce3..7b9cf0db28a0 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -600,11 +600,11 @@ AutoHashableValueRooter::trace(JSTracer *trc) } void -StackShape::AutoRooter::trace(JSTracer *trc) +StackShape::trace(JSTracer *trc) { - if (shape->base) - MarkBaseShapeRoot(trc, (BaseShape**) &shape->base, "StackShape::AutoRooter base"); - MarkIdRoot(trc, (jsid*) &shape->propid, "StackShape::AutoRooter id"); + if (base) + MarkBaseShapeRoot(trc, (BaseShape**) &base, "StackShape base"); + MarkIdRoot(trc, (jsid*) &propid, "StackShape id"); } void diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index c52b69116e68..c14f37d0003f 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1130,14 +1130,14 @@ JSObject::sealOrFreeze(JSContext *cx, HandleObject obj, ImmutabilityType it) Reverse(shapes.begin(), shapes.end()); for (size_t i = 0; i < shapes.length(); i++) { - StackShape child(shapes[i]); - StackShape::AutoRooter rooter(cx, &child); - child.attrs |= getSealedOrFrozenAttributes(child.attrs, it); + StackShape unrootedChild(shapes[i]); + RootedGeneric child(cx, &unrootedChild); + child->attrs |= getSealedOrFrozenAttributes(child->attrs, it); - if (!JSID_IS_EMPTY(child.propid) && it == FREEZE) - MarkTypePropertyNonWritable(cx, obj, child.propid); + if (!JSID_IS_EMPTY(child->propid) && it == FREEZE) + MarkTypePropertyNonWritable(cx, obj, child->propid); - last = cx->compartment()->propertyTree.getChild(cx, last, child); + last = cx->compartment()->propertyTree.getChild(cx, last, *child); if (!last) return false; } diff --git a/js/src/jspropertytree.cpp b/js/src/jspropertytree.cpp index a35457d20b49..6e4d162576f4 100644 --- a/js/src/jspropertytree.cpp +++ b/js/src/jspropertytree.cpp @@ -126,7 +126,7 @@ Shape::removeChild(Shape *child) } Shape * -PropertyTree::getChild(ExclusiveContext *cx, Shape *parentArg, const StackShape &child) +PropertyTree::getChild(ExclusiveContext *cx, Shape *parentArg, StackShape &unrootedChild) { RootedShape parent(cx, parentArg); JS_ASSERT(parent); @@ -144,11 +144,11 @@ PropertyTree::getChild(ExclusiveContext *cx, Shape *parentArg, const StackShape KidsPointer *kidp = &parent->kids; if (kidp->isShape()) { Shape *kid = kidp->toShape(); - if (kid->matches(child)) - existingShape = kid; + if (kid->matches(unrootedChild)) + existingShape = kid; } else if (kidp->isHash()) { - if (KidsHash::Ptr p = kidp->toHash()->lookup(child)) - existingShape = *p; + if (KidsHash::Ptr p = kidp->toHash()->lookup(unrootedChild)) + existingShape = *p; } else { /* If kidp->isNull(), we always insert. */ } @@ -181,13 +181,13 @@ PropertyTree::getChild(ExclusiveContext *cx, Shape *parentArg, const StackShape if (existingShape) return existingShape; - StackShape::AutoRooter childRoot(cx, &child); + RootedGeneric child(cx, &unrootedChild); Shape *shape = newShape(cx); if (!shape) return nullptr; - new (shape) Shape(child, parent->numFixedSlots()); + new (shape) Shape(*child, parent->numFixedSlots()); if (!insertChild(cx, parent, shape)) return nullptr; diff --git a/js/src/jspropertytree.h b/js/src/jspropertytree.h index 1015bf4228b8..362c45c6d02c 100644 --- a/js/src/jspropertytree.h +++ b/js/src/jspropertytree.h @@ -97,7 +97,7 @@ class PropertyTree JSCompartment *compartment() { return compartment_; } Shape *newShape(ExclusiveContext *cx); - Shape *getChild(ExclusiveContext *cx, Shape *parent, const StackShape &child); + Shape *getChild(ExclusiveContext *cx, Shape *parent, StackShape &child); Shape *lookupChild(ThreadSafeContext *cx, Shape *parent, const StackShape &child); }; diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 4617d3395b90..c5fb04615429 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -234,14 +234,6 @@ AutoRooterGetterSetter::AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t at MOZ_GUARD_OBJECT_NOTIFIER_INIT; } -inline -StackShape::AutoRooter::AutoRooter(ThreadSafeContext *cx, const StackShape *shape_ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) - : CustomAutoRooter(cx), shape(shape_), skip(cx, shape_) -{ - MOZ_GUARD_OBJECT_NOTIFIER_INIT; -} - } /* namespace js */ #endif /* vm_Shape_inl_h */ diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 531bf1ad0065..73b92fa9f542 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -363,15 +363,15 @@ JSObject::getChildPropertyOnDictionary(ThreadSafeContext *cx, JS::HandleObject o if (obj->inDictionaryMode()) { JS_ASSERT(parent == obj->lastProperty()); - StackShape::AutoRooter childRoot(cx, &child); + RootedGeneric childRoot(cx, &child); shape = js_NewGCShape(cx); if (!shape) return nullptr; - if (child.hasSlot() && child.slot() >= obj->lastProperty()->base()->slotSpan()) { - if (!JSObject::setSlotSpan(cx, obj, child.slot() + 1)) + if (childRoot->hasSlot() && childRoot->slot() >= obj->lastProperty()->base()->slotSpan()) { + if (!JSObject::setSlotSpan(cx, obj, childRoot->slot() + 1)) return nullptr; } - shape->initDictionaryShape(child, obj->numFixedSlots(), &obj->shape_); + shape->initDictionaryShape(*childRoot, obj->numFixedSlots(), &obj->shape_); } return shape; @@ -379,13 +379,13 @@ JSObject::getChildPropertyOnDictionary(ThreadSafeContext *cx, JS::HandleObject o /* static */ Shape * JSObject::getChildProperty(ExclusiveContext *cx, - HandleObject obj, HandleShape parent, StackShape &child) + HandleObject obj, HandleShape parent, StackShape &unrootedChild) { - StackShape::AutoRooter childRoot(cx, &child); - RootedShape shape(cx, getChildPropertyOnDictionary(cx, obj, parent, child)); + RootedGeneric child(cx, &unrootedChild); + RootedShape shape(cx, getChildPropertyOnDictionary(cx, obj, parent, *child)); if (!obj->inDictionaryMode()) { - shape = cx->compartment()->propertyTree.getChild(cx, parent, child); + shape = cx->compartment()->propertyTree.getChild(cx, parent, *child); if (!shape) return nullptr; //JS_ASSERT(shape->parent == parent); @@ -399,15 +399,15 @@ JSObject::getChildProperty(ExclusiveContext *cx, /* static */ Shape * JSObject::lookupChildProperty(ThreadSafeContext *cx, - HandleObject obj, HandleShape parent, StackShape &child) + HandleObject obj, HandleShape parent, StackShape &unrootedChild) { - StackShape::AutoRooter childRoot(cx, &child); + RootedGeneric child(cx, &unrootedChild); JS_ASSERT(cx->isThreadLocal(obj)); - RootedShape shape(cx, getChildPropertyOnDictionary(cx, obj, parent, child)); + RootedShape shape(cx, getChildPropertyOnDictionary(cx, obj, parent, *child)); if (!obj->inDictionaryMode()) { - shape = cx->compartment_->propertyTree.lookupChild(cx, parent, child); + shape = cx->compartment_->propertyTree.lookupChild(cx, parent, *child); if (!shape) return nullptr; if (!JSObject::setLastProperty(cx, obj, shape)) diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 227b00f829b2..d1da317898c4 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -1546,19 +1546,9 @@ struct StackShape return hash; } - class AutoRooter : private JS::CustomAutoRooter - { - public: - inline AutoRooter(ThreadSafeContext *cx, const StackShape *shape_ - MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - - private: - virtual void trace(JSTracer *trc); - - const StackShape *shape; - SkipRoot skip; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - }; + // For RootedGeneric + static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; } + void trace(JSTracer *trc); }; } /* namespace js */ From 72ac4f30f82374835cb0eb517ae77f1de7ab7e53 Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Wed, 22 Jan 2014 20:20:20 +0000 Subject: [PATCH 27/59] Bug 961712 - Buffer (f)printf_stderr on Android. r=gal Android logging functions append newlines to all output. Layout debugging (and perhaps other areas) relies on being able to print partial lines, making its output almost unreadable. This change adds manual buffering between newlines, making the output readable again. --- xpcom/glue/nsCRTGlue.cpp | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/xpcom/glue/nsCRTGlue.cpp b/xpcom/glue/nsCRTGlue.cpp index d81ad07dfdd2..5e38b9366fc2 100644 --- a/xpcom/glue/nsCRTGlue.cpp +++ b/xpcom/glue/nsCRTGlue.cpp @@ -299,7 +299,43 @@ vprintf_stderr(const char *fmt, va_list args) void vprintf_stderr(const char *fmt, va_list args) { - __android_log_vprint(ANDROID_LOG_INFO, "Gecko", fmt, args); + if (!fmt) { + return; + } + + // Android's logging functions append new-lines to all output, so handle this + // by buffering between new-lines. + + static char printf_buffer[2048]; + static size_t printf_buffer_idx = 0; + + size_t old_idx = printf_buffer_idx; + printf_buffer_idx += + vsnprintf(printf_buffer + printf_buffer_idx, + sizeof(printf_buffer) - printf_buffer_idx, + fmt, args); + + // Handle overflow. In this case, print the old buffer, the new format and + // clear the buffer for the next call. + if (printf_buffer_idx >= sizeof(printf_buffer)) { + printf_buffer[old_idx] = '\0'; + printf_buffer_idx = 0; + __android_log_print(ANDROID_LOG_INFO, "Gecko", printf_buffer); + __android_log_vprint(ANDROID_LOG_INFO, "Gecko", fmt, args); + return; + } + + // Print up to the last new-line, if there are any, and if there are, move + // the rest of the string back to the beginning. + char* last_newline = strrchr(printf_buffer + old_idx, '\n'); + if (last_newline) { + last_newline[0] = '\0'; + __android_log_print(ANDROID_LOG_INFO, "Gecko", printf_buffer); + + char* remainder = last_newline + 1; + printf_buffer_idx = strlen(remainder); + memmove(printf_buffer, remainder, printf_buffer_idx + 1); + } } #else void From 5b9e37d8cf19023e928e9f883616b192880ba3a9 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Wed, 22 Jan 2014 12:27:23 -0800 Subject: [PATCH 28/59] Bug 938904 - [e10s] Make tooltips work (r=smaug,enn) --- browser/base/content/browser.js | 15 ++++ browser/base/content/browser.xul | 1 + dom/ipc/PBrowser.ipdl | 7 ++ dom/ipc/TabChild.cpp | 15 ++++ dom/ipc/TabChild.h | 5 +- dom/ipc/TabParent.cpp | 91 ++++++++++++++------ dom/ipc/TabParent.h | 5 ++ xpfe/appshell/public/nsIXULBrowserWindow.idl | 8 +- 8 files changed, 119 insertions(+), 28 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 878924dc8eb1..861d2d5e50d7 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3459,6 +3459,21 @@ var XULBrowserWindow = { LinkTargetDisplay.update(); }, + showTooltip: function (x, y, tooltip) { + // The x,y coordinates are relative to the element using + // the chrome zoom level. + let elt = document.getElementById("remoteBrowserTooltip"); + elt.label = tooltip; + + let anchor = gBrowser.selectedBrowser; + elt.openPopupAtScreen(anchor.boxObject.screenX + x, anchor.boxObject.screenY + y, false, null); + }, + + hideTooltip: function () { + let elt = document.getElementById("remoteBrowserTooltip"); + elt.hidePopup(); + }, + updateStatusField: function () { var text, type, types = ["overLink"]; if (this._busyUI) diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 6c567598aa08..b73f285e389b 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -129,6 +129,7 @@ oncommand="gotoHistoryIndex(event); event.stopPropagation();" onclick="checkForMiddleClick(this, event);"/> +