diff --git a/b2g/components/test/mochitest/screenshot_helper.js b/b2g/components/test/mochitest/screenshot_helper.js index d10234f928..cf40528f0e 100644 --- a/b2g/components/test/mochitest/screenshot_helper.js +++ b/b2g/components/test/mochitest/screenshot_helper.js @@ -1,6 +1,8 @@ const Cu = Components.utils; const Ci = Components.interfaces; +Cu.importGlobalProperties(['File']); + const { Services } = Cu.import("resource://gre/modules/Services.jsm"); // Load a duplicated copy of the jsm to prevent messing with the currently running one @@ -25,7 +27,7 @@ function next() { let steps = [ function getScreenshot() { let screenshot = Screenshot.get(); - assert.ok(screenshot instanceof Ci.nsIDOMFile, + assert.ok(screenshot instanceof File, "Screenshot.get() returns a File"); next(); }, diff --git a/docshell/base/nsAboutRedirector.cpp b/docshell/base/nsAboutRedirector.cpp index 1aad9b56f8..02950e1bf8 100644 --- a/docshell/base/nsAboutRedirector.cpp +++ b/docshell/base/nsAboutRedirector.cpp @@ -145,7 +145,7 @@ nsAboutRedirector::NewChannel(nsIURI* aURI, tempChannel->SetOriginalURI(aURI); - NS_ADDREF(*aResult = tempChannel); + tempChannel.forget(aResult); return rv; } } @@ -184,9 +184,6 @@ nsAboutRedirector::GetIndexedDBOriginPostfix(nsIURI* aURI, nsAString& aResult) nsresult nsAboutRedirector::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult) { - nsAboutRedirector* about = new nsAboutRedirector(); - NS_ADDREF(about); - nsresult rv = about->QueryInterface(aIID, aResult); - NS_RELEASE(about); - return rv; + nsRefPtr about = new nsAboutRedirector(); + return about->QueryInterface(aIID, aResult); } diff --git a/docshell/base/nsDefaultURIFixup.cpp b/docshell/base/nsDefaultURIFixup.cpp index 0564d8d7c2..f9bd0adf5e 100644 --- a/docshell/base/nsDefaultURIFixup.cpp +++ b/docshell/base/nsDefaultURIFixup.cpp @@ -105,9 +105,7 @@ nsDefaultURIFixup::CreateExposableURI(nsIURI* aURI, nsIURI** aReturn) uri->SetUserPass(EmptyCString()); } - // return the fixed-up URI - *aReturn = uri; - NS_ADDREF(*aReturn); + uri.forget(aReturn); return NS_OK; } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index cd43626dba..b38df07e6f 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -1144,8 +1144,7 @@ nsDocShell::GetInterface(const nsIID& aIID, void** aSink) nsCOMPtr shistory; nsresult rv = GetSessionHistory(getter_AddRefs(shistory)); if (NS_SUCCEEDED(rv) && shistory) { - *aSink = shistory; - NS_ADDREF((nsISupports*)*aSink); + shistory.forget(aSink); return NS_OK; } return NS_NOINTERFACE; @@ -1163,8 +1162,7 @@ nsDocShell::GetInterface(const nsIID& aIID, void** aSink) nsCOMPtr editingSession; mEditorData->GetEditingSession(getter_AddRefs(editingSession)); if (editingSession) { - *aSink = editingSession; - NS_ADDREF((nsISupports*)*aSink); + editingSession.forget(aSink); return NS_OK; } @@ -1783,8 +1781,7 @@ nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo** aLoadInfo) NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY); nsCOMPtr localRef(loadInfo); - *aLoadInfo = localRef; - NS_ADDREF(*aLoadInfo); + localRef.forget(aLoadInfo); return NS_OK; } @@ -6302,7 +6299,7 @@ nsDocShell::GetOnePermittedSandboxedNavigator(nsIDocShell** aSandboxedNavigator) NS_ENSURE_ARG_POINTER(aSandboxedNavigator); nsCOMPtr permittedNavigator = do_QueryReferent(mOnePermittedSandboxedNavigator); - NS_IF_ADDREF(*aSandboxedNavigator = permittedNavigator); + permittedNavigator.forget(aSandboxedNavigator); return NS_OK; } @@ -12174,8 +12171,7 @@ nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel, if (aNewEntry) { *aNewEntry = nullptr; if (NS_SUCCEEDED(rv)) { - *aNewEntry = entry; - NS_ADDREF(*aNewEntry); + entry.forget(aNewEntry); } } diff --git a/docshell/shistory/src/nsSHistory.cpp b/docshell/shistory/src/nsSHistory.cpp index 4a7481e122..b5a77eb2f8 100644 --- a/docshell/shistory/src/nsSHistory.cpp +++ b/docshell/shistory/src/nsSHistory.cpp @@ -10,6 +10,7 @@ // Helper Classes #include "mozilla/Preferences.h" +#include "mozilla/StaticPtr.h" // Interfaces Needed #include "nsILayoutHistoryState.h" @@ -178,7 +179,7 @@ protected: ~nsSHistoryObserver() {} }; -static nsSHistoryObserver* gObserver = nullptr; +StaticRefPtr gObserver; NS_IMPL_ISUPPORTS(nsSHistoryObserver, nsIObserver) @@ -360,7 +361,6 @@ nsSHistory::Startup() // but keep the per SHistory cached viewer limit constant if (!gObserver) { gObserver = new nsSHistoryObserver(); - NS_ADDREF(gObserver); Preferences::AddStrongObservers(gObserver, kObservedPrefs); nsCOMPtr obsSvc = @@ -393,7 +393,7 @@ nsSHistory::Shutdown() obsSvc->RemoveObserver(gObserver, "cacheservice:empty-cache"); obsSvc->RemoveObserver(gObserver, "memory-pressure"); } - NS_RELEASE(gObserver); + gObserver = nullptr; } } @@ -540,8 +540,7 @@ nsSHistory::GetTransactionAtIndex(int32_t aIndex, nsISHTransaction ** aResult) if (NS_SUCCEEDED(rv) && ptr) { cnt++; if (cnt == aIndex) { - *aResult = ptr; - NS_ADDREF(*aResult); + ptr.forget(aResult); break; } else { diff --git a/dom/apps/ImportExport.jsm b/dom/apps/ImportExport.jsm index 0c28d362c8..e4e84fa10f 100644 --- a/dom/apps/ImportExport.jsm +++ b/dom/apps/ImportExport.jsm @@ -14,6 +14,8 @@ Cu.import("resource://gre/modules/AppsUtils.jsm"); Cu.import("resource://gre/modules/Promise.jsm"); Cu.import("resource://gre/modules/Webapps.jsm"); +Cu.importGlobalProperties(['File']); + XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm"); @@ -26,6 +28,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "PermissionsInstaller", XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "OS", + "resource://gre/modules/osfile.jsm"); + this.EXPORTED_SYMBOLS = ["ImportExport"]; const kAppArchiveMimeType = "application/openwebapp+zip"; @@ -38,9 +43,9 @@ const PR_CREATE_FILE = 0x08; const PR_TRUNCATE = 0x20; function debug(aMsg) { -#ifdef DEBUG +//#ifdef DEBUG dump("-*- ImportExport.jsm : " + aMsg + "\n"); -#endif +//#endif } /* @@ -225,7 +230,12 @@ this.ImportExport = { // |file| now points to application.zip, open it. let appZipReader = Cc["@mozilla.org/libjar/zip-reader;1"] .createInstance(Ci.nsIZipReader); - appZipReader.open(file); + try { + appZipReader.open(file); + } catch(e) { + throw "InvalidZip"; + } + if (!appZipReader.hasEntry("manifest.webapp")) { throw "NoManifestFound"; } @@ -233,10 +243,35 @@ this.ImportExport = { return [readObjectFromZip(appZipReader, "manifest.webapp"), file]; }, + // Returns a promise that resolves to the temp file path. + _writeBlobToTempFile: function(aBlob) { + // Save the blob to a temp file. + debug("_writeBlobToTempFile"); + let path; + return new Promise((aResolve, aReject) => { + let reader = Cc['@mozilla.org/files/filereader;1'] + .createInstance(Ci.nsIDOMFileReader); + reader.onloadend = () => { + path = OS.Path.join(OS.Constants.Path.tmpDir, "app-blob.zip"); + debug("onloadend path=" + path); + OS.File.openUnique(path).then(obj => { + path = obj.path; + let file = obj.file; + debug("openUnique path=" + path); + return file.write(new Uint8Array(reader.result)) + .then(file.close.bind(file)) + }) + .then(() => aResolve(path)) + .catch(aReject); + } + reader.readAsArrayBuffer(aBlob); + }); + }, + // Imports a blob, returning a Promise that resolves to // [manifestURL, manifest] // Possible errors are: - // NoBlobFound, UnsupportedBlobArchive, MissingMetadataFile, IncorrectVersion, + // NoBlobFound, InvalidZip, MissingMetadataFile, IncorrectVersion, // AppAlreadyInstalled, DontImportCertifiedApps, InvalidManifest, // InvalidPrivilegeLevel, InvalidOrigin, DuplicateOrigin import: Task.async(function*(aBlob) { @@ -246,15 +281,15 @@ this.ImportExport = { throw "NoBlobFound"; } - let isFile = aBlob instanceof Ci.nsIDOMFile; - if (!isFile) { - // XXX: TODO Store the blob on disk. - throw "UnsupportedBlobArchive"; - } - + let isFileBlob = aBlob instanceof File; // We can't QI the DOMFile to nsIFile, so we need to create one. let zipFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - zipFile.initWithPath(aBlob.mozFullPath); + if (!isFileBlob) { + let path = yield this._writeBlobToTempFile(aBlob); + zipFile.initWithPath(path); + } else { + zipFile.initWithPath(aBlob.mozFullPath); + } debug("Importing from " + zipFile.path); @@ -263,8 +298,13 @@ this.ImportExport = { let manifest; let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"] .createInstance(Ci.nsIZipReader); - zipReader.open(zipFile); try { + try { + zipReader.open(zipFile); + } catch(e) { + throw "InvalidZip"; + } + // Do some sanity checks on the metadata.json and manifest.webapp files. if (!zipReader.hasEntry("metadata.json")) { throw "MissingMetadataFile"; @@ -431,6 +471,9 @@ this.ImportExport = { throw e; } finally { zipReader.close(); + if (!isFileBlob) { + zipFile.remove(false); + } } return [meta.manifestURL, manifest]; @@ -439,31 +482,37 @@ this.ImportExport = { // Extracts the manifest from a blob, returning a Promise that resolves to // the manifest // Possible errors are: - // NoBlobFound, UnsupportedBlobArchive, MissingMetadataFile. + // NoBlobFound, InvalidZip, MissingMetadataFile. extractManifest: Task.async(function*(aBlob) { // First, do we even have a blob? if (!aBlob || !aBlob instanceof Ci.nsIDOMBlob) { throw "NoBlobFound"; } - let isFile = aBlob instanceof Ci.nsIDOMFile; - if (!isFile) { - // XXX: TODO Store the blob on disk. - throw "UnsupportedBlobArchive"; - } - + let isFileBlob = aBlob instanceof File; // We can't QI the DOMFile to nsIFile, so we need to create one. let zipFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - zipFile.initWithPath(aBlob.mozFullPath); + if (!isFileBlob) { + let path = yield this._writeBlobToTempFile(aBlob); + zipFile.initWithPath(path); + } else { + zipFile.initWithPath(aBlob.mozFullPath); + } + debug("extractManifest from " + zipFile.path); // Do some sanity checks on the metadata.json and manifest.webapp files. let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"] .createInstance(Ci.nsIZipReader); - zipReader.open(zipFile); let manifest; try { + try { + zipReader.open(zipFile); + } catch(e) { + throw "InvalidZip"; + } + if (zipReader.hasEntry("manifest.webapp")) { manifest = readObjectFromZip(zipReader, "manifest.webapp"); if (!manifest) { @@ -484,6 +533,9 @@ this.ImportExport = { } } finally { zipReader.close(); + if (!isFileBlob) { + zipFile.remove(false); + } } return manifest; diff --git a/dom/apps/tests/test_import_export.html b/dom/apps/tests/test_import_export.html index f7b08fd02b..036073e417 100644 --- a/dom/apps/tests/test_import_export.html +++ b/dom/apps/tests/test_import_export.html @@ -299,6 +299,21 @@ function runTest() { is(request.result, miniManifestURL, "Packaged App uninstalled."); navigator.mozApps.mgmt.onuninstall = null; + + // Check that we support memory backed blobs. + // The blob here is not a valid app, but that's fine for this test. + let blob = new Blob(["This is a test blob."]); + navigator.mozApps.mgmt.import(blob) + .then(() => { + ok(false, "This is not an app!"); + continueTest(); + }) + .catch(aError => { + is(aError.name, "InvalidZip", "Memory blob processed."); + continueTest(); + }); + yield undefined; + // Check that we restored the app registry. request = navigator.mozApps.mgmt.getAll(); request.onerror = cbError; diff --git a/dom/archivereader/ArchiveRequest.cpp b/dom/archivereader/ArchiveRequest.cpp index 6a857a17a3..b840a82b2d 100644 --- a/dom/archivereader/ArchiveRequest.cpp +++ b/dom/archivereader/ArchiveRequest.cpp @@ -177,7 +177,6 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx, nsTArray>& aFileList) { JS::Rooted array(aCx, JS_NewArrayObject(aCx, aFileList.Length())); - nsresult rv; if (!array) { return NS_ERROR_OUT_OF_MEMORY; @@ -188,14 +187,12 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx, nsRefPtr file = aFileList[i]; nsString filename; - rv = file->GetName(filename); - NS_ENSURE_SUCCESS(rv, rv); + file->GetName(filename); str = JS_NewUCStringCopyZ(aCx, filename.get()); NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY); - if (NS_FAILED(rv) || - !JS_DefineElement(aCx, array, i, str, JSPROP_ENUMERATE)) { + if (!JS_DefineElement(aCx, array, i, str, JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } } @@ -217,8 +214,7 @@ ArchiveRequest::GetFileResult(JSContext* aCx, nsRefPtr file = aFileList[i]; nsString filename; - nsresult rv = file->GetName(filename); - NS_ENSURE_SUCCESS(rv, rv); + file->GetName(filename); if (filename == mFilename) { if (!ToJSValue(aCx, file, aValue)) { diff --git a/dom/base/File.cpp b/dom/base/File.cpp index 600093fb6a..c2d9175c3c 100644 --- a/dom/base/File.cpp +++ b/dom/base/File.cpp @@ -439,22 +439,6 @@ Blob::GetInternalStream(nsIInputStream** aStream) //////////////////////////////////////////////////////////////////////////// // mozilla::dom::File implementation -NS_IMPL_CYCLE_COLLECTION_CLASS(File) - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(File, Blob) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(File, Blob) -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(File) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile) - NS_INTERFACE_MAP_ENTRY(nsIDOMFile) -NS_INTERFACE_MAP_END_INHERITING(Blob) - -NS_IMPL_ADDREF_INHERITED(File, Blob) -NS_IMPL_RELEASE_INHERITED(File, Blob) - File::File(nsISupports* aParent, BlobImpl* aImpl) : Blob(aParent, aImpl) { @@ -553,17 +537,16 @@ File::WrapObject(JSContext* aCx, JS::Handle aGivenProto) return FileBinding::Wrap(aCx, this, aGivenProto); } -NS_IMETHODIMP +void File::GetName(nsAString& aFileName) { mImpl->GetName(aFileName); - return NS_OK; } -NS_IMETHODIMP -File::GetPath(nsAString& aPath) +void +File::GetPath(nsAString& aPath, ErrorResult& aRv) { - return mImpl->GetPath(aPath); + mImpl->GetPath(aPath, aRv); } Date @@ -583,53 +566,16 @@ File::GetLastModified(ErrorResult& aRv) return mImpl->GetLastModified(aRv); } -NS_IMETHODIMP -File::GetLastModifiedDate(JSContext* aCx, - JS::MutableHandle aDate) -{ - ErrorResult rv; - Date value = GetLastModifiedDate(rv); - if (rv.Failed()) { - return rv.StealNSResult(); - } - - if (!value.ToDateObject(aCx, aDate)) { - return NS_ERROR_OUT_OF_MEMORY; - } - - return NS_OK; -} - -NS_IMETHODIMP -File::GetMozFullPath(nsAString& aFileName) -{ - ErrorResult rv; - GetMozFullPath(aFileName, rv); - return rv.StealNSResult(); -} - void File::GetMozFullPath(nsAString& aFilename, ErrorResult& aRv) { mImpl->GetMozFullPath(aFilename, aRv); } -NS_IMETHODIMP -File::GetMozFullPathInternal(nsAString& aFileName) +void +File::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) { - ErrorResult rv; - mImpl->GetMozFullPathInternal(aFileName, rv); - return rv.StealNSResult(); -} - -NS_IMETHODIMP -File::GetMozLastModifiedDate(int64_t* aDate) -{ - MOZ_ASSERT(aDate); - - ErrorResult rv; - *aDate = GetLastModified(rv); - return rv.StealNSResult(); + mImpl->GetMozFullPathInternal(aFileName, aRv); } // Makes sure that aStart and aEnd is less then or equal to aSize and greater @@ -817,12 +763,11 @@ BlobImplBase::GetName(nsAString& aName) aName = mName; } -nsresult -BlobImplBase::GetPath(nsAString& aPath) +void +BlobImplBase::GetPath(nsAString& aPath, ErrorResult& aRv) { NS_ASSERTION(mIsFile, "Should only be called on files"); aPath = mPath; - return NS_OK; } void @@ -1321,9 +1266,9 @@ FileList::GetLength(uint32_t* aLength) } NS_IMETHODIMP -FileList::Item(uint32_t aIndex, nsIDOMFile **aFile) +FileList::Item(uint32_t aIndex, nsISupports** aFile) { - nsRefPtr file = Item(aIndex); + nsCOMPtr file = Item(aIndex); file.forget(aFile); return NS_OK; } diff --git a/dom/base/File.h b/dom/base/File.h index 18eebf68b6..e2e68f3fc4 100644 --- a/dom/base/File.h +++ b/dom/base/File.h @@ -20,7 +20,7 @@ #include "nsAutoPtr.h" #include "nsCycleCollectionParticipant.h" #include "nsCOMPtr.h" -#include "nsIDOMFile.h" +#include "nsIDOMBlob.h" #include "nsIDOMFileList.h" #include "nsIFile.h" #include "nsIMutable.h" @@ -157,17 +157,10 @@ private: }; class File final : public Blob - , public nsIDOMFile { friend class Blob; public: - NS_DECL_NSIDOMFILE - NS_FORWARD_NSIDOMBLOB(Blob::) - - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(File, Blob); - // Note: BlobImpl must be a File in order to use this method. // Check impl->IsFile(). static File* @@ -245,15 +238,18 @@ public: const ChromeFilePropertyBag& aBag, ErrorResult& aRv); - // XPCOM GetName is OK + void GetName(nsAString& aName); int64_t GetLastModified(ErrorResult& aRv); Date GetLastModifiedDate(ErrorResult& aRv); + void GetPath(nsAString& aName, ErrorResult& aRv); void GetMozFullPath(nsAString& aFilename, ErrorResult& aRv); + void GetMozFullPathInternal(nsAString& aName, ErrorResult& aRv); + protected: virtual bool HasFileInterface() const override { return true; } @@ -276,7 +272,7 @@ public: virtual void GetName(nsAString& aName) = 0; - virtual nsresult GetPath(nsAString& aName) = 0; + virtual void GetPath(nsAString& aName, ErrorResult& aRv) = 0; virtual int64_t GetLastModified(ErrorResult& aRv) = 0; @@ -404,7 +400,7 @@ public: virtual void GetName(nsAString& aName) override; - virtual nsresult GetPath(nsAString& aName) override; + virtual void GetPath(nsAString& aName, ErrorResult& aRv) override; virtual int64_t GetLastModified(ErrorResult& aRv) override; diff --git a/dom/base/FileIOObject.h b/dom/base/FileIOObject.h index cb96b93b89..67069d8971 100644 --- a/dom/base/FileIOObject.h +++ b/dom/base/FileIOObject.h @@ -9,7 +9,6 @@ #include "mozilla/DOMEventTargetHelper.h" #include "nsIFile.h" -#include "nsIDOMFile.h" #include "nsITimer.h" #include "nsCOMPtr.h" #include "nsIAsyncInputStream.h" diff --git a/dom/base/MultipartBlobImpl.cpp b/dom/base/MultipartBlobImpl.cpp index 3fa6ffa0cc..a98a3659d0 100644 --- a/dom/base/MultipartBlobImpl.cpp +++ b/dom/base/MultipartBlobImpl.cpp @@ -366,8 +366,7 @@ MultipartBlobImpl::InitializeChromeFile(nsPIDOMWindow* aWindow, } // Pre-cache modified date. - int64_t unusedDate; - aRv = blob->GetMozLastModifiedDate(&unusedDate); + blob->GetLastModified(aRv); if (NS_WARN_IF(aRv.Failed())) { return; } diff --git a/dom/base/moz.build b/dom/base/moz.build index 48019dda10..9891011f18 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -11,10 +11,10 @@ XPIDL_SOURCES += [ 'nsIContentPolicy.idl', 'nsIContentPolicyBase.idl', 'nsIDocumentEncoder.idl', + 'nsIDOMBlob.idl', 'nsIDOMDataChannel.idl', 'nsIDOMDOMCursor.idl', 'nsIDOMDOMRequest.idl', - 'nsIDOMFile.idl', 'nsIDOMFileList.idl', 'nsIDOMFileReader.idl', 'nsIDOMFormData.idl', diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 72ef66748b..b3829ab96e 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -25,6 +25,9 @@ #include "mozilla/layers/ShadowLayers.h" #include "ClientLayerManager.h" #include "nsQueryObject.h" +#ifdef MOZ_FMP4 +#include "MP4Reader.h" +#endif #include "nsIScrollableFrame.h" @@ -55,6 +58,7 @@ #include "nsIContentViewer.h" #include "mozilla/StyleAnimationValue.h" #include "mozilla/dom/File.h" +#include "mozilla/dom/FileBinding.h" #include "mozilla/dom/DOMRect.h" #include @@ -2230,6 +2234,27 @@ nsDOMWindowUtils::GetLayerManagerRemote(bool* retval) return NS_OK; } +NS_IMETHODIMP +nsDOMWindowUtils::GetSupportsHardwareH264Decoding(bool* retval) +{ + MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome()); + +#ifdef MOZ_FMP4 + nsCOMPtr widget = GetWidget(); + if (!widget) + return NS_ERROR_FAILURE; + + LayerManager *mgr = widget->GetLayerManager(); + if (!mgr) + return NS_ERROR_FAILURE; + + *retval = MP4Reader::IsVideoAccelerated(mgr->GetCompositorBackendType()); +#else + *retval = false; +#endif + return NS_OK; +} + NS_IMETHODIMP nsDOMWindowUtils::StartFrameTimeRecording(uint32_t *startIndex) { @@ -2557,7 +2582,7 @@ nsDOMWindowUtils::GetContainerElement(nsIDOMElement** aResult) NS_IMETHODIMP nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile, - nsIDOMFile **aDOMFile) + nsISupports **aDOMFile) { MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome()); @@ -2573,8 +2598,8 @@ nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile, return NS_ERROR_FAILURE; } - nsRefPtr file = File::CreateFromFile(innerWindow, aFile); - file.forget(aDOMFile); + nsCOMPtr blob = File::CreateFromFile(innerWindow, aFile); + blob.forget(aDOMFile); return NS_OK; } @@ -2823,15 +2848,13 @@ nsDOMWindowUtils::GetFilePath(JS::HandleValue aFile, JSContext* aCx, JSObject* obj = aFile.toObjectOrNull(); - nsISupports* nativeObj = - nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, obj); - - nsCOMPtr file = do_QueryInterface(nativeObj); - if (file) { + File* file = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(File, obj, file))) { nsString filePath; - nsresult rv = file->GetMozFullPathInternal(filePath); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + ErrorResult rv; + file->GetMozFullPathInternal(filePath, rv); + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); } _retval = filePath; @@ -3577,6 +3600,18 @@ nsDOMWindowUtils::GetCompositorAPZTestData(JSContext* aContext, return NS_OK; } +NS_IMETHODIMP +nsDOMWindowUtils::PostRestyleSelfEvent(nsIDOMElement* aElement) +{ + nsCOMPtr element = do_QueryInterface(aElement); + if (!element) { + return NS_ERROR_INVALID_ARG; + } + + nsLayoutUtils::PostRestyleEvent(element, eRestyle_Self, nsChangeHint(0)); + return NS_OK; +} + NS_IMETHODIMP nsDOMWindowUtils::GetAudioMuted(bool* aMuted) { diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index b6b36229c3..c98cf93f01 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -23,7 +23,6 @@ #include "nsIContentViewer.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" -#include "nsIDOMFile.h" #include "nsPIDOMWindow.h" #include "nsIWebNavigation.h" #include "nsIWebProgress.h" diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 702e61aee9..86baebfe2e 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -1775,8 +1775,7 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript( } } else { // We're going to run these against some non-global scope. - options.setCompileAndGo(false) - .setHasPollutedScope(true); + options.setHasPollutedScope(true); if (!JS::Compile(cx, options, srcBuf, &script)) { return; } diff --git a/dom/base/nsIDOMFile.idl b/dom/base/nsIDOMBlob.idl similarity index 73% rename from dom/base/nsIDOMFile.idl rename to dom/base/nsIDOMBlob.idl index cc8507aa40..efdc1be84f 100644 --- a/dom/base/nsIDOMFile.idl +++ b/dom/base/nsIDOMBlob.idl @@ -53,25 +53,3 @@ interface nsIDOMBlob : nsISupports // Return true if this blob is a memory file. [notxpcom] bool isMemoryFile(); }; - -// We want to avoid multiple inheritance of nsIDOMBlob so we can downcast from -// nsIDOMBlob to Blob safely. Our chain is: -// - Blob -> nsIDOMBlob -// - File -> nsIDOMFile and Blob -[scriptable, builtinclass, uuid(cc28cf12-f1d4-44ff-843f-9289aa14613b)] -interface nsIDOMFile : nsISupports -{ - readonly attribute DOMString name; - - readonly attribute DOMString path; - - [implicit_jscontext] - readonly attribute jsval lastModifiedDate; - - readonly attribute DOMString mozFullPath; - - // This performs no security checks! - [noscript] readonly attribute DOMString mozFullPathInternal; - - [noscript] readonly attribute int64_t mozLastModifiedDate; -}; diff --git a/dom/base/nsIDOMFileList.idl b/dom/base/nsIDOMFileList.idl index 29186604c5..338bd72793 100644 --- a/dom/base/nsIDOMFileList.idl +++ b/dom/base/nsIDOMFileList.idl @@ -5,11 +5,10 @@ #include "nsISupports.idl" -interface nsIDOMFile; - -[uuid(283aa7b2-da81-4c72-aea2-9797b440fe34)] +[uuid(57128a85-34de-42db-a252-84dd57724a59)] interface nsIDOMFileList : nsISupports { readonly attribute unsigned long length; - nsIDOMFile item(in unsigned long index); + // returns a DOM File object + nsISupports item(in unsigned long index); }; diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index 1c01c6f02a..41ef992c7c 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -1089,7 +1089,7 @@ nsScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI &jsapi, aOptions->setIntroductionType("scriptElement"); aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo); aOptions->setVersion(JSVersion(aRequest->mJSVersion)); - aOptions->setCompileAndGo(JS_IsGlobalObject(aScopeChain)); + aOptions->setIsRunOnce(true); // We only need the setNoScriptRval bit when compiling off-thread here, since // otherwise nsJSUtils::EvaluateString will set it up for us. aOptions->setNoScriptRval(true); diff --git a/dom/bindings/ToJSValue.h b/dom/bindings/ToJSValue.h index 726a8479f5..2a8d4a0bf3 100644 --- a/dom/bindings/ToJSValue.h +++ b/dom/bindings/ToJSValue.h @@ -181,7 +181,7 @@ ToJSValue(JSContext* aCx, } // Accept objects that inherit from nsISupports but not nsWrapperCache (e.g. -// nsIDOMFile). +// DOM File). template MOZ_WARN_UNUSED_RESULT typename EnableIf::value && diff --git a/dom/bluetooth/bluedroid/BluetoothOppManager.cpp b/dom/bluetooth/bluedroid/BluetoothOppManager.cpp index c86a8c3262..b09cb8b683 100644 --- a/dom/bluetooth/bluedroid/BluetoothOppManager.cpp +++ b/dom/bluetooth/bluedroid/BluetoothOppManager.cpp @@ -39,36 +39,47 @@ using namespace mozilla::dom; using namespace mozilla::ipc; namespace { -// Sending system message "bluetooth-opp-update-progress" every 50kb -static const uint32_t kUpdateProgressBase = 50 * 1024; + // Sending system message "bluetooth-opp-update-progress" every 50kb + static const uint32_t kUpdateProgressBase = 50 * 1024; -/* - * The format of the header of an PUT request is - * [opcode:1][packet length:2][headerId:1][header length:2] - */ -static const uint32_t kPutRequestHeaderSize = 6; + /* + * The format of the header of an PUT request is + * [opcode:1][packet length:2][headerId:1][header length:2] + */ + static const uint32_t kPutRequestHeaderSize = 6; -/* - * The format of the appended header of an PUT request is - * [headerId:1][header length:4] - * P.S. Length of name header is 4 since unicode is 2 bytes per char. - */ -static const uint32_t kPutRequestAppendHeaderSize = 5; + /* + * The format of the appended header of an PUT request is + * [headerId:1][header length:4] + * P.S. Length of name header is 4 since unicode is 2 bytes per char. + */ + static const uint32_t kPutRequestAppendHeaderSize = 5; -StaticRefPtr sBluetoothOppManager; -static bool sInShutdown = false; + // UUID of OBEX Object Push + static const BluetoothUuid kObexObjectPush = { + { + 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB + } + }; + + StaticRefPtr sBluetoothOppManager; + static bool sInShutdown = false; } -class mozilla::dom::bluetooth::SendFileBatch { +BEGIN_BLUETOOTH_NAMESPACE + +class BluetoothOppManager::SendFileBatch final +{ public: - SendFileBatch(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob) + SendFileBatch(const nsAString& aDeviceAddress, Blob* aBlob) : mDeviceAddress(aDeviceAddress) { mBlobs.AppendElement(aBlob); } nsString mDeviceAddress; - nsCOMArray mBlobs; + nsTArray> mBlobs; }; NS_IMETHODIMP @@ -87,7 +98,7 @@ BluetoothOppManager::Observe(nsISupports* aSubject, return NS_ERROR_UNEXPECTED; } -class SendSocketDataTask : public nsRunnable +class BluetoothOppManager::SendSocketDataTask final : public nsRunnable { public: SendSocketDataTask(uint8_t* aStream, uint32_t aSize) @@ -111,7 +122,7 @@ private: uint32_t mSize; }; -class ReadFileTask : public nsRunnable +class BluetoothOppManager::ReadFileTask final : public nsRunnable { public: ReadFileTask(nsIInputStream* aInputStream, @@ -156,7 +167,7 @@ private: uint32_t mAvailablePacketSize; }; -class CloseSocketTask : public Task +class BluetoothOppManager::CloseSocketTask final : public Task { public: CloseSocketTask(BluetoothSocket* aSocket) : mSocket(aSocket) @@ -271,7 +282,7 @@ BluetoothOppManager::ConnectInternal(const nsAString& aDeviceAddress) mSocket = new BluetoothSocket(this, BluetoothSocketType::RFCOMM, false, true); - mSocket->ConnectSocket(aDeviceAddress, -1); + mSocket->ConnectSocket(aDeviceAddress, kObexObjectPush, -1); } void @@ -306,7 +317,9 @@ BluetoothOppManager::Listen() mServerSocket = new BluetoothSocket(this, BluetoothSocketType::RFCOMM, false, true); - if (!mServerSocket->ListenSocket(BluetoothReservedChannels::CHANNEL_OPUSH)) { + if (!mServerSocket->ListenSocket(NS_LITERAL_STRING("OBEX Object Push"), + kObexObjectPush, + BluetoothReservedChannels::CHANNEL_OPUSH)) { BT_WARNING("[OPP] Can't listen on RFCOMM socket!"); mServerSocket = nullptr; return false; @@ -358,7 +371,7 @@ BluetoothOppManager::SendFile(const nsAString& aDeviceAddress, bool BluetoothOppManager::SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob) + Blob* aBlob) { MOZ_ASSERT(NS_IsMainThread()); @@ -372,7 +385,7 @@ BluetoothOppManager::SendFile(const nsAString& aDeviceAddress, void BluetoothOppManager::AppendBlobToSend(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob) + Blob* aBlob) { MOZ_ASSERT(NS_IsMainThread()); @@ -734,7 +747,7 @@ BluetoothOppManager::RetrieveSentFileName() { mFileName.Truncate(); - nsCOMPtr file = do_QueryInterface(mBlob); + nsRefPtr file = static_cast(mBlob.get())->ToFile(); if (file) { file->GetName(mFileName); } @@ -1538,3 +1551,5 @@ BluetoothOppManager::Reset() { MOZ_ASSERT(false); } + +END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth/bluedroid/BluetoothOppManager.h b/dom/bluetooth/bluedroid/BluetoothOppManager.h index fcbf4731b8..0951e44e2b 100644 --- a/dom/bluetooth/bluedroid/BluetoothOppManager.h +++ b/dom/bluetooth/bluedroid/BluetoothOppManager.h @@ -14,13 +14,13 @@ #include "mozilla/ipc/SocketBase.h" #include "nsCOMArray.h" -class nsIDOMBlob; class nsIOutputStream; class nsIInputStream; class nsIVolumeMountLock; namespace mozilla { namespace dom { +class Blob; class BlobParent; } } @@ -29,11 +29,15 @@ BEGIN_BLUETOOTH_NAMESPACE class BluetoothSocket; class ObexHeaderSet; -class SendFileBatch; class BluetoothOppManager : public BluetoothSocketObserver , public BluetoothProfileManagerBase { + class CloseSocketTask; + class ReadFileTask; + class SendFileBatch; + class SendSocketDataTask; + public: BT_DECL_PROFILE_MGR_BASE BT_DECL_SOCKET_OBSERVER @@ -52,7 +56,7 @@ public: bool Listen(); bool SendFile(const nsAString& aDeviceAddress, BlobParent* aActor); - bool SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob); + bool SendFile(const nsAString& aDeviceAddress, Blob* aBlob); bool StopSendingFile(); bool ConfirmReceivingFile(bool aConfirm); @@ -94,7 +98,7 @@ private: void NotifyAboutFileChange(); bool AcquireSdcardMountLock(); void SendObexData(uint8_t* aData, uint8_t aOpcode, int aSize); - void AppendBlobToSend(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob); + void AppendBlobToSend(const nsAString& aDeviceAddress, Blob* aBlob); void DiscardBlobsToSend(); bool ProcessNextBatch(); void ConnectInternal(const nsAString& aDeviceAddress); @@ -191,7 +195,7 @@ private: nsAutoArrayPtr mReceivedDataBuffer; int mCurrentBlobIndex; - nsCOMPtr mBlob; + nsRefPtr mBlob; nsTArray mBatches; /** diff --git a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp index 1ee1282e3c..07fa806547 100644 --- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp +++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp @@ -1755,7 +1755,7 @@ BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress, void BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob, + Blob* aBlob, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); diff --git a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h index c14b43ef78..10d894b0d4 100644 --- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h +++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h @@ -130,7 +130,7 @@ public: virtual void SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob, + Blob* aBlob, BluetoothReplyRunnable* aRunnable); virtual void @@ -410,7 +410,7 @@ public: virtual void SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob, + Blob* aBlob, BluetoothReplyRunnable* aRunnable); virtual void diff --git a/dom/bluetooth/bluedroid/BluetoothSocket.cpp b/dom/bluetooth/bluedroid/BluetoothSocket.cpp index d899b7be3e..7d7a2e0cd1 100644 --- a/dom/bluetooth/bluedroid/BluetoothSocket.cpp +++ b/dom/bluetooth/bluedroid/BluetoothSocket.cpp @@ -23,10 +23,6 @@ using namespace mozilla::ipc; USING_BLUETOOTH_NAMESPACE static const size_t MAX_READ_SIZE = 1 << 16; -static const uint8_t UUID_OBEX_OBJECT_PUSH[] = { - 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00, - 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB -}; static BluetoothSocketInterface* sBluetoothSocketInterface; // helper functions @@ -560,7 +556,9 @@ private: }; bool -BluetoothSocket::ConnectSocket(const nsAString& aDeviceAddress, int aChannel) +BluetoothSocket::ConnectSocket(const nsAString& aDeviceAddress, + const BluetoothUuid& aServiceUuid, + int aChannel) { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_FALSE(mImpl, false); @@ -572,12 +570,11 @@ BluetoothSocket::ConnectSocket(const nsAString& aDeviceAddress, int aChannel) BluetoothSocketResultHandler* res = new ConnectSocketResultHandler(mImpl); SetCurrentResultHandler(res); - // TODO: uuid as argument sBluetoothSocketInterface->Connect( aDeviceAddress, BluetoothSocketType::RFCOMM, - UUID_OBEX_OBJECT_PUSH, - aChannel, mEncrypt, mAuth, res); + aServiceUuid.mUuid, aChannel, + mEncrypt, mAuth, res); return true; } @@ -611,7 +608,9 @@ private: }; bool -BluetoothSocket::ListenSocket(int aChannel) +BluetoothSocket::ListenSocket(const nsAString& aServiceName, + const BluetoothUuid& aServiceUuid, + int aChannel) { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_FALSE(mImpl, false); @@ -625,9 +624,8 @@ BluetoothSocket::ListenSocket(int aChannel) sBluetoothSocketInterface->Listen( BluetoothSocketType::RFCOMM, - NS_LITERAL_STRING("OBEX Object Push"), - UUID_OBEX_OBJECT_PUSH, - aChannel, mEncrypt, mAuth, res); + aServiceName, aServiceUuid.mUuid, aChannel, + mEncrypt, mAuth, res); return true; } diff --git a/dom/bluetooth/bluedroid/BluetoothSocket.h b/dom/bluetooth/bluedroid/BluetoothSocket.h index 42790b5442..9ef88ba4b3 100644 --- a/dom/bluetooth/bluedroid/BluetoothSocket.h +++ b/dom/bluetooth/bluedroid/BluetoothSocket.h @@ -24,9 +24,13 @@ public: bool aAuth, bool aEncrypt); - bool ConnectSocket(const nsAString& aDeviceAddress, int aChannel); + bool ConnectSocket(const nsAString& aDeviceAddress, + const BluetoothUuid& aServiceUuid, + int aChannel); - bool ListenSocket(int aChannel); + bool ListenSocket(const nsAString& aServiceName, + const BluetoothUuid& aServiceUuid, + int aChannel); void CloseSocket(); diff --git a/dom/bluetooth/bluetooth1/BluetoothService.h b/dom/bluetooth/bluetooth1/BluetoothService.h index 8bae24a9b4..38d1ace81c 100644 --- a/dom/bluetooth/bluetooth1/BluetoothService.h +++ b/dom/bluetooth/bluetooth1/BluetoothService.h @@ -11,15 +11,13 @@ #include "BluetoothProfileManagerBase.h" #include "nsAutoPtr.h" #include "nsClassHashtable.h" -#include "nsIDOMFile.h" #include "nsIObserver.h" #include "nsTObserverArray.h" #include "nsThreadUtils.h" -class nsIDOMBlob; - namespace mozilla { namespace dom { +class Blob; class BlobChild; class BlobParent; } @@ -241,7 +239,7 @@ public: virtual void SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob, + Blob* aBlob, BluetoothReplyRunnable* aRunnable) = 0; virtual void diff --git a/dom/bluetooth/bluetooth1/ipc/BluetoothServiceChildProcess.cpp b/dom/bluetooth/bluetooth1/ipc/BluetoothServiceChildProcess.cpp index a2835b87c6..c1a847acf0 100644 --- a/dom/bluetooth/bluetooth1/ipc/BluetoothServiceChildProcess.cpp +++ b/dom/bluetooth/bluetooth1/ipc/BluetoothServiceChildProcess.cpp @@ -268,7 +268,7 @@ BluetoothServiceChildProcess::SendFile( void BluetoothServiceChildProcess::SendFile( const nsAString& aDeviceAddress, - nsIDOMBlob* aBlobChild, + Blob* aBlobChild, BluetoothReplyRunnable* aRunnable) { // Parent-process-only method diff --git a/dom/bluetooth/bluetooth1/ipc/BluetoothServiceChildProcess.h b/dom/bluetooth/bluetooth1/ipc/BluetoothServiceChildProcess.h index fa37494301..e873bdfc52 100644 --- a/dom/bluetooth/bluetooth1/ipc/BluetoothServiceChildProcess.h +++ b/dom/bluetooth/bluetooth1/ipc/BluetoothServiceChildProcess.h @@ -111,7 +111,7 @@ public: virtual void SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob, + Blob* aBlob, BluetoothReplyRunnable* aRunnable) override; virtual void diff --git a/dom/bluetooth/bluetooth2/BluetoothService.h b/dom/bluetooth/bluetooth2/BluetoothService.h index d1d4a4cafd..f8e98eb303 100644 --- a/dom/bluetooth/bluetooth2/BluetoothService.h +++ b/dom/bluetooth/bluetooth2/BluetoothService.h @@ -12,15 +12,13 @@ #include "BluetoothProfileManagerBase.h" #include "nsAutoPtr.h" #include "nsClassHashtable.h" -#include "nsIDOMFile.h" #include "nsIObserver.h" #include "nsTObserverArray.h" #include "nsThreadUtils.h" -class nsIDOMBlob; - namespace mozilla { namespace dom { +class Blob; class BlobChild; class BlobParent; } @@ -285,7 +283,7 @@ public: virtual void SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob, + Blob* aBlob, BluetoothReplyRunnable* aRunnable) = 0; virtual void diff --git a/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.cpp b/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.cpp index 22508ca7b6..00244d3ff7 100644 --- a/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.cpp +++ b/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.cpp @@ -302,7 +302,7 @@ BluetoothServiceChildProcess::SendFile( void BluetoothServiceChildProcess::SendFile( const nsAString& aDeviceAddress, - nsIDOMBlob* aBlobChild, + Blob* aBlobChild, BluetoothReplyRunnable* aRunnable) { // Parent-process-only method diff --git a/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.h b/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.h index e9164541ee..63de3022c9 100644 --- a/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.h +++ b/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.h @@ -132,7 +132,7 @@ public: virtual void SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob, + Blob* aBlob, BluetoothReplyRunnable* aRunnable) override; virtual void diff --git a/dom/bluetooth/bluez/BluetoothDBusService.cpp b/dom/bluetooth/bluez/BluetoothDBusService.cpp index f19da0a5fc..1ae7051424 100644 --- a/dom/bluetooth/bluez/BluetoothDBusService.cpp +++ b/dom/bluetooth/bluez/BluetoothDBusService.cpp @@ -4161,7 +4161,7 @@ BluetoothDBusService::SendFile(const nsAString& aDeviceAddress, void BluetoothDBusService::SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob, + Blob* aBlob, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); diff --git a/dom/bluetooth/bluez/BluetoothDBusService.h b/dom/bluetooth/bluez/BluetoothDBusService.h index c27e75ddf9..eefbd9cf9d 100644 --- a/dom/bluetooth/bluez/BluetoothDBusService.h +++ b/dom/bluetooth/bluez/BluetoothDBusService.h @@ -174,7 +174,7 @@ public: virtual void SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob, + Blob* aBlob, BluetoothReplyRunnable* aRunnable) override; virtual void diff --git a/dom/bluetooth/bluez/BluetoothHfpManager.cpp b/dom/bluetooth/bluez/BluetoothHfpManager.cpp index a48085ac85..db1eeefe21 100644 --- a/dom/bluetooth/bluez/BluetoothHfpManager.cpp +++ b/dom/bluetooth/bluez/BluetoothHfpManager.cpp @@ -81,6 +81,30 @@ namespace { bool sInShutdown = false; static const char kHfpCrlf[] = "\xd\xa"; + // UUID of Handsfree Audio Gateway + static const BluetoothUuid kHandsfreeAG = { + { + 0x00, 0x00, 0x11, 0x1F, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB + } + }; + + // UUID of Headset Audio Gateway + static const BluetoothUuid kHeadsetAG = { + { + 0x00, 0x00, 0x11, 0x12, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB + } + }; + + // Unknown service UUID (for SCO socket) + static const BluetoothUuid kUnknownService = { + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB + } + }; + #ifdef MOZ_B2G_RIL // Sending ringtone related static bool sStopSendingRingFlag = true; @@ -1177,6 +1201,8 @@ BluetoothHfpManager::Listen() new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true); if (!mHandsfreeSocket->Listen( + NS_LITERAL_STRING("Handsfree Audio Gateway"), + kHandsfreeAG, BluetoothReservedChannels::CHANNEL_HANDSFREE_AG)) { BT_WARNING("[HFP] Can't listen on RFCOMM socket!"); mHandsfreeSocket = nullptr; @@ -1189,6 +1215,8 @@ BluetoothHfpManager::Listen() new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true); if (!mHeadsetSocket->Listen( + NS_LITERAL_STRING("Headset Audio Gateway"), + kHeadsetAG, BluetoothReservedChannels::CHANNEL_HEADSET_AG)) { BT_WARNING("[HSP] Can't listen on RFCOMM socket!"); mHandsfreeSocket->Disconnect(); @@ -1897,7 +1925,9 @@ BluetoothHfpManager::OnGetServiceChannel(const nsAString& aDeviceAddress, MOZ_ASSERT(mSocket); - if (!mSocket->Connect(NS_ConvertUTF16toUTF8(aDeviceAddress), aChannel)) { + if (!mSocket->Connect(aDeviceAddress, + mIsHsp? kHeadsetAG : kHandsfreeAG, + aChannel)) { OnConnect(NS_LITERAL_STRING(ERR_CONNECTION_FAILED)); } } @@ -1993,7 +2023,7 @@ BluetoothHfpManager::ConnectSco(BluetoothReplyRunnable* aRunnable) // Stop listening mScoSocket->Disconnect(); - mScoSocket->Connect(NS_ConvertUTF16toUTF8(mDeviceAddress), -1); + mScoSocket->Connect(mDeviceAddress, kUnknownService, -1); mScoSocketStatus = mScoSocket->GetConnectionStatus(); mScoRunnable = aRunnable; @@ -2030,7 +2060,8 @@ BluetoothHfpManager::ListenSco() mScoSocket->Disconnect(); - if (!mScoSocket->Listen(-1)) { + if (!mScoSocket->Listen(NS_LITERAL_STRING("Handsfree Audio Gateway SCO"), + kUnknownService, -1)) { BT_WARNING("Can't listen on SCO socket!"); return false; } diff --git a/dom/bluetooth/bluez/BluetoothOppManager.cpp b/dom/bluetooth/bluez/BluetoothOppManager.cpp index ab3e7b77df..6df42823aa 100644 --- a/dom/bluetooth/bluez/BluetoothOppManager.cpp +++ b/dom/bluetooth/bluez/BluetoothOppManager.cpp @@ -41,40 +41,49 @@ using mozilla::TimeDuration; using mozilla::TimeStamp; namespace { -// Sending system message "bluetooth-opp-update-progress" every 50kb -static const uint32_t kUpdateProgressBase = 50 * 1024; + // Sending system message "bluetooth-opp-update-progress" every 50kb + static const uint32_t kUpdateProgressBase = 50 * 1024; -/* - * The format of the header of an PUT request is - * [opcode:1][packet length:2][headerId:1][header length:2] - */ -static const uint32_t kPutRequestHeaderSize = 6; + /* + * The format of the header of an PUT request is + * [opcode:1][packet length:2][headerId:1][header length:2] + */ + static const uint32_t kPutRequestHeaderSize = 6; -/* - * The format of the appended header of an PUT request is - * [headerId:1][header length:4] - * P.S. Length of name header is 4 since unicode is 2 bytes per char. - */ -static const uint32_t kPutRequestAppendHeaderSize = 5; + /* + * The format of the appended header of an PUT request is + * [headerId:1][header length:4] + * P.S. Length of name header is 4 since unicode is 2 bytes per char. + */ + static const uint32_t kPutRequestAppendHeaderSize = 5; -// The default timeout we permit to wait for SDP updating if we can't get -// service channel. -static const double kSdpUpdatingTimeoutMs = 3000.0; + // The default timeout we permit to wait for SDP updating if we can't get + // service channel. + static const double kSdpUpdatingTimeoutMs = 3000.0; -StaticRefPtr sBluetoothOppManager; -static bool sInShutdown = false; + // UUID of OBEX Object Push + static const BluetoothUuid kObexObjectPush = { + { + 0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB + } + }; + + StaticRefPtr sBluetoothOppManager; + static bool sInShutdown = false; } -class mozilla::dom::bluetooth::SendFileBatch { +class mozilla::dom::bluetooth::SendFileBatch +{ public: - SendFileBatch(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob) + SendFileBatch(const nsAString& aDeviceAddress, Blob* aBlob) : mDeviceAddress(aDeviceAddress) { mBlobs.AppendElement(aBlob); } nsString mDeviceAddress; - nsCOMArray mBlobs; + nsTArray> mBlobs; }; NS_IMETHODIMP @@ -314,7 +323,9 @@ BluetoothOppManager::Listen() mRfcommSocket = new BluetoothSocket(this, BluetoothSocketType::RFCOMM, true, true); - if (!mRfcommSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH)) { + if (!mRfcommSocket->Listen(NS_LITERAL_STRING("OBEX Object Push"), + kObexObjectPush, + BluetoothReservedChannels::CHANNEL_OPUSH)) { BT_WARNING("[OPP] Can't listen on RFCOMM socket!"); mRfcommSocket = nullptr; return false; @@ -325,7 +336,9 @@ BluetoothOppManager::Listen() mL2capSocket = new BluetoothSocket(this, BluetoothSocketType::EL2CAP, true, true); - if (!mL2capSocket->Listen(BluetoothReservedChannels::CHANNEL_OPUSH_L2CAP)) { + if (!mL2capSocket->Listen(NS_LITERAL_STRING("OBEX Object Push"), + kObexObjectPush, + BluetoothReservedChannels::CHANNEL_OPUSH_L2CAP)) { BT_WARNING("[OPP] Can't listen on L2CAP socket!"); mRfcommSocket->Disconnect(); mRfcommSocket = nullptr; @@ -373,14 +386,14 @@ BluetoothOppManager::SendFile(const nsAString& aDeviceAddress, MOZ_ASSERT(NS_IsMainThread()); nsRefPtr impl = aActor->GetBlobImpl(); - nsCOMPtr blob = Blob::Create(nullptr, impl); + nsRefPtr blob = Blob::Create(nullptr, impl); - return SendFile(aDeviceAddress, blob.get()); + return SendFile(aDeviceAddress, blob); } bool BluetoothOppManager::SendFile(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob) + Blob* aBlob) { MOZ_ASSERT(NS_IsMainThread()); @@ -394,7 +407,7 @@ BluetoothOppManager::SendFile(const nsAString& aDeviceAddress, void BluetoothOppManager::AppendBlobToSend(const nsAString& aDeviceAddress, - nsIDOMBlob* aBlob) + Blob* aBlob) { MOZ_ASSERT(NS_IsMainThread()); @@ -756,7 +769,7 @@ BluetoothOppManager::RetrieveSentFileName() { mFileName.Truncate(); - nsCOMPtr file = do_QueryInterface(mBlob); + nsRefPtr file = mBlob->ToFile(); if (file) { file->GetName(mFileName); } @@ -1619,7 +1632,7 @@ BluetoothOppManager::OnGetServiceChannel(const nsAString& aDeviceAddress, return; } - if (!mSocket->Connect(NS_ConvertUTF16toUTF8(aDeviceAddress), aChannel)) { + if (!mSocket->Connect(aDeviceAddress, kObexObjectPush, aChannel)) { OnSocketConnectError(mSocket); } } diff --git a/dom/bluetooth/bluez/BluetoothOppManager.h b/dom/bluetooth/bluez/BluetoothOppManager.h index afa559967f..1a1becb3f9 100644 --- a/dom/bluetooth/bluez/BluetoothOppManager.h +++ b/dom/bluetooth/bluez/BluetoothOppManager.h @@ -14,13 +14,13 @@ #include "mozilla/ipc/SocketBase.h" #include "nsCOMArray.h" -class nsIDOMBlob; class nsIOutputStream; class nsIInputStream; class nsIVolumeMountLock; namespace mozilla { namespace dom { +class Blob; class BlobParent; } } @@ -52,7 +52,7 @@ public: bool Listen(); bool SendFile(const nsAString& aDeviceAddress, BlobParent* aActor); - bool SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob); + bool SendFile(const nsAString& aDeviceAddress, Blob* aBlob); bool StopSendingFile(); bool ConfirmReceivingFile(bool aConfirm); @@ -94,7 +94,7 @@ private: void NotifyAboutFileChange(); bool AcquireSdcardMountLock(); void SendObexData(uint8_t* aData, uint8_t aOpcode, int aSize); - void AppendBlobToSend(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob); + void AppendBlobToSend(const nsAString& aDeviceAddress, Blob* aBlob); void DiscardBlobsToSend(); bool ProcessNextBatch(); void ConnectInternal(const nsAString& aDeviceAddress); @@ -191,7 +191,7 @@ private: nsAutoArrayPtr mReceivedDataBuffer; int mCurrentBlobIndex; - nsCOMPtr mBlob; + nsRefPtr mBlob; nsTArray mBatches; /** diff --git a/dom/bluetooth/bluez/BluetoothSocket.cpp b/dom/bluetooth/bluez/BluetoothSocket.cpp index 8cde9712c5..6ba62a2ddc 100644 --- a/dom/bluetooth/bluez/BluetoothSocket.cpp +++ b/dom/bluetooth/bluez/BluetoothSocket.cpp @@ -26,7 +26,9 @@ BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver, } bool -BluetoothSocket::Connect(const nsACString& aDeviceAddress, int aChannel) +BluetoothSocket::Connect(const nsAString& aDeviceAddress, + const BluetoothUuid& aServiceUuid, + int aChannel) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!aDeviceAddress.IsEmpty()); @@ -34,7 +36,8 @@ BluetoothSocket::Connect(const nsACString& aDeviceAddress, int aChannel) nsAutoPtr c( new BluetoothUnixSocketConnector(mType, aChannel, mAuth, mEncrypt)); - if (!ConnectSocket(c.forget(), aDeviceAddress.BeginReading())) { + if (!ConnectSocket(c.forget(), + NS_ConvertUTF16toUTF8(aDeviceAddress).BeginReading())) { nsAutoString addr; GetAddress(addr); BT_LOGD("%s failed. Current connected device address: %s", @@ -46,7 +49,9 @@ BluetoothSocket::Connect(const nsACString& aDeviceAddress, int aChannel) } bool -BluetoothSocket::Listen(int aChannel) +BluetoothSocket::Listen(const nsAString& aServiceName, + const BluetoothUuid& aServiceUuid, + int aChannel) { MOZ_ASSERT(NS_IsMainThread()); diff --git a/dom/bluetooth/bluez/BluetoothSocket.h b/dom/bluetooth/bluez/BluetoothSocket.h index 1fc29a2f41..5e4b82d3ce 100644 --- a/dom/bluetooth/bluez/BluetoothSocket.h +++ b/dom/bluetooth/bluez/BluetoothSocket.h @@ -22,8 +22,12 @@ public: bool aAuth, bool aEncrypt); - bool Connect(const nsACString& aDeviceAddress, int aChannel); - bool Listen(int aChannel); + bool Connect(const nsAString& aDeviceAddress, + const BluetoothUuid& aServiceUuid, + int aChannel); + bool Listen(const nsAString& aServiceName, + const BluetoothUuid& aServiceUuid, + int aChannel); inline void Disconnect() { CloseSocket(); diff --git a/dom/fetch/InternalResponse.cpp b/dom/fetch/InternalResponse.cpp index 6d7c1125b4..6ee065c7bc 100644 --- a/dom/fetch/InternalResponse.cpp +++ b/dom/fetch/InternalResponse.cpp @@ -6,8 +6,6 @@ #include "InternalResponse.h" -#include "nsIDOMFile.h" - #include "mozilla/dom/InternalHeaders.h" #include "nsStreamUtils.h" #include "nsSerializationHelper.h" diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index c505ce064a..4249f5318a 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -600,16 +600,22 @@ HTMLCanvasElement::MozGetAsFile(const nsAString& aName, const nsAString& aType, ErrorResult& aRv) { - nsCOMPtr file; + nsCOMPtr file; aRv = MozGetAsFile(aName, aType, getter_AddRefs(file)); - nsRefPtr tmp = static_cast(file.get()); - return tmp.forget(); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + nsCOMPtr blob = do_QueryInterface(file); + nsRefPtr domBlob = static_cast(blob.get()); + MOZ_ASSERT(domBlob->IsFile()); + return domBlob->ToFile(); } NS_IMETHODIMP HTMLCanvasElement::MozGetAsFile(const nsAString& aName, const nsAString& aType, - nsIDOMFile** aResult) + nsISupports** aResult) { OwnerDoc()->WarnOnceAbout(nsIDocument::eMozGetAsFile); @@ -625,7 +631,7 @@ HTMLCanvasElement::MozGetAsFile(const nsAString& aName, nsresult HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName, const nsAString& aType, - nsIDOMFile** aResult) + nsISupports** aResult) { nsCOMPtr stream; nsAutoString type(aType); @@ -649,7 +655,7 @@ HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName, nsCOMPtr win = do_QueryInterface(OwnerDoc()->GetScopeObject()); // The File takes ownership of the buffer - nsRefPtr file = + nsCOMPtr file = File::CreateMemoryFile(win, imgData, (uint32_t)imgSize, aName, type, PR_Now()); diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h index b9d23d692a..fa5e927bbd 100644 --- a/dom/html/HTMLCanvasElement.h +++ b/dom/html/HTMLCanvasElement.h @@ -234,7 +234,7 @@ protected: nsAString& aDataURL); nsresult MozGetAsBlobImpl(const nsAString& aName, const nsAString& aType, - nsIDOMFile** aResult); + nsISupports** aResult); void CallPrintCallback(); CanvasContextType mCurrentContextType; diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 8ed3127857..1f0495fb51 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -405,7 +405,9 @@ public: MOZ_ASSERT(blobImpl); blobImpl->SetPath(Substring(path, 0, uint32_t(length))); } - *aResult = domFile.forget().downcast().take(); + + nsCOMPtr blob = domFile.get(); + blob.forget(aResult); LookupAndCacheNext(); return NS_OK; } @@ -488,23 +490,28 @@ NS_IMPL_ISUPPORTS(DirPickerRecursiveFileEnumerator, nsISimpleEnumerator) /** * This may return nullptr if aDomFile's implementation of - * nsIDOMFile::mozFullPathInternal does not successfully return a non-empty + * File::mozFullPathInternal does not successfully return a non-empty * string that is a valid path. This can happen on Firefox OS, for example, * where the file picker can create Blobs. */ static already_AddRefed -DOMFileToLocalFile(nsIDOMFile* aDomFile) +DOMFileToLocalFile(File* aDomFile) { nsString path; - nsresult rv = aDomFile->GetMozFullPathInternal(path); - if (NS_FAILED(rv) || path.IsEmpty()) { + ErrorResult rv; + aDomFile->GetMozFullPathInternal(path, rv); + if (rv.Failed() || path.IsEmpty()) { + rv.SuppressException(); return nullptr; } nsCOMPtr localFile; rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true, getter_AddRefs(localFile)); - NS_ENSURE_SUCCESS(rv, nullptr); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + return nullptr; + } return localFile.forget(); } @@ -532,9 +539,9 @@ public: nsCOMPtr tmp; while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) { iter->GetNext(getter_AddRefs(tmp)); - nsCOMPtr domFile = do_QueryInterface(tmp); - MOZ_ASSERT(domFile); - mFileList.AppendElement(static_cast(domFile.get())); + nsCOMPtr domBlob = do_QueryInterface(tmp); + MOZ_ASSERT(domBlob); + mFileList.AppendElement(static_cast(domBlob.get())); mFileListLength = mFileList.Length(); if (mCanceled) { MOZ_ASSERT(!mInput, "This is bad - how did this happen?"); @@ -691,20 +698,23 @@ HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult) while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) { iter->GetNext(getter_AddRefs(tmp)); - nsCOMPtr domFile = do_QueryInterface(tmp); - NS_WARN_IF_FALSE(domFile, + nsCOMPtr domBlob = do_QueryInterface(tmp); + NS_WARN_IF_FALSE(domBlob, "Null file object from FilePicker's file enumerator?"); - if (domFile) { - newFiles.AppendElement(static_cast(domFile.get())); + if (domBlob) { + newFiles.AppendElement(static_cast(domBlob.get())); } } } else { MOZ_ASSERT(mode == static_cast(nsIFilePicker::modeOpen)); - nsCOMPtr domFile; - nsresult rv = mFilePicker->GetDomfile(getter_AddRefs(domFile)); + nsCOMPtr tmp; + nsresult rv = mFilePicker->GetDomfile(getter_AddRefs(tmp)); NS_ENSURE_SUCCESS(rv, rv); - if (domFile) { - newFiles.AppendElement(static_cast(domFile.get())); + + nsCOMPtr blob = do_QueryInterface(tmp); + if (blob) { + nsRefPtr file = static_cast(blob.get())->ToFile(); + newFiles.AppendElement(file); } } @@ -969,7 +979,11 @@ HTMLInputElement::InitFilePicker(FilePickerType aType) aType != FILE_PICKER_DIRECTORY) { nsString path; - oldFiles[0]->GetMozFullPathInternal(path); + ErrorResult error; + oldFiles[0]->GetMozFullPathInternal(path, error); + if (NS_WARN_IF(error.Failed())) { + return error.StealNSResult(); + } nsCOMPtr localFile; rv = NS_NewLocalFile(path, false, getter_AddRefs(localFile)); @@ -1720,7 +1734,12 @@ HTMLInputElement::GetValueInternal(nsAString& aValue) const // XXX We'd love to assert that this can't happen, but some mochitests // use SpecialPowers to circumvent our more sane security model. if (!mFiles.IsEmpty()) { - return mFiles[0]->GetMozFullPath(aValue); + ErrorResult rv; + mFiles[0]->GetMozFullPath(aValue, rv); + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); + } + return NS_OK; } else { aValue.Truncate(); @@ -1728,8 +1747,10 @@ HTMLInputElement::GetValueInternal(nsAString& aValue) const #endif } else { // Just return the leaf name - if (mFiles.IsEmpty() || NS_FAILED(mFiles[0]->GetName(aValue))) { + if (mFiles.IsEmpty()) { aValue.Truncate(); + } else { + mFiles[0]->GetName(aValue); } } @@ -2319,11 +2340,16 @@ HTMLInputElement::FlushFrames() } void -HTMLInputElement::MozGetFileNameArray(nsTArray< nsString >& aArray) +HTMLInputElement::MozGetFileNameArray(nsTArray& aArray, + ErrorResult& aRv) { for (uint32_t i = 0; i < mFiles.Length(); i++) { nsString str; - mFiles[i]->GetMozFullPathInternal(str); + mFiles[i]->GetMozFullPathInternal(str, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + aArray.AppendElement(str); } } @@ -2338,8 +2364,12 @@ HTMLInputElement::MozGetFileNameArray(uint32_t* aLength, char16_t*** aFileNames) return NS_ERROR_DOM_SECURITY_ERR; } + ErrorResult rv; nsTArray array; - MozGetFileNameArray(array); + MozGetFileNameArray(array, rv); + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); + } *aLength = array.Length(); char16_t** ret = @@ -2699,7 +2729,11 @@ HTMLInputElement::AfterSetFiles(bool aSetValueChanged) if (mFiles.IsEmpty()) { mFirstFilePath.Truncate(); } else { - mFiles[0]->GetMozFullPath(mFirstFilePath); + ErrorResult rv; + mFiles[0]->GetMozFullPath(mFirstFilePath, rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } } #endif diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index a103241138..551d4a090b 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -718,7 +718,7 @@ public: int32_t GetTextLength(ErrorResult& aRv); - void MozGetFileNameArray(nsTArray< nsString >& aFileNames); + void MozGetFileNameArray(nsTArray& aFileNames, ErrorResult& aRv); void MozSetFileNameArray(const Sequence< nsString >& aFileNames, ErrorResult& aRv); void MozSetFileArray(const Sequence>& aFiles); diff --git a/dom/html/nsFormSubmission.cpp b/dom/html/nsFormSubmission.cpp index 4c77027bd0..6f62f1f58e 100644 --- a/dom/html/nsFormSubmission.cpp +++ b/dom/html/nsFormSubmission.cpp @@ -18,7 +18,6 @@ #include "nsAttrValueInlines.h" #include "nsISaveAsCharset.h" #include "nsIFile.h" -#include "nsIDOMFile.h" #include "nsDirectoryServiceDefs.h" #include "nsStringStream.h" #include "nsIURI.h" @@ -451,15 +450,13 @@ nsFSMultipartFormData::AddNameFilePair(const nsAString& aName, nsCOMPtr fileStream; if (aFile) { nsAutoString filename16; - rv = aFile->GetName(filename16); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } + aFile->GetName(filename16); + ErrorResult error; nsAutoString filepath16; - rv = aFile->GetPath(filepath16); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; + aFile->GetPath(filepath16, error); + if (NS_WARN_IF(error.Failed())) { + return error.StealNSResult(); } if (!filepath16.IsEmpty()) { diff --git a/dom/indexedDB/IDBMutableFile.cpp b/dom/indexedDB/IDBMutableFile.cpp index 9eaa14d5ed..c8855c0753 100644 --- a/dom/indexedDB/IDBMutableFile.cpp +++ b/dom/indexedDB/IDBMutableFile.cpp @@ -27,7 +27,6 @@ #include "nsContentUtils.h" #include "nsDebug.h" #include "nsError.h" -#include "nsIDOMFile.h" #include "nsIPrincipal.h" namespace mozilla { @@ -328,7 +327,7 @@ IDBMutableFile::GetFileId() const return mFileInfo->Id(); } -already_AddRefed +already_AddRefed IDBMutableFile::CreateFileObject(IDBFileHandle* aFileHandle, MetadataParameters* aMetadataParams) { @@ -393,12 +392,10 @@ GetFileHelper::GetSuccessResult(JSContext* aCx, auto fileHandle = static_cast(mFileHandle.get()); - nsCOMPtr domFile = + nsRefPtr domFile = mMutableFile->CreateFileObject(fileHandle, mParams); - nsresult rv = - nsContentUtils::WrapNative(aCx, domFile, &NS_GET_IID(nsIDOMFile), aVal); - if (NS_WARN_IF(NS_FAILED(rv))) { + if (!ToJSValue(aCx, domFile, aVal)) { return NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR; } diff --git a/dom/indexedDB/IDBMutableFile.h b/dom/indexedDB/IDBMutableFile.h index ca26c78908..45f78b9c67 100644 --- a/dom/indexedDB/IDBMutableFile.h +++ b/dom/indexedDB/IDBMutableFile.h @@ -18,7 +18,6 @@ #include "nsAutoPtr.h" #include "nsCycleCollectionParticipant.h" -class nsIDOMFile; class nsPIDOMWindow; namespace mozilla { @@ -28,6 +27,7 @@ class ErrorResult; namespace dom { class DOMRequest; +class File; class MetadataParameters; namespace indexedDB { @@ -83,7 +83,7 @@ public: return mFileInfo; } - already_AddRefed + already_AddRefed CreateFileObject(IDBFileHandle* aFileHandle, MetadataParameters* aMetadataParams); diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 4c10eaa746..75a831bc6d 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -334,14 +334,14 @@ StructuredCloneWriteCallback(JSContext* aCx, nsRefPtr file = blob->ToFile(); if (file) { - int64_t lastModifiedDate; - MOZ_ALWAYS_TRUE(NS_SUCCEEDED( - file->GetMozLastModifiedDate(&lastModifiedDate))); + ErrorResult rv; + int64_t lastModifiedDate = file->GetLastModified(rv); + MOZ_ALWAYS_TRUE(!rv.Failed()); lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate); nsString name; - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(file->GetName(name))); + file->GetName(name); NS_ConvertUTF16toUTF8 convName(name); uint32_t convNameLength = diff --git a/dom/indexedDB/IDBTransaction.cpp b/dom/indexedDB/IDBTransaction.cpp index a04aceb237..c46c695774 100644 --- a/dom/indexedDB/IDBTransaction.cpp +++ b/dom/indexedDB/IDBTransaction.cpp @@ -17,7 +17,6 @@ #include "mozilla/dom/DOMStringList.h" #include "mozilla/ipc/BackgroundChild.h" #include "nsIAppShell.h" -#include "nsIDOMFile.h" #include "nsPIDOMWindow.h" #include "nsServiceManagerUtils.h" #include "nsTHashtable.h" diff --git a/dom/indexedDB/test/file.js b/dom/indexedDB/test/file.js index db0761910d..ae63af38f9 100644 --- a/dom/indexedDB/test/file.js +++ b/dom/indexedDB/test/file.js @@ -94,12 +94,11 @@ function verifyBlob(blob1, blob2, fileId, blobReadHandler) { is(blob1 instanceof Components.interfaces.nsIDOMBlob, true, "Instance of nsIDOMBlob"); - is(blob1 instanceof Components.interfaces.nsIDOMFile, - blob2 instanceof Components.interfaces.nsIDOMFile, - "Instance of nsIDOMFile"); + is(blob1 instanceof File, blob2 instanceof File, + "Instance of DOM File"); is(blob1.size, blob2.size, "Correct size"); is(blob1.type, blob2.type, "Correct type"); - if (blob2 instanceof Components.interfaces.nsIDOMFile) { + if (blob2 instanceof File) { is(blob1.name, blob2.name, "Correct name"); } is(utils.getFileId(blob1), fileId, "Correct file id"); diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 7d72acc380..fcfb1250f1 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -39,8 +39,6 @@ interface nsIDOMStyleSheet; interface nsITransferable; interface nsIQueryContentEventResult; interface nsIDOMWindow; -interface nsIDOMBlob; -interface nsIDOMFile; interface nsIFile; interface nsIDOMClientRect; interface nsIURI; @@ -51,7 +49,7 @@ interface nsIJSRAIIHelper; interface nsIContentPermissionRequest; interface nsIObserver; -[scriptable, uuid(7f2f44ab-2857-4cc2-8c9d-3d9816f5a4d6)] +[scriptable, uuid(34a42cdc-7a04-4e71-8a5c-63e092fba58e)] interface nsIDOMWindowUtils : nsISupports { /** @@ -613,6 +611,11 @@ interface nsIDOMWindowUtils : nsISupports { */ const unsigned long MOUSESCROLL_PREFER_WIDGET_AT_POINT = 0x00000001; + /** + * Interpret the scroll delta values as lines rather than pixels. + */ + const unsigned long MOUSESCROLL_SCROLL_LINES = 0x00000002; + /** * The platform specific values of aAdditionalFlags. Must be over 0x00010000. */ @@ -1327,6 +1330,13 @@ interface nsIDOMWindowUtils : nsISupports { */ readonly attribute boolean layerManagerRemote; + /** + * True if we can initialize a hardware-backed h264 decoder for a simple + * test video, does not mean that all h264 video decoding will be done + * in hardware. + */ + readonly attribute boolean supportsHardwareH264Decoding; + /** * Record (and return) frame-intervals for frames which were presented * between calling StartFrameTimeRecording and StopFrameTimeRecording. @@ -1433,9 +1443,10 @@ interface nsIDOMWindowUtils : nsISupports { in AString value2); /** - * Wrap an nsIFile in an nsIDOMFile + * Wrap an nsIFile in an DOM File + * Returns a File object. */ - nsIDOMFile wrapDOMFile(in nsIFile aFile); + nsISupports wrapDOMFile(in nsIFile aFile); /** * Get the type of the currently focused html input, if any. @@ -1736,6 +1747,11 @@ interface nsIDOMWindowUtils : nsISupports { [implicit_jscontext] jsval getContentAPZTestData(); [implicit_jscontext] jsval getCompositorAPZTestData(); + /** + * Posts an eRestyle_Self restyle event for the given element. + */ + void postRestyleSelfEvent(in nsIDOMElement aElement); + /** * With this it's possible to mute all the MediaElements in this window. * We have audioMuted and audioVolume to preserve the volume across diff --git a/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl b/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl index 3ec838bb59..eaccc631b0 100644 --- a/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl +++ b/dom/interfaces/html/nsIDOMHTMLCanvasElement.idl @@ -16,11 +16,10 @@ */ interface nsIDOMBlob; -interface nsIDOMFile; interface nsIVariant; interface nsIInputStreamCallback; -[uuid(8978d1c5-2981-4678-a1c3-b0b7bae04fbc)] +[uuid(2c984658-2e7c-4774-8ac5-cf1b39f8bec3)] interface nsIDOMHTMLCanvasElement : nsISupports { attribute unsigned long width; @@ -38,7 +37,8 @@ interface nsIDOMHTMLCanvasElement : nsISupports // Valid calls are // mozGetAsFile(name); -- defaults to image/png // mozGetAsFile(name, type); -- uses given type - nsIDOMFile mozGetAsFile(in DOMString name, [optional] in DOMString type); + // The return value is a File object. + nsISupports mozGetAsFile(in DOMString name, [optional] in DOMString type); // A Mozilla-only extension to get a canvas context backed by double-buffered // shared memory. Only privileged callers can call this. diff --git a/dom/ipc/Blob.cpp b/dom/ipc/Blob.cpp index 18ee2043a6..a713dc321d 100644 --- a/dom/ipc/Blob.cpp +++ b/dom/ipc/Blob.cpp @@ -2064,8 +2064,8 @@ public: virtual void GetName(nsAString& aName) override; - virtual nsresult - GetPath(nsAString& aPath) override; + virtual void + GetPath(nsAString& aPath, ErrorResult& aRv) override; virtual int64_t GetLastModified(ErrorResult& aRv) override; @@ -2742,11 +2742,11 @@ RemoteBlobImpl::GetName(nsAString& aName) mBlobImpl->GetName(aName); } -nsresult +void BlobParent:: -RemoteBlobImpl::GetPath(nsAString& aPath) +RemoteBlobImpl::GetPath(nsAString& aPath, ErrorResult& aRv) { - return mBlobImpl->GetPath(aPath); + mBlobImpl->GetPath(aPath, aRv); } int64_t diff --git a/dom/ipc/FilePickerParent.cpp b/dom/ipc/FilePickerParent.cpp index e1d48ce97b..3ee1189045 100644 --- a/dom/ipc/FilePickerParent.cpp +++ b/dom/ipc/FilePickerParent.cpp @@ -8,7 +8,6 @@ #include "nsComponentManagerUtils.h" #include "nsNetCID.h" #include "nsIDocument.h" -#include "nsIDOMFile.h" #include "nsIDOMWindow.h" #include "nsIFile.h" #include "nsISimpleEnumerator.h" diff --git a/dom/ipc/FilePickerParent.h b/dom/ipc/FilePickerParent.h index 7a2f0e896e..72cc41dc09 100644 --- a/dom/ipc/FilePickerParent.h +++ b/dom/ipc/FilePickerParent.h @@ -7,7 +7,6 @@ #ifndef mozilla_dom_FilePickerParent_h #define mozilla_dom_FilePickerParent_h -#include "nsIDOMFile.h" #include "nsIEventTarget.h" #include "nsIFilePicker.h" #include "nsCOMArray.h" diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index b404cb04fe..23092082e1 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -113,6 +113,7 @@ GetMediaManagerLog() } #define LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg) +using dom::File; using dom::MediaStreamConstraints; using dom::MediaTrackConstraintSet; using dom::MediaTrackConstraints; @@ -264,53 +265,6 @@ private: nsRefPtr mManager; // get ref to this when creating the runnable }; -/** - * Invoke the "onSuccess" callback in content. The callback will take a - * DOMBlob in the case of {picture:true}, and a MediaStream in the case of - * {audio:true} or {video:true}. There is a constructor available for each - * form. Do this only on the main thread. - */ -class SuccessCallbackRunnable : public nsRunnable -{ -public: - SuccessCallbackRunnable( - nsCOMPtr& aOnSuccess, - nsCOMPtr& aOnFailure, - nsIDOMFile* aFile, uint64_t aWindowID) - : mFile(aFile) - , mWindowID(aWindowID) - , mManager(MediaManager::GetInstance()) - { - mOnSuccess.swap(aOnSuccess); - mOnFailure.swap(aOnFailure); - } - - NS_IMETHOD - Run() - { - // Only run if the window is still active. - NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - - nsCOMPtr onSuccess = mOnSuccess.forget(); - nsCOMPtr onFailure = mOnFailure.forget(); - - if (!(mManager->IsWindowStillActive(mWindowID))) { - return NS_OK; - } - // This is safe since we're on main-thread, and the windowlist can only - // be invalidated from the main-thread (see OnNavigation) - onSuccess->OnSuccess(mFile); - return NS_OK; - } - -private: - nsCOMPtr mOnSuccess; - nsCOMPtr mOnFailure; - nsCOMPtr mFile; - uint64_t mWindowID; - nsRefPtr mManager; // get ref to this when creating the runnable -}; - /** * Invoke the GetUserMediaDevices success callback. Wrapped in a runnable * so that it may be called on the main thread. The error callback is also @@ -1894,6 +1848,8 @@ MediaManager::GetUserMedia( false) || #if defined(XP_MACOSX) || defined(XP_WIN) ( + // Allow tab sharing for all platforms including XP and OSX 10.6 + (src != dom::MediaSourceEnum::Browser) && !Preferences::GetBool("media.getusermedia.screensharing.allow_on_old_platforms", false) && #if defined(XP_MACOSX) diff --git a/dom/media/fmp4/MP4Reader.cpp b/dom/media/fmp4/MP4Reader.cpp index 2be353f194..3eae2e057c 100644 --- a/dom/media/fmp4/MP4Reader.cpp +++ b/dom/media/fmp4/MP4Reader.cpp @@ -25,6 +25,7 @@ using mozilla::layers::Image; using mozilla::layers::LayerManager; +using mozilla::layers::ImageContainer; using mozilla::layers::LayersBackend; using mozilla::media::TimeUnit; @@ -60,6 +61,37 @@ TrackTypeToStr(TrackInfo::TrackType aTrack) } } +uint8_t sTestExtraData[40] = { 0x01, 0x64, 0x00, 0x0a, 0xff, 0xe1, 0x00, 0x17, 0x67, 0x64, 0x00, 0x0a, 0xac, 0xd9, 0x44, 0x26, 0x84, 0x00, 0x00, 0x03, + 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0xc8, 0x3c, 0x48, 0x96, 0x58, 0x01, 0x00, 0x06, 0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0 }; + +/* static */ bool +MP4Reader::IsVideoAccelerated(LayersBackend aBackend) +{ + VideoInfo config; + config.mMimeType = "video/avc"; + config.mId = 1; + config.mDuration = 40000; + config.mMediaTime = 0; + config.mDisplay = config.mImage = nsIntSize(64, 64); + config.mExtraData = new MediaByteBuffer(); + config.mExtraData->AppendElements(sTestExtraData, 40); + + PlatformDecoderModule::Init(); + + nsRefPtr platform = PlatformDecoderModule::Create(); + + nsRefPtr decoder = + platform->CreateDecoder(config, nullptr, nullptr, aBackend, nullptr); + nsresult rv = decoder->Init(); + NS_ENSURE_SUCCESS(rv, false); + + bool result = decoder->IsHardwareAccelerated(); + + decoder->Shutdown(); + + return result; +} + // MP4Demuxer wants to do various blocking reads, which cause deadlocks while // mDemuxerMonitor is held. This stuff should really be redesigned, but we don't // have time for that right now. So in order to get proper synchronization while diff --git a/dom/media/fmp4/MP4Reader.h b/dom/media/fmp4/MP4Reader.h index ae032bb947..ecc56eb443 100644 --- a/dom/media/fmp4/MP4Reader.h +++ b/dom/media/fmp4/MP4Reader.h @@ -82,6 +82,8 @@ public: virtual void DisableHardwareAcceleration() override; + static bool IsVideoAccelerated(layers::LayersBackend aBackend); + private: bool InitDemuxer(); diff --git a/dom/media/gmp/GMPLoader.cpp b/dom/media/gmp/GMPLoader.cpp index 63abbfbcd9..41a401bd68 100644 --- a/dom/media/gmp/GMPLoader.cpp +++ b/dom/media/gmp/GMPLoader.cpp @@ -80,7 +80,7 @@ public: virtual void Shutdown() override; -#if defined(XP_MACOSX) +#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX) virtual void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override; #endif @@ -275,7 +275,7 @@ GMPLoaderImpl::Shutdown() } } -#if defined(XP_MACOSX) +#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX) void GMPLoaderImpl::SetSandboxInfo(MacSandboxInfo* aSandboxInfo) { diff --git a/dom/media/gmp/GMPLoader.h b/dom/media/gmp/GMPLoader.h index 4a6afe286c..b14b198a80 100644 --- a/dom/media/gmp/GMPLoader.h +++ b/dom/media/gmp/GMPLoader.h @@ -10,7 +10,7 @@ #include #include "gmp-entrypoints.h" -#if defined(XP_MACOSX) +#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX) #include "mozilla/Sandbox.h" #endif @@ -21,7 +21,7 @@ class SandboxStarter { public: virtual ~SandboxStarter() {} virtual bool Start(const char* aLibPath) = 0; -#if defined(XP_MACOSX) +#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX) // On OS X we need to set Mac-specific sandbox info just before we start the // sandbox, which we don't yet know when the GMPLoader and SandboxStarter // objects are created. @@ -65,7 +65,7 @@ public: // plugin library. virtual void Shutdown() = 0; -#if defined(XP_MACOSX) +#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX) // On OS X we need to set Mac-specific sandbox info just before we start the // sandbox, which we don't yet know when the GMPLoader and SandboxStarter // objects are created. diff --git a/dom/media/platforms/PlatformDecoderModule.cpp b/dom/media/platforms/PlatformDecoderModule.cpp index 07752cb8df..268dd2fcb1 100644 --- a/dom/media/platforms/PlatformDecoderModule.cpp +++ b/dom/media/platforms/PlatformDecoderModule.cpp @@ -91,8 +91,7 @@ PlatformDecoderModule::Init() already_AddRefed PlatformDecoderModule::Create() { - // Note: This runs on the decode thread. - MOZ_ASSERT(!NS_IsMainThread()); + // Note: This (usually) runs on the decode thread. nsRefPtr m(CreatePDM()); diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp index 99436252a1..9253677694 100644 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp @@ -50,8 +50,6 @@ GonkVideoDecoderManager::GonkVideoDecoderManager( , mNativeWindow(nullptr) , mPendingVideoBuffersLock("GonkVideoDecoderManager::mPendingVideoBuffersLock") { - NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread."); - MOZ_ASSERT(mImageContainer); MOZ_COUNT_CTOR(GonkVideoDecoderManager); mMimeType = aConfig.mMimeType; mVideoWidth = aConfig.mDisplay.width; diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index 9ee77aaee8..cfddf4e02e 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -75,8 +75,6 @@ WMFVideoMFTManager::WMFVideoMFTManager( // mVideoStride, mVideoWidth, mVideoHeight, mUseHwAccel are initialized in // Init(). { - NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread."); - MOZ_ASSERT(mImageContainer); MOZ_COUNT_CTOR(WMFVideoMFTManager); // Need additional checks/params to check vp8/vp9 @@ -167,7 +165,12 @@ WMFVideoMFTManager::InitializeDXVA() // The DXVA manager must be created on the main thread. nsRefPtr event(new CreateDXVAManagerEvent(mLayersBackend)); - NS_DispatchToMainThread(event, NS_DISPATCH_SYNC); + + if (NS_IsMainThread()) { + event->Run(); + } else { + NS_DispatchToMainThread(event, NS_DISPATCH_SYNC); + } mDXVA2Manager = event->mDXVA2Manager; return mDXVA2Manager != nullptr; diff --git a/dom/media/webrtc/MediaEngineGonkVideoSource.h b/dom/media/webrtc/MediaEngineGonkVideoSource.h index 12d03724a0..51a6667002 100644 --- a/dom/media/webrtc/MediaEngineGonkVideoSource.h +++ b/dom/media/webrtc/MediaEngineGonkVideoSource.h @@ -112,7 +112,7 @@ protected: mozilla::ReentrantMonitor mCallbackMonitor; // Monitor for camera callback handling // This is only modified on MainThread (AllocImpl and DeallocImpl) nsRefPtr mCameraControl; - nsCOMPtr mLastCapture; + nsRefPtr mLastCapture; android::sp mCameraSource; diff --git a/dom/nfc/nsINfcContentHelper.idl b/dom/nfc/nsINfcContentHelper.idl index 6f5eb22e60..eb8fb92da0 100644 --- a/dom/nfc/nsINfcContentHelper.idl +++ b/dom/nfc/nsINfcContentHelper.idl @@ -207,7 +207,7 @@ interface nsINfcContentHelper : nsISupports * * @param blob * Raw data of the file to be sent. This object represents a file-like - * (nsIDOMFile) object of immutable, raw data. The blob data needs + * (DOM File) object of immutable, raw data. The blob data needs * to be 'object wrapped' before calling this interface. * * @param sessionToken diff --git a/dom/settings/SettingsDB.jsm b/dom/settings/SettingsDB.jsm index e30273352d..492bff72bf 100644 --- a/dom/settings/SettingsDB.jsm +++ b/dom/settings/SettingsDB.jsm @@ -8,7 +8,7 @@ let Cc = Components.classes; let Ci = Components.interfaces; let Cu = Components.utils; -Cu.importGlobalProperties(['Blob']); +Cu.importGlobalProperties(['Blob', 'File']); Cu.import("resource://gre/modules/Services.jsm"); this.EXPORTED_SYMBOLS = ["SettingsDB", "SETTINGSDB_NAME", "SETTINGSSTORE_NAME"]; @@ -209,7 +209,7 @@ SettingsDB.prototype = { return "primitive"; } else if (Array.isArray(aObject)) { return "array"; - } else if (aObject instanceof Ci.nsIDOMFile) { + } else if (aObject instanceof File) { return "file"; } else if (aObject instanceof Ci.nsIDOMBlob) { return "blob"; diff --git a/dom/settings/SettingsRequestManager.jsm b/dom/settings/SettingsRequestManager.jsm index 0edac13d65..92a015fe95 100644 --- a/dom/settings/SettingsRequestManager.jsm +++ b/dom/settings/SettingsRequestManager.jsm @@ -8,6 +8,8 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; +Cu.importGlobalProperties(['File']); + this.EXPORTED_SYMBOLS = ["SettingsRequestManager"]; Cu.import("resource://gre/modules/SettingsDB.jsm"); @@ -245,7 +247,7 @@ let SettingsRequestManager = { if (!aValue || !aValue.constructor) { return false; } - return (aValue.constructor.name == "Date") || (aValue instanceof Ci.nsIDOMFile) || + return (aValue.constructor.name == "Date") || (aValue instanceof File) || (aValue instanceof Ci.nsIDOMBlob); } // We need to serialize settings objects, otherwise they can change between diff --git a/dom/webidl/File.webidl b/dom/webidl/File.webidl index fe2e83d099..9a858e4118 100644 --- a/dom/webidl/File.webidl +++ b/dom/webidl/File.webidl @@ -45,6 +45,8 @@ partial interface File { readonly attribute Date lastModifiedDate; [GetterThrows, ChromeOnly] - readonly attribute DOMString mozFullPath; + readonly attribute DOMString path; + [GetterThrows, ChromeOnly] + readonly attribute DOMString mozFullPath; }; diff --git a/dom/webidl/HTMLInputElement.webidl b/dom/webidl/HTMLInputElement.webidl index 31c24fd61c..f80a4bec0a 100644 --- a/dom/webidl/HTMLInputElement.webidl +++ b/dom/webidl/HTMLInputElement.webidl @@ -148,7 +148,7 @@ partial interface HTMLInputElement { [GetterThrows] readonly attribute long textLength; - [ChromeOnly] + [Throws, ChromeOnly] sequence mozGetFileNameArray(); [ChromeOnly, Throws] diff --git a/dom/wifi/WifiCertService.cpp b/dom/wifi/WifiCertService.cpp index e08f965d3c..a868aa7ab1 100644 --- a/dom/wifi/WifiCertService.cpp +++ b/dom/wifi/WifiCertService.cpp @@ -17,7 +17,7 @@ #include "cert.h" #include "certdb.h" #include "CryptoTask.h" -#include "nsIDOMFile.h" +#include "nsIDOMBlob.h" #include "nsIWifiService.h" #include "nsNetUtil.h" #include "nsServiceManagerUtils.h" diff --git a/js/ipc/JavaScriptLogging.h b/js/ipc/JavaScriptLogging.h index 3196fdc2f7..187579a4b5 100644 --- a/js/ipc/JavaScriptLogging.h +++ b/js/ipc/JavaScriptLogging.h @@ -98,7 +98,8 @@ class Logging } void formatObject(bool incoming, bool local, ObjectId id, nsCString& out) { - const char* side, *objDesc; + const char* side; + const char* objDesc; void* ptr; if (local == incoming) { diff --git a/js/public/HashTable.h b/js/public/HashTable.h index 3e6fe81d2c..6a970c2eef 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -877,7 +877,8 @@ class HashTable : private AllocPolicy ++cur; } - Entry* cur, *end; + Entry* cur; + Entry* end; #ifdef JS_DEBUG const HashTable* table_; uint64_t mutationCount; @@ -1099,7 +1100,8 @@ class HashTable : private AllocPolicy static void destroyTable(AllocPolicy& alloc, Entry* oldTable, uint32_t capacity) { - for (Entry* e = oldTable, *end = e + capacity; e < end; ++e) + Entry* end = oldTable + capacity; + for (Entry* e = oldTable; e < end; ++e) e->destroyIfLive(); alloc.free_(oldTable); } @@ -1355,10 +1357,12 @@ class HashTable : private AllocPolicy table = newTable; // Copy only live entries, leaving removed ones behind. - for (Entry* src = oldTable, *end = src + oldCap; src < end; ++src) { + Entry* end = oldTable + oldCap; + for (Entry* src = oldTable; src < end; ++src) { if (src->isLive()) { HashNumber hn = src->getKeyHash(); - findFreeEntry(hn).setLive(hn, mozilla::Move(src->get())); + findFreeEntry(hn).setLive( + hn, mozilla::Move(const_cast(src->get()))); src->destroy(); } } @@ -1488,7 +1492,8 @@ class HashTable : private AllocPolicy memset(table, 0, sizeof(*table) * capacity()); } else { uint32_t tableCapacity = capacity(); - for (Entry* e = table, *end = table + tableCapacity; e < end; ++e) + Entry* end = table + tableCapacity; + for (Entry* e = table; e < end; ++e) e->clear(); } removedCount = 0; diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index 727ae9659c..0563ddbf53 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -795,7 +795,8 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase * example, Rooted and Rooted, which use the same * stack head pointer for different classes. */ - Rooted** stack, *prev; + Rooted** stack; + Rooted* prev; /* * |ptr| must be the last field in Rooted because the analysis treats all diff --git a/js/src/asmjs/AsmJSLink.cpp b/js/src/asmjs/AsmJSLink.cpp index 2a514e1ba2..7f307588d4 100644 --- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -843,7 +843,6 @@ HandleDynamicLinkFailure(JSContext* cx, const CallArgs& args, AsmJSModule& modul CompileOptions options(cx); options.setMutedErrors(module.scriptSource()->mutedErrors()) .setFile(module.scriptSource()->filename()) - .setCompileAndGo(false) .setNoScriptRval(false); // The exported function inherits an implicit strict context if the module diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 2f9264cce4..c65656c4dd 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -6379,7 +6379,8 @@ CheckConditional(FunctionCompiler& f, ParseNode* ternary, MDefinition** def, Typ if (!condType.isInt()) return f.failf(cond, "%s is not a subtype of int", condType.toChars()); - MBasicBlock* thenBlock = nullptr, *elseBlock = nullptr; + MBasicBlock* thenBlock = nullptr; + MBasicBlock* elseBlock = nullptr; if (!f.branchAndStartThen(condDef, &thenBlock, &elseBlock, thenExpr, elseExpr)) return false; @@ -6498,7 +6499,8 @@ CheckAddOrSub(FunctionCompiler& f, ParseNode* expr, MDefinition** def, Type* typ ParseNode* lhs = AddSubLeft(expr); ParseNode* rhs = AddSubRight(expr); - MDefinition* lhsDef, *rhsDef; + MDefinition* lhsDef; + MDefinition* rhsDef; Type lhsType, rhsType; unsigned lhsNumAddOrSub, rhsNumAddOrSub; @@ -6561,7 +6563,8 @@ CheckDivOrMod(FunctionCompiler& f, ParseNode* expr, MDefinition** def, Type* typ ParseNode* lhs = DivOrModLeft(expr); ParseNode* rhs = DivOrModRight(expr); - MDefinition* lhsDef, *rhsDef; + MDefinition* lhsDef; + MDefinition* rhsDef; Type lhsType, rhsType; if (!CheckExpr(f, lhs, &lhsDef, &lhsType)) return false; @@ -6616,7 +6619,8 @@ CheckComparison(FunctionCompiler& f, ParseNode* comp, MDefinition** def, Type* t ParseNode* lhs = ComparisonLeft(comp); ParseNode* rhs = ComparisonRight(comp); - MDefinition* lhsDef, *rhsDef; + MDefinition* lhsDef; + MDefinition* rhsDef; Type lhsType, rhsType; if (!CheckExpr(f, lhs, &lhsDef, &lhsType)) return false; @@ -6963,9 +6967,12 @@ CheckIfConditional(FunctionCompiler& f, ParseNode* conditional, ParseNode* thenS ParseNode* lhs = TernaryKid2(conditional); ParseNode* rhs = TernaryKid3(conditional); - MBasicBlock* maybeAndTest = nullptr, *maybeOrTest = nullptr; - MBasicBlock** ifTrueBlock = &maybeAndTest, **ifFalseBlock = &maybeOrTest; - ParseNode* ifTrueBlockNode = lhs, *ifFalseBlockNode = rhs; + MBasicBlock* maybeAndTest = nullptr; + MBasicBlock* maybeOrTest = nullptr; + MBasicBlock** ifTrueBlock = &maybeAndTest; + MBasicBlock** ifFalseBlock = &maybeOrTest; + ParseNode* ifTrueBlockNode = lhs; + ParseNode* ifFalseBlockNode = rhs; // Try to spot opportunities for short-circuiting in the AND subpart uint32_t andTestLiteral = 0; @@ -7087,7 +7094,8 @@ CheckIf(FunctionCompiler& f, ParseNode* ifStmt) ParseNode* thenStmt = TernaryKid2(ifStmt); ParseNode* elseStmt = TernaryKid3(ifStmt); - MBasicBlock* thenBlock = nullptr, *elseBlock = nullptr; + MBasicBlock* thenBlock = nullptr; + MBasicBlock* elseBlock = nullptr; ParseNode* elseOrJoinStmt = elseStmt ? elseStmt : nextStmt; if (!CheckIfCondition(f, cond, thenStmt, elseOrJoinStmt, &thenBlock, &elseBlock)) diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 4c3f947507..1efb8486b9 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -332,8 +332,8 @@ EvalKernel(JSContext* cx, const CallArgs& args, EvalType evalType, AbstractFrame CompileOptions options(cx); options.setFileAndLine(filename, 1) - .setCompileAndGo(true) .setHasPollutedScope(hasPollutedGlobalScope) + .setIsRunOnce(true) .setForEval(true) .setNoScriptRval(false) .setMutedErrors(mutedErrors) @@ -415,9 +415,9 @@ js::DirectEvalStringFromIon(JSContext* cx, CompileOptions options(cx); options.setFileAndLine(filename, 1) - .setCompileAndGo(true) .setHasPollutedScope(HasPollutedScopeChain(scopeobj) || callerScript->hasPollutedGlobalScope()) + .setIsRunOnce(true) .setForEval(true) .setNoScriptRval(false) .setMutedErrors(mutedErrors) diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 086e62de37..dca3f51083 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -137,9 +137,10 @@ class OrderedHashTable } ~OrderedHashTable() { - for (Range* r = ranges, *next; r; r = next) { - next = r->next; + for (Range* r = ranges; r; ) { + Range* next = r->next; r->onTableDestroyed(); + r = next; } alloc.free_(hashTable); freeData(data, dataLength); @@ -593,7 +594,8 @@ class OrderedHashTable void rehashInPlace() { for (uint32_t i = 0, N = hashBuckets(); i < N; i++) hashTable[i] = nullptr; - Data* wp = data, *end = data + dataLength; + Data* wp = data; + Data* end = data + dataLength; for (Data* rp = data; rp != end; rp++) { if (!Ops::isEmpty(Ops::getKey(rp->element))) { HashNumber h = prepareHash(Ops::getKey(rp->element)) >> hashShift; @@ -642,7 +644,8 @@ class OrderedHashTable } Data* wp = newData; - for (Data* p = data, *end = data + dataLength; p != end; p++) { + Data* end = data + dataLength; + for (Data* p = data; p != end; p++) { if (!Ops::isEmpty(Ops::getKey(p->element))) { HashNumber h = prepareHash(Ops::getKey(p->element)) >> newHashShift; new (wp) Data(Move(p->element), newHashTable[h]); diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 7b754de155..f9fa9733ea 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2253,7 +2253,6 @@ EvalReturningScope(JSContext* cx, unsigned argc, jsval* vp) JS::CompileOptions options(cx); options.setFileAndLine(filename.get(), lineno); options.setNoScriptRval(true); - options.setCompileAndGo(false); options.setHasPollutedScope(true); JS::SourceBufferHolder srcBuf(src, srclen, JS::SourceBufferHolder::NoOwnership); @@ -2325,7 +2324,6 @@ ShellCloneAndExecuteScript(JSContext* cx, unsigned argc, Value* vp) JS::CompileOptions options(cx); options.setFileAndLine(filename.get(), lineno); options.setNoScriptRval(true); - options.setCompileAndGo(false); JS::SourceBufferHolder srcBuf(src, srclen, JS::SourceBufferHolder::NoOwnership); RootedScript script(cx); diff --git a/js/src/ds/InlineMap.h b/js/src/ds/InlineMap.h index 42a39dd167..53f46c3d66 100644 --- a/js/src/ds/InlineMap.h +++ b/js/src/ds/InlineMap.h @@ -60,7 +60,8 @@ class InlineMap MOZ_ASSERT(map.initialized()); } - for (InlineElem* it = inl, *end = inl + inlNext; it != end; ++it) { + InlineElem* end = inl + inlNext; + for (InlineElem* it = inl; it != end; ++it) { if (it->key && !map.putNew(it->key, it->value)) return false; } @@ -211,7 +212,8 @@ class InlineMap if (usingMap()) return Ptr(map.lookup(key)); - for (InlineElem* it = inl, *end = inl + inlNext; it != end; ++it) { + InlineElem* end = inl + inlNext; + for (InlineElem* it = inl; it != end; ++it) { if (it->key == key) return Ptr(it); } @@ -224,7 +226,8 @@ class InlineMap if (usingMap()) return AddPtr(map.lookupForAdd(key)); - for (InlineElem* it = inl, *end = inl + inlNext; it != end; ++it) { + InlineElem* end = inl + inlNext; + for (InlineElem* it = inl; it != end; ++it) { if (it->key == key) return AddPtr(it, true); } diff --git a/js/src/ds/SplayTree.h b/js/src/ds/SplayTree.h index afd64aa9a4..337da0bef8 100644 --- a/js/src/ds/SplayTree.h +++ b/js/src/ds/SplayTree.h @@ -25,7 +25,9 @@ class SplayTree { struct Node { T item; - Node* left, *right, *parent; + Node* left; + Node* right; + Node* parent; explicit Node(const T& item) : item(item), left(nullptr), right(nullptr), parent(nullptr) @@ -33,7 +35,8 @@ class SplayTree }; LifoAlloc* alloc; - Node* root, *freeList; + Node* root; + Node* freeList; #ifdef DEBUG bool enableCheckCoherency; @@ -124,7 +127,8 @@ class SplayTree // Find another node which can be swapped in for the root: either the // rightmost child of the root's left, or the leftmost child of the // root's right. - Node* swap, *swapChild; + Node* swap; + Node* swapChild; if (root->left) { swap = root->left; while (swap->right) @@ -167,7 +171,8 @@ class SplayTree Node* lookup(const T& v) { MOZ_ASSERT(root); - Node* node = root, *parent; + Node* node = root; + Node* parent; do { parent = node; int c = C::compare(v, node->item); diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 078ffb725f..49895f17e2 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -133,10 +133,9 @@ static inline bool CanLazilyParse(ExclusiveContext* cx, const ReadOnlyCompileOptions& options) { return options.canLazilyParse && - options.compileAndGo && - !options.hasPollutedGlobalScope && - !cx->compartment()->options().discardSource() && - !options.sourceIsLazy; + !options.hasPollutedGlobalScope && + !cx->compartment()->options().discardSource() && + !options.sourceIsLazy; } static void @@ -221,7 +220,7 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco * The scripted callerFrame can only be given for compile-and-go scripts * and non-zero static level requires callerFrame. */ - MOZ_ASSERT_IF(evalCaller, options.compileAndGo); + MOZ_ASSERT_IF(evalCaller, options.isRunOnce); MOZ_ASSERT_IF(evalCaller, options.forEval); MOZ_ASSERT_IF(evalCaller && evalCaller->strict(), options.strictOption); MOZ_ASSERT_IF(staticLevel != 0, evalCaller); @@ -454,7 +453,6 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha options.setMutedErrors(lazy->mutedErrors()) .setFileAndLine(lazy->filename(), lazy->lineno()) .setColumn(lazy->column()) - .setCompileAndGo(true) .setNoScriptRval(false) .setSelfHostingMode(false); @@ -514,17 +512,19 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha if (!bce.init()) return false; - return EmitFunctionScript(cx, &bce, pn->pn_body); + return bce.emitFunctionScript(pn->pn_body); } // Compile a JS function body, which might appear as the value of an event // handler attribute in an HTML tag, or in a Function() constructor. static bool -CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyCompileOptions &options, - const AutoNameVector &formals, SourceBufferHolder &srcBuf, +CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions &options, + const AutoNameVector& formals, SourceBufferHolder& srcBuf, HandleObject enclosingStaticScope, GeneratorKind generatorKind) { - js::TraceLoggerThread *logger = js::TraceLoggerForMainThread(cx->runtime()); + MOZ_ASSERT(!options.isRunOnce); + + js::TraceLoggerThread* logger = js::TraceLoggerForMainThread(cx->runtime()); js::TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, options); js::AutoTraceLog scriptLogger(logger, event); js::AutoTraceLog typeLogger(logger, TraceLogger_ParserCompileFunction); @@ -639,7 +639,7 @@ CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyComp if (!funbce.init()) return false; - if (!EmitFunctionScript(cx, &funbce, fn->pn_body)) + if (!funbce.emitFunctionScript(fn->pn_body)) return false; } else { fun.set(fn->pn_funbox->function()); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 9125857685..89750d8c8f 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -85,10 +85,7 @@ struct frontend::StmtInfoBCE : public StmtInfoBase } }; - -namespace { - -struct LoopStmtInfo : public StmtInfoBCE +struct frontend::LoopStmtInfo : public StmtInfoBCE { int32_t stackDepth; // Stack depth when this loop was pushed. uint32_t loopDepth; // Loop depth. @@ -104,8 +101,6 @@ struct LoopStmtInfo : public StmtInfoBCE } }; -} // anonymous namespace - BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent, Parser* parser, SharedContext* sc, HandleScript script, Handle lazyScript, @@ -193,41 +188,27 @@ BytecodeEmitter::updateLocalsToFrameSlots() return true; } -ptrdiff_t -BytecodeEmitter::emitCheck(ptrdiff_t delta) +bool +BytecodeEmitter::emitCheck(ptrdiff_t delta, ptrdiff_t *offset) { - ptrdiff_t offset = code().length(); + *offset = code().length(); // Start it off moderately large to avoid repeated resizings early on. // ~98% of cases fit within 1024 bytes. if (code().capacity() == 0 && !code().reserve(1024)) - return -1; + return false; - jsbytecode dummy = 0; - if (!code().appendN(dummy, delta)) { + if (!code().growBy(delta)) { ReportOutOfMemory(cx); - return -1; + return false; } - return offset; + return true; } void BytecodeEmitter::updateDepth(ptrdiff_t target) { jsbytecode* pc = code(target); - JSOp op = (JSOp) *pc; - const JSCodeSpec* cs = &js_CodeSpec[op]; - - if (cs->format & JOF_TMPSLOT_MASK) { - /* - * An opcode may temporarily consume stack space during execution. - * Account for this in maxStackDepth separately from uses/defs here. - */ - uint32_t depth = (uint32_t) stackDepth + - ((cs->format & JOF_TMPSLOT_MASK) >> JOF_TMPSLOT_SHIFT); - if (depth > maxStackDepth) - maxStackDepth = depth; - } int nuses = StackUses(nullptr, pc); int ndefs = StackDefs(nullptr, pc); @@ -240,12 +221,12 @@ BytecodeEmitter::updateDepth(ptrdiff_t target) } #ifdef DEBUG -static bool -CheckStrictOrSloppy(BytecodeEmitter *bce, JSOp op) +bool +BytecodeEmitter::checkStrictOrSloppy(JSOp op) { - if (IsCheckStrictOp(op) && !bce->sc->strict()) + if (IsCheckStrictOp(op) && !sc->strict()) return false; - if (IsCheckSloppyOp(op) && bce->sc->strict()) + if (IsCheckSloppyOp(op) && sc->strict()) return false; return true; } @@ -254,9 +235,10 @@ CheckStrictOrSloppy(BytecodeEmitter *bce, JSOp op) bool BytecodeEmitter::emit1(JSOp op) { - MOZ_ASSERT(CheckStrictOrSloppy(this, op)); - ptrdiff_t offset = emitCheck(1); - if (offset < 0) + MOZ_ASSERT(checkStrictOrSloppy(op)); + + ptrdiff_t offset; + if (!emitCheck(1, &offset)) return false; jsbytecode* code = this->code(offset); @@ -268,9 +250,10 @@ BytecodeEmitter::emit1(JSOp op) bool BytecodeEmitter::emit2(JSOp op, jsbytecode op1) { - MOZ_ASSERT(CheckStrictOrSloppy(this, op)); - ptrdiff_t offset = emitCheck(2); - if (offset < 0) + MOZ_ASSERT(checkStrictOrSloppy(op)); + + ptrdiff_t offset; + if (!emitCheck(2, &offset)) return false; jsbytecode* code = this->code(offset); @@ -283,14 +266,14 @@ BytecodeEmitter::emit2(JSOp op, jsbytecode op1) bool BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2) { - MOZ_ASSERT(CheckStrictOrSloppy(this, op)); + MOZ_ASSERT(checkStrictOrSloppy(op)); /* These should filter through emitVarOp. */ MOZ_ASSERT(!IsArgOp(op)); MOZ_ASSERT(!IsLocalOp(op)); - ptrdiff_t offset = emitCheck(3); - if (offset < 0) + ptrdiff_t offset; + if (!emitCheck(3, &offset)) return false; jsbytecode* code = this->code(offset); @@ -301,16 +284,17 @@ BytecodeEmitter::emit3(JSOp op, jsbytecode op1, jsbytecode op2) return true; } -ptrdiff_t -BytecodeEmitter::emitN(JSOp op, size_t extra) +bool +BytecodeEmitter::emitN(JSOp op, size_t extra, ptrdiff_t *offset) { - MOZ_ASSERT(CheckStrictOrSloppy(this, op)); - ptrdiff_t length = 1 + (ptrdiff_t)extra; - ptrdiff_t offset = emitCheck(length); - if (offset < 0) - return -1; + MOZ_ASSERT(checkStrictOrSloppy(op)); + ptrdiff_t length = 1 + ptrdiff_t(extra); - jsbytecode *code = this->code(offset); + ptrdiff_t off; + if (!emitCheck(length, &off)) + return false; + + jsbytecode *code = this->code(off); code[0] = jsbytecode(op); /* The remaining |extra| bytes are set by the caller */ @@ -319,23 +303,27 @@ BytecodeEmitter::emitN(JSOp op, size_t extra) * operand yet to be stored in the extra bytes after op. */ if (js_CodeSpec[op].nuses >= 0) - updateDepth(offset); + updateDepth(off); - return offset; + if (offset) + *offset = off; + return true; } -ptrdiff_t -BytecodeEmitter::emitJump(JSOp op, ptrdiff_t off) +bool +BytecodeEmitter::emitJump(JSOp op, ptrdiff_t off, ptrdiff_t *jumpOffset) { - ptrdiff_t offset = emitCheck(5); - if (offset < 0) - return -1; + ptrdiff_t offset; + if (!emitCheck(5, &offset)) + return false; jsbytecode *code = this->code(offset); code[0] = jsbytecode(op); SET_JUMP_OFFSET(code, off); updateDepth(offset); - return offset; + if (jumpOffset) + *jumpOffset = offset; + return true; } bool @@ -358,8 +346,8 @@ BytecodeEmitter::emitDupAt(unsigned slot) return false; } - ptrdiff_t off = emitN(JSOP_DUPAT, 3); - if (off < 0) + ptrdiff_t off; + if (!emitN(JSOP_DUPAT, 3, &off)) return false; jsbytecode* pc = code(off); @@ -419,7 +407,7 @@ BytecodeEmitter::emitBackPatchOp(ptrdiff_t* lastp) ptrdiff_t delta = offset() - *lastp; *lastp = offset(); MOZ_ASSERT(delta > 0); - return emitJump(JSOP_BACKPATCH, delta) >= 0; + return emitJump(JSOP_BACKPATCH, delta); } static inline unsigned @@ -454,11 +442,11 @@ BytecodeEmitter::updateLineNumberNotes(uint32_t offset) current->currentLine = line; current->lastColumn = 0; if (delta >= LengthOfSetLine(line)) { - if (NewSrcNote2(cx, this, SRC_SETLINE, (ptrdiff_t)line) < 0) + if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(line))) return false; } else { do { - if (NewSrcNote(cx, this, SRC_NEWLINE) < 0) + if (!newSrcNote(SRC_NEWLINE)) return false; } while (--delta != 0); } @@ -483,7 +471,7 @@ BytecodeEmitter::updateSourceCoordNotes(uint32_t offset) // but it's better to fail soft here. if (!SN_REPRESENTABLE_COLSPAN(colspan)) return true; - if (NewSrcNote2(cx, this, SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan)) < 0) + if (!newSrcNote2(SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan))) return false; current->lastColumn = columnIndex; } @@ -558,16 +546,9 @@ BytecodeEmitter::flushPops(int* npops) return true; } -static bool -PopIterator(ExclusiveContext *cx, BytecodeEmitter *bce) -{ - return bce->emit1(JSOP_ENDITER); -} - namespace { class NonLocalExitScope { - ExclusiveContext* cx; BytecodeEmitter* bce; const uint32_t savedScopeIndex; const int savedDepth; @@ -576,9 +557,8 @@ class NonLocalExitScope { NonLocalExitScope(const NonLocalExitScope&) = delete; public: - explicit NonLocalExitScope(ExclusiveContext* cx_, BytecodeEmitter* bce_) - : cx(cx_), - bce(bce_), + explicit NonLocalExitScope(BytecodeEmitter* bce_) + : bce(bce_), savedScopeIndex(bce->blockScopeList.length()), savedDepth(bce->stackDepth), openScopeIndex(UINT32_MAX) { @@ -648,7 +628,7 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE* toStmt) /* The iterator and the current value are on the stack. */ npops += 1; FLUSH_POPS(); - if (!PopIterator(cx, bce)) + if (!bce->emit1(JSOP_ENDITER)) return false; break; @@ -689,22 +669,20 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE* toStmt) } // anonymous namespace -ptrdiff_t -BytecodeEmitter::emitGoto(StmtInfoBCE *toStmt, ptrdiff_t *lastp, SrcNoteType noteType) +bool +BytecodeEmitter::emitGoto(StmtInfoBCE* toStmt, ptrdiff_t* lastp, SrcNoteType noteType) { - NonLocalExitScope nle(cx, this); + NonLocalExitScope nle(this); if (!nle.prepareForNonLocalJump(toStmt)) - return -1; + return false; if (noteType != SRC_NULL) { - if (NewSrcNote(cx, this, noteType) < 0) - return -1; + if (!newSrcNote(noteType)) + return false; } - if (!emitBackPatchOp(lastp)) - return -1; - return *lastp; + return emitBackPatchOp(lastp); } void @@ -738,10 +716,10 @@ BytecodeEmitter::pushStatement(StmtInfoBCE *stmt, StmtType type, ptrdiff_t top) MOZ_ASSERT(!stmt->isLoop()); } -static void -PushLoopStatement(BytecodeEmitter *bce, LoopStmtInfo *stmt, StmtType type, ptrdiff_t top) +void +BytecodeEmitter::pushLoopStatement(LoopStmtInfo *stmt, StmtType type, ptrdiff_t top) { - bce->pushStatementInner(stmt, type, top); + pushStatementInner(stmt, type, top); MOZ_ASSERT(stmt->isLoop()); LoopStmtInfo *downLoop = nullptr; @@ -752,7 +730,7 @@ PushLoopStatement(BytecodeEmitter *bce, LoopStmtInfo *stmt, StmtType type, ptrdi } } - stmt->stackDepth = bce->stackDepth; + stmt->stackDepth = this->stackDepth; stmt->loopDepth = downLoop ? downLoop->loopDepth + 1 : 1; int loopSlots; @@ -772,25 +750,21 @@ PushLoopStatement(BytecodeEmitter *bce, LoopStmtInfo *stmt, StmtType type, ptrdi stmt->canIonOsr = stmt->stackDepth == loopSlots; } -/* - * Return the enclosing lexical scope, which is the innermost enclosing static - * block object or compiler created function. - */ -static JSObject* -EnclosingStaticScope(BytecodeEmitter* bce) +JSObject* +BytecodeEmitter::enclosingStaticScope() { - if (bce->staticScope) - return bce->staticScope; + if (staticScope) + return staticScope; - if (!bce->sc->isFunctionBox()) { - MOZ_ASSERT(!bce->parent); + if (!sc->isFunctionBox()) { + MOZ_ASSERT(!parent); // Top-level eval scripts have a placeholder static scope so that // StaticScopeIter may iterate through evals. - return bce->evalStaticScope; + return evalStaticScope; } - return bce->sc->asFunctionBox()->function(); + return sc->asFunctionBox()->function(); } #ifdef DEBUG @@ -804,10 +778,10 @@ AllLocalsAliased(StaticBlockObject& obj) } #endif -static bool -ComputeAliasedSlots(ExclusiveContext* cx, BytecodeEmitter* bce, Handle blockObj) +bool +BytecodeEmitter::computeAliasedSlots(Handle blockObj) { - uint32_t numAliased = bce->script->bindings.numAliasedBodyLevelLocals(); + uint32_t numAliased = script->bindings.numAliasedBodyLevelLocals(); for (unsigned i = 0; i < blockObj->numVariables(); i++) { Definition* dn = blockObj->definitionParseNode(i); @@ -817,7 +791,7 @@ ComputeAliasedSlots(ExclusiveContext* cx, BytecodeEmitter* bce, Handlepn_cookie.set(bce->parser->tokenStream, dn->pn_cookie.level(), + if (!dn->pn_cookie.set(parser->tokenStream, dn->pn_cookie.level(), numAliased + blockObj->blockIndexToLocalIndex(dn->frameSlot()))) { return false; @@ -831,31 +805,27 @@ ComputeAliasedSlots(ExclusiveContext* cx, BytecodeEmitter* bce, HandlesetAliased(i, bce->isAliasedName(dn)); + blockObj->setAliased(i, isAliasedName(dn)); } - MOZ_ASSERT_IF(bce->sc->allLocalsAliased(), AllLocalsAliased(*blockObj)); + MOZ_ASSERT_IF(sc->allLocalsAliased(), AllLocalsAliased(*blockObj)); return true; } -// In a function, block-scoped locals go after the vars, and form part of the -// fixed part of a stack frame. Outside a function, there are no fixed vars, -// but block-scoped locals still form part of the fixed part of a stack frame -// and are thus addressable via GETLOCAL and friends. -static void -ComputeLocalOffset(ExclusiveContext *cx, BytecodeEmitter *bce, Handle blockObj) +void +BytecodeEmitter::computeLocalOffset(Handle blockObj) { - unsigned nbodyfixed = bce->sc->isFunctionBox() - ? bce->script->bindings.numUnaliasedBodyLevelLocals() + unsigned nbodyfixed = sc->isFunctionBox() + ? script->bindings.numUnaliasedBodyLevelLocals() : 0; unsigned localOffset = nbodyfixed; - if (bce->staticScope) { - Rooted outer(cx, bce->staticScope); + if (staticScope) { + Rooted outer(cx, staticScope); for (; outer; outer = outer->enclosingNestedScope()) { if (outer->is()) { - StaticBlockObject& outerBlock = outer->as(); + StaticBlockObject &outerBlock = outer->as(); localOffset = outerBlock.localOffset() + outerBlock.numVariables(); break; } @@ -863,7 +833,7 @@ ComputeLocalOffset(ExclusiveContext *cx, BytecodeEmitter *bce, HandlenumVariables() - <= nbodyfixed + bce->script->bindings.numBlockScoped()); + <= nbodyfixed + script->bindings.numBlockScoped()); blockObj->setLocalOffset(localOffset); } @@ -905,40 +875,39 @@ ComputeLocalOffset(ExclusiveContext *cx, BytecodeEmitter *bce, Handle scopeObj(cx, &objbox->object->as()); - uint32_t scopeObjectIndex = bce->objectList.add(objbox); + uint32_t scopeObjectIndex = objectList.add(objbox); switch (stmtType) { case STMT_BLOCK: { Rooted blockObj(cx, &scopeObj->as()); - ComputeLocalOffset(cx, bce, blockObj); + computeLocalOffset(blockObj); - if (!ComputeAliasedSlots(cx, bce, blockObj)) + if (!computeAliasedSlots(blockObj)) return false; if (blockObj->needsClone()) { - if (!bce->emitInternedObjectOp(scopeObjectIndex, JSOP_PUSHBLOCKSCOPE)) + if (!emitInternedObjectOp(scopeObjectIndex, JSOP_PUSHBLOCKSCOPE)) return false; } break; } case STMT_WITH: MOZ_ASSERT(scopeObj->is()); - if (!bce->emitInternedObjectOp(scopeObjectIndex, JSOP_ENTERWITH)) + if (!emitInternedObjectOp(scopeObjectIndex, JSOP_ENTERWITH)) return false; break; default: @@ -946,18 +915,18 @@ EnterNestedScope(ExclusiveContext* cx, BytecodeEmitter* bce, StmtInfoBCE* stmt, } uint32_t parent = BlockScopeNote::NoBlockScopeIndex; - if (StmtInfoBCE *stmt = bce->topScopeStmt) { - for (; stmt->staticScope != bce->staticScope; stmt = stmt->down) {} + if (StmtInfoBCE *stmt = topScopeStmt) { + for (; stmt->staticScope != staticScope; stmt = stmt->down) {} parent = stmt->blockScopeIndex; } - stmt->blockScopeIndex = bce->blockScopeList.length(); - if (!bce->blockScopeList.append(scopeObjectIndex, bce->offset(), parent)) + stmt->blockScopeIndex = blockScopeList.length(); + if (!blockScopeList.append(scopeObjectIndex, offset(), parent)) return false; - bce->pushStatement(stmt, stmtType, bce->offset()); - scopeObj->initEnclosingNestedScope(EnclosingStaticScope(bce)); - FinishPushNestedScope(bce, stmt, *scopeObj); + pushStatement(stmt, stmtType, offset()); + scopeObj->initEnclosingNestedScope(enclosingStaticScope()); + FinishPushNestedScope(this, stmt, *scopeObj); MOZ_ASSERT(stmt->isNestedScope); stmt->isBlockScope = (stmtType == STMT_BLOCK); @@ -977,33 +946,33 @@ BytecodeEmitter::popStatement() FinishPopStatement(this); } -static bool -LeaveNestedScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt) +bool +BytecodeEmitter::leaveNestedScope(StmtInfoBCE *stmt) { - MOZ_ASSERT(stmt == bce->topStmt); + MOZ_ASSERT(stmt == topStmt); MOZ_ASSERT(stmt->isNestedScope); MOZ_ASSERT(stmt->isBlockScope == !(stmt->type == STMT_WITH)); uint32_t blockScopeIndex = stmt->blockScopeIndex; #ifdef DEBUG - MOZ_ASSERT(bce->blockScopeList.list[blockScopeIndex].length == 0); - uint32_t blockObjIndex = bce->blockScopeList.list[blockScopeIndex].index; - ObjectBox *blockObjBox = bce->objectList.find(blockObjIndex); + MOZ_ASSERT(blockScopeList.list[blockScopeIndex].length == 0); + uint32_t blockObjIndex = blockScopeList.list[blockScopeIndex].index; + ObjectBox *blockObjBox = objectList.find(blockObjIndex); NestedScopeObject *staticScope = &blockObjBox->object->as(); MOZ_ASSERT(stmt->staticScope == staticScope); - MOZ_ASSERT(staticScope == bce->staticScope); + MOZ_ASSERT(staticScope == this->staticScope); MOZ_ASSERT_IF(!stmt->isBlockScope, staticScope->is()); #endif - bce->popStatement(); + popStatement(); - if (!bce->emit1(stmt->isBlockScope ? JSOP_DEBUGLEAVEBLOCK : JSOP_LEAVEWITH)) + if (!emit1(stmt->isBlockScope ? JSOP_DEBUGLEAVEBLOCK : JSOP_LEAVEWITH)) return false; - bce->blockScopeList.recordEnd(blockScopeIndex, bce->offset()); + blockScopeList.recordEnd(blockScopeIndex, offset()); if (stmt->isBlockScope && stmt->staticScope->as().needsClone()) { - if (!bce->emit1(JSOP_POPBLOCKSCOPE)) + if (!emit1(JSOP_POPBLOCKSCOPE)) return false; } @@ -1013,13 +982,13 @@ LeaveNestedScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmt) bool BytecodeEmitter::emitIndex32(JSOp op, uint32_t index) { - MOZ_ASSERT(CheckStrictOrSloppy(this, op)); + MOZ_ASSERT(checkStrictOrSloppy(op)); const size_t len = 1 + UINT32_INDEX_LEN; MOZ_ASSERT(len == size_t(js_CodeSpec[op].length)); - ptrdiff_t offset = emitCheck(len); - if (offset < 0) + ptrdiff_t offset; + if (!emitCheck(len, &offset)) return false; jsbytecode* code = this->code(offset); @@ -1033,13 +1002,13 @@ BytecodeEmitter::emitIndex32(JSOp op, uint32_t index) bool BytecodeEmitter::emitIndexOp(JSOp op, uint32_t index) { - MOZ_ASSERT(CheckStrictOrSloppy(this, op)); + MOZ_ASSERT(checkStrictOrSloppy(op)); const size_t len = js_CodeSpec[op].length; MOZ_ASSERT(len >= 1 + UINT32_INDEX_LEN); - ptrdiff_t offset = emitCheck(len); - if (offset < 0) + ptrdiff_t offset; + if (!emitCheck(len, &offset)) return false; jsbytecode* code = this->code(offset); @@ -1112,8 +1081,8 @@ BytecodeEmitter::emitLocalOp(JSOp op, uint32_t slot) MOZ_ASSERT(JOF_OPTYPE(op) != JOF_SCOPECOORD); MOZ_ASSERT(IsLocalOp(op)); - ptrdiff_t off = emitN(op, LOCALNO_LEN); - if (off < 0) + ptrdiff_t off; + if (!emitN(op, LOCALNO_LEN, &off)) return false; SET_LOCALNO(code(off), slot); @@ -1142,8 +1111,8 @@ BytecodeEmitter::emitUnaliasedVarOp(JSOp op, uint32_t slot, MaybeCheckLexical ch } MOZ_ASSERT(IsArgOp(op)); - ptrdiff_t off = emitN(op, ARGNO_LEN); - if (off < 0) + ptrdiff_t off; + if (!emitN(op, ARGNO_LEN, &off)) return false; SET_ARGNO(code(off), slot); @@ -1158,8 +1127,8 @@ BytecodeEmitter::emitScopeCoordOp(JSOp op, ScopeCoordinate sc) unsigned n = SCOPECOORD_HOPS_LEN + SCOPECOORD_SLOT_LEN; MOZ_ASSERT(int(n) + 1 /* op */ == js_CodeSpec[op].length); - ptrdiff_t off = emitN(op, n); - if (off < 0) + ptrdiff_t off; + if (!emitN(op, n, &off)) return false; jsbytecode* pc = code(off); @@ -1183,13 +1152,11 @@ BytecodeEmitter::emitAliasedVarOp(JSOp op, ScopeCoordinate sc, MaybeCheckLexical return emitScopeCoordOp(op, sc); } -// Compute the number of nested scope objects that will actually be on the scope -// chain at runtime, given the BCE's current staticScope. -static unsigned -DynamicNestedScopeDepth(BytecodeEmitter *bce) +unsigned +BytecodeEmitter::dynamicNestedScopeDepth() { unsigned depth = 0; - for (NestedScopeObject *b = bce->staticScope; b; b = b->enclosingNestedScope()) { + for (NestedScopeObject *b = staticScope; b; b = b->enclosingNestedScope()) { if (!b->is() || b->as().needsClone()) ++depth; } @@ -1197,17 +1164,17 @@ DynamicNestedScopeDepth(BytecodeEmitter *bce) return depth; } -static bool -LookupAliasedName(BytecodeEmitter *bce, HandleScript script, PropertyName *name, uint32_t *pslot, - ParseNode *pn = nullptr) +bool +BytecodeEmitter::lookupAliasedName(HandleScript script, PropertyName *name, uint32_t *pslot, + ParseNode *pn) { LazyScript::FreeVariable *freeVariables = nullptr; uint32_t lexicalBegin = 0; uint32_t numFreeVariables = 0; - if (bce->emitterMode == BytecodeEmitter::LazyFunction) { - freeVariables = bce->lazyScript->freeVariables(); + if (emitterMode == BytecodeEmitter::LazyFunction) { + freeVariables = lazyScript->freeVariables(); lexicalBegin = script->bindings.lexicalBegin(); - numFreeVariables = bce->lazyScript->numFreeVariables(); + numFreeVariables = lazyScript->numFreeVariables(); } /* @@ -1246,27 +1213,22 @@ LookupAliasedName(BytecodeEmitter *bce, HandleScript script, PropertyName *name, return false; } -static bool -LookupAliasedNameSlot(BytecodeEmitter *bce, HandleScript script, PropertyName *name, - ScopeCoordinate *sc) +bool +BytecodeEmitter::lookupAliasedNameSlot(PropertyName *name, ScopeCoordinate *sc) { uint32_t slot; - if (!LookupAliasedName(bce, script, name, &slot)) + if (!lookupAliasedName(script, name, &slot)) return false; sc->setSlot(slot); return true; } -/* - * Use this function instead of assigning directly to 'hops' to guard for - * uint8_t overflows. - */ -static bool -AssignHops(BytecodeEmitter *bce, ParseNode *pn, unsigned src, ScopeCoordinate *dst) +bool +BytecodeEmitter::assignHops(ParseNode *pn, unsigned src, ScopeCoordinate *dst) { if (src > UINT8_MAX) { - bce->reportError(pn, JSMSG_TOO_DEEP, js_function_str); + reportError(pn, JSMSG_TOO_DEEP, js_function_str); return false; } @@ -1301,7 +1263,7 @@ BytecodeEmitter::emitAliasedVarOp(JSOp op, ParseNode *pn) * enclosing function scope of the definition being accessed. */ for (unsigned i = pn->pn_cookie.level(); i; i--) { - skippedScopes += DynamicNestedScopeDepth(bceOfDef); + skippedScopes += bceOfDef->dynamicNestedScopeDepth(); FunctionBox *funbox = bceOfDef->sc->asFunctionBox(); if (funbox->isHeavyweight()) { skippedScopes++; @@ -1318,22 +1280,22 @@ BytecodeEmitter::emitAliasedVarOp(JSOp op, ParseNode *pn) /* * The final part of the skippedScopes computation depends on the type of * variable. An arg or local variable is at the outer scope of a function - * and so includes the full DynamicNestedScopeDepth. A let/catch-binding + * and so includes the full dynamicNestedScopeDepth. A let/catch-binding * requires a search of the block chain to see how many (dynamic) block * objects to skip. */ ScopeCoordinate sc; if (IsArgOp(pn->getOp())) { - if (!AssignHops(this, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc)) + if (!assignHops(pn, skippedScopes + bceOfDef->dynamicNestedScopeDepth(), &sc)) return false; - JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef, bceOfDef->script, pn->name(), &sc)); + JS_ALWAYS_TRUE(bceOfDef->lookupAliasedNameSlot(pn->name(), &sc)); } else { MOZ_ASSERT(IsLocalOp(pn->getOp()) || pn->isKind(PNK_FUNCTION)); uint32_t local = pn->pn_cookie.slot(); if (local < bceOfDef->script->bindings.numBodyLevelLocals()) { - if (!AssignHops(this, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc)) + if (!assignHops(pn, skippedScopes + bceOfDef->dynamicNestedScopeDepth(), &sc)) return false; - JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef, bceOfDef->script, pn->name(), &sc)); + JS_ALWAYS_TRUE(bceOfDef->lookupAliasedNameSlot(pn->name(), &sc)); } else { MOZ_ASSERT_IF(this->sc->isFunctionBox(), local <= bceOfDef->script->bindings.numLocals()); MOZ_ASSERT(bceOfDef->staticScope->is()); @@ -1344,7 +1306,7 @@ BytecodeEmitter::emitAliasedVarOp(JSOp op, ParseNode *pn) skippedScopes++; b = &b->enclosingNestedScope()->as(); } - if (!AssignHops(this, pn, skippedScopes, &sc)) + if (!assignHops(pn, skippedScopes, &sc)) return false; sc.setSlot(b->localIndexToSlot(local)); } @@ -1485,16 +1447,16 @@ BytecodeEmitter::isAliasedName(ParseNode* pn) return false; } -static JSOp -StrictifySetNameOp(JSOp op, BytecodeEmitter* bce) +JSOp +BytecodeEmitter::strictifySetNameOp(JSOp op) { switch (op) { case JSOP_SETNAME: - if (bce->sc->strict()) + if (sc->strict()) op = JSOP_STRICTSETNAME; break; case JSOP_SETGNAME: - if (bce->sc->strict()) + if (sc->strict()) op = JSOP_STRICTSETGNAME; break; default:; @@ -1502,10 +1464,10 @@ StrictifySetNameOp(JSOp op, BytecodeEmitter* bce) return op; } -static void -StrictifySetNameNode(ParseNode* pn, BytecodeEmitter* bce) +void +BytecodeEmitter::strictifySetNameNode(ParseNode* pn) { - pn->setOp(StrictifySetNameOp(pn->getOp(), bce)); + pn->setOp(strictifySetNameOp(pn->getOp())); } /* @@ -1513,8 +1475,8 @@ StrictifySetNameNode(ParseNode* pn, BytecodeEmitter* bce) * INTRINSIC or ALIASEDVAR op, which optimize accesses on that name. * Return true if a conversion was made. */ -static bool -TryConvertFreeName(BytecodeEmitter* bce, ParseNode* pn) +bool +BytecodeEmitter::tryConvertFreeName(ParseNode* pn) { /* * In self-hosting mode, JSOP_*NAME is unconditionally converted to @@ -1522,7 +1484,7 @@ TryConvertFreeName(BytecodeEmitter* bce, ParseNode* pn) * intrinsics holder in the global object, into which any missing values are * cloned lazily upon first access. */ - if (bce->emitterMode == BytecodeEmitter::SelfHosting) { + if (emitterMode == BytecodeEmitter::SelfHosting) { JSOp op; switch (pn->getOp()) { case JSOP_GETNAME: op = JSOP_GETINTRINSIC; break; @@ -1539,16 +1501,16 @@ TryConvertFreeName(BytecodeEmitter* bce, ParseNode* pn) * longer exist and only the function's scope chain is available for * resolving upvar accesses within the inner function. */ - if (bce->emitterMode == BytecodeEmitter::LazyFunction) { + if (emitterMode == BytecodeEmitter::LazyFunction) { // The only statements within a lazy function which can push lexical // scopes are try/catch blocks. Use generic ops in this case. - for (StmtInfoBCE* stmt = bce->topStmt; stmt; stmt = stmt->down) { + for (StmtInfoBCE* stmt = topStmt; stmt; stmt = stmt->down) { if (stmt->type == STMT_CATCH) return true; } size_t hops = 0; - FunctionBox* funbox = bce->sc->asFunctionBox(); + FunctionBox* funbox = sc->asFunctionBox(); if (funbox->hasExtensibleScope()) return false; if (funbox->function()->isNamedLambda() && funbox->function()->atom() == pn->pn_atom) @@ -1558,10 +1520,10 @@ TryConvertFreeName(BytecodeEmitter* bce, ParseNode* pn) if (funbox->function()->isNamedLambda()) hops++; } - if (bce->script->directlyInsideEval()) + if (script->directlyInsideEval()) return false; - RootedObject outerScope(bce->cx, bce->script->enclosingStaticScope()); - for (StaticScopeIter ssi(bce->cx, outerScope); !ssi.done(); ssi++) { + RootedObject outerScope(cx, script->enclosingStaticScope()); + for (StaticScopeIter ssi(cx, outerScope); !ssi.done(); ssi++) { if (ssi.type() != StaticScopeIter::Function) { if (ssi.type() == StaticScopeIter::Block) { // Use generic ops if a catch block is encountered. @@ -1571,12 +1533,12 @@ TryConvertFreeName(BytecodeEmitter* bce, ParseNode* pn) hops++; continue; } - RootedScript script(bce->cx, ssi.funScript()); + RootedScript script(cx, ssi.funScript()); if (script->functionNonDelazifying()->atom() == pn->pn_atom) return false; if (ssi.hasDynamicScopeObject()) { uint32_t slot; - if (LookupAliasedName(bce, script, pn->pn_atom->asPropertyName(), &slot, pn)) { + if (lookupAliasedName(script, pn->pn_atom->asPropertyName(), &slot, pn)) { JSOp op; switch (pn->getOp()) { case JSOP_GETNAME: op = JSOP_GETALIASEDVAR; break; @@ -1585,7 +1547,7 @@ TryConvertFreeName(BytecodeEmitter* bce, ParseNode* pn) } pn->setOp(op); - JS_ALWAYS_TRUE(pn->pn_cookie.set(bce->parser->tokenStream, hops, slot)); + JS_ALWAYS_TRUE(pn->pn_cookie.set(parser->tokenStream, hops, slot)); return true; } hops++; @@ -1603,23 +1565,23 @@ TryConvertFreeName(BytecodeEmitter* bce, ParseNode* pn) // Unbound names aren't recognizable global-property references if the // script is inside a non-global eval call. - if (bce->insideNonGlobalEval) + if (insideNonGlobalEval) return false; // Skip trying to use GNAME ops if we know our script has a polluted // global scope, since they'll just get treated as NAME ops anyway. - if (bce->script->hasPollutedGlobalScope()) + if (script->hasPollutedGlobalScope()) return false; // Deoptimized names also aren't necessarily globals. if (pn->isDeoptimized()) return false; - if (bce->sc->isFunctionBox()) { + if (sc->isFunctionBox()) { // Unbound names in function code may not be globals if new locals can // be added to this function (or an enclosing one) to alias a global // reference. - FunctionBox* funbox = bce->sc->asFunctionBox(); + FunctionBox* funbox = sc->asFunctionBox(); if (funbox->mightAliasLocals()) return false; } @@ -1641,13 +1603,13 @@ TryConvertFreeName(BytecodeEmitter* bce, ParseNode* pn) // Though actually, we don't even need an inner eval. We could just as well // have a lambda inside that outer strict mode eval and it would run into // the same issue. - if (bce->insideEval && bce->sc->strict()) + if (insideEval && sc->strict()) return false; JSOp op; switch (pn->getOp()) { case JSOP_GETNAME: op = JSOP_GETGNAME; break; - case JSOP_SETNAME: op = StrictifySetNameOp(JSOP_SETGNAME, bce); break; + case JSOP_SETNAME: op = strictifySetNameOp(JSOP_SETGNAME); break; case JSOP_SETCONST: // Not supported. return false; @@ -1659,11 +1621,11 @@ TryConvertFreeName(BytecodeEmitter* bce, ParseNode* pn) /* * BindNameToSlotHelper attempts to optimize name gets and sets to stack slot - * loads and stores, given the compile-time information in bce and a PNK_NAME + * loads and stores, given the compile-time information in |this| and a PNK_NAME * node pn. It returns false on error, true on success. * * The caller can test pn->pn_cookie.isFree() to tell whether optimization - * occurred, in which case BindNameToSlotHelper also updated pn->pn_op. If + * occurred, in which case bindNameToSlotHelper also updated pn->pn_op. If * pn->pn_cookie.isFree() is still true on return, pn->pn_op still may have * been optimized, e.g., from JSOP_GETNAME to JSOP_CALLEE. Whether or not * pn->pn_op was modified, if this function finds an argument or local variable @@ -1674,8 +1636,8 @@ TryConvertFreeName(BytecodeEmitter* bce, ParseNode* pn) * to update the special cases in EmitFor (for-in) and emitAssignment (= and * op=, e.g. +=). */ -static bool -BindNameToSlotHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) +bool +BytecodeEmitter::bindNameToSlotHelper(ParseNode* pn) { MOZ_ASSERT(pn->isKind(PNK_NAME)); @@ -1714,27 +1676,27 @@ BindNameToSlotHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) JSAutoByteString name; if (!AtomToPrintableString(cx, pn->pn_atom, &name)) return false; - bce->reportError(pn, JSMSG_BAD_CONST_ASSIGN, name.ptr()); + reportError(pn, JSMSG_BAD_CONST_ASSIGN, name.ptr()); return false; } } if (dn->pn_cookie.isFree()) { - if (HandleScript caller = bce->evalCaller) { - MOZ_ASSERT(bce->script->compileAndGo()); + if (evalCaller) { + MOZ_ASSERT(script->treatAsRunOnce() || sc->isFunctionBox()); /* * Don't generate upvars on the left side of a for loop. See * bug 470758. */ - if (bce->emittingForInit) + if (emittingForInit) return true; /* * If this is an eval in the global scope, then unbound variables * must be globals, so try to use GNAME ops. */ - if (!caller->functionOrCallerFunction() && TryConvertFreeName(bce, pn)) { + if (!evalCaller->functionOrCallerFunction() && tryConvertFreeName(pn)) { pn->pn_dflags |= PND_BOUND; return true; } @@ -1747,7 +1709,7 @@ BindNameToSlotHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) } /* Optimize accesses to undeclared globals. */ - if (!TryConvertFreeName(bce, pn)) + if (!tryConvertFreeName(pn)) return true; pn->pn_dflags |= PND_BOUND; @@ -1815,15 +1777,15 @@ BindNameToSlotHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) * Currently, the ALIASEDVAR ops do not support accessing the * callee of a DeclEnvObject, so use NAME. */ - if (dn->pn_cookie.level() != bce->script->staticLevel()) + if (dn->pn_cookie.level() != script->staticLevel()) return true; - DebugOnly fun = bce->sc->asFunctionBox()->function(); + DebugOnly fun = sc->asFunctionBox()->function(); MOZ_ASSERT(fun->isLambda()); MOZ_ASSERT(pn->pn_atom == fun->atom()); /* - * Leave pn->isOp(JSOP_GETNAME) if bce->fun is heavyweight to + * Leave pn->isOp(JSOP_GETNAME) if this->fun is heavyweight to * address two cases: a new binding introduced by eval, and * assignment to the name in strict mode. * @@ -1846,7 +1808,7 @@ BindNameToSlotHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) * heavyweight, ensuring that the function name is represented in * the scope chain so that assignment will throw a TypeError. */ - if (!bce->sc->asFunctionBox()->isHeavyweight()) { + if (!sc->asFunctionBox()->isHeavyweight()) { op = JSOP_CALLEE; pn->pn_dflags |= PND_CONST; } @@ -1868,7 +1830,7 @@ BindNameToSlotHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) * the definition is the number of function scopes between the current * scope and dn's scope. */ - unsigned skip = bce->script->staticLevel() - dn->pn_cookie.level(); + unsigned skip = script->staticLevel() - dn->pn_cookie.level(); MOZ_ASSERT_IF(skip, dn->isClosed()); /* @@ -1881,7 +1843,7 @@ BindNameToSlotHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) * associated TypeSet. */ if (skip) { - BytecodeEmitter *bceSkipped = bce; + BytecodeEmitter *bceSkipped = this; for (unsigned i = 0; i < skip; i++) bceSkipped = bceSkipped->parent; if (!bceSkipped->sc->isFunctionBox()) @@ -1890,7 +1852,7 @@ BindNameToSlotHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) MOZ_ASSERT(!pn->isOp(op)); pn->setOp(op); - if (!pn->pn_cookie.set(bce->parser->tokenStream, skip, dn->pn_cookie.slot())) + if (!pn->pn_cookie.set(parser->tokenStream, skip, dn->pn_cookie.slot())) return false; pn->pn_dflags |= PND_BOUND; @@ -1905,10 +1867,10 @@ BindNameToSlotHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) bool BytecodeEmitter::bindNameToSlot(ParseNode* pn) { - if (!BindNameToSlotHelper(cx, this, pn)) + if (!bindNameToSlotHelper(pn)) return false; - StrictifySetNameNode(pn, this); + strictifySetNameNode(pn); if (emitterMode == BytecodeEmitter::SelfHosting && !pn->isBound()) { reportError(pn, JSMSG_SELFHOSTED_UNBOUND_NAME); @@ -1918,20 +1880,8 @@ BytecodeEmitter::bindNameToSlot(ParseNode* pn) return true; } -/* - * If pn contains a useful expression, return true with *answer set to true. - * If pn contains a useless expression, return true with *answer set to false. - * Return false on error. - * - * The caller should initialize *answer to false and invoke this function on - * an expression statement or similar subtree to decide whether the tree could - * produce code that has any side effects. For an expression statement, we - * define useless code as code with no side effects, because the main effect, - * the value left on the stack after the code executes, will be discarded by a - * pop bytecode. - */ -static bool -CheckSideEffects(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn, bool* answer) +bool +BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) { if (!pn || *answer) return true; @@ -1957,7 +1907,7 @@ CheckSideEffects(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn, bool */ bool ok = true; for (ParseNode* pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) - ok &= CheckSideEffects(cx, bce, pn2, answer); + ok &= checkSideEffects(pn2, answer); return ok; } @@ -1985,9 +1935,9 @@ CheckSideEffects(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn, bool return true; case PN_TERNARY: - return CheckSideEffects(cx, bce, pn->pn_kid1, answer) && - CheckSideEffects(cx, bce, pn->pn_kid2, answer) && - CheckSideEffects(cx, bce, pn->pn_kid3, answer); + return checkSideEffects(pn->pn_kid1, answer) && + checkSideEffects(pn->pn_kid2, answer) && + checkSideEffects(pn->pn_kid3, answer); case PN_BINARY: case PN_BINARY_OBJ: @@ -2005,9 +1955,9 @@ CheckSideEffects(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn, bool if (!pn2->isKind(PNK_NAME)) { *answer = true; } else { - if (!bce->bindNameToSlot(pn2)) + if (!bindNameToSlot(pn2)) return false; - if (!CheckSideEffects(cx, bce, pn->pn_right, answer)) + if (!checkSideEffects(pn->pn_right, answer)) return false; if (!*answer && (!pn->isOp(JSOP_NOP) || !pn2->isConst())) *answer = true; @@ -2034,7 +1984,7 @@ CheckSideEffects(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn, bool ParseNode* pn2 = pn->pn_kid; switch (pn2->getKind()) { case PNK_NAME: - if (!bce->bindNameToSlot(pn2)) + if (!bindNameToSlot(pn2)) return false; if (pn2->isConst()) { MOZ_ASSERT(*answer == false); @@ -2048,7 +1998,7 @@ CheckSideEffects(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn, bool *answer = true; return true; default: - return CheckSideEffects(cx, bce, pn2, answer); + return checkSideEffects(pn2, answer); } MOZ_CRASH("We have a returning default case"); } @@ -2059,7 +2009,7 @@ CheckSideEffects(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn, bool case PNK_BITNOT: if (pn->isOp(JSOP_NOT)) { /* ! does not convert its operand via toString or valueOf. */ - return CheckSideEffects(cx, bce, pn->pn_kid, answer); + return checkSideEffects(pn->pn_kid, answer); } /* FALL THROUGH */ @@ -2082,7 +2032,7 @@ CheckSideEffects(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn, bool * defaulted to JSOP_NOP). */ if (pn->isKind(PNK_NAME) && !pn->isOp(JSOP_NOP)) { - if (!bce->bindNameToSlot(pn)) + if (!bindNameToSlot(pn)) return false; if (!pn->isOp(JSOP_CALLEE) && pn->pn_cookie.isFree()) { /* @@ -2103,7 +2053,7 @@ CheckSideEffects(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn, bool /* Dotted property references in general can call getters. */ *answer = true; } - return CheckSideEffects(cx, bce, pn->maybeExpr(), answer); + return checkSideEffects(pn->maybeExpr(), answer); case PN_NULLARY: if (pn->isKind(PNK_DEBUGGER)) @@ -2126,12 +2076,18 @@ BytecodeEmitter::isInLoop() bool BytecodeEmitter::checkSingletonContext() { - if (!script->compileAndGo() || sc->isFunctionBox() || isInLoop()) + if (!script->treatAsRunOnce() || sc->isFunctionBox() || isInLoop()) return false; hasSingletons = true; return true; } +bool +BytecodeEmitter::checkRunOnceContext() +{ + return checkSingletonContext() || (!isInLoop() && isRunOnceLambda()); +} + bool BytecodeEmitter::needsImplicitThis() { @@ -2208,8 +2164,8 @@ bool BytecodeEmitter::emitNewInit(JSProtoKey key) { const size_t len = 1 + UINT32_INDEX_LEN; - ptrdiff_t offset = emitCheck(len); - if (offset < 0) + ptrdiff_t offset; + if (!emitCheck(len, &offset)) return false; jsbytecode* code = this->code(offset); @@ -2223,14 +2179,13 @@ BytecodeEmitter::emitNewInit(JSProtoKey key) return true; } -static bool -IteratorResultShape(ExclusiveContext* cx, BytecodeEmitter* bce, unsigned* shape) +bool +BytecodeEmitter::iteratorResultShape(unsigned* shape) { - MOZ_ASSERT(bce->script->compileAndGo()); - - RootedPlainObject obj(cx); - gc::AllocKind kind = GuessObjectGCKind(2); - obj = NewBuiltinClassInstance(cx, kind); + // No need to do any guessing for the object kind, since we know exactly how + // many properties we plan to have. + gc::AllocKind kind = gc::GetGCObjectKind(2); + RootedPlainObject obj(cx, NewBuiltinClassInstance(cx, kind, TenuredObject)); if (!obj) return false; @@ -2247,11 +2202,11 @@ IteratorResultShape(ExclusiveContext* cx, BytecodeEmitter* bce, unsigned* shape) return false; } - ObjectBox* objbox = bce->parser->newObjectBox(obj); + ObjectBox* objbox = parser->newObjectBox(obj); if (!objbox) return false; - *shape = bce->objectList.add(objbox); + *shape = objectList.add(objbox); return true; } @@ -2259,14 +2214,10 @@ IteratorResultShape(ExclusiveContext* cx, BytecodeEmitter* bce, unsigned* shape) bool BytecodeEmitter::emitPrepareIteratorResult() { - if (script->compileAndGo()) { - unsigned shape; - if (!IteratorResultShape(cx, this, &shape)) - return false; - return emitIndex32(JSOP_NEWOBJECT, shape); - } - - return emitNewInit(JSProto_Object); + unsigned shape; + if (!iteratorResultShape(&shape)) + return false; + return emitIndex32(JSOP_NEWOBJECT, shape); } bool @@ -2337,8 +2288,9 @@ BytecodeEmitter::emitPropLHS(ParseNode *pn, JSOp op) * bottom up (reversing again as we go), to avoid excessive recursion. */ if (pn2->isKind(PNK_DOT)) { - ParseNode *pndot = pn2; - ParseNode *pnup = nullptr, *pndown; + ParseNode* pndot = pn2; + ParseNode* pnup = nullptr; + ParseNode* pndown; ptrdiff_t top = offset(); for (;;) { /* Reverse pndot->pn_expr to point up, not down. */ @@ -2462,7 +2414,7 @@ BytecodeEmitter::emitNameIncDec(ParseNode *pn) return false; } - JSOp setOp = StrictifySetNameOp(global ? JSOP_SETGNAME : JSOP_SETNAME, this); + JSOp setOp = strictifySetNameOp(global ? JSOP_SETGNAME : JSOP_SETNAME); if (!emitAtomOp(pn->pn_kid, setOp)) // N? N+1 return false; if (post && !emit1(JSOP_POP)) // RESULT @@ -2556,10 +2508,6 @@ bool BytecodeEmitter::emitNumberOp(double dval) { int32_t ival; - uint32_t u; - ptrdiff_t off; - jsbytecode* pc; - if (NumberIsInt32(dval, &ival)) { if (ival == 0) return emit1(JSOP_ZERO); @@ -2568,21 +2516,19 @@ BytecodeEmitter::emitNumberOp(double dval) if ((int)(int8_t)ival == ival) return emit2(JSOP_INT8, (jsbytecode)(int8_t)ival); - u = (uint32_t)ival; + uint32_t u = uint32_t(ival); if (u < JS_BIT(16)) { emitUint16Operand(JSOP_UINT16, u); } else if (u < JS_BIT(24)) { - off = emitN(JSOP_UINT24, 3); - if (off < 0) + ptrdiff_t off; + if (!emitN(JSOP_UINT24, 3, &off)) return false; - pc = code(off); - SET_UINT24(pc, u); + SET_UINT24(code(off), u); } else { - off = emitN(JSOP_INT32, 4); - if (off < 0) + ptrdiff_t off; + if (!emitN(JSOP_INT32, 4, &off)) return false; - pc = code(off); - SET_INT32(pc, ival); + SET_INT32(code(off), ival); } return true; } @@ -2599,60 +2545,61 @@ BytecodeEmitter::setJumpOffsetAt(ptrdiff_t off) SET_JUMP_OFFSET(code(off), offset() - off); } -static bool -PushInitialConstants(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp op, unsigned n) +bool +BytecodeEmitter::pushInitialConstants(JSOp op, unsigned n) { MOZ_ASSERT(op == JSOP_UNDEFINED || op == JSOP_UNINITIALIZED); + for (unsigned i = 0; i < n; ++i) { - if (!bce->emit1(op)) + if (!emit1(op)) return false; } + return true; } -static bool -InitializeBlockScopedLocalsFromStack(ExclusiveContext* cx, BytecodeEmitter* bce, - Handle blockObj) +bool +BytecodeEmitter::initializeBlockScopedLocalsFromStack(Handle blockObj) { for (unsigned i = blockObj->numVariables(); i > 0; --i) { if (blockObj->isAliased(i - 1)) { ScopeCoordinate sc; sc.setHops(0); sc.setSlot(BlockObject::RESERVED_SLOTS + i - 1); - if (!bce->emitAliasedVarOp(JSOP_INITALIASEDLEXICAL, sc, DontCheckLexical)) + if (!emitAliasedVarOp(JSOP_INITALIASEDLEXICAL, sc, DontCheckLexical)) return false; } else { // blockIndexToLocalIndex returns the slot index after the unaliased // locals stored in the frame. EmitUnaliasedVarOp expects the slot index // to include both unaliased and aliased locals, so we have to add the // number of aliased locals. - uint32_t numAliased = bce->script->bindings.numAliasedBodyLevelLocals(); + uint32_t numAliased = script->bindings.numAliasedBodyLevelLocals(); unsigned local = blockObj->blockIndexToLocalIndex(i - 1) + numAliased; - if (!bce->emitUnaliasedVarOp(JSOP_INITLEXICAL, local, DontCheckLexical)) + if (!emitUnaliasedVarOp(JSOP_INITLEXICAL, local, DontCheckLexical)) return false; } - if (!bce->emit1(JSOP_POP)) + if (!emit1(JSOP_POP)) return false; } return true; } -static bool -EnterBlockScope(ExclusiveContext* cx, BytecodeEmitter* bce, StmtInfoBCE* stmtInfo, - ObjectBox* objbox, JSOp initialValueOp, unsigned alreadyPushed = 0) +bool +BytecodeEmitter::enterBlockScope(StmtInfoBCE* stmtInfo, ObjectBox* objbox, JSOp initialValueOp, + unsigned alreadyPushed) { // Initial values for block-scoped locals. Whether it is undefined or the // JS_UNINITIALIZED_LEXICAL magic value depends on the context. The // current way we emit for-in and for-of heads means its let bindings will // always be initialized, so we can initialize them to undefined. Rooted blockObj(cx, &objbox->object->as()); - if (!PushInitialConstants(cx, bce, initialValueOp, blockObj->numVariables() - alreadyPushed)) + if (!pushInitialConstants(initialValueOp, blockObj->numVariables() - alreadyPushed)) return false; - if (!EnterNestedScope(cx, bce, stmtInfo, objbox, STMT_BLOCK)) + if (!enterNestedScope(stmtInfo, objbox, STMT_BLOCK)) return false; - if (!InitializeBlockScopedLocalsFromStack(cx, bce, blockObj)) + if (!initializeBlockScopedLocalsFromStack(blockObj)) return false; return true; @@ -2664,103 +2611,89 @@ EnterBlockScope(ExclusiveContext* cx, BytecodeEmitter* bce, StmtInfoBCE* stmtInf * into emitTree which is recursive and uses relatively little stack space. */ MOZ_NEVER_INLINE bool -BytecodeEmitter::emitSwitch(ParseNode *pn) +BytecodeEmitter::emitSwitch(ParseNode* pn) { - JSOp switchOp; - bool hasDefault; - ptrdiff_t top, off, defaultOffset; - ParseNode* pn2, *pn3, *pn4; - int32_t low, high; - int noteIndex; - size_t switchSize; - jsbytecode* pc; - - /* Try for most optimal, fall back if not dense ints. */ - switchOp = JSOP_TABLESWITCH; - hasDefault = false; - defaultOffset = -1; - - pn2 = pn->pn_right; - MOZ_ASSERT(pn2->isKind(PNK_LEXICALSCOPE) || pn2->isKind(PNK_STATEMENTLIST)); + ParseNode* cases = pn->pn_right; + MOZ_ASSERT(cases->isKind(PNK_LEXICALSCOPE) || cases->isKind(PNK_STATEMENTLIST)); /* Push the discriminant. */ if (!emitTree(pn->pn_left)) return false; StmtInfoBCE stmtInfo(cx); - if (pn2->isKind(PNK_LEXICALSCOPE)) { - if (!EnterBlockScope(cx, this, &stmtInfo, pn2->pn_objbox, JSOP_UNINITIALIZED, 0)) + ptrdiff_t top; + if (cases->isKind(PNK_LEXICALSCOPE)) { + if (!enterBlockScope(&stmtInfo, cases->pn_objbox, JSOP_UNINITIALIZED, 0)) return false; stmtInfo.type = STMT_SWITCH; stmtInfo.update = top = offset(); - /* Advance pn2 to refer to the switch case list. */ - pn2 = pn2->expr(); + /* Advance |cases| to refer to the switch case list. */ + cases = cases->expr(); } else { - MOZ_ASSERT(pn2->isKind(PNK_STATEMENTLIST)); + MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST)); top = offset(); pushStatement(&stmtInfo, STMT_SWITCH, top); } /* Switch bytecodes run from here till end of final case. */ - uint32_t caseCount = pn2->pn_count; - uint32_t tableLength = 0; - UniquePtr table(nullptr); - + uint32_t caseCount = cases->pn_count; if (caseCount > JS_BIT(16)) { parser->tokenStream.reportError(JSMSG_TOO_MANY_CASES); return false; } + /* Try for most optimal, fall back if not dense ints. */ + JSOp switchOp = JSOP_TABLESWITCH; + uint32_t tableLength = 0; + int32_t low, high; + bool hasDefault = false; if (caseCount == 0 || (caseCount == 1 && - (hasDefault = (pn2->pn_head->isKind(PNK_DEFAULT))))) { + (hasDefault = cases->pn_head->isKind(PNK_DEFAULT)))) { caseCount = 0; low = 0; high = -1; } else { - bool ok = true; -#define INTMAP_LENGTH 256 - jsbitmap intmap_space[INTMAP_LENGTH]; - jsbitmap* intmap = nullptr; - int32_t intmap_bitlen = 0; + Vector intmap; + int32_t intmapBitLength = 0; low = JSVAL_INT_MAX; high = JSVAL_INT_MIN; - for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { - if (pn3->isKind(PNK_DEFAULT)) { + for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) { + if (caseNode->isKind(PNK_DEFAULT)) { hasDefault = true; caseCount--; /* one of the "cases" was the default */ continue; } - MOZ_ASSERT(pn3->isKind(PNK_CASE)); + MOZ_ASSERT(caseNode->isKind(PNK_CASE)); if (switchOp == JSOP_CONDSWITCH) continue; MOZ_ASSERT(switchOp == JSOP_TABLESWITCH); - pn4 = pn3->pn_left; + ParseNode* caseValue = caseNode->pn_left; - if (pn4->getKind() != PNK_NUMBER) { + if (caseValue->getKind() != PNK_NUMBER) { switchOp = JSOP_CONDSWITCH; continue; } int32_t i; - if (!NumberIsInt32(pn4->pn_dval, &i)) { + if (!NumberIsInt32(caseValue->pn_dval, &i)) { switchOp = JSOP_CONDSWITCH; continue; } - if ((unsigned)(i + (int)JS_BIT(15)) >= (unsigned)JS_BIT(16)) { + if (unsigned(i + int(JS_BIT(15))) >= unsigned(JS_BIT(16))) { switchOp = JSOP_CONDSWITCH; continue; } if (i < low) low = i; - if (high < i) + if (i > high) high = i; /* @@ -2770,21 +2703,11 @@ BytecodeEmitter::emitSwitch(ParseNode *pn) */ if (i < 0) i += JS_BIT(16); - if (i >= intmap_bitlen) { - if (!intmap && - size_t(i) < (INTMAP_LENGTH * JS_BITMAP_NBITS)) { - intmap = intmap_space; - intmap_bitlen = INTMAP_LENGTH * JS_BITMAP_NBITS; - } else { - /* Just grab 8K for the worst-case bitmap. */ - intmap_bitlen = JS_BIT(16); - intmap = cx->pod_malloc(JS_BIT(16) / JS_BITMAP_NBITS); - if (!intmap) { - ReportOutOfMemory(cx); - return false; - } - } - memset(intmap, 0, size_t(intmap_bitlen) / CHAR_BIT); + if (i >= intmapBitLength) { + size_t newLength = (i / JS_BITMAP_NBITS) + 1; + if (!intmap.resize(newLength)) + return false; + intmapBitLength = newLength * JS_BITMAP_NBITS; } if (JS_TEST_BIT(intmap, i)) { switchOp = JSOP_CONDSWITCH; @@ -2793,17 +2716,12 @@ BytecodeEmitter::emitSwitch(ParseNode *pn) JS_SET_BIT(intmap, i); } - if (intmap && intmap != intmap_space) - js_free(intmap); - if (!ok) - return false; - /* * Compute table length and select condswitch instead if overlarge or * more than half-sparse. */ if (switchOp == JSOP_TABLESWITCH) { - tableLength = (uint32_t)(high - low + 1); + tableLength = uint32_t(high - low + 1); if (tableLength >= JS_BIT(16) || tableLength > 2 * caseCount) switchOp = JSOP_CONDSWITCH; } @@ -2813,58 +2731,59 @@ BytecodeEmitter::emitSwitch(ParseNode *pn) * The note has one or two offsets: first tells total switch code length; * second (if condswitch) tells offset to first JSOP_CASE. */ + unsigned noteIndex; + size_t switchSize; if (switchOp == JSOP_CONDSWITCH) { /* 0 bytes of immediate for unoptimized switch. */ switchSize = 0; - noteIndex = NewSrcNote3(cx, this, SRC_CONDSWITCH, 0, 0); + if (!newSrcNote3(SRC_CONDSWITCH, 0, 0, ¬eIndex)) + return false; } else { MOZ_ASSERT(switchOp == JSOP_TABLESWITCH); /* 3 offsets (len, low, high) before the table, 1 per entry. */ switchSize = (size_t)(JUMP_OFFSET_LEN * (3 + tableLength)); - noteIndex = NewSrcNote2(cx, this, SRC_TABLESWITCH, 0); + if (!newSrcNote2(SRC_TABLESWITCH, 0, ¬eIndex)) + return false; } - if (noteIndex < 0) - return false; /* Emit switchOp followed by switchSize bytes of jump or lookup table. */ - if (emitN(switchOp, switchSize) < 0) + if (!emitN(switchOp, switchSize)) return false; - off = -1; + Vector table; + + ptrdiff_t condSwitchDefaultOff = -1; if (switchOp == JSOP_CONDSWITCH) { - int caseNoteIndex = -1; + unsigned caseNoteIndex; bool beforeCases = true; + ptrdiff_t prevCaseOffset; /* Emit code for evaluating cases and jumping to case statements. */ - for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { - pn4 = pn3->pn_left; - if (pn4 && !emitTree(pn4)) + for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) { + ParseNode* caseValue = caseNode->pn_left; + if (caseValue && !emitTree(caseValue)) return false; - if (caseNoteIndex >= 0) { - /* off is the previous JSOP_CASE's bytecode offset. */ - if (!setSrcNoteOffset(unsigned(caseNoteIndex), 0, offset() - off)) + if (!beforeCases) { + /* prevCaseOffset is the previous JSOP_CASE's bytecode offset. */ + if (!setSrcNoteOffset(caseNoteIndex, 0, offset() - prevCaseOffset)) return false; } - if (!pn4) { - MOZ_ASSERT(pn3->isKind(PNK_DEFAULT)); + if (!caseValue) { + MOZ_ASSERT(caseNode->isKind(PNK_DEFAULT)); continue; } - caseNoteIndex = NewSrcNote2(cx, this, SRC_NEXTCASE, 0); - if (caseNoteIndex < 0) + if (!newSrcNote2(SRC_NEXTCASE, 0, &caseNoteIndex)) return false; - off = emitJump(JSOP_CASE, 0); - if (off < 0) + if (!emitJump(JSOP_CASE, 0, &prevCaseOffset)) return false; - pn3->pn_offset = off; + caseNode->pn_offset = prevCaseOffset; if (beforeCases) { - unsigned noteCount, noteCountDelta; - /* Switch note's second offset is to first JSOP_CASE. */ - noteCount = notes().length(); - if (!setSrcNoteOffset(unsigned(noteIndex), 1, off - top)) + unsigned noteCount = notes().length(); + if (!setSrcNoteOffset(noteIndex, 1, prevCaseOffset - top)) return false; - noteCountDelta = notes().length() - noteCount; + unsigned noteCountDelta = notes().length() - noteCount; if (noteCountDelta != 0) caseNoteIndex += noteCountDelta; beforeCases = false; @@ -2878,19 +2797,18 @@ BytecodeEmitter::emitSwitch(ParseNode *pn) * the benefit of IonBuilder. */ if (!hasDefault && - caseNoteIndex >= 0 && - !setSrcNoteOffset(unsigned(caseNoteIndex), 0, offset() - off)) + !beforeCases && + !setSrcNoteOffset(caseNoteIndex, 0, offset() - prevCaseOffset)) { return false; } /* Emit default even if no explicit default statement. */ - defaultOffset = emitJump(JSOP_DEFAULT, 0); - if (defaultOffset < 0) + if (!emitJump(JSOP_DEFAULT, 0, &condSwitchDefaultOff)) return false; } else { MOZ_ASSERT(switchOp == JSOP_TABLESWITCH); - pc = code(top + JUMP_OFFSET_LEN); + jsbytecode* pc = code(top + JUMP_OFFSET_LEN); /* Fill in switch bounds, which we know fit in 16-bit offsets. */ SET_JUMP_OFFSET(pc, low); @@ -2898,67 +2816,65 @@ BytecodeEmitter::emitSwitch(ParseNode *pn) SET_JUMP_OFFSET(pc, high); pc += JUMP_OFFSET_LEN; - /* - * Use malloc to avoid arena bloat for programs with many switches. - * UniquePtr takes care of freeing it on exit. - */ if (tableLength != 0) { - table = cx->make_zeroed_pod_array(tableLength); - if (!table) + if (!table.growBy(tableLength)) return false; - for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { - if (pn3->isKind(PNK_DEFAULT)) + + for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) { + if (caseNode->isKind(PNK_DEFAULT)) continue; - MOZ_ASSERT(pn3->isKind(PNK_CASE)); + MOZ_ASSERT(caseNode->isKind(PNK_CASE)); - pn4 = pn3->pn_left; - MOZ_ASSERT(pn4->getKind() == PNK_NUMBER); + ParseNode* caseValue = caseNode->pn_left; + MOZ_ASSERT(caseValue->isKind(PNK_NUMBER)); - int32_t i = int32_t(pn4->pn_dval); - MOZ_ASSERT(double(i) == pn4->pn_dval); + int32_t i = int32_t(caseValue->pn_dval); + MOZ_ASSERT(double(i) == caseValue->pn_dval); i -= low; MOZ_ASSERT(uint32_t(i) < tableLength); - table[i] = pn3; + MOZ_ASSERT(!table[i]); + table[i] = caseNode; } } } - /* Emit code for each case's statements, copying pn_offset up to pn3. */ - for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { - if (switchOp == JSOP_CONDSWITCH && !pn3->isKind(PNK_DEFAULT)) - setJumpOffsetAt(pn3->pn_offset); - pn4 = pn3->pn_right; - if (!emitTree(pn4)) + ptrdiff_t defaultOffset = -1; + + /* Emit code for each case's statements, copying pn_offset up to caseNode. */ + for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) { + if (switchOp == JSOP_CONDSWITCH && !caseNode->isKind(PNK_DEFAULT)) + setJumpOffsetAt(caseNode->pn_offset); + ParseNode* caseValue = caseNode->pn_right; + if (!emitTree(caseValue)) return false; - pn3->pn_offset = pn4->pn_offset; - if (pn3->isKind(PNK_DEFAULT)) - off = pn3->pn_offset - top; + caseNode->pn_offset = caseValue->pn_offset; + if (caseNode->isKind(PNK_DEFAULT)) + defaultOffset = caseNode->pn_offset - top; } if (!hasDefault) { /* If no default case, offset for default is to end of switch. */ - off = offset() - top; + defaultOffset = offset() - top; } - /* We better have set "off" by now. */ - MOZ_ASSERT(off != -1); + /* We better have set "defaultOffset" by now. */ + MOZ_ASSERT(defaultOffset != -1); /* Set the default offset (to end of switch if no default). */ + jsbytecode* pc; if (switchOp == JSOP_CONDSWITCH) { pc = nullptr; - MOZ_ASSERT(defaultOffset != -1); - SET_JUMP_OFFSET(code(defaultOffset), off - (defaultOffset - top)); + SET_JUMP_OFFSET(code(condSwitchDefaultOff), defaultOffset - (condSwitchDefaultOff - top)); } else { pc = code(top); - SET_JUMP_OFFSET(pc, off); + SET_JUMP_OFFSET(pc, defaultOffset); pc += JUMP_OFFSET_LEN; } /* Set the SRC_SWITCH note's offset operand to tell end of switch. */ - off = offset() - top; - if (!setSrcNoteOffset(unsigned(noteIndex), 0, off)) + if (!setSrcNoteOffset(noteIndex, 0, offset() - top)) return false; if (switchOp == JSOP_TABLESWITCH) { @@ -2967,15 +2883,15 @@ BytecodeEmitter::emitSwitch(ParseNode *pn) /* Fill in the jump table, if there is one. */ for (uint32_t i = 0; i < tableLength; i++) { - pn3 = table[i]; - off = pn3 ? pn3->pn_offset - top : 0; + ParseNode* caseNode = table[i]; + ptrdiff_t off = caseNode ? caseNode->pn_offset - top : 0; SET_JUMP_OFFSET(pc, off); pc += JUMP_OFFSET_LEN; } } if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) { - if (!LeaveNestedScope(cx, this, &stmtInfo)) + if (!leaveNestedScope(&stmtInfo)) return false; } else { popStatement(); @@ -3011,8 +2927,8 @@ BytecodeEmitter::emitYieldOp(JSOp op) MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD); - ptrdiff_t off = emitN(op, 3); - if (off < 0) + ptrdiff_t off; + if (!emitN(op, 3, &off)) return false; uint32_t yieldIndex = yieldOffsetList.length(); @@ -3030,9 +2946,9 @@ BytecodeEmitter::emitYieldOp(JSOp op) } bool -frontend::EmitFunctionScript(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* body) +BytecodeEmitter::emitFunctionScript(ParseNode* body) { - if (!bce->updateLocalsToFrameSlots()) + if (!updateLocalsToFrameSlots()) return false; /* @@ -3042,28 +2958,28 @@ frontend::EmitFunctionScript(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNo * execution starts from script->code, so this has no semantic effect. */ - FunctionBox* funbox = bce->sc->asFunctionBox(); + FunctionBox* funbox = sc->asFunctionBox(); if (funbox->argumentsHasLocalBinding()) { - MOZ_ASSERT(bce->offset() == 0); /* See JSScript::argumentsBytecode. */ - bce->switchToProlog(); - if (!bce->emit1(JSOP_ARGUMENTS)) + MOZ_ASSERT(offset() == 0); /* See JSScript::argumentsBytecode. */ + switchToProlog(); + if (!emit1(JSOP_ARGUMENTS)) return false; - InternalBindingsHandle bindings(bce->script, &bce->script->bindings); + InternalBindingsHandle bindings(script, &script->bindings); BindingIter bi = Bindings::argumentsBinding(cx, bindings); - if (bce->script->bindingIsAliased(bi)) { + if (script->bindingIsAliased(bi)) { ScopeCoordinate sc; sc.setHops(0); sc.setSlot(0); // initialize to silence GCC warning - JS_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().arguments, &sc)); - if (!bce->emitAliasedVarOp(JSOP_SETALIASEDVAR, sc, DontCheckLexical)) + JS_ALWAYS_TRUE(lookupAliasedNameSlot(cx->names().arguments, &sc)); + if (!emitAliasedVarOp(JSOP_SETALIASEDVAR, sc, DontCheckLexical)) return false; } else { - if (!bce->emitUnaliasedVarOp(JSOP_SETLOCAL, bi.localIndex(), DontCheckLexical)) + if (!emitUnaliasedVarOp(JSOP_SETLOCAL, bi.localIndex(), DontCheckLexical)) return false; } - if (!bce->emit1(JSOP_POP)) + if (!emit1(JSOP_POP)) return false; - bce->switchToMain(); + switchToMain(); } /* @@ -3071,55 +2987,52 @@ frontend::EmitFunctionScript(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNo * the script ends up running multiple times via foo.caller related * shenanigans. */ - bool runOnce = bce->isRunOnceLambda(); + bool runOnce = isRunOnceLambda(); if (runOnce) { - bce->switchToProlog(); - if (!bce->emit1(JSOP_RUNONCE)) + switchToProlog(); + if (!emit1(JSOP_RUNONCE)) return false; - bce->switchToMain(); + switchToMain(); } - if (!bce->emitTree(body)) + if (!emitTree(body)) return false; - if (bce->sc->isFunctionBox()) { - if (bce->sc->asFunctionBox()->isGenerator()) { + if (sc->isFunctionBox()) { + if (sc->asFunctionBox()->isGenerator()) { // If we fall off the end of a generator, do a final yield. - if (bce->sc->asFunctionBox()->isStarGenerator() && !bce->emitPrepareIteratorResult()) + if (sc->asFunctionBox()->isStarGenerator() && !emitPrepareIteratorResult()) return false; - if (!bce->emit1(JSOP_UNDEFINED)) + if (!emit1(JSOP_UNDEFINED)) return false; - if (bce->sc->asFunctionBox()->isStarGenerator() && - !bce->emitFinishIteratorResult(true)) - { + if (sc->asFunctionBox()->isStarGenerator() && !emitFinishIteratorResult(true)) return false; - } - if (!bce->emit1(JSOP_SETRVAL)) + if (!emit1(JSOP_SETRVAL)) return false; ScopeCoordinate sc; // We know that .generator is on the top scope chain node, as we are // at the function end. sc.setHops(0); - MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().dotGenerator, &sc)); - if (!bce->emitAliasedVarOp(JSOP_GETALIASEDVAR, sc, DontCheckLexical)) + MOZ_ALWAYS_TRUE(lookupAliasedNameSlot(cx->names().dotGenerator, &sc)); + if (!emitAliasedVarOp(JSOP_GETALIASEDVAR, sc, DontCheckLexical)) return false; // No need to check for finally blocks, etc as in EmitReturn. - if (!bce->emitYieldOp(JSOP_FINALYIELDRVAL)) + if (!emitYieldOp(JSOP_FINALYIELDRVAL)) return false; } else { // Non-generator functions just return |undefined|. The JSOP_RETRVAL // emitted below will do that, except if the script has a finally // block: there can be a non-undefined value in the return value // slot. We just emit an explicit return in this case. - if (bce->hasTryFinally) { - if (!bce->emit1(JSOP_UNDEFINED)) + if (hasTryFinally) { + if (!emit1(JSOP_UNDEFINED)) return false; - if (!bce->emit1(JSOP_RETURN)) + if (!emit1(JSOP_RETURN)) return false; } } @@ -3127,17 +3040,17 @@ frontend::EmitFunctionScript(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNo // Always end the script with a JSOP_RETRVAL. Some other parts of the codebase // depend on this opcode, e.g. InterpreterRegs::setToEndOfScript. - if (!bce->emit1(JSOP_RETRVAL)) + if (!emit1(JSOP_RETRVAL)) return false; // If all locals are aliased, the frame's block slots won't be used, so we // can set numBlockScoped = 0. This is nice for generators as it ensures // nfixed == 0, so we don't have to initialize any local slots when resuming // a generator. - if (bce->sc->allLocalsAliased()) - bce->script->bindings.setAllLocalsAliased(); + if (sc->allLocalsAliased()) + script->bindings.setAllLocalsAliased(); - if (!JSScript::fullyInitFromEmitter(cx, bce->script, bce)) + if (!JSScript::fullyInitFromEmitter(cx, script, this)) return false; /* @@ -3145,20 +3058,20 @@ frontend::EmitFunctionScript(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNo * initializers created within it may be given more precise types. */ if (runOnce) { - bce->script->setTreatAsRunOnce(); - MOZ_ASSERT(!bce->script->hasRunOnce()); + script->setTreatAsRunOnce(); + MOZ_ASSERT(!script->hasRunOnce()); } /* Initialize fun->script() so that the debugger has a valid fun->script(). */ - RootedFunction fun(cx, bce->script->functionNonDelazifying()); + RootedFunction fun(cx, script->functionNonDelazifying()); MOZ_ASSERT(fun->isInterpreted()); if (fun->isInterpretedLazy()) - fun->setUnlazifiedScript(bce->script); + fun->setUnlazifiedScript(script); else - fun->setScript(bce->script); + fun->setScript(script); - bce->tellDebuggerAboutCompiledScript(cx); + tellDebuggerAboutCompiledScript(cx); return true; } @@ -3191,13 +3104,9 @@ BytecodeEmitter::maybeEmitVarDecl(JSOp prologOp, ParseNode *pn, jsatomid *result return true; } -typedef bool -(*DestructuringDeclEmitter)(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn); - -template -static bool -EmitDestructuringDeclsWithEmitter(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp prologOp, - ParseNode* pattern) +template +bool +BytecodeEmitter::emitDestructuringDeclsWithEmitter(JSOp prologOp, ParseNode* pattern) { if (pattern->isKind(PNK_ARRAY)) { for (ParseNode* element = pattern->pn_head; element; element = element->pn_next) { @@ -3211,10 +3120,10 @@ EmitDestructuringDeclsWithEmitter(ExclusiveContext* cx, BytecodeEmitter* bce, JS if (target->isKind(PNK_ASSIGN)) target = target->pn_left; if (target->isKind(PNK_NAME)) { - if (!EmitName(cx, bce, prologOp, target)) + if (!EmitName(this, prologOp, target)) return false; } else { - if (!EmitDestructuringDeclsWithEmitter(cx, bce, prologOp, target)) + if (!emitDestructuringDeclsWithEmitter(prologOp, target)) return false; } } @@ -3232,18 +3141,18 @@ EmitDestructuringDeclsWithEmitter(ExclusiveContext* cx, BytecodeEmitter* bce, JS if (target->isKind(PNK_ASSIGN)) target = target->pn_left; if (target->isKind(PNK_NAME)) { - if (!EmitName(cx, bce, prologOp, target)) + if (!EmitName(this, prologOp, target)) return false; } else { - if (!EmitDestructuringDeclsWithEmitter(cx, bce, prologOp, target)) + if (!emitDestructuringDeclsWithEmitter(prologOp, target)) return false; } } return true; } -bool -EmitDestructuringDecl(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp prologOp, ParseNode* pn) +static bool +EmitDestructuringDecl(BytecodeEmitter* bce, JSOp prologOp, ParseNode* pn) { MOZ_ASSERT(pn->isKind(PNK_NAME)); if (!bce->bindNameToSlot(pn)) @@ -3253,38 +3162,28 @@ EmitDestructuringDecl(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp prologOp, return bce->maybeEmitVarDecl(prologOp, pn, nullptr); } -static inline bool -EmitDestructuringDecls(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp prologOp, - ParseNode* pattern) +bool +BytecodeEmitter::emitDestructuringDecls(JSOp prologOp, ParseNode* pattern) { - return EmitDestructuringDeclsWithEmitter(cx, bce, prologOp, pattern); + return emitDestructuringDeclsWithEmitter(prologOp, pattern); } -bool -EmitInitializeDestructuringDecl(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp prologOp, - ParseNode* pn) +static bool +EmitInitializeDestructuringDecl(BytecodeEmitter* bce, JSOp prologOp, ParseNode* pn) { MOZ_ASSERT(pn->isKind(PNK_NAME)); MOZ_ASSERT(pn->isBound()); return bce->emitVarOp(pn, pn->getOp()); } -// Emit code to initialize all destructured names to the value on the top of -// the stack. -static inline bool -EmitInitializeDestructuringDecls(ExclusiveContext* cx, BytecodeEmitter* bce, JSOp prologOp, - ParseNode* pattern) +bool +BytecodeEmitter::emitInitializeDestructuringDecls(JSOp prologOp, ParseNode* pattern) { - return EmitDestructuringDeclsWithEmitter(cx, bce, - prologOp, pattern); + return emitDestructuringDeclsWithEmitter(prologOp, pattern); } -static bool -EmitDestructuringOpsHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pattern, - VarEmitOption emitOption); - bool -BytecodeEmitter::emitDestructuringLHS(ParseNode *target, VarEmitOption emitOption) +BytecodeEmitter::emitDestructuringLHS(ParseNode* target, VarEmitOption emitOption) { MOZ_ASSERT(emitOption != DefineVars); @@ -3297,10 +3196,10 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode *target, VarEmitOption emitOptio else if (target->isKind(PNK_ASSIGN)) target = target->pn_left; if (target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT)) { - if (!EmitDestructuringOpsHelper(cx, this, target, emitOption)) + if (!emitDestructuringOpsHelper(target, emitOption)) return false; if (emitOption == InitializeVars) { - // Per its post-condition, EmitDestructuringOpsHelper has left the + // Per its post-condition, emitDestructuringOpsHelper has left the // to-be-destructured value on top of the stack. if (!emit1(JSOP_POP)) return false; @@ -3448,10 +3347,10 @@ BytecodeEmitter::emitDefault(ParseNode *defaultExpr) if (!emit1(JSOP_STRICTEQ)) // VALUE EQL? return false; // Emit source note to enable ion compilation. - if (NewSrcNote(cx, this, SRC_IF) < 0) + if (!newSrcNote(SRC_IF)) return false; - ptrdiff_t jump = emitJump(JSOP_IFEQ, 0); // VALUE - if (jump < 0) + ptrdiff_t jump; + if (!emitJump(JSOP_IFEQ, 0, &jump)) // VALUE return false; if (!emit1(JSOP_POP)) // . return false; @@ -3461,23 +3360,22 @@ BytecodeEmitter::emitDefault(ParseNode *defaultExpr) return true; } -static bool -EmitDestructuringOpsArrayHelper(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pattern, - VarEmitOption emitOption) +bool +BytecodeEmitter::emitDestructuringOpsArrayHelper(ParseNode* pattern, VarEmitOption emitOption) { MOZ_ASSERT(pattern->isKind(PNK_ARRAY)); MOZ_ASSERT(pattern->isArity(PN_LIST)); - MOZ_ASSERT(bce->stackDepth != 0); + MOZ_ASSERT(this->stackDepth != 0); /* * Use an iterator to destructure the RHS, instead of index lookup. * InitializeVars expects us to leave the *original* value on the stack. */ if (emitOption == InitializeVars) { - if (!bce->emit1(JSOP_DUP)) // ... OBJ OBJ + if (!emit1(JSOP_DUP)) // ... OBJ OBJ return false; } - if (!bce->emitIterator()) // ... OBJ? ITER + if (!emitIterator()) // ... OBJ? ITER return false; bool needToPopIterator = true; @@ -3496,73 +3394,73 @@ EmitDestructuringOpsArrayHelper(ExclusiveContext* cx, BytecodeEmitter* bce, Pars if (elem->isKind(PNK_SPREAD)) { /* Create a new array with the rest of the iterator */ - ptrdiff_t off = bce->emitN(JSOP_NEWARRAY, 3); // ... OBJ? ITER ARRAY - if (off < 0) + ptrdiff_t off; + if (!emitN(JSOP_NEWARRAY, 3, &off)) // ... OBJ? ITER ARRAY return false; - bce->checkTypeSet(JSOP_NEWARRAY); - jsbytecode *pc = bce->code(off); + checkTypeSet(JSOP_NEWARRAY); + jsbytecode *pc = code(off); SET_UINT24(pc, 0); - if (!bce->emitNumberOp(0)) // ... OBJ? ITER ARRAY INDEX + if (!emitNumberOp(0)) // ... OBJ? ITER ARRAY INDEX return false; - if (!bce->emitSpread()) // ... OBJ? ARRAY INDEX + if (!emitSpread()) // ... OBJ? ARRAY INDEX return false; - if (!bce->emit1(JSOP_POP)) // ... OBJ? ARRAY + if (!emit1(JSOP_POP)) // ... OBJ? ARRAY return false; needToPopIterator = false; } else { - if (!bce->emit1(JSOP_DUP)) // ... OBJ? ITER ITER + if (!emit1(JSOP_DUP)) // ... OBJ? ITER ITER return false; - if (!bce->emitIteratorNext(pattern)) // ... OBJ? ITER RESULT + if (!emitIteratorNext(pattern)) // ... OBJ? ITER RESULT return false; - if (!bce->emit1(JSOP_DUP)) // ... OBJ? ITER RESULT RESULT + if (!emit1(JSOP_DUP)) // ... OBJ? ITER RESULT RESULT return false; - if (!bce->emitAtomOp(cx->names().done, JSOP_GETPROP)) // ... OBJ? ITER RESULT DONE? + if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ... OBJ? ITER RESULT DONE? return false; // Emit (result.done ? undefined : result.value) - // This is mostly copied from EmitConditionalExpression, except that this code + // This is mostly copied from emitConditionalExpression, except that this code // does not push new values onto the stack. - ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_COND); - if (noteIndex < 0) + unsigned noteIndex; + if (!newSrcNote(SRC_COND, ¬eIndex)) return false; - ptrdiff_t beq = bce->emitJump(JSOP_IFEQ, 0); - if (beq < 0) + ptrdiff_t beq; + if (!emitJump(JSOP_IFEQ, 0, &beq)) return false; - if (!bce->emit1(JSOP_POP)) // ... OBJ? ITER + if (!emit1(JSOP_POP)) // ... OBJ? ITER return false; - if (!bce->emit1(JSOP_UNDEFINED)) // ... OBJ? ITER UNDEFINED + if (!emit1(JSOP_UNDEFINED)) // ... OBJ? ITER UNDEFINED return false; /* Jump around else, fixup the branch, emit else, fixup jump. */ - ptrdiff_t jmp = bce->emitJump(JSOP_GOTO, 0); - if (jmp < 0) + ptrdiff_t jmp; + if (!emitJump(JSOP_GOTO, 0, &jmp)) return false; - bce->setJumpOffsetAt(beq); + setJumpOffsetAt(beq); - if (!bce->emitAtomOp(cx->names().value, JSOP_GETPROP)) // ... OBJ? ITER VALUE + if (!emitAtomOp(cx->names().value, JSOP_GETPROP)) // ... OBJ? ITER VALUE return false; - bce->setJumpOffsetAt(jmp); - if (!bce->setSrcNoteOffset(noteIndex, 0, jmp - beq)) + setJumpOffsetAt(jmp); + if (!setSrcNoteOffset(noteIndex, 0, jmp - beq)) return false; } - if (pndefault && !bce->emitDefault(pndefault)) + if (pndefault && !emitDefault(pndefault)) return false; // Destructure into the pattern the element contains. ParseNode *subpattern = elem; if (subpattern->isKind(PNK_ELISION)) { // The value destructuring into an elision just gets ignored. - if (!bce->emit1(JSOP_POP)) // ... OBJ? ITER + if (!emit1(JSOP_POP)) // ... OBJ? ITER return false; continue; } - int32_t depthBefore = bce->stackDepth; - if (!bce->emitDestructuringLHS(subpattern, emitOption)) + int32_t depthBefore = this->stackDepth; + if (!emitDestructuringLHS(subpattern, emitOption)) return false; if (emitOption == PushInitialValues && needToPopIterator) { @@ -3576,37 +3474,36 @@ EmitDestructuringOpsArrayHelper(ExclusiveContext* cx, BytecodeEmitter* bce, Pars * before destructuring z. This gives the loop invariant that * the to-be-destructured-value is always on top of the stack. */ - MOZ_ASSERT((bce->stackDepth - bce->stackDepth) >= -1); - uint32_t pickDistance = (uint32_t)((bce->stackDepth + 1) - depthBefore); + MOZ_ASSERT((this->stackDepth - this->stackDepth) >= -1); + uint32_t pickDistance = uint32_t((this->stackDepth + 1) - depthBefore); if (pickDistance > 0) { if (pickDistance > UINT8_MAX) { - bce->reportError(subpattern, JSMSG_TOO_MANY_LOCALS); + reportError(subpattern, JSMSG_TOO_MANY_LOCALS); return false; } - if (!bce->emit2(JSOP_PICK, (jsbytecode)pickDistance)) + if (!emit2(JSOP_PICK, (jsbytecode)pickDistance)) return false; } } } - if (needToPopIterator && !bce->emit1(JSOP_POP)) + if (needToPopIterator && !emit1(JSOP_POP)) return false; return true; } -static bool -EmitDestructuringOpsObjectHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pattern, - VarEmitOption emitOption) +bool +BytecodeEmitter::emitDestructuringOpsObjectHelper(ParseNode *pattern, VarEmitOption emitOption) { MOZ_ASSERT(pattern->isKind(PNK_OBJECT)); MOZ_ASSERT(pattern->isArity(PN_LIST)); - MOZ_ASSERT(bce->stackDepth != 0); // ... OBJ + MOZ_ASSERT(this->stackDepth != 0); // ... OBJ for (ParseNode *member = pattern->pn_head; member; member = member->pn_next) { // Duplicate the value being destructured to use as a reference base. - if (!bce->emit1(JSOP_DUP)) // ... OBJ OBJ + if (!emit1(JSOP_DUP)) // ... OBJ OBJ return false; // Now push the property name currently being matched, which is the @@ -3616,7 +3513,7 @@ EmitDestructuringOpsObjectHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Par ParseNode *subpattern; if (member->isKind(PNK_MUTATEPROTO)) { - if (!bce->emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... OBJ PROP + if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... OBJ PROP return false; needsGetElem = false; subpattern = member->pn_kid; @@ -3625,7 +3522,7 @@ EmitDestructuringOpsObjectHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Par ParseNode* key = member->pn_left; if (key->isKind(PNK_NUMBER)) { - if (!bce->emitNumberOp(key->pn_dval)) // ... OBJ OBJ KEY + if (!emitNumberOp(key->pn_dval)) // ... OBJ OBJ KEY return false; } else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) { PropertyName* name = key->pn_atom->asPropertyName(); @@ -3635,16 +3532,16 @@ EmitDestructuringOpsObjectHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Par // as indexes for simplification of downstream analysis. jsid id = NameToId(name); if (id != IdToTypeId(id)) { - if (!bce->emitTree(key)) // ... OBJ OBJ KEY + if (!emitTree(key)) // ... OBJ OBJ KEY return false; } else { - if (!bce->emitAtomOp(name, JSOP_GETPROP)) // ...OBJ PROP + if (!emitAtomOp(name, JSOP_GETPROP)) // ...OBJ PROP return false; needsGetElem = false; } } else { MOZ_ASSERT(key->isKind(PNK_COMPUTED_NAME)); - if (!bce->emitTree(key->pn_kid)) // ... OBJ OBJ KEY + if (!emitTree(key->pn_kid)) // ... OBJ OBJ KEY return false; } @@ -3652,25 +3549,25 @@ EmitDestructuringOpsObjectHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Par } // Get the property value if not done already. - if (needsGetElem && !bce->emitElemOpBase(JSOP_GETELEM)) // ... OBJ PROP + if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... OBJ PROP return false; if (subpattern->isKind(PNK_ASSIGN)) { - if (!bce->emitDefault(subpattern->pn_right)) + if (!emitDefault(subpattern->pn_right)) return false; subpattern = subpattern->pn_left; } // Destructure PROP per this member's subpattern. - int32_t depthBefore = bce->stackDepth; - if (!bce->emitDestructuringLHS(subpattern, emitOption)) + int32_t depthBefore = this->stackDepth; + if (!emitDestructuringLHS(subpattern, emitOption)) return false; // If emitOption is InitializeVars, destructuring initialized each // target in the subpattern's LHS as it went, then popped PROP. We've // correctly returned to the loop-entry stack, and we continue to the // next member. - if (emitOption == InitializeVars) // ... OBJ + if (emitOption == InitializeVars) // ... OBJ continue; MOZ_ASSERT(emitOption == PushInitialValues); @@ -3698,14 +3595,14 @@ EmitDestructuringOpsObjectHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Par // // so that we can continue, ready to destruct z from OBJ. Pick OBJ out // of the stack, moving it to the top, to accomplish this. - MOZ_ASSERT((bce->stackDepth - bce->stackDepth) >= -1); - uint32_t pickDistance = (uint32_t)((bce->stackDepth + 1) - depthBefore); + MOZ_ASSERT((this->stackDepth - this->stackDepth) >= -1); + uint32_t pickDistance = uint32_t((this->stackDepth + 1) - depthBefore); if (pickDistance > 0) { if (pickDistance > UINT8_MAX) { - bce->reportError(subpattern, JSMSG_TOO_MANY_LOCALS); + reportError(subpattern, JSMSG_TOO_MANY_LOCALS); return false; } - if (!bce->emit2(JSOP_PICK, (jsbytecode)pickDistance)) + if (!emit2(JSOP_PICK, (jsbytecode)pickDistance)) return false; } } @@ -3714,7 +3611,7 @@ EmitDestructuringOpsObjectHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Par // Per the above loop invariant, the value being destructured into this // object pattern is atop the stack. Pop it to achieve the // post-condition. - if (!bce->emit1(JSOP_POP)) // ... + if (!emit1(JSOP_POP)) // ... return false; } @@ -3722,7 +3619,7 @@ EmitDestructuringOpsObjectHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Par } /* - * Recursive helper for EmitDestructuringOps. + * Recursive helper for emitDestructuringOps. * EmitDestructuringOpsHelper assumes the to-be-destructured value has been * pushed on the stack and emits code to destructure each part of a [] or {} * lhs expression. @@ -3734,27 +3631,25 @@ EmitDestructuringOpsObjectHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Par * with the initial values of the N (where 0 <= N) variables assigned in the * lhs expression. (Same post-condition as emitDestructuringLHS) */ -static bool -EmitDestructuringOpsHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pattern, - VarEmitOption emitOption) +bool +BytecodeEmitter::emitDestructuringOpsHelper(ParseNode *pattern, VarEmitOption emitOption) { MOZ_ASSERT(emitOption != DefineVars); if (pattern->isKind(PNK_ARRAY)) - return EmitDestructuringOpsArrayHelper(cx, bce, pattern, emitOption); - return EmitDestructuringOpsObjectHelper(cx, bce, pattern, emitOption); + return emitDestructuringOpsArrayHelper(pattern, emitOption); + return emitDestructuringOpsObjectHelper(pattern, emitOption); } -static bool -EmitDestructuringOps(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pattern, - bool isLet = false) +bool +BytecodeEmitter::emitDestructuringOps(ParseNode *pattern, bool isLet) { /* * Call our recursive helper to emit the destructuring assignments and * related stack manipulations. */ VarEmitOption emitOption = isLet ? PushInitialValues : InitializeVars; - return EmitDestructuringOpsHelper(cx, bce, pattern, emitOption); + return emitDestructuringOpsHelper(pattern, emitOption); } bool @@ -3819,7 +3714,7 @@ BytecodeEmitter::emitVariables(ParseNode *pn, VarEmitOption emitOption, bool isL // emitForInOrOfVariables. MOZ_ASSERT(pn->pn_count == 1); if (emitOption == DefineVars) { - if (!EmitDestructuringDecls(cx, this, pn->getOp(), pn2)) + if (!emitDestructuringDecls(pn->getOp(), pn2)) return false; } else { // Lexical bindings cannot be used before they are @@ -3828,7 +3723,7 @@ BytecodeEmitter::emitVariables(ParseNode *pn, VarEmitOption emitOption, bool isL MOZ_ASSERT_IF(emitOption == InitializeVars, pn->pn_xflags & PNX_POPVAR); if (!emit1(JSOP_UNDEFINED)) return false; - if (!EmitInitializeDestructuringDecls(cx, this, pn->getOp(), pn2)) + if (!emitInitializeDestructuringDecls(pn->getOp(), pn2)) return false; } break; @@ -3856,13 +3751,13 @@ BytecodeEmitter::emitVariables(ParseNode *pn, VarEmitOption emitOption, bool isL } pn3 = pn2->pn_left; - if (!EmitDestructuringDecls(cx, this, pn->getOp(), pn3)) + if (!emitDestructuringDecls(pn->getOp(), pn3)) return false; if (!emitTree(pn2->pn_right)) return false; - if (!EmitDestructuringOps(cx, this, pn3, isLetExpr)) + if (!emitDestructuringOps(pn3, isLetExpr)) return false; /* If we are not initializing, nothing to pop. */ @@ -4116,7 +4011,7 @@ BytecodeEmitter::emitAssignment(ParseNode *lhs, JSOp op, ParseNode *rhs) * a bit further below) we will avoid emitting the assignment op. */ if (!lhs->isKind(PNK_NAME) || !lhs->isConst()) { - if (NewSrcNote(cx, this, SRC_ASSIGNOP) < 0) + if (!newSrcNote(SRC_ASSIGNOP)) return false; } if (!emit1(op)) @@ -4154,7 +4049,7 @@ BytecodeEmitter::emitAssignment(ParseNode *lhs, JSOp op, ParseNode *rhs) } case PNK_ARRAY: case PNK_OBJECT: - if (!EmitDestructuringOps(cx, this, lhs)) + if (!emitDestructuringOps(lhs)) return false; break; default: @@ -4373,7 +4268,7 @@ BytecodeEmitter::emitCatch(ParseNode *pn) switch (pn2->getKind()) { case PNK_ARRAY: case PNK_OBJECT: - if (!EmitDestructuringOps(cx, this, pn2)) + if (!emitDestructuringOps(pn2)) return false; if (!emit1(JSOP_POP)) return false; @@ -4401,12 +4296,12 @@ BytecodeEmitter::emitCatch(ParseNode *pn) // If the guard expression is false, fall through, pop the block scope, // and jump to the next catch block. Otherwise jump over that code and // pop the dupped exception. - ptrdiff_t guardCheck = emitJump(JSOP_IFNE, 0); - if (guardCheck < 0) + ptrdiff_t guardCheck; + if (!emitJump(JSOP_IFNE, 0, &guardCheck)) return false; { - NonLocalExitScope nle(cx, this); + NonLocalExitScope nle(this); // Move exception back to cx->exception to prepare for // the next catch. @@ -4418,8 +4313,8 @@ BytecodeEmitter::emitCatch(ParseNode *pn) return false; // Jump to the next handler. The jump target is backpatched by emitTry. - ptrdiff_t guardJump = emitJump(JSOP_GOTO, 0); - if (guardJump < 0) + ptrdiff_t guardJump; + if (!emitJump(JSOP_GOTO, 0, &guardJump)) return false; stmt->guardJump() = guardJump; } @@ -4464,9 +4359,12 @@ BytecodeEmitter::emitTry(ParseNode *pn) int depth = stackDepth; // Record the try location, then emit the try block. - ptrdiff_t noteIndex = NewSrcNote(cx, this, SRC_TRY); - if (noteIndex < 0 || !emit1(JSOP_TRY)) + unsigned noteIndex; + if (!newSrcNote(SRC_TRY, ¬eIndex)) return false; + if (!emit1(JSOP_TRY)) + return false; + ptrdiff_t tryStart = offset(); if (!emitTree(pn->pn_kid1)) return false; @@ -4613,7 +4511,7 @@ BytecodeEmitter::emitIf(ParseNode *pn) stmtInfo.type = STMT_IF; ptrdiff_t beq = -1; ptrdiff_t jmp = -1; - ptrdiff_t noteIndex = -1; + unsigned noteIndex = -1; if_again: /* Emit code for the condition before pushing stmtInfo. */ @@ -4637,11 +4535,9 @@ BytecodeEmitter::emitIf(ParseNode *pn) /* Emit an annotated branch-if-false around the then part. */ ParseNode *pn3 = pn->pn_kid3; - noteIndex = NewSrcNote(cx, this, pn3 ? SRC_IF_ELSE : SRC_IF); - if (noteIndex < 0) + if (!newSrcNote(pn3 ? SRC_IF_ELSE : SRC_IF, ¬eIndex)) return false; - beq = emitJump(JSOP_IFEQ, 0); - if (beq < 0) + if (!emitJump(JSOP_IFEQ, 0, &beq)) return false; /* Emit code for the then and optional else parts. */ @@ -4657,9 +4553,9 @@ BytecodeEmitter::emitIf(ParseNode *pn) * this function will fix up the backpatch chain linked from * stmtInfo.breaks. */ - jmp = emitGoto(&stmtInfo, &stmtInfo.breaks); - if (jmp < 0) + if (!emitGoto(&stmtInfo, &stmtInfo.breaks)) return false; + jmp = stmtInfo.breaks; /* Ensure the branch-if-false comes here, then emit the else. */ setJumpOffsetAt(beq); @@ -4694,54 +4590,52 @@ BytecodeEmitter::emitIf(ParseNode *pn) */ /* * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See - * the comment on EmitSwitch. + * the comment on emitSwitch. */ -MOZ_NEVER_INLINE static bool -EmitLetBlock(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet) +MOZ_NEVER_INLINE bool +BytecodeEmitter::emitLetBlock(ParseNode* pnLet) { MOZ_ASSERT(pnLet->isArity(PN_BINARY)); - ParseNode *varList = pnLet->pn_left; + ParseNode* varList = pnLet->pn_left; MOZ_ASSERT(varList->isArity(PN_LIST)); - ParseNode *letBody = pnLet->pn_right; + ParseNode* letBody = pnLet->pn_right; MOZ_ASSERT(letBody->isLexical() && letBody->isKind(PNK_LEXICALSCOPE)); - int letHeadDepth = bce->stackDepth; + int letHeadDepth = this->stackDepth; - if (!bce->emitVariables(varList, PushInitialValues, true)) + if (!emitVariables(varList, PushInitialValues, true)) return false; /* Push storage for hoisted let decls (e.g. 'let (x) { let y }'). */ - uint32_t valuesPushed = bce->stackDepth - letHeadDepth; + uint32_t valuesPushed = this->stackDepth - letHeadDepth; StmtInfoBCE stmtInfo(cx); - if (!EnterBlockScope(cx, bce, &stmtInfo, letBody->pn_objbox, JSOP_UNINITIALIZED, valuesPushed)) + if (!enterBlockScope(&stmtInfo, letBody->pn_objbox, JSOP_UNINITIALIZED, valuesPushed)) return false; - if (!bce->emitTree(letBody->pn_expr)) + if (!emitTree(letBody->pn_expr)) return false; - if (!LeaveNestedScope(cx, bce, &stmtInfo)) + if (!leaveNestedScope(&stmtInfo)) return false; return true; } -/* - * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See - * the comment on EmitSwitch. - */ -MOZ_NEVER_INLINE static bool -EmitLexicalScope(ExclusiveContext* cx, BytecodeEmitter* bce, ParseNode* pn) +// Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See +// the comment on emitSwitch. +MOZ_NEVER_INLINE bool +BytecodeEmitter::emitLexicalScope(ParseNode* pn) { MOZ_ASSERT(pn->isKind(PNK_LEXICALSCOPE)); StmtInfoBCE stmtInfo(cx); - if (!EnterBlockScope(cx, bce, &stmtInfo, pn->pn_objbox, JSOP_UNINITIALIZED, 0)) + if (!enterBlockScope(&stmtInfo, pn->pn_objbox, JSOP_UNINITIALIZED, 0)) return false; - if (!bce->emitTree(pn->pn_expr)) + if (!emitTree(pn->pn_expr)) return false; - if (!LeaveNestedScope(cx, bce, &stmtInfo)) + if (!leaveNestedScope(&stmtInfo)) return false; return true; @@ -4753,11 +4647,11 @@ BytecodeEmitter::emitWith(ParseNode *pn) StmtInfoBCE stmtInfo(cx); if (!emitTree(pn->pn_left)) return false; - if (!EnterNestedScope(cx, this, &stmtInfo, pn->pn_binary_obj, STMT_WITH)) + if (!enterNestedScope(&stmtInfo, pn->pn_binary_obj, STMT_WITH)) return false; if (!emitTree(pn->pn_right)) return false; - if (!LeaveNestedScope(cx, this, &stmtInfo)) + if (!leaveNestedScope(&stmtInfo)) return false; return true; } @@ -4787,7 +4681,7 @@ BytecodeEmitter::emitForInOrOfVariables(ParseNode *pn, bool *letDecl) MOZ_ASSERT_IF(*letDecl, pn->isLexical()); // If the left part is 'var x', emit code to define x if necessary using a - // prolog opcode, but do not emit a pop. If it is 'let x', EnterBlockScope + // prolog opcode, but do not emit a pop. If it is 'let x', enterBlockScope // will initialize let bindings in emitForOf and emitForIn with // undefineds. // @@ -4849,21 +4743,21 @@ BytecodeEmitter::emitForOf(StmtType type, ParseNode *pn, ptrdiff_t top) // assigned to is a plain assignment. StmtInfoBCE letStmt(cx); if (letDecl) { - if (!EnterBlockScope(cx, this, &letStmt, pn1->pn_objbox, JSOP_UNDEFINED, 0)) + if (!enterBlockScope(&letStmt, pn1->pn_objbox, JSOP_UNDEFINED, 0)) return false; } LoopStmtInfo stmtInfo(cx); - PushLoopStatement(this, &stmtInfo, type, top); + pushLoopStatement(&stmtInfo, type, top); // Jump down to the loop condition to minimize overhead assuming at least // one iteration, as the other loop forms do. Annotate so IonMonkey can // find the loop-closing jump. - int noteIndex = NewSrcNote(cx, this, SRC_FOR_OF); - if (noteIndex < 0) + unsigned noteIndex; + if (!newSrcNote(SRC_FOR_OF, ¬eIndex)) return false; - ptrdiff_t jmp = emitJump(JSOP_GOTO, 0); - if (jmp < 0) + ptrdiff_t jmp; + if (!emitJump(JSOP_GOTO, 0, &jmp)) return false; top = offset(); @@ -4933,14 +4827,14 @@ BytecodeEmitter::emitForOf(StmtType type, ParseNode *pn, ptrdiff_t top) if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ... RESULT DONE? return false; - ptrdiff_t beq = emitJump(JSOP_IFEQ, top - offset()); // ... RESULT - if (beq < 0) + ptrdiff_t beq; + if (!emitJump(JSOP_IFEQ, top - offset(), &beq)) // ... RESULT return false; MOZ_ASSERT(stackDepth == loopDepth); // Let Ion know where the closing jump of this loop is. - if (!setSrcNoteOffset(unsigned(noteIndex), 0, beq - jmp)) + if (!setSrcNoteOffset(noteIndex, 0, beq - jmp)) return false; // Fixup breaks and continues. @@ -4951,7 +4845,7 @@ BytecodeEmitter::emitForOf(StmtType type, ParseNode *pn, ptrdiff_t top) return false; if (letDecl) { - if (!LeaveNestedScope(cx, this, &letStmt)) + if (!leaveNestedScope(&letStmt)) return false; } @@ -4998,24 +4892,24 @@ BytecodeEmitter::emitForIn(ParseNode *pn, ptrdiff_t top) // assigned to is a plain assignment. StmtInfoBCE letStmt(cx); if (letDecl) { - if (!EnterBlockScope(cx, this, &letStmt, pn1->pn_objbox, JSOP_UNDEFINED, 0)) + if (!enterBlockScope(&letStmt, pn1->pn_objbox, JSOP_UNDEFINED, 0)) return false; } LoopStmtInfo stmtInfo(cx); - PushLoopStatement(this, &stmtInfo, STMT_FOR_IN_LOOP, top); + pushLoopStatement(&stmtInfo, STMT_FOR_IN_LOOP, top); /* Annotate so IonMonkey can find the loop-closing jump. */ - int noteIndex = NewSrcNote(cx, this, SRC_FOR_IN); - if (noteIndex < 0) + unsigned noteIndex; + if (!newSrcNote(SRC_FOR_IN, ¬eIndex)) return false; /* * Jump down to the loop condition to minimize overhead assuming at * least one iteration, as the other loop forms do. */ - ptrdiff_t jmp = emitJump(JSOP_GOTO, 0); - if (jmp < 0) + ptrdiff_t jmp; + if (!emitJump(JSOP_GOTO, 0, &jmp)) return false; top = offset(); @@ -5057,12 +4951,12 @@ BytecodeEmitter::emitForIn(ParseNode *pn, ptrdiff_t top) return false; if (!emit1(JSOP_ISNOITER)) return false; - ptrdiff_t beq = emitJump(JSOP_IFEQ, top - offset()); - if (beq < 0) + ptrdiff_t beq; + if (!emitJump(JSOP_IFEQ, top - offset(), &beq)) return false; /* Set the srcnote offset so we can find the closing jump. */ - if (!setSrcNoteOffset(unsigned(noteIndex), 0, beq - jmp)) + if (!setSrcNoteOffset(noteIndex, 0, beq - jmp)) return false; // Fix up breaks and continues. @@ -5078,7 +4972,7 @@ BytecodeEmitter::emitForIn(ParseNode *pn, ptrdiff_t top) return false; if (letDecl) { - if (!LeaveNestedScope(cx, this, &letStmt)) + if (!leaveNestedScope(&letStmt)) return false; } @@ -5089,7 +4983,7 @@ bool BytecodeEmitter::emitNormalFor(ParseNode *pn, ptrdiff_t top) { LoopStmtInfo stmtInfo(cx); - PushLoopStatement(this, &stmtInfo, STMT_FOR_LOOP, top); + pushLoopStatement(&stmtInfo, STMT_FOR_LOOP, top); ParseNode *forHead = pn->pn_left; ParseNode *forBody = pn->pn_right; @@ -5127,16 +5021,17 @@ BytecodeEmitter::emitNormalFor(ParseNode *pn, ptrdiff_t top) * from the top local variable by the length of the JSOP_GOTO * emitted in between tmp and top if this loop has a condition. */ - int noteIndex = NewSrcNote(cx, this, SRC_FOR); - if (noteIndex < 0 || !emit1(op)) + unsigned noteIndex; + if (!newSrcNote(SRC_FOR, ¬eIndex)) + return false; + if (!emit1(op)) return false; ptrdiff_t tmp = offset(); ptrdiff_t jmp = -1; if (forHead->pn_kid2) { /* Goto the loop condition, which branches back to iterate. */ - jmp = emitJump(JSOP_GOTO, 0); - if (jmp < 0) + if (!emitJump(JSOP_GOTO, 0, &jmp)) return false; } else { if (op != JSOP_NOP && !emit1(JSOP_NOP)) @@ -5155,7 +5050,6 @@ BytecodeEmitter::emitNormalFor(ParseNode *pn, ptrdiff_t top) return false; /* Set the second note offset so we can find the update part. */ - MOZ_ASSERT(noteIndex != -1); ptrdiff_t tmp2 = offset(); // Set loop and enclosing "update" offsets, for continue. Note that we @@ -5199,7 +5093,7 @@ BytecodeEmitter::emitNormalFor(ParseNode *pn, ptrdiff_t top) /* Restore the absolute line number for source note readers. */ uint32_t lineNum = parser->tokenStream.srcCoords.lineNum(pn->pn_pos.end); if (currentLine() != lineNum) { - if (NewSrcNote2(cx, this, SRC_SETLINE, ptrdiff_t(lineNum)) < 0) + if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum))) return false; current->currentLine = lineNum; current->lastColumn = 0; @@ -5220,17 +5114,17 @@ BytecodeEmitter::emitNormalFor(ParseNode *pn, ptrdiff_t top) } /* Set the first note offset so we can find the loop condition. */ - if (!setSrcNoteOffset(unsigned(noteIndex), 0, tmp3 - tmp)) + if (!setSrcNoteOffset(noteIndex, 0, tmp3 - tmp)) return false; - if (!setSrcNoteOffset(unsigned(noteIndex), 1, tmp2 - tmp)) + if (!setSrcNoteOffset(noteIndex, 1, tmp2 - tmp)) return false; /* The third note offset helps us find the loop-closing jump. */ - if (!setSrcNoteOffset(unsigned(noteIndex), 2, offset() - tmp)) + if (!setSrcNoteOffset(noteIndex, 2, offset() - tmp)) return false; /* If no loop condition, just emit a loop-closing jump. */ op = forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO; - if (emitJump(op, top - offset()) < 0) + if (!emitJump(op, top - offset())) return false; if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top, offset())) @@ -5254,8 +5148,8 @@ BytecodeEmitter::emitFor(ParseNode *pn, ptrdiff_t top) return emitNormalFor(pn, top); } -static MOZ_NEVER_INLINE bool -EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool needsProto = false) +MOZ_NEVER_INLINE bool +BytecodeEmitter::emitFunction(ParseNode *pn, bool needsProto) { FunctionBox *funbox = pn->pn_funbox; RootedFunction fun(cx, funbox->function()); @@ -5264,12 +5158,12 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool needsPr /* * Set the EMITTEDFUNCTION flag in function definitions once they have been * emitted. Function definitions that need hoisting to the top of the - * function will be seen by EmitFunc in two places. + * function will be seen by emitFunction in two places. */ if (pn->pn_dflags & PND_EMITTEDFUNCTION) { MOZ_ASSERT_IF(fun->hasScript(), fun->nonLazyScript()); MOZ_ASSERT(pn->functionIsHoisted()); - MOZ_ASSERT(bce->sc->isFunctionBox()); + MOZ_ASSERT(sc->isFunctionBox()); return true; } @@ -5282,42 +5176,37 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool needsPr * make a deep clone of its contents. */ if (fun->isInterpreted()) { - bool singleton = - bce->script->compileAndGo() && - fun->isInterpreted() && - (bce->checkSingletonContext() || - (!bce->isInLoop() && bce->isRunOnceLambda())); + bool singleton = checkRunOnceContext(); if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton)) return false; if (fun->isInterpretedLazy()) { if (!fun->lazyScript()->sourceObject()) { - JSObject *scope = EnclosingStaticScope(bce); - JSObject *source = bce->script->sourceObject(); + JSObject *scope = enclosingStaticScope(); + JSObject *source = script->sourceObject(); fun->lazyScript()->setParent(scope, &source->as()); } - if (bce->emittingRunOnceLambda) + if (emittingRunOnceLambda) fun->lazyScript()->setTreatAsRunOnce(); } else { - SharedContext *outersc = bce->sc; + SharedContext *outersc = sc; if (outersc->isFunctionBox() && outersc->asFunctionBox()->mightAliasLocals()) funbox->setMightAliasLocals(); // inherit mightAliasLocals from parent MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript); // Inherit most things (principals, version, etc) from the parent. - Rooted parent(cx, bce->script); - CompileOptions options(cx, bce->parser->options()); + Rooted parent(cx, script); + CompileOptions options(cx, parser->options()); options.setMutedErrors(parent->mutedErrors()) - .setCompileAndGo(parent->compileAndGo()) .setHasPollutedScope(parent->hasPollutedGlobalScope()) .setSelfHostingMode(parent->selfHosted()) .setNoScriptRval(false) .setForEval(false) .setVersion(parent->getVersion()); - Rooted enclosingScope(cx, EnclosingStaticScope(bce)); - Rooted sourceObject(cx, bce->script->sourceObject()); + Rooted enclosingScope(cx, enclosingStaticScope()); + Rooted sourceObject(cx, script->sourceObject()); Rooted script(cx, JSScript::Create(cx, enclosingScope, false, options, parent->staticLevel() + 1, sourceObject, @@ -5327,16 +5216,16 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool needsPr script->bindings = funbox->bindings; - uint32_t lineNum = bce->parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin); - BytecodeEmitter bce2(bce, bce->parser, funbox, script, /* lazyScript = */ js::NullPtr(), - bce->insideEval, bce->evalCaller, + uint32_t lineNum = parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin); + BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ js::NullPtr(), + insideEval, evalCaller, /* evalStaticScope = */ js::NullPtr(), - bce->insideNonGlobalEval, lineNum, bce->emitterMode); + insideNonGlobalEval, lineNum, emitterMode); if (!bce2.init()) return false; /* We measured the max scope depth when we parsed the function. */ - if (!EmitFunctionScript(cx, &bce2, pn->pn_body)) + if (!bce2.emitFunctionScript(pn->pn_body)) return false; if (funbox->usesArguments && funbox->usesApply && funbox->usesThis) @@ -5347,19 +5236,19 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool needsPr } /* Make the function object a literal in the outer script's pool. */ - unsigned index = bce->objectList.add(pn->pn_funbox); + unsigned index = objectList.add(pn->pn_funbox); /* Non-hoisted functions simply emit their respective op. */ if (!pn->functionIsHoisted()) { /* JSOP_LAMBDA_ARROW is always preceded by JSOP_THIS. */ MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW)); - if (fun->isArrow() && !bce->emit1(JSOP_THIS)) + if (fun->isArrow() && !emit1(JSOP_THIS)) return false; if (needsProto) { MOZ_ASSERT(pn->getOp() == JSOP_LAMBDA); pn->setOp(JSOP_FUNWITHPROTO); } - return bce->emitIndex32(pn->getOp(), index); + return emitIndex32(pn->getOp(), index); } MOZ_ASSERT(!needsProto); @@ -5373,19 +5262,19 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool needsPr * invocation of the emitter and calls to emitTree for function * definitions can be scheduled before generating the rest of code. */ - if (!bce->sc->isFunctionBox()) { + if (!sc->isFunctionBox()) { MOZ_ASSERT(pn->pn_cookie.isFree()); MOZ_ASSERT(pn->getOp() == JSOP_NOP); - MOZ_ASSERT(!bce->topStmt); - bce->switchToProlog(); - if (!bce->emitIndex32(JSOP_DEFFUN, index)) + MOZ_ASSERT(!topStmt); + switchToProlog(); + if (!emitIndex32(JSOP_DEFFUN, index)) return false; - if (!bce->updateSourceCoordNotes(pn->pn_pos.begin)) + if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false; - bce->switchToMain(); + switchToMain(); } else { #ifdef DEBUG - BindingIter bi(bce->script); + BindingIter bi(script); while (bi->name() != fun->atom()) bi++; MOZ_ASSERT(bi->kind() == Binding::VARIABLE || bi->kind() == Binding::CONSTANT || @@ -5393,13 +5282,13 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool needsPr MOZ_ASSERT(bi.argOrLocalIndex() < JS_BIT(20)); #endif pn->pn_index = index; - if (!bce->emitIndexOp(JSOP_LAMBDA, index)) + if (!emitIndexOp(JSOP_LAMBDA, index)) return false; MOZ_ASSERT(pn->getOp() == JSOP_GETLOCAL || pn->getOp() == JSOP_GETARG); JSOp setOp = pn->getOp() == JSOP_GETLOCAL ? JSOP_SETLOCAL : JSOP_SETARG; - if (!bce->emitVarOp(pn, setOp)) + if (!emitVarOp(pn, setOp)) return false; - if (!bce->emit1(JSOP_POP)) + if (!emit1(JSOP_POP)) return false; } @@ -5410,12 +5299,14 @@ bool BytecodeEmitter::emitDo(ParseNode *pn) { /* Emit an annotated nop so IonBuilder can recognize the 'do' loop. */ - ptrdiff_t noteIndex = NewSrcNote(cx, this, SRC_WHILE); - if (noteIndex < 0 || !emit1(JSOP_NOP)) + unsigned noteIndex; + if (!newSrcNote(SRC_WHILE, ¬eIndex)) + return false; + if (!emit1(JSOP_NOP)) return false; - ptrdiff_t noteIndex2 = NewSrcNote(cx, this, SRC_WHILE); - if (noteIndex2 < 0) + unsigned noteIndex2; + if (!newSrcNote(SRC_WHILE, ¬eIndex2)) return false; /* Compile the loop body. */ @@ -5424,7 +5315,7 @@ BytecodeEmitter::emitDo(ParseNode *pn) return false; LoopStmtInfo stmtInfo(cx); - PushLoopStatement(this, &stmtInfo, STMT_DO_LOOP, top); + pushLoopStatement(&stmtInfo, STMT_DO_LOOP, top); if (!emitLoopEntry(nullptr)) return false; @@ -5443,8 +5334,8 @@ BytecodeEmitter::emitDo(ParseNode *pn) if (!emitTree(pn->pn_right)) return false; - ptrdiff_t beq = emitJump(JSOP_IFNE, top - offset()); - if (beq < 0) + ptrdiff_t beq; + if (!emitJump(JSOP_IFNE, top - offset(), &beq)) return false; if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top, offset())) @@ -5483,14 +5374,14 @@ BytecodeEmitter::emitWhile(ParseNode *pn, ptrdiff_t top) * N N*(ifeq-fail; goto); ifeq-pass goto; N*ifne-pass; ifne-fail */ LoopStmtInfo stmtInfo(cx); - PushLoopStatement(this, &stmtInfo, STMT_WHILE_LOOP, top); + pushLoopStatement(&stmtInfo, STMT_WHILE_LOOP, top); - ptrdiff_t noteIndex = NewSrcNote(cx, this, SRC_WHILE); - if (noteIndex < 0) + unsigned noteIndex; + if (!newSrcNote(SRC_WHILE, ¬eIndex)) return false; - ptrdiff_t jmp = emitJump(JSOP_GOTO, 0); - if (jmp < 0) + ptrdiff_t jmp; + if (!emitJump(JSOP_GOTO, 0, &jmp)) return false; top = offset(); @@ -5506,8 +5397,8 @@ BytecodeEmitter::emitWhile(ParseNode *pn, ptrdiff_t top) if (!emitTree(pn->pn_left)) return false; - ptrdiff_t beq = emitJump(JSOP_IFNE, top - offset()); - if (beq < 0) + ptrdiff_t beq; + if (!emitJump(JSOP_IFNE, top - offset(), &beq)) return false; if (!tryNoteList.append(JSTRY_LOOP, stackDepth, top, offset())) @@ -5535,7 +5426,7 @@ BytecodeEmitter::emitBreak(PropertyName *label) noteType = (stmt->type == STMT_SWITCH) ? SRC_SWITCHBREAK : SRC_BREAK; } - return emitGoto(stmt, &stmt->breaks, noteType) >= 0; + return emitGoto(stmt, &stmt->breaks, noteType); } bool @@ -5556,13 +5447,13 @@ BytecodeEmitter::emitContinue(PropertyName *label) stmt = stmt->down; } - return emitGoto(stmt, &stmt->continues, SRC_CONTINUE) >= 0; + return emitGoto(stmt, &stmt->continues, SRC_CONTINUE); } -static bool -InTryBlockWithFinally(BytecodeEmitter *bce) +bool +BytecodeEmitter::inTryBlockWithFinally() { - for (StmtInfoBCE *stmt = bce->topStmt; stmt; stmt = stmt->down) { + for (StmtInfoBCE *stmt = topStmt; stmt; stmt = stmt->down) { if (stmt->type == STMT_FINALLY) return true; } @@ -5611,7 +5502,7 @@ BytecodeEmitter::emitReturn(ParseNode *pn) bool isGenerator = sc->isFunctionBox() && sc->asFunctionBox()->isGenerator(); bool useGenRVal = false; if (isGenerator) { - if (sc->asFunctionBox()->isStarGenerator() && InTryBlockWithFinally(this)) { + if (sc->asFunctionBox()->isStarGenerator() && inTryBlockWithFinally()) { // Emit JSOP_SETALIASEDVAR .genrval to store the return value on the // scope chain, so it's not lost when we yield in a finally block. useGenRVal = true; @@ -5629,7 +5520,7 @@ BytecodeEmitter::emitReturn(ParseNode *pn) return false; } - NonLocalExitScope nle(cx, this); + NonLocalExitScope nle(this); if (!nle.prepareForNonLocalJump(nullptr)) return false; @@ -5640,14 +5531,14 @@ BytecodeEmitter::emitReturn(ParseNode *pn) // as we just exited nested scopes. sc.setHops(0); if (useGenRVal) { - MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(this, script, cx->names().dotGenRVal, &sc)); + MOZ_ALWAYS_TRUE(lookupAliasedNameSlot(cx->names().dotGenRVal, &sc)); if (!emitAliasedVarOp(JSOP_GETALIASEDVAR, sc, DontCheckLexical)) return false; if (!emit1(JSOP_SETRVAL)) return false; } - MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(this, script, cx->names().dotGenerator, &sc)); + MOZ_ALWAYS_TRUE(lookupAliasedNameSlot(cx->names().dotGenerator, &sc)); if (!emitAliasedVarOp(JSOP_GETALIASEDVAR, sc, DontCheckLexical)) return false; if (!emitYieldOp(JSOP_FINALYIELDRVAL)) @@ -5723,9 +5614,11 @@ BytecodeEmitter::emitYieldStar(ParseNode *iter, ParseNode *gen) // Try prologue. // ITER RESULT StmtInfoBCE stmtInfo(cx); pushStatement(&stmtInfo, STMT_TRY, offset()); - ptrdiff_t noteIndex = NewSrcNote(cx, this, SRC_TRY); + unsigned noteIndex; + if (!newSrcNote(SRC_TRY, ¬eIndex)) + return false; ptrdiff_t tryStart = offset(); // tryStart: - if (noteIndex < 0 || !emit1(JSOP_TRY)) + if (!emit1(JSOP_TRY)) return false; MOZ_ASSERT(this->stackDepth == depth); @@ -5763,8 +5656,8 @@ BytecodeEmitter::emitYieldStar(ParseNode *iter, ParseNode *gen) if (!emit1(JSOP_IN)) // EXCEPTION ITER THROW? return false; // if (THROW?) goto delegate - ptrdiff_t checkThrow = emitJump(JSOP_IFNE, 0); // EXCEPTION ITER - if (checkThrow < 0) + ptrdiff_t checkThrow; + if (!emitJump(JSOP_IFNE, 0, &checkThrow)) // EXCEPTION ITER return false; if (!emit1(JSOP_POP)) // EXCEPTION return false; @@ -5832,7 +5725,7 @@ BytecodeEmitter::emitYieldStar(ParseNode *iter, ParseNode *gen) if (!emitAtomOp(cx->names().done, JSOP_GETPROP)) // ITER RESULT DONE return false; // if (!DONE) goto tryStart; - if (emitJump(JSOP_IFEQ, tryStart - offset()) < 0) // ITER RESULT + if (!emitJump(JSOP_IFEQ, tryStart - offset())) // ITER RESULT return false; // result.value @@ -5900,7 +5793,7 @@ BytecodeEmitter::emitStatement(ParseNode *pn) /* Don't eliminate expressions with side effects. */ if (!useful) { - if (!CheckSideEffects(cx, this, pn2, &useful)) + if (!checkSideEffects(pn2, &useful)) return false; /* @@ -5997,7 +5890,7 @@ BytecodeEmitter::emitDelete(ParseNode *pn) * to foo(), true (a comma expression). */ bool useful = false; - if (!CheckSideEffects(cx, this, pn2, &useful)) + if (!checkSideEffects(pn2, &useful)) return false; if (useful) { @@ -6173,7 +6066,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode *pn) * will just cause the inner scripts to be repeatedly cloned. */ MOZ_ASSERT(!emittingRunOnceLambda); - if (checkSingletonContext() || (!isInLoop() && isRunOnceLambda())) { + if (checkRunOnceContext()) { emittingRunOnceLambda = true; if (!emitTree(pn2)) return false; @@ -6257,8 +6150,8 @@ BytecodeEmitter::emitLogical(ParseNode *pn) ParseNode *pn2 = pn->pn_head; if (!emitTree(pn2)) return false; - ptrdiff_t top = emitJump(JSOP_BACKPATCH, 0); - if (top < 0) + ptrdiff_t top; + if (!emitJump(JSOP_BACKPATCH, 0, &top)) return false; if (!emit1(JSOP_POP)) return false; @@ -6268,8 +6161,8 @@ BytecodeEmitter::emitLogical(ParseNode *pn) while ((pn2 = pn2->pn_next)->pn_next) { if (!emitTree(pn2)) return false; - ptrdiff_t off = emitJump(JSOP_BACKPATCH, 0); - if (off < 0) + ptrdiff_t off; + if (!emitJump(JSOP_BACKPATCH, 0, &off)) return false; if (!emit1(JSOP_POP)) return false; @@ -6371,52 +6264,56 @@ BytecodeEmitter::emitIncOrDec(ParseNode *pn) return true; } -/* - * Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See - * the comment on EmitSwitch. - */ -MOZ_NEVER_INLINE static bool -EmitLabeledStatement(ExclusiveContext *cx, BytecodeEmitter *bce, const LabeledStatement *pn) +// Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See +// the comment on emitSwitch. +MOZ_NEVER_INLINE bool +BytecodeEmitter::emitLabeledStatement(const LabeledStatement *pn) { /* * Emit a JSOP_LABEL instruction. The argument is the offset to the statement * following the labeled statement. */ jsatomid index; - if (!bce->makeAtomIndex(pn->label(), &index)) + if (!makeAtomIndex(pn->label(), &index)) return false; - ptrdiff_t top = bce->emitJump(JSOP_LABEL, 0); - if (top < 0) + ptrdiff_t top; + if (!emitJump(JSOP_LABEL, 0, &top)) return false; /* Emit code for the labeled statement. */ StmtInfoBCE stmtInfo(cx); - bce->pushStatement(&stmtInfo, STMT_LABEL, bce->offset()); + pushStatement(&stmtInfo, STMT_LABEL, offset()); stmtInfo.label = pn->label(); - if (!bce->emitTree(pn->statement())) + + if (!emitTree(pn->statement())) return false; - bce->popStatement(); + + popStatement(); /* Patch the JSOP_LABEL offset. */ - bce->setJumpOffsetAt(top); + setJumpOffsetAt(top); return true; } -static bool -EmitSyntheticStatements(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top) +bool +BytecodeEmitter::emitSyntheticStatements(ParseNode *pn, ptrdiff_t top) { MOZ_ASSERT(pn->isArity(PN_LIST)); + StmtInfoBCE stmtInfo(cx); - bce->pushStatement(&stmtInfo, STMT_SEQ, top); + pushStatement(&stmtInfo, STMT_SEQ, top); + ParseNode *pn2 = pn->pn_head; if (pn->pn_xflags & PNX_DESTRUCT) pn2 = pn2->pn_next; + for (; pn2; pn2 = pn2->pn_next) { - if (!bce->emitTree(pn2)) + if (!emitTree(pn2)) return false; } - bce->popStatement(); + + popStatement(); return true; } @@ -6426,16 +6323,21 @@ BytecodeEmitter::emitConditionalExpression(ConditionalExpression &conditional) /* Emit the condition, then branch if false to the else part. */ if (!emitTree(&conditional.condition())) return false; - ptrdiff_t noteIndex = NewSrcNote(cx, this, SRC_COND); - if (noteIndex < 0) + + unsigned noteIndex; + if (!newSrcNote(SRC_COND, ¬eIndex)) return false; - ptrdiff_t beq = emitJump(JSOP_IFEQ, 0); - if (beq < 0 || !emitTree(&conditional.thenExpression())) + + ptrdiff_t beq; + if (!emitJump(JSOP_IFEQ, 0, &beq)) + return false; + + if (!emitTree(&conditional.thenExpression())) return false; /* Jump around else, fixup the branch, emit else, fixup jump. */ - ptrdiff_t jmp = emitJump(JSOP_GOTO, 0); - if (jmp < 0) + ptrdiff_t jmp; + if (!emitJump(JSOP_GOTO, 0, &jmp)) return false; setJumpOffsetAt(beq); @@ -6588,12 +6490,12 @@ BytecodeEmitter::emitObject(ParseNode *pn) * JSOP_NEWOBJECT with the final shape instead. */ RootedPlainObject obj(cx); - if (script->compileAndGo()) { - gc::AllocKind kind = GuessObjectGCKind(pn->pn_count); - obj = NewBuiltinClassInstance(cx, kind, TenuredObject); - if (!obj) - return false; - } + // No need to do any guessing for the object kind, since we know exactly + // how many properties we plan to have. + gc::AllocKind kind = gc::GetGCObjectKind(pn->pn_count); + obj = NewBuiltinClassInstance(cx, kind, TenuredObject); + if (!obj) + return false; if (!emitPropertyList(pn, &obj, ObjectLiteral)) return false; @@ -6667,8 +6569,8 @@ BytecodeEmitter::emitArray(ParseNode *pn, uint32_t count) nspread++; } - ptrdiff_t off = emitN(JSOP_NEWARRAY, 3); // ARRAY - if (off < 0) + ptrdiff_t off; + if (!emitN(JSOP_NEWARRAY, 3, &off)) // ARRAY return false; checkTypeSet(JSOP_NEWARRAY); jsbytecode *pc = code(off); @@ -6709,8 +6611,7 @@ BytecodeEmitter::emitArray(ParseNode *pn, uint32_t count) if (!emit1(JSOP_INITELEM_INC)) return false; } else { - off = emitN(JSOP_INITELEM_ARRAY, 3); - if (off < 0) + if (!emitN(JSOP_INITELEM_ARRAY, 3, &off)) return false; SET_UINT24(code(off), atomIndex); } @@ -6750,8 +6651,8 @@ BytecodeEmitter::emitDefaults(ParseNode *pn) { MOZ_ASSERT(pn->isKind(PNK_ARGSBODY)); - ParseNode *arg, *pnlast = pn->last(); - for (arg = pn->pn_head; arg != pnlast; arg = arg->pn_next) { + ParseNode* pnlast = pn->last(); + for (ParseNode* arg = pn->pn_head; arg != pnlast; arg = arg->pn_next) { if (!(arg->pn_dflags & PND_DEFAULT)) continue; if (!bindNameToSlot(arg)) @@ -6763,10 +6664,10 @@ BytecodeEmitter::emitDefaults(ParseNode *pn) if (!emit1(JSOP_STRICTEQ)) return false; // Emit source note to enable ion compilation. - if (NewSrcNote(cx, this, SRC_IF) < 0) + if (!newSrcNote(SRC_IF)) return false; - ptrdiff_t jump = emitJump(JSOP_IFEQ, 0); - if (jump < 0) + ptrdiff_t jump; + if (!emitJump(JSOP_IFEQ, 0, &jump)) return false; if (!emitTree(arg->expr())) return false; @@ -6848,7 +6749,7 @@ BytecodeEmitter::emitClass(ParseNode *pn) StmtInfoBCE stmtInfo(cx); if (names) { - if (!EnterBlockScope(cx, this, &stmtInfo, classNode.scopeObject(), JSOP_UNINITIALIZED)) + if (!enterBlockScope(&stmtInfo, classNode.scopeObject(), JSOP_UNINITIALIZED)) return false; } @@ -6859,7 +6760,7 @@ BytecodeEmitter::emitClass(ParseNode *pn) return false; } - if (!EmitFunc(cx, this, constructor, !!heritageExpression)) + if (!emitFunction(constructor, !!heritageExpression)) return false; if (heritageExpression) { @@ -6894,7 +6795,7 @@ BytecodeEmitter::emitClass(ParseNode *pn) if (!emitLexicalInitialization(innerName, JSOP_DEFCONST)) return false; - if (!LeaveNestedScope(cx, this, &stmtInfo)) + if (!leaveNestedScope(&stmtInfo)) return false; ParseNode *outerName = names->outerBinding(); @@ -6930,7 +6831,7 @@ BytecodeEmitter::emitTree(ParseNode *pn) switch (pn->getKind()) { case PNK_FUNCTION: - ok = EmitFunc(cx, this, pn); + ok = emitFunction(pn); break; case PNK_ARGSBODY: @@ -7104,7 +7005,7 @@ BytecodeEmitter::emitTree(ParseNode *pn) break; case PNK_SEQ: - ok = EmitSyntheticStatements(cx, this, pn, top); + ok = emitSyntheticStatements(pn, top); break; case PNK_SEMI: @@ -7112,7 +7013,7 @@ BytecodeEmitter::emitTree(ParseNode *pn) break; case PNK_LABEL: - ok = EmitLabeledStatement(cx, this, &pn->as()); + ok = emitLabeledStatement(&pn->as()); break; case PNK_COMMA: @@ -7243,11 +7144,11 @@ BytecodeEmitter::emitTree(ParseNode *pn) break; case PNK_LEXICALSCOPE: - ok = EmitLexicalScope(cx, this, pn); + ok = emitLexicalScope(pn); break; case PNK_LETBLOCK: - ok = EmitLetBlock(cx, this, pn); + ok = emitLetBlock(pn); break; case PNK_CONST: @@ -7388,47 +7289,45 @@ BytecodeEmitter::emitTree(ParseNode *pn) return ok; } -static int -AllocSrcNote(ExclusiveContext* cx, SrcNotesVector& notes) +static bool +AllocSrcNote(ExclusiveContext* cx, SrcNotesVector& notes, unsigned* index) { // Start it off moderately large to avoid repeated resizings early on. // ~99% of cases fit within 256 bytes. if (notes.capacity() == 0 && !notes.reserve(256)) - return -1; + return false; - jssrcnote dummy = 0; - if (!notes.append(dummy)) { + if (!notes.growBy(1)) { ReportOutOfMemory(cx); - return -1; + return false; } - return notes.length() - 1; + + *index = notes.length() - 1; + return true; } -int -frontend::NewSrcNote(ExclusiveContext* cx, BytecodeEmitter* bce, SrcNoteType type) +bool +BytecodeEmitter::newSrcNote(SrcNoteType type, unsigned* indexp) { - SrcNotesVector& notes = bce->notes(); - int index; - - index = AllocSrcNote(cx, notes); - if (index < 0) - return -1; + SrcNotesVector& notes = this->notes(); + unsigned index; + if (!AllocSrcNote(cx, notes, &index)) + return false; /* * Compute delta from the last annotated bytecode's offset. If it's too * big to fit in sn, allocate one or more xdelta notes and reset sn. */ - ptrdiff_t offset = bce->offset(); - ptrdiff_t delta = offset - bce->lastNoteOffset(); - bce->current->lastNoteOffset = offset; + ptrdiff_t offset = this->offset(); + ptrdiff_t delta = offset - lastNoteOffset(); + current->lastNoteOffset = offset; if (delta >= SN_DELTA_LIMIT) { do { ptrdiff_t xdelta = Min(delta, SN_XDELTA_MASK); SN_MAKE_XDELTA(¬es[index], xdelta); delta -= xdelta; - index = AllocSrcNote(cx, notes); - if (index < 0) - return -1; + if (!AllocSrcNote(cx, notes, &index)) + return false; } while (delta >= SN_DELTA_LIMIT); } @@ -7439,49 +7338,52 @@ frontend::NewSrcNote(ExclusiveContext* cx, BytecodeEmitter* bce, SrcNoteType typ */ SN_MAKE_NOTE(¬es[index], type, delta); for (int n = (int)js_SrcNoteSpec[type].arity; n > 0; n--) { - if (NewSrcNote(cx, bce, SRC_NULL) < 0) - return -1; + if (!newSrcNote(SRC_NULL)) + return false; } - return index; -} -int -frontend::NewSrcNote2(ExclusiveContext* cx, BytecodeEmitter* bce, SrcNoteType type, ptrdiff_t offset) -{ - int index; - - index = NewSrcNote(cx, bce, type); - if (index >= 0) { - if (!bce->setSrcNoteOffset(index, 0, offset)) - return -1; - } - return index; -} - -int -frontend::NewSrcNote3(ExclusiveContext* cx, BytecodeEmitter* bce, SrcNoteType type, ptrdiff_t offset1, - ptrdiff_t offset2) -{ - int index; - - index = NewSrcNote(cx, bce, type); - if (index >= 0) { - if (!bce->setSrcNoteOffset(index, 0, offset1)) - return -1; - if (!bce->setSrcNoteOffset(index, 1, offset2)) - return -1; - } - return index; + if (indexp) + *indexp = index; + return true; } bool -frontend::AddToSrcNoteDelta(ExclusiveContext* cx, BytecodeEmitter* bce, jssrcnote* sn, ptrdiff_t delta) +BytecodeEmitter::newSrcNote2(SrcNoteType type, ptrdiff_t offset, unsigned *indexp) +{ + unsigned index; + if (!newSrcNote(type, &index)) + return false; + if (!setSrcNoteOffset(index, 0, offset)) + return false; + if (indexp) + *indexp = index; + return true; +} + +bool +BytecodeEmitter::newSrcNote3(SrcNoteType type, ptrdiff_t offset1, ptrdiff_t offset2, + unsigned *indexp) +{ + unsigned index; + if (!newSrcNote(type, &index)) + return false; + if (!setSrcNoteOffset(index, 0, offset1)) + return false; + if (!setSrcNoteOffset(index, 1, offset2)) + return false; + if (indexp) + *indexp = index; + return true; +} + +bool +BytecodeEmitter::addToSrcNoteDelta(jssrcnote* sn, ptrdiff_t delta) { /* - * Called only from FinishTakingSrcNotes to add to main script note + * Called only from finishTakingSrcNotes to add to main script note * deltas, and only by a small positive amount. */ - MOZ_ASSERT(bce->current == &bce->main); + MOZ_ASSERT(current == &main); MOZ_ASSERT((unsigned) delta < (unsigned) SN_XDELTA_LIMIT); ptrdiff_t base = SN_DELTA(sn); @@ -7492,7 +7394,7 @@ frontend::AddToSrcNoteDelta(ExclusiveContext* cx, BytecodeEmitter* bce, jssrcnot } else { jssrcnote xdelta; SN_MAKE_XDELTA(&xdelta, delta); - if (!(sn = bce->main.notes.insert(sn, xdelta))) + if (!main.notes.insert(sn, xdelta)) return false; } return true; @@ -7509,7 +7411,7 @@ BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offs SrcNotesVector& notes = this->notes(); /* Find the offset numbered which (i.e., skip exactly which offsets). */ - jssrcnote *sn = notes.begin() + index; + jssrcnote *sn = ¬es[index]; MOZ_ASSERT(SN_TYPE(sn) != SRC_XDELTA); MOZ_ASSERT((int) which < js_SrcNoteSpec[SN_TYPE(sn)].arity); for (sn++; which; sn++, which--) { @@ -7543,21 +7445,17 @@ BytecodeEmitter::setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offs return true; } -/* - * Finish taking source notes in cx's notePool. - * If successful, the final source note count is stored in the out outparam. - */ bool -frontend::FinishTakingSrcNotes(ExclusiveContext* cx, BytecodeEmitter* bce, uint32_t* out) +BytecodeEmitter::finishTakingSrcNotes(uint32_t* out) { - MOZ_ASSERT(bce->current == &bce->main); + MOZ_ASSERT(current == &main); - unsigned prologCount = bce->prolog.notes.length(); - if (prologCount && bce->prolog.currentLine != bce->firstLine) { - bce->switchToProlog(); - if (NewSrcNote2(cx, bce, SRC_SETLINE, (ptrdiff_t)bce->firstLine) < 0) + unsigned prologCount = prolog.notes.length(); + if (prologCount && prolog.currentLine != firstLine) { + switchToProlog(); + if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(firstLine))) return false; - bce->switchToMain(); + switchToMain(); } else { /* * Either no prolog srcnotes, or no line number change over prolog. @@ -7566,24 +7464,24 @@ frontend::FinishTakingSrcNotes(ExclusiveContext* cx, BytecodeEmitter* bce, uint3 * prepending SRC_XDELTA notes to it to account for prolog bytecodes * that came at and after the last annotated bytecode. */ - ptrdiff_t offset = bce->prologOffset() - bce->prolog.lastNoteOffset; + ptrdiff_t offset = prologOffset() - prolog.lastNoteOffset; MOZ_ASSERT(offset >= 0); - if (offset > 0 && bce->main.notes.length() != 0) { + if (offset > 0 && main.notes.length() != 0) { /* NB: Use as much of the first main note's delta as we can. */ - jssrcnote* sn = bce->main.notes.begin(); + jssrcnote* sn = main.notes.begin(); ptrdiff_t delta = SN_IS_XDELTA(sn) ? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK) : SN_DELTA_MASK - (*sn & SN_DELTA_MASK); if (offset < delta) delta = offset; for (;;) { - if (!AddToSrcNoteDelta(cx, bce, sn, delta)) + if (!addToSrcNoteDelta(sn, delta)) return false; offset -= delta; if (offset == 0) break; delta = Min(offset, SN_XDELTA_MASK); - sn = bce->main.notes.begin(); + sn = main.notes.begin(); } } } @@ -7591,20 +7489,20 @@ frontend::FinishTakingSrcNotes(ExclusiveContext* cx, BytecodeEmitter* bce, uint3 // The prolog count might have changed, so we can't reuse prologCount. // The + 1 is to account for the final SN_MAKE_TERMINATOR that is appended // when the notes are copied to their final destination by CopySrcNotes. - *out = bce->prolog.notes.length() + bce->main.notes.length() + 1; + *out = prolog.notes.length() + main.notes.length() + 1; return true; } void -frontend::CopySrcNotes(BytecodeEmitter* bce, jssrcnote* destination, uint32_t nsrcnotes) +BytecodeEmitter::copySrcNotes(jssrcnote* destination, uint32_t nsrcnotes) { - unsigned prologCount = bce->prolog.notes.length(); - unsigned mainCount = bce->main.notes.length(); + unsigned prologCount = prolog.notes.length(); + unsigned mainCount = main.notes.length(); unsigned totalCount = prologCount + mainCount; MOZ_ASSERT(totalCount == nsrcnotes - 1); if (prologCount) - PodCopy(destination, bce->prolog.notes.begin(), prologCount); - PodCopy(destination + prologCount, bce->main.notes.begin(), mainCount); + PodCopy(destination, prolog.notes.begin(), prologCount); + PodCopy(destination + prologCount, main.notes.begin(), mainCount); SN_MAKE_TERMINATOR(&destination[totalCount]); } @@ -7689,6 +7587,7 @@ CGObjectList::finish(ObjectArray* array) do { --cursor; MOZ_ASSERT(!*cursor); + MOZ_ASSERT(objbox->object->isTenured()); *cursor = objbox->object; } while ((objbox = objbox->emitLink) != nullptr); MOZ_ASSERT(cursor == array->vector); diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 71ee3b4a85..91d1b6d0ea 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -83,6 +83,7 @@ struct CGYieldOffsetList { void finish(YieldOffsetArray& array, uint32_t prologLength); }; +struct LoopStmtInfo; struct StmtInfoBCE; // Use zero inline elements because these go on the stack and affect how many @@ -247,6 +248,10 @@ struct BytecodeEmitter bool isInLoop(); bool checkSingletonContext(); + // Check whether our function is in a run-once context (a toplevel + // run-one script or a run-once lambda). + bool checkRunOnceContext(); + bool needsImplicitThis(); void tellDebuggerAboutCompiledScript(ExclusiveContext* cx); @@ -269,13 +274,50 @@ struct BytecodeEmitter bool reportStrictWarning(ParseNode *pn, unsigned errorNumber, ...); bool reportStrictModeError(ParseNode *pn, unsigned errorNumber, ...); + // If pn contains a useful expression, return true with *answer set to true. + // If pn contains a useless expression, return true with *answer set to + // false. Return false on error. + // + // The caller should initialize *answer to false and invoke this function on + // an expression statement or similar subtree to decide whether the tree + // could produce code that has any side effects. For an expression + // statement, we define useless code as code with no side effects, because + // the main effect, the value left on the stack after the code executes, + // will be discarded by a pop bytecode. + bool checkSideEffects(ParseNode *pn, bool *answer); + + bool inTryBlockWithFinally(); + +#ifdef DEBUG + bool checkStrictOrSloppy(JSOp op); +#endif + + // Append a new source note of the given type (and therefore size) to the + // notes dynamic array, updating noteCount. Return the new note's index + // within the array pointed at by current->notes as outparam. + bool newSrcNote(SrcNoteType type, unsigned *indexp = nullptr); + bool newSrcNote2(SrcNoteType type, ptrdiff_t offset, unsigned *indexp = nullptr); + bool newSrcNote3(SrcNoteType type, ptrdiff_t offset1, ptrdiff_t offset2, + unsigned *indexp = nullptr); + + void copySrcNotes(jssrcnote *destination, uint32_t nsrcnotes); bool setSrcNoteOffset(unsigned index, unsigned which, ptrdiff_t offset); + // NB: this function can add at most one extra extended delta note. + bool addToSrcNoteDelta(jssrcnote *sn, ptrdiff_t delta); + + // Finish taking source notes in cx's notePool. If successful, the final + // source note count is stored in the out outparam. + bool finishTakingSrcNotes(uint32_t *out); + void setJumpOffsetAt(ptrdiff_t off); // Emit code for the tree rooted at pn. bool emitTree(ParseNode *pn); + // Emit function code for the tree rooted at body. + bool emitFunctionScript(ParseNode *body); + // If op is JOF_TYPESET (see the type barriers comment in TypeInference.h), // reserve a type set to store its result. void checkTypeSet(JSOp op); @@ -285,14 +327,51 @@ struct BytecodeEmitter bool updateSourceCoordNotes(uint32_t offset); bool bindNameToSlot(ParseNode *pn); + bool bindNameToSlotHelper(ParseNode *pn); + + void strictifySetNameNode(ParseNode *pn); + JSOp strictifySetNameOp(JSOp op); + + bool tryConvertFreeName(ParseNode *pn); void popStatement(); void pushStatement(StmtInfoBCE *stmt, StmtType type, ptrdiff_t top); void pushStatementInner(StmtInfoBCE *stmt, StmtType type, ptrdiff_t top); + void pushLoopStatement(LoopStmtInfo *stmt, StmtType type, ptrdiff_t top); + + // Return the enclosing lexical scope, which is the innermost enclosing static + // block object or compiler created function. + JSObject *enclosingStaticScope(); + + // Compute the number of nested scope objects that will actually be on the + // scope chain at runtime, given the current staticScope. + unsigned dynamicNestedScopeDepth(); + + bool enterNestedScope(StmtInfoBCE *stmt, ObjectBox *objbox, StmtType stmtType); + bool leaveNestedScope(StmtInfoBCE *stmt); + + bool enterBlockScope(StmtInfoBCE *stmtInfo, ObjectBox *objbox, JSOp initialValueOp, + unsigned alreadyPushed = 0); + + bool computeAliasedSlots(Handle blockObj); + + bool lookupAliasedName(HandleScript script, PropertyName *name, uint32_t *pslot, + ParseNode *pn = nullptr); + bool lookupAliasedNameSlot(PropertyName *name, ScopeCoordinate *sc); + + // Use this function instead of assigning directly to 'hops' to guard for + // uint8_t overflows. + bool assignHops(ParseNode *pn, unsigned src, ScopeCoordinate *dst); + + // In a function, block-scoped locals go after the vars, and form part of the + // fixed part of a stack frame. Outside a function, there are no fixed vars, + // but block-scoped locals still form part of the fixed part of a stack frame + // and are thus addressable via GETLOCAL and friends. + void computeLocalOffset(Handle blockObj); bool flushPops(int *npops); - ptrdiff_t emitCheck(ptrdiff_t delta); + bool emitCheck(ptrdiff_t delta, ptrdiff_t *offset); // Emit one bytecode. bool emit1(JSOp op); @@ -321,11 +400,11 @@ struct BytecodeEmitter bool emitUint16Operand(JSOp op, uint32_t i); // Emit (1 + extra) bytecodes, for N bytes of op and its immediate operand. - ptrdiff_t emitN(JSOp op, size_t extra); + bool emitN(JSOp op, size_t extra, ptrdiff_t *offset = nullptr); bool emitNumberOp(double dval); - ptrdiff_t emitJump(JSOp op, ptrdiff_t off); + bool emitJump(JSOp op, ptrdiff_t off, ptrdiff_t *jumpOffset = nullptr); bool emitCall(JSOp op, uint16_t argc, ParseNode *pn = nullptr); bool emitLoopHead(ParseNode *nextpn); @@ -337,7 +416,7 @@ struct BytecodeEmitter bool emitBackPatchOp(ptrdiff_t *lastp); void backPatch(ptrdiff_t last, jsbytecode *target, jsbytecode op); - ptrdiff_t emitGoto(StmtInfoBCE *toStmt, ptrdiff_t *lastp, SrcNoteType noteType = SRC_NULL); + bool emitGoto(StmtInfoBCE *toStmt, ptrdiff_t *lastp, SrcNoteType noteType = SRC_NULL); bool emitIndex32(JSOp op, uint32_t index); bool emitIndexOp(JSOp op, uint32_t index); @@ -353,6 +432,7 @@ struct BytecodeEmitter bool emitObjectPairOp(ObjectBox *objbox1, ObjectBox *objbox2, JSOp op); bool emitRegExp(uint32_t index); + MOZ_NEVER_INLINE bool emitFunction(ParseNode *pn, bool needsProto = false); MOZ_NEVER_INLINE bool emitObject(ParseNode *pn); bool emitPropertyList(ParseNode *pn, MutableHandlePlainObject objp, PropListType type); @@ -383,6 +463,7 @@ struct BytecodeEmitter bool emitPrepareIteratorResult(); bool emitFinishIteratorResult(bool done); + bool iteratorResultShape(unsigned *shape); bool emitYield(ParseNode *pn); bool emitYieldOp(JSOp op); @@ -405,6 +486,9 @@ struct BytecodeEmitter bool emitIf(ParseNode *pn); bool emitWith(ParseNode *pn); + MOZ_NEVER_INLINE bool emitLabeledStatement(const LabeledStatement *pn); + MOZ_NEVER_INLINE bool emitLetBlock(ParseNode *pnLet); + MOZ_NEVER_INLINE bool emitLexicalScope(ParseNode *pn); MOZ_NEVER_INLINE bool emitSwitch(ParseNode *pn); MOZ_NEVER_INLINE bool emitTry(ParseNode *pn); @@ -420,6 +504,23 @@ struct BytecodeEmitter // lhs expression. (Same post-condition as EmitDestructuringOpsHelper) bool emitDestructuringLHS(ParseNode *target, VarEmitOption emitOption); + bool emitDestructuringOps(ParseNode *pattern, bool isLet = false); + bool emitDestructuringOpsHelper(ParseNode *pattern, VarEmitOption emitOption); + bool emitDestructuringOpsArrayHelper(ParseNode *pattern, VarEmitOption emitOption); + bool emitDestructuringOpsObjectHelper(ParseNode *pattern, VarEmitOption emitOption); + + typedef bool + (*DestructuringDeclEmitter)(BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn); + + template + bool emitDestructuringDeclsWithEmitter(JSOp prologOp, ParseNode *pattern); + + bool emitDestructuringDecls(JSOp prologOp, ParseNode *pattern); + + // Emit code to initialize all destructured names to the value on the top of + // the stack. + bool emitInitializeDestructuringDecls(JSOp prologOp, ParseNode *pattern); + // emitIterator expects the iterable to already be on the stack. // It will replace that stack value with the corresponding iterator bool emitIterator(); @@ -439,6 +540,7 @@ struct BytecodeEmitter bool emitReturn(ParseNode *pn); bool emitStatement(ParseNode *pn); bool emitStatementList(ParseNode *pn, ptrdiff_t top); + bool emitSyntheticStatements(ParseNode *pn, ptrdiff_t top); bool emitDelete(ParseNode *pn); bool emitLogical(ParseNode *pn); @@ -466,6 +568,9 @@ struct BytecodeEmitter bool emitDefaults(ParseNode *pn); bool emitLexicalInitialization(ParseNode *pn, JSOp globalDefOp); + bool pushInitialConstants(JSOp op, unsigned n); + bool initializeBlockScopedLocalsFromStack(Handle blockObj); + // emitSpread expects the current index (I) of the array, the array itself // and the iterator to be on the stack in that order (iterator on the bottom). // It will pop the iterator and I, then iterate over the iterator by calling @@ -487,38 +592,6 @@ struct BytecodeEmitter bool emitClass(ParseNode *pn); }; -/* - * Emit function code using bce for the tree rooted at body. - */ -bool -EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *body); - -/* - * Append a new source note of the given type (and therefore size) to bce's - * notes dynamic array, updating bce->noteCount. Return the new note's index - * within the array pointed at by bce->current->notes. Return -1 if out of - * memory. - */ -int -NewSrcNote(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type); - -int -NewSrcNote2(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset); - -int -NewSrcNote3(ExclusiveContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset1, - ptrdiff_t offset2); - -/* NB: this function can add at most one extra extended delta note. */ -bool -AddToSrcNoteDelta(ExclusiveContext *cx, BytecodeEmitter *bce, jssrcnote *sn, ptrdiff_t delta); - -bool -FinishTakingSrcNotes(ExclusiveContext *cx, BytecodeEmitter *bce, uint32_t *out); - -void -CopySrcNotes(BytecodeEmitter *bce, jssrcnote *destination, uint32_t nsrcnotes); - } /* namespace frontend */ } /* namespace js */ diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 60a96f3a1b..a194f2bc0f 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -619,7 +619,9 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, bool inGenexpLambda, SyntacticContext sc) { ParseNode* pn = *pnp; - ParseNode* pn1 = nullptr, *pn2 = nullptr, *pn3 = nullptr; + ParseNode* pn1 = nullptr; + ParseNode* pn2 = nullptr; + ParseNode* pn3 = nullptr; JS_CHECK_RECURSION(cx, return false); diff --git a/js/src/frontend/ParseMaps.cpp b/js/src/frontend/ParseMaps.cpp index ee4ff35efa..2e375eb594 100644 --- a/js/src/frontend/ParseMaps.cpp +++ b/js/src/frontend/ParseMaps.cpp @@ -35,7 +35,8 @@ ParseMapPool::checkInvariants() void ParseMapPool::purgeAll() { - for (void** it = all.begin(), **end = all.end(); it != end; ++it) + void** end = all.end(); + for (void** it = all.begin(); it != end; ++it) js_delete(asAtomMap(*it)); all.clearAndFree(); @@ -121,8 +122,8 @@ frontend::InitAtomMap(frontend::AtomIndexMap* indices, HeapPtrAtom* atoms) atoms[index].init(atom); } } else { - for (const AtomIndexMap::InlineElem* it = indices->asInline(), *end = indices->inlineEnd(); - it != end; ++it) { + const AtomIndexMap::InlineElem* end = indices->inlineEnd(); + for (const AtomIndexMap::InlineElem* it = indices->asInline(); it != end; ++it) { JSAtom* atom = it->key; if (!atom) continue; diff --git a/js/src/frontend/ParseMaps.h b/js/src/frontend/ParseMaps.h index fd4bdbbcb1..899a78e0ed 100644 --- a/js/src/frontend/ParseMaps.h +++ b/js/src/frontend/ParseMaps.h @@ -60,14 +60,14 @@ class ParseMapPool #ifdef DEBUG bool ok = false; /* Make sure the map is in |all| but not already in |recyclable|. */ - for (void** it = all.begin(), **end = all.end(); it != end; ++it) { + for (void** it = all.begin(); it != all.end(); ++it) { if (*it == map) { ok = true; break; } } MOZ_ASSERT(ok); - for (void** it = recyclable.begin(), **end = recyclable.end(); it != end; ++it) + for (void** it = recyclable.begin(); it != recyclable.end(); ++it) MOZ_ASSERT(*it != map); #endif MOZ_ASSERT(recyclable.length() < all.length()); diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 690b8fadf2..cf4c186372 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -23,9 +23,14 @@ ParseNode::checkListConsistency() ParseNode** tail; uint32_t count = 0; if (pn_head) { - ParseNode* pn, *last; - for (pn = last = pn_head; pn; last = pn, pn = pn->pn_next, count++) - ; + ParseNode* last = pn_head; + ParseNode* pn = last; + while (pn) { + last = pn; + pn = pn->pn_next; + count++; + } + tail = &last->pn_next; } else { tail = &pn_head; @@ -1109,6 +1114,7 @@ ObjectBox::ObjectBox(JSObject *object, ObjectBox* traceLink) emitLink(nullptr) { MOZ_ASSERT(!object->is()); + MOZ_ASSERT(object->isTenured()); } ObjectBox::ObjectBox(JSFunction *function, ObjectBox* traceLink) @@ -1118,6 +1124,7 @@ ObjectBox::ObjectBox(JSFunction *function, ObjectBox* traceLink) { MOZ_ASSERT(object->is()); MOZ_ASSERT(asFunctionBox()->function() == function); + MOZ_ASSERT(object->isTenured()); } FunctionBox* diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 429fa50fb0..3e6ccebfac 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4556,7 +4556,8 @@ Parser::forStatement() * pc->parsingForInit. */ StmtInfoPC letStmt(context); /* used if blockObj != nullptr. */ - ParseNode* pn2, *pn3; /* forHead->pn_kid2 and pn_kid3. */ + ParseNode* pn2; /* forHead->pn_kid2 */ + ParseNode* pn3; /* forHead->pn_kid3 */ ParseNodeKind headKind = PNK_FORHEAD; if (pn1) { bool isForIn, isForOf; @@ -6716,7 +6717,9 @@ Parser::legacyComprehensionTail(ParseNode* bodyExpr, unsigned } unsigned adjust; - ParseNode* pn, *pn3, **pnp; + ParseNode* pn; + ParseNode* pn3; + ParseNode** pnp; StmtInfoPC stmtInfo(context); BindData data(context); TokenKind tt; diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 99ed92b440..a51f28d917 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1503,7 +1503,8 @@ GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr) } else if (tag == SavedValueArrayTag) { MOZ_ASSERT(!(addr & CellMask)); NativeObject* obj = reinterpret_cast(addr); - HeapValue* vp, *end; + HeapValue* vp; + HeapValue* end; if (restoreValueArray(obj, (void**)&vp, (void**)&end)) pushValueArray(obj, vp, end); else @@ -1543,7 +1544,8 @@ GCMarker::processMarkStackTop(SliceBudget& budget) * object directly. It allows to eliminate the tail recursion and * significantly improve the marking performance, see bug 641025. */ - HeapSlot* vp, *end; + HeapSlot* vp; + HeapSlot* end; JSObject* obj; const int32_t* unboxedTraceList; diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index 4b4273002a..d92c52b3ca 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -590,7 +590,10 @@ js::Nursery::traceObject(MinorCollectionTracer* trc, JSObject* obj) if (!nobj->hasEmptyElements() && !nobj->denseElementsAreCopyOnWrite()) markSlots(trc, nobj->getDenseElements(), nobj->getDenseInitializedLength()); - HeapSlot* fixedStart, *fixedEnd, *dynStart, *dynEnd; + HeapSlot* fixedStart; + HeapSlot* fixedEnd; + HeapSlot* dynStart; + HeapSlot* dynEnd; nobj->getSlotRange(0, nobj->slotSpan(), &fixedStart, &fixedEnd, &dynStart, &dynEnd); markSlots(trc, fixedStart, fixedEnd); markSlots(trc, dynStart, dynEnd); @@ -669,7 +672,8 @@ js::Nursery::moveObjectToTenured(MinorCollectionTracer *trc, js_memcpy(dst, src, srcSize); if (src->isNative()) { - NativeObject* ndst = &dst->as(), *nsrc = &src->as(); + NativeObject* ndst = &dst->as(); + NativeObject* nsrc = &src->as(); tenuredSize += moveSlotsToTenured(ndst, nsrc, dstKind); tenuredSize += moveElementsToTenured(ndst, nsrc, dstKind); diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index ecf7e42c92..89d5e03b4a 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -329,7 +329,8 @@ enum ZoneSelector { class ZonesIter { gc::AutoEnterIteration iterMarker; - JS::Zone** it, **end; + JS::Zone** it; + JS::Zone** end; public: ZonesIter(JSRuntime* rt, ZoneSelector selector) : iterMarker(&rt->gc) { diff --git a/js/src/irregexp/RegExpParser.h b/js/src/irregexp/RegExpParser.h index 010dcb5a0b..ee6074a68e 100644 --- a/js/src/irregexp/RegExpParser.h +++ b/js/src/irregexp/RegExpParser.h @@ -282,7 +282,8 @@ class RegExpParser frontend::TokenStream& ts; LifoAlloc* alloc; RegExpCaptureVector* captures_; - const CharT* next_pos_, *end_; + const CharT* next_pos_; + const CharT* end_; widechar current_; // The capture count is only valid after we have scanned for captures. int capture_count_; diff --git a/js/src/jit-test/lib/bytecode-cache.js b/js/src/jit-test/lib/bytecode-cache.js index b382cb1eae..9e9905ca6a 100644 --- a/js/src/jit-test/lib/bytecode-cache.js +++ b/js/src/jit-test/lib/bytecode-cache.js @@ -11,9 +11,8 @@ function evalWithCache(code, ctx) { if (!("global" in ctx)) ctx.global = newGlobal(); - // ... and by default enable compileAndGo. - if (!("compileAndGo" in ctx)) - ctx.compileAndGo = true; + if (!("isRunOnce" in ctx)) + ctx.isRunOnce = true; // Fetch the verification function from the evaluation context. This function // is used to assert the state of the script/function after each run of the diff --git a/js/src/jit-test/tests/SIMD/bug1121299.js b/js/src/jit-test/tests/SIMD/bug1121299.js index c610e5b961..b99221ecc9 100644 --- a/js/src/jit-test/tests/SIMD/bug1121299.js +++ b/js/src/jit-test/tests/SIMD/bug1121299.js @@ -27,5 +27,5 @@ function test_2() { } test_2(); evaluate("test_2(); test_2();", { - compileAndGo: true + isRunOnce: true, }); diff --git a/js/src/jit-test/tests/TypedObject/bug1004527.js b/js/src/jit-test/tests/TypedObject/bug1004527.js index 934b528bb0..db4387598a 100644 --- a/js/src/jit-test/tests/TypedObject/bug1004527.js +++ b/js/src/jit-test/tests/TypedObject/bug1004527.js @@ -5,4 +5,5 @@ var { ArrayType, StructType, uint32 } = TypedObject; var L = 1024; var Matrix = uint32.array(L, 2); var matrix = new Matrix(); -evaluate("for (var i = 0; i < L; i++) matrix[i][0] = (function d() {});", { compileAndGo : true }); +evaluate("for (var i = 0; i < L; i++) matrix[i][0] = (function d() {});", + { isRunOnce: true }); diff --git a/js/src/jit-test/tests/asm.js/testBug893519.js b/js/src/jit-test/tests/asm.js/testBug893519.js index d430100931..8995c6e875 100644 --- a/js/src/jit-test/tests/asm.js/testBug893519.js +++ b/js/src/jit-test/tests/asm.js/testBug893519.js @@ -6,6 +6,6 @@ if (!isAsmJSCompilationAvailable()) { } var g = newGlobal(); -evaluate("function h() { function f() { 'use asm'; function g() { return 42 } return g } return f }", { compileAndGo:false, global:g}); +evaluate("function h() { function f() { 'use asm'; function g() { return 42 } return g } return f }", { global:g}); var h = clone(g.h); assertEq(h()()(), 42); diff --git a/js/src/jit-test/tests/auto-regress/bug677977.js b/js/src/jit-test/tests/auto-regress/bug677977.js index 5219b5889c..74624e01dc 100644 --- a/js/src/jit-test/tests/auto-regress/bug677977.js +++ b/js/src/jit-test/tests/auto-regress/bug677977.js @@ -20,7 +20,7 @@ dbg.onNewScript = function (s) { }; assertEq(g.eval("eval('2 + 3')"), 5); this.gczeal(hits, 2); -var fn = g.evaluate("(function (a) { return 5 + a; })", {compileAndGo: false}); +var fn = g.evaluate("(function (a) { return 5 + a; })"); var g2 = newGlobal(); dbg.addDebuggee(g2, dbg); g2.clone(fn); diff --git a/js/src/jit-test/tests/basic/bug1024786.js b/js/src/jit-test/tests/basic/bug1024786.js index 95add49195..6811513cbe 100644 --- a/js/src/jit-test/tests/basic/bug1024786.js +++ b/js/src/jit-test/tests/basic/bug1024786.js @@ -61,5 +61,5 @@ evaluate("function f(){\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",({ fileName: null, lineNumber: 42, - compileAndGo: 9 + isRunOnce: 9, })) diff --git a/js/src/jit-test/tests/basic/bug1057571.js b/js/src/jit-test/tests/basic/bug1057571.js index b56c81fda3..7b8e88431f 100644 --- a/js/src/jit-test/tests/basic/bug1057571.js +++ b/js/src/jit-test/tests/basic/bug1057571.js @@ -8,7 +8,7 @@ test = (function () { evalWithCache(test, {}); function evalWithCache(code, ctx) { code = cacheEntry(code); - ctx.compileAndGo = true; + ctx.isRunOnce = true; var res1 = evaluate(code, Object.create(ctx, {saveBytecode: { value: true } })); var res2 = evaluate(code, Object.create(ctx, {loadBytecode: { value: true }, saveBytecode: { value: true } })); } diff --git a/js/src/jit-test/tests/basic/bug1061534.js b/js/src/jit-test/tests/basic/bug1061534.js index 62a79c99a1..4044155f5c 100644 --- a/js/src/jit-test/tests/basic/bug1061534.js +++ b/js/src/jit-test/tests/basic/bug1061534.js @@ -11,4 +11,4 @@ function evalWithCache(code, ctx) { if (typeof assertThrowsInstanceOf === 'undefined') { var assertThrowsInstanceOf = function assertThrowsInstanceOf(f, ctor, msg) {}; } -evaluate('evaluate(\'assertThrowsInstanceOf(function () {}, ["jak", "ms"]);\', { noScriptRval : true, compileAndGo : true })'); +evaluate('evaluate(\'assertThrowsInstanceOf(function () {}, ["jak", "ms"]);\', { noScriptRval : true, isRunOnce: true })'); diff --git a/js/src/jit-test/tests/basic/bug1106982-2.js b/js/src/jit-test/tests/basic/bug1106982-2.js index 058210a995..378d10f514 100644 --- a/js/src/jit-test/tests/basic/bug1106982-2.js +++ b/js/src/jit-test/tests/basic/bug1106982-2.js @@ -12,7 +12,7 @@ var p = new Proxy(t, { }); evaluate(`function testFunc() { x += " x"; -}`, { compileAndGo: false }); +}`); var cloneFunc = clone(testFunc, p); cloneFunc(); diff --git a/js/src/jit-test/tests/basic/bug1146836.js b/js/src/jit-test/tests/basic/bug1146836.js new file mode 100644 index 0000000000..2b4f4acec8 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1146836.js @@ -0,0 +1,11 @@ +function f() { + var s = "switch (x) {"; + for (var i=8000; i<16400; i++) { + s += "case " + i + ": return " + i + "; break;"; + } + s += "case 8005: return -1; break;"; + s += "}"; + var g = Function("x", s); + assertEq(g(8005), 8005); +} +f(); diff --git a/js/src/jit-test/tests/basic/testLet.js b/js/src/jit-test/tests/basic/testLet.js index 1ac2e99f57..b7e97fb0c5 100644 --- a/js/src/jit-test/tests/basic/testLet.js +++ b/js/src/jit-test/tests/basic/testLet.js @@ -20,7 +20,7 @@ function test(str, arg, result) // test xdr by cloning a cross-compartment function var code = "(function (x) { " + str + " })"; - var c = clone(otherGlobal.evaluate(code, {compileAndGo: false})); + var c = clone(otherGlobal.evaluate(code)); assertEq(c.toSource(), eval(code).toSource()); var got = fun(arg); diff --git a/js/src/jit-test/tests/basic/testScriptCloning.js b/js/src/jit-test/tests/basic/testScriptCloning.js index 426de2d9b5..e68f2131a2 100644 --- a/js/src/jit-test/tests/basic/testScriptCloning.js +++ b/js/src/jit-test/tests/basic/testScriptCloning.js @@ -1,25 +1,21 @@ var g = newGlobal(); -function cloneableFunction(body) { - return evaluate("(function () { " + body + " })", {compileAndGo: false}); -} - -g.f = cloneableFunction('return function(x) { return x };'); +g.f = new Function('return function(x) { return x };'); assertEq(g.eval("clone(f)()(9)"), 9); -g.f = cloneableFunction('return function(x) { { let y = x+1; return y } };'); +g.f = new Function('return function(x) { { let y = x+1; return y } };'); assertEq(g.eval("clone(f)()(9)"), 10); -g.f = cloneableFunction('return function(x) { { let y = x, z = 1; return y+z } };'); +g.f = new Function('return function(x) { { let y = x, z = 1; return y+z } };'); assertEq(g.eval("clone(f)()(9)"), 10); -g.f = cloneableFunction('return function(x) { return x.search(/ponies/) };'); +g.f = new Function('return function(x) { return x.search(/ponies/) };'); assertEq(g.eval("clone(f)()('123ponies')"), 3); -g.f = cloneableFunction('return function(x,y) { return x.search(/a/) + y.search(/b/) };'); +g.f = new Function('return function(x,y) { return x.search(/a/) + y.search(/b/) };'); assertEq(g.eval("clone(f)()('12a','foo')"), 1); -g.f = cloneableFunction('return function(x) { switch(x) { case "a": return "b"; case null: return "c" } };'); +g.f = new Function('return function(x) { switch(x) { case "a": return "b"; case null: return "c" } };'); assertEq(g.eval("clone(f)()('a')"), "b"); assertEq(g.eval("clone(f)()(null)"), "c"); assertEq(g.eval("clone(f)()(3)"), undefined); diff --git a/js/src/jit-test/tests/basic/weird-scopechains.js b/js/src/jit-test/tests/basic/weird-scopechains.js index 8f240cea78..035a934ec5 100644 --- a/js/src/jit-test/tests/basic/weird-scopechains.js +++ b/js/src/jit-test/tests/basic/weird-scopechains.js @@ -6,9 +6,7 @@ function assertWithMessage(got, expected, message) { assertEq(message + ": " + got, message + ": " + expected); } -// Create our test func via "evaluate" so it won't be compileAndGo and -// we can clone it. -evaluate(`function testFunc() { +function testFunc() { assertWithMessage(checkNameLookup(), "local", "nameLookup"); assertWithMessage(checkThisBinding(), "local", "thisBinding"); @@ -20,7 +18,7 @@ evaluate(`function testFunc() { assertWithMessage(checkNameLookup(), "local", "nameLookup" + reason); assertWithMessage(checkThisBinding(), "local", "thisBinding" + reason); })(); -}`, { compileAndGo: false }); +} var obj = { checkNameLookup: function() { diff --git a/js/src/jit-test/tests/debug/Debugger-findScripts-15.js b/js/src/jit-test/tests/debug/Debugger-findScripts-15.js index dd0323d1cc..c2308c6135 100644 --- a/js/src/jit-test/tests/debug/Debugger-findScripts-15.js +++ b/js/src/jit-test/tests/debug/Debugger-findScripts-15.js @@ -1,7 +1,7 @@ // findScripts finds non-compile-and-go scripts var g = newGlobal(); -g.evaluate("function f(x) { return x + 1; }", {compileAndGo: false}); +g.evaluate("function f(x) { return x + 1; }"); var dbg = new Debugger; var gw = dbg.addDebuggee(g); var s = dbg.findScripts(); diff --git a/js/src/jit-test/tests/debug/breakpoint-noncng.js b/js/src/jit-test/tests/debug/breakpoint-noncng.js index db83f9b28f..7a45fa2af6 100644 --- a/js/src/jit-test/tests/debug/breakpoint-noncng.js +++ b/js/src/jit-test/tests/debug/breakpoint-noncng.js @@ -8,8 +8,7 @@ g.evaluate( "function f() {\n" + // fscript.startLine " s += 'a';\n" + // fscript.startLine + 1 " s += 'b';\n" + // fscript.startLine + 2 - "}\n", - {compileAndGo: false}); + "}\n"); var fscript = gw.makeDebuggeeValue(g.f).script; var handler = {hit: function (frame) { g.s += '1'; }}; diff --git a/js/src/jit-test/tests/debug/bug1106164.js b/js/src/jit-test/tests/debug/bug1106164.js index 8159f1efa3..40759439e9 100644 --- a/js/src/jit-test/tests/debug/bug1106164.js +++ b/js/src/jit-test/tests/debug/bug1106164.js @@ -14,4 +14,4 @@ evaluate("\ }\ }\ }\ -", { noScriptRval : true, compileAndGo : true }); +", { noScriptRval : true, isRunOnce: true }); diff --git a/js/src/jit-test/tests/debug/bug1107913.js b/js/src/jit-test/tests/debug/bug1107913.js index b212cf337a..b1ba03ba2a 100644 --- a/js/src/jit-test/tests/debug/bug1107913.js +++ b/js/src/jit-test/tests/debug/bug1107913.js @@ -4,4 +4,4 @@ var g = newGlobal(); g.parent = this; g.eval("new Debugger(parent).onExceptionUnwind = function () {};"); Object.preventExtensions(this); -evaluate("function testcase() { }", { noScriptRval : true, compileAndGo : true }); +evaluate("function testcase() { }", { noScriptRval : true, isRunOnce: true }); diff --git a/js/src/jit-test/tests/debug/bug1108556.js b/js/src/jit-test/tests/debug/bug1108556.js index d0961f8f76..2e399bc6d0 100644 --- a/js/src/jit-test/tests/debug/bug1108556.js +++ b/js/src/jit-test/tests/debug/bug1108556.js @@ -7,4 +7,4 @@ evaluate('\ var fe="v";\ for (i=0; String.fromCharCode(0x004E); i++)\ fe += fe;\ -', { compileAndGo : true }); +', { isRunOnce: true }); diff --git a/js/src/jit-test/tests/debug/bug1118878.js b/js/src/jit-test/tests/debug/bug1118878.js index 3dc4e361ab..91e6e8cb9a 100644 --- a/js/src/jit-test/tests/debug/bug1118878.js +++ b/js/src/jit-test/tests/debug/bug1118878.js @@ -8,4 +8,4 @@ var evalInFrame = (function (global) { var completion = frame.eval(code); }; })(this); -evaluate("for (var k in 'xxx') (function g() { Math.atan2(42); evalInFrame((0), (''), true); })();", { noScriptRval : true, compileAndGo : true }); +evaluate("for (var k in 'xxx') (function g() { Math.atan2(42); evalInFrame((0), (''), true); })();", { noScriptRval : true, isRunOnce : true }); diff --git a/js/src/jit-test/tests/debug/onNewScript-01.js b/js/src/jit-test/tests/debug/onNewScript-01.js index 7050a760ee..2305848599 100644 --- a/js/src/jit-test/tests/debug/onNewScript-01.js +++ b/js/src/jit-test/tests/debug/onNewScript-01.js @@ -37,7 +37,7 @@ assertEq(fn(8), 13); assertEq(hits, 1); // cloning functions across compartments -fn = g.evaluate("(function(a) { return 5 + a; })", {compileAndGo: false}); +fn = g.evaluate("(function(a) { return 5 + a; })"); var g2 = newGlobal(); dbg.addDebuggee(g2, dbg); hits = 0; diff --git a/js/src/jit-test/tests/debug/onNewScript-02.js b/js/src/jit-test/tests/debug/onNewScript-02.js index 397c771f37..5f3e8ccd2a 100644 --- a/js/src/jit-test/tests/debug/onNewScript-02.js +++ b/js/src/jit-test/tests/debug/onNewScript-02.js @@ -44,7 +44,7 @@ test(function () { g.eval("var obj = {get x() { return 1; }, set x(v) { print(v) test(function () { return g.Function("a", "b", "return b - a;"); }); // cloning a function with nested functions -test(function () { g.clone(evaluate("(function(x) { return x + 1; })", {compileAndGo: false})); }); +test(function () { g.clone(evaluate("(function(x) { return x + 1; })")); }); // eval declaring a generator test(function () { g.eval("function r(n) { for (var i=0;inumIntervals() <= 2 && reg1->numIntervals() <= 2); - LiveInterval* interval0 = reg0->getInterval(0), *interval1 = reg1->getInterval(0); + LiveInterval* interval0 = reg0->getInterval(0); + LiveInterval* interval1 = reg1->getInterval(0); // Interval ranges are sorted in reverse order. The lifetimes overlap if // any of their ranges overlap. @@ -190,7 +191,8 @@ BacktrackingAllocator::tryGroupRegisters(uint32_t vreg0, uint32_t vreg1) // See if reg0 and reg1 can be placed in the same group, following the // restrictions imposed by VirtualRegisterGroup and any other registers // already grouped with reg0 or reg1. - BacktrackingVirtualRegister* reg0 = &vregs[vreg0], *reg1 = &vregs[vreg1]; + BacktrackingVirtualRegister* reg0 = &vregs[vreg0]; + BacktrackingVirtualRegister* reg1 = &vregs[vreg1]; if (!reg0->isCompatibleVReg(*reg1)) return true; @@ -214,7 +216,8 @@ BacktrackingAllocator::tryGroupRegisters(uint32_t vreg0, uint32_t vreg1) } } - VirtualRegisterGroup* group0 = reg0->group(), *group1 = reg1->group(); + VirtualRegisterGroup* group0 = reg0->group(); + VirtualRegisterGroup* group1 = reg1->group(); if (!group0 && group1) return tryGroupRegisters(vreg1, vreg0); @@ -261,7 +264,8 @@ BacktrackingAllocator::tryGroupRegisters(uint32_t vreg0, uint32_t vreg1) bool BacktrackingAllocator::tryGroupReusedRegister(uint32_t def, uint32_t use) { - BacktrackingVirtualRegister& reg = vregs[def], &usedReg = vregs[use]; + BacktrackingVirtualRegister& reg = vregs[def]; + BacktrackingVirtualRegister& usedReg = vregs[use]; // reg is a vreg which reuses its input usedReg for its output physical // register. Try to group reg with usedReg if at all possible, as avoiding @@ -1913,7 +1917,8 @@ BacktrackingAllocator::trySplitAcrossHotcode(LiveInterval* interval, bool* succe } LiveInterval* hotInterval = LiveInterval::New(alloc(), interval->vreg(), 0); - LiveInterval* preInterval = nullptr, *postInterval = nullptr; + LiveInterval* preInterval = nullptr; + LiveInterval* postInterval = nullptr; // Accumulate the ranges of hot and cold code in the interval. Note that // we are only comparing with the single hot range found, so the cold code diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 5f69178230..aad5079580 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -705,13 +705,13 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC, scopeChain = fun->environment(); } } else { - // For global, compile-and-go scripts the scope chain is the - // script's global (Ion does not compile non-compile-and-go - // scripts). Also note that it's invalid to resume into the - // prologue in this case because the prologue expects the scope - // chain in R1 for eval and global scripts. + // For global scripts without a polluted global scope the scope + // chain is the script's global (Ion does not compile scripts + // with a polluted global scope). Also note that it's invalid to + // resume into the prologue in this case because the prologue + // expects the scope chain in R1 for eval and global scripts. MOZ_ASSERT(!script->isForEval()); - MOZ_ASSERT(script->compileAndGo()); + MOZ_ASSERT(!script->hasPollutedGlobalScope()); scopeChain = &(script->global()); } } diff --git a/js/src/jit/BaselineDebugModeOSR.h b/js/src/jit/BaselineDebugModeOSR.h index 0343443151..87380da85c 100644 --- a/js/src/jit/BaselineDebugModeOSR.h +++ b/js/src/jit/BaselineDebugModeOSR.h @@ -75,7 +75,8 @@ class DebugModeOSRVolatileStub // class DebugModeOSRVolatileJitFrameIterator : public JitFrameIterator { - DebugModeOSRVolatileJitFrameIterator** stack, *prev; + DebugModeOSRVolatileJitFrameIterator** stack; + DebugModeOSRVolatileJitFrameIterator* prev; public: explicit DebugModeOSRVolatileJitFrameIterator(JSContext* cx) diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index 3f78f10080..1237915691 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -256,7 +256,8 @@ CanUseInt32Compare(ICStub::Kind kind) MCompare::CompareType BaselineInspector::expectedCompareType(jsbytecode* pc) { - ICStub* first = monomorphicStub(pc), *second = nullptr; + ICStub* first = monomorphicStub(pc); + ICStub* second = nullptr; if (!first && !dimorphicStub(pc, &first, &second)) return MCompare::Compare_Unknown; diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index a3156ef8d6..fa5e2c1c6f 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -186,7 +186,8 @@ CodeGenerator::visitValueToInt32(LValueToInt32* lir) // We can only handle strings in truncation contexts, like bitwise // operations. - Label* stringEntry, *stringRejoin; + Label* stringEntry; + Label* stringRejoin; Register stringReg; if (input->mightBeType(MIRType_String)) { stringReg = ToRegister(lir->temp()); @@ -8876,7 +8877,8 @@ CodeGenerator::visitClampVToUint8(LClampVToUint8* lir) Register output = ToRegister(lir->output()); MDefinition* input = lir->mir()->input(); - Label* stringEntry, *stringRejoin; + Label* stringEntry; + Label* stringRejoin; if (input->mightBeType(MIRType_String)) { OutOfLineCode* oolString = oolCallVM(StringToNumberInfo, lir, (ArgList(), output), StoreFloatRegisterTo(tempFloat)); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index b31a0c9006..4acc68654c 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1041,10 +1041,8 @@ IonScript::getSafepointIndex(uint32_t disp) const const OsiIndex* IonScript::getOsiIndex(uint32_t disp) const { - for (const OsiIndex* it = osiIndices(), *end = osiIndices() + osiIndexEntries_; - it != end; - ++it) - { + const OsiIndex* end = osiIndices() + osiIndexEntries_; + for (const OsiIndex* it = osiIndices(); it != end; ++it) { if (it->returnPointDisplacement() == disp) return it; } @@ -2042,11 +2040,12 @@ CheckScript(JSContext* cx, JSScript* script, bool osr) return false; } - if (!script->compileAndGo() && !script->functionNonDelazifying()) { - // Support non-CNG functions but not other scripts. For global scripts, - // IonBuilder currently uses the global object as scope chain, this is - // not valid for non-CNG code. - TrackAndSpewIonAbort(cx, script, "not compile-and-go"); + if (script->hasPollutedGlobalScope() && !script->functionNonDelazifying()) { + // Support functions with a polluted global scope but not other + // scripts. For global scripts, IonBuilder currently uses the global + // object as scope chain, this is not valid when the script has a + // polluted global scope. + TrackAndSpewIonAbort(cx, script, "has polluted global scope"); return false; } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index ab1bd719c4..30c45ed1b7 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -598,7 +598,8 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod if (!loopHeaders_.append(LoopHeader(start, entry))) return false; - jsbytecode* last = nullptr, *earlier = nullptr; + jsbytecode* last = nullptr; + jsbytecode* earlier = nullptr; for (jsbytecode* pc = start; pc != end; earlier = last, last = pc, pc += GetBytecodeLength(pc)) { uint32_t slot; if (*pc == JSOP_SETLOCAL) @@ -1206,8 +1207,10 @@ IonBuilder::initScopeChain(MDefinition* callee) return false; } } else { - // For CNG global scripts, the scope chain is the global object. - MOZ_ASSERT(script()->compileAndGo()); + // For global scripts without a polluted global scope, the scope chain + // is the global object. + MOZ_ASSERT(!script()->isForEval()); + MOZ_ASSERT(!script()->hasPollutedGlobalScope()); scope = constant(ObjectValue(script()->global())); } @@ -2579,7 +2582,8 @@ IonBuilder::processForUpdateEnd(CFGState& state) IonBuilder::DeferredEdge* IonBuilder::filterDeadDeferredEdges(DeferredEdge* edge) { - DeferredEdge* head = edge, *prev = nullptr; + DeferredEdge* head = edge; + DeferredEdge* prev = nullptr; while (edge) { if (edge->block->isDead()) { @@ -7900,7 +7904,8 @@ IonBuilder::pushScalarLoadFromTypedObject(MDefinition* obj, MOZ_ASSERT(size == ScalarTypeDescr::alignment(elemType)); // Find location within the owner object. - MDefinition* elements, *scaledOffset; + MDefinition* elements; + MDefinition* scaledOffset; int32_t adjustment; loadTypedObjectElements(obj, byteOffset, size, &elements, &scaledOffset, &adjustment); @@ -7939,7 +7944,8 @@ IonBuilder::pushReferenceLoadFromTypedObject(MDefinition* typedObj, PropertyName* name) { // Find location within the owner object. - MDefinition* elements, *scaledOffset; + MDefinition* elements; + MDefinition* scaledOffset; int32_t adjustment; size_t alignment = ReferenceTypeDescr::alignment(type); loadTypedObjectElements(typedObj, byteOffset, alignment, &elements, &scaledOffset, &adjustment); @@ -12744,7 +12750,8 @@ IonBuilder::storeScalarTypedObjectValue(MDefinition *typedObj, MDefinition *value) { // Find location within the owner object. - MDefinition *elements, *scaledOffset; + MDefinition* elements; + MDefinition* scaledOffset; int32_t adjustment; size_t alignment = ScalarTypeDescr::alignment(type); loadTypedObjectElements(typedObj, byteOffset, alignment, &elements, &scaledOffset, &adjustment); @@ -12788,7 +12795,8 @@ IonBuilder::storeReferenceTypedObjectValue(MDefinition* typedObj, } // Find location within the owner object. - MDefinition* elements, *scaledOffset; + MDefinition* elements; + MDefinition* scaledOffset; int32_t adjustment; size_t alignment = ReferenceTypeDescr::alignment(type); loadTypedObjectElements(typedObj, byteOffset, alignment, &elements, &scaledOffset, &adjustment); diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 80957810a0..ff812e87db 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -1028,7 +1028,9 @@ class IonBuilder return analysis_; } - TemporaryTypeSet* thisTypes, *argTypes, *typeArray; + TemporaryTypeSet* thisTypes; + TemporaryTypeSet* argTypes; + TemporaryTypeSet* typeArray; uint32_t typeArrayHint; uint32_t* bytecodeTypeMap; diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index 6670a06a86..0160689cc4 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -2491,9 +2491,10 @@ InlineFrameIterator::computeScopeChain(Value scopeChainValue, MaybeReadFallback& if (isFunctionFrame()) return callee(fallback)->environment(); - // Ion does not handle scripts that are not compile-and-go. + // Ion does not handle non-function scripts that have anything other than + // the global on their scope chain. MOZ_ASSERT(!script()->isForEval()); - MOZ_ASSERT(script()->compileAndGo()); + MOZ_ASSERT(!script()->hasPollutedGlobalScope()); return &script()->global(); } diff --git a/js/src/jit/LoopUnroller.cpp b/js/src/jit/LoopUnroller.cpp index 9b8bdcf064..25b8aae96e 100644 --- a/js/src/jit/LoopUnroller.cpp +++ b/js/src/jit/LoopUnroller.cpp @@ -28,15 +28,18 @@ struct LoopUnroller TempAllocator& alloc; // Header and body of the original loop. - MBasicBlock* header, *backedge; + MBasicBlock* header; + MBasicBlock* backedge; // Header and body of the unrolled loop. - MBasicBlock* unrolledHeader, *unrolledBackedge; + MBasicBlock* unrolledHeader; + MBasicBlock* unrolledBackedge; // Old and new preheaders. The old preheader starts out associated with the // original loop, but becomes the preheader of the new loop. The new // preheader will be given to the original loop. - MBasicBlock* oldPreheader, *newPreheader; + MBasicBlock* oldPreheader; + MBasicBlock* newPreheader; // Map terms in the original loop to terms in the current unrolled iteration. DefinitionMap unrolledDefinitions; diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 568910df46..ea27ccc5fe 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1518,8 +1518,8 @@ MPhi::removeOperand(size_t index) void MPhi::removeAllOperands() { - for (MUse* p = inputs_.begin(), *e = inputs_.end(); p < e; ++p) - p->producer()->removeUse(p); + for (MUse& p : inputs_) + p.producer()->removeUse(&p); inputs_.clear(); } @@ -2690,7 +2690,8 @@ MustBeUInt32(MDefinition* def, MDefinition** pwrapped) bool MBinaryInstruction::tryUseUnsignedOperands() { - MDefinition* newlhs, *newrhs; + MDefinition* newlhs; + MDefinition* newrhs; if (MustBeUInt32(getOperand(0), &newlhs) && MustBeUInt32(getOperand(1), &newrhs)) { if (newlhs->type() != MIRType_Int32 || newrhs->type() != MIRType_Int32) return false; diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp index 7902a6a9e4..3c93802002 100644 --- a/js/src/jit/MIRGraph.cpp +++ b/js/src/jit/MIRGraph.cpp @@ -990,8 +990,8 @@ MBasicBlock::discardPhi(MPhi* phi) phis_.remove(phi); if (phis_.empty()) { - for (MBasicBlock** pred = predecessors_.begin(), **end = predecessors_.end(); pred < end; ++pred) - (*pred)->clearSuccessorWithPhis(); + for (MBasicBlock* pred : predecessors_) + pred->clearSuccessorWithPhis(); } } diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 618ed71858..5d450d6f3c 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -602,7 +602,8 @@ GetDynamicName(JSContext* cx, JSObject* scopeChain, JSString* str, Value* vp) } Shape* shape = nullptr; - JSObject* scope = nullptr, *pobj = nullptr; + JSObject* scope = nullptr; + JSObject* pobj = nullptr; if (LookupNameNoGC(cx, atom->asPropertyName(), scopeChain, &scope, &pobj, &shape)) { if (FetchNameNoGC(pobj, shape, MutableHandleValue::fromMarkedLocation(vp))) return; diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 1d77a51936..c0bafd99af 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -342,7 +342,8 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir, MOZ_ASSERT(mir->isRecoveredOnBailout()); uint32_t index = 0; LRecoverInfo* recoverInfo = snapshot->recoverInfo(); - MNode** it = recoverInfo->begin(), **end = recoverInfo->end(); + MNode** it = recoverInfo->begin(); + MNode** end = recoverInfo->end(); while (it != end && mir != *it) { ++it; ++index; @@ -471,8 +472,8 @@ CodeGeneratorShared::encode(LRecoverInfo* recover) RecoverOffset offset = recovers_.startRecover(numInstructions, resumeAfter); - for (MNode** it = recover->begin(), **end = recover->end(); it != end; ++it) - recovers_.writeInstruction(*it); + for (MNode* insn : *recover) + recovers_.writeInstruction(insn); recovers_.endRecover(); recover->setRecoverOffset(offset); @@ -556,18 +557,15 @@ CodeGeneratorShared::assignBailoutId(LSnapshot* snapshot) void CodeGeneratorShared::encodeSafepoints() { - for (SafepointIndex* it = safepointIndices_.begin(), *end = safepointIndices_.end(); - it != end; - ++it) - { - LSafepoint* safepoint = it->safepoint(); + for (SafepointIndex& index : safepointIndices_) { + LSafepoint* safepoint = index.safepoint(); if (!safepoint->encoded()) { safepoint->fixupOffset(&masm); safepoints_.encode(safepoint); } - it->resolve(); + index.resolve(); } } diff --git a/js/src/jsapi-tests/testHashTable.cpp b/js/src/jsapi-tests/testHashTable.cpp index 6ec934cb50..c2906827fc 100644 --- a/js/src/jsapi-tests/testHashTable.cpp +++ b/js/src/jsapi-tests/testHashTable.cpp @@ -287,3 +287,52 @@ BEGIN_TEST(testHashRekeyManualRemoval) return true; } END_TEST(testHashRekeyManualRemoval) + +// A type that is not copyable, only movable. +struct MoveOnlyType { + uint32_t val; + + explicit MoveOnlyType(uint32_t val) : val(val) { } + + MoveOnlyType(MoveOnlyType &&rhs) { + val = rhs.val; + } + + MoveOnlyType &operator=(MoveOnlyType &&rhs) { + MOZ_ASSERT(&rhs != this); + this->~MoveOnlyType(); + new(this) MoveOnlyType(mozilla::Move(rhs)); + return *this; + } + + struct HashPolicy { + typedef MoveOnlyType Lookup; + + static js::HashNumber hash(const Lookup &lookup) { + return lookup.val; + } + + static bool match(const MoveOnlyType &existing, const Lookup &lookup) { + return existing.val == lookup.val; + } + }; + + private: + MoveOnlyType(const MoveOnlyType &) = delete; + MoveOnlyType& operator=(const MoveOnlyType &) = delete; +}; + +BEGIN_TEST(testHashSetOfMoveOnlyType) +{ + typedef js::HashSet Set; + + Set set; + set.init(); + + MoveOnlyType a(1); + + set.put(mozilla::Move(a)); // This shouldn't generate a compiler error. + + return true; +} +END_TEST(testHashSetOfMoveOnlyType) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 60e38584e1..8db5bfeaae 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3269,7 +3269,7 @@ IsFunctionCloneable(HandleFunction fun, HandleObject dynamicScope) return false; } - return !fun->nonLazyScript()->compileAndGo() || dynamicScope->is(); + return true; } static JSObject* @@ -3677,7 +3677,6 @@ JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions& rhs) utf8 = rhs.utf8; lineno = rhs.lineno; column = rhs.column; - compileAndGo = rhs.compileAndGo; forEval = rhs.forEval; noScriptRval = rhs.noScriptRval; selfHostingMode = rhs.selfHostingMode; @@ -3794,7 +3793,6 @@ JS::CompileOptions::CompileOptions(JSContext* cx, JSVersion version) { this->version = (version != JSVERSION_UNKNOWN) ? version : cx->findVersion(); - compileAndGo = false; strictOption = cx->runtime()->options().strictMode(); extraWarningsOption = cx->compartment()->options().extraWarnings(cx); werrorOption = cx->runtime()->options().werror(); @@ -3942,7 +3940,6 @@ JS_BufferIsCompilableUnit(JSContext* cx, HandleObject obj, const char* utf8, siz bool result = true; CompileOptions options(cx); - options.setCompileAndGo(false); Parser parser(cx, &cx->tempLifoAlloc(), options, chars, length, /* foldConstants = */ true, nullptr, nullptr); @@ -4042,9 +4039,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg, return false; // Make sure to handle cases when we have a polluted scopechain. - OwningCompileOptions options(cx); - if (!options.copy(cx, optionsArg)) - return false; + CompileOptions options(cx, optionsArg); if (!enclosingDynamicScope->is()) options.setHasPollutedScope(true); @@ -4220,8 +4215,8 @@ Evaluate(JSContext *cx, HandleObject scope, const ReadOnlyCompileOptions &option AutoLastFrameCheck lfc(cx); - options.setCompileAndGo(scope->is()); options.setHasPollutedScope(!scope->is()); + options.setIsRunOnce(true); SourceCompressionTask sct(cx); RootedScript script(cx, frontend::CompileScript(cx, &cx->tempLifoAlloc(), scope, NullPtr(), NullPtr(), options, diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 972a0db303..f4b518c01c 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3403,8 +3403,8 @@ class JS_FRIEND_API(ReadOnlyCompileOptions) utf8(false), lineno(1), column(0), - compileAndGo(false), hasPollutedGlobalScope(false), + isRunOnce(false), forEval(false), noScriptRval(false), selfHostingMode(false), @@ -3443,8 +3443,9 @@ class JS_FRIEND_API(ReadOnlyCompileOptions) bool utf8; unsigned lineno; unsigned column; - bool compileAndGo; bool hasPollutedGlobalScope; + // isRunOnce only applies to non-function scripts. + bool isRunOnce; bool forEval; bool noScriptRval; bool selfHostingMode; @@ -3535,8 +3536,8 @@ class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions } OwningCompileOptions& setUTF8(bool u) { utf8 = u; return *this; } OwningCompileOptions& setColumn(unsigned c) { column = c; return *this; } - OwningCompileOptions& setCompileAndGo(bool cng) { compileAndGo = cng; return *this; } OwningCompileOptions& setHasPollutedScope(bool p) { hasPollutedGlobalScope = p; return *this; } + OwningCompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; } OwningCompileOptions& setForEval(bool eval) { forEval = eval; return *this; } OwningCompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } OwningCompileOptions& setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; } @@ -3619,8 +3620,8 @@ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOpti } CompileOptions& setUTF8(bool u) { utf8 = u; return *this; } CompileOptions& setColumn(unsigned c) { column = c; return *this; } - CompileOptions& setCompileAndGo(bool cng) { compileAndGo = cng; return *this; } CompileOptions& setHasPollutedScope(bool p) { hasPollutedGlobalScope = p; return *this; } + CompileOptions& setIsRunOnce(bool once) { isRunOnce = once; return *this; } CompileOptions& setForEval(bool eval) { forEval = eval; return *this; } CompileOptions& setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; } CompileOptions& setSelfHostingMode(bool shm) { selfHostingMode = shm; return *this; } diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 3048fce873..c28c007411 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -621,7 +621,9 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, */ if (argCount > 0) { if (efs->format) { - char16_t* buffer, *fmt, *out; + char16_t* buffer; + char16_t* fmt; + char16_t* out; int expandedArgs = 0; size_t expandedLength; size_t len = strlen(efs->format); diff --git a/js/src/jsdtoa.cpp b/js/src/jsdtoa.cpp index d619395c54..42ef901876 100644 --- a/js/src/jsdtoa.cpp +++ b/js/src/jsdtoa.cpp @@ -248,7 +248,8 @@ static uint32_t quorem2(Bigint* b, int32_t k) { ULong mask; ULong result; - ULong* bx, *bxe; + ULong* bx; + ULong* bxe; int32_t w; int32_t n = k >> 5; k &= 0x1F; @@ -365,9 +366,10 @@ js_dtobasestr(DtoaState* state, int base, double dinput) /* We have a fraction. */ int e, bbits; int32_t s2, done; - Bigint* b, *s, *mlo, *mhi; - - b = s = mlo = mhi = nullptr; + Bigint* b = nullptr; + Bigint* s = nullptr; + Bigint* mlo = nullptr; + Bigint* mhi = nullptr; *p++ = '.'; b = d2b(PASS_STATE df, &e, &bbits); diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 5241da9ce6..2c116d6df4 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1880,7 +1880,6 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener options.setMutedErrors(mutedErrors) .setFileAndLine(filename, 1) .setNoScriptRval(false) - .setCompileAndGo(true) .setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset); unsigned n = args.length() ? args.length() - 1 : 0; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 8f5878ee7d..15f09cea6d 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2598,8 +2598,8 @@ GCRuntime::updatePointersToRelocatedCells(Zone *zone) void GCRuntime::protectRelocatedArenas() { - for (ArenaHeader* arena = relocatedArenasToRelease, *next; arena; arena = next) { - next = arena->next; + for (ArenaHeader* arena = relocatedArenasToRelease; arena; ) { + ArenaHeader* next = arena->next; #if defined(XP_WIN) DWORD oldProtect; if (!VirtualProtect(arena, ArenaSize, PAGE_NOACCESS, &oldProtect)) @@ -2608,6 +2608,7 @@ GCRuntime::protectRelocatedArenas() if (mprotect(arena, ArenaSize, PROT_NONE)) MOZ_CRASH(); #endif + arena = next; } } diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index b703672728..71b7bb8be6 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -1102,7 +1102,9 @@ js::InitRuntimeNumberState(JSRuntime* rt) // change its return type. #if !EXPOSE_INTL_API /* Copy locale-specific separators into the runtime strings. */ - const char* thousandsSeparator, *decimalPoint, *grouping; + const char* thousandsSeparator; + const char* decimalPoint; + const char* grouping; #ifdef HAVE_LOCALECONV struct lconv* locale = localeconv(); thousandsSeparator = locale->thousands_sep; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 66fb18a1ce..ff651ebd87 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2085,7 +2085,7 @@ JSObject * js::CloneObjectLiteral(JSContext *cx, HandleObject srcObj) { if (srcObj->is()) { - AllocKind kind = GetBackgroundAllocKind(GuessObjectGCKind(srcObj->as().numFixedSlots())); + AllocKind kind = GetBackgroundAllocKind(gc::GetGCObjectKind(srcObj->as().numFixedSlots())); MOZ_ASSERT_IF(srcObj->isTenured(), kind == srcObj->asTenured().getAllocKind()); RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx)); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index e6d3b0e542..8337b7066b 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -397,29 +397,20 @@ class JSObject : public js::gc::Cell bool shouldSplicePrototype(JSContext *cx); /* - * Parents and scope chains. + * Scope chains. * - * All script-accessible objects with a nullptr parent are global objects, - * and all global objects have a nullptr parent. Some builtin objects - * which are not script-accessible also have a nullptr parent, such as - * parser created functions for non-compileAndGo scripts. + * The scope chain of an object is the link in the search path when a script + * does a name lookup on a scope object. For JS internal scope objects --- + * Call, DeclEnv, Block, and With --- the chain is stored in the first fixed + * slot of the object. For other scope objects, the chain goes directly to + * the global. * - * Except for the non-script-accessible builtins, the global with which an - * object is associated can be reached by following parent links to that - * global (see global()). - * - * The scope chain of an object is the link in the search path when a - * script does a name lookup on a scope object. For JS internal scope - * objects --- Call, DeclEnv and Block --- the chain is stored in - * the first fixed slot of the object, and the object's parent is the - * associated global. For other scope objects, the chain is stored in the - * object's parent. - * - * In compileAndGo code, scope chains can contain only internal scope - * objects with a global object at the root as the scope of the outermost - * non-function script. In non-compileAndGo code, the scope of the - * outermost non-function script might not be a global object, and can have - * a mix of other objects above it before the global object is reached. + * In code which is not marked hasPollutedGlobalScope, scope chains can + * contain only syntactic scope objects (see IsSyntacticScope) with a global + * object at the root as the scope of the outermost non-function script. In + * hasPollutedGlobalScope code, the scope of the outermost non-function + * script might not be a global object, and can have a mix of other objects + * above it before the global object is reached. */ /* diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 34a95cf1b1..7bef5dc1ae 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -726,9 +726,6 @@ DisassembleAtPC(JSContext* cx, JSScript* scriptArg, bool lines, RootedScript script(cx, scriptArg); BytecodeParser parser(cx, script); - jsbytecode* next, *end; - unsigned len; - if (showAll && !parser.parse()) return false; @@ -753,8 +750,8 @@ DisassembleAtPC(JSContext* cx, JSScript* scriptArg, bool lines, sp->put("----"); sp->put(" --\n"); - next = script->code(); - end = script->codeEnd(); + jsbytecode* next = script->code(); + jsbytecode* end = script->codeEnd(); while (next < end) { if (next == script->main()) sp->put("main:\n"); @@ -783,7 +780,7 @@ DisassembleAtPC(JSContext* cx, JSScript* scriptArg, bool lines, else Sprint(sp, " "); } - len = Disassemble1(cx, script, next, script->pcToOffset(next), lines, sp); + unsigned len = Disassemble1(cx, script, next, script->pcToOffset(next), lines, sp); if (!len) return false; next += len; diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index 83793a62c2..3764420c44 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -76,16 +76,8 @@ enum { JOF_CHECKSTRICT = 1 << 20, /* Op can only be generated in strict mode */ JOF_INVOKE = 1 << 21, /* JSOP_CALL, JSOP_FUNCALL, JSOP_FUNAPPLY, JSOP_NEW, JSOP_EVAL */ - JOF_TMPSLOT = 1 << 22, /* interpreter uses extra temporary slot - to root intermediate objects besides - the slots opcode uses */ - JOF_TMPSLOT2 = 2 << 22, /* interpreter uses extra 2 temporary slot - besides the slots opcode uses */ - JOF_TMPSLOT3 = 3 << 22, /* interpreter uses extra 3 temporary slot - besides the slots opcode uses */ - JOF_TMPSLOT_SHIFT = 22, - JOF_TMPSLOT_MASK = JS_BITMASK(2) << JOF_TMPSLOT_SHIFT, - + /* 1 << 22 is unused */ + /* 1 << 23 is unused */ /* 1 << 24 is unused */ JOF_GNAME = 1 << 25, /* predicted global name */ JOF_TYPESET = 1 << 26, /* has an entry in a script's type sets */ diff --git a/js/src/jsopcodeinlines.h b/js/src/jsopcodeinlines.h index fe22296550..3600db4588 100644 --- a/js/src/jsopcodeinlines.h +++ b/js/src/jsopcodeinlines.h @@ -111,7 +111,8 @@ class BytecodeRange { private: RootedScript script; - jsbytecode* pc, *end; + jsbytecode* pc; + jsbytecode* end; }; } // namespace js diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 369f5d3414..188d07fb48 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -323,8 +323,8 @@ Bindings::trace(JSTracer* trc) if (bindingArrayUsingTemporaryStorage()) return; - for (Binding* b = bindingArray(), *end = b + count(); b != end; b++) { - PropertyName* name = b->name(); + for (const Binding& b : *this) { + PropertyName* name = b.name(); MarkStringUnbarriered(trc, &name, "bindingArray"); } } @@ -576,7 +576,6 @@ js::XDRScript(XDRState* xdr, HandleObject enclosingScope, HandleScript enc OwnSource, ExplicitUseStrict, SelfHosted, - IsCompileAndGo, HasSingleton, TreatAsRunOnce, HasLazyScript, @@ -606,6 +605,22 @@ js::XDRScript(XDRState* xdr, HandleObject enclosingScope, HandleScript enc if (mode == XDR_ENCODE) { script = scriptp.get(); MOZ_ASSERT_IF(enclosingScript, enclosingScript->compartment() == script->compartment()); + MOZ_ASSERT(script->functionNonDelazifying() == fun); + + if (!fun && script->treatAsRunOnce()) { + // This is a toplevel or eval script that's runOnce. We want to + // make sure that we're not XDR-saving an object we emitted for + // JSOP_OBJECT that then got modified. So throw if we're not + // cloning in JSOP_OBJECT or if we ever didn't clone in it in the + // past. + const JS::CompartmentOptions& opts = JS::CompartmentOptionsRef(cx); + if (!opts.cloneSingletons() || !opts.getSingletonsAsTemplates()) { + JS_ReportError(cx, + "Can't serialize a run-once non-function script " + "when we're not doing singleton cloning"); + return false; + } + } nargs = script->bindings.numArgs(); nblocklocals = script->bindings.numBlockScoped(); @@ -690,8 +705,6 @@ js::XDRScript(XDRState* xdr, HandleObject enclosingScope, HandleScript enc scriptBits |= (1 << IsLegacyGenerator); if (script->isStarGenerator()) scriptBits |= (1 << IsStarGenerator); - if (script->compileAndGo()) - scriptBits |= (1 << IsCompileAndGo); if (script->hasSingletons()) scriptBits |= (1 << HasSingleton); if (script->treatAsRunOnce()) @@ -811,8 +824,6 @@ js::XDRScript(XDRState* xdr, HandleObject enclosingScope, HandleScript enc script->setNeedsArgsObj(true); if (scriptBits & (1 << IsGeneratorExp)) script->isGeneratorExp_ = true; - if (scriptBits & (1 << IsCompileAndGo)) - script->compileAndGo_ = true; if (scriptBits & (1 << HasSingleton)) script->hasSingletons_ = true; if (scriptBits & (1 << TreatAsRunOnce)) @@ -2399,10 +2410,10 @@ JSScript::Create(ExclusiveContext *cx, HandleObject enclosingScope, bool savedCa script->savedCallerFun_ = savedCallerFun; script->initCompartment(cx); - script->compileAndGo_ = options.compileAndGo; script->hasPollutedGlobalScope_ = options.hasPollutedGlobalScope; script->selfHosted_ = options.selfHostingMode; script->noScriptRval_ = options.noScriptRval; + script->treatAsRunOnce_ = options.isRunOnce; script->version = options.version; MOZ_ASSERT(script->getVersion() == options.version); // assert that no overflow occurred @@ -2569,7 +2580,7 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco uint32_t mainLength = bce->offset(); uint32_t prologLength = bce->prologOffset(); uint32_t nsrcnotes; - if (!FinishTakingSrcNotes(cx, bce, &nsrcnotes)) + if (!bce->finishTakingSrcNotes(&nsrcnotes)) return false; uint32_t natoms = bce->atomIndices->count(); if (!partiallyInit(cx, script, @@ -2594,7 +2605,7 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco jsbytecode* code = ssd->data; PodCopy(code, bce->prolog.code.begin(), prologLength); PodCopy(code + prologLength, bce->code().begin(), mainLength); - CopySrcNotes(bce, (jssrcnote*)(code + script->length()), nsrcnotes); + bce->copySrcNotes((jssrcnote*)(code + script->length()), nsrcnotes); InitAtomMap(bce->atomIndices.getMap(), ssd->atoms()); if (!SaveSharedScriptData(cx, script, ssd, nsrcnotes)) @@ -2965,6 +2976,12 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, PollutedGlobalScopeOption polluted /* = HasCleanGlobalScope */, NewObjectKind newKind /* = GenericObject */) { + if (src->treatAsRunOnce() && !src->functionNonDelazifying()) { + // Toplevel run-once scripts may not be cloned. + JS_ReportError(cx, "No cloning toplevel run-once scripts"); + return nullptr; + } + /* NB: Keep this in sync with XDRScript. */ /* Some embeddings are not careful to use ExposeObjectToActiveJS as needed. */ @@ -3089,7 +3106,6 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, CompileOptions options(cx); options.setMutedErrors(src->mutedErrors()) - .setCompileAndGo(src->compileAndGo()) .setHasPollutedScope(src->hasPollutedGlobalScope() || polluted == HasPollutedGlobalScope) .setSelfHostingMode(src->selfHosted()) diff --git a/js/src/jsscript.h b/js/src/jsscript.h index a1486a1535..c757f36a07 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -316,6 +316,9 @@ class Bindings return !callObjShape_->isEmptyShape(); } + Binding* begin() const { return bindingArray(); } + Binding* end() const { return bindingArray() + count(); } + static js::ThingRootKind rootKind() { return js::THING_ROOT_BINDINGS; } void trace(JSTracer* trc); }; @@ -925,9 +928,6 @@ class JSScript : public js::gc::TenuredCell // Code has "use strict"; explicitly. bool explicitUseStrict_:1; - // See Parser::compileAndGo. - bool compileAndGo_:1; - // True if the script has a non-syntactic scope on its dynamic scope chain. // That is, there are objects about which we know nothing between the // outermost syntactic scope and the global. @@ -950,7 +950,9 @@ class JSScript : public js::gc::TenuredCell // Script has singleton objects. bool hasSingletons_:1; - // Script is a lambda to treat as running once. + // Script is a lambda to treat as running once or a global or eval script + // that will only run once. Which one it is can be disambiguated by + // checking whether function_ is null. bool treatAsRunOnce_:1; // If treatAsRunOnce, whether script has executed. @@ -1154,10 +1156,6 @@ class JSScript : public js::gc::TenuredCell bool explicitUseStrict() const { return explicitUseStrict_; } - bool compileAndGo() const { - return compileAndGo_; - } - bool hasPollutedGlobalScope() const { return hasPollutedGlobalScope_; } @@ -1193,6 +1191,10 @@ class JSScript : public js::gc::TenuredCell MOZ_ASSERT(isActiveEval() && !isCachedEval()); isActiveEval_ = false; isCachedEval_ = true; + // IsEvalCacheCandidate will make sure that there's nothing in this + // script that would prevent reexecution even if isRunOnce is + // true. So just pretend like we never ran this script. + hasRunOnce_ = false; } void uncacheForEval() { @@ -1574,6 +1576,7 @@ class JSScript : public js::gc::TenuredCell JSObject *getObject(size_t index) { js::ObjectArray *arr = objects(); MOZ_ASSERT(index < arr->length); + MOZ_ASSERT(arr->vector[index]->isTenured()); return arr->vector[index]; } @@ -1772,7 +1775,9 @@ class BindingIter */ class AliasedFormalIter { - const Binding* begin_, *p_, *end_; + const Binding* begin_; + const Binding* p_; + const Binding* end_; unsigned slot_; void settle() { @@ -1800,7 +1805,7 @@ class LazyScript : public gc::TenuredCell public: class FreeVariable { - // Free variable names are possible tagged JSAtom* s. + // Variable name is stored as a tagged JSAtom pointer. uintptr_t bits_; static const uintptr_t HOISTED_USE_BIT = 0x1; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 692355b930..821cc875fe 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1239,7 +1239,8 @@ StringMatch(const TextChar* text, uint32_t textLen, const PatChar* pat, uint32_t */ if (patLen == 1) { const PatChar p0 = *pat; - for (const TextChar* c = text, *end = text + textLen; c != end; ++c) { + const TextChar* end = text + textLen; + for (const TextChar* c = text; c != end; ++c) { if (*c == p0) return c - text; } diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 0eea6bfd91..2fc97f6787 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -169,10 +169,10 @@ ** Macros to get the number of elements and the pointer to one past the ** last element of a C array. Use them like this: ** -** char16_t buf[10], *s; +** char16_t buf[10]; ** JSString* str; ** ... -** for (s = buf; s != JS_ARRAY_END(buf); ++s) *s = ...; +** for (char16_t* s = buf; s != JS_ARRAY_END(buf); ++s) *s = ...; ** ... ** str = JS_NewStringCopyN(cx, buf, JS_ARRAY_LENGTH(buf)); ** ... diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index c8747ed05a..ed20167c0a 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -110,8 +110,8 @@ void WeakMapBase::sweepCompartment(JSCompartment* c) { WeakMapBase** tailPtr = &c->gcWeakMapList; - for (WeakMapBase* m = c->gcWeakMapList, *next; m; m = next) { - next = m->next; + for (WeakMapBase* m = c->gcWeakMapList; m; ) { + WeakMapBase* next = m->next; if (m->marked) { m->sweep(); *tailPtr = m; @@ -121,6 +121,7 @@ WeakMapBase::sweepCompartment(JSCompartment* c) m->finish(); m->next = WeakMapNotInList; } + m = next; } *tailPtr = nullptr; diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index db040ea4c5..1dd1b94406 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -580,10 +580,8 @@ js::RemapAllWrappersForObject(JSContext* cx, JSObject* oldTargetArg, } } - for (WrapperValue* begin = toTransplant.begin(), *end = toTransplant.end(); - begin != end; ++begin) - { - if (!RemapWrapper(cx, &begin->toObject(), newTarget)) + for (const WrapperValue& v : toTransplant) { + if (!RemapWrapper(cx, &v.toObject(), newTarget)) MOZ_CRASH(); } @@ -619,9 +617,8 @@ js::RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter, } // Recompute all the wrappers in the list. - for (WrapperValue* begin = toRecompute.begin(), *end = toRecompute.end(); begin != end; ++begin) - { - JSObject* wrapper = &begin->toObject(); + for (const WrapperValue& v : toRecompute) { + JSObject* wrapper = &v.toObject(); JSObject* wrapped = Wrapper::wrappedObject(wrapper); if (!RemapWrapper(cx, wrapper, wrapped)) MOZ_CRASH(); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 0eaf8f2cb6..587b03df1e 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -448,7 +448,7 @@ RunFile(JSContext *cx, const char *filename, FILE *file, bool compileOnly) options.setIntroductionType("js shell file") .setUTF8(true) .setFileAndLine(filename, 1) - .setCompileAndGo(true) + .setIsRunOnce(true) .setNoScriptRval(true); gGotError = false; @@ -479,7 +479,7 @@ EvalAndPrint(JSContext *cx, const char *bytes, size_t length, JS::CompileOptions options(cx); options.setIntroductionType("js shell interactive") .setUTF8(true) - .setCompileAndGo(true) + .setIsRunOnce(true) .setFileAndLine("typein", lineno); RootedScript script(cx); if (!JS::Compile(cx, options, bytes, length, &script)) @@ -863,7 +863,7 @@ LoadScript(JSContext* cx, unsigned argc, jsval* vp, bool scriptRelative) CompileOptions opts(cx); opts.setIntroductionType("js shell load") .setUTF8(true) - .setCompileAndGo(true) + .setIsRunOnce(true) .setNoScriptRval(true); RootedScript script(cx); RootedValue unused(cx); @@ -900,10 +900,10 @@ ParseCompileOptions(JSContext* cx, CompileOptions& options, HandleObject opts, RootedValue v(cx); RootedString s(cx); - if (!JS_GetProperty(cx, opts, "compileAndGo", &v)) + if (!JS_GetProperty(cx, opts, "isRunOnce", &v)) return false; if (!v.isUndefined()) - options.setCompileAndGo(ToBoolean(v)); + options.setIsRunOnce(ToBoolean(v)); if (!JS_GetProperty(cx, opts, "noScriptRval", &v)) return false; @@ -1482,7 +1482,7 @@ Run(JSContext* cx, unsigned argc, jsval* vp) JS::CompileOptions options(cx); options.setIntroductionType("js shell run") .setFileAndLine(filename.ptr(), 1) - .setCompileAndGo(true) + .setIsRunOnce(true) .setNoScriptRval(true); if (!JS_CompileUCScript(cx, ucbuf, buflen, options, &script)) return false; @@ -2187,13 +2187,11 @@ static const char* const TryNoteNames[] = { "catch", "finally", "for-in", "for-o static bool TryNotes(JSContext* cx, HandleScript script, Sprinter* sp) { - JSTryNote* tn, *tnlimit; - if (!script->hasTrynotes()) return true; - tn = script->trynotes()->vector; - tnlimit = tn + script->trynotes()->length; + JSTryNote* tn = script->trynotes()->vector; + JSTryNote* tnlimit = tn + script->trynotes()->length; Sprint(sp, "\nException table:\nkind stack start end\n"); do { MOZ_ASSERT(tn->kind < ArrayLength(TryNoteNames)); @@ -2376,7 +2374,7 @@ DisassFile(JSContext* cx, unsigned argc, jsval* vp) options.setIntroductionType("js shell disFile") .setUTF8(true) .setFileAndLine(filename.ptr(), 1) - .setCompileAndGo(true) + .setIsRunOnce(true) .setNoScriptRval(true); if (!JS::Compile(cx, options, filename.ptr(), &script)) @@ -2405,7 +2403,6 @@ DisassWithSrc(JSContext* cx, unsigned argc, jsval* vp) unsigned len, line1, line2, bupline; FILE* file; char linebuf[LINE_BUF_LEN]; - jsbytecode* pc, *end; static const char sep[] = ";-------------------------"; bool ok = true; @@ -2429,8 +2426,8 @@ DisassWithSrc(JSContext* cx, unsigned argc, jsval* vp) return false; } - pc = script->code(); - end = script->codeEnd(); + jsbytecode* pc = script->code(); + jsbytecode* end = script->codeEnd(); Sprinter sprinter(cx); if (!sprinter.init()) { @@ -2555,14 +2552,6 @@ Clone(JSContext* cx, unsigned argc, jsval* vp) funobj = JS_GetFunctionObject(fun); } } - if (funobj->compartment() != cx->compartment()) { - JSFunction* fun = &funobj->as(); - if (fun->hasScript() && fun->nonLazyScript()->compileAndGo()) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE, - "function", "compile-and-go"); - return false; - } - } if (args.length() > 1) { if (!JS_ValueToObject(cx, args[1], &parent)) @@ -2804,7 +2793,7 @@ WorkerMain(void* arg) JS::CompileOptions options(cx); options.setFileAndLine("", 1) - .setCompileAndGo(true); + .setIsRunOnce(true); RootedScript script(cx); if (!JS::Compile(cx, options, input->chars, input->length, &script)) @@ -3236,7 +3225,7 @@ Compile(JSContext* cx, unsigned argc, jsval* vp) JS::CompileOptions options(cx); options.setIntroductionType("js shell compile") .setFileAndLine("", 1) - .setCompileAndGo(true) + .setIsRunOnce(true) .setNoScriptRval(true); RootedScript script(cx); const char16_t* chars = stableChars.twoByteRange().start().get(); @@ -3276,8 +3265,7 @@ Parse(JSContext* cx, unsigned argc, jsval* vp) CompileOptions options(cx); options.setIntroductionType("js shell parse") - .setFileAndLine("", 1) - .setCompileAndGo(false); + .setFileAndLine("", 1); Parser parser(cx, &cx->tempLifoAlloc(), options, chars, length, /* foldConstants = */ true, nullptr, nullptr); if (!parser.checkOptions()) @@ -3317,8 +3305,7 @@ SyntaxParse(JSContext* cx, unsigned argc, jsval* vp) return false; CompileOptions options(cx); options.setIntroductionType("js shell syntaxParse") - .setFileAndLine("", 1) - .setCompileAndGo(false); + .setFileAndLine("", 1); AutoStableStringChars stableChars(cx); if (!stableChars.initTwoByte(cx, scriptContents)) @@ -3468,7 +3455,7 @@ OffThreadCompileScript(JSContext* cx, unsigned argc, jsval* vp) } // These option settings must override whatever the caller requested. - options.setCompileAndGo(true) + options.setIsRunOnce(true) .setSourceIsLazy(false); // We assume the caller wants caching if at all possible, ignoring @@ -4505,7 +4492,7 @@ static const JSFunctionSpecWithHelp shell_functions[] = { "evaluate(code[, options])", " Evaluate code as though it were the contents of a file.\n" " options is an optional object that may have these properties:\n" -" compileAndGo: use the compile-and-go compiler option (default: true)\n" +" isRunOnce: use the isRunOnce compiler option (default: false)\n" " noScriptRval: use the no-script-rval compiler option (default: false)\n" " fileName: filename for error messages and debug info\n" " lineNumber: starting line number for error messages and debug info\n" diff --git a/js/src/shell/jsoptparse.cpp b/js/src/shell/jsoptparse.cpp index 5705c2cf92..c7b8dd0945 100644 --- a/js/src/shell/jsoptparse.cpp +++ b/js/src/shell/jsoptparse.cpp @@ -194,11 +194,10 @@ OptionParser::printHelp(const char* progname) static const char fmt[] = " %s "; size_t fmtChars = sizeof(fmt) - 2; size_t lhsLen = 0; - for (Option** it = arguments.begin(), **end = arguments.end(); it != end; ++it) - lhsLen = Max(lhsLen, strlen((*it)->longflag) + fmtChars); + for (Option* arg : arguments) + lhsLen = Max(lhsLen, strlen(arg->longflag) + fmtChars); - for (Option** it = arguments.begin(), **end = arguments.end(); it != end; ++it) { - Option* arg = *it; + for (Option* arg : arguments) { size_t chars = printf(fmt, arg->longflag); for (; chars < lhsLen; ++chars) putchar(' '); @@ -213,8 +212,7 @@ OptionParser::printHelp(const char* progname) /* Calculate sizes for column alignment. */ size_t lhsLen = 0; - for (Option** it = options.begin(), **end = options.end(); it != end; ++it) { - Option* opt = *it; + for (Option* opt : options) { size_t longflagLen = strlen(opt->longflag); size_t fmtLen; @@ -227,8 +225,7 @@ OptionParser::printHelp(const char* progname) } /* Print option help text. */ - for (Option** it = options.begin(), **end = options.end(); it != end; ++it) { - Option* opt = *it; + for (Option* opt : options) { size_t fmtLen; const char* fmt = OptionFlagsToFormatInfo(opt->shortflag, opt->isValued(), &fmtLen); size_t chars; @@ -459,18 +456,18 @@ OptionParser::getMultiStringOption(const char* longflag) const OptionParser::~OptionParser() { - for (Option** it = options.begin(), **end = options.end(); it != end; ++it) - js_delete