diff --git a/browser/fuel/src/fuelApplication.js b/browser/fuel/src/fuelApplication.js index c7b0c9a067cd..623694bb7660 100644 --- a/browser/fuel/src/fuelApplication.js +++ b/browser/fuel/src/fuelApplication.js @@ -20,6 +20,12 @@ var Utilities = { return this.bookmarks; }, + get bookmarksObserver() { + let bookmarksObserver = new BookmarksObserver(); + this.__defineGetter__("bookmarksObserver", function() bookmarksObserver); + return this.bookmarksObserver; + }, + get livemarks() { let livemarks = Cc["@mozilla.org/browser/livemark-service;2"]. getService[Ci.mozIAsyncLivemarks]. @@ -49,15 +55,16 @@ var Utilities = { return this.windowMediator; }, - makeURI : function(aSpec) { + makeURI: function fuelutil_makeURI(aSpec) { if (!aSpec) return null; var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); return ios.newURI(aSpec, null, null); }, - free : function() { + free: function fuelutil_free() { delete this.bookmarks; + delete this.bookmarksObserver; delete this.livemarks delete this.annotations; delete this.history; @@ -68,19 +75,26 @@ var Utilities = { //================================================= // Window implementation + +var fuelWindowMap = new WeakMap(); +function getWindow(aWindow) { + let fuelWindow = fuelWindowMap.get(aWindow); + if (!fuelWindow) { + fuelWindow = new Window(aWindow); + fuelWindowMap.set(aWindow, fuelWindow); + } + return fuelWindow; +} + +// Don't call new Window() directly; use getWindow instead. function Window(aWindow) { this._window = aWindow; - this._tabbrowser = aWindow.getBrowser(); this._events = new Events(); - this._cleanup = {}; this._watch("TabOpen"); this._watch("TabMove"); this._watch("TabClose"); this._watch("TabSelect"); - - var self = this; - gShutdown.push(function() { self._shutdown(); }); } Window.prototype = { @@ -88,65 +102,75 @@ Window.prototype = { return this._events; }, + get _tabbrowser() { + return this._window.getBrowser(); + }, + /* * Helper used to setup event handlers on the XBL element. Note that the events * are actually dispatched to tabs, so we capture them. */ - _watch : function win_watch(aType) { - var self = this; - this._tabbrowser.tabContainer.addEventListener(aType, - this._cleanup[aType] = function(e){ self._event(e); }, - true); + _watch: function win_watch(aType) { + this._tabbrowser.tabContainer.addEventListener(aType, this, + /* useCapture = */ true); }, - /* - * Helper event callback used to redirect events made on the XBL element - */ - _event : function win_event(aEvent) { - this._events.dispatch(aEvent.type, new BrowserTab(this, aEvent.originalTarget.linkedBrowser)); + handleEvent: function win_handleEvent(aEvent) { + this._events.dispatch(aEvent.type, getBrowserTab(this, aEvent.originalTarget.linkedBrowser)); }, + get tabs() { var tabs = []; var browsers = this._tabbrowser.browsers; for (var i=0; i lProcesses = aMgr.getRunningAppProcesses(); int lcv = 0; - String strProcName = ""; - int nPID = 0; + String sFoundProcName = ""; int nProcs = 0; + boolean bFoundAppProcess = false; - if (lProcesses != null) + if (lProcesses != null) nProcs = lProcesses.size(); for (lcv = 0; lcv < nProcs; lcv++) { if (lProcesses.get(lcv).processName.contains(sProcName)) { - strProcName = lProcesses.get(lcv).processName; - nPID = lProcesses.get(lcv).pid; - sRet = sErrorPrefix + "Failed to kill " + nPID + " " + strProcName + "\n"; - - sCmd += " " + nPID; + sFoundProcName = lProcesses.get(lcv).processName; + bFoundAppProcess = true; try { - pProc = Runtime.getRuntime().exec(this.getSuArgs(sCmd)); + pProc = Runtime.getRuntime().exec(this.getSuArgs("kill " + lProcesses.get(lcv).pid)); RedirOutputThread outThrd = new RedirOutputThread(pProc, null); outThrd.start(); outThrd.join(15000); - sTmp = outThrd.strOutput; + String sTmp = outThrd.strOutput; Log.e("KILLPROCESS", sTmp); - if (outThrd.nExitCode == 0) { - sRet = "Successfully killed " + nPID + " " + strProcName + "\n"; - nPID = 0; - break; - } else { - sRet = sErrorPrefix + "Failed to kill " + nPID + " " + strProcName + "\n"; - } } catch (IOException e) { @@ -2429,31 +2416,30 @@ private void CancelNotification() { e.printStackTrace(); } - - // Give the messages a chance to be processed - try { - Thread.sleep(2000); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - break; } } - if (nPID > 0) + if (bFoundAppProcess) { - sRet = "Successfully killed " + nPID + " " + strProcName + "\n"; + // Give the messages a chance to be processed + try { + Thread.sleep(2000); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + + sRet = "Successfully killed " + sProcName + "\n"; lProcesses = aMgr.getRunningAppProcesses(); nProcs = 0; - if (lProcesses != null) + if (lProcesses != null) nProcs = lProcesses.size(); for (lcv = 0; lcv < nProcs; lcv++) { if (lProcesses.get(lcv).processName.contains(sProcName)) { - sRet = sErrorPrefix + "Unable to kill " + nPID + " " + strProcName + "\n"; + sRet = sErrorPrefix + "Unable to kill " + sProcName + " (couldn't kill " + sFoundProcName +")\n"; break; } } @@ -2469,7 +2455,7 @@ private void CancelNotification() RedirOutputThread outThrd = new RedirOutputThread(pProc, null); outThrd.start(); outThrd.join(10000); - sTmp = outThrd.strOutput; + String sTmp = outThrd.strOutput; StringTokenizer stokLines = new StringTokenizer(sTmp, "\n"); while(stokLines.hasMoreTokens()) { @@ -2490,7 +2476,7 @@ private void CancelNotification() if (sName.contains(sProcName)) { NewKillProc(sPid, out); - sRet = "Successfully killed " + sPid + " " + sName + "\n"; + sRet = "Successfully killed " + sName + "\n"; } } } diff --git a/content/base/src/FileIOObject.cpp b/content/base/src/FileIOObject.cpp index 51f9f6c54fd1..10386c9541ca 100644 --- a/content/base/src/FileIOObject.cpp +++ b/content/base/src/FileIOObject.cpp @@ -38,6 +38,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FileIOObject, NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(abort) NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error) NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(progress) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mError) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileIOObject, @@ -46,6 +47,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FileIOObject, NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(abort) NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error) NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(progress) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mError) NS_IMPL_CYCLE_COLLECTION_UNLINK_END FileIOObject::FileIOObject() diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index 3d829c265919..18ce572f3681 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -1160,31 +1160,6 @@ PR_STATIC_ASSERT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32); return SetAttrHelper(nsGkAtoms::_atom, aValue); \ } -/** - * A macro to implement the getter and setter for a given content - * property that needs to set a positive integer. The method uses - * the generic GetAttr and SetAttr methods. This macro is much like - * the NS_IMPL_NON_NEGATIVE_INT_ATTR macro except the exception is - * thrown also when the value is equal to 0. - */ -#define NS_IMPL_POSITIVE_INT_ATTR(_class, _method, _atom) \ - NS_IMPL_POSITIVE_INT_ATTR_DEFAULT_VALUE(_class, _method, _atom, 1) - -#define NS_IMPL_POSITIVE_INT_ATTR_DEFAULT_VALUE(_class, _method, _atom, _default) \ - NS_IMETHODIMP \ - _class::Get##_method(PRInt32* aValue) \ - { \ - return GetIntAttr(nsGkAtoms::_atom, _default, aValue); \ - } \ - NS_IMETHODIMP \ - _class::Set##_method(PRInt32 aValue) \ - { \ - if (aValue <= 0) { \ - return NS_ERROR_DOM_INDEX_SIZE_ERR; \ - } \ - return SetIntAttr(nsGkAtoms::_atom, aValue); \ - } - /** * QueryInterface() implementation helper macros */ diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 39b6caa790e1..58e685e78fe3 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -8046,6 +8046,23 @@ private: bool mFirstParty; }; +/** + * Returns true if we started an asynchronous load (i.e., from the network), but + * the document we're loading there hasn't yet become this docshell's active + * document. + * + * When JustStartedNetworkLoad is true, you should be careful about modifying + * mLoadType and mLSHE. These are both set when the asynchronous load first + * starts, and the load expects that, when it eventually runs InternalLoad, + * mLoadType and mLSHE will have their original values. + */ +bool +nsDocShell::JustStartedNetworkLoad() +{ + return mDocumentRequest && + mDocumentRequest != GetCurrentDocChannel(); +} + NS_IMETHODIMP nsDocShell::InternalLoad(nsIURI * aURI, nsIURI * aReferrer, @@ -8462,7 +8479,16 @@ nsDocShell::InternalLoad(nsIURI * aURI, // See bug 737307. AutoRestore loadTypeResetter(mLoadType); - mLoadType = aLoadType; + // If a non-short-circuit load (i.e., a network load) is pending, + // make this a replacement load, so that we don't add a SHEntry here + // and the network load goes into the SHEntry it expects to. + if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) { + mLoadType = LOAD_NORMAL_REPLACE; + } + else { + mLoadType = aLoadType; + } + mURIResultedInDocument = true; /* we need to assign mLSHE to aSHEntry right here, so that on History loads, @@ -9662,6 +9688,16 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle, nsresult rv; + // Don't clobber the load type of an existing network load. + AutoRestore loadTypeResetter(mLoadType); + + // pushState effectively becomes replaceState when we've started a network + // load but haven't adopted its document yet. This mirrors what we do with + // changes to the hash at this stage of the game. + if (JustStartedNetworkLoad()) { + aReplace = true; + } + nsCOMPtr document = do_GetInterface(GetAsSupports(this)); NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index ca7992e4309e..83e7b0533499 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -660,6 +660,8 @@ protected: nsRefPtr mDocShell; }; + bool JustStartedNetworkLoad(); + // hash of session storages, keyed by domain nsInterfaceHashtable mStorages; diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index a850522eb8fd..a65b82125f43 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -7455,7 +7455,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // binding a name) a new undefined property that's not already // defined on our prototype chain. This way we can access this // expando w/o ever getting back into XPConnect. - if ((flags & JSRESOLVE_ASSIGNING) && !(flags & JSRESOLVE_WITH)) { + if (flags & JSRESOLVE_ASSIGNING) { JSObject *realObj; wrapper->GetJSObject(&realObj); diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 47eb001e19c3..7496cda91ef0 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8992,7 +8992,175 @@ nsGlobalWindow::SetTimeoutOrInterval(bool aIsInterval, PRInt32 *aReturn) return SetTimeoutOrInterval(handler, interval, isInterval, aReturn); } -// static +bool +nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout, + nsIScriptContext* aScx) +{ + // Hold on to the timeout in case mExpr or mFunObj releases its + // doc. + nsRefPtr timeout = aTimeout; + nsTimeout* last_running_timeout = mRunningTimeout; + mRunningTimeout = timeout; + timeout->mRunning = true; + + // Push this timeout's popup control state, which should only be + // eabled the first time a timeout fires that was created while + // popups were enabled and with a delay less than + // "dom.disable_open_click_delay". + nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState); + + // Clear the timeout's popup state, if any, to prevent interval + // timeouts from repeatedly opening poups. + timeout->mPopupState = openAbused; + + ++gRunningTimeoutDepth; + ++mTimeoutFiringDepth; + + bool trackNestingLevel = !timeout->mIsInterval; + PRUint32 nestingLevel; + if (trackNestingLevel) { + nestingLevel = sNestingLevel; + sNestingLevel = timeout->mNestingLevel; + } + + nsCOMPtr handler(timeout->mScriptHandler); + JSObject* scriptObject = handler->GetScriptObject(); + if (!scriptObject) { + // Evaluate the timeout expression. + const PRUnichar* script = handler->GetHandlerText(); + NS_ASSERTION(script, "timeout has no script nor handler text!"); + + const char* filename = nsnull; + PRUint32 lineNo = 0; + handler->GetLocation(&filename, &lineNo); + + NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo); + + bool is_undefined; + aScx->EvaluateString(nsDependentString(script), FastGetGlobalJSObject(), + timeout->mPrincipal, timeout->mPrincipal, + filename, lineNo, JSVERSION_DEFAULT, nsnull, + &is_undefined); + } else { + nsCOMPtr dummy; + nsCOMPtr me(static_cast(this)); + aScx->CallEventHandler(me, FastGetGlobalJSObject(), + scriptObject, handler->GetArgv(), + // XXXmarkh - consider allowing CallEventHandler to + // accept nsnull? + getter_AddRefs(dummy)); + + } + + // We ignore any failures from calling EvaluateString() or + // CallEventHandler() on the context here since we're in a loop + // where we're likely to be running timeouts whose OS timers + // didn't fire in time and we don't want to not fire those timers + // now just because execution of one timer failed. We can't + // propagate the error to anyone who cares about it from this + // point anyway, and the script context should have already reported + // the script error in the usual way - so we just drop it. + + if (trackNestingLevel) { + sNestingLevel = nestingLevel; + } + + --mTimeoutFiringDepth; + --gRunningTimeoutDepth; + + mRunningTimeout = last_running_timeout; + timeout->mRunning = false; + return timeout->mCleared; +} + +bool +nsGlobalWindow::RescheduleTimeout(nsTimeout* aTimeout, const TimeStamp& now, + bool aRunningPendingTimeouts) +{ + if (!aTimeout->mIsInterval) { + if (aTimeout->mTimer) { + // The timeout still has an OS timer, and it's not an interval, + // that means that the OS timer could still fire; cancel the OS + // timer and release its reference to the timeout. + aTimeout->mTimer->Cancel(); + aTimeout->mTimer = nsnull; + aTimeout->Release(); + } + return false; + } + + // Compute time to next timeout for interval timer. + // Make sure nextInterval is at least DOMMinTimeoutValue(). + TimeDuration nextInterval = + TimeDuration::FromMilliseconds(NS_MAX(aTimeout->mInterval, + PRUint32(DOMMinTimeoutValue()))); + + // If we're running pending timeouts, set the next interval to be + // relative to "now", and not to when the timeout that was pending + // should have fired. + TimeStamp firingTime; + if (aRunningPendingTimeouts) { + firingTime = now + nextInterval; + } else { + firingTime = aTimeout->mWhen + nextInterval; + } + + TimeStamp currentNow = TimeStamp::Now(); + TimeDuration delay = firingTime - currentNow; + + // And make sure delay is nonnegative; that might happen if the timer + // thread is firing our timers somewhat early or if they're taking a long + // time to run the callback. + if (delay < TimeDuration(0)) { + delay = TimeDuration(0); + } + + if (!aTimeout->mTimer) { + NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth, + "How'd our timer end up null if we're not frozen or " + "suspended?"); + + aTimeout->mTimeRemaining = delay; + return true; + } + + aTimeout->mWhen = currentNow + delay; + + // Reschedule the OS timer. Don't bother returning any error codes if + // this fails since the callers of this method don't care about them. + + // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed + // PRTime to make the division do the right thing on 64-bit + // platforms whether delay is positive or negative (which we + // know is always positive here, but cast anyways for + // consistency). + nsresult rv = aTimeout->mTimer-> + InitWithFuncCallback(TimerCallback, aTimeout, + delay.ToMilliseconds(), + nsITimer::TYPE_ONE_SHOT); + + if (NS_FAILED(rv)) { + NS_ERROR("Error initializing timer for DOM timeout!"); + + // We failed to initialize the new OS timer, this timer does + // us no good here so we just cancel it (just in case) and + // null out the pointer to the OS timer, this will release the + // OS timer. As we continue executing the code below we'll end + // up deleting the timeout since it's not an interval timeout + // any more (since timeout->mTimer == nsnull). + aTimeout->mTimer->Cancel(); + aTimeout->mTimer = nsnull; + + // Now that the OS timer no longer has a reference to the + // timeout we need to drop that reference. + aTimeout->Release(); + + return false; + } + + return true; +} + void nsGlobalWindow::RunTimeout(nsTimeout *aTimeout) { @@ -9133,90 +9301,8 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout) } // This timeout is good to run - nsTimeout *last_running_timeout = mRunningTimeout; - mRunningTimeout = timeout; - timeout->mRunning = true; ++timeoutsRan; - - // Push this timeout's popup control state, which should only be - // eabled the first time a timeout fires that was created while - // popups were enabled and with a delay less than - // "dom.disable_open_click_delay". - nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState); - - // Clear the timeout's popup state, if any, to prevent interval - // timeouts from repeatedly opening poups. - timeout->mPopupState = openAbused; - - // Hold on to the timeout in case mExpr or mFunObj releases its - // doc. - timeout->AddRef(); - - ++gRunningTimeoutDepth; - ++mTimeoutFiringDepth; - - bool trackNestingLevel = !timeout->mIsInterval; - PRUint32 nestingLevel; - if (trackNestingLevel) { - nestingLevel = sNestingLevel; - sNestingLevel = timeout->mNestingLevel; - } - - nsCOMPtr handler(timeout->mScriptHandler); - JSObject* scriptObject = handler->GetScriptObject(); - if (!scriptObject) { - // Evaluate the timeout expression. - const PRUnichar *script = handler->GetHandlerText(); - NS_ASSERTION(script, "timeout has no script nor handler text!"); - - const char *filename = nsnull; - PRUint32 lineNo = 0; - handler->GetLocation(&filename, &lineNo); - - NS_TIME_FUNCTION_MARK("(file: %s, line: %d)", filename, lineNo); - - bool is_undefined; - scx->EvaluateString(nsDependentString(script), FastGetGlobalJSObject(), - timeout->mPrincipal, timeout->mPrincipal, - filename, lineNo, JSVERSION_DEFAULT, nsnull, - &is_undefined); - } else { - nsCOMPtr dummy; - nsCOMPtr me(static_cast(this)); - scx->CallEventHandler(me, FastGetGlobalJSObject(), - scriptObject, handler->GetArgv(), - // XXXmarkh - consider allowing CallEventHandler to - // accept nsnull? - getter_AddRefs(dummy)); - - } - handler = nsnull; // drop reference before dropping timeout refs. - - if (trackNestingLevel) { - sNestingLevel = nestingLevel; - } - - --mTimeoutFiringDepth; - --gRunningTimeoutDepth; - - mRunningTimeout = last_running_timeout; - timeout->mRunning = false; - - // We ignore any failures from calling EvaluateString() or - // CallEventHandler() on the context here since we're in a loop - // where we're likely to be running timeouts whose OS timers - // didn't fire in time and we don't want to not fire those timers - // now just because execution of one timer failed. We can't - // propagate the error to anyone who cares about it from this - // point anyway, and the script context should have already reported - // the script error in the usual way - so we just drop it. - - // If all timeouts were cleared and |timeout != aTimeout| then - // |timeout| may be the last reference to the timeout so check if - // it was cleared before releasing it. - bool timeout_was_cleared = timeout->mCleared; - - timeout->Release(); + bool timeout_was_cleared = RunTimeoutHandler(timeout, scx); if (timeout_was_cleared) { // The running timeout's window was cleared, this means that @@ -9229,96 +9315,9 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout) return; } - bool isInterval = false; - // If we have a regular interval timer, we re-schedule the // timeout, accounting for clock drift. - if (timeout->mIsInterval) { - // Compute time to next timeout for interval timer. - // Make sure nextInterval is at least DOMMinTimeoutValue(). - TimeDuration nextInterval = - TimeDuration::FromMilliseconds(NS_MAX(timeout->mInterval, - PRUint32(DOMMinTimeoutValue()))); - - // If we're running pending timeouts because they've been temporarily - // disabled (!aTimeout), set the next interval to be relative to "now", - // and not to when the timeout that was pending should have fired. - TimeStamp firingTime; - if (!aTimeout) - firingTime = now + nextInterval; - else - firingTime = timeout->mWhen + nextInterval; - - TimeStamp currentNow = TimeStamp::Now(); - TimeDuration delay = firingTime - currentNow; - - // And make sure delay is nonnegative; that might happen if the timer - // thread is firing our timers somewhat early or if they're taking a long - // time to run the callback. - if (delay < TimeDuration(0)) { - delay = TimeDuration(0); - } - - if (timeout->mTimer) { - timeout->mWhen = currentNow + delay; // firingTime unless delay got - // clamped, in which case it's - // currentNow. - - // Reschedule the OS timer. Don't bother returning any error - // codes if this fails since the callers of this method - // doesn't care about them nobody who cares about them - // anyways. - - // Make sure to cast the unsigned PR_USEC_PER_MSEC to signed - // PRTime to make the division do the right thing on 64-bit - // platforms whether delay is positive or negative (which we - // know is always positive here, but cast anyways for - // consistency). - nsresult rv = timeout->mTimer-> - InitWithFuncCallback(TimerCallback, timeout, - delay.ToMilliseconds(), - nsITimer::TYPE_ONE_SHOT); - - if (NS_FAILED(rv)) { - NS_ERROR("Error initializing timer for DOM timeout!"); - - // We failed to initialize the new OS timer, this timer does - // us no good here so we just cancel it (just in case) and - // null out the pointer to the OS timer, this will release the - // OS timer. As we continue executing the code below we'll end - // up deleting the timeout since it's not an interval timeout - // any more (since timeout->mTimer == nsnull). - timeout->mTimer->Cancel(); - timeout->mTimer = nsnull; - - // Now that the OS timer no longer has a reference to the - // timeout we need to drop that reference. - timeout->Release(); - } - } else { - NS_ASSERTION(IsFrozen() || mTimeoutsSuspendDepth, - "How'd our timer end up null if we're not frozen or " - "suspended?"); - - timeout->mTimeRemaining = delay; - isInterval = true; - } - } - - if (timeout->mTimer) { - if (timeout->mIsInterval) { - isInterval = true; - } else { - // The timeout still has an OS timer, and it's not an - // interval, that means that the OS timer could still fire (if - // it didn't already, i.e. aTimeout == timeout), cancel the OS - // timer and release its reference to the timeout. - timeout->mTimer->Cancel(); - timeout->mTimer = nsnull; - - timeout->Release(); - } - } + bool needsReinsertion = RescheduleTimeout(timeout, now, !aTimeout); // Running a timeout can cause another timeout to be deleted, so // we need to reset the pointer to the following timeout. @@ -9326,9 +9325,10 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout) PR_REMOVE_LINK(timeout); - if (isInterval) { - // Reschedule an interval timeout. Insert interval timeout - // onto list sorted in deadline order. + if (needsReinsertion) { + NS_ASSERTION(timeout->mTimer, + "rescheduling interval timeout without a timer!"); + // Insert interval timeout onto list sorted in deadline order. // AddRefs timeout. InsertTimeoutIntoList(timeout); } diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 788986c4d8fc..ca5379c61b1e 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -659,6 +659,11 @@ protected: // The timeout implementation functions. void RunTimeout(nsTimeout *aTimeout); void RunTimeout() { RunTimeout(nsnull); } + // Return true if |aTimeout| was cleared while its handler ran. + bool RunTimeoutHandler(nsTimeout* aTimeout, nsIScriptContext* aScx); + // Return true if |aTimeout| needs to be reinserted into the timeout list. + bool RescheduleTimeout(nsTimeout* aTimeout, const TimeStamp& now, + bool aRunningPendingTimeouts); void ClearAllTimeouts(); // Insert aTimeout into the list, before all timeouts that would diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h index b068440c3bbf..ffa7d6ae2425 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -13,6 +13,8 @@ * the generated code itself. */ +#include "mozilla/Assertions.h" + #include "nsISupports.h" #include "jsapi.h" #include "nsString.h" @@ -63,10 +65,19 @@ public: { } + /** + * Ditto for flat strings. + */ + explicit nsDependentJSString(JSFlatString* fstr) + : nsDependentString(JS_GetFlatStringChars(fstr), + JS_GetStringLength(JS_FORGET_STRING_FLATNESS(fstr))) + { + } + /** * For all other strings, the nsDependentJSString object should be default * constructed, which leaves it empty (this->IsEmpty()), and initialized with - * one of the fallible init() methods below. + * one of the init() methods below. */ nsDependentJSString() @@ -91,6 +102,12 @@ public: return init(aContext, JSVAL_TO_STRING(v)); } + void init(JSFlatString* fstr) + { + MOZ_ASSERT(IsEmpty(), "init() on initialized string"); + new(this) nsDependentJSString(fstr); + } + ~nsDependentJSString() { } diff --git a/dom/plugins/base/Makefile.in b/dom/plugins/base/Makefile.in index dafe2adbd045..0f9e0ff23078 100644 --- a/dom/plugins/base/Makefile.in +++ b/dom/plugins/base/Makefile.in @@ -26,7 +26,6 @@ XPIDLSRCS = \ nsIPluginHost.idl \ nsIPluginInputStream.idl \ nsIPluginInstanceOwner.idl \ - nsIPluginStreamInfo.idl \ nsIPluginTag.idl \ nsIPluginTagInfo.idl \ nspluginroot.idl \ diff --git a/dom/plugins/base/nsIPluginStreamInfo.idl b/dom/plugins/base/nsIPluginStreamInfo.idl deleted file mode 100644 index b6b512974e79..000000000000 --- a/dom/plugins/base/nsIPluginStreamInfo.idl +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * nsIPluginStreamInfo - * - * @status DEPRECATED - * - * Originally published XPCOM Plugin API is now deprecated - * Developers are welcome to use NPAPI, please refer to: - * http://mozilla.org/projects/plugins/ - */ - -#include "nsISupports.idl" -#include "nspluginroot.idl" - -%{C++ -#include "npapi.h" -%} - -[uuid(A700845F-0E26-44EA-84F5-3BE5381F98D5)] -interface nsIPluginStreamInfo : nsISupports -{ - readonly attribute string contentType; - - void isSeekable(out boolean aSeekable); - - readonly attribute unsigned long length; - - readonly attribute unsigned long lastModified; - - void getURL(out constCharPtr aURL); - - void requestRead(in NPByteRangePtr aRangeList); - - attribute long streamOffset; -}; diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index 9cce533c2a2e..e703161b51f4 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -19,6 +19,7 @@ #include "nsNPAPIPlugin.h" #include "nsNPAPIPluginInstance.h" #include "nsNPAPIPluginStreamListener.h" +#include "nsPluginStreamListenerPeer.h" #include "nsIServiceManager.h" #include "nsThreadUtils.h" #include "mozilla/Preferences.h" @@ -533,11 +534,12 @@ nsNPAPIPlugin::RetainStream(NPStream *pstream, nsISupports **aRetainedPeer) return NPERR_GENERIC_ERROR; } - nsPluginStreamListenerPeer* peer = listener->GetStreamListenerPeer(); - if (!peer) + nsIStreamListener* streamListener = listener->GetStreamListenerPeer(); + if (!streamListener) { return NPERR_GENERIC_ERROR; + } - *aRetainedPeer = (nsISupports*) peer; + *aRetainedPeer = streamListener; NS_ADDREF(*aRetainedPeer); return NS_OK; } @@ -2510,10 +2512,10 @@ _requestread(NPStream *pstream, NPByteRange *rangeList) if (streamtype != NP_SEEK) return NPERR_STREAM_NOT_SEEKABLE; - if (!streamlistener->mStreamInfo) + if (!streamlistener->mStreamListenerPeer) return NPERR_GENERIC_ERROR; - nsresult rv = streamlistener->mStreamInfo->RequestRead((NPByteRange *)rangeList); + nsresult rv = streamlistener->mStreamListenerPeer->RequestRead((NPByteRange *)rangeList); if (NS_FAILED(rv)) return NPERR_GENERIC_ERROR; diff --git a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp index 286b64e1503d..3a110a00af7d 100644 --- a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp +++ b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp @@ -137,7 +137,6 @@ nsNPAPIPluginStreamListener::nsNPAPIPluginStreamListener(nsNPAPIPluginInstance* : mStreamBuffer(nsnull), mNotifyURL(aURL ? PL_strdup(aURL) : nsnull), mInst(inst), -mStreamListenerPeer(nsnull), mStreamBufferSize(0), mStreamBufferByteCount(0), mStreamType(NP_NORMAL), @@ -215,7 +214,7 @@ nsNPAPIPluginStreamListener::CleanUpStream(NPReason reason) if (!mInst || !mInst->CanFireNotifications()) return rv; - mStreamInfo = NULL; + mStreamListenerPeer = nsnull; PluginDestructionGuard guard(mInst); @@ -279,7 +278,7 @@ nsNPAPIPluginStreamListener::CallURLNotify(NPReason reason) } nsresult -nsNPAPIPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo) +nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPeer) { if (!mInst || !mInst->CanFireNotifications()) return NS_ERROR_FAILURE; @@ -303,18 +302,18 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo) PRUint16 streamType = NP_NORMAL; NPError error; - pluginInfo->GetURL(&mNPStreamWrapper->mNPStream.url); - pluginInfo->GetLength((PRUint32*)&(mNPStreamWrapper->mNPStream.end)); - pluginInfo->GetLastModified((PRUint32*)&(mNPStreamWrapper->mNPStream.lastmodified)); - pluginInfo->IsSeekable(&seekable); - pluginInfo->GetContentType(&contentType); + streamPeer->GetURL(&mNPStreamWrapper->mNPStream.url); + streamPeer->GetLength((PRUint32*)&(mNPStreamWrapper->mNPStream.end)); + streamPeer->GetLastModified((PRUint32*)&(mNPStreamWrapper->mNPStream.lastmodified)); + streamPeer->IsSeekable(&seekable); + streamPeer->GetContentType(&contentType); if (!mResponseHeaders.IsEmpty()) { mResponseHeaderBuf = PL_strdup(mResponseHeaders.get()); mNPStreamWrapper->mNPStream.headers = mResponseHeaderBuf; } - mStreamInfo = pluginInfo; + mStreamListenerPeer = streamPeer; NPPAutoPusher nppPusher(npp); @@ -360,31 +359,22 @@ nsNPAPIPluginStreamListener::SuspendRequest() { NS_ASSERTION(!mIsSuspended, "Suspending a request that's already suspended!"); - - nsCOMPtr pluginInfoNPAPI = - do_QueryInterface(mStreamInfo); - - if (!pluginInfoNPAPI) { - return; - } - + nsresult rv = StartDataPump(); if (NS_FAILED(rv)) return; mIsSuspended = true; - - pluginInfoNPAPI->SuspendRequests(); + + if (mStreamListenerPeer) { + mStreamListenerPeer->SuspendRequests(); + } } void nsNPAPIPluginStreamListener::ResumeRequest() { - nsCOMPtr pluginInfoNPAPI = - do_QueryInterface(mStreamInfo); - - pluginInfoNPAPI->ResumeRequests(); - + mStreamListenerPeer->ResumeRequests(); mIsSuspended = false; } @@ -436,7 +426,7 @@ nsNPAPIPluginStreamListener::PluginInitJSLoadInProgress() // and the length will be the number of bytes available in our // internal buffer. nsresult -nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, +nsNPAPIPluginStreamListener::OnDataAvailable(nsPluginStreamListenerPeer* streamPeer, nsIInputStream* input, PRUint32 length) { @@ -446,7 +436,7 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, PluginDestructionGuard guard(mInst); // Just in case the caller switches plugin info on us. - mStreamInfo = pluginInfo; + mStreamListenerPeer = streamPeer; nsNPAPIPlugin* plugin = mInst->GetPlugin(); if (!plugin || !plugin->GetLibrary()) @@ -466,7 +456,7 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, // consecutive Read() calls form input stream into our buff. PRUint32 contentLength; - pluginInfo->GetLength(&contentLength); + streamPeer->GetLength(&contentLength); mStreamBufferSize = NS_MAX(length, contentLength); @@ -486,7 +476,7 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, mInst->GetNPP(&npp); PRInt32 streamPosition; - pluginInfo->GetStreamOffset(&streamPosition); + streamPeer->GetStreamOffset(&streamPosition); PRInt32 streamOffset = streamPosition; if (input) { @@ -501,7 +491,7 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, // // Note: there is a special case when data flow should be // temporarily stopped if NPP_WriteReady returns 0 (bug #89270) - pluginInfo->SetStreamOffset(streamOffset); + streamPeer->SetStreamOffset(streamOffset); // set new end in case the content is compressed // initial end is less than end of decompressed stream @@ -695,10 +685,10 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, // NPN_RequestRead() call. PRInt32 postWriteStreamPosition; - pluginInfo->GetStreamOffset(&postWriteStreamPosition); + streamPeer->GetStreamOffset(&postWriteStreamPosition); if (postWriteStreamPosition == streamOffset) { - pluginInfo->SetStreamOffset(streamPosition); + streamPeer->SetStreamOffset(streamPosition); } } @@ -706,7 +696,7 @@ nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, } nsresult -nsNPAPIPluginStreamListener::OnFileAvailable(nsIPluginStreamInfo* pluginInfo, +nsNPAPIPluginStreamListener::OnFileAvailable(nsPluginStreamListenerPeer* streamPeer, const char* fileName) { if (!mInst || !mInst->CanFireNotifications()) @@ -736,7 +726,7 @@ nsNPAPIPluginStreamListener::OnFileAvailable(nsIPluginStreamInfo* pluginInfo, } nsresult -nsNPAPIPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo, +nsNPAPIPluginStreamListener::OnStopBinding(nsPluginStreamListenerPeer* streamPeer, nsresult status) { StopDataPump(); @@ -744,9 +734,8 @@ nsNPAPIPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo, if (NS_FAILED(status)) { // The stream was destroyed, or died for some reason. Make sure we // cancel the underlying request. - nsCOMPtr pluginInfoNPAPI = do_QueryInterface(mStreamInfo); - if (pluginInfoNPAPI) { - pluginInfoNPAPI->CancelRequests(status); + if (mStreamListenerPeer) { + mStreamListenerPeer->CancelRequests(status); } } @@ -788,7 +777,7 @@ nsNPAPIPluginStreamListener::Notify(nsITimer *aTimer) PRInt32 oldStreamBufferByteCount = mStreamBufferByteCount; - nsresult rv = OnDataAvailable(mStreamInfo, nsnull, mStreamBufferByteCount); + nsresult rv = OnDataAvailable(mStreamListenerPeer, nsnull, mStreamBufferByteCount); if (NS_FAILED(rv)) { // We ran into an error, no need to keep firing this timer then. diff --git a/dom/plugins/base/nsNPAPIPluginStreamListener.h b/dom/plugins/base/nsNPAPIPluginStreamListener.h index 577aa2d28e47..dfa4ff5758df 100644 --- a/dom/plugins/base/nsNPAPIPluginStreamListener.h +++ b/dom/plugins/base/nsNPAPIPluginStreamListener.h @@ -7,7 +7,6 @@ #define nsNPAPIPluginStreamListener_h_ #include "nscore.h" -#include "nsIPluginStreamInfo.h" #include "nsIHTTPHeaderListener.h" #include "nsIRequest.h" #include "nsITimer.h" @@ -22,7 +21,6 @@ #define MAX_PLUGIN_NECKO_BUFFER 16384 -class nsINPAPIPluginStreamInfo; class nsPluginStreamListenerPeer; class nsNPAPIPluginStreamListener; @@ -42,64 +40,6 @@ protected: nsNPAPIPluginStreamListener* mStreamListener; // only valid if browser initiated }; -// nsINPAPIPluginStreamInfo is an internal helper interface that exposes -// the underlying necko request to consumers of nsIPluginStreamInfo's. -#define NS_INPAPIPLUGINSTREAMINFO_IID \ -{ 0x097fdaaa, 0xa2a3, 0x49c2, \ -{0x91, 0xee, 0xeb, 0xc5, 0x7d, 0x6c, 0x9c, 0x97} } - -class nsINPAPIPluginStreamInfo : public nsIPluginStreamInfo -{ -public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_INPAPIPLUGINSTREAMINFO_IID) - - void TrackRequest(nsIRequest* request) - { - mRequests.AppendObject(request); - } - - void ReplaceRequest(nsIRequest* oldRequest, nsIRequest* newRequest) - { - PRInt32 i = mRequests.IndexOfObject(oldRequest); - if (i == -1) { - NS_ASSERTION(mRequests.Count() == 0, - "Only our initial stream should be unknown!"); - mRequests.AppendObject(oldRequest); - } - else { - mRequests.ReplaceObjectAt(newRequest, i); - } - } - - void CancelRequests(nsresult status) - { - // Copy the array to avoid modification during the loop. - nsCOMArray requestsCopy(mRequests); - for (PRInt32 i = 0; i < requestsCopy.Count(); ++i) - requestsCopy[i]->Cancel(status); - } - - void SuspendRequests() { - nsCOMArray requestsCopy(mRequests); - for (PRInt32 i = 0; i < requestsCopy.Count(); ++i) - requestsCopy[i]->Suspend(); - } - - void ResumeRequests() { - nsCOMArray requestsCopy(mRequests); - for (PRInt32 i = 0; i < requestsCopy.Count(); ++i) - requestsCopy[i]->Resume(); - } - -protected: - friend class nsPluginByteRangeStreamListener; - - nsCOMArray mRequests; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsINPAPIPluginStreamInfo, - NS_INPAPIPLUGINSTREAMINFO_IID) - // Used to handle NPN_NewStream() - writes the stream as received by the plugin // to a file and at completion (NPN_DestroyStream), tells the browser to load it into // a plugin-specified target @@ -134,13 +74,13 @@ public: const char* aURL); virtual ~nsNPAPIPluginStreamListener(); - nsresult OnStartBinding(nsIPluginStreamInfo* pluginInfo); - nsresult OnDataAvailable(nsIPluginStreamInfo* pluginInfo, + nsresult OnStartBinding(nsPluginStreamListenerPeer* streamPeer); + nsresult OnDataAvailable(nsPluginStreamListenerPeer* streamPeer, nsIInputStream* input, PRUint32 length); - nsresult OnFileAvailable(nsIPluginStreamInfo* pluginInfo, + nsresult OnFileAvailable(nsPluginStreamListenerPeer* streamPeer, const char* fileName); - nsresult OnStopBinding(nsIPluginStreamInfo* pluginInfo, + nsresult OnStopBinding(nsPluginStreamListenerPeer* streamPeer, nsresult status); nsresult GetStreamType(PRInt32 *result); @@ -167,7 +107,6 @@ protected: char* mStreamBuffer; char* mNotifyURL; nsRefPtr mInst; - nsPluginStreamListenerPeer* mStreamListenerPeer; nsNPAPIStreamWrapper *mNPStreamWrapper; PRUint32 mStreamBufferSize; PRInt32 mStreamBufferByteCount; @@ -184,7 +123,7 @@ protected: nsCOMPtr mHTTPRedirectCallback; public: - nsCOMPtr mStreamInfo; + nsRefPtr mStreamListenerPeer; }; #endif // nsNPAPIPluginStreamListener_h_ diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 8c76ca0e706d..d8397cd4e9cb 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -15,6 +15,8 @@ #include "nsNPAPIPlugin.h" #include "nsNPAPIPluginStreamListener.h" #include "nsNPAPIPluginInstance.h" +#include "nsPluginInstanceOwner.h" +#include "nsObjectLoadingContent.h" #include "nsIHTTPHeaderListener.h" #include "nsIHttpHeaderVisitor.h" #include "nsIObserverService.h" diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp index ab4ebdc6ab4c..a0856462b597 100644 --- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp +++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp @@ -27,6 +27,7 @@ #include "nsNetUtil.h" #include "nsPluginNativeWindow.h" #include "sampler.h" +#include "nsObjectLoadingContent.h" #define MAGIC_REQUEST_CONTEXT 0x01020304 @@ -264,13 +265,11 @@ public: // nsPluginStreamListenerPeer -NS_IMPL_ISUPPORTS8(nsPluginStreamListenerPeer, +NS_IMPL_ISUPPORTS6(nsPluginStreamListenerPeer, nsIStreamListener, nsIRequestObserver, nsIHttpHeaderVisitor, nsISupportsWeakReference, - nsIPluginStreamInfo, - nsINPAPIPluginStreamInfo, nsIInterfaceRequestor, nsIChannelEventSink) @@ -635,7 +634,7 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStatus(nsIRequest *request, return NS_OK; } -NS_IMETHODIMP +nsresult nsPluginStreamListenerPeer::GetContentType(char** result) { *result = const_cast(mContentType.get()); @@ -643,28 +642,28 @@ nsPluginStreamListenerPeer::GetContentType(char** result) } -NS_IMETHODIMP +nsresult nsPluginStreamListenerPeer::IsSeekable(bool* result) { *result = mSeekable; return NS_OK; } -NS_IMETHODIMP +nsresult nsPluginStreamListenerPeer::GetLength(PRUint32* result) { *result = mLength; return NS_OK; } -NS_IMETHODIMP +nsresult nsPluginStreamListenerPeer::GetLastModified(PRUint32* result) { *result = mModified; return NS_OK; } -NS_IMETHODIMP +nsresult nsPluginStreamListenerPeer::GetURL(const char** result) { *result = mURLSpec.get(); @@ -707,7 +706,7 @@ nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACStr return; } -NS_IMETHODIMP +nsresult nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList) { nsCAutoString rangeString; @@ -770,14 +769,14 @@ nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList) return rv; } -NS_IMETHODIMP +nsresult nsPluginStreamListenerPeer::GetStreamOffset(PRInt32* result) { *result = mStreamOffset; return NS_OK; } -NS_IMETHODIMP +nsresult nsPluginStreamListenerPeer::SetStreamOffset(PRInt32 value) { mStreamOffset = value; @@ -1289,11 +1288,11 @@ nsPluginStreamListenerPeer::GetInterface(const nsIID& aIID, void** result) class ChannelRedirectProxyCallback : public nsIAsyncVerifyRedirectCallback { public: - ChannelRedirectProxyCallback(nsINPAPIPluginStreamInfo* listener, + ChannelRedirectProxyCallback(nsPluginStreamListenerPeer* listener, nsIAsyncVerifyRedirectCallback* parent, nsIChannel* oldChannel, nsIChannel* newChannel) - : mWeakListener(do_GetWeakReference(listener)) + : mWeakListener(do_GetWeakReference(static_cast(listener))) , mParent(parent) , mOldChannel(oldChannel) , mNewChannel(newChannel) @@ -1308,9 +1307,9 @@ public: NS_IMETHODIMP OnRedirectVerifyCallback(nsresult result) { if (NS_SUCCEEDED(result)) { - nsCOMPtr listener = do_QueryReferent(mWeakListener); + nsCOMPtr listener = do_QueryReferent(mWeakListener); if (listener) - listener->ReplaceRequest(mOldChannel, mNewChannel); + static_cast(listener.get())->ReplaceRequest(mOldChannel, mNewChannel); } return mParent->OnRedirectVerifyCallback(result); } diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.h b/dom/plugins/base/nsPluginStreamListenerPeer.h index 67bcdae82369..49281964eecc 100644 --- a/dom/plugins/base/nsPluginStreamListenerPeer.h +++ b/dom/plugins/base/nsPluginStreamListenerPeer.h @@ -17,9 +17,10 @@ #include "nsNPAPIPluginInstance.h" #include "nsIInterfaceRequestor.h" #include "nsIChannelEventSink.h" -#include "nsObjectLoadingContent.h" +#include "nsIObjectLoadingContent.h" class nsIChannel; +class nsObjectLoadingContent; /** * When a plugin requests opens multiple requests to the same URL and @@ -47,7 +48,6 @@ class nsPluginStreamListenerPeer : public nsIStreamListener, public nsIProgressEventSink, public nsIHttpHeaderVisitor, public nsSupportsWeakReference, -public nsINPAPIPluginStreamInfo, public nsIInterfaceRequestor, public nsIChannelEventSink { @@ -63,9 +63,6 @@ public: NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSICHANNELEVENTSINK - // nsINPAPIPluginStreamInfo interface - NS_DECL_NSIPLUGINSTREAMINFO - // Called by RequestRead void MakeByteRangeString(NPByteRange* aRangeList, nsACString &string, PRInt32 *numRequests); @@ -89,6 +86,53 @@ public: nsNPAPIPluginInstance *GetPluginInstance() { return mPluginInstance; } + nsresult RequestRead(NPByteRange* rangeList); + nsresult GetLength(PRUint32* result); + nsresult GetURL(const char** result); + nsresult GetLastModified(PRUint32* result); + nsresult IsSeekable(bool* result); + nsresult GetContentType(char** result); + nsresult GetStreamOffset(PRInt32* result); + nsresult SetStreamOffset(PRInt32 value); + + void TrackRequest(nsIRequest* request) + { + mRequests.AppendObject(request); + } + + void ReplaceRequest(nsIRequest* oldRequest, nsIRequest* newRequest) + { + PRInt32 i = mRequests.IndexOfObject(oldRequest); + if (i == -1) { + NS_ASSERTION(mRequests.Count() == 0, + "Only our initial stream should be unknown!"); + mRequests.AppendObject(oldRequest); + } + else { + mRequests.ReplaceObjectAt(newRequest, i); + } + } + + void CancelRequests(nsresult status) + { + // Copy the array to avoid modification during the loop. + nsCOMArray requestsCopy(mRequests); + for (PRInt32 i = 0; i < requestsCopy.Count(); ++i) + requestsCopy[i]->Cancel(status); + } + + void SuspendRequests() { + nsCOMArray requestsCopy(mRequests); + for (PRInt32 i = 0; i < requestsCopy.Count(); ++i) + requestsCopy[i]->Suspend(); + } + + void ResumeRequests() { + nsCOMArray requestsCopy(mRequests); + for (PRInt32 i = 0; i < requestsCopy.Count(); ++i) + requestsCopy[i]->Resume(); + } + private: nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL); nsresult SetupPluginCacheFile(nsIChannel* channel); @@ -132,6 +176,7 @@ public: PRInt32 mPendingRequests; nsWeakPtr mWeakPtrChannelCallbacks; nsWeakPtr mWeakPtrChannelLoadGroup; + nsCOMArray mRequests; }; #endif // nsPluginStreamListenerPeer_h_ diff --git a/dom/system/gonk/systemlibs.js b/dom/system/gonk/systemlibs.js index 6c88eccb6efc..0a0f268b356d 100644 --- a/dom/system/gonk/systemlibs.js +++ b/dom/system/gonk/systemlibs.js @@ -192,6 +192,10 @@ let libnetutils = (function () { serverbuf, lease.address()); + if (ret && DEBUG) { + let error = iface.dhcp_get_errmsg(); + dump("dhcp_do_request failed - " + error.readString()); + } let obj = { ret: ret | 0, ipaddr_str: ipaddrbuf.readString(), @@ -246,6 +250,10 @@ let libnetutils = (function () { ints.addressOfElement(4), ints.addressOfElement(5), ints.addressOfElement(6)); + if (ret && DEBUG) { + let error = iface.dhcp_get_errmsg(); + dump("dhcp_do_request_* failed - " + error.readString()); + } return {ret: ret | 0, ipaddr: ints[0] | 0, gateway: ints[1] | 0, diff --git a/dom/system/nsDeviceSensors.cpp b/dom/system/nsDeviceSensors.cpp index 8722c0b29a72..139517f6f235 100644 --- a/dom/system/nsDeviceSensors.cpp +++ b/dom/system/nsDeviceSensors.cpp @@ -160,9 +160,11 @@ nsDeviceSensors::Notify(const mozilla::hal::SensorData& aSensorData) { PRUint32 type = aSensorData.sensor(); - double x = aSensorData.values()[0]; - double y = aSensorData.values()[1]; - double z = aSensorData.values()[2]; + const InfallibleTArray& values = aSensorData.values(); + size_t len = values.Length(); + double x = len > 0 ? values[0] : 0.0; + double y = len > 1 ? values[1] : 0.0; + double z = len > 2 ? values[2] : 0.0; nsCOMArray windowListeners; for (PRUint32 i = 0; i < mWindowListeners[type]->Length(); i++) { diff --git a/dom/wifi/libnetutils.js b/dom/wifi/libnetutils.js deleted file mode 100644 index db36f4e07f84..000000000000 --- a/dom/wifi/libnetutils.js +++ /dev/null @@ -1,150 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ - -"use strict"; - -let libnetutils = (function () { - let library = ctypes.open("libnetutils.so"); - let cutils = ctypes.open("libcutils.so"); - - let cbuf = ctypes.char.array(4096)(); - let c_property_get = cutils.declare("property_get", ctypes.default_abi, - ctypes.int, // return value: length - ctypes.char.ptr, // key - ctypes.char.ptr, // value - ctypes.char.ptr); // default - let property_get = function (key, defaultValue) { - if (defaultValue === undefined) { - defaultValue = null; - } - c_property_get(key, cbuf, defaultValue); - return cbuf.readString(); - } - - let sdkVersion = parseInt(property_get("ro.build.version.sdk")); - - let iface = { - ifc_enable: library.declare("ifc_enable", ctypes.default_abi, ctypes.int, ctypes.char.ptr), - ifc_disable: library.declare("ifc_disable", ctypes.default_abi, ctypes.int, ctypes.char.ptr), - ifc_add_host_route: library.declare("ifc_add_host_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int), - ifc_remove_host_routes: library.declare("ifc_remove_host_routes", ctypes.default_abi, ctypes.int, ctypes.char.ptr), - ifc_set_default_route: library.declare("ifc_set_default_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int), - ifc_get_default_route: library.declare("ifc_get_default_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr), - ifc_remove_default_route: library.declare("ifc_remove_default_route", ctypes.default_abi, ctypes.int, ctypes.char.ptr), - ifc_reset_connections: library.declare("ifc_reset_connections", ctypes.default_abi, ctypes.int, ctypes.char.ptr), - ifc_configure: library.declare("ifc_configure", ctypes.default_abi, ctypes.int, ctypes.char.ptr, - ctypes.int, ctypes.int, ctypes.int, ctypes.int, ctypes.int), - dhcp_stop: library.declare("dhcp_stop", ctypes.default_abi, ctypes.int, ctypes.char.ptr), - dhcp_release_lease: library.declare("dhcp_release_lease", ctypes.default_abi, ctypes.int, ctypes.char.ptr), - dhcp_get_errmsg: library.declare("dhcp_get_errmsg", ctypes.default_abi, ctypes.char.ptr), - }; - - if (sdkVersion >= 15) { - let ipaddrbuf = ctypes.char.array(4096)(); - let gatewaybuf = ctypes.char.array(4096)(); - let prefixLen = ctypes.int(); - let dns1buf = ctypes.char.array(4096)(); - let dns2buf = ctypes.char.array(4096)(); - let serverbuf = ctypes.char.array(4096)(); - let lease = ctypes.int(); - let c_dhcp_do_request = - library.declare("dhcp_do_request", ctypes.default_abi, - ctypes.int, // [return] - ctypes.char.ptr, // ifname - ctypes.char.ptr, // ipaddr - ctypes.char.ptr, // gateway - ctypes.int.ptr, // prefixlen - ctypes.char.ptr, // dns1 - ctypes.char.ptr, // dns2 - ctypes.char.ptr, // server - ctypes.int.ptr); // lease - - let stringToIp = function (s) { - if (!s) return 0; - let comps = s.split("."); - return ((parseInt(comps[0]) & 0xff) << 0 | - (parseInt(comps[1]) & 0xff) << 8 | - (parseInt(comps[2]) & 0xff) << 16 | - (parseInt(comps[3]) & 0xff) << 24); - } - - let makeMask = function (len) { - let mask = 0; - for (let i = 0; i < len; ++i) - mask |= (1 << i); - return mask; - } - - iface.dhcp_do_request = function (ifname) { - let ret = c_dhcp_do_request(ifname, - ipaddrbuf, - gatewaybuf, - prefixLen.address(), - dns1buf, - dns2buf, - serverbuf, - lease.address()); - return { - ret: ret |0, - ipaddr: stringToIp(ipaddrbuf.readString()), - gateway: stringToIp(gatewaybuf.readString()), - mask: makeMask(prefixLen), - dns1: stringToIp(dns1buf.readString()), - dns2: stringToIp(dns2buf.readString()), - server: stringToIp(serverbuf.readString()), - lease: lease |0 - }; - }; - // dhcp_do_request_renew() went away in newer libnetutils. - iface.dhcp_do_request_renew = iface.dhcp_do_request; - } else { - let ints = ctypes.int.array(8)(); - let c_dhcp_do_request = - library.declare("dhcp_do_request", ctypes.default_abi, - ctypes.int, // [return] - ctypes.char.ptr, // ifname - ctypes.int.ptr, // ipaddr - ctypes.int.ptr, // gateway - ctypes.int.ptr, // mask - ctypes.int.ptr, // dns1 - ctypes.int.ptr, // dns2 - ctypes.int.ptr, // server - ctypes.int.ptr); // lease - let c_dhcp_do_request_renew = - library.declare("dhcp_do_request_renew", ctypes.default_abi, - ctypes.int, // [return] - ctypes.char.ptr, // ifname - ctypes.int.ptr, // ipaddr - ctypes.int.ptr, // gateway - ctypes.int.ptr, // mask - ctypes.int.ptr, // dns1 - ctypes.int.ptr, // dns2 - ctypes.int.ptr, // server - ctypes.int.ptr); // lease - - let makeRequestWrapper = function (c_fn) { - return function (ifname) { - let ret = c_fn(ifname, - ints.addressOfElement(0), - ints.addressOfElement(1), - ints.addressOfElement(2), - ints.addressOfElement(3), - ints.addressOfElement(4), - ints.addressOfElement(5), - ints.addressOfElement(6)); - return { ret: ret |0, ipaddr: ints[0] |0, gateway: ints[1] |0, - mask: ints[2] |0, dns1: ints[3] |0, dns2: ints[4] |0, - server: ints[5] |0, lease: ints[6] |0 }; - }; - } - - iface.dhcp_do_request = makeRequestWrapper(c_dhcp_do_request); - iface.dhcp_do_request_renew = makeRequestWrapper(c_dhcp_do_request_renew); - } - - return iface; -})(); diff --git a/embedding/examples/Makefile.in b/embedding/examples/Makefile.in deleted file mode 100644 index be26e62b74c0..000000000000 --- a/embedding/examples/Makefile.in +++ /dev/null @@ -1,15 +0,0 @@ -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEPTH = ../.. -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -DIRS= - -include $(topsrcdir)/config/rules.mk diff --git a/embedding/examples/readme.txt b/embedding/examples/readme.txt deleted file mode 100644 index 8422b34bc822..000000000000 --- a/embedding/examples/readme.txt +++ /dev/null @@ -1,3 +0,0 @@ -This folder contains sample applications developed using the Gecko embedding -APIs. - diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 9d896d72980d..dfb078f7e2e0 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -295,12 +295,13 @@ regexp_compile(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, regexp_compile, &RegExpClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, regexp_compile, &RegExpClass, &thisObj)) + return false; + if (!thisObj) + return true; - RegExpObjectBuilder builder(cx, &obj->asRegExp()); + RegExpObjectBuilder builder(cx, &thisObj->asRegExp()); return CompileRegExpObject(cx, builder, args); } @@ -333,12 +334,13 @@ regexp_toString(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, regexp_toString, &RegExpClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, regexp_toString, &RegExpClass, &thisObj)) + return false; + if (!thisObj) + return true; - JSString *str = obj->asRegExp().toString(cx); + JSString *str = thisObj->asRegExp().toString(cx); if (!str) return false; @@ -540,12 +542,13 @@ ExecuteRegExp(JSContext *cx, Native native, unsigned argc, Value *vp) CallArgs args = CallArgsFromVp(argc, vp); /* Step 1. */ - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, native, &RegExpClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, native, &RegExpClass, &thisObj)) + return false; + if (!thisObj) + return true; - Rooted reobj(cx, &obj->asRegExp()); + Rooted reobj(cx, &thisObj->asRegExp()); RegExpGuard re; if (StartsWithGreedyStar(reobj->getSource())) { diff --git a/js/src/gc/Root.h b/js/src/gc/Root.h index 9d5aeb811731..729271c62885 100644 --- a/js/src/gc/Root.h +++ b/js/src/gc/Root.h @@ -122,6 +122,7 @@ class Handle typedef Handle HandleObject; typedef Handle HandleFunction; +typedef Handle HandleScript; typedef Handle HandleString; typedef Handle HandleId; typedef Handle HandleValue; @@ -224,6 +225,7 @@ Handle::Handle(const Rooted &root) typedef Rooted RootedObject; typedef Rooted RootedFunction; +typedef Rooted RootedScript; typedef Rooted RootedString; typedef Rooted RootedId; typedef Rooted RootedValue; diff --git a/js/src/jit-test/tests/basic/testBug761439.js b/js/src/jit-test/tests/basic/testBug761439.js new file mode 100644 index 000000000000..cda3a45f4909 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug761439.js @@ -0,0 +1,5 @@ +var b = new ArrayBuffer(4); +var dv = new DataView(b); +dv.setInt32(0, 42); +var w = wrap(dv); +assertEq(DataView.prototype.getInt32.call(w, 0), 42); diff --git a/js/src/jsapi-tests/Makefile.in b/js/src/jsapi-tests/Makefile.in index 605153bc43bd..0ceee042f695 100644 --- a/js/src/jsapi-tests/Makefile.in +++ b/js/src/jsapi-tests/Makefile.in @@ -18,7 +18,9 @@ CPPSRCS = \ selfTest.cpp \ testAddPropertyPropcache.cpp \ testArgumentsObject.cpp \ + testBindCallable.cpp \ testBug604087.cpp \ + testCallNonGenericMethodOnProxy.cpp \ testChromeBuffer.cpp \ testClassGetter.cpp \ testCloneScript.cpp \ @@ -61,7 +63,6 @@ CPPSRCS = \ testValueABI.cpp \ testVersion.cpp \ testXDR.cpp \ - testBindCallable.cpp \ $(NULL) CSRCS = \ diff --git a/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp new file mode 100644 index 000000000000..ac9142b998b4 --- /dev/null +++ b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp @@ -0,0 +1,82 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "tests.h" + +using namespace JS; + +static JSClass CustomClass = { + "CustomClass", + JSCLASS_HAS_RESERVED_SLOTS(1), + JS_PropertyStub, + JS_PropertyStub, + JS_PropertyStub, + JS_StrictPropertyStub, + JS_EnumerateStub, + JS_ResolveStub, + JS_ConvertStub +}; + +static const uint32_t CUSTOM_SLOT = 0; + +static JSBool +CustomMethod(JSContext *cx, unsigned argc, Value *vp) +{ + const Value &thisv = JS_THIS_VALUE(cx, vp); + JSObject *thisObj; + if (!thisv.isObject() || JS_GetClass((thisObj = &thisv.toObject())) != &CustomClass) + return JS_CallNonGenericMethodOnProxy(cx, argc, vp, CustomMethod, &CustomClass); + + JS_SET_RVAL(cx, vp, JS_GetReservedSlot(thisObj, CUSTOM_SLOT)); + return true; +} + +BEGIN_TEST(test_CallNonGenericMethodOnProxy) +{ + // Create the first global object and compartment + JSObject *globalA = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL); + CHECK(globalA); + + JSObject *customA = JS_NewObject(cx, &CustomClass, NULL, NULL); + CHECK(customA); + JS_SetReservedSlot(customA, CUSTOM_SLOT, Int32Value(17)); + + JSFunction *customMethodA = JS_NewFunction(cx, CustomMethod, 0, 0, customA, "customMethodA"); + CHECK(customMethodA); + + jsval rval; + CHECK(JS_CallFunction(cx, customA, customMethodA, 0, NULL, &rval)); + CHECK_SAME(rval, Int32Value(17)); + + // Now create the second global object and compartment... + { + JSObject *globalB = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL); + CHECK(globalB); + + // ...and enter it. + JSAutoEnterCompartment enter; + CHECK(enter.enter(cx, globalB)); + + JSObject *customB = JS_NewObject(cx, &CustomClass, NULL, NULL); + CHECK(customB); + JS_SetReservedSlot(customB, CUSTOM_SLOT, Int32Value(42)); + + JSFunction *customMethodB = JS_NewFunction(cx, CustomMethod, 0, 0, customB, "customMethodB"); + CHECK(customMethodB); + + jsval rval; + CHECK(JS_CallFunction(cx, customB, customMethodB, 0, NULL, &rval)); + CHECK_SAME(rval, Int32Value(42)); + + JSObject *wrappedCustomA = customA; + CHECK(JS_WrapObject(cx, &wrappedCustomA)); + + jsval rval2; + CHECK(JS_CallFunction(cx, wrappedCustomA, customMethodB, 0, NULL, &rval2)); + CHECK_SAME(rval, Int32Value(42)); + } + + return true; +} +END_TEST(test_CallNonGenericMethodOnProxy) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index acf260ece541..e37f349da2cd 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3440,49 +3440,6 @@ JS_DeepFreezeObject(JSContext *cx, JSObject *obj) return true; } -JS_PUBLIC_API(JSObject *) -JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *parent) -{ - return JS_ConstructObjectWithArguments(cx, jsclasp, parent, 0, NULL); -} - -JS_PUBLIC_API(JSObject *) -JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *parent, - unsigned argc, jsval *argv) -{ - AssertNoGC(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, parent, JSValueArray(argv, argc)); - - AutoArrayRooter argtvr(cx, argc, argv); - - Class *clasp = Valueify(jsclasp); - if (!clasp) - clasp = &ObjectClass; /* default class is Object */ - - JSProtoKey protoKey = GetClassProtoKey(clasp); - - /* Protect constructor in case a crazy getter for .prototype uproots it. */ - RootedValue value(cx); - if (!js_FindClassObject(cx, parent, protoKey, value.address(), clasp)) - return NULL; - - Value rval; - if (!InvokeConstructor(cx, value, argc, argv, &rval)) - return NULL; - - /* - * If the instance's class differs from what was requested, throw a type - * error. - */ - if (!rval.isObject() || rval.toObject().getClass() != clasp) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_WRONG_CONSTRUCTOR, clasp->name); - return NULL; - } - return &rval.toObject(); -} - static JSBool LookupPropertyById(JSContext *cx, JSObject *obj, HandleId id, unsigned flags, JSObject **objp, JSProperty **propp) @@ -4845,6 +4802,14 @@ JS_DefineFunctionById(JSContext *cx, JSObject *obj_, jsid id_, JSNative call, return js_DefineFunction(cx, obj, id, call, nargs, attrs); } +extern JS_PUBLIC_API(JSBool) +JS_CallNonGenericMethodOnProxy(JSContext *cx, unsigned argc, jsval *vp, JSNative native, + JSClass *clasp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + return HandleNonGenericMethodClassMismatch(cx, args, native, Valueify(clasp)); +} + struct AutoLastFrameCheck { AutoLastFrameCheck(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) : cx(cx) { @@ -5344,7 +5309,8 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *scriptArg, jsval *rval) * mozilla, but there doesn't seem to be one, so we handle it here. */ if (scriptArg->compartment() != obj->compartment()) { - script = CloneScript(cx, scriptArg); + RootedScript scriptArgRoot(cx, scriptArg); + script = CloneScript(cx, scriptArgRoot); if (!script.get()) return false; } else { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index f27df2712ee6..f6dfa03fe0cc 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3811,7 +3811,6 @@ JS_IdToValue(JSContext *cx, jsid id, jsval *vp); #define JSRESOLVE_ASSIGNING 0x02 /* resolve on the left of assignment */ #define JSRESOLVE_DETECTING 0x04 /* 'if (o.p)...' or '(o.p) ?...:...' */ #define JSRESOLVE_DECLARING 0x08 /* var, const, or function prolog op */ -#define JSRESOLVE_WITH 0x10 /* resolve inside a with statement */ /* * Invoke the [[DefaultValue]] hook (see ES5 8.6.2) with the provided hint on @@ -3976,13 +3975,6 @@ JS_DeepFreezeObject(JSContext *cx, JSObject *obj); extern JS_PUBLIC_API(JSBool) JS_FreezeObject(JSContext *cx, JSObject *obj); -extern JS_PUBLIC_API(JSObject *) -JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *parent); - -extern JS_PUBLIC_API(JSObject *) -JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *parent, - unsigned argc, jsval *argv); - extern JS_PUBLIC_API(JSObject *) JS_New(JSContext *cx, JSObject *ctor, unsigned argc, jsval *argv); @@ -4473,6 +4465,66 @@ JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call, extern JS_PUBLIC_API(JSObject *) JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent); +/* + * Methods usually act upon |this| objects only from a single global object and + * compartment. Sometimes, however, a method must act upon |this| values from + * multiple global objects or compartments. In such cases the |this| value a + * method might see will be wrapped, such that various access to the object -- + * to its class, its private data, its reserved slots, and so on -- will not + * work properly without entering that object's compartment. This method + * implements a solution to this problem. + * + * When called, this method attempts to unwrap |this| and call |native| on the + * underlying object with the provided arguments, entering |this|'s compartment + * in the process. It is critical that |this|-checking occur right at the + * start of |native| so that reentrant invocation is idempotent! If the call + * fails because |this| isn't a proxy to another object, a TypeError is thrown. + * + * The following example demonstrates the most common way this method might be + * used, to accept objects having only a particular class but which might be + * found in another compartment/global object or might be a proxy of some sort: + * + * static JSClass MyClass = { "MyClass", JSCLASS_HAS_PRIVATE, ... }; + * + * inline bool + * RequireMyClassThis(JSContext *cx, unsigned argc, JSObject **thisObj) + * { + * const Value &thisv = JS_THIS_VALUE(cx, vp); + * if (!thisv.isObject()) { + * JS_ReportError(cx, "this must be an object"); + * return false; + * } + * + * JSObject *obj = &thisv.toObject(); + * if (JS_GetClass(obj) == &MyClass) { + * *thisObj = obj; + * return true; + * } + * + * *thisObj = NULL; // prevent infinite recursion into calling method + * return JS_CallNonGenericMethodOnProxy(cx, argc, vp, method, &MyClass); + * } + * + * static JSBool + * Method(JSContext *cx, unsigned argc, jsval *vp) + * { + * if (!RequireMyClassThis(cx, argc, vp, &thisObj)) + * return false; + * if (!thisObj) + * return true; // method invocation was performed by nested call + * + * // thisObj definitely has MyClass: implement the guts of the method. + * void *priv = JS_GetPrivate(thisObj); + * ... + * } + * + * This method doesn't do any checking of its own, except to throw a TypeError + * if the |this| in the arguments isn't a proxy that can be unwrapped for the + * recursive call. The client is responsible for performing all type-checks! + */ +extern JS_PUBLIC_API(JSBool) +JS_CallNonGenericMethodOnProxy(JSContext *cx, unsigned argc, jsval *vp, JSNative native, JSClass *clasp); + /* * Given a buffer, return JS_FALSE if the buffer might become a valid * javascript statement with the addition of more lines. Otherwise return diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 702d513a632a..245832729e32 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -1385,12 +1385,13 @@ date_getTime(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getTime, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getTime, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - args.rval() = obj->getDateUTCTime(); + args.rval() = thisObj->getDateUTCTime(); return true; } @@ -1399,15 +1400,16 @@ date_getYear(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getYear, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getYear, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!GetAndCacheLocalTime(cx, obj)) + if (!GetAndCacheLocalTime(cx, thisObj)) return false; - Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR); + Value yearVal = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR); if (yearVal.isInt32()) { /* Follow ECMA-262 to the letter, contrary to IE JScript. */ int year = yearVal.toInt32() - 1900; @@ -1424,15 +1426,16 @@ date_getFullYear(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getFullYear, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getFullYear, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!GetAndCacheLocalTime(cx, obj)) + if (!GetAndCacheLocalTime(cx, thisObj)) return false; - args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR); + args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR); return true; } @@ -1441,12 +1444,13 @@ date_getUTCFullYear(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCFullYear, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getUTCFullYear, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - double result = obj->getDateUTCTime().toNumber(); + double result = thisObj->getDateUTCTime().toNumber(); if (MOZ_DOUBLE_IS_FINITE(result)) result = YearFromTime(result); @@ -1459,15 +1463,16 @@ date_getMonth(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getMonth, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getMonth, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!GetAndCacheLocalTime(cx, obj)) + if (!GetAndCacheLocalTime(cx, thisObj)) return false; - args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH); + args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH); return true; } @@ -1476,12 +1481,13 @@ date_getUTCMonth(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMonth, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getUTCMonth, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - double result = obj->getDateUTCTime().toNumber(); + double result = thisObj->getDateUTCTime().toNumber(); if (MOZ_DOUBLE_IS_FINITE(result)) result = MonthFromTime(result); @@ -1494,15 +1500,16 @@ date_getDate(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getDate, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getDate, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!GetAndCacheLocalTime(cx, obj)) + if (!GetAndCacheLocalTime(cx, thisObj)) return false; - args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE); + args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE); return true; } @@ -1511,12 +1518,13 @@ date_getUTCDate(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCDate, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getUTCDate, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - double result = obj->getDateUTCTime().toNumber(); + double result = thisObj->getDateUTCTime().toNumber(); if (MOZ_DOUBLE_IS_FINITE(result)) result = DateFromTime(result); @@ -1529,15 +1537,16 @@ date_getDay(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getDay, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getDay, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!GetAndCacheLocalTime(cx, obj)) + if (!GetAndCacheLocalTime(cx, thisObj)) return false; - args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY); + args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY); return true; } @@ -1546,12 +1555,13 @@ date_getUTCDay(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCDay, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getUTCDay, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - double result = obj->getDateUTCTime().toNumber(); + double result = thisObj->getDateUTCTime().toNumber(); if (MOZ_DOUBLE_IS_FINITE(result)) result = WeekDay(result); @@ -1564,15 +1574,16 @@ date_getHours(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getHours, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getHours, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!GetAndCacheLocalTime(cx, obj)) + if (!GetAndCacheLocalTime(cx, thisObj)) return false; - args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS); + args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS); return true; } @@ -1581,12 +1592,13 @@ date_getUTCHours(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCHours, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getUTCHours, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - double result = obj->getDateUTCTime().toNumber(); + double result = thisObj->getDateUTCTime().toNumber(); if (MOZ_DOUBLE_IS_FINITE(result)) result = HourFromTime(result); @@ -1599,15 +1611,16 @@ date_getMinutes(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getMinutes, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getMinutes, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!GetAndCacheLocalTime(cx, obj)) + if (!GetAndCacheLocalTime(cx, thisObj)) return false; - args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES); + args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES); return true; } @@ -1616,12 +1629,13 @@ date_getUTCMinutes(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMinutes, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getUTCMinutes, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - double result = obj->getDateUTCTime().toNumber(); + double result = thisObj->getDateUTCTime().toNumber(); if (MOZ_DOUBLE_IS_FINITE(result)) result = MinFromTime(result); @@ -1636,15 +1650,16 @@ date_getUTCSeconds(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCSeconds, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getUTCSeconds, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!GetAndCacheLocalTime(cx, obj)) + if (!GetAndCacheLocalTime(cx, thisObj)) return false; - args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS); + args.rval() = thisObj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS); return true; } @@ -1655,12 +1670,13 @@ date_getUTCMilliseconds(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getUTCMilliseconds, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getUTCMilliseconds, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - double result = obj->getDateUTCTime().toNumber(); + double result = thisObj->getDateUTCTime().toNumber(); if (MOZ_DOUBLE_IS_FINITE(result)) result = msFromTime(result); @@ -1673,15 +1689,16 @@ date_getTimezoneOffset(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_getTimezoneOffset, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_getTimezoneOffset, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - double utctime = obj->getDateUTCTime().toNumber(); + double utctime = thisObj->getDateUTCTime().toNumber(); double localtime; - if (!GetAndCacheLocalTime(cx, obj, &localtime)) + if (!GetAndCacheLocalTime(cx, thisObj, &localtime)) return false; /* @@ -1699,13 +1716,14 @@ date_setTime(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - RootedObject obj(cx, NonGenericMethodGuard(cx, args, date_setTime, &DateClass, &ok)); - if (!obj) - return ok; + RootedObject thisObj(cx); + if (!NonGenericMethodGuard(cx, args, date_setTime, &DateClass, thisObj.address())) + return false; + if (!thisObj) + return true; if (args.length() == 0) { - SetDateToNaN(cx, obj, &args.rval()); + SetDateToNaN(cx, thisObj, &args.rval()); return true; } @@ -1713,7 +1731,7 @@ date_setTime(JSContext *cx, unsigned argc, Value *vp) if (!ToNumber(cx, args[0], &result)) return false; - return SetUTCTime(cx, obj, TimeClip(result), &args.rval()); + return SetUTCTime(cx, thisObj, TimeClip(result), &args.rval()); } static JSBool @@ -1721,12 +1739,13 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - RootedObject obj(cx, NonGenericMethodGuard(cx, args, native, &DateClass, &ok)); - if (!obj) - return ok; + RootedObject thisObj(cx); + if (!NonGenericMethodGuard(cx, args, native, &DateClass, thisObj.address())) + return false; + if (!thisObj) + return true; - double result = obj->getDateUTCTime().toNumber(); + double result = thisObj->getDateUTCTime().toNumber(); /* * Satisfy the ECMA rule that if a function is called with @@ -1738,7 +1757,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi * d.setMilliseconds()" returns NaN. Blech. */ if (args.length() == 0) { - SetDateToNaN(cx, obj, &args.rval()); + SetDateToNaN(cx, thisObj, &args.rval()); return true; } @@ -1767,7 +1786,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi /* set Date to NaN, after argument evaluation. */ if (argIsNotFinite) { - SetDateToNaN(cx, obj, &args.rval()); + SetDateToNaN(cx, thisObj, &args.rval()); return true; } @@ -1809,7 +1828,7 @@ date_makeTime(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi if (local) result = UTC(result, cx); - return SetUTCTime(cx, obj, TimeClip(result), &args.rval()); + return SetUTCTime(cx, thisObj, TimeClip(result), &args.rval()); } static JSBool @@ -1865,16 +1884,17 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - RootedObject obj(cx, NonGenericMethodGuard(cx, args, native, &DateClass, &ok)); - if (!obj) - return ok; + RootedObject thisObj(cx); + if (!NonGenericMethodGuard(cx, args, native, &DateClass, thisObj.address())) + return false; + if (!thisObj) + return true; - double result = obj->getDateUTCTime().toNumber(); + double result = thisObj->getDateUTCTime().toNumber(); /* See complaint about ECMA in date_makeTime. */ if (args.length() == 0) { - SetDateToNaN(cx, obj, &args.rval()); + SetDateToNaN(cx, thisObj, &args.rval()); return true; } @@ -1894,7 +1914,7 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi /* If we found a non-finite argument, set the date to NaN and return. */ if (argIsNotFinite) { - SetDateToNaN(cx, obj, &args.rval()); + SetDateToNaN(cx, thisObj, &args.rval()); return true; } @@ -1939,7 +1959,7 @@ date_makeDate(JSContext *cx, Native native, unsigned maxargs, JSBool local, unsi if (local) result = UTC(result, cx); - return SetUTCTime(cx, obj, TimeClip(result), &args.rval()); + return SetUTCTime(cx, thisObj, TimeClip(result), &args.rval()); } static JSBool @@ -1983,24 +2003,25 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - RootedObject obj(cx, NonGenericMethodGuard(cx, args, date_setYear, &DateClass, &ok)); - if (!obj) - return ok; + RootedObject thisObj(cx); + if (!NonGenericMethodGuard(cx, args, date_setYear, &DateClass, thisObj.address())) + return false; + if (!thisObj) + return true; if (args.length() == 0) { /* Call this only after verifying that obj.[[Class]] = "Date". */ - SetDateToNaN(cx, obj, &args.rval()); + SetDateToNaN(cx, thisObj, &args.rval()); return true; } - double result = obj->getDateUTCTime().toNumber(); + double result = thisObj->getDateUTCTime().toNumber(); double year; if (!ToNumber(cx, args[0], &year)) return false; if (!MOZ_DOUBLE_IS_FINITE(year)) { - SetDateToNaN(cx, obj, &args.rval()); + SetDateToNaN(cx, thisObj, &args.rval()); return true; } year = ToInteger(year); @@ -2012,7 +2033,7 @@ date_setYear(JSContext *cx, unsigned argc, Value *vp) result = MakeDate(day, TimeWithinDay(t)); result = UTC(result, cx); - return SetUTCTime(cx, obj, TimeClip(result), &args.rval()); + return SetUTCTime(cx, thisObj, TimeClip(result), &args.rval()); } /* constants for toString, toUTCString */ @@ -2059,12 +2080,13 @@ static JSBool date_utc_format(JSContext *cx, Native native, CallArgs args, void (*printFunc)(char*, size_t, double)) { - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, native, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - double utctime = obj->getDateUTCTime().toNumber(); + double utctime = thisObj->getDateUTCTime().toNumber(); char buf[100]; if (!MOZ_DOUBLE_IS_FINITE(utctime)) { @@ -2338,12 +2360,13 @@ date_toLocaleHelper(JSContext *cx, unsigned argc, Value *vp, Native native, cons { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, native, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - return ToLocaleHelper(cx, args, obj, format); + return ToLocaleHelper(cx, args, thisObj, format); } static JSBool @@ -2398,10 +2421,11 @@ date_toLocaleFormat(JSContext *cx, unsigned argc, Value *vp) CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_toLocaleFormat, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_toLocaleFormat, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; JSString *fmt = ToString(cx, args[0]); if (!fmt) @@ -2412,7 +2436,7 @@ date_toLocaleFormat(JSContext *cx, unsigned argc, Value *vp) if (!fmtbytes) return false; - return ToLocaleHelper(cx, args, obj, fmtbytes.ptr()); + return ToLocaleHelper(cx, args, thisObj, fmtbytes.ptr()); } static JSBool @@ -2420,12 +2444,13 @@ date_toTimeString(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_toTimeString, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_toTimeString, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_TIME, args); + return date_format(cx, thisObj->getDateUTCTime().toNumber(), FORMATSPEC_TIME, args); } static JSBool @@ -2433,12 +2458,13 @@ date_toDateString(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_toDateString, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_toDateString, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_DATE, args); + return date_format(cx, thisObj->getDateUTCTime().toNumber(), FORMATSPEC_DATE, args); } #if JS_HAS_TOSOURCE @@ -2447,13 +2473,15 @@ date_toSource(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_toSource, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_toSource, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; StringBuffer sb(cx); - if (!sb.append("(new Date(") || !NumberValueToStringBuffer(cx, obj->getDateUTCTime(), sb) || + if (!sb.append("(new Date(") || + !NumberValueToStringBuffer(cx, thisObj->getDateUTCTime(), sb) || !sb.append("))")) { return false; @@ -2472,12 +2500,13 @@ date_toString(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_toString, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_toString, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; - return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args); + return date_format(cx, thisObj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args); } static JSBool @@ -2485,14 +2514,15 @@ date_valueOf(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, date_valueOf, &DateClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, date_valueOf, &DateClass, &thisObj)) + return false; + if (!thisObj) + return true; /* If called directly with no arguments, convert to a time number. */ if (argc == 0) { - args.rval() = obj->getDateUTCTime(); + args.rval() = thisObj->getDateUTCTime(); return true; } @@ -2505,10 +2535,10 @@ date_valueOf(JSContext *cx, unsigned argc, Value *vp) return false; JSAtom *number_str = cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]; if (EqualStrings(linear_str, number_str)) { - args.rval() = obj->getDateUTCTime(); + args.rval() = thisObj->getDateUTCTime(); return true; } - return date_format(cx, obj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args); + return date_format(cx, thisObj->getDateUTCTime().toNumber(), FORMATSPEC_FULL, args); } static JSFunctionSpec date_static_methods[] = { diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 52a76992b256..ab4876e5a2a4 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -167,6 +167,12 @@ JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc) return cx->compartment->wrap(cx, desc); } +JS_FRIEND_API(JSBool) +JS_WrapAutoIdVector(JSContext *cx, js::AutoIdVector &props) +{ + return cx->compartment->wrap(cx, props); +} + JS_FRIEND_API(void) JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape) { diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 852db6f5718b..07f7d9a3f132 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -130,6 +130,9 @@ JS_CopyPropertiesFrom(JSContext *cx, JSObject *target, JSObject *obj); extern JS_FRIEND_API(JSBool) JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc); +extern JS_FRIEND_API(JSBool) +JS_WrapAutoIdVector(JSContext *cx, JS::AutoIdVector &props); + extern JS_FRIEND_API(JSBool) JS_EnumerateState(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, js::Value *statep, jsid *idp); diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index b9e09bb44ae6..339b538598f8 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -426,7 +426,7 @@ js::CloneInterpretedFunction(JSContext *cx, JSFunction *srcFun) if (!clone->clearType(cx)) return NULL; - JSScript *clonedScript = CloneScript(cx, srcFun->script()); + JSScript *clonedScript = CloneScript(cx, RootedScript(cx, srcFun->script())); if (!clonedScript) return NULL; @@ -1295,7 +1295,7 @@ js_CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent, * functions. */ if (clone->isInterpreted()) { - JSScript *script = clone->script(); + RootedScript script(cx, clone->script()); JS_ASSERT(script); JS_ASSERT(script->compartment() == fun->compartment()); JS_ASSERT(script->compartment() != cx->compartment); diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 17d4dabdf784..8c3a26ec1405 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -5508,15 +5508,18 @@ JSObject::shouldSplicePrototype(JSContext *cx) } bool -JSObject::splicePrototype(JSContext *cx, JSObject *proto) +JSObject::splicePrototype(JSContext *cx, JSObject *proto_) { + RootedObject proto(cx, proto_); + RootedObject self(cx, this); + /* * For singleton types representing only a single JSObject, the proto * can be rearranged as needed without destroying type information for * the old or new types. Note that type constraints propagating properties * from the old prototype are not removed. */ - JS_ASSERT_IF(cx->typeInferenceEnabled(), hasSingletonType()); + JS_ASSERT_IF(cx->typeInferenceEnabled(), self->hasSingletonType()); /* Inner objects may not appear on prototype chains. */ JS_ASSERT_IF(proto, !proto->getClass()->ext.outerObject); @@ -5525,7 +5528,7 @@ JSObject::splicePrototype(JSContext *cx, JSObject *proto) * Force type instantiation when splicing lazy types. This may fail, * in which case inference will be disabled for the compartment. */ - TypeObject *type = getType(cx); + TypeObject *type = self->getType(cx); TypeObject *protoType = NULL; if (proto) { protoType = proto->getType(cx); @@ -5537,7 +5540,7 @@ JSObject::splicePrototype(JSContext *cx, JSObject *proto) TypeObject *type = proto ? proto->getNewType(cx) : cx->compartment->getEmptyType(cx); if (!type) return false; - type_ = type; + self->type_ = type; return true; } diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 4e8e1e6227c8..ea894439eb71 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -2329,11 +2329,11 @@ BEGIN_CASE(JSOP_GETXPROP) BEGIN_CASE(JSOP_LENGTH) BEGIN_CASE(JSOP_CALLPROP) { - Value rval; - if (!GetPropertyOperation(cx, regs.pc, regs.sp[-1], &rval)) + RootedValue rval(cx); + if (!GetPropertyOperation(cx, regs.pc, regs.sp[-1], rval.address())) goto error; - TypeScript::Monitor(cx, script, regs.pc, rval); + TypeScript::Monitor(cx, script, regs.pc, rval.reference()); regs.sp[-1] = rval; assertSameCompartment(cx, regs.sp[-1]); diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index 49028c90285b..1805f3a9adae 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -287,9 +287,9 @@ SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Val /* Fast path for, e.g., plain Object instance properties. */ obj->nativeSetSlotWithType(cx, shape, rval); } else { - Value rref = rval; + RootedValue rref(cx, rval); bool strict = cx->stack.currentScript()->strictModeCode; - if (!js_NativeSet(cx, obj, shape, false, strict, &rref)) + if (!js_NativeSet(cx, obj, shape, false, strict, rref.address())) return false; } return true; diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index bce911da94f0..58c7543da3ec 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -828,12 +828,13 @@ iterator_next(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - RootedObject obj(cx, NonGenericMethodGuard(cx, args, iterator_next, &IteratorClass, &ok)); - if (!obj) - return ok; + RootedObject thisObj(cx); + if (!NonGenericMethodGuard(cx, args, iterator_next, &IteratorClass, thisObj.address())) + return false; + if (!thisObj) + return true; - if (!js_IteratorMore(cx, obj, &args.rval())) + if (!js_IteratorMore(cx, thisObj, &args.rval())) return false; if (!args.rval().toBoolean()) { @@ -841,7 +842,7 @@ iterator_next(JSContext *cx, unsigned argc, Value *vp) return false; } - return js_IteratorNext(cx, obj, &args.rval()); + return js_IteratorNext(cx, thisObj, &args.rval()); } #define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT) @@ -1582,12 +1583,13 @@ generator_op(JSContext *cx, Native native, JSGeneratorOp op, Value *vp, unsigned { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, native, &GeneratorClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, native, &GeneratorClass, &thisObj)) + return false; + if (!thisObj) + return true; - JSGenerator *gen = (JSGenerator *) obj->getPrivate(); + JSGenerator *gen = (JSGenerator *) thisObj->getPrivate(); if (!gen) { /* This happens when obj is the generator prototype. See bug 352885. */ goto closed_generator; @@ -1630,7 +1632,7 @@ generator_op(JSContext *cx, Native native, JSGeneratorOp op, Value *vp, unsigned } bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && args.length() != 0); - if (!SendToGenerator(cx, op, obj, gen, undef ? args[0] : UndefinedValue())) + if (!SendToGenerator(cx, op, thisObj, gen, undef ? args[0] : UndefinedValue())) return false; args.rval() = gen->fp->returnValue(); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index f3adca88a830..46ef1fb4ef20 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1930,7 +1930,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD JS_ASSERT(obj == obj2); - const Shape *shape = reinterpret_cast(current); + Rooted shape(cx, reinterpret_cast(current)); do { if (desc.isAccessorDescriptor()) { if (!shape->isAccessorDescriptor()) @@ -3040,10 +3040,8 @@ Detecting(JSContext *cx, jsbytecode *pc) } /* - * Infer lookup flags from the currently executing bytecode. This does - * not attempt to infer JSRESOLVE_WITH, because the current bytecode - * does not indicate whether we are in a with statement. Return defaultFlags - * if a currently executing bytecode cannot be determined. + * Infer lookup flags from the currently executing bytecode, returning + * defaultFlags if a currently executing bytecode cannot be determined. */ unsigned js_InferFlags(JSContext *cx, unsigned defaultFlags) @@ -4974,7 +4972,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, bool Rooted shapeRoot(cx, shape); int32_t sample = cx->runtime->propertyRemovals; - if (!shape->set(cx, RootedObject(cx, obj), strict, vp)) + if (!shapeRoot->set(cx, RootedObject(cx, obj), strict, vp)) return false; /* diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index dfbc93d52f26..79e01b1c14f8 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -459,6 +459,7 @@ bool IndirectProxyHandler::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args) { + args.thisv() = ObjectValue(*GetProxyTargetObject(proxy)); return CallJSNative(cx, native, args); } diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index b4722bdf7cfd..eafc1f66039b 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -965,7 +965,7 @@ JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *n RootedShape newRoot(cx, newShape); if (!toDictionaryMode(cx)) return NULL; - oldShape = self->lastProperty(); + oldShape = selfRoot->lastProperty(); self = selfRoot; newShape = newRoot; } @@ -976,7 +976,7 @@ JSObject::replaceWithNewEquivalentShape(JSContext *cx, Shape *oldShape, Shape *n newShape = js_NewGCShape(cx); if (!newShape) return NULL; - new (newShape) Shape(oldShape->base()->unowned(), 0); + new (newShape) Shape(oldRoot->base()->unowned(), 0); self = selfRoot; oldShape = oldRoot; } @@ -1315,7 +1315,7 @@ EmptyShape::getInitialShape(JSContext *cx, Class *clasp, JSObject *proto, JSObje } void -NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto) +NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto_) { Class *clasp = shape->getObjectClass(); @@ -1323,7 +1323,8 @@ NewObjectCache::invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject if (CanBeFinalizedInBackground(kind, clasp)) kind = GetBackgroundAllocKind(kind); - GlobalObject *global = &shape->getObjectParent()->global(); + Rooted global(cx, &shape->getObjectParent()->global()); + RootedObject proto(cx, proto_); types::TypeObject *type = proto->getNewType(cx); EntryIndex entry; diff --git a/js/src/jsscope.h b/js/src/jsscope.h index 70d8117715f4..73edef007dc5 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -1110,8 +1110,8 @@ Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding) if (start->isBigEnoughForAShapeTable()) { RootedShape startRoot(cx, start); RootedId idRoot(cx, id); - if (start->hashify(cx)) { - Shape **spp = start->table().search(id, adding); + if (startRoot->hashify(cx)) { + Shape **spp = startRoot->table().search(id, adding); return SHAPE_FETCH(spp); } start = startRoot; diff --git a/js/src/jsscopeinlines.h b/js/src/jsscopeinlines.h index 1ddec3a97975..dc96897a9516 100644 --- a/js/src/jsscopeinlines.h +++ b/js/src/jsscopeinlines.h @@ -259,7 +259,7 @@ Shape::getUserId(JSContext *cx, jsid *idp) const return ValueToId(cx, Int32Value(id), idp); *idp = INT_TO_JSID(id); } else { - *idp = propid(); + *idp = self->propid(); } return true; } @@ -274,11 +274,12 @@ Shape::get(JSContext* cx, HandleObject receiver, JSObject* obj, JSObject *pobj, return InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp); } + Rooted self(cx, this); RootedId id(cx); - if (!getUserId(cx, id.address())) + if (!self->getUserId(cx, id.address())) return false; - return CallJSPropertyOp(cx, getterOp(), receiver, id, vp); + return CallJSPropertyOp(cx, self->getterOp(), receiver, id, vp); } inline bool @@ -294,8 +295,9 @@ Shape::set(JSContext* cx, HandleObject obj, bool strict, Value* vp) const if (attrs & JSPROP_GETTER) return js_ReportGetterOnlyAssignment(cx); + Rooted self(cx, this); RootedId id(cx); - if (!getUserId(cx, id.address())) + if (!self->getUserId(cx, id.address())) return false; /* @@ -304,10 +306,10 @@ Shape::set(JSContext* cx, HandleObject obj, bool strict, Value* vp) const */ if (obj->isWith()) { RootedObject nobj(cx, &obj->asWith().object()); - return CallJSPropertyOpSetter(cx, setterOp(), nobj, id, strict, vp); + return CallJSPropertyOpSetter(cx, self->setterOp(), nobj, id, strict, vp); } - return CallJSPropertyOpSetter(cx, setterOp(), obj, id, strict, vp); + return CallJSPropertyOpSetter(cx, self->setterOp(), obj, id, strict, vp); } inline void diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index bc8a598c4adc..0636203ce4b7 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1684,7 +1684,7 @@ Rebase(JSScript *dst, JSScript *src, T *srcp) } JSScript * -js::CloneScript(JSContext *cx, JSScript *src) +js::CloneScript(JSContext *cx, HandleScript src) { /* NB: Keep this in sync with XDRScript. */ @@ -1707,6 +1707,7 @@ js::CloneScript(JSContext *cx, JSScript *src) /* Bindings */ Bindings bindings(cx); + Bindings::AutoRooter bindingsRoot(cx, &bindings); BindingNames names(cx); if (!src->bindings.getLocalNameArray(cx, &names)) return NULL; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 6f1b7569b46b..c5873129090a 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1050,7 +1050,7 @@ inline void CurrentScriptFileLineOrigin(JSContext *cx, unsigned *linenop, LineOption = NOT_CALLED_FROM_JSOP_EVAL); extern JSScript * -CloneScript(JSContext *cx, JSScript *script); +CloneScript(JSContext *cx, HandleScript script); /* * NB: after a successful XDR_DECODE, XDRScript callers must do any required diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index ee7aa5d7f696..826b5bbb4925 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -134,12 +134,13 @@ ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_slice, &ArrayBufferClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_slice, &ArrayBufferClass, &thisObj)) + return false; + if (!thisObj) + return true; - ArrayBufferObject &arrayBuffer = obj->asArrayBuffer(); + ArrayBufferObject &arrayBuffer = thisObj->asArrayBuffer(); // these are the default values int32_t length = int32_t(arrayBuffer.byteLength()); @@ -485,7 +486,8 @@ JSBool ArrayBufferObject::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, Value *vp) { - RootedObject delegate(cx, DelegateObject(cx, RootedObject(cx, getArrayBuffer(obj)))); + RootedObject buffer(cx, getArrayBuffer(obj)); + RootedObject delegate(cx, DelegateObject(cx, buffer)); if (!delegate) return false; return baseops::GetElement(cx, delegate, receiver, index, vp); @@ -495,7 +497,8 @@ JSBool ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, Value *vp, bool *present) { - JSObject *delegate = DelegateObject(cx, RootedObject(cx, getArrayBuffer(obj))); + RootedObject buffer(cx, getArrayBuffer(obj)); + RootedObject delegate(cx, DelegateObject(cx, buffer)); if (!delegate) return false; return delegate->getElementIfPresent(cx, receiver, index, vp, present); @@ -1419,14 +1422,14 @@ class TypedArrayTemplate obj->setSlot(FIELD_BUFFER, ObjectValue(*bufobj)); JS_ASSERT(bufobj->isArrayBuffer()); - ArrayBufferObject &buffer = bufobj->asArrayBuffer(); + Rooted buffer(cx, &bufobj->asArrayBuffer()); /* * N.B. The base of the array's data is stored in the object's * private data rather than a slot, to avoid alignment restrictions * on private Values. */ - obj->setPrivate(buffer.dataPointer() + byteOffset); + obj->setPrivate(buffer->dataPointer() + byteOffset); obj->setSlot(FIELD_LENGTH, Int32Value(len)); obj->setSlot(FIELD_BYTEOFFSET, Int32Value(byteOffset)); @@ -1442,10 +1445,10 @@ class TypedArrayTemplate return NULL; obj->setLastPropertyInfallible(empty); - DebugOnly bufferByteLength = buffer.byteLength(); + DebugOnly bufferByteLength = buffer->byteLength(); JS_ASSERT(bufferByteLength - getByteOffset(obj) >= getByteLength(obj)); JS_ASSERT(getByteOffset(obj) <= bufferByteLength); - JS_ASSERT(buffer.dataPointer() <= getDataOffset(obj)); + JS_ASSERT(buffer->dataPointer() <= getDataOffset(obj)); JS_ASSERT(getDataOffset(obj) <= offsetData(obj, bufferByteLength)); JS_ASSERT(obj->numFixedSlots() == NUM_FIXED_SLOTS); @@ -1453,6 +1456,13 @@ class TypedArrayTemplate return obj; } + static JSObject * + makeInstance(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, uint32_t len) + { + RootedObject nullproto(cx, NULL); + return makeInstance(cx, bufobj, byteOffset, len, nullproto); + } + /* * new [Type]Array(length) * new [Type]Array(otherTypedArray) @@ -1474,8 +1484,9 @@ class TypedArrayTemplate fromBuffer(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - JSObject *obj = fromBuffer(cx, RootedObject(cx, &args[0].toObject()), - args[1].toInt32(), args[2].toInt32(), RootedObject(cx, &args[3].toObject())); + RootedObject buffer(cx, &args[0].toObject()); + RootedObject proto(cx, &args[3].toObject()); + JSObject *obj = fromBuffer(cx, buffer, args[1].toInt32(), args[2].toInt32(), proto); if (!obj) return false; vp->setObject(*obj); @@ -1544,12 +1555,13 @@ class TypedArrayTemplate { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_subarray, fastClass(), &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_subarray, fastClass(), &thisObj)) + return false; + if (!thisObj) + return true; - JSObject *tarray = getTypedArray(obj); + JSObject *tarray = getTypedArray(thisObj); if (!tarray) return true; @@ -1583,12 +1595,13 @@ class TypedArrayTemplate { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - RootedObject obj(cx, NonGenericMethodGuard(cx, args, fun_set, fastClass(), &ok)); - if (!obj) - return ok; + RootedObject thisObj(cx); + if (!NonGenericMethodGuard(cx, args, fun_set, fastClass(), thisObj.address())) + return false; + if (!thisObj) + return true; - RootedObject tarray(cx, getTypedArray(obj)); + RootedObject tarray(cx, getTypedArray(thisObj)); if (!tarray) return true; @@ -1623,7 +1636,7 @@ class TypedArrayTemplate return false; } - if (!copyFromTypedArray(cx, obj, src, offset)) + if (!copyFromTypedArray(cx, thisObj, src, offset)) return false; } else { src = arg0; @@ -1637,7 +1650,7 @@ class TypedArrayTemplate return false; } - if (!copyFromArray(cx, obj, src, len, offset)) + if (!copyFromArray(cx, thisObj, src, len, offset)) return false; } @@ -1743,7 +1756,7 @@ class TypedArrayTemplate RootedObject buffer(cx, createBufferWithSizeAndCount(cx, nelements)); if (!buffer) return NULL; - return makeInstance(cx, buffer, 0, nelements, RootedObject(cx, NULL)); + return makeInstance(cx, buffer, 0, nelements); } static JSObject * @@ -1757,7 +1770,7 @@ class TypedArrayTemplate if (!bufobj) return NULL; - RootedObject obj(cx, makeInstance(cx, bufobj, 0, len, RootedObject(cx))); + RootedObject obj(cx, makeInstance(cx, bufobj, 0, len)); if (!obj || !copyFromArray(cx, obj, other, len)) return NULL; return obj; @@ -1795,7 +1808,7 @@ class TypedArrayTemplate JS_ASSERT(UINT32_MAX - begin * sizeof(NativeType) >= getByteOffset(tarray)); uint32_t byteOffset = getByteOffset(tarray) + begin * sizeof(NativeType); - return makeInstance(cx, bufobj, byteOffset, length, RootedObject(cx)); + return makeInstance(cx, bufobj, byteOffset, length); } protected: @@ -2287,6 +2300,9 @@ DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp) argv[argc + 2].setObject(*proto); argv[0].setUndefined(); // We want to use a different callee (avoid an assertion) + // Appease 'thisv' assertion in CrossCompartmentWrapper::nativeCall + argv[1].setMagic(JS_IS_CONSTRUCTING); + CallArgs proxyArgs = CallArgsFromVp(argc + 1, argv.begin()); if (!Proxy::nativeCall(cx, bufobj, &DataViewClass, constructWithProto, proxyArgs)) return false; @@ -2481,13 +2497,14 @@ DataViewObject::fun_getInt8(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_getInt8, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_getInt8, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; int8_t val; - if (!obj->asDataView().read(cx, args, &val, "getInt8")) + if (!thisObj->asDataView().read(cx, args, &val, "getInt8")) return false; args.rval().setInt32(val); return true; @@ -2498,13 +2515,14 @@ DataViewObject::fun_getUint8(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_getUint8, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_getUint8, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; uint8_t val; - if (!obj->asDataView().read(cx, args, &val, "getUint8")) + if (!thisObj->asDataView().read(cx, args, &val, "getUint8")) return false; args.rval().setInt32(val); return true; @@ -2515,13 +2533,14 @@ DataViewObject::fun_getInt16(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_getInt16, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_getInt16, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; int16_t val; - if (!obj->asDataView().read(cx, args, &val, "getInt16")) + if (!thisObj->asDataView().read(cx, args, &val, "getInt16")) return false; args.rval().setInt32(val); return true; @@ -2532,13 +2551,14 @@ DataViewObject::fun_getUint16(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_getUint16, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_getUint16, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; uint16_t val; - if (!obj->asDataView().read(cx, args, &val, "getUint16")) + if (!thisObj->asDataView().read(cx, args, &val, "getUint16")) return false; args.rval().setInt32(val); return true; @@ -2549,13 +2569,14 @@ DataViewObject::fun_getInt32(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_getInt32, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_getInt32, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; int32_t val; - if (!obj->asDataView().read(cx, args, &val, "getInt32")) + if (!thisObj->asDataView().read(cx, args, &val, "getInt32")) return false; args.rval().setInt32(val); return true; @@ -2566,13 +2587,14 @@ DataViewObject::fun_getUint32(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_getUint32, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_getUint32, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; uint32_t val; - if (!obj->asDataView().read(cx, args, &val, "getUint32")) + if (!thisObj->asDataView().read(cx, args, &val, "getUint32")) return false; args.rval().setNumber(val); return true; @@ -2583,13 +2605,14 @@ DataViewObject::fun_getFloat32(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_getFloat32, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_getFloat32, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; float val; - if (!obj->asDataView().read(cx, args, &val, "getFloat32")) + if (!thisObj->asDataView().read(cx, args, &val, "getFloat32")) return false; args.rval().setDouble(JS_CANONICALIZE_NAN(val)); @@ -2601,13 +2624,14 @@ DataViewObject::fun_getFloat64(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_getFloat64, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_getFloat64, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; double val; - if (!obj->asDataView().read(cx, args, &val, "getFloat64")) + if (!thisObj->asDataView().read(cx, args, &val, "getFloat64")) return false; args.rval().setDouble(JS_CANONICALIZE_NAN(val)); @@ -2619,12 +2643,13 @@ DataViewObject::fun_setInt8(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_setInt8, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_setInt8, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!obj->asDataView().write(cx, args, "setInt8")) + if (!thisObj->asDataView().write(cx, args, "setInt8")) return false; args.rval().setUndefined(); return true; @@ -2635,12 +2660,13 @@ DataViewObject::fun_setUint8(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_setUint8, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_setUint8, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!obj->asDataView().write(cx, args, "setUint8")) + if (!thisObj->asDataView().write(cx, args, "setUint8")) return false; args.rval().setUndefined(); return true; @@ -2651,12 +2677,13 @@ DataViewObject::fun_setInt16(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_setInt16, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_setInt16, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!obj->asDataView().write(cx, args, "setInt16")) + if (!thisObj->asDataView().write(cx, args, "setInt16")) return false; args.rval().setUndefined(); return true; @@ -2667,12 +2694,13 @@ DataViewObject::fun_setUint16(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_setUint16, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_setUint16, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!obj->asDataView().write(cx, args, "setUint16")) + if (!thisObj->asDataView().write(cx, args, "setUint16")) return false; args.rval().setUndefined(); return true; @@ -2683,12 +2711,13 @@ DataViewObject::fun_setInt32(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_setInt32, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_setInt32, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!obj->asDataView().write(cx, args, "setInt32")) + if (!thisObj->asDataView().write(cx, args, "setInt32")) return false; args.rval().setUndefined(); return true; @@ -2699,12 +2728,13 @@ DataViewObject::fun_setUint32(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_setUint32, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_setUint32, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!obj->asDataView().write(cx, args, "setUint32")) + if (!thisObj->asDataView().write(cx, args, "setUint32")) return false; args.rval().setUndefined(); return true; @@ -2715,12 +2745,13 @@ DataViewObject::fun_setFloat32(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_setFloat32, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_setFloat32, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!obj->asDataView().write(cx, args, "setFloat32")) + if (!thisObj->asDataView().write(cx, args, "setFloat32")) return false; args.rval().setUndefined(); return true; @@ -2731,12 +2762,13 @@ DataViewObject::fun_setFloat64(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, fun_setFloat64, &DataViewClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, fun_setFloat64, &DataViewClass, &thisObj)) + return false; + if (!thisObj) + return true; - if (!obj->asDataView().write(cx, args, "setFloat64")) + if (!thisObj->asDataView().write(cx, args, "setFloat64")) return false; args.rval().setUndefined(); return true; @@ -2918,6 +2950,7 @@ IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double) #_typedArray, \ JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) | \ JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | \ + JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray) | \ JSCLASS_FOR_OF_ITERATION | \ Class::NON_NATIVE, \ JS_PropertyStub, /* addProperty */ \ diff --git a/js/src/jsval.h b/js/src/jsval.h index 9fcf07980737..2ee90a8e4fa8 100644 --- a/js/src/jsval.h +++ b/js/src/jsval.h @@ -12,8 +12,6 @@ * Implementation details for js::Value in jsapi.h. */ -#include "mozilla/FloatingPoint.h" - #include "js/Utility.h" JS_BEGIN_EXTERN_C diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index 97e106c2d1cd..e56ecb937f59 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -125,10 +125,11 @@ WeakMap_has(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_has, &WeakMapClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, WeakMap_has, &WeakMapClass, &thisObj)) + return false; + if (!thisObj) + return true; if (args.length() < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -139,7 +140,7 @@ WeakMap_has(JSContext *cx, unsigned argc, Value *vp) if (!key) return false; - ObjectValueMap *map = GetObjectMap(obj); + ObjectValueMap *map = GetObjectMap(thisObj); if (map) { ObjectValueMap::Ptr ptr = map->lookup(key); if (ptr) { @@ -157,10 +158,11 @@ WeakMap_get(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_get, &WeakMapClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, WeakMap_get, &WeakMapClass, &thisObj)) + return false; + if (!thisObj) + return true; if (args.length() < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -171,7 +173,7 @@ WeakMap_get(JSContext *cx, unsigned argc, Value *vp) if (!key) return false; - ObjectValueMap *map = GetObjectMap(obj); + ObjectValueMap *map = GetObjectMap(thisObj); if (map) { ObjectValueMap::Ptr ptr = map->lookup(key); if (ptr) { @@ -189,10 +191,11 @@ WeakMap_delete(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_delete, &WeakMapClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, WeakMap_delete, &WeakMapClass, &thisObj)) + return false; + if (!thisObj) + return true; if (args.length() < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -203,7 +206,7 @@ WeakMap_delete(JSContext *cx, unsigned argc, Value *vp) if (!key) return false; - ObjectValueMap *map = GetObjectMap(obj); + ObjectValueMap *map = GetObjectMap(thisObj); if (map) { ObjectValueMap::Ptr ptr = map->lookup(key); if (ptr) { @@ -222,10 +225,11 @@ WeakMap_set(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - bool ok; - JSObject *obj = NonGenericMethodGuard(cx, args, WeakMap_set, &WeakMapClass, &ok); - if (!obj) - return ok; + JSObject *thisObj; + if (!NonGenericMethodGuard(cx, args, WeakMap_set, &WeakMapClass, &thisObj)) + return false; + if (!thisObj) + return true; if (args.length() < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -238,14 +242,14 @@ WeakMap_set(JSContext *cx, unsigned argc, Value *vp) Value value = (args.length() > 1) ? args[1] : UndefinedValue(); - ObjectValueMap *map = GetObjectMap(obj); + ObjectValueMap *map = GetObjectMap(thisObj); if (!map) { - map = cx->new_(cx, obj); + map = cx->new_(cx, thisObj); if (!map->init()) { cx->delete_(map); goto out_of_memory; } - obj->setPrivate(map); + thisObj->setPrivate(map); } if (!map->put(key, value)) diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index d4ea544b8f0a..41749af14183 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -706,7 +706,7 @@ CrossCompartmentWrapper::nativeCall(JSContext *cx, JSObject *wrapper, Class *cla return false; } - if (!DirectWrapper::nativeCall(cx, wrapper, clasp, native, dstArgs)) + if (!CallJSNative(cx, native, dstArgs)) return false; srcArgs.rval() = dstArgs.rval(); diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 4ab549e0089d..6fcfdc01754e 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -491,6 +491,37 @@ NewXMLAttributeName(JSContext *cx, JSLinearString *uri, JSLinearString *prefix, return obj; } +static JSObject * +ConstructObjectWithArguments(JSContext *cx, Class *clasp, JSObject *parent, + unsigned argc, jsval *argv) +{ + assertSameCompartment(cx, parent, JSValueArray(argv, argc)); + + AutoArrayRooter argtvr(cx, argc, argv); + + JSProtoKey protoKey = GetClassProtoKey(clasp); + + /* Protect constructor in case a crazy getter for .prototype uproots it. */ + RootedValue value(cx); + if (!js_FindClassObject(cx, parent, protoKey, value.address(), clasp)) + return NULL; + + Value rval; + if (!InvokeConstructor(cx, value, argc, argv, &rval)) + return NULL; + + /* + * If the instance's class differs from what was requested, throw a type + * error. + */ + if (!rval.isObject() || rval.toObject().getClass() != clasp) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_WRONG_CONSTRUCTOR, clasp->name); + return NULL; + } + return &rval.toObject(); +} + JSObject * js_ConstructXMLQNameObject(JSContext *cx, const Value &nsval, const Value &lnval) { @@ -508,7 +539,7 @@ js_ConstructXMLQNameObject(JSContext *cx, const Value &nsval, const Value &lnval argv[0] = nsval; } argv[1] = lnval; - return JS_ConstructObjectWithArguments(cx, Jsvalify(&QNameClass), NULL, 2, argv); + return ConstructObjectWithArguments(cx, &QNameClass, NULL, 2, argv); } static JSBool @@ -2250,7 +2281,7 @@ GetNamespace(JSContext *cx, JSObject *qn, const JSXMLArray *inScopeNSe if (!match) { argv[0] = prefix ? STRING_TO_JSVAL(prefix) : JSVAL_VOID; argv[1] = STRING_TO_JSVAL(uri); - ns = JS_ConstructObjectWithArguments(cx, Jsvalify(&NamespaceClass), NULL, 2, argv); + ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, 2, argv); if (!ns) return NULL; match = ns; @@ -2929,7 +2960,7 @@ ToXMLName(JSContext *cx, jsval v, jsid *funidp) construct: v = STRING_TO_JSVAL(name); - obj = JS_ConstructObjectWithArguments(cx, Jsvalify(&QNameClass), NULL, 1, &v); + obj = ConstructObjectWithArguments(cx, &QNameClass, NULL, 1, &v); if (!obj) return NULL; @@ -6713,7 +6744,7 @@ xml_setName(JSContext *cx, unsigned argc, jsval *vp) } } - nameqn = JS_ConstructObjectWithArguments(cx, Jsvalify(&QNameClass), NULL, 1, &name); + nameqn = ConstructObjectWithArguments(cx, &QNameClass, NULL, 1, &name); if (!nameqn) return JS_FALSE; @@ -6818,8 +6849,7 @@ xml_setNamespace(JSContext *cx, unsigned argc, jsval *vp) if (!JSXML_HAS_NAME(xml)) return JS_TRUE; - ns = JS_ConstructObjectWithArguments(cx, Jsvalify(&NamespaceClass), NULL, - argc == 0 ? 0 : 1, vp + 2); + ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, argc == 0 ? 0 : 1, vp + 2); if (!ns) return JS_FALSE; vp[0] = OBJECT_TO_JSVAL(ns); @@ -6827,7 +6857,7 @@ xml_setNamespace(JSContext *cx, unsigned argc, jsval *vp) qnargv[0] = OBJECT_TO_JSVAL(ns); qnargv[1] = OBJECT_TO_JSVAL(xml->name); - qn = JS_ConstructObjectWithArguments(cx, Jsvalify(&QNameClass), NULL, 2, qnargv); + qn = ConstructObjectWithArguments(cx, &QNameClass, NULL, 2, qnargv); if (!qn) return JS_FALSE; @@ -7569,7 +7599,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) obj = tmp; } - ns = JS_ConstructObjectWithArguments(cx, Jsvalify(&NamespaceClass), NULL, 0, NULL); + ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, 0, NULL); if (!ns) return JS_FALSE; v = OBJECT_TO_JSVAL(ns); @@ -7587,7 +7617,7 @@ js_SetDefaultXMLNamespace(JSContext *cx, const Value &v) Value argv[2]; argv[0].setString(cx->runtime->emptyString); argv[1] = v; - JSObject *ns = JS_ConstructObjectWithArguments(cx, Jsvalify(&NamespaceClass), NULL, 2, argv); + JSObject *ns = ConstructObjectWithArguments(cx, &NamespaceClass, NULL, 2, argv); if (!ns) return JS_FALSE; @@ -7705,7 +7735,7 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i nameobj = &nameval.toObject(); if (nameobj->getClass() == &AnyNameClass) { v = STRING_TO_JSVAL(cx->runtime->atomState.starAtom); - nameobj = JS_ConstructObjectWithArguments(cx, Jsvalify(&QNameClass), NULL, 1, &v); + nameobj = ConstructObjectWithArguments(cx, &QNameClass, NULL, 1, &v); if (!nameobj) return JS_FALSE; } else { diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 03e467484e1e..56fba44e4444 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2143,7 +2143,7 @@ DumpStack(JSContext *cx, unsigned argc, Value *vp) uint32_t index = 0; for (; !iter.done(); ++index, ++iter) { - Value v; + RootedValue v(cx); if (iter.isNonEvalFunctionFrame() || iter.isNativeCall()) { v = iter.calleev(); } else if (iter.isEvalFrame()) { @@ -2151,9 +2151,9 @@ DumpStack(JSContext *cx, unsigned argc, Value *vp) } else { v = StringValue(globalStr); } - if (!JS_WrapValue(cx, &v)) + if (!JS_WrapValue(cx, v.address())) return false; - if (!JS_SetElement(cx, arr, index, &v)) + if (!JS_SetElement(cx, arr, index, v.address())) return false; } diff --git a/js/src/tests/js1_8_5/extensions/dataview.js b/js/src/tests/js1_8_5/extensions/dataview.js index bc4dc42a4f80..56cd93c6ec33 100644 --- a/js/src/tests/js1_8_5/extensions/dataview.js +++ b/js/src/tests/js1_8_5/extensions/dataview.js @@ -1631,6 +1631,14 @@ function test() { assertEq(av.getUint8(4), 100); assertEq(Object.getPrototypeOf(av), DataView.prototype); + // Bug 760904: call another compartment's constructor with an ArrayBuffer + // from this compartment, both as a constructor and as a regular call. (The + // latter is what was broken in that bug.) + var alien_constructor = alien.DataView; + var local_buffer = (new Int8Array(3)).buffer; + var foreign_exchange_student_1 = alien_constructor(local_buffer); + var foreign_exchange_student_2 = new alien_constructor(local_buffer); + reportCompare(0, 0, 'done.'); exitFunc ('test'); } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index c766b4646770..6e1210193e08 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -941,7 +941,7 @@ Debugger::fireEnterFrame(JSContext *cx, Value *vp) } void -Debugger::fireNewScript(JSContext *cx, Handle script) +Debugger::fireNewScript(JSContext *cx, HandleScript script) { RootedObject hook(cx, getHook(OnNewScript)); JS_ASSERT(hook); @@ -2376,7 +2376,7 @@ Class DebuggerScript_class = { }; JSObject * -Debugger::newDebuggerScript(JSContext *cx, Handle script) +Debugger::newDebuggerScript(JSContext *cx, HandleScript script) { assertSameCompartment(cx, object.get()); @@ -2392,7 +2392,7 @@ Debugger::newDebuggerScript(JSContext *cx, Handle script) } JSObject * -Debugger::wrapScript(JSContext *cx, Handle script) +Debugger::wrapScript(JSContext *cx, HandleScript script) { assertSameCompartment(cx, object.get()); JS_ASSERT(cx->compartment != script->compartment()); @@ -4396,7 +4396,7 @@ DebuggerEnv_getVariable(JSContext *cx, unsigned argc, Value *vp) if (!ValueToIdentifier(cx, args[0], id.address())) return false; - Value v; + RootedValue v(cx); { AutoCompartment ac(cx, env); if (!ac.enter() || !cx->compartment->wrapId(cx, id.address())) @@ -4404,11 +4404,11 @@ DebuggerEnv_getVariable(JSContext *cx, unsigned argc, Value *vp) /* This can trigger getters. */ ErrorCopier ec(ac, dbg->toJSObject()); - if (!env->getGeneric(cx, id, &v)) + if (!env->getGeneric(cx, id, v.address())) return false; } - if (!dbg->wrapDebuggeeValue(cx, &v)) + if (!dbg->wrapDebuggeeValue(cx, v.address())) return false; args.rval() = v; return true; diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 392e013be8b1..89c634f1ef89 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -190,13 +190,13 @@ class Debugger { * Allocate and initialize a Debugger.Script instance whose referent is * |script|. */ - JSObject *newDebuggerScript(JSContext *cx, Handle script); + JSObject *newDebuggerScript(JSContext *cx, HandleScript script); /* * Receive a "new script" event from the engine. A new script was compiled * or deserialized. */ - void fireNewScript(JSContext *cx, Handle script); + void fireNewScript(JSContext *cx, HandleScript script); static inline Debugger *fromLinks(JSCList *links); inline Breakpoint *firstBreakpoint() const; @@ -337,7 +337,7 @@ class Debugger { * needed. The context |cx| must be in the debugger compartment; |script| * must be a script in a debuggee compartment. */ - JSObject *wrapScript(JSContext *cx, Handle script); + JSObject *wrapScript(JSContext *cx, HandleScript script); private: Debugger(const Debugger &) MOZ_DELETE; diff --git a/js/src/vm/MethodGuard-inl.h b/js/src/vm/MethodGuard-inl.h index 334bf569f52e..d69cd0a39013 100644 --- a/js/src/vm/MethodGuard-inl.h +++ b/js/src/vm/MethodGuard-inl.h @@ -53,20 +53,20 @@ class PrimitiveBehavior { } /* namespace detail */ -inline JSObject * -NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok) +inline bool +NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, JSObject **thisObj) { const Value &thisv = args.thisv(); if (thisv.isObject()) { JSObject &obj = thisv.toObject(); if (obj.getClass() == clasp) { - *ok = true; /* quell gcc overwarning */ - return &obj; + *thisObj = &obj; + return true; } } - *ok = HandleNonGenericMethodClassMismatch(cx, args, native, clasp); - return NULL; + *thisObj = NULL; + return HandleNonGenericMethodClassMismatch(cx, args, native, clasp); } template @@ -81,10 +81,11 @@ BoxedPrimitiveMethodGuard(JSContext *cx, CallArgs args, Native native, T *v, boo return true; } - if (!NonGenericMethodGuard(cx, args, native, Behavior::getClass(), ok)) + JSObject *thisObj; + *ok = NonGenericMethodGuard(cx, args, native, Behavior::getClass(), &thisObj); + if (!*ok || !thisObj) return false; - - *v = Behavior::extract(thisv.toObject()); + *v = Behavior::extract(*thisObj); return true; } diff --git a/js/src/vm/MethodGuard.h b/js/src/vm/MethodGuard.h index 125240a1922a..c0eb04034ede 100644 --- a/js/src/vm/MethodGuard.h +++ b/js/src/vm/MethodGuard.h @@ -32,31 +32,36 @@ ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp); * NonGenericMethodGuard performs this checking. Canonical usage is: * * CallArgs args = ... - * bool ok; - * JSObject *thisObj = NonGenericMethodGuard(cx, args, clasp, &ok); + * JSObject *thisObj; + * if (!NonGenericMethodGuard(cx, args, clasp, &thisObj)) + * return false; * if (!thisObj) - * return ok; + * return true; * - * Specifically: if obj is a proxy, NonGenericMethodGuard will call the - * object's ProxyHandler's nativeCall hook (which may recursively call - * args.callee in args.thisv's compartment). Thus, there are three possible - * post-conditions: + * Specifically: if args.thisv is a proxy, NonGenericMethodGuard will call its + * ProxyHandler's nativeCall hook (which may recursively call args.callee in + * args.thisv's compartment). These are the possible post-conditions: * - * 1. thisv is an object of the given clasp: the caller may proceed; + * 1. NonGenericMethodGuard returned false because it encountered an error: + * args.thisv wasn't an object, was an object of the wrong class, was a + * proxy to an object of the wrong class, or was a proxy to an object of + * the right class but the recursive call to args.callee failed. This case + * should be handled like any other failure: propagate it, or catch it and + * continue. + * 2. NonGenericMethodGuard returned true, and thisObj was nulled out. In + * this case args.thisv was a proxy to an object with the desired class, + * and recursive invocation of args.callee succeeded. This completes the + * invocation of args.callee, so return true. + * 3. NonGenericMethodGuard returned true, and thisObj was set to a non-null + * pointer. In this case args.thisv was exactly an object of the desired + * class, and not a proxy to one. Finish up the call using thisObj as the + * this object provided to the call, which will have clasp as its class. * - * 2. there was an error: the caller must return 'false'; - * - * 3. thisv wrapped an object of the given clasp and the native was reentered - * and completed succesfully: the caller must return 'true'. - * - * Case 1 is indicated by a non-NULL return value; case 2 by a NULL return - * value with *ok == false; and case 3 by a NULL return value with *ok == true. - * - * NB: since this guard may reenter the native, the guard must be placed before - * any effectful operations are performed. + * Be careful! This guard may reenter the native, so the guard must be placed + * before any effectful operations are performed. */ -inline JSObject * -NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, bool *ok); +inline bool +NonGenericMethodGuard(JSContext *cx, CallArgs args, Native native, Class *clasp, JSObject **thisObj); /* * NonGenericMethodGuard tests args.thisv's class using 'clasp'. If more than diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 72142bd011da..c5d443717475 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -332,12 +332,6 @@ WithObject::create(JSContext *cx, HandleObject proto, HandleObject enclosing, ui static JSBool with_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp, JSProperty **propp) { - /* Fixes bug 463997 */ - unsigned flags = cx->resolveFlags; - if (flags == RESOLVE_INFER) - flags = js_InferFlags(cx, flags); - flags |= JSRESOLVE_WITH; - JSAutoResolveFlags rf(cx, flags); return obj->asWith().object().lookupGeneric(cx, id, objp, propp); } @@ -1375,7 +1369,7 @@ int DebugScopeProxy::family = 0; DebugScopeProxy DebugScopeProxy::singleton; /* static */ DebugScopeObject * -DebugScopeObject::create(JSContext *cx, ScopeObject &scope, JSObject &enclosing) +DebugScopeObject::create(JSContext *cx, ScopeObject &scope, HandleObject enclosing) { JSObject *obj = NewProxyObject(cx, &DebugScopeProxy::singleton, ObjectValue(scope), NULL /* proto */, &scope.global(), @@ -1383,8 +1377,8 @@ DebugScopeObject::create(JSContext *cx, ScopeObject &scope, JSObject &enclosing) if (!obj) return NULL; - JS_ASSERT(!enclosing.isScope()); - SetProxyExtra(obj, ENCLOSING_EXTRA, ObjectValue(enclosing)); + JS_ASSERT(!enclosing->isScope()); + SetProxyExtra(obj, ENCLOSING_EXTRA, ObjectValue(*enclosing.value())); return &obj->asDebugScope(); } @@ -1735,19 +1729,19 @@ GetDebugScopeForScope(JSContext *cx, ScopeObject &scope, ScopeIter enclosing) if (DebugScopeObject *debugScope = debugScopes.hasDebugScope(cx, scope)) return debugScope; - JSObject *enclosingDebug = GetDebugScope(cx, enclosing); + RootedObject enclosingDebug(cx, GetDebugScope(cx, enclosing)); if (!enclosingDebug) return NULL; JSObject &maybeDecl = scope.enclosingScope(); if (maybeDecl.isDeclEnv()) { JS_ASSERT(CallObjectLambdaName(scope.asCall().getCalleeFunction())); - enclosingDebug = DebugScopeObject::create(cx, maybeDecl.asDeclEnv(), *enclosingDebug); + enclosingDebug = DebugScopeObject::create(cx, maybeDecl.asDeclEnv(), enclosingDebug); if (!enclosingDebug) return NULL; } - DebugScopeObject *debugScope = DebugScopeObject::create(cx, scope, *enclosingDebug); + DebugScopeObject *debugScope = DebugScopeObject::create(cx, scope, enclosingDebug); if (!debugScope) return NULL; @@ -1760,11 +1754,13 @@ GetDebugScopeForScope(JSContext *cx, ScopeObject &scope, ScopeIter enclosing) static DebugScopeObject * GetDebugScopeForMissing(JSContext *cx, ScopeIter si) { + SkipRoot si_(cx, &si); + DebugScopes &debugScopes = *cx->runtime->debugScopes; if (DebugScopeObject *debugScope = debugScopes.hasDebugScope(cx, si)) return debugScope; - JSObject *enclosingDebug = GetDebugScope(cx, si.enclosing()); + RootedObject enclosingDebug(cx, GetDebugScope(cx, si.enclosing())); if (!enclosingDebug) return NULL; @@ -1784,12 +1780,12 @@ GetDebugScopeForMissing(JSContext *cx, ScopeIter si) if (callobj->enclosingScope().isDeclEnv()) { JS_ASSERT(CallObjectLambdaName(callobj->getCalleeFunction())); DeclEnvObject &declenv = callobj->enclosingScope().asDeclEnv(); - enclosingDebug = DebugScopeObject::create(cx, declenv, *enclosingDebug); + enclosingDebug = DebugScopeObject::create(cx, declenv, enclosingDebug); if (!enclosingDebug) return NULL; } - debugScope = DebugScopeObject::create(cx, *callobj, *enclosingDebug); + debugScope = DebugScopeObject::create(cx, *callobj, enclosingDebug); break; } case ScopeIter::Block: { @@ -1798,7 +1794,7 @@ GetDebugScopeForMissing(JSContext *cx, ScopeIter si) if (!block) return NULL; - debugScope = DebugScopeObject::create(cx, *block, *enclosingDebug); + debugScope = DebugScopeObject::create(cx, *block, enclosingDebug); break; } case ScopeIter::With: diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index f25a7e82dd9d..b90fa0081971 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -12,6 +12,8 @@ #include "jsobj.h" #include "jsweakmap.h" +#include "gc/Barrier.h" + namespace js { /*****************************************************************************/ @@ -402,7 +404,7 @@ class DebugScopeObject : public JSObject static const unsigned ENCLOSING_EXTRA = 0; public: - static DebugScopeObject *create(JSContext *cx, ScopeObject &scope, JSObject &enclosing); + static DebugScopeObject *create(JSContext *cx, ScopeObject &scope, HandleObject enclosing); ScopeObject &scope() const; JSObject &enclosingScope() const; diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 812f62bc74d4..2537038ab734 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -36,10 +36,11 @@ class ScriptFrameIter; class AllFramesIter; class ArgumentsObject; -class ScopeCoordinate; class ScopeObject; class StaticBlockObject; +struct ScopeCoordinate; + #ifdef JS_METHODJIT namespace mjit { class CallCompiler; @@ -415,7 +416,7 @@ class StackFrame #ifdef JS_METHODJIT friend class mjit::CallCompiler; friend class mjit::GetPropCompiler; - friend class mjit::ic::GetElementIC; + friend struct mjit::ic::GetElementIC; #endif /* diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index a5f0f8733409..b75d02958770 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -357,15 +357,6 @@ TraceJSHolder(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32_t number, return JS_DHASH_NEXT; } -static PLDHashOperator -TraceExpandos(XPCWrappedNative *wn, JSObject *&expando, void *aClosure) -{ - if (wn->IsWrapperExpired()) - return PL_DHASH_REMOVE; - JS_CALL_OBJECT_TRACER(static_cast(aClosure), expando, "expando object"); - return PL_DHASH_NEXT; -} - static PLDHashOperator TraceDOMExpandos(nsPtrHashKey *expando, void *aClosure) { @@ -400,8 +391,6 @@ void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc) XPCCompartmentSet &set = GetCompartmentSet(); for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) { CompartmentPrivate *priv = GetCompartmentPrivate(r.front()); - if (priv->expandoMap) - priv->expandoMap->Enumerate(TraceExpandos, trc); if (priv->domExpandoMap) priv->domExpandoMap->EnumerateEntries(TraceDOMExpandos, trc); } @@ -464,15 +453,6 @@ XPCJSRuntime::SuspectWrappedNative(XPCWrappedNative *wrapper, cb.NoteJSRoot(obj); } -static PLDHashOperator -SuspectExpandos(XPCWrappedNative *wrapper, JSObject *expando, void *arg) -{ - Closure* closure = static_cast(arg); - XPCJSRuntime::SuspectWrappedNative(wrapper, *closure->cb); - - return PL_DHASH_NEXT; -} - static PLDHashOperator SuspectDOMExpandos(nsPtrHashKey *key, void *arg) { @@ -546,12 +526,10 @@ XPCJSRuntime::AddXPConnectRoots(nsCycleCollectionTraversalCallback &cb) JS_DHashTableEnumerate(&mJSHolders, NoteJSHolder, &closure); } - // Suspect wrapped natives with expando objects. + // Suspect objects with expando objects. XPCCompartmentSet &set = GetCompartmentSet(); for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) { CompartmentPrivate *priv = GetCompartmentPrivate(r.front()); - if (priv->expandoMap) - priv->expandoMap->EnumerateRead(SuspectExpandos, &closure); if (priv->domExpandoMap) priv->domExpandoMap->EnumerateEntries(SuspectDOMExpandos, &closure); } @@ -599,14 +577,6 @@ DoDeferredRelease(nsTArray &array) } } -static PLDHashOperator -SweepExpandos(XPCWrappedNative *wn, JSObject *&expando, void *arg) -{ - return JS_IsAboutToBeFinalized(wn->GetFlatJSObjectPreserveColor()) - ? PL_DHASH_REMOVE - : PL_DHASH_NEXT; -} - /* static */ void XPCJSRuntime::GCCallback(JSRuntime *rt, JSGCStatus status) { @@ -688,8 +658,6 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp *fop, JSFinalizeStatus status, JSBool is CompartmentPrivate *priv = GetCompartmentPrivate(r.front()); if (priv->waiverWrapperMap) priv->waiverWrapperMap->Sweep(); - if (priv->expandoMap) - priv->expandoMap->Enumerate(SweepExpandos, NULL); } self->mDoingFinalization = true; diff --git a/js/xpconnect/src/XPCMaps.cpp b/js/xpconnect/src/XPCMaps.cpp index dce55474a35b..43f938c0bfd2 100644 --- a/js/xpconnect/src/XPCMaps.cpp +++ b/js/xpconnect/src/XPCMaps.cpp @@ -129,7 +129,11 @@ Native2WrappedNativeMap::newMap(int size) Native2WrappedNativeMap* map = new Native2WrappedNativeMap(size); if (map && map->mTable) return map; - delete map; + // Allocation of the map or the creation of its hash table has + // failed. This will cause a NULL deref later when we attempt to + // use the map, so we abort immediately to provide a more useful + // crash stack. + NS_RUNTIMEABORT("Ran out of memory."); return nsnull; } @@ -297,7 +301,11 @@ ClassInfo2WrappedNativeProtoMap::newMap(int size) ClassInfo2WrappedNativeProtoMap* map = new ClassInfo2WrappedNativeProtoMap(size); if (map && map->mTable) return map; - delete map; + // Allocation of the map or the creation of its hash table has + // failed. This will cause a NULL deref later when we attempt to + // use the map, so we abort immediately to provide a more useful + // crash stack. + NS_RUNTIMEABORT("Ran out of memory."); return nsnull; } diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index c10f8a047737..6719eb823bbb 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -17,6 +17,7 @@ #include "jsproxy.h" #include "AccessCheck.h" #include "WrapperFactory.h" +#include "XrayWrapper.h" #include "dombindings.h" #include "nsContentUtils.h" @@ -90,16 +91,6 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p, cb.NoteJSChild(obj); } - if (tmp->MightHaveExpandoObject()) { - XPCJSRuntime *rt = tmp->GetRuntime(); - XPCCompartmentSet &set = rt->GetCompartmentSet(); - for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) { - CompartmentPrivate *priv = GetCompartmentPrivate(r.front()); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "XPCWrappedNative expando object"); - cb.NoteJSChild(priv->LookupExpandoObjectPreserveColor(tmp)); - } - } - // XPCWrappedNative keeps its native object alive. NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mIdentity"); cb.NoteXPCOMChild(tmp->GetIdentityObject()); @@ -1192,10 +1183,11 @@ XPCWrappedNative::Init(XPCCallContext& ccx, JSObject* parent, JSBool XPCWrappedNative::Init(XPCCallContext &ccx, JSObject *existingJSObject) { + // Set up the private to point to the WN. JS_SetPrivate(existingJSObject, this); - // Morph the existing object. - JS_SetReservedSlot(existingJSObject, 0, JSVAL_VOID); + // Officially mark us as non-slim. + MorphMultiSlot(existingJSObject); mScriptableInfo = GetProto()->GetScriptableInfo(); mFlatJSObject = existingJSObject; @@ -1210,6 +1202,11 @@ XPCWrappedNative::Init(XPCCallContext &ccx, JSObject *existingJSObject) JSBool XPCWrappedNative::FinishInit(XPCCallContext &ccx) { + // For all WNs, we want to make sure that the multislot starts out as null. + // This happens explicitly when morphing a slim wrapper, but we need to + // make sure it happens in the other cases too. + JS_SetReservedSlot(mFlatJSObject, WRAPPER_MULTISLOT, JSVAL_NULL); + // This reference will be released when mFlatJSObject is finalized. // Since this reference will push the refcount to 2 it will also root // mFlatJSObject; @@ -1614,6 +1611,12 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx, if (!propertyHolder || !JS_CopyPropertiesFrom(ccx, propertyHolder, flat)) return NS_ERROR_OUT_OF_MEMORY; + // Expandos from other compartments are attached to the target JS object. + // Copy them over, and let the old ones die a natural death. + SetExpandoChain(newobj, nsnull); + if (!XrayUtils::CloneExpandoChain(ccx, newobj, flat)) + return NS_ERROR_FAILURE; + // Before proceeding, eagerly create any same-compartment security wrappers // that the object might have. This forces us to take the 'WithWrapper' path // while transplanting that handles this stuff correctly. @@ -1652,40 +1655,13 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx, } // Ok, now we do the special object-plus-wrapper transplant. - // - // This is some pretty serious brain surgery. - // - // In the case where we wrap a Location object from a same- - // origin compartment, we actually want our cross-compartment - // wrapper to point to the same-compartment wrapper in the - // other compartment. This double-wrapping allows expandos to - // be shared. So our wrapping callback (in WrapperFactory.cpp) - // calls XPCWrappedNative::GetSameCompartmentSecurityWrapper - // before wrapping same-origin Location objects. - // - // This normally works fine, but gets tricky here. - // js_TransplantObjectWithWrapper needs to update the old - // same-compartment security wrapper to be a cross-compartment - // wrapper to the newly transplanted object. So it needs to go - // through the aforementioned double-wrapping mechanism. - // But during the call, things aren't really in a consistent - // state, because mFlatJSObject hasn't yet been updated to - // point to the object in the new compartment. - // - // So we need to cache the new same-compartment security - // wrapper on the XPCWN before the call, so that - // GetSameCompartmentSecurityWrapper can return early before - // getting confused. Hold your breath. - JSObject *wwsaved = ww; - wrapper->SetWrapper(newwrapper); ww = js_TransplantObjectWithWrapper(ccx, flat, ww, newobj, newwrapper); - if (!ww) { - wrapper->SetWrapper(wwsaved); + if (!ww) return NS_ERROR_FAILURE; - } flat = newobj; + wrapper->SetWrapper(ww); } else { flat = JS_TransplantObject(ccx, flat, newobj); if (!flat) @@ -1698,11 +1674,10 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx, if (!JS_CopyPropertiesFrom(ccx, flat, propertyHolder)) return NS_ERROR_FAILURE; } else { - JS_SetReservedSlot(flat, 0, - PRIVATE_TO_JSVAL(newProto.get())); + SetSlimWrapperProto(flat, newProto.get()); if (!JS_SetPrototype(ccx, flat, newProto->GetJSProtoObject())) { // this is bad, very bad - JS_SetReservedSlot(flat, 0, JSVAL_NULL); + SetSlimWrapperProto(flat, nsnull); NS_ERROR("JS_SetPrototype failed"); return NS_ERROR_FAILURE; } @@ -2232,10 +2207,6 @@ XPCWrappedNative::GetSameCompartmentSecurityWrapper(JSContext *cx) JSObject *wrapper = GetWrapper(); // If we already have a wrapper, it must be what we want. - // - // NB: This must come before anything below because of some trickiness - // with brain transplants. See the "pretty serious brain surgery" comment - // in ReparentWrapperIfFound. if (wrapper) return wrapper; @@ -3936,7 +3907,7 @@ ConstructSlimWrapper(XPCCallContext &ccx, return false; JS_SetPrivate(wrapper, identityObj); - JS_SetReservedSlot(wrapper, 0, PRIVATE_TO_JSVAL(xpcproto.get())); + SetSlimWrapperProto(wrapper, xpcproto.get()); // Transfer ownership to the wrapper's private. aHelper.forgetCanonical(); diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index e8f19fba113f..0e06bdf3b4f0 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -301,8 +301,44 @@ typedef XPCCompartmentSet::Range XPCCompartmentRange; #define WRAPPER_SLOTS (JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | \ JSCLASS_HAS_RESERVED_SLOTS(1)) +// WRAPPER_MULTISLOT is defined in xpcpublic.h + #define INVALID_OBJECT ((JSObject *)1) +inline void SetSlimWrapperProto(JSObject *obj, XPCWrappedNativeProto *proto) +{ + JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, PRIVATE_TO_JSVAL(proto)); +} + +inline XPCWrappedNativeProto* GetSlimWrapperProto(JSObject *obj) +{ + MOZ_ASSERT(IS_SLIM_WRAPPER(obj)); + const JS::Value &v = js::GetReservedSlot(obj, WRAPPER_MULTISLOT); + return static_cast(v.toPrivate()); +} + +// A slim wrapper is identified by having a native pointer in its reserved slot. +// This function, therefore, does the official transition from a slim wrapper to +// a non-slim wrapper. +inline void MorphMultiSlot(JSObject *obj) +{ + MOZ_ASSERT(IS_SLIM_WRAPPER(obj)); + JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, JSVAL_NULL); + MOZ_ASSERT(!IS_SLIM_WRAPPER(obj)); +} + +inline void SetExpandoChain(JSObject *obj, JSObject *chain) +{ + MOZ_ASSERT(IS_WN_WRAPPER(obj)); + JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, JS::ObjectOrNullValue(chain)); +} + +inline JSObject* GetExpandoChain(JSObject *obj) +{ + MOZ_ASSERT(IS_WN_WRAPPER(obj)); + return JS_GetReservedSlot(obj, WRAPPER_MULTISLOT).toObjectOrNull(); +} + /***************************************************************************/ // Auto locking support class... @@ -2426,14 +2462,6 @@ extern JSBool ConstructSlimWrapper(XPCCallContext &ccx, jsval *rval); extern JSBool MorphSlimWrapper(JSContext *cx, JSObject *obj); -static inline XPCWrappedNativeProto* -GetSlimWrapperProto(JSObject *obj) -{ - const js::Value &v = js::GetReservedSlot(obj, 0); - return static_cast(v.toPrivate()); -} - - /***********************************************/ // XPCWrappedNativeTearOff represents the info needed to make calls to one // interface on the underlying native object of a XPCWrappedNative. @@ -2807,8 +2835,6 @@ public: void SetNeedsSOW() { mWrapperWord |= NEEDS_SOW; } JSBool NeedsCOW() { return !!(mWrapperWord & NEEDS_COW); } void SetNeedsCOW() { mWrapperWord |= NEEDS_COW; } - JSBool MightHaveExpandoObject() { return !!(mWrapperWord & MIGHT_HAVE_EXPANDO); } - void SetHasExpandoObject() { mWrapperWord |= MIGHT_HAVE_EXPANDO; } JSObject* GetWrapperPreserveColor() const {return (JSObject*)(mWrapperWord & (size_t)~(size_t)FLAG_MASK);} @@ -2875,7 +2901,6 @@ private: enum { NEEDS_SOW = JS_BIT(0), NEEDS_COW = JS_BIT(1), - MIGHT_HAVE_EXPANDO = JS_BIT(2), FLAG_MASK = JS_BITMASK(3) }; @@ -4354,7 +4379,6 @@ namespace xpc { class CompartmentPrivate { public: - typedef nsDataHashtable, JSObject *> ExpandoMap; typedef nsTHashtable > DOMExpandoMap; CompartmentPrivate(bool wantXrays) @@ -4367,40 +4391,8 @@ public: bool wantXrays; nsAutoPtr waiverWrapperMap; - // NB: we don't want this map to hold a strong reference to the wrapper. - nsAutoPtr expandoMap; nsAutoPtr domExpandoMap; - bool RegisterExpandoObject(XPCWrappedNative *wn, JSObject *expando) { - if (!expandoMap) { - expandoMap = new ExpandoMap(); - expandoMap->Init(8); - } - wn->SetHasExpandoObject(); - return expandoMap->Put(wn, expando, mozilla::fallible_t()); - } - - /** - * This lookup does not change the color of the JSObject meaning that the - * object returned is not guaranteed to be kept alive past the next CC. - * - * This should only be called if you are certain that the return value won't - * be passed into a JS API function and that it won't be stored without - * being rooted (or otherwise signaling the stored value to the CC). - */ - JSObject *LookupExpandoObjectPreserveColor(XPCWrappedNative *wn) { - return expandoMap ? expandoMap->Get(wn) : nsnull; - } - - /** - * This lookup clears the gray bit before handing out the JSObject which - * means that the object is guaranteed to be kept alive past the next CC. - */ - JSObject *LookupExpandoObject(XPCWrappedNative *wn) { - JSObject *obj = LookupExpandoObjectPreserveColor(wn); - return xpc_UnmarkGrayObject(obj); - } - bool RegisterDOMExpandoObject(JSObject *expando) { if (!domExpandoMap) { domExpandoMap = new DOMExpandoMap(); diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 339c17903912..66e6ccda9aac 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -74,13 +74,21 @@ DebugCheckWrapperClass(JSObject* obj) // a slim wrapper, holding a native in its private slot, or a wrappednative // wrapper, holding the XPCWrappedNative in its private slot. A slim wrapper // also holds a pointer to its XPCWrappedNativeProto in a reserved slot, we can -// check that slot for a non-void value to distinguish between the two. +// check that slot for a private value (i.e. a double) to distinguish between +// the two. This allows us to store a JSObject in that slot for non-slim wrappers +// while still being able to distinguish the two cases. + +// NB: This slot isn't actually reserved for us on globals, because SpiderMonkey +// uses the first N slots on globals internally. The fact that we use it for +// wrapped global objects is totally broken. But due to a happy coincidence, the +// JS engine never uses that slot. This still needs fixing though. See bug 760095. +#define WRAPPER_MULTISLOT 0 // Only use these macros if IS_WRAPPER_CLASS(GetObjectClass(obj)) is true. #define IS_WN_WRAPPER_OBJECT(obj) \ - (DebugCheckWrapperClass(obj) && js::GetReservedSlot(obj, 0).isUndefined()) + (DebugCheckWrapperClass(obj) && !js::GetReservedSlot(obj, WRAPPER_MULTISLOT).isDouble()) #define IS_SLIM_WRAPPER_OBJECT(obj) \ - (DebugCheckWrapperClass(obj) && !js::GetReservedSlot(obj, 0).isUndefined()) + (DebugCheckWrapperClass(obj) && js::GetReservedSlot(obj, WRAPPER_MULTISLOT).isDouble()) // Use these macros if IS_WRAPPER_CLASS(GetObjectClass(obj)) might be false. // Avoid calling them if IS_WRAPPER_CLASS(GetObjectClass(obj)) can only be diff --git a/js/xpconnect/tests/chrome/Makefile.in b/js/xpconnect/tests/chrome/Makefile.in index 3f2c1405e99b..730a26f409a2 100644 --- a/js/xpconnect/tests/chrome/Makefile.in +++ b/js/xpconnect/tests/chrome/Makefile.in @@ -47,6 +47,8 @@ _CHROME_FILES = \ test_exnstack.xul \ test_weakref.xul \ test_bug726949.xul \ + test_expandosharing.xul \ + file_expandosharing.jsm \ test_bug758563.xul \ test_bug760076.xul \ $(NULL) diff --git a/js/xpconnect/tests/chrome/file_expandosharing.jsm b/js/xpconnect/tests/chrome/file_expandosharing.jsm new file mode 100644 index 000000000000..19e18ebdbb49 --- /dev/null +++ b/js/xpconnect/tests/chrome/file_expandosharing.jsm @@ -0,0 +1,10 @@ +var EXPORTED_SYMBOLS = ['checkFromJSM']; + +function checkFromJSM(target, is_op) { + is_op(target.numProp, 42, "Number expando works"); + is_op(target.strProp, "foo", "String expando works"); + // If is_op is todo_is, target.objProp will be undefined. + try { + is_op(target.objProp.bar, "baz", "Object expando works"); + } catch(e) { is_op(0, 1, "No object expando"); } +} diff --git a/js/xpconnect/tests/chrome/test_expandosharing.xul b/js/xpconnect/tests/chrome/test_expandosharing.xul new file mode 100644 index 000000000000..ed57ac880bc9 --- /dev/null +++ b/js/xpconnect/tests/chrome/test_expandosharing.xul @@ -0,0 +1,141 @@ + + + + + + +