diff --git a/accessible/src/jsat/AccessFu.jsm b/accessible/src/jsat/AccessFu.jsm index c07f4597d673..43cacb5f7fbc 100644 --- a/accessible/src/jsat/AccessFu.jsm +++ b/accessible/src/jsat/AccessFu.jsm @@ -735,6 +735,12 @@ var Input = { case 'swipeleft1': this.moveCursor('movePrevious', 'Simple', 'gesture'); break; + case 'swipeup1': + this.contextAction('backward'); + break; + case 'swipedown1': + this.contextAction('forward'); + break; case 'exploreend1': this.activateCurrent(null, true); break; @@ -859,6 +865,12 @@ var Input = { origin: 'top', inputType: aInputType}); }, + contextAction: function contextAction(aDirection) { + // XXX: For now, the only supported context action is adjusting a range. + let mm = Utils.getMessageManager(Utils.CurrentBrowser); + mm.sendAsyncMessage('AccessFu:AdjustRange', {direction: aDirection}); + }, + moveByGranularity: function moveByGranularity(aDetails) { const MOVEMENT_GRANULARITY_PARAGRAPH = 8; diff --git a/accessible/src/jsat/content-script.js b/accessible/src/jsat/content-script.js index 1b1075d233fa..69101a78b84f 100644 --- a/accessible/src/jsat/content-script.js +++ b/accessible/src/jsat/content-script.js @@ -331,6 +331,23 @@ function scroll(aMessage) { } } +function adjustRange(aMessage) { + function sendUpDownKey(aAccessible) { + let evt = content.document.createEvent('KeyboardEvent'); + let keycode = aMessage.json.direction == 'forward' ? + content.KeyEvent.DOM_VK_DOWN : content.KeyEvent.DOM_VK_UP; + evt.initKeyEvent( + "keypress", false, true, null, false, false, false, false, keycode, 0); + if (aAccessible.DOMNode) { + aAccessible.DOMNode.dispatchEvent(evt); + } + } + + let position = Utils.getVirtualCursor(content.document).position; + if (!forwardToChild(aMessage, adjustRange, position)) { + sendUpDownKey(position); + } +} addMessageListener( 'AccessFu:Start', function(m) { @@ -344,6 +361,7 @@ addMessageListener( addMessageListener('AccessFu:Activate', activateCurrent); addMessageListener('AccessFu:ContextMenu', activateContextMenu); addMessageListener('AccessFu:Scroll', scroll); + addMessageListener('AccessFu:AdjustRange', adjustRange); addMessageListener('AccessFu:MoveCaret', moveCaret); addMessageListener('AccessFu:MoveByGranularity', moveByGranularity); diff --git a/content/base/public/nsIMessageManager.idl b/content/base/public/nsIMessageManager.idl index 417eb0fdafba..fbeb920d8de9 100644 --- a/content/base/public/nsIMessageManager.idl +++ b/content/base/public/nsIMessageManager.idl @@ -9,6 +9,7 @@ interface nsIDOMDOMStringList; interface nsIDOMWindow; interface nsIDocShell; interface nsIContent; +interface nsIPrincipal; /** * Message managers provide a way for chrome-privileged JS code to @@ -156,14 +157,15 @@ interface nsIMessageListener : nsISupports * receiveMessage is called with one parameter, which has the following * properties: * { - * target: %the target of the message. Either an element owning - * the message manager, or message manager itself if no - * element owns it% - * name: %message name%, - * sync: %true or false%. - * data: %structured clone of the sent message data%, - * json: %same as .data, deprecated%, - * objects: %named table of jsvals/objects, or null% + * target: %the target of the message. Either an element owning + * the message manager, or message manager itself if no + * element owns it% + * name: %message name%, + * sync: %true or false%. + * data: %structured clone of the sent message data%, + * json: %same as .data, deprecated%, + * objects: %named table of jsvals/objects, or null% + * principal: %principal for the window app * } * * Each listener is invoked with its own copy of the message @@ -231,7 +233,7 @@ interface nsIMessageListenerManager : nsISupports * messages that are only delivered to its one parent-process message * manager. */ -[scriptable, builtinclass, uuid(7f23767d-0f39-40c1-a22d-d3ab8a481f9d)] +[scriptable, builtinclass, uuid(d6b0d851-43e6-426d-9f13-054bc0198175)] interface nsIMessageSender : nsIMessageListenerManager { /** @@ -252,7 +254,8 @@ interface nsIMessageSender : nsIMessageListenerManager [implicit_jscontext, optional_argc] void sendAsyncMessage([optional] in AString messageName, [optional] in jsval obj, - [optional] in jsval objects); + [optional] in jsval objects, + [optional] in nsIPrincipal principal); }; /** @@ -289,7 +292,7 @@ interface nsIMessageBroadcaster : nsIMessageListenerManager nsIMessageListenerManager getChildAt(in unsigned long aIndex); }; -[scriptable, builtinclass, uuid(79eeb70f-58e3-4d32-b46f-106f42ada12b)] +[scriptable, builtinclass, uuid(7fda0941-9dcc-448b-bd39-16373c5b4003)] interface nsISyncMessageSender : nsIMessageSender { /** @@ -300,7 +303,8 @@ interface nsISyncMessageSender : nsIMessageSender [implicit_jscontext, optional_argc] jsval sendSyncMessage([optional] in AString messageName, [optional] in jsval obj, - [optional] in jsval objects); + [optional] in jsval objects, + [optional] in nsIPrincipal principal); /** * Like |sendSyncMessage()|, except re-entrant. New RPC messages may be @@ -314,7 +318,8 @@ interface nsISyncMessageSender : nsIMessageSender [implicit_jscontext, optional_argc] jsval sendRpcMessage([optional] in AString messageName, [optional] in jsval obj, - [optional] in jsval objects); + [optional] in jsval objects, + [optional] in nsIPrincipal principal); }; [scriptable, builtinclass, uuid(894ff2d4-39a3-4df8-9d76-8ee329975488)] diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index c7b75c447c84..d0270f36ec03 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -2215,8 +2215,10 @@ public: nsFrameLoader* aFrameLoader, const nsAString& aMessage, const StructuredCloneData& aData, - JS::Handle aCpows) - : mRuntime(js::GetRuntime(aCx)), mFrameLoader(aFrameLoader), mMessage(aMessage), mCpows(aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) + : mRuntime(js::GetRuntime(aCx)), mFrameLoader(aFrameLoader) + , mMessage(aMessage), mCpows(aCpows), mPrincipal(aPrincipal) { if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) { NS_RUNTIMEABORT("OOM"); @@ -2249,7 +2251,7 @@ public: nsRefPtr mm = tabChild->GetInnerManager(); mm->ReceiveMessage(static_cast(tabChild), mMessage, - false, &data, &cpows, nullptr); + false, &data, &cpows, mPrincipal, nullptr); } return NS_OK; } @@ -2259,13 +2261,15 @@ public: JSAutoStructuredCloneBuffer mData; StructuredCloneClosure mClosure; JSObject* mCpows; + nsCOMPtr mPrincipal; }; bool nsFrameLoader::DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) { TabParent* tabParent = mRemoteBrowser; if (tabParent) { @@ -2278,11 +2282,14 @@ nsFrameLoader::DoSendAsyncMessage(JSContext* aCx, if (aCpows && !cp->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { return false; } - return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows); + return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows, + aPrincipal); } if (mChildMessageManager) { - nsRefPtr ev = new nsAsyncMessageToChild(aCx, this, aMessage, aData, aCpows); + nsRefPtr ev = new nsAsyncMessageToChild(aCx, this, aMessage, + aData, aCpows, + aPrincipal); NS_DispatchToCurrentThread(ev); return true; } diff --git a/content/base/src/nsFrameLoader.h b/content/base/src/nsFrameLoader.h index 55623c683782..91e2dcc48611 100644 --- a/content/base/src/nsFrameLoader.h +++ b/content/base/src/nsFrameLoader.h @@ -184,7 +184,8 @@ public: virtual bool DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, - JS::Handle aCpows); + JS::Handle aCpows, + nsIPrincipal* aPrincipal) MOZ_OVERRIDE; virtual bool CheckPermission(const nsAString& aPermission) MOZ_OVERRIDE; virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE; virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE; diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index a989affc923c..e038283aa215 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -500,28 +500,33 @@ NS_IMETHODIMP nsFrameMessageManager::SendSyncMessage(const nsAString& aMessageName, const JS::Value& aJSON, const JS::Value& aObjects, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc, JS::Value* aRetval) { - return SendMessage(aMessageName, aJSON, aObjects, aCx, aArgc, aRetval, true); + return SendMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, aArgc, + aRetval, true); } NS_IMETHODIMP nsFrameMessageManager::SendRpcMessage(const nsAString& aMessageName, const JS::Value& aJSON, const JS::Value& aObjects, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc, JS::Value* aRetval) { - return SendMessage(aMessageName, aJSON, aObjects, aCx, aArgc, aRetval, false); + return SendMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, aArgc, + aRetval, false); } nsresult nsFrameMessageManager::SendMessage(const nsAString& aMessageName, const JS::Value& aJSON, const JS::Value& aObjects, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc, JS::Value* aRetval, @@ -556,7 +561,8 @@ nsFrameMessageManager::SendMessage(const nsAString& aMessageName, InfallibleTArray retval; sSendingSyncMessage |= aIsSync; - bool rv = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, objects, &retval, aIsSync); + bool rv = mCallback->DoSendBlockingMessage(aCx, aMessageName, data, objects, + aPrincipal, &retval, aIsSync); if (aIsSync) { sSendingSyncMessage = false; } @@ -591,19 +597,20 @@ nsresult nsFrameMessageManager::DispatchAsyncMessageInternal(JSContext* aCx, const nsAString& aMessage, const StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) { if (mIsBroadcaster) { int32_t len = mChildManagers.Count(); for (int32_t i = 0; i < len; ++i) { static_cast(mChildManagers[i])-> - DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows); + DispatchAsyncMessageInternal(aCx, aMessage, aData, aCpows, aPrincipal); } return NS_OK; } NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED); - if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows)) { + if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows, aPrincipal)) { return NS_ERROR_FAILURE; } return NS_OK; @@ -613,6 +620,7 @@ nsresult nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName, const JS::Value& aJSON, const JS::Value& aObjects, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc) { @@ -632,7 +640,8 @@ nsFrameMessageManager::DispatchAsyncMessage(const nsAString& aMessageName, data.mData = buffer.data(); data.mDataLength = buffer.nbytes(); - return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects); + return DispatchAsyncMessageInternal(aCx, aMessageName, data, objects, + aPrincipal); } @@ -642,10 +651,12 @@ NS_IMETHODIMP nsFrameMessageManager::SendAsyncMessage(const nsAString& aMessageName, const JS::Value& aJSON, const JS::Value& aObjects, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc) { - return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aCx, aArgc); + return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aPrincipal, aCx, + aArgc); } @@ -658,7 +669,8 @@ nsFrameMessageManager::BroadcastAsyncMessage(const nsAString& aMessageName, JSContext* aCx, uint8_t aArgc) { - return DispatchAsyncMessage(aMessageName, aJSON, aObjects, aCx, aArgc); + return DispatchAsyncMessage(aMessageName, aJSON, aObjects, nullptr, aCx, + aArgc); } NS_IMETHODIMP @@ -841,6 +853,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, bool aIsSync, const StructuredCloneData* aCloneData, CpowHolder* aCpows, + nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal) { AutoSafeJSContext ctx; @@ -926,6 +939,42 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, JS_DefineProperty(ctx, param, "data", json, nullptr, nullptr, JSPROP_ENUMERATE); JS_DefineProperty(ctx, param, "objects", cpowsv, nullptr, nullptr, JSPROP_ENUMERATE); + // message.principal == null + if (!aPrincipal) { + JS::Rooted nullValue(ctx); + JS_DefineProperty(ctx, param, "principal", nullValue, nullptr, nullptr, JSPROP_ENUMERATE); + } + + // message.principal = { appId: , origin: , isInBrowserElement: } + else { + JS::Rooted principalObj(ctx, + JS_NewObject(ctx, nullptr, nullptr, nullptr)); + + uint32_t appId; + nsresult rv = aPrincipal->GetAppId(&appId); + NS_ENSURE_SUCCESS(rv, rv); + + JS::Rooted appIdValue(ctx, INT_TO_JSVAL(appId)); + JS_DefineProperty(ctx, principalObj, "appId", appIdValue, nullptr, nullptr, JSPROP_ENUMERATE); + + nsCString origin; + rv = aPrincipal->GetOrigin(getter_Copies(origin)); + NS_ENSURE_SUCCESS(rv, rv); + + JS::Rooted originValue(ctx, JS_InternString(ctx, origin.get())); + JS_DefineProperty(ctx, principalObj, "origin", STRING_TO_JSVAL(originValue), nullptr, nullptr, JSPROP_ENUMERATE); + + bool browser; + rv = aPrincipal->GetIsInBrowserElement(&browser); + NS_ENSURE_SUCCESS(rv, rv); + + JS::Rooted browserValue(ctx, BOOLEAN_TO_JSVAL(browser)); + JS_DefineProperty(ctx, principalObj, "isInBrowserElement", browserValue, nullptr, nullptr, JSPROP_ENUMERATE); + + JS::RootedValue principalValue(ctx, JS::ObjectValue(*principalObj)); + JS_DefineProperty(ctx, param, "principal", principalValue, nullptr, nullptr, JSPROP_ENUMERATE); + } + JS::Rooted thisValue(ctx, JS::UndefinedValue()); JS::Rooted funval(ctx); @@ -981,7 +1030,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, nsRefPtr kungfuDeathGrip = mParentManager; return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage, aIsSync, aCloneData, - aCpows, + aCpows, aPrincipal, aJSONRetVal) : NS_OK; } @@ -1452,10 +1501,12 @@ public: nsAsyncMessageToSameProcessChild(JSContext* aCx, const nsAString& aMessage, const StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) : mRuntime(js::GetRuntime(aCx)), mMessage(aMessage), - mCpows(aCpows) + mCpows(aCpows), + mPrincipal(aPrincipal) { if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) { NS_RUNTIMEABORT("OOM"); @@ -1485,7 +1536,7 @@ public: nsRefPtr ppm = nsFrameMessageManager::sChildProcessManager; ppm->ReceiveMessage(static_cast(ppm.get()), mMessage, - false, &data, &cpows, nullptr); + false, &data, &cpows, mPrincipal, nullptr); } return NS_OK; } @@ -1494,6 +1545,7 @@ public: JSAutoStructuredCloneBuffer mData; StructuredCloneClosure mClosure; JSObject* mCpows; + nsCOMPtr mPrincipal; }; @@ -1515,10 +1567,12 @@ public: virtual bool DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) { nsRefPtr ev = - new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows); + new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows, + aPrincipal); NS_DispatchToCurrentThread(ev); return true; } @@ -1562,6 +1616,7 @@ public: const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, JS::Handle aCpows, + nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal, bool aIsSync) MOZ_OVERRIDE { @@ -1579,15 +1634,18 @@ public: return false; } if (aIsSync) { - return cc->SendSyncMessage(nsString(aMessage), data, cpows, aJSONRetVal); + return cc->SendSyncMessage(nsString(aMessage), data, cpows, aPrincipal, + aJSONRetVal); } - return cc->CallRpcMessage(nsString(aMessage), data, cpows, aJSONRetVal); + return cc->CallRpcMessage(nsString(aMessage), data, cpows, aPrincipal, + aJSONRetVal); } virtual bool DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, - JS::Handle aCpows) MOZ_OVERRIDE + JS::Handle aCpows, + nsIPrincipal* aPrincipal) MOZ_OVERRIDE { mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton(); @@ -1602,7 +1660,7 @@ public: if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { return false; } - return cc->SendAsyncMessage(nsString(aMessage), data, cpows); + return cc->SendAsyncMessage(nsString(aMessage), data, cpows, aPrincipal); } }; @@ -1614,10 +1672,12 @@ public: nsAsyncMessageToSameProcessParent(JSContext* aCx, const nsAString& aMessage, const StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) : mRuntime(js::GetRuntime(aCx)), mMessage(aMessage), - mCpows(aCpows) + mCpows(aCpows), + mPrincipal(aPrincipal) { if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) { NS_RUNTIMEABORT("OOM"); @@ -1651,7 +1711,7 @@ public: nsRefPtr ppm = nsFrameMessageManager::sSameProcessParentManager; ppm->ReceiveMessage(static_cast(ppm.get()), - mMessage, false, &data, &cpows, nullptr); + mMessage, false, &data, &cpows, mPrincipal, nullptr); } return NS_OK; } @@ -1660,6 +1720,7 @@ public: JSAutoStructuredCloneBuffer mData; StructuredCloneClosure mClosure; JSObject* mCpows; + nsCOMPtr mPrincipal; }; /** @@ -1681,6 +1742,7 @@ public: const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, JS::Handle aCpows, + nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal, bool aIsSync) MOZ_OVERRIDE { @@ -1697,7 +1759,7 @@ public: SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows); nsRefPtr ppm = nsFrameMessageManager::sSameProcessParentManager; ppm->ReceiveMessage(static_cast(ppm.get()), aMessage, - true, &aData, &cpows, aJSONRetVal); + true, &aData, &cpows, aPrincipal, aJSONRetVal); } return true; } @@ -1705,13 +1767,14 @@ public: virtual bool DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) { if (!nsFrameMessageManager::sPendingSameProcessAsyncMessages) { nsFrameMessageManager::sPendingSameProcessAsyncMessages = new nsTArray >; } nsCOMPtr ev = - new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows); + new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows, aPrincipal); nsFrameMessageManager::sPendingSameProcessAsyncMessages->AppendElement(ev); NS_DispatchToCurrentThread(ev); return true; diff --git a/content/base/src/nsFrameMessageManager.h b/content/base/src/nsFrameMessageManager.h index f3e710743c9f..b18dc838e18c 100644 --- a/content/base/src/nsFrameMessageManager.h +++ b/content/base/src/nsFrameMessageManager.h @@ -61,6 +61,7 @@ public: const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, JS::Handle aCpows, + nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal, bool aIsSync) { @@ -70,7 +71,8 @@ public: virtual bool DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) { return true; } @@ -218,7 +220,7 @@ public: nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage, bool aIsSync, const StructuredCloneData* aCloneData, - CpowHolder* aCpows, + CpowHolder* aCpows, nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal); void AddChildManager(nsFrameMessageManager* aManager, @@ -239,12 +241,14 @@ public: nsresult DispatchAsyncMessage(const nsAString& aMessageName, const JS::Value& aJSON, const JS::Value& aObjects, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc); nsresult DispatchAsyncMessageInternal(JSContext* aCx, const nsAString& aMessage, const StructuredCloneData& aData, - JS::Handle aCpows); + JS::Handle aCpows, + nsIPrincipal* aPrincipal); void RemoveFromParent(); nsFrameMessageManager* GetParentManager() { return mParentManager; } void SetParentManager(nsFrameMessageManager* aParent) @@ -268,6 +272,7 @@ private: nsresult SendMessage(const nsAString& aMessageName, const JS::Value& aJSON, const JS::Value& aObjects, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc, JS::Value* aRetval, diff --git a/content/base/src/nsInProcessTabChildGlobal.cpp b/content/base/src/nsInProcessTabChildGlobal.cpp index 051c739c481c..f6e89831f1c4 100644 --- a/content/base/src/nsInProcessTabChildGlobal.cpp +++ b/content/base/src/nsInProcessTabChildGlobal.cpp @@ -30,6 +30,7 @@ nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx, const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, JS::Handle aCpows, + nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal, bool aIsSync) { @@ -43,7 +44,8 @@ nsInProcessTabChildGlobal::DoSendBlockingMessage(JSContext* aCx, if (mChromeMessageManager) { SameProcessCpowHolder cpows(js::GetRuntime(aCx), aCpows); nsRefPtr mm = mChromeMessageManager; - mm->ReceiveMessage(mOwner, aMessage, true, &aData, &cpows, aJSONRetVal); + mm->ReceiveMessage(mOwner, aMessage, true, &aData, &cpows, aPrincipal, + aJSONRetVal); } return true; } @@ -55,11 +57,13 @@ public: nsInProcessTabChildGlobal* aTabChild, const nsAString& aMessage, const StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) : mRuntime(js::GetRuntime(aCx)), mTabChild(aTabChild), mMessage(aMessage), mCpows(aCpows), + mPrincipal(aPrincipal), mRun(false) { if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) { @@ -95,7 +99,8 @@ public: SameProcessCpowHolder cpows(mRuntime, JS::Handle::fromMarkedLocation(&mCpows)); nsRefPtr mm = mTabChild->mChromeMessageManager; - mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data, &cpows, nullptr); + mm->ReceiveMessage(mTabChild->mOwner, mMessage, false, &data, &cpows, + mPrincipal, nullptr); } return NS_OK; } @@ -105,6 +110,7 @@ public: JSAutoStructuredCloneBuffer mData; StructuredCloneClosure mClosure; JSObject* mCpows; + nsCOMPtr mPrincipal; // True if this runnable has already been called. This can happen if DoSendSyncMessage // is called while waiting for an asynchronous message send. bool mRun; @@ -114,10 +120,11 @@ bool nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) { nsCOMPtr ev = - new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows); + new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows, aPrincipal); mASyncMessages.AppendElement(ev); NS_DispatchToCurrentThread(ev); return true; diff --git a/content/base/src/nsInProcessTabChildGlobal.h b/content/base/src/nsInProcessTabChildGlobal.h index 07ace7d8c08d..fedfe89b66aa 100644 --- a/content/base/src/nsInProcessTabChildGlobal.h +++ b/content/base/src/nsInProcessTabChildGlobal.h @@ -43,23 +43,27 @@ public: NS_IMETHOD SendSyncMessage(const nsAString& aMessageName, const JS::Value& aObject, const JS::Value& aRemote, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc, JS::Value* aRetval) { return mMessageManager - ? mMessageManager->SendSyncMessage(aMessageName, aObject, aRemote, aCx, aArgc, aRetval) + ? mMessageManager->SendSyncMessage(aMessageName, aObject, aRemote, + aPrincipal, aCx, aArgc, aRetval) : NS_ERROR_NULL_POINTER; } NS_IMETHOD SendRpcMessage(const nsAString& aMessageName, const JS::Value& aObject, const JS::Value& aRemote, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc, JS::Value* aRetval) { return mMessageManager - ? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote, aCx, aArgc, aRetval) + ? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote, + aPrincipal, aCx, aArgc, aRetval) : NS_ERROR_NULL_POINTER; } NS_IMETHOD GetContent(nsIDOMWindow** aContent) MOZ_OVERRIDE; @@ -83,12 +87,14 @@ public: const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, JS::Handle aCpows, + nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal, bool aIsSync) MOZ_OVERRIDE; virtual bool DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, - JS::Handle aCpows); + JS::Handle aCpows, + nsIPrincipal* aPrincipal) MOZ_OVERRIDE; virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE; NS_IMETHOD AddEventListener(const nsAString& aType, diff --git a/content/base/test/chrome.ini b/content/base/test/chrome.ini index 0a1f2e864359..4432f014e9a7 100644 --- a/content/base/test/chrome.ini +++ b/content/base/test/chrome.ini @@ -2,3 +2,4 @@ [test_bug357450.js] [test_copypaste.xul] +[test_messagemanager_principal.html] diff --git a/content/base/test/test_messagemanager_principal.html b/content/base/test/test_messagemanager_principal.html new file mode 100644 index 000000000000..768c10d45150 --- /dev/null +++ b/content/base/test/test_messagemanager_principal.html @@ -0,0 +1,94 @@ + + + + Test for Principal in MessageManager + + + + + + + + diff --git a/content/html/content/src/HTMLOptionElement.cpp b/content/html/content/src/HTMLOptionElement.cpp index 1758667b06a0..f74dfde701e3 100644 --- a/content/html/content/src/HTMLOptionElement.cpp +++ b/content/html/content/src/HTMLOptionElement.cpp @@ -211,7 +211,8 @@ HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName, int32_t index = Index(); uint32_t mask = HTMLSelectElement::SET_DISABLED; - if (aValue) { + bool defaultSelected = aValue; + if (defaultSelected) { mask |= HTMLSelectElement::IS_SELECTED; } @@ -227,8 +228,10 @@ HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName, // Now reset our members; when we finish the attr set we'll end up with the // rigt selected state. mIsInSetDefaultSelected = inSetDefaultSelected; - mSelectedChanged = false; - // mIsSelected doesn't matter while mSelectedChanged is false + // mIsSelected has already been set by SetOptionsSelectedByIndex. + // Possibly more than once; make sure our mSelectedChanged state is + // set correctly. + mSelectedChanged = mIsSelected != defaultSelected; return NS_OK; } diff --git a/content/html/content/test/mochitest.ini b/content/html/content/test/mochitest.ini index 1c1263f7af1d..f4246a1ff634 100644 --- a/content/html/content/test/mochitest.ini +++ b/content/html/content/test/mochitest.ini @@ -402,6 +402,7 @@ support-files = [test_object_attributes_reflection.html] [test_object_plugin_nav.html] [test_ol_attributes_reflection.html] +[test_option_defaultSelected.html] [test_param_attributes_reflection.html] [test_q_attributes_reflection.html] [test_restore_from_parser_fragment.html] diff --git a/content/html/content/test/test_option_defaultSelected.html b/content/html/content/test/test_option_defaultSelected.html new file mode 100644 index 000000000000..f3994e784d59 --- /dev/null +++ b/content/html/content/test/test_option_defaultSelected.html @@ -0,0 +1,47 @@ + + + + + + Test for Bug 927796 + + + + +Mozilla Bug 927796 +

+ + +

+ +
+
+ + + diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 78a55c5da911..b6ad4c2b3a25 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -3651,6 +3651,14 @@ NS_IMETHODIMP nsWindowSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSFreeOp *fop, JSObject *obj) { + // Since this call is virtual, the exact rooting hazard static analysis is + // not able to determine that it happens during finalization and should be + // ignored. Moreover, the analysis cannot discover and validate the + // potential targets of the virtual call to OnFinalize below because of the + // indirection through nsCOMMPtr. Thus, we annotate the analysis here so + // that it does not report OnFinalize as GCing with |obj| on stack. + JS::AutoAssertNoGC nogc; + nsCOMPtr sgo(do_QueryWrappedNative(wrapper)); NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED); diff --git a/dom/ipc/AppProcessChecker.cpp b/dom/ipc/AppProcessChecker.cpp index 7b36470a822d..6dbf484697e0 100644 --- a/dom/ipc/AppProcessChecker.cpp +++ b/dom/ipc/AppProcessChecker.cpp @@ -25,7 +25,12 @@ using namespace mozilla::dom; using namespace mozilla::hal_sandbox; using namespace mozilla::services; #else +namespace mozilla { +namespace dom { class PContentParent; +} +} + class nsIPrincipal; #endif @@ -280,16 +285,16 @@ AssertAppProcess(mozilla::hal_sandbox::PHalParent* aActor, } bool -AssertAppPrincipal(PContentParent* aActor, +AssertAppPrincipal(mozilla::dom::PContentParent* aActor, nsIPrincipal* aPrincipal) { return true; } uint32_t -CheckPermission(PContentParent*, - nsIPrincipal*, - const char*) +CheckPermission(mozilla::dom::PContentParent* aActor, + nsIPrincipal* aPrincipal, + const char* aPermission) { return nsIPermissionManager::ALLOW_ACTION; } diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 26b54a6078a4..59f27358a8a2 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -72,6 +72,8 @@ #include "nsPermissionManager.h" #endif +#include "PermissionMessageUtils.h" + #if defined(MOZ_WIDGET_ANDROID) #include "APKOpen.h" #endif @@ -1172,14 +1174,15 @@ ContentChild::RecvNotifyVisited(const URIParams& aURI) bool ContentChild::RecvAsyncMessage(const nsString& aMsg, const ClonedMessageData& aData, - const InfallibleTArray& aCpows) + const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal) { nsRefPtr cpm = nsFrameMessageManager::sChildProcessManager; if (cpm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData); CpowIdHolder cpows(GetCPOWManager(), aCpows); cpm->ReceiveMessage(static_cast(cpm.get()), - aMsg, false, &cloneData, &cpows, nullptr); + aMsg, false, &cloneData, &cpows, aPrincipal, nullptr); } return true; } diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 71e703a02e71..7303b077f841 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -188,7 +188,8 @@ public: virtual bool RecvAsyncMessage(const nsString& aMsg, const ClonedMessageData& aData, - const InfallibleTArray& aCpows); + const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal); virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index c2a2366dd09f..02dd24914367 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1139,7 +1139,7 @@ ContentParent::ActorDestroy(ActorDestroyReason why) if (ppm) { ppm->ReceiveMessage(static_cast(ppm.get()), CHILD_PROCESS_SHUTDOWN_MESSAGE, false, - nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr); } nsCOMPtr kungFuDeathGrip(static_cast(this)); @@ -2865,14 +2865,21 @@ bool ContentParent::RecvSyncMessage(const nsString& aMsg, const ClonedMessageData& aData, const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal, InfallibleTArray* aRetvals) { + nsIPrincipal* principal = aPrincipal; + if (principal && !AssertAppPrincipal(this, principal)) { + return false; + } + nsRefPtr ppm = mMessageManager; if (ppm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); CpowIdHolder cpows(GetCPOWManager(), aCpows); + ppm->ReceiveMessage(static_cast(ppm.get()), - aMsg, true, &cloneData, &cpows, aRetvals); + aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals); } return true; } @@ -2881,14 +2888,20 @@ bool ContentParent::AnswerRpcMessage(const nsString& aMsg, const ClonedMessageData& aData, const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal, InfallibleTArray* aRetvals) { + nsIPrincipal* principal = aPrincipal; + if (principal && !AssertAppPrincipal(this, principal)) { + return false; + } + nsRefPtr ppm = mMessageManager; if (ppm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); CpowIdHolder cpows(GetCPOWManager(), aCpows); ppm->ReceiveMessage(static_cast(ppm.get()), - aMsg, true, &cloneData, &cpows, aRetvals); + aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals); } return true; } @@ -2896,14 +2909,20 @@ ContentParent::AnswerRpcMessage(const nsString& aMsg, bool ContentParent::RecvAsyncMessage(const nsString& aMsg, const ClonedMessageData& aData, - const InfallibleTArray& aCpows) + const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal) { + nsIPrincipal* principal = aPrincipal; + if (principal && !AssertAppPrincipal(this, principal)) { + return false; + } + nsRefPtr ppm = mMessageManager; if (ppm) { StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); CpowIdHolder cpows(GetCPOWManager(), aCpows); ppm->ReceiveMessage(static_cast(ppm.get()), - aMsg, false, &cloneData, &cpows, nullptr); + aMsg, false, &cloneData, &cpows, aPrincipal, nullptr); } return true; } @@ -3110,7 +3129,8 @@ bool ContentParent::DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) { ClonedMessageData data; if (!BuildClonedMessageDataForParent(this, aData, data)) { @@ -3120,7 +3140,7 @@ ContentParent::DoSendAsyncMessage(JSContext* aCx, if (!GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { return false; } - return SendAsyncMessage(nsString(aMessage), data, cpows); + return SendAsyncMessage(nsString(aMessage), data, cpows, aPrincipal); } bool diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index cb2ca2751c32..54ecbcdb910f 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -117,7 +117,8 @@ public: virtual bool DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, - JS::Handle aCpows) MOZ_OVERRIDE; + JS::Handle aCpows, + nsIPrincipal* aPrincipal) MOZ_OVERRIDE; virtual bool CheckPermission(const nsAString& aPermission) MOZ_OVERRIDE; virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE; virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE; @@ -420,14 +421,17 @@ private: virtual bool RecvSyncMessage(const nsString& aMsg, const ClonedMessageData& aData, const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal, InfallibleTArray* aRetvals); virtual bool AnswerRpcMessage(const nsString& aMsg, const ClonedMessageData& aData, const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal, InfallibleTArray* aRetvals); virtual bool RecvAsyncMessage(const nsString& aMsg, const ClonedMessageData& aData, - const InfallibleTArray& aCpows); + const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal); virtual bool RecvFilePathUpdateNotify(const nsString& aType, const nsString& aStorageName, diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index ea39cb6b26d0..8dcc684c630e 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -61,7 +61,8 @@ intr protocol PBrowser manages PIndexedDB; both: - AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows); + AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows, + Principal aPrincipal); parent: /** @@ -74,10 +75,12 @@ parent: intr CreateWindow() returns (PBrowser window); - sync SyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows) + sync SyncMessage(nsString aMessage, ClonedMessageData aData, + CpowEntry[] aCpows, Principal aPrincipal) returns (nsString[] retval); - rpc RpcMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows) + rpc RpcMessage(nsString aMessage, ClonedMessageData aData, + CpowEntry[] aCpows, Principal aPrincipal) returns (nsString[] retval); /** diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 59c9184ce967..445b14decf8c 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -375,10 +375,12 @@ parent: sync ReadFontList() returns (FontListEntry[] retValue); - sync SyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows) + sync SyncMessage(nsString aMessage, ClonedMessageData aData, + CpowEntry[] aCpows, Principal aPrincipal) returns (nsString[] retval); - rpc RpcMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows) + rpc RpcMessage(nsString aMessage, ClonedMessageData aData, + CpowEntry[] aCpows, Principal aPrincipal) returns (nsString[] retval); ShowAlertNotification(nsString imageUrl, @@ -469,7 +471,8 @@ parent: returns (OptionalInputStreamParams postData, OptionalURIParams uri); both: - AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows); + AsyncMessage(nsString aMessage, ClonedMessageData aData, + CpowEntry[] aCpows, Principal aPrincipal); }; } diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index f5fa0cbcd5fb..d4cb34d1a610 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -62,6 +62,7 @@ #include "nsPrintfCString.h" #include "nsThreadUtils.h" #include "nsWeakReference.h" +#include "PermissionMessageUtils.h" #include "PCOMContentPermissionRequestChild.h" #include "PuppetWidget.h" #include "StructuredCloneUtils.h" @@ -1506,7 +1507,7 @@ TabChild::DispatchMessageManagerMessage(const nsAString& aMessageName, nsRefPtr mm = static_cast(mTabChildGlobal->mMessageManager.get()); mm->ReceiveMessage(static_cast(mTabChildGlobal), - aMessageName, false, &cloneData, nullptr, nullptr); + aMessageName, false, &cloneData, nullptr, nullptr, nullptr); } bool @@ -2071,7 +2072,8 @@ TabChild::RecvLoadRemoteScript(const nsString& aURL) bool TabChild::RecvAsyncMessage(const nsString& aMessage, const ClonedMessageData& aData, - const InfallibleTArray& aCpows) + const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal) { if (mTabChildGlobal) { nsCOMPtr kungFuDeathGrip(GetGlobal()); @@ -2080,7 +2082,7 @@ TabChild::RecvAsyncMessage(const nsString& aMessage, static_cast(mTabChildGlobal->mMessageManager.get()); CpowIdHolder cpows(static_cast(Manager())->GetCPOWManager(), aCpows); mm->ReceiveMessage(static_cast(mTabChildGlobal), - aMessage, false, &cloneData, &cpows, nullptr); + aMessage, false, &cloneData, &cpows, aPrincipal, nullptr); } return true; } @@ -2404,6 +2406,7 @@ TabChild::DoSendBlockingMessage(JSContext* aCx, const nsAString& aMessage, const StructuredCloneData& aData, JS::Handle aCpows, + nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal, bool aIsSync) { @@ -2418,16 +2421,21 @@ TabChild::DoSendBlockingMessage(JSContext* aCx, return false; } } - if (aIsSync) - return SendSyncMessage(nsString(aMessage), data, cpows, aJSONRetVal); - return CallRpcMessage(nsString(aMessage), data, cpows, aJSONRetVal); + if (aIsSync) { + return SendSyncMessage(nsString(aMessage), data, cpows, aPrincipal, + aJSONRetVal); + } + + return CallRpcMessage(nsString(aMessage), data, cpows, aPrincipal, + aJSONRetVal); } bool TabChild::DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const StructuredCloneData& aData, - JS::Handle aCpows) + JS::Handle aCpows, + nsIPrincipal* aPrincipal) { ContentChild* cc = Manager(); ClonedMessageData data; @@ -2440,7 +2448,8 @@ TabChild::DoSendAsyncMessage(JSContext* aCx, return false; } } - return SendAsyncMessage(nsString(aMessage), data, cpows); + return SendAsyncMessage(nsString(aMessage), data, cpows, + aPrincipal); } TabChild* diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 095ec72784aa..0c7859409682 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -63,23 +63,27 @@ public: NS_IMETHOD SendSyncMessage(const nsAString& aMessageName, const JS::Value& aObject, const JS::Value& aRemote, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc, JS::Value* aRetval) { return mMessageManager - ? mMessageManager->SendSyncMessage(aMessageName, aObject, aRemote, aCx, aArgc, aRetval) + ? mMessageManager->SendSyncMessage(aMessageName, aObject, aRemote, + aPrincipal, aCx, aArgc, aRetval) : NS_ERROR_NULL_POINTER; } NS_IMETHOD SendRpcMessage(const nsAString& aMessageName, const JS::Value& aObject, const JS::Value& aRemote, + nsIPrincipal* aPrincipal, JSContext* aCx, uint8_t aArgc, JS::Value* aRetval) { return mMessageManager - ? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote, aCx, aArgc, aRetval) + ? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote, + aPrincipal, aCx, aArgc, aRetval) : NS_ERROR_NULL_POINTER; } NS_IMETHOD GetContent(nsIDOMWindow** aContent) MOZ_OVERRIDE; @@ -194,12 +198,14 @@ public: const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, JS::Handle aCpows, + nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal, bool aIsSync) MOZ_OVERRIDE; virtual bool DoSendAsyncMessage(JSContext* aCx, const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData, - JS::Handle aCpows) MOZ_OVERRIDE; + JS::Handle aCpows, + nsIPrincipal* aPrincipal) MOZ_OVERRIDE; virtual bool RecvLoadURL(const nsCString& uri); virtual bool RecvCacheFileDescriptor(const nsString& aPath, @@ -237,7 +243,8 @@ public: virtual bool RecvLoadRemoteScript(const nsString& aURL); virtual bool RecvAsyncMessage(const nsString& aMessage, const ClonedMessageData& aData, - const InfallibleTArray& aCpows); + const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal) MOZ_OVERRIDE; virtual PDocumentRendererChild* AllocPDocumentRendererChild(const nsRect& documentRect, const gfxMatrix& transform, diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 863445a92ddc..ec3ba977a8d2 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -8,6 +8,7 @@ #include "TabParent.h" +#include "AppProcessChecker.h" #include "IDBFactory.h" #include "IndexedDBParent.h" #include "mozIApplication.h" @@ -52,6 +53,7 @@ #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" #include "private/pprio.h" +#include "PermissionMessageUtils.h" #include "StructuredCloneUtils.h" #include "JavaScriptParent.h" #include "TabChild.h" @@ -299,7 +301,8 @@ TabParent::ActorDestroy(ActorDestroyReason why) if (frameLoader) { fmm = frameLoader->GetFrameMessageManager(); nsCOMPtr frameElement(mFrameElement); - ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr); + ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr, + nullptr); frameLoader->DestroyChild(); if (why == AbnormalShutdown && os) { @@ -765,32 +768,53 @@ bool TabParent::RecvSyncMessage(const nsString& aMessage, const ClonedMessageData& aData, const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal, InfallibleTArray* aJSONRetVal) { + nsIPrincipal* principal = aPrincipal; + ContentParent* parent = static_cast(Manager()); + if (principal && !AssertAppPrincipal(parent, principal)) { + return false; + } + StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); - CpowIdHolder cpows(static_cast(Manager())->GetCPOWManager(), aCpows); - return ReceiveMessage(aMessage, true, &cloneData, &cpows, aJSONRetVal); + CpowIdHolder cpows(parent->GetCPOWManager(), aCpows); + return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal); } bool TabParent::AnswerRpcMessage(const nsString& aMessage, const ClonedMessageData& aData, const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal, InfallibleTArray* aJSONRetVal) { + nsIPrincipal* principal = aPrincipal; + ContentParent* parent = static_cast(Manager()); + if (principal && !AssertAppPrincipal(parent, principal)) { + return false; + } + StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); - CpowIdHolder cpows(static_cast(Manager())->GetCPOWManager(), aCpows); - return ReceiveMessage(aMessage, true, &cloneData, &cpows, aJSONRetVal); + CpowIdHolder cpows(parent->GetCPOWManager(), aCpows); + return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal); } bool TabParent::RecvAsyncMessage(const nsString& aMessage, const ClonedMessageData& aData, - const InfallibleTArray& aCpows) + const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal) { + nsIPrincipal* principal = aPrincipal; + ContentParent* parent = static_cast(Manager()); + if (principal && !AssertAppPrincipal(parent, principal)) { + return false; + } + StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); - CpowIdHolder cpows(static_cast(Manager())->GetCPOWManager(), aCpows); - return ReceiveMessage(aMessage, false, &cloneData, &cpows, nullptr); + CpowIdHolder cpows(parent->GetCPOWManager(), aCpows); + return ReceiveMessage(aMessage, false, &cloneData, &cpows, aPrincipal, nullptr); } bool @@ -1214,6 +1238,7 @@ TabParent::ReceiveMessage(const nsString& aMessage, bool aSync, const StructuredCloneData* aCloneData, CpowHolder* aCpows, + nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal) { nsRefPtr frameLoader = GetFrameLoader(); @@ -1226,6 +1251,7 @@ TabParent::ReceiveMessage(const nsString& aMessage, aSync, aCloneData, aCpows, + aPrincipal, aJSONRetVal); } return true; diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index bfbc9644ebc8..a7c565cbc2b9 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -23,6 +23,7 @@ struct gfxMatrix; class nsFrameLoader; class nsIContent; +class nsIPrincipal; class nsIURI; class nsIWidget; class CpowHolder; @@ -121,14 +122,17 @@ public: virtual bool RecvSyncMessage(const nsString& aMessage, const ClonedMessageData& aData, const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal, InfallibleTArray* aJSONRetVal); virtual bool AnswerRpcMessage(const nsString& aMessage, const ClonedMessageData& aData, const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal, InfallibleTArray* aJSONRetVal); virtual bool RecvAsyncMessage(const nsString& aMessage, const ClonedMessageData& aData, - const InfallibleTArray& aCpows); + const InfallibleTArray& aCpows, + const IPC::Principal& aPrincipal); virtual bool RecvNotifyIMEFocus(const bool& aFocus, nsIMEUpdatePreference* aPreference, uint32_t* aSeqno); @@ -254,6 +258,7 @@ protected: bool aSync, const StructuredCloneData* aCloneData, CpowHolder* aCpows, + nsIPrincipal* aPrincipal, InfallibleTArray* aJSONRetVal = nullptr); virtual bool Recv__delete__() MOZ_OVERRIDE; diff --git a/embedding/browser/webBrowser/nsWebBrowser.cpp b/embedding/browser/webBrowser/nsWebBrowser.cpp index b61ad5d72741..3b3744e82575 100644 --- a/embedding/browser/webBrowser/nsWebBrowser.cpp +++ b/embedding/browser/webBrowser/nsWebBrowser.cpp @@ -1662,6 +1662,7 @@ NS_IMETHODIMP nsWebBrowser::EnsureDocShellTreeOwner() static void DrawThebesLayer(ThebesLayer* aLayer, gfxContext* aContext, const nsIntRegion& aRegionToDraw, + DrawRegionClip aClip, const nsIntRegion& aRegionToInvalidate, void* aCallbackData) { diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 924cd1400de2..87be868fe94e 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -265,6 +265,7 @@ public: typedef void (* DrawThebesLayerCallback)(ThebesLayer* aLayer, gfxContext* aContext, const nsIntRegion& aRegionToDraw, + DrawRegionClip aClip, const nsIntRegion& aRegionToInvalidate, void* aCallbackData); diff --git a/gfx/layers/LayersTypes.h b/gfx/layers/LayersTypes.h index a3b20e72b5c2..3721389de1e2 100644 --- a/gfx/layers/LayersTypes.h +++ b/gfx/layers/LayersTypes.h @@ -58,6 +58,12 @@ enum BufferMode { BUFFER_BUFFERED }; +enum DrawRegionClip { + CLIP_DRAW, + CLIP_DRAW_SNAPPED, + CLIP_NONE, +}; + // LayerRenderState for Composer2D // We currently only support Composer2D using gralloc. If we want to be backed // by other surfaces we will need a more generic LayerRenderState. diff --git a/gfx/layers/ThebesLayerBuffer.cpp b/gfx/layers/ThebesLayerBuffer.cpp index e0b4cb0516ad..6af984379586 100644 --- a/gfx/layers/ThebesLayerBuffer.cpp +++ b/gfx/layers/ThebesLayerBuffer.cpp @@ -856,6 +856,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType, nsIntPoint topLeft; result.mContext = GetContextForQuadrantUpdate(drawBounds, BUFFER_BOTH, &topLeft); + result.mClip = CLIP_DRAW_SNAPPED; if (mode == Layer::SURFACE_COMPONENT_ALPHA) { if (IsAzureBuffer()) { @@ -873,7 +874,6 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType, FillSurface(mBuffer, result.mRegionToDraw, topLeft, gfxRGBA(0.0, 0.0, 0.0, 1.0)); FillSurface(mBufferOnWhite, result.mRegionToDraw, topLeft, gfxRGBA(1.0, 1.0, 1.0, 1.0)); } - gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw); } else if (contentType == GFX_CONTENT_COLOR_ALPHA && !isClear) { if (IsAzureBuffer()) { nsIntRegionRectIterator iter(result.mRegionToDraw); @@ -883,16 +883,14 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType, } // Clear will do something expensive with a complex clip pushed, so clip // here. - gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw); } else { MOZ_ASSERT(result.mContext->IsCairo()); + result.mContext->Save(); gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw); result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR); result.mContext->Paint(); - result.mContext->SetOperator(gfxContext::OPERATOR_OVER); + result.mContext->Restore(); } - } else { - gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw); } return result; diff --git a/gfx/layers/ThebesLayerBuffer.h b/gfx/layers/ThebesLayerBuffer.h index 819eab4452c9..1df643c65e4e 100644 --- a/gfx/layers/ThebesLayerBuffer.h +++ b/gfx/layers/ThebesLayerBuffer.h @@ -21,6 +21,7 @@ #include "nsRect.h" // for nsIntRect #include "nsRegion.h" // for nsIntRegion #include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc +#include "LayersTypes.h" struct gfxMatrix; struct nsIntSize; @@ -218,6 +219,7 @@ public: nsIntRegion mRegionToDraw; nsIntRegion mRegionToInvalidate; bool mDidSelfCopy; + DrawRegionClip mClip; }; enum { diff --git a/gfx/layers/basic/BasicCompositor.cpp b/gfx/layers/basic/BasicCompositor.cpp index 2200776506df..a263b055377b 100644 --- a/gfx/layers/basic/BasicCompositor.cpp +++ b/gfx/layers/basic/BasicCompositor.cpp @@ -115,10 +115,10 @@ protected: { EnsureSurface(); if (!mSurface) { - mSurface = mCompositor->GetDrawTarget()->CreateSourceSurfaceFromData(mThebesImage->Data(), - mSize, - mThebesImage->Stride(), - mFormat); + mSurface = Factory::CreateWrappingDataSourceSurface(mThebesImage->Data(), + mThebesImage->Stride(), + mSize, + mFormat); } return true; } diff --git a/gfx/layers/basic/BasicThebesLayer.cpp b/gfx/layers/basic/BasicThebesLayer.cpp index dd7d146f4394..a739debebfc6 100644 --- a/gfx/layers/basic/BasicThebesLayer.cpp +++ b/gfx/layers/basic/BasicThebesLayer.cpp @@ -131,7 +131,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, groupContext = aContext; } SetAntialiasingFlags(this, groupContext); - aCallback(this, groupContext, toDraw, nsIntRegion(), aCallbackData); + aCallback(this, groupContext, toDraw, CLIP_NONE, nsIntRegion(), aCallbackData); if (needsGroup) { BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext); if (needsClipToVisibleRegion) { @@ -236,6 +236,7 @@ BasicThebesLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback, PaintBuffer(state.mContext, state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate, state.mDidSelfCopy, + state.mClip, aCallback, aCallbackData); MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this)); Mutated(); diff --git a/gfx/layers/basic/BasicThebesLayer.h b/gfx/layers/basic/BasicThebesLayer.h index af9220dc0fbe..6c0ecc97603b 100644 --- a/gfx/layers/basic/BasicThebesLayer.h +++ b/gfx/layers/basic/BasicThebesLayer.h @@ -103,6 +103,7 @@ protected: const nsIntRegion& aExtendedRegionToDraw, const nsIntRegion& aRegionToInvalidate, bool aDidSelfCopy, + DrawRegionClip aClip, LayerManager::DrawThebesLayerCallback aCallback, void* aCallbackData) { @@ -110,8 +111,8 @@ protected: BasicManager()->SetTransactionIncomplete(); return; } - aCallback(this, aContext, aExtendedRegionToDraw, aRegionToInvalidate, - aCallbackData); + aCallback(this, aContext, aExtendedRegionToDraw, aClip, + aRegionToInvalidate, aCallbackData); // Everything that's visible has been validated. Do this instead of just // OR-ing with aRegionToDraw, since that can lead to a very complex region // here (OR doesn't automatically simplify to the simplest possible diff --git a/gfx/layers/client/ClientThebesLayer.cpp b/gfx/layers/client/ClientThebesLayer.cpp index 51a15ba7ef0f..95d4496827ea 100644 --- a/gfx/layers/client/ClientThebesLayer.cpp +++ b/gfx/layers/client/ClientThebesLayer.cpp @@ -106,7 +106,7 @@ ClientThebesLayer::PaintThebes() PaintBuffer(state.mContext, state.mRegionToDraw, extendedDrawRegion, state.mRegionToInvalidate, - state.mDidSelfCopy); + state.mDidSelfCopy, state.mClip); MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this)); Mutated(); } else { @@ -146,7 +146,7 @@ ClientThebesLayer::PaintBuffer(gfxContext* aContext, const nsIntRegion& aRegionToDraw, const nsIntRegion& aExtendedRegionToDraw, const nsIntRegion& aRegionToInvalidate, - bool aDidSelfCopy) + bool aDidSelfCopy, DrawRegionClip aClip) { ContentClientRemote* contentClientRemote = static_cast(mContentClient.get()); MOZ_ASSERT(contentClientRemote->GetIPDLActor()); @@ -161,7 +161,8 @@ ClientThebesLayer::PaintBuffer(gfxContext* aContext, } ClientManager()->GetThebesLayerCallback()(this, aContext, - aExtendedRegionToDraw, + aExtendedRegionToDraw, + aClip, aRegionToInvalidate, ClientManager()->GetThebesLayerCallbackData()); diff --git a/gfx/layers/client/ClientThebesLayer.h b/gfx/layers/client/ClientThebesLayer.h index 6f1eae7da1aa..42fbfe49dcd8 100644 --- a/gfx/layers/client/ClientThebesLayer.h +++ b/gfx/layers/client/ClientThebesLayer.h @@ -105,7 +105,8 @@ protected: const nsIntRegion& aRegionToDraw, const nsIntRegion& aExtendedRegionToDraw, const nsIntRegion& aRegionToInvalidate, - bool aDidSelfCopy); + bool aDidSelfCopy, + DrawRegionClip aClip); void PaintThebes(); diff --git a/gfx/layers/client/ClientTiledThebesLayer.h b/gfx/layers/client/ClientTiledThebesLayer.h index c01967653492..01c262e06abf 100644 --- a/gfx/layers/client/ClientTiledThebesLayer.h +++ b/gfx/layers/client/ClientTiledThebesLayer.h @@ -69,18 +69,6 @@ private: return static_cast(mManager); } - // BasicImplData - virtual void - PaintBuffer(gfxContext* aContext, - const nsIntRegion& aRegionToDraw, - const nsIntRegion& aExtendedRegionToDraw, - const nsIntRegion& aRegionToInvalidate, - bool aDidSelfCopy, - LayerManager::DrawThebesLayerCallback aCallback, - void* aCallbackData) - { NS_RUNTIMEABORT("Not reached."); } - - /** * For the initial PaintThebes of a transaction, calculates all the data * needed for that paint and any repeated transactions. diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 5ecf1568ebed..ad23e2fcac63 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -894,12 +894,14 @@ ContentClientIncremental::BeginPaintBuffer(ThebesLayer* aLayer, // although they never cover it. This leads to two draw rects, the narow strip and the actually // newly exposed area. It would be wise to fix this glitch in any way to have simpler // clip and draw regions. - gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw); + result.mClip = CLIP_DRAW; if (mContentType == GFX_CONTENT_COLOR_ALPHA) { + result.mContext->Save(); + gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw); result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR); result.mContext->Paint(); - result.mContext->SetOperator(gfxContext::OPERATOR_OVER); + result.mContext->Restore(); } return result; diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index 5f98aa4ce5a1..cdf98d15385d 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -274,7 +274,7 @@ BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, #endif PROFILER_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferDraw"); - mCallback(mThebesLayer, ctxt, aPaintRegion, nsIntRegion(), mCallbackData); + mCallback(mThebesLayer, ctxt, aPaintRegion, CLIP_NONE, nsIntRegion(), mCallbackData); } #ifdef GFX_TILEDLAYER_PREF_WARNINGS @@ -383,6 +383,7 @@ BasicTiledLayerBuffer::ValidateTileInternal(BasicTiledLayerTile aTile, mCallback(mThebesLayer, ctxt, nsIntRegion(nsIntRect(a, nsIntSize(GetScaledTileLength(), GetScaledTileLength()))), + CLIP_NONE, nsIntRegion(), mCallbackData); } diff --git a/gfx/layers/composite/APZCTreeManager.cpp b/gfx/layers/composite/APZCTreeManager.cpp index a9aaec77a0ab..4f191cbeb131 100644 --- a/gfx/layers/composite/APZCTreeManager.cpp +++ b/gfx/layers/composite/APZCTreeManager.cpp @@ -392,7 +392,6 @@ APZCTreeManager::ProcessEvent(const WidgetInputEvent& aEvent, gfx3DMatrix transformToApzc; gfx3DMatrix transformToGecko; GetInputTransforms(apzc, transformToApzc, transformToGecko); - ApplyTransform(&(aOutEvent->refPoint), transformToApzc); gfx3DMatrix outTransform = transformToApzc * transformToGecko; ApplyTransform(&(aOutEvent->refPoint), outTransform); return nsEventStatus_eIgnore; diff --git a/gfx/layers/composite/LayerManagerComposite.h b/gfx/layers/composite/LayerManagerComposite.h index fa32b5ac35df..476a4a1afde0 100644 --- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -158,20 +158,6 @@ public: void* GetThebesLayerCallbackData() const { return mThebesLayerCallbackData; } - /* - * Helper functions for our layers - */ - void CallThebesLayerDrawCallback(ThebesLayer* aLayer, - gfxContext* aContext, - const nsIntRegion& aRegionToDraw) - { - NS_ASSERTION(mThebesLayerCallback, - "CallThebesLayerDrawCallback without callback!"); - mThebesLayerCallback(aLayer, aContext, - aRegionToDraw, nsIntRegion(), - mThebesLayerCallbackData); - } - #ifdef MOZ_LAYERS_HAVE_LOG virtual const char* Name() const MOZ_OVERRIDE { return ""; } #endif // MOZ_LAYERS_HAVE_LOG diff --git a/gfx/layers/d3d10/ThebesLayerD3D10.cpp b/gfx/layers/d3d10/ThebesLayerD3D10.cpp index a0d12f4899c0..f6239932fc58 100644 --- a/gfx/layers/d3d10/ThebesLayerD3D10.cpp +++ b/gfx/layers/d3d10/ThebesLayerD3D10.cpp @@ -414,40 +414,22 @@ ThebesLayerD3D10::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode) destinationSurface = mD2DSurface; } - nsRefPtr context; + MOZ_ASSERT(mDrawTarget); + nsRefPtr context = new gfxContext(mDrawTarget); - if (mDrawTarget) { - context = new gfxContext(mDrawTarget); - } else { - context = new gfxContext(destinationSurface); - } - - nsIntRegionRectIterator iter(aRegion); context->Translate(gfxPoint(-visibleRect.x, -visibleRect.y)); - context->NewPath(); - const nsIntRect *iterRect; - while ((iterRect = iter.Next())) { - context->Rectangle(gfxRect(iterRect->x, iterRect->y, iterRect->width, iterRect->height)); - if (mDrawTarget && aMode == SURFACE_SINGLE_CHANNEL_ALPHA) { + if (aMode == SURFACE_SINGLE_CHANNEL_ALPHA) { + nsIntRegionRectIterator iter(aRegion); + const nsIntRect *iterRect; + while ((iterRect = iter.Next())) { mDrawTarget->ClearRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height)); } } - context->Clip(); - if (!mDrawTarget && aMode == SURFACE_SINGLE_CHANNEL_ALPHA) { - context->SetOperator(gfxContext::OPERATOR_CLEAR); - context->Paint(); - context->SetOperator(gfxContext::OPERATOR_OVER); - } - - if (mD2DSurface) { - mD2DSurface->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA)); - } else if (mDrawTarget) { - mDrawTarget->SetPermitSubpixelAA(!(mContentFlags & CONTENT_COMPONENT_ALPHA)); - } + mDrawTarget->SetPermitSubpixelAA(!(mContentFlags & CONTENT_COMPONENT_ALPHA)); LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); - cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData); + cbInfo.Callback(this, context, aRegion, CLIP_DRAW, nsIntRegion(), cbInfo.CallbackData); } void diff --git a/gfx/layers/d3d9/ThebesLayerD3D9.cpp b/gfx/layers/d3d9/ThebesLayerD3D9.cpp index 7fa002cdf2e6..8543fa8f969d 100644 --- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp +++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp @@ -493,7 +493,7 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode, context->Translate(gfxPoint(-bounds.x, -bounds.y)); LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); - cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData); + cbInfo.Callback(this, context, aRegion, CLIP_NONE, nsIntRegion(), cbInfo.CallbackData); for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) { NS_ASSERTION(aMode == SURFACE_OPAQUE, diff --git a/gfx/layers/opengl/LayerManagerOGL.h b/gfx/layers/opengl/LayerManagerOGL.h index bfa22e2fafb2..e0dde9d06493 100644 --- a/gfx/layers/opengl/LayerManagerOGL.h +++ b/gfx/layers/opengl/LayerManagerOGL.h @@ -200,21 +200,6 @@ public: void* GetThebesLayerCallbackData() const { return mThebesLayerCallbackData; } - /* - * Helper functions for our layers - */ - void CallThebesLayerDrawCallback(ThebesLayer* aLayer, - gfxContext* aContext, - const nsIntRegion& aRegionToDraw) - { - NS_ASSERTION(mThebesLayerCallback, - "CallThebesLayerDrawCallback without callback!"); - mThebesLayerCallback(aLayer, aContext, - aRegionToDraw, nsIntRegion(), - mThebesLayerCallbackData); - } - - GLenum FBOTextureTarget() { return mFBOTextureTarget; } /** diff --git a/gfx/layers/opengl/ThebesLayerOGL.cpp b/gfx/layers/opengl/ThebesLayerOGL.cpp index 6293314ab5d4..85fb106af71c 100644 --- a/gfx/layers/opengl/ThebesLayerOGL.cpp +++ b/gfx/layers/opengl/ThebesLayerOGL.cpp @@ -828,12 +828,14 @@ BasicBufferOGL::BeginPaint(ContentType aContentType, // although they never cover it. This leads to two draw rects, the narow strip and the actually // newly exposed area. It would be wise to fix this glitch in any way to have simpler // clip and draw regions. - gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw); + result.mClip = CLIP_DRAW; if (mTexImage->GetContentType() == GFX_CONTENT_COLOR_ALPHA) { + result.mContext->Save(); + gfxUtils::ClipToRegion(result.mContext, result.mRegionToDraw); result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR); result.mContext->Paint(); - result.mContext->SetOperator(gfxContext::OPERATOR_OVER); + result.mContext->Restore(); } return result; @@ -931,7 +933,7 @@ ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, } else { void* callbackData = mOGLManager->GetThebesLayerCallbackData(); SetAntialiasingFlags(this, state.mContext); - callback(this, state.mContext, state.mRegionToDraw, + callback(this, state.mContext, state.mRegionToDraw, state.mClip, state.mRegionToInvalidate, callbackData); // Everything that's visible has been validated. Do this instead of just // OR-ing with aRegionToDraw, since that can lead to a very complex region diff --git a/js/public/GCAPI.h b/js/public/GCAPI.h index a156ea1d4d16..8102d7f7e337 100644 --- a/js/public/GCAPI.h +++ b/js/public/GCAPI.h @@ -213,13 +213,18 @@ WasIncrementalGC(JSRuntime *rt); extern JS_FRIEND_API(size_t) GetGCNumber(); -class AutoAssertNoGC { +class JS_PUBLIC_API(AutoAssertNoGC) +{ #ifdef DEBUG size_t gcNumber; public: AutoAssertNoGC(); ~AutoAssertNoGC(); +#else + public: + /* Prevent unreferenced local warnings in opt builds. */ + AutoAssertNoGC() {} #endif }; @@ -311,6 +316,31 @@ ExposeObjectToActiveJS(JSObject *obj) ExposeGCThingToActiveJS(obj, JSTRACE_OBJECT); } +/* + * If a GC is currently marking, mark the object black. + */ +static JS_ALWAYS_INLINE void +MarkGCThingAsLive(JSRuntime *rt_, void *thing, JSGCTraceKind kind) +{ + shadow::Runtime *rt = shadow::Runtime::asShadowRuntime(rt_); +#ifdef JSGC_GENERATIONAL + /* + * Any object in the nursery will not be freed during any GC running at that time. + */ + if (js::gc::IsInsideNursery(rt, thing)) + return; +#endif + if (IsIncrementalBarrierNeededOnGCThing(rt, thing, kind)) + IncrementalReferenceBarrier(thing, kind); +} + +static JS_ALWAYS_INLINE void +MarkStringAsLive(Zone *zone, JSString *string) +{ + JSRuntime *rt = JS::shadow::Zone::asShadowZone(zone)->runtimeFromMainThread(); + MarkGCThingAsLive(rt, string, JSTRACE_STRING); +} + } /* namespace JS */ #endif /* js_GCAPI_h */ diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index d58b2e971bf1..583de578c5fb 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -1249,6 +1249,8 @@ js_InitTypedObjectClass(JSContext *cx, HandleObject obj) RootedObject module(cx, NewObjectWithClassProto(cx, &JSObject::class_, objProto, global)); + if (!module) + return nullptr; // Define TypedObject global. diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index e5784a7e4d02..a078a94b681a 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -38,6 +38,7 @@ #include "frontend/ParseMaps-inl.h" #include "frontend/ParseNode-inl.h" +#include "vm/ScopeObject-inl.h" using namespace js; using namespace js::gc; @@ -1165,9 +1166,9 @@ TryConvertFreeName(BytecodeEmitter *bce, ParseNode *pn) if (bce->script->directlyInsideEval) return false; RootedObject outerScope(bce->sc->context, bce->script->enclosingStaticScope()); - for (StaticScopeIter ssi(bce->sc->context, outerScope); !ssi.done(); ssi++) { - if (ssi.type() != StaticScopeIter::FUNCTION) { - if (ssi.type() == StaticScopeIter::BLOCK) { + for (StaticScopeIter ssi(bce->sc->context, outerScope); !ssi.done(); ssi++) { + if (ssi.type() != StaticScopeIter::FUNCTION) { + if (ssi.type() == StaticScopeIter::BLOCK) { // Use generic ops if a catch block is encountered. return false; } @@ -6446,6 +6447,11 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) : EmitVariables(cx, bce, pn, InitializeVars); break; + case PNK_IMPORT: + // TODO: Implement emitter support for modules + bce->reportError(nullptr, JSMSG_MODULES_NOT_IMPLEMENTED); + return false; + case PNK_ARRAYPUSH: { int slot; diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 7bde5f46eca9..b638d76daeff 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -295,6 +295,16 @@ class FullParseHandler return new_(PNK_SEMI, JSOP_NOP, pos, (ParseNode *) nullptr); } + ParseNode *newImportDeclaration(ParseNode *importSpecSet, + ParseNode *moduleSpec, const TokenPos &pos) + { + ParseNode *pn = new_(PNK_IMPORT, JSOP_NOP, pos, + importSpecSet, moduleSpec); + if (!pn) + return null(); + return pn; + } + ParseNode *newExprStatement(ParseNode *expr, uint32_t end) { JS_ASSERT(expr->pn_pos.end <= end); return new_(PNK_SEMI, JSOP_NOP, TokenPos(expr->pn_pos.begin, end), expr); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index bb981cb8cbaf..4b8cb1bf7943 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -128,6 +128,9 @@ class UpvarCookie F(ARRAYPUSH) \ F(LEXICALSCOPE) \ F(LET) \ + F(IMPORT) \ + F(IMPORT_SPEC_LIST) \ + F(IMPORT_SPEC) \ F(SEQ) \ F(FORIN) \ F(FOROF) \ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 0cb25dbac7e3..d191d17b8ffe 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -3628,6 +3628,134 @@ Parser::letStatement() return SyntaxParseHandler::NodeFailure; } +template +typename ParseHandler::Node +Parser::importDeclaration() +{ + JS_ASSERT(tokenStream.currentToken().type == TOK_IMPORT); + + if (pc->sc->isFunctionBox() || !pc->atBodyLevel()) { + report(ParseError, false, null(), JSMSG_IMPORT_DECL_AT_TOP_LEVEL); + return null(); + } + + uint32_t begin = pos().begin; + TokenKind tt = tokenStream.getToken(); + + Node importSpecSet = handler.newList(PNK_IMPORT_SPEC_LIST); + if (!importSpecSet) + return null(); + + if (tt == TOK_NAME || tt == TOK_LC) { + if (tt == TOK_NAME) { + // Handle the form |import a from 'b'|, by adding a single import + // specifier to the list, with 'default' as the import name and + // 'a' as the binding name. This is equivalent to + // |import { default as a } from 'b'|. + Node importName = newName(context->names().default_); + if (!importName) + return null(); + + Node bindingName = newName(tokenStream.currentName()); + if (!bindingName) + return null(); + + Node importSpec = handler.newBinary(PNK_IMPORT_SPEC, importName, bindingName); + if (!importSpec) + return null(); + + handler.addList(importSpecSet, importSpec); + } else { + do { + // Handle the forms |import {} from 'a'| and + // |import { ..., } from 'a'| (where ... is non empty), by + // escaping the loop early if the next token is }. + tt = tokenStream.peekToken(TokenStream::KeywordIsName); + if (tt == TOK_ERROR) + return null(); + if (tt == TOK_RC) + break; + + // If the next token is a keyword, the previous call to + // peekToken matched it as a TOK_NAME, and put it in the + // lookahead buffer, so this call will match keywords as well. + MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME); + Node importName = newName(tokenStream.currentName()); + if (!importName) + return null(); + + if (tokenStream.getToken() == TOK_NAME && + tokenStream.currentName() == context->names().as) + { + if (tokenStream.getToken() != TOK_NAME) { + report(ParseError, false, null(), JSMSG_NO_BINDING_NAME); + return null(); + } + } else { + // Keywords cannot be bound to themselves, so an import name + // that is a keyword is a syntax error if it is not followed + // by the keyword 'as'. + if (IsKeyword(importName->name())) { + JSAutoByteString bytes; + if (!AtomToPrintableString(context, importName->name(), &bytes)) + return null(); + report(ParseError, false, null(), JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + return null(); + } + tokenStream.ungetToken(); + } + Node bindingName = newName(tokenStream.currentName()); + if (!bindingName) + return null(); + + Node importSpec = handler.newBinary(PNK_IMPORT_SPEC, importName, bindingName); + if (!importSpec) + return null(); + + handler.addList(importSpecSet, importSpec); + } while (tokenStream.matchToken(TOK_COMMA)); + + MUST_MATCH_TOKEN(TOK_RC, JSMSG_RC_AFTER_IMPORT_SPEC_LIST); + } + + if (tokenStream.getToken() != TOK_NAME || + tokenStream.currentName() != context->names().from) + { + report(ParseError, false, null(), JSMSG_FROM_AFTER_IMPORT_SPEC_SET); + return null(); + } + + MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); + } else { + if (tt != TOK_STRING) { + report(ParseError, false, null(), JSMSG_DECLARATION_AFTER_IMPORT); + return null(); + } + + // Handle the form |import 'a'| by leaving the list empty. This is + // equivalent to |import {} from 'a'|. + importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; + } + + Node moduleSpec = stringLiteral(); + if (!moduleSpec) + return null(); + + if (!MatchOrInsertSemicolon(tokenStream)) + return null(); + + return handler.newImportDeclaration(importSpecSet, moduleSpec, + TokenPos(begin, pos().end)); +} + +template<> +SyntaxParseHandler::Node +Parser::importDeclaration() +{ + JS_ALWAYS_FALSE(abortIfSyntaxParser()); + return SyntaxParseHandler::NodeFailure; +} + template typename ParseHandler::Node Parser::expressionStatement() @@ -4907,6 +5035,8 @@ Parser::statement(bool canHaveDirectives) case TOK_LET: return letStatement(); + case TOK_IMPORT: + return importDeclaration(); case TOK_SEMI: return handler.newEmptyStatement(pos()); case TOK_IF: diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 2de501307e5b..119a6892d434 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -512,6 +512,7 @@ class Parser : private AutoGCRooter, public StrictModeGetter Node debuggerStatement(); Node letStatement(); + Node importDeclaration(); Node expressionStatement(); Node variables(ParseNodeKind kind, bool *psimple = nullptr, StaticBlockObject *blockObj = nullptr, diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp index 97e30db09c73..4c9159809f01 100644 --- a/js/src/gc/Memory.cpp +++ b/js/src/gc/Memory.cpp @@ -297,7 +297,7 @@ gc::GetPageFaultCount() return 0; } -#elif defined(XP_UNIX) || defined(XP_MACOSX) || defined(DARWIN) +#elif defined(XP_UNIX) #include #include diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 9e8551b7162d..72d648529114 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -39,6 +39,7 @@ JS::Zone::Zone(JSRuntime *rt) maybeAlive(true), gcMallocBytes(0), gcGrayRoots(), + data(nullptr), types(this) { /* Ensure that there are no vtables to mess us up here. */ diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 2f641ea4de60..c11c73f956d5 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -255,6 +255,9 @@ struct Zone : public JS::shadow::Zone, /* This compartment's gray roots. */ js::Vector gcGrayRoots; + /* Per-zone data for use by an embedder. */ + void *data; + Zone(JSRuntime *rt); ~Zone(); bool init(JSContext *cx); diff --git a/js/src/jit-test/lib/match.js b/js/src/jit-test/lib/match.js new file mode 100644 index 000000000000..87d84688ecd4 --- /dev/null +++ b/js/src/jit-test/lib/match.js @@ -0,0 +1 @@ +loadRelativeToScript("../../tests/js1_8_5/extensions/shell.js"); diff --git a/js/src/jit-test/tests/arguments/strict-osr-shadowed-args.js b/js/src/jit-test/tests/arguments/strict-osr-shadowed-args.js new file mode 100644 index 000000000000..5c193b99f630 --- /dev/null +++ b/js/src/jit-test/tests/arguments/strict-osr-shadowed-args.js @@ -0,0 +1,13 @@ + +"use strict"; + +function loop(a) { + a = arguments.length; + var result = 0; + for (var i = 0; i < 5000; i++) { + result += a; + } + return result; +} + +assertEq(loop(11), 5000); diff --git a/js/src/jit-test/tests/basic/bug934789-1.js b/js/src/jit-test/tests/basic/bug934789-1.js new file mode 100644 index 000000000000..3b290e135b47 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug934789-1.js @@ -0,0 +1,13 @@ +if (typeof dis === "function") { + (function() { + function foo() {} + + dis(function bar(e) { + try { + (function() { e; }); + } catch (e) { + foo(); + } + }); + }()); +} diff --git a/js/src/jit-test/tests/basic/bug934789-2.js b/js/src/jit-test/tests/basic/bug934789-2.js new file mode 100644 index 000000000000..5272d63e0197 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug934789-2.js @@ -0,0 +1,15 @@ +load(libdir + "asserts.js"); +assertThrowsInstanceOf( + function() { + function foo() {} + foo = null; + (function bar(e) { + try { + (function() { e; }); + throw 1; + } catch (e) { + foo(); + } + })(); + }, + TypeError); diff --git a/js/src/jit-test/tests/modules/import-declaration.js b/js/src/jit-test/tests/modules/import-declaration.js new file mode 100644 index 000000000000..54596359a92a --- /dev/null +++ b/js/src/jit-test/tests/modules/import-declaration.js @@ -0,0 +1,186 @@ +load(libdir + "match.js"); +load(libdir + "asserts.js"); + +var { Pattern, MatchError } = Match; + +program = (elts) => Pattern({ + type: "Program", + body: elts +}) +importDeclaration = (specifiers, source) => Pattern({ + type: "ImportDeclaration", + specifiers: specifiers, + source: source +}); +importSpecifier = (id, name) => Pattern({ + type: "ImportSpecifier", + id: id, + name: name +}); +ident = (name) => Pattern({ + type: "Identifier", + name: name +}) +lit = (val) => Pattern({ + type: "Literal", + value: val +}) + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("a") + ) + ], + lit("b") + ) +]).assert(Reflect.parse("import a from 'b'")); + +program([ + importDeclaration( + [], + lit("a") + ) +]).assert(Reflect.parse("import {} from 'a'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("a") + ) + ], + lit("b") + ) +]).assert(Reflect.parse("import { a } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("a") + ) + ], + lit("b") + ) +]).assert(Reflect.parse("import { a, } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("b") + ) + ], + lit("c") + ) +]).assert(Reflect.parse("import { a as b } from 'c'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("as"), + ident("as") + ) + ], + lit("a") + ) +]).assert(Reflect.parse("import { as as as } from 'a'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("true"), + ident("a") + ) + ], + lit("b") + ) +]).assert(Reflect.parse("import { true as a } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("a") + ), + importSpecifier( + ident("b"), + ident("b") + ), + ], + lit("c") + ) +]).assert(Reflect.parse("import { a, b } from 'c'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("b") + ), + importSpecifier( + ident("c"), + ident("d") + ), + ], + lit("e") + ) +]).assert(Reflect.parse("import { a as b, c as d } from 'e'")); + +program([ + importDeclaration( + [], + lit("a") + ) +]).assert(Reflect.parse("import 'a'")); + +var loc = Reflect.parse("import { a as b } from 'c'", { + loc: true +}).body[0].loc; + +assertEq(loc.start.line, 1); +assertEq(loc.start.column, 0); +assertEq(loc.start.line, 1); +assertEq(loc.end.column, 26); + +assertThrowsInstanceOf(function () { + Reflect.parse("function f() { import a from 'b' }"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + Reflect.parse("if (true) import a from 'b'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + Reflect.parse("import {"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + Reflect.parse("import {}"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + Reflect.parse("import {} from"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + Reflect.parse("import {,} from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + Reflect.parse("import { a as true } from 'b'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + Reflect.parse("import { true } from 'a'"); +}, SyntaxError); diff --git a/js/src/jit/AsmJS.cpp b/js/src/jit/AsmJS.cpp index 03d75992e9f6..fc188ef8fec9 100644 --- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -1231,6 +1231,7 @@ class MOZ_STACK_CLASS ModuleCompiler char * errorString_; uint32_t errorOffset_; + bool errorOverRecursed_; int64_t usecBefore_; SlowFunctionVector slowFunctions_; @@ -1260,6 +1261,7 @@ class MOZ_STACK_CLASS ModuleCompiler globalAccesses_(cx), errorString_(nullptr), errorOffset_(UINT32_MAX), + errorOverRecursed_(false), usecBefore_(PRMJ_Now()), slowFunctions_(cx), finishedFunctionBodies_(false) @@ -1275,6 +1277,8 @@ class MOZ_STACK_CLASS ModuleCompiler errorString_); js_free(errorString_); } + if (errorOverRecursed_) + js_ReportOverRecursed(cx_); // Avoid spurious Label assertions on compilation failure. if (!stackOverflowLabel_.bound()) @@ -1324,7 +1328,15 @@ class MOZ_STACK_CLASS ModuleCompiler } bool fail(ParseNode *pn, const char *str) { - return failOffset(pn ? pn->pn_pos.begin : parser_.tokenStream.peekTokenPos().begin, str); + if (pn) + return failOffset(pn->pn_pos.begin, str); + + // The exact rooting static analysis does not perform dataflow analysis, so it believes + // that unrooted things on the stack during compilation may still be accessed after this. + // Since pn is typically only null under OOM, this suppression simply forces any GC to be + // delayed until the compilation is off the stack and more memory can be freed. + gc::AutoSuppressGC nogc(cx_); + return failOffset(parser_.tokenStream.peekTokenPos().begin, str); } bool failfVA(ParseNode *pn, const char *fmt, va_list ap) { @@ -1353,6 +1365,11 @@ class MOZ_STACK_CLASS ModuleCompiler return false; } + bool failOverRecursed() { + errorOverRecursed_ = true; + return false; + } + static const unsigned SLOW_FUNCTION_THRESHOLD_MS = 250; bool maybeReportCompileTime(const Func &func) { @@ -3813,7 +3830,7 @@ CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltin static bool CheckCall(FunctionCompiler &f, ParseNode *call, RetType retType, MDefinition **def, Type *type) { - JS_CHECK_RECURSION(f.cx(), return false); + JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed()); ParseNode *callee = CallCallee(call); @@ -4104,7 +4121,7 @@ static bool CheckAddOrSub(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type, unsigned *numAddOrSubOut = nullptr) { - JS_CHECK_RECURSION(f.cx(), return false); + JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed()); JS_ASSERT(expr->isKind(PNK_ADD) || expr->isKind(PNK_SUB)); ParseNode *lhs = BinaryLeft(expr); @@ -4308,7 +4325,7 @@ CheckBitwise(FunctionCompiler &f, ParseNode *bitwise, MDefinition **def, Type *t static bool CheckExpr(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type) { - JS_CHECK_RECURSION(f.cx(), return false); + JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed()); if (!f.mirGen().ensureBallast()) return false; @@ -4781,7 +4798,7 @@ CheckStatementList(FunctionCompiler &f, ParseNode *stmtList) static bool CheckStatement(FunctionCompiler &f, ParseNode *stmt, LabelVector *maybeLabels) { - JS_CHECK_RECURSION(f.cx(), return false); + JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed()); if (!f.mirGen().ensureBallast()) return false; diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 396396147ed1..3a86f46622e0 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -1907,7 +1907,7 @@ Address BaselineCompiler::getScopeCoordinateAddressFromObject(Register objReg, Register reg) { ScopeCoordinate sc(pc); - Shape *shape = ScopeCoordinateToStaticScopeShape(cx, script, pc); + Shape *shape = ScopeCoordinateToStaticScopeShape(script, pc); Address addr; if (shape->numFixedSlots() <= sc.slot) { @@ -1950,7 +1950,7 @@ BaselineCompiler::emit_JSOP_CALLALIASEDVAR() bool BaselineCompiler::emit_JSOP_SETALIASEDVAR() { - JSScript *outerScript = ScopeCoordinateFunctionScript(cx, script, pc); + JSScript *outerScript = ScopeCoordinateFunctionScript(script, pc); if (outerScript && outerScript->treatAsRunOnce) { // Type updates for this operation might need to be tracked, so treat // this as a SETPROP. diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index f76c1124f4d9..538904ba2b9b 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1460,7 +1460,7 @@ DoTypeUpdateFallback(JSContext *cx, BaselineFrame *frame, ICUpdatedStub *stub, H JS_ASSERT(obj->isNative()); jsbytecode *pc = stub->getChainFallback()->icEntry()->pc(script); if (*pc == JSOP_SETALIASEDVAR) - id = NameToId(ScopeCoordinateName(cx, script, pc)); + id = NameToId(ScopeCoordinateName(script, pc)); else id = NameToId(script->getName(pc)); types::AddTypePropertyId(cx, obj, id, value); @@ -6843,7 +6843,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub, RootedPropertyName name(cx); if (op == JSOP_SETALIASEDVAR) - name = ScopeCoordinateName(cx, script, pc); + name = ScopeCoordinateName(script, pc); else name = script->getName(pc); RootedId id(cx, NameToId(name)); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 3190fa8dea5e..7e335f7bd425 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -46,6 +46,7 @@ IonBuilder::IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph, cx(cx), baselineFrame_(baselineFrame), abortReason_(AbortReason_Disable), + reprSetHash_(nullptr), constraints_(constraints), analysis_(info->script()), thisTypes(nullptr), @@ -5696,7 +5697,11 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry) for (uint32_t i = 0; i < info().nargs(); i++) { uint32_t slot = needsArgsObj ? info().argSlotUnchecked(i) : info().argSlot(i); - if (needsArgsObj) { + // Only grab arguments from the arguments object if the arguments object + // aliases formals. If the argsobj does not alias formals, then the + // formals may have been assigned to during interpretation, and that change + // will not be reflected in the argsobj. + if (needsArgsObj && info().argsObjAliasesFormals()) { JS_ASSERT(argsObj && argsObj->isOsrArgumentsObject()); // If this is an aliased formal, then the arguments object // contains a hole at this index. Any references to this @@ -7678,8 +7683,9 @@ IonBuilder::testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName } bool -IonBuilder::annotateGetPropertyCache(JSContext *cx, MDefinition *obj, MGetPropertyCache *getPropCache, - types::TemporaryTypeSet *objTypes, types::TemporaryTypeSet *pushedTypes) +IonBuilder::annotateGetPropertyCache(MDefinition *obj, MGetPropertyCache *getPropCache, + types::TemporaryTypeSet *objTypes, + types::TemporaryTypeSet *pushedTypes) { PropertyName *name = getPropCache->name(); @@ -8240,7 +8246,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name, Shape *objShape = shapes[0]; obj = addShapeGuard(obj, objShape, Bailout_ShapeGuard); - Shape *shape = objShape->search(cx, NameToId(name)); + Shape *shape = objShape->searchLinear(NameToId(name)); JS_ASSERT(shape); if (!loadSlot(obj, shape, rvalType, barrier, types)) @@ -8255,7 +8261,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name, for (size_t i = 0; i < shapes.length(); i++) { Shape *objShape = shapes[i]; - Shape *shape = objShape->search(cx, NameToId(name)); + Shape *shape = objShape->searchLinear(NameToId(name)); JS_ASSERT(shape); if (!load->addShape(objShape, shape)) return false; @@ -8307,7 +8313,7 @@ IonBuilder::getPropTryCache(bool *emitted, PropertyName *name, } if (JSOp(*pc) == JSOP_CALLPROP) { - if (!annotateGetPropertyCache(cx, obj, load, obj->resultTypeSet(), types)) + if (!annotateGetPropertyCache(obj, load, obj->resultTypeSet(), types)) return false; } @@ -8642,7 +8648,7 @@ IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj, Shape *objShape = shapes[0]; obj = addShapeGuard(obj, objShape, Bailout_ShapeGuard); - Shape *shape = objShape->search(cx, NameToId(name)); + Shape *shape = objShape->searchLinear(NameToId(name)); JS_ASSERT(shape); bool needsBarrier = objTypes->propertyNeedsBarrier(constraints(), NameToId(name)); @@ -8658,7 +8664,7 @@ IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj, for (size_t i = 0; i < shapes.length(); i++) { Shape *objShape = shapes[i]; - Shape *shape = objShape->search(cx, NameToId(name)); + Shape *shape = objShape->searchLinear(NameToId(name)); JS_ASSERT(shape); if (!ins->addShape(objShape, shape)) return false; @@ -8727,9 +8733,8 @@ IonBuilder::jsop_delelem() bool IonBuilder::jsop_regexp(RegExpObject *reobj) { - JSObject *prototype = script()->global().getOrCreateRegExpPrototype(cx); - if (!prototype) - return false; + JSObject *prototype = reobj->getProto(); + JS_ASSERT(prototype == script()->global().maybeGetRegExpPrototype()); JS_ASSERT(&reobj->JSObject::global() == &script()->global()); @@ -9057,7 +9062,7 @@ IonBuilder::walkScopeChain(unsigned hops) bool IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall) { - JSScript *outerScript = ScopeCoordinateFunctionScript(cx, script(), pc); + JSScript *outerScript = ScopeCoordinateFunctionScript(script(), pc); if (!outerScript || !outerScript->treatAsRunOnce) return false; @@ -9114,7 +9119,7 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc) { JSObject *call = nullptr; if (hasStaticScopeObject(sc, &call) && call) { - PropertyName *name = ScopeCoordinateName(cx, script(), pc); + PropertyName *name = ScopeCoordinateName(script(), pc); bool succeeded; if (!getStaticName(call, name, &succeeded)) return false; @@ -9124,7 +9129,7 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc) MDefinition *obj = walkScopeChain(sc.hops); - Shape *shape = ScopeCoordinateToStaticScopeShape(cx, script(), pc); + Shape *shape = ScopeCoordinateToStaticScopeShape(script(), pc); MInstruction *load; if (shape->numFixedSlots() <= sc.slot) { @@ -9154,7 +9159,7 @@ IonBuilder::jsop_setaliasedvar(ScopeCoordinate sc) return false; } MDefinition *value = current->pop(); - PropertyName *name = ScopeCoordinateName(cx, script(), pc); + PropertyName *name = ScopeCoordinateName(script(), pc); if (call) { // Push the object on the stack to match the bound object expected in @@ -9177,7 +9182,7 @@ IonBuilder::jsop_setaliasedvar(ScopeCoordinate sc) MDefinition *rval = current->peek(-1); MDefinition *obj = walkScopeChain(sc.hops); - Shape *shape = ScopeCoordinateToStaticScopeShape(cx, script(), pc); + Shape *shape = ScopeCoordinateToStaticScopeShape(script(), pc); if (NeedsPostBarrier(info(), rval)) current->add(MPostWriteBarrier::New(obj, rval)); @@ -9333,16 +9338,14 @@ TypeRepresentationSetHash * IonBuilder::getOrCreateReprSetHash() { if (!reprSetHash_) { - TypeRepresentationSetHash* hash = - cx->new_(); - if (!hash || !hash->init()) { - js_delete(hash); + TypeRepresentationSetHash *hash = + temp_->lifoAlloc()->new_(); + if (!hash || !hash->init()) return nullptr; - } reprSetHash_ = hash; } - return reprSetHash_.get(); + return reprSetHash_; } bool diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index da63f2afee54..a774b2f6ee99 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -636,8 +636,9 @@ class IonBuilder : public MIRGenerator bool testShouldDOMCall(types::TypeSet *inTypes, JSFunction *func, JSJitInfo::OpType opType); - bool annotateGetPropertyCache(JSContext *cx, MDefinition *obj, MGetPropertyCache *getPropCache, - types::TemporaryTypeSet *objTypes, types::TemporaryTypeSet *pushedTypes); + bool annotateGetPropertyCache(MDefinition *obj, MGetPropertyCache *getPropCache, + types::TemporaryTypeSet *objTypes, + types::TemporaryTypeSet *pushedTypes); MGetPropertyCache *getInlineableGetPropertyCache(CallInfo &callInfo); @@ -712,7 +713,7 @@ class IonBuilder : public MIRGenerator JSContext *cx; BaselineFrame *baselineFrame_; AbortReason abortReason_; - ScopedJSDeletePtr reprSetHash_; + TypeRepresentationSetHash *reprSetHash_; // Constraints for recording dependencies on type information. types::CompilerConstraintList *constraints_; diff --git a/js/src/js.msg b/js/src/js.msg index 15986cd569c7..8bd4f8bd0556 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -417,3 +417,13 @@ MSG_DEF(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, 363, 1, JSEXN_TYPEERR, "No such property MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 364, 2, JSEXN_TYPEERR, "argument {0} invalid: expected {1}") MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 365, 0, JSEXN_TYPEERR, "handle unattached") MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE, 366, 0, JSEXN_TYPEERR, "handle moved to destination of incorrect type") + +MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 367, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level") +MSG_DEF(JSMSG_NO_IMPORT_NAME, 368, 0, JSEXN_SYNTAXERR, "missing import name") +MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 369, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'") +MSG_DEF(JSMSG_NO_BINDING_NAME, 370, 0, JSEXN_SYNTAXERR, "missing binding name") +MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 371, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list") +MSG_DEF(JSMSG_FROM_AFTER_IMPORT_SPEC_SET, 372, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import specifier set") +MSG_DEF(JSMSG_DECLARATION_AFTER_IMPORT, 373, 0, JSEXN_SYNTAXERR, "missing declaration after 'import' keyword") +MSG_DEF(JSMSG_MODULE_SPEC_AFTER_FROM, 374, 0, JSEXN_SYNTAXERR, "missing module specifier after 'from' keyword") +MSG_DEF(JSMSG_MODULES_NOT_IMPLEMENTED, 375, 0, JSEXN_SYNTAXERR, "modules are not implemented yet") diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index d548b4da0500..f0800eda9e31 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -908,6 +908,18 @@ JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback cal rt->destroyCompartmentCallback = callback; } +JS_PUBLIC_API(void) +JS_SetDestroyZoneCallback(JSRuntime *rt, JSZoneCallback callback) +{ + rt->destroyZoneCallback = callback; +} + +JS_PUBLIC_API(void) +JS_SetSweepZoneCallback(JSRuntime *rt, JSZoneCallback callback) +{ + rt->sweepZoneCallback = callback; +} + JS_PUBLIC_API(void) JS_SetCompartmentNameCallback(JSRuntime *rt, JSCompartmentNameCallback callback) { @@ -988,6 +1000,18 @@ JS_GetCompartmentPrivate(JSCompartment *compartment) return compartment->data; } +JS_PUBLIC_API(void) +JS_SetZoneUserData(JS::Zone *zone, void *data) +{ + zone->data = data; +} + +JS_PUBLIC_API(void *) +JS_GetZoneUserData(JS::Zone *zone) +{ + return zone->data; +} + JS_PUBLIC_API(bool) JS_WrapObject(JSContext *cx, MutableHandleObject objp) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 69a6af98676d..b7fd10b44c08 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -841,6 +841,9 @@ typedef JSObject * typedef void (* JSDestroyCompartmentCallback)(JSFreeOp *fop, JSCompartment *compartment); +typedef void +(* JSZoneCallback)(JS::Zone *zone); + typedef void (* JSCompartmentNameCallback)(JSRuntime *rt, JSCompartment *compartment, char *buf, size_t bufsize); @@ -1623,6 +1626,12 @@ JS_GetImplementationVersion(void); extern JS_PUBLIC_API(void) JS_SetDestroyCompartmentCallback(JSRuntime *rt, JSDestroyCompartmentCallback callback); +extern JS_PUBLIC_API(void) +JS_SetDestroyZoneCallback(JSRuntime *rt, JSZoneCallback callback); + +extern JS_PUBLIC_API(void) +JS_SetSweepZoneCallback(JSRuntime *rt, JSZoneCallback callback); + extern JS_PUBLIC_API(void) JS_SetCompartmentNameCallback(JSRuntime *rt, JSCompartmentNameCallback callback); @@ -1638,6 +1647,12 @@ JS_SetCompartmentPrivate(JSCompartment *compartment, void *data); extern JS_PUBLIC_API(void *) JS_GetCompartmentPrivate(JSCompartment *compartment); +extern JS_PUBLIC_API(void) +JS_SetZoneUserData(JS::Zone *zone, void *data); + +extern JS_PUBLIC_API(void *) +JS_GetZoneUserData(JS::Zone *zone); + extern JS_PUBLIC_API(bool) JS_WrapObject(JSContext *cx, JS::MutableHandleObject objp); diff --git a/js/src/jsast.tbl b/js/src/jsast.tbl index bcfb6907b634..4e2aa4daedb6 100644 --- a/js/src/jsast.tbl +++ b/js/src/jsast.tbl @@ -57,6 +57,8 @@ ASTDEF(AST_TRY_STMT, "TryStatement", "tryStatemen ASTDEF(AST_THROW_STMT, "ThrowStatement", "throwStatement") ASTDEF(AST_DEBUGGER_STMT, "DebuggerStatement", "debuggerStatement") ASTDEF(AST_LET_STMT, "LetStatement", "letStatement") +ASTDEF(AST_IMPORT_DECL, "ImportDeclaration", "importDeclaration") +ASTDEF(AST_IMPORT_SPEC, "ImportSpecifier", "importSpecifier") ASTDEF(AST_CASE, "SwitchCase", "switchCase") ASTDEF(AST_CATCH, "CatchClause", "catchClause") diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 9affb38146ee..6b236f4c207e 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -25,6 +25,8 @@ #include "jsobjinlines.h" +#include "vm/ScopeObject-inl.h" + using namespace js; using namespace JS; @@ -453,8 +455,8 @@ js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx) RootedFunction scriptedCaller(cx, iter.callee()); RootedScript outermost(cx, scriptedCaller->nonLazyScript()); - for (StaticScopeIter i(cx, scriptedCaller); !i.done(); i++) { - if (i.type() == StaticScopeIter::FUNCTION) + for (StaticScopeIter i(scriptedCaller); !i.done(); i++) { + if (i.type() == StaticScopeIter::FUNCTION) outermost = i.funScript(); } return outermost; diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 92a84cf57df3..d0c13dfd9410 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -665,7 +665,7 @@ GetNativeStackLimit(JSContext *cx) * extra space so that we can ensure that crucial code is able to run. */ -#define JS_CHECK_RECURSION(cx, onerror) \ +#define JS_CHECK_RECURSION(cx, onerror) \ JS_BEGIN_MACRO \ int stackDummy_; \ if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_)) { \ @@ -674,6 +674,14 @@ GetNativeStackLimit(JSContext *cx) } \ JS_END_MACRO +#define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \ + JS_BEGIN_MACRO \ + int stackDummy_; \ + if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_)) { \ + onerror; \ + } \ + JS_END_MACRO + #define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \ JS_BEGIN_MACRO \ if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 463b3588df9c..ab4f63861089 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2614,6 +2614,7 @@ static void SweepZones(FreeOp *fop, bool lastGC) { JSRuntime *rt = fop->runtime(); + JSZoneCallback callback = rt->destroyZoneCallback; /* Skip the atomsCompartment zone. */ Zone **read = rt->zones.begin() + 1; @@ -2628,6 +2629,8 @@ SweepZones(FreeOp *fop, bool lastGC) if (!zone->hold && zone->wasGCStarted()) { if (zone->allocator.arenas.arenaListsAreEmpty() || lastGC) { zone->allocator.arenas.checkEmptyFreeLists(); + if (callback) + callback(zone); SweepCompartments(fop, zone, false, lastGC); JS_ASSERT(zone->compartments.empty()); fop->delete_(zone); @@ -3714,6 +3717,9 @@ BeginSweepingZoneGroup(JSRuntime *rt) if (rt->isAtomsZone(zone)) sweepingAtoms = true; + + if (rt->sweepZoneCallback) + rt->sweepZoneCallback(zone); } ValidateIncrementalMarking(rt); diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 786815895a77..756f16b2326e 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -389,7 +389,7 @@ class BytecodeParser JSContext *cx_; LifoAllocScope allocScope_; - JSScript *script_; + RootedScript script_; Bytecode **codeArray_; @@ -397,7 +397,7 @@ class BytecodeParser BytecodeParser(JSContext *cx, JSScript *script) : cx_(cx), allocScope_(&cx->tempLifoAlloc()), - script_(script), + script_(cx, script), codeArray_(nullptr) { } bool parse(); @@ -949,7 +949,7 @@ js_Disassemble1(JSContext *cx, HandleScript script, jsbytecode *pc, } case JOF_SCOPECOORD: { - Value v = StringValue(ScopeCoordinateName(cx, script, pc)); + Value v = StringValue(ScopeCoordinateName(script, pc)); JSAutoByteString bytes; if (!ToDisassemblySource(cx, v, &bytes)) return 0; @@ -1590,7 +1590,7 @@ ExpressionDecompiler::decompilePC(jsbytecode *pc) } case JSOP_CALLALIASEDVAR: case JSOP_GETALIASEDVAR: { - JSAtom *atom = ScopeCoordinateName(cx, script, pc); + JSAtom *atom = ScopeCoordinateName(script, pc); JS_ASSERT(atom); return write(atom); } diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index 34baac115ca4..7cf7f2fd0a79 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -562,6 +562,10 @@ class NodeBuilder bool letStatement(NodeVector &head, HandleValue stmt, TokenPos *pos, MutableHandleValue dst); + bool importDeclaration(NodeVector &elts, HandleValue moduleSpec, TokenPos *pos, MutableHandleValue dst); + + bool importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos *pos, MutableHandleValue dst); + /* * expressions */ @@ -1353,6 +1357,38 @@ NodeBuilder::letStatement(NodeVector &head, HandleValue stmt, TokenPos *pos, Mut dst); } +bool +NodeBuilder::importDeclaration(NodeVector &elts, HandleValue moduleSpec, TokenPos *pos, + MutableHandleValue dst) +{ + RootedValue array(cx); + if (!newArray(elts, &array)) + return false; + + RootedValue cb(cx, callbacks[AST_IMPORT_DECL]); + if (!cb.isNull()) + return callback(cb, array, moduleSpec, pos, dst); + + return newNode(AST_IMPORT_DECL, pos, + "specifiers", array, + "source", moduleSpec, + dst); +} + +bool +NodeBuilder::importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos *pos, + MutableHandleValue dst) +{ + RootedValue cb(cx, callbacks[AST_IMPORT_SPEC]); + if (!cb.isNull()) + return callback(cb, importName, bindingName, pos, dst); + + return newNode(AST_IMPORT_SPEC, pos, + "id", importName, + "name", bindingName, + dst); +} + bool NodeBuilder::variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos, MutableHandleValue dst) @@ -1520,6 +1556,8 @@ class ASTSerializer bool variableDeclaration(ParseNode *pn, bool let, MutableHandleValue dst); bool variableDeclarator(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst); bool let(ParseNode *pn, bool expr, MutableHandleValue dst); + bool importDeclaration(ParseNode *pn, MutableHandleValue dst); + bool importSpecifier(ParseNode *pn, MutableHandleValue dst); bool optStatement(ParseNode *pn, MutableHandleValue dst) { if (!pn) { @@ -1883,6 +1921,41 @@ ASTSerializer::let(ParseNode *pn, bool expr, MutableHandleValue dst) builder.letStatement(dtors, v, &pn->pn_pos, dst); } +bool +ASTSerializer::importDeclaration(ParseNode *pn, MutableHandleValue dst) +{ + JS_ASSERT(pn->isKind(PNK_IMPORT)); + JS_ASSERT(pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST)); + JS_ASSERT(pn->pn_right->isKind(PNK_STRING)); + + NodeVector elts(cx); + if (!elts.reserve(pn->pn_count)) + return false; + + for (ParseNode *next = pn->pn_left->pn_head; next; next = next->pn_next) { + RootedValue elt(cx); + if (!importSpecifier(next, &elt)) + return false; + elts.infallibleAppend(elt); + } + + RootedValue moduleSpec(cx); + return literal(pn->pn_right, &moduleSpec) && + builder.importDeclaration(elts, moduleSpec, &pn->pn_pos, dst); +} + +bool +ASTSerializer::importSpecifier(ParseNode *pn, MutableHandleValue dst) +{ + JS_ASSERT(pn->isKind(PNK_IMPORT_SPEC)); + + RootedValue importName(cx); + RootedValue bindingName(cx); + return identifier(pn->pn_left, &importName) && + identifier(pn->pn_right, &bindingName) && + builder.importSpecifier(importName, bindingName, &pn->pn_pos, dst); +} + bool ASTSerializer::switchCase(ParseNode *pn, MutableHandleValue dst) { @@ -2038,6 +2111,9 @@ ASTSerializer::statement(ParseNode *pn, MutableHandleValue dst) ? let(pn, false, dst) : declaration(pn, dst); + case PNK_IMPORT: + return importDeclaration(pn, dst); + case PNK_NAME: LOCAL_ASSERT(pn->isUsed()); return statement(pn->pn_lexdef, dst); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index fbc451ea37b9..691de9e83ff8 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -687,8 +687,8 @@ js::XDRScript(XDRState *xdr, HandleObject enclosingScope, HandleScript enc if (!innerScript) return false; RootedObject staticScope(cx, innerScript->enclosingStaticScope()); - StaticScopeIter ssi(cx, staticScope); - if (ssi.done() || ssi.type() == StaticScopeIter::FUNCTION) { + StaticScopeIter ssi(staticScope); + if (ssi.done() || ssi.type() == StaticScopeIter::FUNCTION) { JS_ASSERT(ssi.done() == !fun); funEnclosingScopeIndex = UINT32_MAX; } else { @@ -2315,9 +2315,9 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, return nullptr; } RootedObject staticScope(cx, innerFun->nonLazyScript()->enclosingStaticScope()); - StaticScopeIter ssi(cx, staticScope); + StaticScopeIter ssi(cx, staticScope); RootedObject enclosingScope(cx); - if (!ssi.done() && ssi.type() == StaticScopeIter::BLOCK) + if (!ssi.done() && ssi.type() == StaticScopeIter::BLOCK) enclosingScope = objects[FindBlockIndex(src, ssi.block())]; else enclosingScope = fun; @@ -3001,8 +3001,8 @@ LazyScript::Create(ExclusiveContext *cx, HandleFunction fun, uint32_t LazyScript::staticLevel(JSContext *cx) const { - for (StaticScopeIter ssi(cx, enclosingScope()); !ssi.done(); ssi++) { - if (ssi.type() == StaticScopeIter::FUNCTION) + for (StaticScopeIter ssi(enclosingScope()); !ssi.done(); ssi++) { + if (ssi.type() == StaticScopeIter::FUNCTION) return ssi.funScript()->staticLevel + 1; } return 1; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index bf6aadf1600f..5a6a07e29b88 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4129,10 +4129,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = { "intern(str)", " Internalize str in the atom table."), - JS_FN_HELP("clone", Clone, 1, 0, -"clone(fun[, scope])", -" Clone function object."), - JS_FN_HELP("getpda", GetPDA, 1, 0, "getpda(obj)", " Get the property descriptors for obj."), @@ -4277,6 +4273,10 @@ static const JSFunctionSpecWithHelp shell_functions[] = { }; static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = { + JS_FN_HELP("clone", Clone, 1, 0, +"clone(fun[, scope])", +" Clone function object."), + JS_FN_HELP("getSelfHostedValue", GetSelfHostedValue, 1, 0, "getSelfHostedValue()", " Get a self-hosted value by its name. Note that these values don't get \n" diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index f4f3e03ba8bd..6406291bfa6b 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -15,6 +15,7 @@ macro(anonymous, anonymous, "anonymous") \ macro(apply, apply, "apply") \ macro(arguments, arguments, "arguments") \ + macro(as, as, "as") \ macro(ArrayType, ArrayType, "ArrayType") \ macro(buffer, buffer, "buffer") \ macro(builder, builder, "builder") \ @@ -43,6 +44,7 @@ macro(DateTimeFormatFormatGet, DateTimeFormatFormatGet, "Intl_DateTimeFormat_format_get") \ macro(decodeURI, decodeURI, "decodeURI") \ macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \ + macro(default_, default_, "default") \ macro(defineProperty, defineProperty, "defineProperty") \ macro(defineGetter, defineGetter, "__defineGetter__") \ macro(defineSetter, defineSetter, "__defineSetter__") \ @@ -68,6 +70,7 @@ macro(float32, float32, "float32") \ macro(float64, float64, "float64") \ macro(format, format, "format") \ + macro(from, from, "from") \ macro(get, get, "get") \ macro(getInternals, getInternals, "getInternals") \ macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \ diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 8dd14ba0f829..401bf8b2c4e3 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -390,6 +390,12 @@ class GlobalObject : public JSObject return &self->getPrototype(JSProto_RegExp).toObject(); } + JSObject *maybeGetRegExpPrototype() { + if (regexpClassInitialized()) + return &getPrototype(JSProto_RegExp).toObject(); + return nullptr; + } + JSObject *getOrCreateArrayBufferPrototype(JSContext *cx) { if (arrayBufferClassInitialized()) return &getPrototype(JSProto_ArrayBuffer).toObject(); @@ -523,9 +529,10 @@ class GlobalObject : public JSObject bool getIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue value) { if (maybeGetIntrinsicValue(name, value.address())) return true; + Rooted self(cx, this); if (!cx->runtime()->cloneSelfHostedValue(cx, name, value)) return false; - RootedObject holder(cx, intrinsicsHolder()); + RootedObject holder(cx, self->intrinsicsHolder()); RootedId id(cx, NameToId(name)); return JS_DefinePropertyById(cx, holder, id, value, nullptr, nullptr, 0); } diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 470b053d1eca..3aeeadb0e0e4 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -2787,7 +2787,7 @@ CASE(JSOP_SETALIASEDVAR) // Avoid computing the name if no type updates are needed, as this may be // expensive on scopes with large numbers of variables. - PropertyName *name = obj.hasSingletonType() ? ScopeCoordinateName(cx, script, REGS.pc) + PropertyName *name = obj.hasSingletonType() ? ScopeCoordinateName(script, REGS.pc) : nullptr; obj.setAliasedVar(cx, sc, name, REGS.sp[-1]); diff --git a/js/src/vm/Keywords.h b/js/src/vm/Keywords.h index f1d7211b2029..a6c867e79214 100644 --- a/js/src/vm/Keywords.h +++ b/js/src/vm/Keywords.h @@ -41,12 +41,12 @@ macro(void, void_, TOK_VOID, JSVERSION_DEFAULT) \ macro(while, while_, TOK_WHILE, JSVERSION_DEFAULT) \ macro(with, with, TOK_WITH, JSVERSION_DEFAULT) \ + macro(import, import, TOK_IMPORT, JSVERSION_DEFAULT) \ /* Reserved keywords. */ \ macro(class, class_, TOK_RESERVED, JSVERSION_DEFAULT) \ macro(enum, enum_, TOK_RESERVED, JSVERSION_DEFAULT) \ macro(export, export, TOK_RESERVED, JSVERSION_DEFAULT) \ macro(extends, extends, TOK_RESERVED, JSVERSION_DEFAULT) \ - macro(import, import, TOK_RESERVED, JSVERSION_DEFAULT) \ macro(super, super, TOK_RESERVED, JSVERSION_DEFAULT) \ /* Future reserved keywords, but only in strict mode. */ \ macro(implements, implements, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \ diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 3f9a5fc22242..1985db85d18a 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -146,6 +146,8 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) nativeStackBase(0), cxCallback(nullptr), destroyCompartmentCallback(nullptr), + destroyZoneCallback(nullptr), + sweepZoneCallback(nullptr), compartmentNameCallback(nullptr), activityCallback(nullptr), activityCallbackArg(nullptr), diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 92810edfbaf3..a144c8af0e34 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -950,6 +950,12 @@ struct JSRuntime : public JS::shadow::Runtime, /* Compartment destroy callback. */ JSDestroyCompartmentCallback destroyCompartmentCallback; + /* Zone destroy callback. */ + JSZoneCallback destroyZoneCallback; + + /* Zone sweep callback. */ + JSZoneCallback sweepZoneCallback; + /* Call this to get the name of a compartment. */ JSCompartmentNameCallback compartmentNameCallback; diff --git a/js/src/vm/ScopeObject-inl.h b/js/src/vm/ScopeObject-inl.h index 8a1f19f00599..cfb878a9038c 100644 --- a/js/src/vm/ScopeObject-inl.h +++ b/js/src/vm/ScopeObject-inl.h @@ -36,6 +36,74 @@ CallObject::setAliasedVar(JSContext *cx, AliasedFormalIter fi, PropertyName *nam types::AddTypePropertyId(cx, this, NameToId(name), v); } +template +inline bool +StaticScopeIter::done() const +{ + return !obj; +} + +template +inline void +StaticScopeIter::operator++(int) +{ + if (obj->template is()) { + obj = obj->template as().enclosingStaticScope(); + } else if (onNamedLambda || !obj->template as().isNamedLambda()) { + onNamedLambda = false; + obj = obj->template as().nonLazyScript()->enclosingStaticScope(); + } else { + onNamedLambda = true; + } + JS_ASSERT_IF(obj, obj->template is() || obj->template is()); + JS_ASSERT_IF(onNamedLambda, obj->template is()); +} + +template +inline bool +StaticScopeIter::hasDynamicScopeObject() const +{ + return obj->template is() + ? obj->template as().needsClone() + : obj->template as().isHeavyweight(); +} + +template +inline Shape * +StaticScopeIter::scopeShape() const +{ + JS_ASSERT(hasDynamicScopeObject()); + JS_ASSERT(type() != NAMED_LAMBDA); + return type() == BLOCK + ? block().lastProperty() + : funScript()->bindings.callObjShape(); +} + +template +inline typename StaticScopeIter::Type +StaticScopeIter::type() const +{ + if (onNamedLambda) + return NAMED_LAMBDA; + return obj->template is() ? BLOCK : FUNCTION; +} + +template +inline StaticBlockObject & +StaticScopeIter::block() const +{ + JS_ASSERT(type() == BLOCK); + return obj->template as(); +} + +template +inline JSScript * +StaticScopeIter::funScript() const +{ + JS_ASSERT(type() == FUNCTION); + return obj->template as().nonLazyScript(); +} + } /* namespace js */ #endif /* vm_ScopeObject_inl_h */ diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 89fd6c8564d5..82b23cb7545f 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -32,75 +32,6 @@ typedef Rooted RootedArgumentsObject; /*****************************************************************************/ -StaticScopeIter::StaticScopeIter(ExclusiveContext *cx, JSObject *objArg) - : obj(cx, objArg), onNamedLambda(false) -{ - JS_ASSERT_IF(obj, obj->is() || obj->is()); -} - -bool -StaticScopeIter::done() const -{ - return !obj; -} - -void -StaticScopeIter::operator++(int) -{ - if (obj->is()) { - obj = obj->as().enclosingStaticScope(); - } else if (onNamedLambda || !obj->as().isNamedLambda()) { - onNamedLambda = false; - obj = obj->as().nonLazyScript()->enclosingStaticScope(); - } else { - onNamedLambda = true; - } - JS_ASSERT_IF(obj, obj->is() || obj->is()); - JS_ASSERT_IF(onNamedLambda, obj->is()); -} - -bool -StaticScopeIter::hasDynamicScopeObject() const -{ - return obj->is() - ? obj->as().needsClone() - : obj->as().isHeavyweight(); -} - -Shape * -StaticScopeIter::scopeShape() const -{ - JS_ASSERT(hasDynamicScopeObject()); - JS_ASSERT(type() != NAMED_LAMBDA); - return type() == BLOCK - ? block().lastProperty() - : funScript()->bindings.callObjShape(); -} - -StaticScopeIter::Type -StaticScopeIter::type() const -{ - if (onNamedLambda) - return NAMED_LAMBDA; - return obj->is() ? BLOCK : FUNCTION; -} - -StaticBlockObject & -StaticScopeIter::block() const -{ - JS_ASSERT(type() == BLOCK); - return obj->as(); -} - -JSScript * -StaticScopeIter::funScript() const -{ - JS_ASSERT(type() == FUNCTION); - return obj->as().nonLazyScript(); -} - -/*****************************************************************************/ - static JSObject * InnermostStaticScope(JSScript *script, jsbytecode *pc) { @@ -115,9 +46,9 @@ InnermostStaticScope(JSScript *script, jsbytecode *pc) } Shape * -js::ScopeCoordinateToStaticScopeShape(JSContext *cx, JSScript *script, jsbytecode *pc) +js::ScopeCoordinateToStaticScopeShape(JSScript *script, jsbytecode *pc) { - StaticScopeIter ssi(cx, InnermostStaticScope(script, pc)); + StaticScopeIter ssi(InnermostStaticScope(script, pc)); ScopeCoordinate sc(pc); while (true) { if (ssi.hasDynamicScopeObject()) { @@ -131,9 +62,9 @@ js::ScopeCoordinateToStaticScopeShape(JSContext *cx, JSScript *script, jsbytecod } PropertyName * -js::ScopeCoordinateName(JSContext *cx, JSScript *script, jsbytecode *pc) +js::ScopeCoordinateName(JSScript *script, jsbytecode *pc) { - Shape::Range r(ScopeCoordinateToStaticScopeShape(cx, script, pc)); + Shape::Range r(ScopeCoordinateToStaticScopeShape(script, pc)); ScopeCoordinate sc(pc); while (r.front().slot() != sc.slot) r.popFront(); @@ -141,14 +72,14 @@ js::ScopeCoordinateName(JSContext *cx, JSScript *script, jsbytecode *pc) /* Beware nameless destructuring formal. */ if (!JSID_IS_ATOM(id)) - return cx->runtime()->atomState.empty; + return script->runtimeFromAnyThread()->atomState.empty; return JSID_TO_ATOM(id)->asPropertyName(); } JSScript * -js::ScopeCoordinateFunctionScript(JSContext *cx, JSScript *script, jsbytecode *pc) +js::ScopeCoordinateFunctionScript(JSScript *script, jsbytecode *pc) { - StaticScopeIter ssi(cx, InnermostStaticScope(script, pc)); + StaticScopeIter ssi(InnermostStaticScope(script, pc)); ScopeCoordinate sc(pc); while (true) { if (ssi.hasDynamicScopeObject()) { @@ -158,7 +89,7 @@ js::ScopeCoordinateFunctionScript(JSContext *cx, JSScript *script, jsbytecode *p } ssi++; } - if (ssi.type() != StaticScopeIter::FUNCTION) + if (ssi.type() != StaticScopeIter::FUNCTION) return nullptr; return ssi.funScript(); } @@ -2195,7 +2126,7 @@ RemoveReferencedNames(JSContext *cx, HandleScript script, PropertyNameSet &remai case JSOP_GETALIASEDVAR: case JSOP_CALLALIASEDVAR: case JSOP_SETALIASEDVAR: - name = ScopeCoordinateName(cx, script, pc); + name = ScopeCoordinateName(script, pc); break; default: diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 7d56b3e8b48d..3c65f296e184 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -54,13 +54,26 @@ namespace frontend { struct Definition; } * * (See also AssertDynamicScopeMatchesStaticScope.) */ +template class StaticScopeIter { - RootedObject obj; + typename MaybeRooted::RootType obj; bool onNamedLambda; public: - explicit StaticScopeIter(ExclusiveContext *cx, JSObject *obj); + StaticScopeIter(ExclusiveContext *cx, JSObject *obj) + : obj(cx, obj), onNamedLambda(false) + { + JS_STATIC_ASSERT(allowGC == CanGC); + JS_ASSERT_IF(obj, obj->is() || obj->is()); + } + + StaticScopeIter(JSObject *obj) + : obj((ExclusiveContext *) nullptr, obj), onNamedLambda(false) + { + JS_STATIC_ASSERT(allowGC == NoGC); + JS_ASSERT_IF(obj, obj->is() || obj->is()); + } bool done() const; void operator++(int); @@ -106,15 +119,15 @@ struct ScopeCoordinate * accessed by the ALIASEDVAR op at 'pc'. */ extern Shape * -ScopeCoordinateToStaticScopeShape(JSContext *cx, JSScript *script, jsbytecode *pc); +ScopeCoordinateToStaticScopeShape(JSScript *script, jsbytecode *pc); /* Return the name being accessed by the given ALIASEDVAR op. */ extern PropertyName * -ScopeCoordinateName(JSContext *cx, JSScript *script, jsbytecode *pc); +ScopeCoordinateName(JSScript *script, jsbytecode *pc); /* Return the function script accessed by the given ALIASEDVAR op, or nullptr. */ extern JSScript * -ScopeCoordinateFunctionScript(JSContext *cx, JSScript *script, jsbytecode *pc); +ScopeCoordinateFunctionScript(JSScript *script, jsbytecode *pc); /*****************************************************************************/ diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 65f34422123c..975035b91424 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -1295,6 +1295,7 @@ class Shape : public gc::BarrieredCell } inline Shape *search(ExclusiveContext *cx, jsid id); + inline Shape *searchLinear(jsid id); /* For JIT usage */ static inline size_t offsetOfBase() { return offsetof(Shape, base_); } @@ -1582,6 +1583,25 @@ Shape::Shape(UnownedBaseShape *base, uint32_t nfixed) kids.setNull(); } +inline Shape * +Shape::searchLinear(jsid id) +{ + /* + * Non-dictionary shapes can acquire a table at any point the main thread + * is operating on it, so other threads inspecting such shapes can't use + * their table without racing. This function can be called from any thread + * on any non-dictionary shape. + */ + JS_ASSERT(!inDictionary()); + + for (Shape *shape = this; shape; shape = shape->parent) { + if (shape->propidRef() == id) + return shape; + } + + return nullptr; +} + /* * Keep this function in sync with search. It neither hashifies the start * shape nor increments linear search count. @@ -1598,12 +1618,7 @@ Shape::searchNoHashify(Shape *start, jsid id) return SHAPE_FETCH(spp); } - for (Shape *shape = start; shape; shape = shape->parent) { - if (shape->propidRef() == id) - return shape; - } - - return nullptr; + return start->searchLinear(id); } inline bool diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 46317e7451be..e92bca1ace47 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -20,6 +20,7 @@ #include "jit/IonFrameIterator-inl.h" #include "vm/Interpreter-inl.h" #include "vm/Probes-inl.h" +#include "vm/ScopeObject-inl.h" using namespace js; @@ -204,7 +205,7 @@ AssertDynamicScopeMatchesStaticScope(JSContext *cx, JSScript *script, JSObject * { #ifdef DEBUG RootedObject enclosingScope(cx, script->enclosingStaticScope()); - for (StaticScopeIter i(cx, enclosingScope); !i.done(); i++) { + for (StaticScopeIter i(enclosingScope); !i.done(); i++) { if (i.hasDynamicScopeObject()) { /* * 'with' does not participate in the static scope of the script, @@ -214,15 +215,15 @@ AssertDynamicScopeMatchesStaticScope(JSContext *cx, JSScript *script, JSObject * scope = &scope->as().enclosingScope(); switch (i.type()) { - case StaticScopeIter::BLOCK: + case StaticScopeIter::BLOCK: JS_ASSERT(i.block() == scope->as().staticBlock()); scope = &scope->as().enclosingScope(); break; - case StaticScopeIter::FUNCTION: + case StaticScopeIter::FUNCTION: JS_ASSERT(scope->as().callee().nonLazyScript() == i.funScript()); scope = &scope->as().enclosingScope(); break; - case StaticScopeIter::NAMED_LAMBDA: + case StaticScopeIter::NAMED_LAMBDA: scope = &scope->as().enclosingScope(); break; } diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index acb6f2976100..84384dbec723 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -741,8 +741,6 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop, JSFinalizeStatus status, bool isCo // Find dying scopes. XPCWrappedNativeScope::StartFinalizationPhaseOfGC(fop, self); - XPCStringConvert::ClearCache(); - self->mDoingFinalization = true; break; } diff --git a/js/xpconnect/src/XPCString.cpp b/js/xpconnect/src/XPCString.cpp index df9e400e4770..2e21f7aadeaa 100644 --- a/js/xpconnect/src/XPCString.cpp +++ b/js/xpconnect/src/XPCString.cpp @@ -24,24 +24,29 @@ #include "jsapi.h" #include "xpcpublic.h" -// One-slot cache, because it turns out it's common for web pages to -// get the same string a few times in a row. We get about a 40% cache -// hit rate on this cache last it was measured. We'd get about 70% -// hit rate with a hashtable with removal on finalization, but that -// would take a lot more machinery. -nsStringBuffer* XPCStringConvert::sCachedBuffer = nullptr; -JSString* XPCStringConvert::sCachedString = nullptr; -// Called from GC finalize callback to make sure we don't hand out a pointer to -// a JSString that's about to be finalized by incremental sweeping. // static void -XPCStringConvert::ClearCache() +XPCStringConvert::FreeZoneCache(JS::Zone *zone) { - sCachedBuffer = nullptr; - sCachedString = nullptr; + // Put the zone user data into an AutoPtr (which will do the cleanup for us), + // and null out the user data (which may already be null). + nsAutoPtr cache(static_cast(JS_GetZoneUserData(zone))); + JS_SetZoneUserData(zone, nullptr); } +// static +void +XPCStringConvert::ClearZoneCache(JS::Zone *zone) +{ + ZoneStringCache *cache = static_cast(JS_GetZoneUserData(zone)); + if (cache) { + cache->mBuffer = nullptr; + cache->mString = nullptr; + } +} + +// static void XPCStringConvert::FinalizeDOMString(const JSStringFinalizer *fin, jschar *chars) { @@ -83,26 +88,6 @@ XPCStringConvert::ReadableToJSVal(JSContext *cx, } // blech, have to copy. - - jschar *chars = reinterpret_cast - (JS_malloc(cx, (length + 1) * - sizeof(jschar))); - if (!chars) - return JS::NullValue(); - - if (length && !CopyUnicodeTo(readable, 0, - reinterpret_cast(chars), - length)) { - JS_free(cx, chars); - return JS::NullValue(); - } - - chars[length] = 0; - - str = JS_NewUCString(cx, chars, length); - if (!str) { - JS_free(cx, chars); - } - - return str ? STRING_TO_JSVAL(str) : JSVAL_NULL; + str = JS_NewUCStringCopyN(cx, readable.BeginReading(), length); + return str ? JS::StringValue(str) : JS::NullValue(); } diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 995ac4c43cdf..8f0fcefaea84 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -149,6 +149,17 @@ xpc_ActivateDebugMode(); // readable string conversions, static methods and members only class XPCStringConvert { + // One-slot cache, because it turns out it's common for web pages to + // get the same string a few times in a row. We get about a 40% cache + // hit rate on this cache last it was measured. We'd get about 70% + // hit rate with a hashtable with removal on finalization, but that + // would take a lot more machinery. + struct ZoneStringCache + { + nsStringBuffer* mBuffer; + JSString* mString; + }; + public: // If the string shares the readable's buffer, that buffer will @@ -162,10 +173,12 @@ public: StringBufferToJSVal(JSContext* cx, nsStringBuffer* buf, uint32_t length, JS::MutableHandleValue rval, bool* sharedBuffer) { - if (buf == sCachedBuffer && - JS::GetGCThingZone(sCachedString) == js::GetContextZone(cx)) - { - rval.set(JS::StringValue(sCachedString)); + JS::Zone *zone = js::GetContextZone(cx); + ZoneStringCache *cache = static_cast(JS_GetZoneUserData(zone)); + if (cache && buf == cache->mBuffer) { + MOZ_ASSERT(JS::GetGCThingZone(cache->mString) == zone); + JS::MarkStringAsLive(zone, cache->mString); + rval.setString(cache->mString); *sharedBuffer = false; return true; } @@ -177,17 +190,20 @@ public: return false; } rval.setString(str); - sCachedString = str; - sCachedBuffer = buf; + if (!cache) { + cache = new ZoneStringCache(); + JS_SetZoneUserData(zone, cache); + } + cache->mBuffer = buf; + cache->mString = str; *sharedBuffer = true; return true; } - static void ClearCache(); + static void FreeZoneCache(JS::Zone *zone); + static void ClearZoneCache(JS::Zone *zone); private: - static nsStringBuffer* sCachedBuffer; - static JSString* sCachedString; static const JSStringFinalizer sDOMStringFinalizer; static void FinalizeDOMString(const JSStringFinalizer *fin, jschar *chars); diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 7966d965e6a4..fa237b93dd03 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -24,6 +24,7 @@ #include "GeckoProfiler.h" #include "mozilla/gfx/Tools.h" +#include "mozilla/gfx/2D.h" #include @@ -1942,6 +1943,7 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder, context = new gfxContext(surf); } #endif + basic->BeginTransaction(); basic->SetTarget(context); if (aItem->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) { @@ -2347,7 +2349,7 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer, { ThebesDisplayItemLayerUserData* thebesData = static_cast(aLayer->GetUserData(&gThebesDisplayItemLayerUserData)); - nsRefPtr tempManager; + nsRefPtr tempManager; nsIntRect intClip; bool hasClip = false; if (aLayerState != LAYER_NONE) { @@ -2417,6 +2419,7 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer, tempManager->SetRoot(layer); layerBuilder->WillEndTransaction(); + tempManager->AbortTransaction(); nsIntPoint offset = GetLastPaintOffset(aLayer) - GetTranslationForThebesLayer(aLayer); props->MoveBy(-offset); @@ -2506,13 +2509,7 @@ FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame, FrameLayerBuilder::ClippedDisplayItem::~ClippedDisplayItem() { if (mInactiveLayerManager) { - // We always start a transaction during layer construction for all inactive - // layers, but we don't necessarily call EndTransaction during painting. - // If the transaaction is still open, end it to avoid assertions. BasicLayerManager* basic = static_cast(mInactiveLayerManager.get()); - if (basic->InTransaction()) { - basic->EndTransaction(nullptr, nullptr); - } basic->SetUserData(&gLayerManagerLayerBuilder, nullptr); } } @@ -2523,7 +2520,7 @@ FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer, const DisplayItemClip& aClip, LayerState aLayerState, const nsPoint& aTopLeft, - LayerManager* aManager, + BasicLayerManager* aManager, nsAutoPtr aGeometry) { if (aLayer->Manager() != mRetainingManager) @@ -3114,6 +3111,167 @@ static void DebugPaintItem(nsRenderingContext* aDest, nsDisplayItem *aItem, nsDi } #endif +/* static */ void +FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray& aItems, + nsDisplayListBuilder *aBuilder, + const nsIntRegion& aRegionToDraw, + const nsIntPoint& aOffset, + int32_t aAppUnitsPerDevPixel, + float aXScale, + float aYScale) +{ + uint32_t i; + // Update visible regions. We need perform visibility analysis again + // because we may be asked to draw into part of a ThebesLayer that + // isn't actually visible in the window (e.g., because a ThebesLayer + // expanded its visible region to a rectangle internally), in which + // case the mVisibleRect stored in the display item may be wrong. + nsRegion visible = aRegionToDraw.ToAppUnits(aAppUnitsPerDevPixel); + visible.MoveBy(NSIntPixelsToAppUnits(aOffset.x, aAppUnitsPerDevPixel), + NSIntPixelsToAppUnits(aOffset.y, aAppUnitsPerDevPixel)); + visible.ScaleInverseRoundOut(aXScale, aYScale); + + for (i = aItems.Length(); i > 0; --i) { + ClippedDisplayItem* cdi = &aItems[i - 1]; + const DisplayItemClip& clip = cdi->mItem->GetClip(); + + NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == aAppUnitsPerDevPixel, + "a thebes layer should contain items only at the same zoom"); + + NS_ABORT_IF_FALSE(clip.HasClip() || + clip.GetRoundedRectCount() == 0, + "If we have rounded rects, we must have a clip rect"); + + if (!clip.IsRectAffectedByClip(visible.GetBounds())) { + cdi->mItem->RecomputeVisibility(aBuilder, &visible); + continue; + } + + // Do a little dance to account for the fact that we're clipping + // to cdi->mClipRect + nsRegion clipped; + clipped.And(visible, clip.NonRoundedIntersection()); + nsRegion finalClipped = clipped; + cdi->mItem->RecomputeVisibility(aBuilder, &finalClipped); + // If we have rounded clip rects, don't subtract from the visible + // region since we aren't displaying everything inside the rect. + if (clip.GetRoundedRectCount() == 0) { + nsRegion removed; + removed.Sub(clipped, finalClipped); + nsRegion newVisible; + newVisible.Sub(visible, removed); + // Don't let the visible region get too complex. + if (newVisible.GetNumRects() <= 15) { + visible = newVisible; + } + } + } +} + +void +FrameLayerBuilder::PaintItems(nsTArray& aItems, + const nsIntRect& aRect, + gfxContext *aContext, + nsRenderingContext *aRC, + nsDisplayListBuilder* aBuilder, + nsPresContext* aPresContext, + const nsIntPoint& aOffset, + float aXScale, float aYScale, + int32_t aCommonClipCount) +{ + int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel(); + nsRect boundRect = aRect.ToAppUnits(appUnitsPerDevPixel); + boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel), + NSIntPixelsToAppUnits(aOffset.y, appUnitsPerDevPixel)); + boundRect.ScaleInverseRoundOut(aXScale, aYScale); + + DisplayItemClip currentClip; + bool currentClipIsSetInContext = false; + DisplayItemClip tmpClip; + + for (uint32_t i = 0; i < aItems.Length(); ++i) { + ClippedDisplayItem* cdi = &aItems[i]; + + nsRect paintRect = cdi->mItem->GetVisibleRect().Intersect(boundRect); + if (paintRect.IsEmpty()) + continue; + + // If the new desired clip state is different from the current state, + // update the clip. + const DisplayItemClip* clip = &cdi->mItem->GetClip(); + if (clip->GetRoundedRectCount() > 0 && + !clip->IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) { + tmpClip = *clip; + tmpClip.RemoveRoundedCorners(); + clip = &tmpClip; + } + if (currentClipIsSetInContext != clip->HasClip() || + (clip->HasClip() && *clip != currentClip)) { + if (currentClipIsSetInContext) { + aContext->Restore(); + } + currentClipIsSetInContext = clip->HasClip(); + if (currentClipIsSetInContext) { + currentClip = *clip; + aContext->Save(); + NS_ASSERTION(aCommonClipCount < 100, + "Maybe you really do have more than a hundred clipping rounded rects, or maybe something has gone wrong."); + currentClip.ApplyTo(aContext, aPresContext, aCommonClipCount); + aContext->NewPath(); + } + } + + if (cdi->mInactiveLayerManager) { + PaintInactiveLayer(aBuilder, cdi->mInactiveLayerManager, cdi->mItem, aContext, aRC); + } else { + nsIFrame* frame = cdi->mItem->Frame(); + frame->AddStateBits(NS_FRAME_PAINTED_THEBES); +#ifdef MOZ_DUMP_PAINTING + + if (gfxUtils::sDumpPainting) { + DebugPaintItem(aRC, cdi->mItem, aBuilder); + } else { +#else + { +#endif + cdi->mItem->Paint(aBuilder, aRC); + } + } + + if (CheckDOMModified()) + break; + } + + if (currentClipIsSetInContext) { + aContext->Restore(); + } +} + +/** + * Returns true if it is preferred to draw the list of display + * items separately for each rect in the visible region rather + * than clipping to a complex region. + */ +static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip) +{ + if (aContext->IsCairo() || aClip == CLIP_NONE) { + return false; + } + DrawTarget *dt = aContext->GetDrawTarget(); + return dt->GetType() == BACKEND_DIRECT2D; +} + +static void DrawForcedBackgroundColor(gfxContext* aContext, Layer* aLayer, nscolor aBackgroundColor) +{ + if (NS_GET_A(aBackgroundColor) > 0) { + nsIntRect r = aLayer->GetVisibleRegion().GetBounds(); + aContext->NewPath(); + aContext->Rectangle(gfxRect(r.x, r.y, r.width, r.height)); + aContext->SetColor(gfxRGBA(aBackgroundColor)); + aContext->Fill(); + } +} + /* * A note on residual transforms: * @@ -3146,6 +3304,7 @@ static void DebugPaintItem(nsRenderingContext* aDest, nsDisplayItem *aItem, nsDi FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, gfxContext* aContext, const nsIntRegion& aRegionToDraw, + DrawRegionClip aClip, const nsIntRegion& aRegionToInvalidate, void* aCallbackData) { @@ -3160,163 +3319,77 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, if (layerBuilder->CheckDOMModified()) return; - nsTArray items; - uint32_t commonClipCount; - nsIFrame* containerLayerFrame; - { - ThebesLayerItemsEntry* entry = layerBuilder->mThebesLayerItems.GetEntry(aLayer); - NS_ASSERTION(entry, "We shouldn't be drawing into a layer with no items!"); - items.SwapElements(entry->mItems); - commonClipCount = entry->mCommonClipCount; - containerLayerFrame = entry->mContainerLayerFrame; - // Later after this point, due to calls to DidEndTransaction - // for temporary layer managers, mThebesLayerItems can change, - // so 'entry' could become invalid. - } - - if (!containerLayerFrame) { + ThebesLayerItemsEntry* entry = layerBuilder->mThebesLayerItems.GetEntry(aLayer); + NS_ASSERTION(entry, "We shouldn't be drawing into a layer with no items!"); + if (!entry->mContainerLayerFrame) { return; } + ThebesDisplayItemLayerUserData* userData = static_cast (aLayer->GetUserData(&gThebesDisplayItemLayerUserData)); NS_ASSERTION(userData, "where did our user data go?"); - if (NS_GET_A(userData->mForcedBackgroundColor) > 0) { - nsIntRect r = aLayer->GetVisibleRegion().GetBounds(); - aContext->NewPath(); - aContext->Rectangle(gfxRect(r.x, r.y, r.width, r.height)); - aContext->SetColor(gfxRGBA(userData->mForcedBackgroundColor)); - aContext->Fill(); + + bool shouldDrawRectsSeparately = ShouldDrawRectsSeparately(aContext, aClip); + + if (!shouldDrawRectsSeparately) { + if (aClip == CLIP_DRAW_SNAPPED) { + gfxUtils::ClipToRegionSnapped(aContext, aRegionToDraw); + } else if (aClip == CLIP_DRAW) { + gfxUtils::ClipToRegion(aContext, aRegionToDraw); + } + + DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor); } // make the origin of the context coincide with the origin of the // ThebesLayer gfxContextMatrixAutoSaveRestore saveMatrix(aContext); nsIntPoint offset = GetTranslationForThebesLayer(aLayer); - // Apply the residual transform if it has been enabled, to ensure that - // snapping when we draw into aContext exactly matches the ideal transform. - // See above for why this is OK. - aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y)); - aContext->Scale(userData->mXScale, userData->mYScale); - nsPresContext* presContext = containerLayerFrame->PresContext(); + nsPresContext* presContext = entry->mContainerLayerFrame->PresContext(); int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); - uint32_t i; - // Update visible regions. We need perform visibility analysis again - // because we may be asked to draw into part of a ThebesLayer that - // isn't actually visible in the window (e.g., because a ThebesLayer - // expanded its visible region to a rectangle internally), in which - // case the mVisibleRect stored in the display item may be wrong. - nsRegion visible = aRegionToDraw.ToAppUnits(appUnitsPerDevPixel); - visible.MoveBy(NSIntPixelsToAppUnits(offset.x, appUnitsPerDevPixel), - NSIntPixelsToAppUnits(offset.y, appUnitsPerDevPixel)); - visible.ScaleInverseRoundOut(userData->mXScale, userData->mYScale); - - for (i = items.Length(); i > 0; --i) { - ClippedDisplayItem* cdi = &items[i - 1]; - const DisplayItemClip& clip = cdi->mItem->GetClip(); - - NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == appUnitsPerDevPixel, - "a thebes layer should contain items only at the same zoom"); - - NS_ABORT_IF_FALSE(clip.HasClip() || - clip.GetRoundedRectCount() == 0, - "If we have rounded rects, we must have a clip rect"); - - if (!clip.IsRectAffectedByClip(visible.GetBounds())) { - cdi->mItem->RecomputeVisibility(builder, &visible); - continue; - } - - // Do a little dance to account for the fact that we're clipping - // to cdi->mClipRect - nsRegion clipped; - clipped.And(visible, clip.NonRoundedIntersection()); - nsRegion finalClipped = clipped; - cdi->mItem->RecomputeVisibility(builder, &finalClipped); - // If we have rounded clip rects, don't subtract from the visible - // region since we aren't displaying everything inside the rect. - if (clip.GetRoundedRectCount() == 0) { - nsRegion removed; - removed.Sub(clipped, finalClipped); - nsRegion newVisible; - newVisible.Sub(visible, removed); - // Don't let the visible region get too complex. - if (newVisible.GetNumRects() <= 15) { - visible = newVisible; - } - } - } + RecomputeVisibilityForItems(entry->mItems, builder, aRegionToDraw, + offset, appUnitsPerDevPixel, + userData->mXScale, userData->mYScale); nsRefPtr rc = new nsRenderingContext(); rc->Init(presContext->DeviceContext(), aContext); - DisplayItemClip currentClip; - bool currentClipIsSetInContext = false; - DisplayItemClip tmpClip; + if (shouldDrawRectsSeparately) { + nsIntRegionRectIterator it(aRegionToDraw); + while (const nsIntRect* iterRect = it.Next()) { + gfxContextAutoSaveRestore save(aContext); + aContext->NewPath(); + aContext->Rectangle(*iterRect, aClip == CLIP_DRAW_SNAPPED); + aContext->Clip(); - for (i = 0; i < items.Length(); ++i) { - ClippedDisplayItem* cdi = &items[i]; + DrawForcedBackgroundColor(aContext, aLayer, userData->mForcedBackgroundColor); - if (cdi->mItem->GetVisibleRect().IsEmpty()) - continue; + // Apply the residual transform if it has been enabled, to ensure that + // snapping when we draw into aContext exactly matches the ideal transform. + // See above for why this is OK. + aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y)); + aContext->Scale(userData->mXScale, userData->mYScale); - // If the new desired clip state is different from the current state, - // update the clip. - const DisplayItemClip* clip = &cdi->mItem->GetClip(); - if (clip->GetRoundedRectCount() > 0 && - !clip->IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) { - tmpClip = *clip; - tmpClip.RemoveRoundedCorners(); - clip = &tmpClip; - } - if (currentClipIsSetInContext != clip->HasClip() || - (clip->HasClip() && *clip != currentClip)) { - if (currentClipIsSetInContext) { - aContext->Restore(); - } - currentClipIsSetInContext = clip->HasClip(); - if (currentClipIsSetInContext) { - currentClip = *clip; - aContext->Save(); - NS_ASSERTION(commonClipCount < 100, - "Maybe you really do have more than a hundred clipping rounded rects, or maybe something has gone wrong."); - currentClip.ApplyTo(aContext, presContext, commonClipCount); - aContext->NewPath(); - } + layerBuilder->PaintItems(entry->mItems, *iterRect, aContext, rc, + builder, presContext, + offset, userData->mXScale, userData->mYScale, + entry->mCommonClipCount); } + } else { + // Apply the residual transform if it has been enabled, to ensure that + // snapping when we draw into aContext exactly matches the ideal transform. + // See above for why this is OK. + aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y)); + aContext->Scale(userData->mXScale, userData->mYScale); - if (cdi->mInactiveLayerManager) { - PaintInactiveLayer(builder, cdi->mInactiveLayerManager, cdi->mItem, aContext, rc); - } else { - nsIFrame* frame = cdi->mItem->Frame(); - frame->AddStateBits(NS_FRAME_PAINTED_THEBES); -#ifdef MOZ_DUMP_PAINTING - - if (gfxUtils::sDumpPainting) { - DebugPaintItem(rc, cdi->mItem, builder); - } else { -#else - { -#endif - cdi->mItem->Paint(builder, rc); - } - } - - if (layerBuilder->CheckDOMModified()) - break; - } - - { - ThebesLayerItemsEntry* entry = - layerBuilder->mThebesLayerItems.GetEntry(aLayer); - items.SwapElements(entry->mItems); - } - - if (currentClipIsSetInContext) { - aContext->Restore(); + layerBuilder->PaintItems(entry->mItems, aRegionToDraw.GetBounds(), aContext, rc, + builder, presContext, + offset, userData->mXScale, userData->mYScale, + entry->mCommonClipCount); } if (presContext->GetPaintFlashing()) { diff --git a/layout/base/FrameLayerBuilder.h b/layout/base/FrameLayerBuilder.h index 04b01955cd8f..9ea239215b42 100644 --- a/layout/base/FrameLayerBuilder.h +++ b/layout/base/FrameLayerBuilder.h @@ -24,6 +24,7 @@ namespace mozilla { namespace layers { class ContainerLayer; class LayerManager; +class BasicLayerManager; class ThebesLayer; } @@ -95,6 +96,7 @@ public: typedef layers::ThebesLayer ThebesLayer; typedef layers::ImageLayer ImageLayer; typedef layers::LayerManager LayerManager; + typedef layers::BasicLayerManager BasicLayerManager; FrameLayerBuilder() : mRetainingManager(nullptr), @@ -242,6 +244,7 @@ public: static void DrawThebesLayer(ThebesLayer* aLayer, gfxContext* aContext, const nsIntRegion& aRegionToDraw, + mozilla::layers::DrawRegionClip aClip, const nsIntRegion& aRegionToInvalidate, void* aCallbackData); @@ -273,7 +276,7 @@ public: const DisplayItemClip& aClip, LayerState aLayerState, const nsPoint& aTopLeft, - LayerManager* aManager, + BasicLayerManager* aManager, nsAutoPtr aGeometry); /** @@ -420,7 +423,7 @@ public: LayerManagerData* mParent; nsRefPtr mLayer; nsRefPtr mOptLayer; - nsRefPtr mInactiveManager; + nsRefPtr mInactiveManager; nsAutoTArray mFrameList; nsAutoPtr mGeometry; DisplayItemClip mClip; @@ -518,6 +521,24 @@ protected: uint32_t mContainerLayerGeneration; }; + static void RecomputeVisibilityForItems(nsTArray& aItems, + nsDisplayListBuilder* aBuilder, + const nsIntRegion& aRegionToDraw, + const nsIntPoint& aOffset, + int32_t aAppUnitsPerDevPixel, + float aXScale, + float aYScale); + + void PaintItems(nsTArray& aItems, + const nsIntRect& aRect, + gfxContext* aContext, + nsRenderingContext* aRC, + nsDisplayListBuilder* aBuilder, + nsPresContext* aPresContext, + const nsIntPoint& aOffset, + float aXScale, float aYScale, + int32_t aCommonClipCount); + /** * We accumulate ClippedDisplayItem elements in a hashtable during * the paint process. This is the hashentry for that hashtable. diff --git a/python/mozboot/mozboot/osx.py b/python/mozboot/mozboot/osx.py index bfe2965a94ea..94182750a03d 100644 --- a/python/mozboot/mozboot/osx.py +++ b/python/mozboot/mozboot/osx.py @@ -27,7 +27,7 @@ MACPORTS_URL = {'8': 'https://distfiles.macports.org/MacPorts/MacPorts-2.1.3-10. '7': 'https://distfiles.macports.org/MacPorts/MacPorts-2.1.3-10.7-Lion.pkg', '6': 'https://distfiles.macports.org/MacPorts/MacPorts-2.1.3-10.6-SnowLeopard.pkg',} -MACPORTS_CLANG_PACKAGE = 'clang-3.2' +MACPORTS_CLANG_PACKAGE = 'clang-3.3' RE_CLANG_VERSION = re.compile('Apple (?:clang|LLVM) version (\d+\.\d+)') diff --git a/testing/marionette/client/marionette/runtests.py b/testing/marionette/client/marionette/runtests.py index a982933b13a2..0fe9353092b4 100644 --- a/testing/marionette/client/marionette/runtests.py +++ b/testing/marionette/client/marionette/runtests.py @@ -19,12 +19,26 @@ from manifestparser import TestManifest from mozhttpd import MozHttpd from marionette import Marionette -from moztest.results import TestResultCollection +from moztest.results import TestResultCollection, TestResult, relevant_line from marionette_test import MarionetteJSTestCase, MarionetteTestCase +class MarionetteTest(TestResult): + + @property + def test_name(self): + if self.test_class is not None: + return '%s.py %s.%s' % (self.test_class.split('.')[0], + self.test_class, + self.name) + else: + return self.name + + class MarionetteTestResult(unittest._TextTestResult, TestResultCollection): + resultClass = MarionetteTest + def __init__(self, *args, **kwargs): self.marionette = kwargs.pop('marionette') TestResultCollection.__init__(self, 'MarionetteTest') @@ -83,10 +97,25 @@ class MarionetteTestResult(unittest._TextTestResult, TestResultCollection): else: return 0 - def add_test_result(self, test, *args, **kwargs): - self.add_result(test, *args, **kwargs) - self[-1].time_start = test.start_time - self[-1].time_end = time.time() if test.start_time else 0 + def add_test_result(self, test, result_expected='PASS', + result_actual='PASS', output='', context=None, **kwargs): + def get_class(test): + return test.__class__.__module__ + '.' + test.__class__.__name__ + + name = str(test).split()[0] + test_class = get_class(test) + if hasattr(test, 'jsFile'): + name = os.path.basename(test.jsFile) + test_class = None + + t = self.resultClass(name=name, test_class=test_class, + time_start=test.start_time, result_expected=result_expected, + context=context, **kwargs) + t.finish(result_actual, + time_end=time.time() if test.start_time else 0, + reason=relevant_line(output), + output=output) + self.append(t) def addError(self, test, err): self.add_test_result(test, output=self._exc_info_to_string(err, test), result_actual='ERROR') diff --git a/toolkit/components/alerts/nsIAlertsService.idl b/toolkit/components/alerts/nsIAlertsService.idl index 82fc94c8ee91..836c88d9ea55 100644 --- a/toolkit/components/alerts/nsIAlertsService.idl +++ b/toolkit/components/alerts/nsIAlertsService.idl @@ -24,9 +24,7 @@ interface nsIAlertsService : nsISupports * @param alertListener Used for callbacks. May be null if the caller * doesn't care about callbacks. * @param name The name of the notification. This is currently - * only used on OS X with Growl and Android. - * On OS X with Growl, users can disable notifications - * with a given name. On Android the name is hashed + * only used on Android. On Android the name is hashed * and used as a notification ID. Notifications will * replace previous notifications with the same name. * @param dir Bidi override for the title. Valid values are diff --git a/toolkit/components/alerts/test/test_alerts.html b/toolkit/components/alerts/test/test_alerts.html index 7ebef2008c46..431f0d76749b 100644 --- a/toolkit/components/alerts/test/test_alerts.html +++ b/toolkit/components/alerts/test/test_alerts.html @@ -53,7 +53,7 @@ function runTest() { ok(true, "Alerts service is available"); } catch (ex) { todo(false, - "Alerts service is not available. (Mac OS X without Growl?)", ex); + "Alerts service is not available.", ex); return; } @@ -64,7 +64,7 @@ function runTest() { false, "foobarcookie", observer); ok(true, "showAlertNotification() succeeded. Waiting for notification..."); } catch (ex) { - todo(false, "showAlertNotification() failed. (Mac OS X without Growl?)", ex); + todo(false, "showAlertNotification() failed.", ex); SimpleTest.finish(); } } diff --git a/toolkit/components/alerts/test/test_alerts_noobserve.html b/toolkit/components/alerts/test/test_alerts_noobserve.html index db235bff8545..fa903a060a44 100644 --- a/toolkit/components/alerts/test/test_alerts_noobserve.html +++ b/toolkit/components/alerts/test/test_alerts_noobserve.html @@ -35,7 +35,7 @@ if (!("@mozilla.org/alerts-service;1" in Cc)) { getService(Ci.nsIAlertsService); ok(true, "Alerts service is available"); } catch (ex) { - todo(false, "Alerts service is not available. (Mac OS X without Growl?)", ex); + todo(false, "Alerts service is not available.", ex); } if (notifier) { @@ -46,7 +46,7 @@ if (!("@mozilla.org/alerts-service;1" in Cc)) { gNotificationIsAvailable = true; } catch (ex) { - todo(false, "showAlertNotification() failed. (Mac OS X without Growl?)", ex); + todo(false, "showAlertNotification() failed.", ex); } } } diff --git a/toolkit/content/license.html b/toolkit/content/license.html index f0cbdeb3cc5d..812179e94d9c 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -83,7 +83,6 @@
  • Google Gears License
  • Google Gears/iStumbler License
  • Google VP8 License
  • -
  • Growl License
  • gyp License
  • halloc License
  • HarfBuzz License
  • @@ -2260,48 +2259,7 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -
    -

    Growl License

    - -

    This license applies to certain files in the directory - toolkit/components/alerts/mac/growl/. - (This code only ships in the Mac OS X version of the product.) - -

    -Copyright (c) The Growl Project, 2004-2011
    -All rights reserved.
    -
    -Redistribution and use in source and binary forms, with or without
    -modification, are permitted provided that the following conditions are met:
    -
    -
    -1. Redistributions of source code must retain the above copyright
    -   notice, this list of conditions and the following disclaimer.
    -2. Redistributions in binary form must reproduce the above copyright
    -   notice, this list of conditions and the following disclaimer in the
    -   documentation and/or other materials provided with the distribution.
    -3. Neither the name of Growl nor the names of its contributors
    -   may be used to endorse or promote products derived from this software
    -   without specific prior written permission.
    -
    -
    -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    -
    - - -
    -

    gyp License

    diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index f5563c5d1b56..1956832e0245 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -452,6 +452,8 @@ CycleCollectedJSRuntime::CycleCollectedJSRuntime(uint32_t aMaxbytes, JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this); JS_SetGCCallback(mJSRuntime, GCCallback, this); JS_SetContextCallback(mJSRuntime, ContextCallback, this); + JS_SetDestroyZoneCallback(mJSRuntime, XPCStringConvert::FreeZoneCache); + JS_SetSweepZoneCallback(mJSRuntime, XPCStringConvert::ClearZoneCache); nsCycleCollector_registerJSRuntime(this); }