diff --git a/accessible/src/base/Statistics.h b/accessible/src/base/Statistics.h index 7b541a21eee..e35016d5a50 100644 --- a/accessible/src/base/Statistics.h +++ b/accessible/src/base/Statistics.h @@ -60,7 +60,7 @@ namespace statistics { { static bool firstTime = true; if (firstTime) { - Telemetry::Accumulate(Telemetry::ISIMPLE_DOM_USAGE, 1); + Telemetry::Accumulate(Telemetry::A11Y_ISIMPLEDOM_USAGE, 1); firstTime = false; } } @@ -69,13 +69,13 @@ namespace statistics { * Report that IAccessibleTable has been used. */ inline void IAccessibleTableUsed() - { Telemetry::Accumulate(Telemetry::IACCESSIBLE_TABLE_USAGE, 1); } + { Telemetry::Accumulate(Telemetry::A11Y_IATABLE_USAGE, 1); } /** * Report that XForms accessibility has been instantiated. */ inline void XFormsAccessibleUsed() - { Telemetry::Accumulate(Telemetry::XFORMS_ACCESSIBLE_USED, 1); } + { Telemetry::Accumulate(Telemetry::A11Y_XFORMS_USAGE, 1); } } // namespace statistics } // namespace a11y diff --git a/accessible/src/base/nsARIAMap.cpp b/accessible/src/base/nsARIAMap.cpp index d6bf7bcf897..576c2c232e7 100644 --- a/accessible/src/base/nsARIAMap.cpp +++ b/accessible/src/base/nsARIAMap.cpp @@ -136,7 +136,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] = "combobox", roles::COMBOBOX, kUseMapRole, - eHasValueMinMax, + eNoValue, eOpenCloseAction, eNoLiveAttr, states::COLLAPSED | states::HASPOPUP, diff --git a/accessible/src/base/nsAccessible.cpp b/accessible/src/base/nsAccessible.cpp index 70f774c90e5..712966f696a 100644 --- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -854,9 +854,10 @@ nsAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY, nsDocAccessible* contentDocAcc = GetAccService()-> GetDocAccessible(content->OwnerDoc()); - // contentDocAcc in some circumstances can be NULL - // See https://bugzilla.mozilla.org/show_bug.cgi?id=729861 - NS_ENSURE_TRUE(contentDocAcc, fallbackAnswer); + // contentDocAcc in some circumstances can be NULL. See bug 729861 + NS_ASSERTION(contentDocAcc, "could not get the document accessible"); + if (!contentDocAcc) + return fallbackAnswer; nsAccessible* accessible = contentDocAcc->GetAccessibleOrContainer(content); if (!accessible) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 574e6675c74..e25f236622e 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1653,12 +1653,6 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) { gPrefService.addObserver(ctrlTab.prefName, ctrlTab, false); gPrefService.addObserver(allTabs.prefName, allTabs, false); - // Delayed initialization of the livemarks update timer. - // Livemark updates don't need to start until after bookmark UI - // such as the toolbar has initialized. Starting 5 seconds after - // delayedStartup in order to stagger this before the download manager starts. - setTimeout(function() PlacesUtils.livemarks.start(), 5000); - // Initialize the download manager some time after the app starts so that // auto-resume downloads begin (such as after crashing or quitting with // active downloads) and speeds up the first-load of the download manager UI. diff --git a/browser/base/content/test/Makefile.in b/browser/base/content/test/Makefile.in index 1b2e97edc24..c0465639852 100644 --- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -225,6 +225,7 @@ _BROWSER_FILES = \ browser_tabs_owner.js \ browser_urlbarCopying.js \ browser_urlbarEnter.js \ + browser_urlbarRevert.js \ browser_urlbarTrimURLs.js \ browser_urlHighlight.js \ browser_visibleFindSelection.js \ diff --git a/browser/base/content/test/browser_urlbarRevert.js b/browser/base/content/test/browser_urlbarRevert.js new file mode 100644 index 00000000000..2bd596efc01 --- /dev/null +++ b/browser/base/content/test/browser_urlbarRevert.js @@ -0,0 +1,29 @@ +function test() { + waitForExplicitFinish(); + + let tab = gBrowser.addTab("http://example.com"); + gBrowser.selectedTab = tab; + + onLoad(function () { + let originalValue = gURLBar.value; + + gBrowser.userTypedValue = "foobar"; + gBrowser.selectedTab = gBrowser.tabs[0]; + gBrowser.selectedTab = tab; + is(gURLBar.value, "foobar", "location bar displays typed value"); + + gURLBar.focus(); + EventUtils.synthesizeKey("VK_ESCAPE", {}); + is(gURLBar.value, originalValue, "ESC reverted the location bar value"); + + gBrowser.removeTab(tab); + finish(); + }); +} + +function onLoad(callback) { + gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() { + gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false); + executeSoon(callback); + }); +} diff --git a/browser/components/distribution.js b/browser/components/distribution.js index 63d155e1398..1efc57c76e8 100644 --- a/browser/components/distribution.js +++ b/browser/components/distribution.js @@ -45,6 +45,10 @@ const Cu = Components.utils; const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC = "distribution-customization-complete"; +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", + "resource://gre/modules/PlacesUtils.jsm"); + function DistributionCustomizer() { let dirSvc = Cc["@mozilla.org/file/directory_service;1"]. getService(Ci.nsIProperties); @@ -78,27 +82,6 @@ DistributionCustomizer.prototype = { return this._locale; }, - get _bmSvc() { - let svc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); - this.__defineGetter__("_bmSvc", function() svc); - return this._bmSvc; - }, - - get _annoSvc() { - let svc = Cc["@mozilla.org/browser/annotation-service;1"]. - getService(Ci.nsIAnnotationService); - this.__defineGetter__("_annoSvc", function() svc); - return this._annoSvc; - }, - - get _livemarkSvc() { - let svc = Cc["@mozilla.org/browser/livemark-service;2"]. - getService(Ci.nsILivemarkService); - this.__defineGetter__("_livemarkSvc", function() svc); - return this._livemarkSvc; - }, - get _prefSvc() { let svc = Cc["@mozilla.org/preferences-service;1"]. getService(Ci.nsIPrefService); @@ -167,7 +150,7 @@ DistributionCustomizer.prototype = { if (!items[iid]) continue; - let index = this._bmSvc.DEFAULT_INDEX; + let index = PlacesUtils.bookmarks.DEFAULT_INDEX; let newId; switch (items[iid]["type"]) { @@ -178,23 +161,25 @@ DistributionCustomizer.prototype = { if (iid < defaultItemId) index = prependIndex++; - newId = this._bmSvc.createFolder(parentId, items[iid]["title"], index); + newId = PlacesUtils.bookmarks.createFolder(parentId, + items[iid]["title"], + index); this._parseBookmarksSection(newId, "BookmarksFolder-" + items[iid]["folderId"]); if (items[iid]["description"]) - this._annoSvc.setItemAnnotation(newId, - "bookmarkProperties/description", - items[iid]["description"], 0, - this._annoSvc.EXPIRE_NEVER); + PlacesUtils.annotations.setItemAnnotation(newId, + "bookmarkProperties/description", + items[iid]["description"], 0, + PlacesUtils.annotations.EXPIRE_NEVER); break; case "separator": if (iid < defaultItemId) index = prependIndex++; - this._bmSvc.insertSeparator(parentId, index); + PlacesUtils.bookmarks.insertSeparator(parentId, index); break; case "livemark": @@ -202,12 +187,12 @@ DistributionCustomizer.prototype = { index = prependIndex++; // Don't bother updating the livemark contents on creation. - newId = this._livemarkSvc. - createLivemarkFolderOnly(parentId, - items[iid]["title"], - this._makeURI(items[iid]["siteLink"]), - this._makeURI(items[iid]["feedLink"]), - index); + PlacesUtils.livemarks.addLivemark({ title: items[iid]["title"] + , parentId: parentId + , index: index + , feedURI: this._makeURI(items[iid]["feedLink"]) + , siteURI: this._makeURI(items[iid]["siteLink"]) + }); break; case "bookmark": @@ -215,15 +200,15 @@ DistributionCustomizer.prototype = { if (iid < defaultItemId) index = prependIndex++; - newId = this._bmSvc.insertBookmark(parentId, - this._makeURI(items[iid]["link"]), - index, items[iid]["title"]); + newId = PlacesUtils.bookmarks.insertBookmark(parentId, + this._makeURI(items[iid]["link"]), + index, items[iid]["title"]); if (items[iid]["description"]) - this._annoSvc.setItemAnnotation(newId, - "bookmarkProperties/description", - items[iid]["description"], 0, - this._annoSvc.EXPIRE_NEVER); + PlacesUtils.annotations.setItemAnnotation(newId, + "bookmarkProperties/description", + items[iid]["description"], 0, + PlacesUtils.annotations.EXPIRE_NEVER); break; } @@ -277,10 +262,10 @@ DistributionCustomizer.prototype = { if (!bmProcessed) { if (sections["BookmarksMenu"]) - this._parseBookmarksSection(this._bmSvc.bookmarksMenuFolder, + this._parseBookmarksSection(PlacesUtils.bookmarksMenuFolderId, "BookmarksMenu"); if (sections["BookmarksToolbar"]) - this._parseBookmarksSection(this._bmSvc.toolbarFolder, + this._parseBookmarksSection(PlacesUtils.toolbarFolderId, "BookmarksToolbar"); this._prefs.setBoolPref(bmProcessedPref, true); } diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index c213ff6f784..8da566b394f 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -777,6 +777,15 @@ BrowserGlue.prototype = { // This is used to reprompt users when privacy message changes const TELEMETRY_PROMPT_REV = 2; + function appendTelemetryNotification(notifyBox, message, buttons, hideclose) { + let notification = notifyBox.appendNotification(message, "telemetry", null, + notifyBox.PRIORITY_INFO_LOW, + buttons); + notification.setAttribute("hideclose", hideclose); + notification.persistence = -1; // Until user closes it + return notification; + } + var telemetryPrompted = null; try { telemetryPrompted = Services.prefs.getIntPref(PREF_TELEMETRY_PROMPTED); @@ -823,10 +832,8 @@ BrowserGlue.prototype = { // Set pref to indicate we've shown the notification. Services.prefs.setIntPref(PREF_TELEMETRY_PROMPTED, TELEMETRY_PROMPT_REV); - var notification = notifyBox.appendNotification(telemetryPrompt, "telemetry", null, notifyBox.PRIORITY_INFO_LOW, buttons); - notification.setAttribute("hideclose", true); - notification.persistence = -1; // Until user closes it - + let notification = appendTelemetryNotification(notifyBox, telemetryPrompt, + buttons, true); let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; let link = notification.ownerDocument.createElementNS(XULNS, "label"); link.className = "text-link telemetry-text-link"; @@ -838,8 +845,7 @@ BrowserGlue.prototype = { notification.parentNode.removeNotification(notification, true); // Add a new notification to that tab, with no "Learn more" link notifyBox = browser.getNotificationBox(); - notification = notifyBox.appendNotification(telemetryPrompt, "telemetry", null, notifyBox.PRIORITY_INFO_LOW, buttons); - notification.persistence = -1; // Until user closes it + appendTelemetryNotification(notifyBox, telemetryPrompt, buttons, true); }, false); let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText"); description.appendChild(link); @@ -1300,7 +1306,7 @@ BrowserGlue.prototype = { // be set to the version it has been added in, we will compare its value // to users' smartBookmarksVersion and add new smart bookmarks without // recreating old deleted ones. - const SMART_BOOKMARKS_VERSION = 2; + const SMART_BOOKMARKS_VERSION = 3; const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark"; const SMART_BOOKMARKS_PREF = "browser.places.smartBookmarksVersion"; @@ -1346,7 +1352,6 @@ BrowserGlue.prototype = { Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS + "&sort=" + Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_DESCENDING + - "&excludeItemIfParentHasAnnotation=livemark%2FfeedURI" + "&maxResults=" + MAX_RESULTS + "&excludeQueries=1"), parent: PlacesUtils.bookmarksMenuFolderId, diff --git a/browser/components/places/content/bookmarkProperties.js b/browser/components/places/content/bookmarkProperties.js index 458949bdb4b..2dafec536f7 100644 --- a/browser/components/places/content/bookmarkProperties.js +++ b/browser/components/places/content/bookmarkProperties.js @@ -281,13 +281,26 @@ var BookmarkPropertiesPanel = { break; case "folder": - if (PlacesUtils.itemIsLivemark(this._itemId)) { - this._itemType = LIVEMARK_CONTAINER; - this._feedURI = PlacesUtils.livemarks.getFeedURI(this._itemId); - this._siteURI = PlacesUtils.livemarks.getSiteURI(this._itemId); - } - else - this._itemType = BOOKMARK_FOLDER; + this._itemType = BOOKMARK_FOLDER; + PlacesUtils.livemarks.getLivemark( + { id: this._itemId }, + (function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + this._itemType = LIVEMARK_CONTAINER; + this._feedURI = aLivemark.feedURI; + this._siteURI = aLivemark.siteURI; + this._fillEditProperties(); + + let acceptButton = document.documentElement.getButton("accept"); + acceptButton.disabled = !this._inputIsValid(); + + let newHeight = window.outerHeight + + this._element("descriptionField").boxObject.height; + window.resizeTo(window.outerWidth, newHeight); + } + }).bind(this) + ); + break; } @@ -341,8 +354,7 @@ var BookmarkPropertiesPanel = { this._fillAddProperties(); // if this is an uri related dialog disable accept button until // the user fills an uri value. - if (this._itemType == BOOKMARK_ITEM || - this._itemType == LIVEMARK_CONTAINER) + if (this._itemType == BOOKMARK_ITEM) acceptButton.disabled = !this._inputIsValid(); break; } @@ -518,16 +530,6 @@ var BookmarkPropertiesPanel = { if (this._isAddKeywordDialog && !this._element("keywordField").value.length) return false; - // Feed Location has to be a valid URI; - // Site Location has to be a valid URI or empty - if (this._itemType == LIVEMARK_CONTAINER) { - if (!this._containsValidURI("feedLocationField")) - return false; - if (!this._containsValidURI("siteLocationField") && - (this._element("siteLocationField").value.length > 0)) - return false; - } - return true; }, diff --git a/browser/components/places/content/browserPlacesViews.js b/browser/components/places/content/browserPlacesViews.js index 050a16f3c45..687020a0b3c 100644 --- a/browser/components/places/content/browserPlacesViews.js +++ b/browser/components/places/content/browserPlacesViews.js @@ -1,44 +1,6 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Places Frontend Code. - * - * The Initial Developer of the Original Code is - * Google Inc. - * Portions created by the Initial Developer are Copyright (C) 2005 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Annie Sullivan - * Ben Goodger - * Myk Melez - * Marco Bonardo - * Asaf Romano - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); @@ -170,7 +132,8 @@ PlacesViewBase.prototype = { let selectedNode = this.selectedNode; if (selectedNode) { let popup = document.popupNode; - if (!popup._placesNode || popup._placesNode == this._resultNode) { + if (!popup._placesNode || popup._placesNode == this._resultNode || + popup._placesNode.itemId == -1) { // If a static menuitem is selected, or if the root node is selected, // the insertion point is inside the folder, at the end. container = selectedNode; @@ -210,7 +173,9 @@ PlacesViewBase.prototype = { let end = aPopup._endMarker != -1 ? aPopup._endMarker : aPopup.childNodes.length; let items = []; - let placesNodeFound = false; + + // Automatically adjust the start and the end markers. + let firstNonStaticNodeFound = false; for (let i = start; i < end; ++i) { let item = aPopup.childNodes[i]; if (item.getAttribute("builder") == "end") { @@ -220,18 +185,20 @@ PlacesViewBase.prototype = { aPopup._endMarker = i; break; } + if (item._placesNode) { items.push(item); - placesNodeFound = true; + firstNonStaticNodeFound = true; } else { - // This is static content... - if (!placesNodeFound) - // ...at the start of the popup - // Initialized in menu.xml, in the base binding + // This is static content. + if (!firstNonStaticNodeFound) { + // We are at the beginning of the popup, in static content. + // The markers are initialized in menu.xml, in the base binding. aPopup._startMarker++; + } else { - // ...after places nodes + // We are at the end of the popup, after places nodes aPopup._endMarker = i; break; } @@ -248,15 +215,20 @@ PlacesViewBase.prototype = { _rebuildPopup: function PVB__rebuildPopup(aPopup) { this._cleanPopup(aPopup); - // If this is a livemark container check if the status menuitem has - // to be added or removed. - if (PlacesUtils.nodeIsLivemarkContainer(aPopup._placesNode)) - this._ensureLivemarkStatusMenuItem(aPopup); - let resultNode = aPopup._placesNode; if (!resultNode.containerOpen) return; + if (resultNode._feedURI) { + aPopup.removeAttribute("emptyplacesresult"); + if (aPopup._emptyMenuItem) { + aPopup._emptyMenuItem.hidden = true; + } + aPopup._built = true; + this._populateLivemarkPopup(aPopup); + return; + } + let cc = resultNode.childCount; if (cc > 0) { aPopup.removeAttribute("emptyplacesresult"); @@ -303,11 +275,14 @@ PlacesViewBase.prototype = { _createMenuItemForPlacesNode: function PVB__createMenuItemForPlacesNode(aPlacesNode) { + delete aPlacesNode._DOMElement; let element; let type = aPlacesNode.type; - if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) + if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) { element = document.createElement("menuseparator"); + } else { + let itemId = aPlacesNode.itemId; if (PlacesUtils.uriTypes.indexOf(type) != -1) { element = document.createElement("menuitem"); element.className = "menuitem-iconic bookmark-item menuitem-with-favicon"; @@ -327,9 +302,19 @@ PlacesViewBase.prototype = { else if (PlacesUtils.nodeIsHost(aPlacesNode)) element.setAttribute("hostContainer", "true"); } - else if (aPlacesNode.itemId != -1) { - if (PlacesUtils.nodeIsLivemarkContainer(aPlacesNode)) - element.setAttribute("livemark", "true"); + else if (itemId != -1) { + PlacesUtils.livemarks.getLivemark( + { id: itemId }, + function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + element.setAttribute("livemark", "true"); + // Set an expando on the node, controller will use it to build + // its metadata. + aPlacesNode._feedURI = aLivemark.feedURI; + aPlacesNode._siteURI = aLivemark.siteURI; + } + } + ); } let popup = document.createElement("menupopup"); @@ -392,42 +377,84 @@ PlacesViewBase.prototype = { return element; }, + _setLivemarkSiteURIMenuItem: + function PVB__setLivemarkSiteURIMenuItem(aPopup) { + let siteUrl = aPopup._placesNode._siteURI ? aPopup._placesNode._siteURI.spec + : null; + if (!siteUrl && aPopup._siteURIMenuitem) { + aPopup.removeChild(aPopup._siteURIMenuitem); + aPopup._siteURIMenuitem = null; + aPopup._startMarker--; + aPopup.removeChild(aPopup._siteURIMenuseparator); + aPopup._siteURIMenuseparator = null; + aPopup._startMarker--; + } + else if (siteUrl && !aPopup._siteURIMenuitem) { + // Add "Open (Feed Name)" menuitem. + aPopup._siteURIMenuitem = document.createElement("menuitem"); + aPopup._siteURIMenuitem.className = "openlivemarksite-menuitem"; + aPopup._siteURIMenuitem.setAttribute("targetURI", siteUrl); + aPopup._siteURIMenuitem.setAttribute("oncommand", + "openUILink(this.getAttribute('targetURI'), event);"); + + // If a user middle-clicks this item we serve the oncommand event. + // We are using checkForMiddleClick because of Bug 246720. + // Note: stopPropagation is needed to avoid serving middle-click + // with BT_onClick that would open all items in tabs. + aPopup._siteURIMenuitem.setAttribute("onclick", + "checkForMiddleClick(this, event); event.stopPropagation();"); + let label = + PlacesUIUtils.getFormattedString("menuOpenLivemarkOrigin.label", + [aPopup.parentNode.getAttribute("label")]) + aPopup._siteURIMenuitem.setAttribute("label", label); + aPopup.insertBefore(aPopup._siteURIMenuitem, + aPopup.childNodes.item(aPopup._startMarker + 1)); + aPopup._startMarker++; + + aPopup._siteURIMenuseparator = document.createElement("menuseparator"); + aPopup.insertBefore(aPopup._siteURIMenuseparator, + aPopup.childNodes.item(aPopup._startMarker + 1)); + aPopup._startMarker++; + } + }, + /** * Add, update or remove the livemark status menuitem. * @param aPopup * The livemark container popup + * @param aStatus + * The livemark status */ - _ensureLivemarkStatusMenuItem: - function PVB_ensureLivemarkStatusMenuItem(aPopup) { + _setLivemarkStatusMenuItem: + function PVB_setLivemarkStatusMenuItem(aPopup, aStatus) { let itemId = aPopup._placesNode.itemId; - let as = PlacesUtils.annotations; + let statusMenuitem = aPopup._statusMenuitem; + let stringId = ""; + if (aStatus == Ci.mozILivemark.STATUS_LOADING) + stringId = "bookmarksLivemarkLoading"; + else if (aStatus == Ci.mozILivemark.STATUS_FAILED) + stringId = "bookmarksLivemarkFailed"; - let lmStatus = null; - if (as.itemHasAnnotation(itemId, PlacesUtils.LMANNO_LOADFAILED)) - lmStatus = "bookmarksLivemarkFailed"; - else if (as.itemHasAnnotation(itemId, PlacesUtils.LMANNO_LOADING)) - lmStatus = "bookmarksLivemarkLoading"; - - let lmStatusElt = aPopup._lmStatusMenuItem; - if (lmStatus && !lmStatusElt) { + if (stringId && !statusMenuitem) { // Create the status menuitem and cache it in the popup object. - lmStatusElt = document.createElement("menuitem"); - lmStatusElt.setAttribute("lmStatus", lmStatus); - lmStatusElt.setAttribute("label", PlacesUIUtils.getString(lmStatus)); - lmStatusElt.setAttribute("disabled", true); - aPopup.insertBefore(lmStatusElt, + statusMenuitem = document.createElement("menuitem"); + statusMenuitem.setAttribute("livemarkStatus", stringId); + statusMenuitem.setAttribute("label", PlacesUIUtils.getString(stringId)); + statusMenuitem.setAttribute("disabled", true); + aPopup.insertBefore(statusMenuitem, aPopup.childNodes.item(aPopup._startMarker + 1)); - aPopup._lmStatusMenuItem = lmStatusElt; + aPopup._statusMenuitem = statusMenuitem; aPopup._startMarker++; } - else if (lmStatus && lmStatusElt.getAttribute("lmStatus") != lmStatus) { + else if (stringId && + statusMenuitem.getAttribute("livemarkStatus") != stringId) { // Status has changed, update the cached status menuitem. - lmStatusElt.setAttribute("label", this.getString(lmStatus)); + statusMenuitem.setAttribute("label", PlacesUIUtils.getString(stringId)); } - else if (!lmStatus && lmStatusElt) { - // No status, remove the cached menuitem. - aPopup.removeChild(aPopup._lmStatusMenuItem); - aPopup._lmStatusMenuItem = null; + else if (!stringId && statusMenuitem) { + // The livemark has finished loading. + aPopup.removeChild(aPopup._statusMenuitem); + aPopup._statusMenuitem = null; aPopup._startMarker--; } }, @@ -488,14 +515,22 @@ PlacesViewBase.prototype = { // being modified. if (aAnno == PlacesUtils.LMANNO_FEEDURI) { let menu = elt.parentNode; - if (!menu.hasAttribute("livemark")) + if (!menu.hasAttribute("livemark")) { menu.setAttribute("livemark", "true"); - } + } - if ([PlacesUtils.LMANNO_LOADING, - PlacesUtils.LMANNO_LOADFAILED].indexOf(aAnno) != -1) { - // Loading status changed, update the livemark status menuitem. - this._ensureLivemarkStatusMenuItem(elt); + PlacesUtils.livemarks.getLivemark( + { id: aPlacesNode.itemId }, + (function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + // Set an expando on the node, controller will use it to build + // its metadata. + aPlacesNode._feedURI = aLivemark.feedURI; + aPlacesNode._siteURI = aLivemark.siteURI; + this.invalidateContainer(aPlacesNode); + } + }).bind(this) + ); } }, @@ -580,7 +615,24 @@ PlacesViewBase.prototype = { } }, - nodeHistoryDetailsChanged: function() { }, + nodeHistoryDetailsChanged: + function PVB_nodeHistoryDetailsChanged(aPlacesNode, aTime, aCount) { + if (aPlacesNode.parent && aPlacesNode.parent._feedURI) { + // Find the node in the parent. + let popup = aPlacesNode.parent._DOMElement; + for (let i = popup._startMarker; i < popup.childNodes.length; i++) { + let child = popup.childNodes[i]; + if (child._placesNode && child._placesNode.uri == aPlacesNode.uri) { + if (aCount) + child.setAttribute("visited", "true"); + else + child.removeAttribute("visited"); + break; + } + } + } + }, + nodeTagsChanged: function() { }, nodeDateAddedChanged: function() { }, nodeLastModifiedChanged: function() { }, @@ -642,10 +694,60 @@ PlacesViewBase.prototype = { if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED || aNewState == Ci.nsINavHistoryContainerResultNode.STATE_CLOSED) { this.invalidateContainer(aPlacesNode); + + if (PlacesUtils.nodeIsFolder(aPlacesNode)) { + let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions; + if (queryOptions.excludeItems) { + return; + } + + PlacesUtils.livemarks.getLivemark({ id: aPlacesNode.itemId }, + (function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + let shouldInvalidate = !aPlacesNode._feedURI; + aPlacesNode._feedURI = aLivemark.feedURI; + aPlacesNode._siteURI = aLivemark.siteURI; + if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) { + aLivemark.registerForUpdates(aPlacesNode, this); + aLivemark.reload(); + if (shouldInvalidate) + this.invalidateContainer(aPlacesNode); + } + else { + aLivemark.unregisterForUpdates(aPlacesNode); + } + } + }).bind(this) + ); + } } - else { - throw "Unexpected state passed to containerStateChanged"; - } + }, + + _populateLivemarkPopup: function PVB__populateLivemarkPopup(aPopup) + { + this._setLivemarkSiteURIMenuItem(aPopup); + this._setLivemarkStatusMenuItem(aPopup, Ci.mozILivemark.STATUS_LOADING); + + PlacesUtils.livemarks.getLivemark({ id: aPopup._placesNode.itemId }, + (function (aStatus, aLivemark) { + let placesNode = aPopup._placesNode; + if (!Components.isSuccessCode(aStatus) || !placesNode.containerOpen) + return; + + this._setLivemarkStatusMenuItem(aPopup, aLivemark.status); + this._cleanPopup(aPopup); + + let children = aLivemark.getNodesForContainer(placesNode); + for (let i = 0; i < children.length; i++) { + let child = children[i]; + this.nodeInserted(placesNode, child, i); + if (child.accessCount) + child._DOMElement.setAttribute("visited", true); + else + child._DOMElement.removeAttribute("visited"); + } + }).bind(this) + ); }, invalidateContainer: function PVB_invalidateContainer(aPlacesNode) { @@ -696,77 +798,44 @@ PlacesViewBase.prototype = { if (aPopup == this._rootElt) return; - // Check if the popup contains at least 2 menuitems with places nodes - let numURINodes = 0; - let currentChild = aPopup.firstChild; - while (currentChild) { - if (currentChild.localName == "menuitem" && currentChild._placesNode) { - if (++numURINodes == 2) - break; + let hasMultipleURIs = false; + + // Check if the popup contains at least 2 menuitems with places nodes. + // We don't currently support opening multiple uri nodes when they are not + // populated by the result. + if (aPopup._placesNode.childCount > 0) { + let currentChild = aPopup.firstChild; + let numURINodes = 0; + while (currentChild) { + if (currentChild.localName == "menuitem" && currentChild._placesNode) { + if (++numURINodes == 2) + break; + } + currentChild = currentChild.nextSibling; } - currentChild = currentChild.nextSibling; + hasMultipleURIs = numURINodes > 1; } - let hasMultipleURIs = numURINodes > 1; - let itemId = aPopup._placesNode.itemId; - let siteURIString = ""; - if (itemId != -1 && PlacesUtils.itemIsLivemark(itemId)) { - let siteURI = PlacesUtils.livemarks.getSiteURI(itemId); - if (siteURI) - siteURIString = siteURI.spec; - } - - if (!siteURIString && aPopup._endOptOpenSiteURI) { - aPopup.removeChild(aPopup._endOptOpenSiteURI); - aPopup._endOptOpenSiteURI = null; - } - - if (!hasMultipleURIs && aPopup._endOptOpenAllInTabs) { - aPopup.removeChild(aPopup._endOptOpenAllInTabs); - aPopup._endOptOpenAllInTabs = null; - } - - if (!(hasMultipleURIs || siteURIString)) { + if (!hasMultipleURIs) { // We don't have to show any option. - if (aPopup._endOptSeparator) { + if (aPopup._endOptOpenAllInTabs) { + aPopup.removeChild(aPopup._endOptOpenAllInTabs); + aPopup._endOptOpenAllInTabs = null; + aPopup._endMarker--; + aPopup.removeChild(aPopup._endOptSeparator); aPopup._endOptSeparator = null; - aPopup._endMarker = -1; + aPopup._endMarker--; } - return; } - - if (!aPopup._endOptSeparator) { + else if (!aPopup._endOptOpenAllInTabs) { // Create a separator before options. aPopup._endOptSeparator = document.createElement("menuseparator"); aPopup._endOptSeparator.className = "bookmarks-actions-menuseparator"; - aPopup._endMarker = aPopup.childNodes.length; aPopup.appendChild(aPopup._endOptSeparator); - } + aPopup._endMarker++; - if (siteURIString && !aPopup._endOptOpenSiteURI) { - // Add "Open (Feed Name)" menuitem if it's a livemark with a siteURI. - aPopup._endOptOpenSiteURI = document.createElement("menuitem"); - aPopup._endOptOpenSiteURI.className = "openlivemarksite-menuitem"; - aPopup._endOptOpenSiteURI.setAttribute("targetURI", siteURIString); - aPopup._endOptOpenSiteURI.setAttribute("oncommand", - "openUILink(this.getAttribute('targetURI'), event);"); - - // If a user middle-clicks this item we serve the oncommand event - // We are using checkForMiddleClick because of Bug 246720 - // Note: stopPropagation is needed to avoid serving middle-click - // with BT_onClick that would open all items in tabs. - aPopup._endOptOpenSiteURI.setAttribute("onclick", - "checkForMiddleClick(this, event); event.stopPropagation();"); - aPopup._endOptOpenSiteURI.setAttribute("label", - PlacesUIUtils.getFormattedString("menuOpenLivemarkOrigin.label", - [aPopup.parentNode.getAttribute("label")])); - aPopup.appendChild(aPopup._endOptOpenSiteURI); - } - - if (hasMultipleURIs && !aPopup._endOptOpenAllInTabs) { - // Add the "Open All in Tabs" menuitem if there are - // at least two menuitems with places result nodes. + // Add the "Open All in Tabs" menuitem. aPopup._endOptOpenAllInTabs = document.createElement("menuitem"); aPopup._endOptOpenAllInTabs.className = "openintabs-menuitem"; aPopup._endOptOpenAllInTabs.setAttribute("oncommand", @@ -777,6 +846,7 @@ PlacesViewBase.prototype = { aPopup._endOptOpenAllInTabs.setAttribute("label", gNavigatorBundle.getString("menuOpenAllInTabs.label")); aPopup.appendChild(aPopup._endOptOpenAllInTabs); + aPopup._endMarker++; } }, @@ -901,6 +971,7 @@ PlacesToolbar.prototype = { _insertNewItem: function PT__insertNewItem(aChild, aBefore) { + delete aChild._DOMElement; let type = aChild.type; let button; if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) { @@ -923,8 +994,19 @@ PlacesToolbar.prototype = { if (PlacesUtils.nodeIsTagQuery(aChild)) button.setAttribute("tagContainer", "true"); } - else if (PlacesUtils.nodeIsLivemarkContainer(aChild)) { - button.setAttribute("livemark", "true"); + else if (PlacesUtils.nodeIsFolder(aChild)) { + PlacesUtils.livemarks.getLivemark( + { id: aChild.itemId }, + function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + button.setAttribute("livemark", "true"); + // Set an expando on the node, controller will use it to build + // its metadata. + aChild._feedURI = aLivemark.feedURI; + aChild._siteURI = aLivemark.siteURI; + } + } + ); } let popup = document.createElement("menupopup"); @@ -1188,12 +1270,19 @@ PlacesToolbar.prototype = { // All livemarks have a feedURI, so use it as our indicator. if (aAnno == PlacesUtils.LMANNO_FEEDURI) { elt.setAttribute("livemark", true); - } - if ([PlacesUtils.LMANNO_LOADING, - PlacesUtils.LMANNO_LOADFAILED].indexOf(aAnno) != -1) { - // Loading status changed, update the livemark status menuitem. - this._ensureLivemarkStatusMenuItem(elt.firstChild); + PlacesUtils.livemarks.getLivemark( + { id: aPlacesNode.itemId }, + (function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + // Set an expando on the node, controller will use it to build + // its metadata. + aPlacesNode._feedURI = aLivemark.feedURI; + aPlacesNode._siteURI = aLivemark.siteURI; + this.invalidateContainer(aPlacesNode); + } + }).bind(this) + ); } } else { @@ -1623,13 +1712,16 @@ PlacesToolbar.prototype = { _onPopupHidden: function PT__onPopupHidden(aEvent) { let popup = aEvent.target; - + let placesNode = popup._placesNode; // Avoid handling popuphidden of inner views - if (popup._placesNode && PlacesUIUtils.getViewForNode(popup) == this) { + if (placesNode && PlacesUIUtils.getViewForNode(popup) == this) { // UI performance: folder queries are cheap, keep the resultnode open // so we don't rebuild its contents whenever the popup is reopened. - if (!PlacesUtils.nodeIsFolder(popup._placesNode)) - popup._placesNode.containerOpen = false; + // Though, we want to always close feed containers so their expiration + // status will be checked at next opening. + if (!PlacesUtils.nodeIsFolder(placesNode) || placesNode._feedURI) { + placesNode.containerOpen = false; + } } let parent = popup.parentNode; diff --git a/browser/components/places/content/controller.js b/browser/components/places/content/controller.js index 16ec8077ae1..ebd0bf7e98b 100644 --- a/browser/components/places/content/controller.js +++ b/browser/components/places/content/controller.js @@ -44,7 +44,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", // XXXmano: we should move most/all of these constants to PlacesUtils const ORGANIZER_ROOT_BOOKMARKS = "place:folder=BOOKMARKS_MENU&excludeItems=1&queryType=1"; -const ORGANIZER_SUBSCRIPTIONS_QUERY = "place:annotation=livemark%2FfeedURI"; // No change to the view, preserve current selection const RELOAD_ACTION_NOTHING = 0; @@ -208,15 +207,11 @@ PlacesController.prototype = { Ci.nsINavHistoryQueryOptions.SORT_BY_NONE; case "placesCmd_show:info": var selectedNode = this._view.selectedNode; - if (selectedNode && - PlacesUtils.getConcreteItemId(selectedNode) != -1 && - !PlacesUtils.nodeIsLivemarkItem(selectedNode)) - return true; - return false; + return selectedNode && PlacesUtils.getConcreteItemId(selectedNode) != -1 case "placesCmd_reload": // Livemark containers var selectedNode = this._view.selectedNode; - return selectedNode && PlacesUtils.nodeIsLivemarkContainer(selectedNode); + return selectedNode && !!selectedNode._feedURI; case "placesCmd_sortBy:name": var selectedNode = this._view.selectedNode; return selectedNode && @@ -509,7 +504,7 @@ PlacesController.prototype = { if (parentNode) { if (PlacesUtils.nodeIsTagQuery(parentNode)) nodeData["tagChild"] = true; - else if (PlacesUtils.nodeIsLivemarkContainer(parentNode)) + else if (parentNode._feedURI) nodeData["livemarkChild"] = true; } } @@ -734,8 +729,17 @@ PlacesController.prototype = { */ reloadSelectedLivemark: function PC_reloadSelectedLivemark() { var selectedNode = this._view.selectedNode; - if (selectedNode && PlacesUtils.nodeIsLivemarkContainer(selectedNode)) - PlacesUtils.livemarks.reloadLivemarkFolder(selectedNode.itemId); + if (selectedNode) { + let itemId = selectedNode.itemId; + PlacesUtils.livemarks.getLivemark( + { id: itemId }, + (function(aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + aLivemark.reload(true); + } + }).bind(this) + ); + } }, /** @@ -1065,10 +1069,12 @@ PlacesController.prototype = { addData(PlacesUtils.TYPE_X_MOZ_PLACE, i); // Drop the feed uri for livemark containers - if (PlacesUtils.nodeIsLivemarkContainer(node)) - addURIData(i, PlacesUtils.livemarks.getFeedURI(node.itemId).spec); - else if (node.uri) + if (node._feedURI) { + addURIData(i, node._feedURI.spec); + } + else if (node.uri) { addURIData(i); + } } } finally { @@ -1138,8 +1144,7 @@ PlacesController.prototype = { if (PlacesUtils.nodeIsFolder(node)) copiedFolders.push(node); - let overrideURI = PlacesUtils.nodeIsLivemarkContainer(node) ? - PlacesUtils.livemarks.getFeedURI(node.itemId).spec : null; + let overrideURI = node._feedURI ? node._feedURI.spec : null; let resolveShortcuts = !PlacesControllerDragHelper.canMoveNode(node); contents.forEach(function (content) { diff --git a/browser/components/places/content/editBookmarkOverlay.js b/browser/components/places/content/editBookmarkOverlay.js index 51096d14f6b..be048976403 100644 --- a/browser/components/places/content/editBookmarkOverlay.js +++ b/browser/components/places/content/editBookmarkOverlay.js @@ -1,39 +1,6 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Places Bookmark Properties dialog. - * - * The Initial Developer of the Original Code is Google Inc. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Asaf Romano - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ const LAST_USED_ANNO = "bookmarkPropertiesDialog/folderLastUsed"; const MAX_FOLDER_ITEM_IN_MENU_LIST = 5; @@ -52,6 +19,7 @@ var gEditItemOverlay = { _observersAdded: false, _staticFoldersListBuilt: false, _initialized: false, + _titleOverride: "", // the first field which was edited after this panel was initialized for // a certain item @@ -80,6 +48,8 @@ var gEditItemOverlay = { this._hiddenRows.splice(0, this._hiddenRows.length); // force-read-only this._readOnly = aInfo && aInfo.forceReadOnly; + this._titleOverride = aInfo && aInfo.titleOverride ? aInfo.titleOverride + : ""; }, _showHideRows: function EIO__showHideRows() { @@ -160,32 +130,34 @@ var gEditItemOverlay = { } else { this._itemId = aFor; + // We can't store information on invalid itemIds. + this._readOnly = this._readOnly || this._itemId == -1; + var containerId = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId); this._itemType = PlacesUtils.bookmarks.getItemType(this._itemId); if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK) { this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId); - if (!this._readOnly) // If readOnly wasn't forced through aInfo - this._readOnly = PlacesUtils.itemIsLivemark(containerId); this._initTextField("keywordField", PlacesUtils.bookmarks .getKeywordForBookmark(this._itemId)); - // Load In Sidebar checkbox this._element("loadInSidebarCheckbox").checked = PlacesUtils.annotations.itemHasAnnotation(this._itemId, PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO); } else { - if (!this._readOnly) // If readOnly wasn't forced through aInfo - this._readOnly = false; - this._uri = null; - this._isLivemark = PlacesUtils.itemIsLivemark(this._itemId); - if (this._isLivemark) { - var feedURI = PlacesUtils.livemarks.getFeedURI(this._itemId); - var siteURI = PlacesUtils.livemarks.getSiteURI(this._itemId); - this._initTextField("feedLocationField", feedURI.spec); - this._initTextField("siteLocationField", siteURI ? siteURI.spec : ""); - } + this._isLivemark = false; + PlacesUtils.livemarks.getLivemark( + {id: this._itemId }, + (function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + this._isLivemark = true; + this._initTextField("feedLocationField", aLivemark.feedURI.spec, true); + this._initTextField("siteLocationField", aLivemark.siteURI ? aLivemark.siteURI.spec : "", true); + this._showHideRows(); + } + }).bind(this) + ); } // folder picker @@ -379,10 +351,17 @@ var gEditItemOverlay = { }, _getItemStaticTitle: function EIO__getItemStaticTitle() { - if (this._itemId == -1) - return PlacesUtils.history.getPageTitle(this._uri); + if (this._titleOverride) + return this._titleOverride; - return PlacesUtils.bookmarks.getItemTitle(this._itemId); + let title = ""; + if (this._itemId == -1) { + title = PlacesUtils.history.getPageTitle(this._uri); + } + else { + title = PlacesUtils.bookmarks.getItemTitle(this._itemId); + } + return title; }, _initNamePicker: function EIO_initNamePicker() { @@ -425,6 +404,8 @@ var gEditItemOverlay = { this._multiEdit = false; this._firstEditedField = ""; this._initialized = false; + this._titleOverride = ""; + this._readOnly = false; }, onTagsFieldBlur: function EIO_onTagsFieldBlur() { @@ -597,36 +578,6 @@ var gEditItemOverlay = { } }, - onFeedLocationFieldBlur: function EIO_onFeedLocationFieldBlur() { - var uri; - try { - uri = PlacesUIUtils.createFixedURI(this._element("feedLocationField").value); - } - catch(ex) { return; } - - var currentFeedURI = PlacesUtils.livemarks.getFeedURI(this._itemId); - if (!currentFeedURI.equals(uri)) { - var txn = PlacesUIUtils.ptm.editLivemarkFeedURI(this._itemId, uri); - PlacesUIUtils.ptm.doTransaction(txn); - } - }, - - onSiteLocationFieldBlur: function EIO_onSiteLocationFieldBlur() { - var uri = null; - try { - uri = PlacesUIUtils.createFixedURI(this._element("siteLocationField").value); - } - catch(ex) { } - - var currentSiteURI = PlacesUtils.livemarks.getSiteURI(this._itemId); - if ((!uri && !currentSiteURI) || - (uri && currentSiteURI && currentSiteURI.equals(uri))) { - return; - } - var txn = PlacesUIUtils.ptm.editLivemarkSiteURI(this._itemId, uri); - PlacesUIUtils.ptm.doTransaction(txn); - }, - onLoadInSidebarCheckboxCommand: function EIO_onLoadInSidebarCheckboxCommand() { var loadInSidebarChecked = this._element("loadInSidebarCheckbox").checked; @@ -1019,15 +970,19 @@ var gEditItemOverlay = { PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO); break; case PlacesUtils.LMANNO_FEEDURI: - var feedURISpec = PlacesUtils.livemarks.getFeedURI(this._itemId).spec; - this._initTextField("feedLocationField", feedURISpec); + let feedURISpec = + PlacesUtils.annotations.getItemAnnotation(this._itemId, + PlacesUtils.LMANNO_FEEDURI); + this._initTextField("feedLocationField", feedURISpec, true); break; case PlacesUtils.LMANNO_SITEURI: - var siteURISpec = ""; - var siteURI = PlacesUtils.livemarks.getSiteURI(this._itemId); - if (siteURI) - siteURISpec = siteURI.spec; - this._initTextField("siteLocationField", siteURISpec); + let siteURISpec = ""; + try { + siteURISpec = + PlacesUtils.annotations.getItemAnnotation(this._itemId, + PlacesUtils.LMANNO_SITEURI); + } catch (ex) {} + this._initTextField("siteLocationField", siteURISpec, true); break; } }, diff --git a/browser/components/places/content/places.js b/browser/components/places/content/places.js index 1e24d9e659f..0ac61adfc35 100644 --- a/browser/components/places/content/places.js +++ b/browser/components/places/content/places.js @@ -600,9 +600,7 @@ var PlacesOrganizer = { return; } if (aNode.itemId != -1 && - ((PlacesUtils.nodeIsFolder(aNode) && - !PlacesUtils.nodeIsLivemarkContainer(aNode)) || - PlacesUtils.nodeIsLivemarkItem(aNode))) { + PlacesUtils.nodeIsFolder(aNode) && !aNode._feedURI) { if (infoBox.getAttribute("minimal") == "true") infoBox.setAttribute("wasminimal", "true"); infoBox.removeAttribute("minimal"); @@ -688,8 +686,10 @@ var PlacesOrganizer = { else itemId = PlacesUtils._uri(aSelectedNode.uri); - gEditItemOverlay.initPanel(itemId, { hiddenRows: ["folderPicker"], - forceReadOnly: readOnly }); + gEditItemOverlay.initPanel(itemId, { hiddenRows: ["folderPicker"] + , forceReadOnly: readOnly + , titleOverride: aSelectedNode.title + }); // Dynamically generated queries, like history date containers, have // itemId !=0 and do not exist in history. For them the panel is diff --git a/browser/components/places/content/treeView.js b/browser/components/places/content/treeView.js index 04bdf215ecb..13d647b5e1e 100644 --- a/browser/components/places/content/treeView.js +++ b/browser/components/places/content/treeView.js @@ -1,41 +1,6 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla History System - * - * The Initial Developer of the Original Code is - * Google Inc. - * Portions created by the Initial Developer are Copyright (C) 2005 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Brett Wilson (Original author) - * Asaf Romano (JavaScript version) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ function PlacesTreeView(aFlatList, aOnOpenFlatContainer) { this._tree = null; @@ -129,6 +94,10 @@ PlacesTreeView.prototype = { if (aContainer._plainContainer !== undefined) return aContainer._plainContainer; + // Livemarks are always plain containers. + if (aContainer._feedURI) + return aContainer._plainContainer = true; + // We don't know enough about non-query containers. if (!(aContainer instanceof Ci.nsINavHistoryQueryResultNode)) return aContainer._plainContainer = false; @@ -328,7 +297,8 @@ PlacesTreeView.prototype = { // Recursively do containers. if (!this._flatList && - curChild instanceof Ci.nsINavHistoryContainerResultNode) { + curChild instanceof Ci.nsINavHistoryContainerResultNode && + !curChild._feedURI) { let resource = this._getResourceForNode(curChild); let isopen = resource != null && PlacesUIUtils.localStore.HasAssertion(resource, @@ -625,7 +595,8 @@ PlacesTreeView.prototype = { // Compute the new row number of the node. let row = -1; - if (aNewIndex == 0 || this._isPlainContainer(aParentNode)) { + let cc = aParentNode.childCount; + if (aNewIndex == 0 || this._isPlainContainer(aParentNode) || cc == 0) { // We don't need to worry about sub hierarchies of the parent node // if it's a plain container, or if the new node is its first child. if (aParentNode == this._rootNode) @@ -638,7 +609,6 @@ PlacesTreeView.prototype = { // can set the new visible index to be right before that. Note that we // have to search down instead of up, because some siblings could have // children themselves that would be in the way. - let cc = aParentNode.childCount; let separatorsAreHidden = PlacesUtils.nodeIsSeparator(aNode) && this.isSorted(); for (let i = aNewIndex + 1; i < cc; i++) { @@ -664,8 +634,10 @@ PlacesTreeView.prototype = { this._rows.splice(row, 0, aNode); this._tree.rowCountChanged(row, 1); - if (PlacesUtils.nodeIsContainer(aNode) && PlacesUtils.asContainer(aNode).containerOpen) + if (PlacesUtils.nodeIsContainer(aNode) && + PlacesUtils.asContainer(aNode).containerOpen) { this.invalidateContainer(aNode); + } }, /** @@ -814,6 +786,22 @@ PlacesTreeView.prototype = { } }, + _populateLivemarkContainer: function PTV__populateLivemarkContainer(aNode) { + PlacesUtils.livemarks.getLivemark({ id: aNode.itemId }, + (function (aStatus, aLivemark) { + let placesNode = aNode; + // Need to check containerOpen since getLivemark is async. + if (!Components.isSuccessCode(aStatus) || !placesNode.containerOpen) + return; + + let children = aLivemark.getNodesForContainer(placesNode); + for (let i = 0; i < children.length; i++) { + let child = children[i]; + this.nodeInserted(placesNode, child, i); + } + }).bind(this)); + }, + nodeTitleChanged: function PTV_nodeTitleChanged(aNode, aNewTitle) { this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE); }, @@ -829,6 +817,20 @@ PlacesTreeView.prototype = { nodeHistoryDetailsChanged: function PTV_nodeHistoryDetailsChanged(aNode, aUpdatedVisitDate, aUpdatedVisitCount) { + if (aNode.parent && aNode.parent._feedURI) { + // Find the node in the parent. + let parentRow = this._flatList ? 0 : this._getRowForNode(aNode.parent); + for (let i = parentRow; i < this._rows.length; i++) { + let child = this.nodeForTreeIndex(i); + if (child.uri == aNode.uri) { + delete child._cellProperties; + this._invalidateCellValue(child, this.COLUMN_TYPE_TITLE); + break; + } + } + return; + } + this._invalidateCellValue(aNode, this.COLUMN_TYPE_DATE); this._invalidateCellValue(aNode, this.COLUMN_TYPE_VISITCOUNT); }, @@ -844,9 +846,21 @@ PlacesTreeView.prototype = { nodeAnnotationChanged: function PTV_nodeAnnotationChanged(aNode, aAnno) { if (aAnno == PlacesUIUtils.DESCRIPTION_ANNO) { this._invalidateCellValue(aNode, this.COLUMN_TYPE_DESCRIPTION); - } else if (aAnno == PlacesUtils.LMANNO_FEEDURI) { - // The livemark attribute is set as a cell property on the title cell. - this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE); + } + else if (aAnno == PlacesUtils.LMANNO_FEEDURI) { + PlacesUtils.livemarks.getLivemark( + { id: aNode.itemId }, + (function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + aNode._feedURI = aLivemark.feedURI; + if (aNode._cellProperties) { + aNode._cellProperties.push(this._getAtomFor("livemark")); + } + // The livemark attribute is set as a cell property on the title cell. + this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE); + } + }).bind(this) + ); } }, @@ -862,6 +876,32 @@ PlacesTreeView.prototype = { containerStateChanged: function PTV_containerStateChanged(aNode, aOldState, aNewState) { this.invalidateContainer(aNode); + + if (PlacesUtils.nodeIsFolder(aNode) || + (this._flatList && aNode == this._rootNode)) { + let queryOptions = PlacesUtils.asQuery(this._rootNode).queryOptions; + if (queryOptions.excludeItems) { + return; + } + + PlacesUtils.livemarks.getLivemark({ id: aNode.itemId }, + (function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + let shouldInvalidate = !aNode._feedURI; + aNode._feedURI = aLivemark.feedURI; + if (aNewState == Components.interfaces.nsINavHistoryContainerResultNode.STATE_OPENED) { + aLivemark.registerForUpdates(aNode, this); + aLivemark.reload(); + if (shouldInvalidate) + this.invalidateContainer(aNode); + } + else { + aLivemark.unregisterForUpdates(aNode); + } + } + }).bind(this) + ); + } }, invalidateContainer: function PTV_invalidateContainer(aContainer) { @@ -955,6 +995,13 @@ PlacesTreeView.prototype = { } } + if (aContainer._feedURI) { + let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions; + if (!queryOptions.excludeItems) { + this._populateLivemarkContainer(aContainer); + } + } + this._tree.endUpdateBatch(); // Restore selection. @@ -1109,8 +1156,22 @@ PlacesTreeView.prototype = { } else if (nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER || nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT) { - if (PlacesUtils.nodeIsLivemarkContainer(node)) + if (node._feedURI) { properties.push(this._getAtomFor("livemark")); + } + else { + PlacesUtils.livemarks.getLivemark( + { id: node.itemId }, + (function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + node._feedURI = aLivemark.feedURI; + node._cellProperties.push(this._getAtomFor("livemark")); + // The livemark attribute is set as a cell property on the title cell. + this._invalidateCellValue(node, this.COLUMN_TYPE_TITLE); + } + }).bind(this) + ); + } } if (itemId != -1) { @@ -1123,9 +1184,12 @@ PlacesTreeView.prototype = { properties.push(this._getAtomFor("separator")); else if (PlacesUtils.nodeIsURI(node)) { properties.push(this._getAtomFor(PlacesUIUtils.guessUrlSchemeForUI(node.uri))); - if (itemId != -1) { - if (PlacesUtils.nodeIsLivemarkContainer(node.parent)) - properties.push(this._getAtomFor("livemarkItem")); + + if (node.parent._feedURI) { + properties.push(this._getAtomFor("livemarkItem")); + if (node.accessCount) { + properties.push(this._getAtomFor("visited")); + } } } @@ -1154,7 +1218,7 @@ PlacesTreeView.prototype = { let parent = node.parent; if ((PlacesUtils.nodeIsQuery(parent) || PlacesUtils.nodeIsFolder(parent)) && - !node.hasChildren) + !PlacesUtils.asQuery(node).hasChildren) return PlacesUtils.asQuery(parent).queryOptions.expandQueries; } return true; @@ -1174,8 +1238,14 @@ PlacesTreeView.prototype = { if (this._flatList) return true; + let node = this._rows[aRow]; + if (node._feedURI) { + let queryOptions = PlacesUtils.asQuery(this._result.root).queryOptions; + return queryOptions.excludeItems; + } + // All containers are listed in the rows array. - return !this._rows[aRow].hasChildren; + return !node.hasChildren; }, isSeparator: function PTV_isSeparator(aRow) { @@ -1418,15 +1488,18 @@ PlacesTreeView.prototype = { return; } - let resource = this._getResourceForNode(node); - if (resource) { - const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open"); - const trueLiteral = PlacesUIUtils.RDF.GetLiteral("true"); + // Persist containers open status, but never persist livemarks. + if (!node._feedURI) { + let resource = this._getResourceForNode(node); + if (resource) { + const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open"); + const trueLiteral = PlacesUIUtils.RDF.GetLiteral("true"); - if (node.containerOpen) - PlacesUIUtils.localStore.Unassert(resource, openLiteral, trueLiteral); - else - PlacesUIUtils.localStore.Assert(resource, openLiteral, trueLiteral, true); + if (node.containerOpen) + PlacesUIUtils.localStore.Unassert(resource, openLiteral, trueLiteral); + else + PlacesUIUtils.localStore.Assert(resource, openLiteral, trueLiteral, true); + } } node.containerOpen = !node.containerOpen; @@ -1569,10 +1642,8 @@ PlacesTreeView.prototype = { // The following items are never editable: // * Read-only items. // * places-roots - // * livemark items // * separators if (PlacesUtils.nodeIsReadOnly(node) || - PlacesUtils.nodeIsLivemarkItem(node) || PlacesUtils.nodeIsSeparator(node)) return false; diff --git a/browser/components/places/tests/browser/browser_457473_no_copy_guid.js b/browser/components/places/tests/browser/browser_457473_no_copy_guid.js index d5e6d27056a..34acad36910 100644 --- a/browser/components/places/tests/browser/browser_457473_no_copy_guid.js +++ b/browser/components/places/tests/browser/browser_457473_no_copy_guid.js @@ -41,7 +41,7 @@ function test() { ok(PlacesUIUtils, "checking PlacesUIUtils, running in chrome context?"); /* - - create, a test folder, add bookmark, separator, livemark to it + - create, a test folder, add bookmark, separator to it - fetch guids for all - copy the folder - test that guids are all different @@ -66,10 +66,6 @@ function test() { PlacesUtils.bookmarks.insertBookmark(folderAId, PlacesUtils._uri("http://foo"), -1, "test bookmark"); PlacesUtils.bookmarks.insertSeparator(folderAId, -1); - PlacesUtils.livemarks.createLivemarkFolderOnly(folderAId, "test livemark", - PlacesUtils._uri("http://test"), - PlacesUtils._uri("http://test"), -1); - var folderANode = testRootNode.getChild(0); var folderAGUIDs = getGUIDs(folderANode); @@ -125,8 +121,7 @@ function getGUIDs(aNode) { var GUIDs = { folder: PlacesUtils.bookmarks.getItemGUID(aNode.itemId), bookmark: PlacesUtils.bookmarks.getItemGUID(aNode.getChild(0).itemId), - separator: PlacesUtils.bookmarks.getItemGUID(aNode.getChild(1).itemId), - livemark: PlacesUtils.bookmarks.getItemGUID(aNode.getChild(2).itemId) + separator: PlacesUtils.bookmarks.getItemGUID(aNode.getChild(1).itemId) }; aNode.containerOpen = false; return GUIDs; @@ -144,8 +139,7 @@ function checkGUIDs(aFolderNode, aGUIDs, aShouldMatch) { var allMatch = check(aFolderNode, aGUIDs.folder, aShouldMatch) && check(aFolderNode.getChild(0), aGUIDs.bookmark, aShouldMatch) && - check(aFolderNode.getChild(1), aGUIDs.separator, aShouldMatch) && - check(aFolderNode.getChild(2), aGUIDs.livemark, aShouldMatch); + check(aFolderNode.getChild(1), aGUIDs.separator, aShouldMatch) aFolderNode.containerOpen = false; return allMatch; diff --git a/browser/components/places/tests/browser/browser_library_views_liveupdate.js b/browser/components/places/tests/browser/browser_library_views_liveupdate.js index ddc8b1df0bd..ed84e639b89 100644 --- a/browser/components/places/tests/browser/browser_library_views_liveupdate.js +++ b/browser/components/places/tests/browser/browser_library_views_liveupdate.js @@ -95,11 +95,6 @@ function startTest() { "bmf1"); addedBookmarks.push(id); bs.moveItem(id, bs.bookmarksMenuFolder, 0); - id = PlacesUtils.livemarks.createLivemarkFolderOnly( - bs.bookmarksMenuFolder, "bml", - PlacesUtils._uri("http://bml.siteuri.mozilla.org/"), - PlacesUtils._uri("http://bml.feeduri.mozilla.org/"), bs.DEFAULT_INDEX); - addedBookmarks.push(id); // TOOLBAR ok(true, "*** Acting on toolbar bookmarks"); @@ -128,10 +123,6 @@ function startTest() { "bmf1"); addedBookmarks.push(id); bs.moveItem(id, bs.toolbarFolder, 0); - id = PlacesUtils.livemarks.createLivemarkFolderOnly( - bs.toolbarFolder, "tbl", PlacesUtils._uri("http://tbl.siteuri.mozilla.org/"), - PlacesUtils._uri("http://tbl.feeduri.mozilla.org/"), bs.DEFAULT_INDEX); - addedBookmarks.push(id); // UNSORTED ok(true, "*** Acting on unsorted bookmarks"); @@ -160,11 +151,6 @@ function startTest() { "ubf1"); addedBookmarks.push(id); bs.moveItem(id, bs.unfiledBookmarksFolder, 0); - id = PlacesUtils.livemarks.createLivemarkFolderOnly( - bs.unfiledBookmarksFolder, "bubl", - PlacesUtils._uri("http://bubl.siteuri.mozilla.org/"), - PlacesUtils._uri("http://bubl.feeduri.mozilla.org/"), bs.DEFAULT_INDEX); - addedBookmarks.push(id); // Remove all added bookmarks. addedBookmarks.forEach(function (aItem) { @@ -201,27 +187,7 @@ var bookmarksObserver = { ]), // nsIAnnotationObserver - onItemAnnotationSet: function(aItemId, aAnnotationName) { - if (aAnnotationName == PlacesUtils.LMANNO_FEEDURI) { - // Check that item is recognized as a livemark. - let validator = function(aTreeRowIndex) { - let tree = gLibrary.PlacesOrganizer._places; - let livemarkAtom = Cc["@mozilla.org/atom-service;1"]. - getService(Ci.nsIAtomService). - getAtom("livemark"); - let properties = Cc["@mozilla.org/supports-array;1"]. - createInstance(Ci.nsISupportsArray); - tree.view.getCellProperties(aTreeRowIndex, - tree.columns.getColumnAt(0), - properties); - return properties.GetIndexOf(livemarkAtom) != -1; - }; - - var [node, index, valid] = getNodeForTreeItem(aItemId, gLibrary.PlacesOrganizer._places, validator); - isnot(node, null, "Found new Places node in left pane at " + index); - ok(valid, "Node is recognized as a livemark"); - } - }, + onItemAnnotationSet: function() {}, onItemAnnotationRemoved: function() {}, onPageAnnotationSet: function() {}, onPageAnnotationRemoved: function() {}, diff --git a/browser/components/places/tests/browser/browser_views_liveupdate.js b/browser/components/places/tests/browser/browser_views_liveupdate.js index 1d5169cd8d2..3fc088750c6 100644 --- a/browser/components/places/tests/browser/browser_views_liveupdate.js +++ b/browser/components/places/tests/browser/browser_views_liveupdate.js @@ -118,11 +118,6 @@ function startTest() { bs.setItemTitle(id, "bmf1_edited"); addedBookmarks.push(id); bs.moveItem(id, bs.bookmarksMenuFolder, 0); - id = PlacesUtils.livemarks.createLivemarkFolderOnly( - bs.bookmarksMenuFolder, "bml", - PlacesUtils._uri("http://bml.siteuri.mozilla.org/"), - PlacesUtils._uri("http://bml.feeduri.mozilla.org/"), bs.DEFAULT_INDEX); - addedBookmarks.push(id); // TOOLBAR info("*** Acting on toolbar bookmarks"); @@ -154,10 +149,6 @@ function startTest() { bs.setItemTitle(id, "tbf1_edited"); addedBookmarks.push(id); bs.moveItem(id, bs.toolbarFolder, 0); - id = PlacesUtils.livemarks.createLivemarkFolderOnly( - bs.toolbarFolder, "tbl", PlacesUtils._uri("http://tbl.siteuri.mozilla.org/"), - PlacesUtils._uri("http://tbl.feeduri.mozilla.org/"), bs.DEFAULT_INDEX); - addedBookmarks.push(id); // UNSORTED info("*** Acting on unsorted bookmarks"); @@ -187,11 +178,6 @@ function startTest() { bs.setItemTitle(id, "bubf1_edited"); addedBookmarks.push(id); bs.moveItem(id, bs.unfiledBookmarksFolder, 0); - id = PlacesUtils.livemarks.createLivemarkFolderOnly( - bs.unfiledBookmarksFolder, "bubl", - PlacesUtils._uri("http://bubl.siteuri.mozilla.org/"), - PlacesUtils._uri("http://bubl.feeduri.mozilla.org/"), bs.DEFAULT_INDEX); - addedBookmarks.push(id); // Remove all added bookmarks. addedBookmarks.forEach(function (aItem) { @@ -233,38 +219,7 @@ var bookmarksObserver = { ]), // nsIAnnotationObserver - onItemAnnotationSet: function(aItemId, aAnnotationName) { - if (aAnnotationName == PlacesUtils.LMANNO_FEEDURI) { - var views = getViewsForFolder(PlacesUtils.bookmarks.getFolderIdForItem(aItemId)); - ok(views.length > 0, "Found affected views (" + views.length + "): " + views); - - // Check that item is recognized as a livemark. - let validator = function(aElementOrTreeIndex) { - if (typeof(aElementOrTreeIndex) == "number") { - var sidebar = document.getElementById("sidebar"); - var tree = sidebar.contentDocument.getElementById("bookmarks-view"); - let livemarkAtom = Cc["@mozilla.org/atom-service;1"]. - getService(Ci.nsIAtomService). - getAtom("livemark"); - let properties = Cc["@mozilla.org/supports-array;1"]. - createInstance(Ci.nsISupportsArray); - tree.view.getCellProperties(aElementOrTreeIndex, - tree.columns.getColumnAt(0), - properties); - return properties.GetIndexOf(livemarkAtom) != -1; - } - else { - return aElementOrTreeIndex.hasAttribute("livemark"); - } - }; - - for (var i = 0; i < views.length; i++) { - var [node, index, valid] = searchItemInView(aItemId, views[i], validator); - isnot(node, null, "Found new Places node in " + views[i] + " at " + index); - ok(valid, "Node is recognized as a livemark"); - } - } - }, + onItemAnnotationSet: function() {}, onItemAnnotationRemoved: function() {}, onPageAnnotationSet: function() {}, onPageAnnotationRemoved: function() {}, diff --git a/browser/components/places/tests/unit/head_bookmarks.js b/browser/components/places/tests/unit/head_bookmarks.js index 64c16c620ab..557e45b35a0 100644 --- a/browser/components/places/tests/unit/head_bookmarks.js +++ b/browser/components/places/tests/unit/head_bookmarks.js @@ -102,7 +102,7 @@ let (backup_date = new Date().toLocaleFormat("%Y-%m-%d")) { } // Smart bookmarks constants. -const SMART_BOOKMARKS_VERSION = 2; +const SMART_BOOKMARKS_VERSION = 3; const SMART_BOOKMARKS_ON_TOOLBAR = 1; const SMART_BOOKMARKS_ON_MENU = 3; // Takes in count the additional separator. diff --git a/browser/components/places/tests/unit/test_384370.js b/browser/components/places/tests/unit/test_384370.js index 3944dbd7bca..adb7c4ae34c 100644 --- a/browser/components/places/tests/unit/test_384370.js +++ b/browser/components/places/tests/unit/test_384370.js @@ -36,11 +36,6 @@ * * ***** END LICENSE BLOCK ***** */ -// The following components need to be initialized to perform tests without -// asserting in debug builds (Bug 448804). -Cc["@mozilla.org/browser/livemark-service;2"].getService(Ci.nsILivemarkService); -Cc["@mozilla.org/feed-processor;1"].createInstance(Ci.nsIFeedProcessor); - const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar"; const DESCRIPTION_ANNO = "bookmarkProperties/description"; const POST_DATA_ANNO = "bookmarkProperties/POSTData"; @@ -49,6 +44,7 @@ do_check_eq(typeof PlacesUtils, "object"); // main function run_test() { + do_test_pending(); /* HTML+FEATURES SUMMARY: - import legacy bookmarks @@ -92,21 +88,25 @@ function run_test() { populate(); validate(); - // Test exporting a Places canonical json file. - // 1. export to bookmarks.exported.json - // 2. empty bookmarks db - // 3. import bookmarks.exported.json - // 4. run the test-suite - try { - PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile); - } catch(ex) { do_throw("couldn't export to file: " + ex); } - LOG("exported json"); - try { - PlacesUtils.restoreBookmarksFromJSONFile(jsonFile); - } catch(ex) { do_throw("couldn't import the exported file: " + ex); } - LOG("imported json"); - validate(); - LOG("validated import"); + waitForAsyncUpdates(function () { + // Test exporting a Places canonical json file. + // 1. export to bookmarks.exported.json + // 2. empty bookmarks db + // 3. import bookmarks.exported.json + // 4. run the test-suite + try { + PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile); + } catch(ex) { do_throw("couldn't export to file: " + ex); } + LOG("exported json"); + try { + PlacesUtils.restoreBookmarksFromJSONFile(jsonFile); + } catch(ex) { do_throw("couldn't import the exported file: " + ex); } + LOG("imported json"); + validate(); + LOG("validated import"); + + waitForAsyncUpdates(do_test_finished); + }); } var tagData = [ @@ -243,14 +243,17 @@ function testToolbarFolder() { var livemark = toolbar.getChild(1); // title do_check_eq("Latest Headlines", livemark.title); - // livemark check - do_check_true(PlacesUtils.livemarks.isLivemark(livemark.itemId)); - // site url - do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/", - PlacesUtils.livemarks.getSiteURI(livemark.itemId).spec); - // feed url - do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml", - PlacesUtils.livemarks.getFeedURI(livemark.itemId).spec); + + PlacesUtils.livemarks.getLivemark( + { id: livemark.itemId }, + function (aStatus, aLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/", + aLivemark.siteURI.spec); + do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml", + aLivemark.feedURI.spec); + } + ); // test added bookmark data var child = toolbar.getChild(2); diff --git a/browser/components/places/tests/unit/test_457441-import-export-corrupt-bookmarks-html.js b/browser/components/places/tests/unit/test_457441-import-export-corrupt-bookmarks-html.js index f7e20ba5962..f53451a2cdd 100644 --- a/browser/components/places/tests/unit/test_457441-import-export-corrupt-bookmarks-html.js +++ b/browser/components/places/tests/unit/test_457441-import-export-corrupt-bookmarks-html.js @@ -49,8 +49,6 @@ var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. getService(Ci.nsINavBookmarksService); var as = Cc["@mozilla.org/browser/annotation-service;1"]. getService(Ci.nsIAnnotationService); -var lms = Cc["@mozilla.org/browser/livemark-service;2"]. - getService(Ci.nsILivemarkService); var icos = Cc["@mozilla.org/browser/favicon-service;1"]. getService(Ci.nsIFaviconService); var ps = Cc["@mozilla.org/preferences-service;1"]. @@ -65,8 +63,9 @@ const POST_DATA_ANNO = "bookmarkProperties/POSTData"; const TEST_FAVICON_PAGE_URL = "http://en-US.www.mozilla.com/en-US/firefox/central/"; const TEST_FAVICON_DATA_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="; -// main function run_test() { + do_test_pending(); + // avoid creating the places smart folder during tests ps.setIntPref("browser.places.smartBookmarksVersion", -1); @@ -79,38 +78,41 @@ function run_test() { // Check that every bookmark is correct // Corrupt bookmarks should not have been imported database_check(); + waitForAsyncUpdates(function() { + // Create corruption in database + var corruptItemId = bs.insertBookmark(bs.toolbarFolder, + uri("http://test.mozilla.org"), + bs.DEFAULT_INDEX, "We love belugas"); + var stmt = dbConn.createStatement("UPDATE moz_bookmarks SET fk = NULL WHERE id = :itemId"); + stmt.params.itemId = corruptItemId; + stmt.execute(); + stmt.finalize(); - // Create corruption in database - var corruptItemId = bs.insertBookmark(bs.toolbarFolder, - uri("http://test.mozilla.org"), - bs.DEFAULT_INDEX, "We love belugas"); - var stmt = dbConn.createStatement("UPDATE moz_bookmarks SET fk = NULL WHERE id = :itemId"); - stmt.params.itemId = corruptItemId; - stmt.execute(); - stmt.finalize(); + // Export bookmarks + var bookmarksFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile); + bookmarksFile.append("bookmarks.exported.html"); + if (bookmarksFile.exists()) + bookmarksFile.remove(false); + bookmarksFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600); + if (!bookmarksFile.exists()) + do_throw("couldn't create file: bookmarks.exported.html"); + try { + ies.exportHTMLToFile(bookmarksFile); + } catch(ex) { do_throw("couldn't export to bookmarks.exported.html: " + ex); } - // Export bookmarks - var bookmarksFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile); - bookmarksFile.append("bookmarks.exported.html"); - if (bookmarksFile.exists()) - bookmarksFile.remove(false); - bookmarksFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600); - if (!bookmarksFile.exists()) - do_throw("couldn't create file: bookmarks.exported.html"); - try { - ies.exportHTMLToFile(bookmarksFile); - } catch(ex) { do_throw("couldn't export to bookmarks.exported.html: " + ex); } + // Clear all bookmarks + remove_all_bookmarks(); - // Clear all bookmarks - remove_all_bookmarks(); + // Import bookmarks + try { + ies.importHTMLFromFile(bookmarksFile, true); + } catch(ex) { do_throw("couldn't import the exported file: " + ex); } - // Import bookmarks - try { - ies.importHTMLFromFile(bookmarksFile, true); - } catch(ex) { do_throw("couldn't import the exported file: " + ex); } + // Check that every bookmark is correct + database_check(); - // Check that every bookmark is correct - database_check(); + waitForAsyncUpdates(do_test_finished); + }); } /* @@ -192,14 +194,16 @@ function database_check() { var livemark = toolbar.getChild(1); // title do_check_eq("Latest Headlines", livemark.title); - // livemark check - do_check_true(lms.isLivemark(livemark.itemId)); - // site url - do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/", - lms.getSiteURI(livemark.itemId).spec); - // feed url - do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml", - lms.getFeedURI(livemark.itemId).spec); + PlacesUtils.livemarks.getLivemark( + { id: livemark.itemId }, + function (aStatus, aLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/", + aLivemark.siteURI.spec); + do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml", + aLivemark.feedURI.spec); + } + ); // cleanup toolbar.containerOpen = false; diff --git a/browser/components/places/tests/unit/test_bookmarks_html.js b/browser/components/places/tests/unit/test_bookmarks_html.js index 116de805e06..b32430d8def 100644 --- a/browser/components/places/tests/unit/test_bookmarks_html.js +++ b/browser/components/places/tests/unit/test_bookmarks_html.js @@ -83,7 +83,6 @@ let test_bookmarks = { icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" }, { title: "Latest Headlines", - description: "Livemark test comment", url: "http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/", feedUrl: "http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml", } @@ -105,6 +104,10 @@ let importer = Cc["@mozilla.org/browser/places/import-export-service;1"]. function run_test() { + run_next_test(); +} + +add_test(function setup() { // Avoid creating smart bookmarks during the test. Services.prefs.setIntPref("browser.places.smartBookmarksVersion", -1); @@ -131,16 +134,20 @@ function run_test() importer.importHTMLFromFile(gBookmarksFileOld, true); } catch(ex) { do_throw("couldn't import legacy bookmarks file: " + ex); } - testImportedBookmarks(); + waitForAsyncUpdates(function () { + testImportedBookmarks(); - // Prepare for next tests. - try { - importer.exportHTMLToFile(gBookmarksFileNew); - } catch(ex) { do_throw("couldn't export to file: " + ex); } + // Prepare for next tests. + try { + importer.exportHTMLToFile(gBookmarksFileNew); + } catch(ex) { do_throw("couldn't export to file: " + ex); } - remove_all_bookmarks(); - run_next_test(); -} + waitForAsyncUpdates(function () { + remove_all_bookmarks(); + run_next_test(); + }); + }); +}); add_test(function test_import_new() { @@ -152,10 +159,14 @@ add_test(function test_import_new() importer.importHTMLFromFile(gBookmarksFileNew, true); } catch(ex) { do_throw("couldn't import the exported file: " + ex); } - testImportedBookmarks(); + waitForAsyncUpdates(function () { + testImportedBookmarks(); - remove_all_bookmarks(); - run_next_test(); + waitForAsyncUpdates(function () { + remove_all_bookmarks(); + run_next_test(); + }); + }); }); add_test(function test_emptytitle_export() @@ -189,18 +200,22 @@ add_test(function test_emptytitle_export() importer.importHTMLFromFile(gBookmarksFileNew, true); } catch(ex) { do_throw("couldn't import the exported file: " + ex); } - testImportedBookmarks(); + waitForAsyncUpdates(function () { + testImportedBookmarks(); - // Cleanup. - test_bookmarks.unfiled.pop(); - PlacesUtils.bookmarks.removeItem(id); + // Cleanup. + test_bookmarks.unfiled.pop(); + PlacesUtils.bookmarks.removeItem(id); - try { - importer.exportHTMLToFile(gBookmarksFileNew); - } catch(ex) { do_throw("couldn't export to file: " + ex); } + try { + importer.exportHTMLToFile(gBookmarksFileNew); + } catch(ex) { do_throw("couldn't export to file: " + ex); } - remove_all_bookmarks(); - run_next_test(); + waitForAsyncUpdates(function () { + remove_all_bookmarks(); + run_next_test(); + }); + }); }); add_test(function test_import_preplaces_to_folder() @@ -218,11 +233,15 @@ add_test(function test_import_preplaces_to_folder() importer.importHTMLFromFileToFolder(gBookmarksFileOld, testFolder, false); } catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); } - // Import-to-folder creates subfolders for toolbar and unfiled. - testImportedBookmarksToFolder(testFolder); + waitForAsyncUpdates(function () { + // Import-to-folder creates subfolders for toolbar and unfiled. + testImportedBookmarksToFolder(testFolder); - remove_all_bookmarks(); - run_next_test(); + waitForAsyncUpdates(function () { + remove_all_bookmarks(); + run_next_test(); + }); + }); }); add_test(function test_import_to_folder() @@ -240,11 +259,15 @@ add_test(function test_import_to_folder() importer.importHTMLFromFileToFolder(gBookmarksFileNew, testFolder, false); } catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); } - // Import-to-folder creates subfolders for toolbar and unfiled. - testImportedBookmarksToFolder(testFolder); + waitForAsyncUpdates(function () { + // Import-to-folder creates subfolders for toolbar and unfiled. + testImportedBookmarksToFolder(testFolder); - remove_all_bookmarks(); - run_next_test(); + waitForAsyncUpdates(function () { + remove_all_bookmarks(); + run_next_test(); + }); + }); }); add_test(function test_import_ontop() @@ -267,10 +290,14 @@ add_test(function test_import_ontop() importer.importHTMLFromFile(gBookmarksFileNew, true); } catch(ex) { do_throw("couldn't import the exported file: " + ex); } - testImportedBookmarks(); + waitForAsyncUpdates(function () { + testImportedBookmarks(); - remove_all_bookmarks(); - run_next_test(); + waitForAsyncUpdates(function () { + remove_all_bookmarks(); + run_next_test(); + }); + }); }); function testImportedBookmarks() @@ -350,8 +377,14 @@ function checkItem(aExpected, aNode) aExpected.lastModified); break; case "url": - if (!PlacesUtils.livemarks.isLivemark(id)) - do_check_eq(aNode.uri, aExpected.url); + PlacesUtils.livemarks.getLivemark( + { id: id }, + function (aStatus, aLivemark) { + if (!Components.isSuccessCode(aStatus)) { + do_check_eq(aNode.uri, aExpected.url); + } + } + ); break; case "icon": let faviconURI = PlacesUtils.favicons.getFaviconForPage( @@ -378,11 +411,14 @@ function checkItem(aExpected, aNode) aExpected.charset); break; case "feedUrl": - do_check_true(PlacesUtils.livemarks.isLivemark(id)); - do_check_eq(PlacesUtils.livemarks.getSiteURI(id).spec, - aExpected.url); - do_check_eq(PlacesUtils.livemarks.getFeedURI(id).spec, - aExpected.feedUrl); + PlacesUtils.livemarks.getLivemark( + { id: id }, + function (aStatus, aLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.siteURI.spec, aExpected.url); + do_check_eq(aLivemark.feedURI.spec, Expected.feedUrl); + } + ); break; case "children": let folder = aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode); diff --git a/browser/components/places/tests/unit/test_placesTxn.js b/browser/components/places/tests/unit/test_placesTxn.js index 0bc206b3ba8..78f5a3a538e 100644 --- a/browser/components/places/tests/unit/test_placesTxn.js +++ b/browser/components/places/tests/unit/test_placesTxn.js @@ -39,7 +39,6 @@ * ***** END LICENSE BLOCK ***** */ var bmsvc = PlacesUtils.bookmarks; -var lmsvc = PlacesUtils.livemarks; var ptSvc = PlacesUIUtils.ptm; var tagssvc = PlacesUtils.tagging; var annosvc = PlacesUtils.annotations; @@ -419,84 +418,6 @@ function run_test() { do_check_eq(observer._itemChangedProperty, "keyword"); do_check_eq(observer._itemChangedValue, ""); - // Testing create livemark - var txn12 = ptSvc.createLivemark(uri("http://feeduri.com"), - uri("http://siteuri.com"), - "Livemark1", root); - txn12.doTransaction(); - var lvmkId = observer._itemAddedId; - do_check_true(lmsvc.isLivemark(lvmkId)); - do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/"); - do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/"); - txn12.undoTransaction(); - do_check_false(lmsvc.isLivemark(lvmkId)); - txn12.redoTransaction(); - lvmkId = observer._itemAddedId; - do_check_true(lmsvc.isLivemark(lvmkId)); - do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/"); - do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/"); - - // editLivemarkSiteURI - var txn13 = ptSvc.editLivemarkSiteURI(lvmkId, uri("http://new-siteuri.com/")); - txn13.doTransaction(); - do_check_eq(observer._itemChangedId, lvmkId); - do_check_eq(observer._itemChangedProperty, "livemark/siteURI"); - do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://new-siteuri.com/"); - txn13.undoTransaction(); - do_check_eq(observer._itemChangedId, lvmkId); - do_check_eq(observer._itemChangedProperty, "livemark/siteURI"); - do_check_eq(observer._itemChangedValue, ""); - do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/"); - txn13.redoTransaction(); - do_check_eq(observer._itemChangedId, lvmkId); - do_check_eq(observer._itemChangedProperty, "livemark/siteURI"); - do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://new-siteuri.com/"); - txn13.undoTransaction(); - do_check_eq(observer._itemChangedId, lvmkId); - do_check_eq(observer._itemChangedProperty, "livemark/siteURI"); - do_check_eq(observer._itemChangedValue, ""); - do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/"); - - // editLivemarkFeedURI - var txn14 = ptSvc.editLivemarkFeedURI(lvmkId, uri("http://new-feeduri.com/")); - txn14.doTransaction(); - do_check_eq(observer._itemChangedId, lvmkId); - do_check_eq(observer._itemChangedProperty, "livemark/feedURI"); - do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://new-feeduri.com/"); - txn14.undoTransaction(); - do_check_eq(observer._itemChangedId, lvmkId); - do_check_eq(observer._itemChangedProperty, "livemark/feedURI"); - do_check_eq(observer._itemChangedValue, ""); - do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/"); - txn14.redoTransaction(); - do_check_eq(observer._itemChangedId, lvmkId); - do_check_eq(observer._itemChangedProperty, "livemark/feedURI"); - do_check_eq(observer._itemChangedValue, ""); - do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://new-feeduri.com/"); - txn14.undoTransaction(); - do_check_eq(observer._itemChangedId, lvmkId); - do_check_eq(observer._itemChangedProperty, "livemark/feedURI"); - do_check_eq(observer._itemChangedValue, ""); - do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/"); - - // Testing remove livemark - // Set an annotation and check that we don't lose it on undo - annosvc.setItemAnnotation(lvmkId, "livemark/testAnno", "testAnno", - 0, annosvc.EXPIRE_NEVER); - var txn15 = ptSvc.removeItem(lvmkId); - txn15.doTransaction(); - do_check_false(lmsvc.isLivemark(lvmkId)); - do_check_eq(observer._itemRemovedId, lvmkId); - txn15.undoTransaction(); - lvmkId = observer._itemAddedId; - do_check_true(lmsvc.isLivemark(lvmkId)); - do_check_eq(lmsvc.getSiteURI(lvmkId).spec, "http://siteuri.com/"); - do_check_eq(lmsvc.getFeedURI(lvmkId).spec, "http://feeduri.com/"); - do_check_eq(annosvc.getItemAnnotation(lvmkId, "livemark/testAnno"), "testAnno"); - txn15.redoTransaction(); - do_check_false(lmsvc.isLivemark(lvmkId)); - do_check_eq(observer._itemRemovedId, lvmkId); - // Test LoadInSidebar transaction. var txn16 = ptSvc.setLoadInSidebar(bkmk1Id, true); txn16.doTransaction(); diff --git a/browser/components/places/tests/unit/test_txnGUIDs.js b/browser/components/places/tests/unit/test_txnGUIDs.js index d2abf40e7c4..d5188d9c131 100644 --- a/browser/components/places/tests/unit/test_txnGUIDs.js +++ b/browser/components/places/tests/unit/test_txnGUIDs.js @@ -41,47 +41,65 @@ * This test will ensure any transactions service that is going to create * a new item, won't replace the GUID when undoing and redoing the action. */ -var bmsvc = PlacesUtils.bookmarks; -var txnsvc = PlacesUIUtils.ptm; function test_GUID_persistance(aTxn) { aTxn.doTransaction(); - var itemId = bmsvc.getIdForItemAt(bmsvc.unfiledBookmarksFolder, 0); - var GUID = bmsvc.getItemGUID(itemId); - aTxn.undoTransaction(); - aTxn.redoTransaction(); - do_check_eq(GUID, bmsvc.getItemGUID(itemId)); - aTxn.undoTransaction(); + waitForAsyncUpdates(function () { + let itemId = PlacesUtils.bookmarks + .getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0); + let GUID = PlacesUtils.bookmarks.getItemGUID(itemId); + aTxn.undoTransaction(); + aTxn.redoTransaction(); + waitForAsyncUpdates(function() { + let itemId = PlacesUtils.bookmarks + .getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0); + do_check_eq(GUID, PlacesUtils.bookmarks.getItemGUID(itemId)); + aTxn.undoTransaction(); + waitForAsyncUpdates(run_next_test); + }); + }); } function run_test() { - // Create folder. - var createFolderTxn = txnsvc.createFolder("Test folder", - bmsvc.unfiledBookmarksFolder, - bmsvc.DEFAULT_INDEX); - test_GUID_persistance(createFolderTxn); - - // Create bookmark. - var createBookmarkTxn = txnsvc.createItem(uri("http://www.example.com"), - bmsvc.unfiledBookmarksFolder, - bmsvc.DEFAULT_INDEX, - "Test bookmark"); - test_GUID_persistance(createBookmarkTxn); - - // Create separator. - var createSeparatorTxn = txnsvc.createSeparator(bmsvc.unfiledBookmarksFolder, - bmsvc.DEFAULT_INDEX); - test_GUID_persistance(createFolderTxn); - - // Create livemark. - var createLivemarkTxn = txnsvc.createLivemark(uri("http://feeduri.com"), - uri("http://siteuri.com"), - "Test livemark", - bmsvc.unfiledBookmarksFolder, - bmsvc.DEFAULT_INDEX); - test_GUID_persistance(createLivemarkTxn); - - // Tag URI. - var tagURITxn = txnsvc.tagURI(uri("http://www.example.com"), ["foo"]); - test_GUID_persistance(tagURITxn); + run_next_test(); } + +add_test(function create_folder() { + let createFolderTxn = new PlacesCreateFolderTransaction( + "Test folder", PlacesUtils.unfiledBookmarksFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX + ); + test_GUID_persistance(createFolderTxn); +}); + +add_test(function create_bookmark() { + let createBookmarkTxn = new PlacesCreateBookmarkTransaction( + NetUtil.newURI("http://www.example.com"), PlacesUtils.unfiledBookmarksFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX, "Test bookmark" + ); + test_GUID_persistance(createBookmarkTxn); +}); + +add_test(function create_separator() { + let createSeparatorTxn = new PlacesCreateSeparatorTransaction( + PlacesUtils.unfiledBookmarksFolderId, PlacesUtils.bookmarks.DEFAULT_INDEX + ); + test_GUID_persistance(createSeparatorTxn); +}); + +add_test(function tag_uri() { + let tagURITxn = new PlacesTagURITransaction( + NetUtil.newURI("http://www.example.com"), ["foo"] + ); + test_GUID_persistance(tagURITxn); +}); + +add_test(function create_livemark() { + let createLivemarkTxn = new PlacesCreateLivemarkTransaction( + NetUtil.newURI("http://feeduri.com"), NetUtil.newURI("http://siteuri.com"), + "Test livemark", PlacesUtils.unfiledBookmarksFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX + ); + test_GUID_persistance(createLivemarkTxn); +}); + diff --git a/browser/fuel/src/fuelApplication.js b/browser/fuel/src/fuelApplication.js index cc087321312..e57e0c8b109 100644 --- a/browser/fuel/src/fuelApplication.js +++ b/browser/fuel/src/fuelApplication.js @@ -55,7 +55,8 @@ var Utilities = { get livemarks() { let livemarks = Cc["@mozilla.org/browser/livemark-service;2"]. - getService(Ci.nsILivemarkService); + getService[Ci.mozIAsyncLivemarks]. + QueryInterface(Ci.nsILivemarkService); this.__defineGetter__("livemarks", function() livemarks); return this.livemarks; }, diff --git a/browser/themes/gnomestripe/browser.css b/browser/themes/gnomestripe/browser.css index 3a2360963b2..4c23cadb2ed 100644 --- a/browser/themes/gnomestripe/browser.css +++ b/browser/themes/gnomestripe/browser.css @@ -213,6 +213,11 @@ menuitem.bookmark-item { .bookmark-item[container][livemark] .bookmark-item { list-style-image: url("chrome://browser/skin/places/livemark-item.png"); + -moz-image-region: rect(0px, 16px, 16px, 0px); +} + +.bookmark-item[container][livemark] .bookmark-item[visited] { + -moz-image-region: rect(0px, 32px, 16px, 16px); } .bookmark-item[container][query] { diff --git a/browser/themes/gnomestripe/places/livemark-item.png b/browser/themes/gnomestripe/places/livemark-item.png index 1ed34429cca..8ef1ba4a5cd 100644 Binary files a/browser/themes/gnomestripe/places/livemark-item.png and b/browser/themes/gnomestripe/places/livemark-item.png differ diff --git a/browser/themes/gnomestripe/places/places.css b/browser/themes/gnomestripe/places/places.css index fe426d87c81..fd05a48e36b 100644 --- a/browser/themes/gnomestripe/places/places.css +++ b/browser/themes/gnomestripe/places/places.css @@ -28,6 +28,11 @@ treechildren::-moz-tree-image(title) { treechildren::-moz-tree-image(title, livemarkItem) { list-style-image: url("chrome://browser/skin/places/livemark-item.png"); + -moz-image-region: rect(0px, 16px, 16px, 0px); +} + +treechildren::-moz-tree-image(title, livemarkItem, visited) { + -moz-image-region: rect(0px, 32px, 16px, 16px); } treechildren::-moz-tree-image(title, separator) { diff --git a/browser/themes/pinstripe/browser.css b/browser/themes/pinstripe/browser.css index 565fe6fe68d..a8c668dea8c 100644 --- a/browser/themes/pinstripe/browser.css +++ b/browser/themes/pinstripe/browser.css @@ -258,7 +258,12 @@ toolbarbutton.bookmark-item > menupopup { } .bookmark-item[livemark] .menuitem-iconic { - list-style-image: url("chrome://browser/skin/livemark-item.png"); + list-style-image: url("chrome://browser/skin/places/livemark-item.png"); + -moz-image-region: rect(0px, 16px, 16px, 0px); +} + +.bookmark-item[livemark] .menuitem-iconic[visited] { + -moz-image-region: rect(0px, 32px, 16px, 16px); } .bookmark-item menuitem[openInTabs], diff --git a/browser/themes/pinstripe/jar.mn b/browser/themes/pinstripe/jar.mn index d7236c745b1..0ca0092be4b 100644 --- a/browser/themes/pinstripe/jar.mn +++ b/browser/themes/pinstripe/jar.mn @@ -29,7 +29,6 @@ browser.jar: skin/classic/browser/menu-back.png skin/classic/browser/menu-forward.png skin/classic/browser/page-livemarks.png - skin/classic/browser/livemark-item.png skin/classic/browser/pageInfo.css skin/classic/browser/Privacy-16.png skin/classic/browser/Privacy-48.png @@ -90,6 +89,7 @@ browser.jar: skin/classic/browser/places/expander-closed.png (places/expander-closed.png) skin/classic/browser/places/expander-open-active.png (places/expander-open-active.png) skin/classic/browser/places/expander-open.png (places/expander-open.png) + skin/classic/browser/places/livemark-item.png (places/livemark-item.png) skin/classic/browser/preferences/alwaysAsk.png (preferences/alwaysAsk.png) skin/classic/browser/preferences/application.png (preferences/application.png) skin/classic/browser/preferences/Options.png (preferences/Options.png) diff --git a/browser/themes/pinstripe/livemark-item.png b/browser/themes/pinstripe/livemark-item.png deleted file mode 100644 index 32af074ad84..00000000000 Binary files a/browser/themes/pinstripe/livemark-item.png and /dev/null differ diff --git a/browser/themes/pinstripe/places/livemark-item.png b/browser/themes/pinstripe/places/livemark-item.png new file mode 100644 index 00000000000..8ef1ba4a5cd Binary files /dev/null and b/browser/themes/pinstripe/places/livemark-item.png differ diff --git a/browser/themes/pinstripe/places/places.css b/browser/themes/pinstripe/places/places.css index e48bdecab3a..41d2fd1dc40 100644 --- a/browser/themes/pinstripe/places/places.css +++ b/browser/themes/pinstripe/places/places.css @@ -97,7 +97,12 @@ treechildren::-moz-tree-image(title) { } treechildren::-moz-tree-image(title, livemarkItem) { - list-style-image: url("chrome://browser/skin/livemark-item.png"); + list-style-image: url("chrome://browser/skin/places/livemark-item.png"); + -moz-image-region: rect(0px, 16px, 16px, 0px); +} + +treechildren::-moz-tree-image(title, livemarkItem, visited) { + -moz-image-region: rect(0px, 32px, 16px, 16px); } treechildren::-moz-tree-image(title, container), diff --git a/browser/themes/winstripe/browser.css b/browser/themes/winstripe/browser.css index 3703c2a54f9..17620b2984d 100644 --- a/browser/themes/winstripe/browser.css +++ b/browser/themes/winstripe/browser.css @@ -609,8 +609,12 @@ menuitem.bookmark-item { } .bookmark-item[container][livemark] .bookmark-item { - list-style-image: url("chrome://browser/skin/livemark-item.png"); - -moz-image-region: auto; + list-style-image: url("chrome://browser/skin/places/livemark-item.png"); + -moz-image-region: rect(0px, 16px, 16px, 0px); +} + +.bookmark-item[container][livemark] .bookmark-item[visited] { + -moz-image-region: rect(0px, 32px, 16px, 16px); } .bookmark-item[container][query] { diff --git a/browser/themes/winstripe/jar.mn b/browser/themes/winstripe/jar.mn index 766a4d9d972..f652406065b 100644 --- a/browser/themes/winstripe/jar.mn +++ b/browser/themes/winstripe/jar.mn @@ -27,7 +27,6 @@ browser.jar: skin/classic/browser/pageInfo.css skin/classic/browser/pageInfo.png (pageInfo.png) skin/classic/browser/page-livemarks.png (feeds/feedIcon16.png) - skin/classic/browser/livemark-item.png (livemark-item.png) skin/classic/browser/livemark-folder.png (livemark-folder.png) skin/classic/browser/Privacy-16.png skin/classic/browser/Privacy-48.png @@ -80,6 +79,7 @@ browser.jar: skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png) skin/classic/browser/places/unsortedBookmarks.png (places/unsortedBookmarks.png) skin/classic/browser/places/downloads.png (places/downloads.png) + skin/classic/browser/places/livemark-item.png (places/livemark-item.png) skin/classic/browser/preferences/alwaysAsk.png (preferences/alwaysAsk.png) skin/classic/browser/preferences/application.png (preferences/application.png) skin/classic/browser/preferences/mail.png (preferences/mail.png) @@ -196,7 +196,6 @@ browser.jar: skin/classic/aero/browser/pageInfo.css skin/classic/aero/browser/pageInfo.png (pageInfo-aero.png) skin/classic/aero/browser/page-livemarks.png (feeds/feedIcon16-aero.png) - skin/classic/aero/browser/livemark-item.png (livemark-item-aero.png) skin/classic/aero/browser/livemark-folder.png (livemark-folder-aero.png) skin/classic/aero/browser/Privacy-16.png (Privacy-16-aero.png) skin/classic/aero/browser/Privacy-48.png (Privacy-48-aero.png) @@ -249,6 +248,7 @@ browser.jar: skin/classic/aero/browser/places/allBookmarks.png (places/allBookmarks-aero.png) skin/classic/aero/browser/places/unsortedBookmarks.png (places/unsortedBookmarks-aero.png) skin/classic/aero/browser/places/downloads.png (places/downloads.png) + skin/classic/aero/browser/places/livemark-item.png (places/livemark-item.png) skin/classic/aero/browser/preferences/alwaysAsk.png (preferences/alwaysAsk-aero.png) skin/classic/aero/browser/preferences/application.png (preferences/application-aero.png) skin/classic/aero/browser/preferences/mail.png (preferences/mail-aero.png) diff --git a/browser/themes/winstripe/livemark-item-aero.png b/browser/themes/winstripe/livemark-item-aero.png deleted file mode 100644 index 1fa03b78bc2..00000000000 Binary files a/browser/themes/winstripe/livemark-item-aero.png and /dev/null differ diff --git a/browser/themes/winstripe/livemark-item.png b/browser/themes/winstripe/livemark-item.png deleted file mode 100644 index 83139be7332..00000000000 Binary files a/browser/themes/winstripe/livemark-item.png and /dev/null differ diff --git a/browser/themes/winstripe/places/livemark-item.png b/browser/themes/winstripe/places/livemark-item.png new file mode 100644 index 00000000000..8ef1ba4a5cd Binary files /dev/null and b/browser/themes/winstripe/places/livemark-item.png differ diff --git a/browser/themes/winstripe/places/places.css b/browser/themes/winstripe/places/places.css index d6d31be0695..bd910f14fd6 100644 --- a/browser/themes/winstripe/places/places.css +++ b/browser/themes/winstripe/places/places.css @@ -30,7 +30,12 @@ treechildren::-moz-tree-image(title) { } treechildren::-moz-tree-image(title, livemarkItem) { - list-style-image: url("chrome://browser/skin/livemark-item.png"); + list-style-image: url("chrome://browser/skin/places/livemark-item.png"); + -moz-image-region: rect(0px, 16px, 16px, 0px); +} + +treechildren::-moz-tree-image(title, livemarkItem, visited) { + -moz-image-region: rect(0px, 32px, 16px, 16px); } treechildren::-moz-tree-image(title, separator) { diff --git a/build/unix/build-toolchain/build-gcc.py b/build/unix/build-toolchain/build-gcc.py index ddf349818c5..47ed4ccf11c 100755 --- a/build/unix/build-toolchain/build-gcc.py +++ b/build/unix/build-toolchain/build-gcc.py @@ -4,7 +4,7 @@ # a reproducible build is to run it in a know absolute directory. # We use a directory in /builds/slave because the mozilla infrastructure # cleans it up automatically. -base_dir = "/builds/slave/moz-toolschain" +base_dir = "/builds/slave/moz-toolchain" source_dir = base_dir + "/src" build_dir = base_dir + "/build" @@ -58,6 +58,10 @@ def build_aux_tools(base_dir): make_build_dir = base_dir + '/make_build' build_package(make_source_dir, make_build_dir, ["--prefix=%s" % aux_inst_dir], "make") + + run_in(unifdef_source_dir, ["make"]) + run_in(unifdef_source_dir, ["make", "prefix=%s" % aux_inst_dir, "install"]) + tar_build_dir = base_dir + '/tar_build' build_package(tar_source_dir, tar_build_dir, ["--prefix=%s" % aux_inst_dir]) @@ -84,12 +88,17 @@ def build_glibc_aux(stage_dir, inst_dir): "--libdir=%s/lib64" % inst_dir, "--prefix=%s" % inst_dir]) -def build_linux_headers(inst_dir): +def build_linux_headers_aux(inst_dir): run_in(linux_source_dir, [old_make, "headers_check"]) run_in(linux_source_dir, [old_make, "INSTALL_HDR_PATH=dest", "headers_install"]) shutil.move(linux_source_dir + "/dest", inst_dir) +def build_linux_headers(inst_dir): + def f(): + build_linux_headers_aux(inst_dir) + with_env({"PATH" : aux_inst_dir + "/bin:%s" % os.environ["PATH"]}, f) + def build_one_stage(env, stage_dir, is_stage_one): def f(): build_one_stage_aux(stage_dir, is_stage_one) @@ -167,6 +176,7 @@ gcc_version = "4.5.2" mpfr_version = "2.4.2" gmp_version = "5.0.1" mpc_version = "0.8.1" +unifdef_version = "2.6" binutils_source_uri = "http://ftp.gnu.org/gnu/binutils/binutils-%sa.tar.bz2" % \ binutils_version @@ -178,6 +188,8 @@ tar_source_uri = "http://ftp.gnu.org/gnu/tar/tar-%s.tar.bz2" % \ tar_version make_source_uri = "http://ftp.gnu.org/gnu/make/make-%s.tar.bz2" % \ make_version +unifdef_source_uri = "http://dotat.at/prog/unifdef/unifdef-%s.tar.gz" % \ + unifdef_version gcc_source_uri = "http://ftp.gnu.org/gnu/gcc/gcc-%s/gcc-%s.tar.bz2" % \ (gcc_version, gcc_version) mpfr_source_uri = "http://www.mpfr.org/mpfr-%s/mpfr-%s.tar.bz2" % \ @@ -191,6 +203,7 @@ glibc_source_tar = download_uri(glibc_source_uri) linux_source_tar = download_uri(linux_source_uri) tar_source_tar = download_uri(tar_source_uri) make_source_tar = download_uri(make_source_uri) +unifdef_source_tar = download_uri(unifdef_source_uri) mpc_source_tar = download_uri(mpc_source_uri) mpfr_source_tar = download_uri(mpfr_source_uri) gmp_source_tar = download_uri(gmp_source_uri) @@ -201,6 +214,7 @@ glibc_source_dir = build_source_dir('glibc-', glibc_version) linux_source_dir = build_source_dir('linux-', linux_version) tar_source_dir = build_source_dir('tar-', tar_version) make_source_dir = build_source_dir('make-', make_version) +unifdef_source_dir = build_source_dir('unifdef-', unifdef_version) mpc_source_dir = build_source_dir('mpc-', mpc_version) mpfr_source_dir = build_source_dir('mpfr-', mpfr_version) gmp_source_dir = build_source_dir('gmp-', gmp_version) @@ -216,6 +230,7 @@ if not os.path.exists(source_dir): run_in(glibc_source_dir, ["autoconf"]) extract(tar_source_tar, source_dir) extract(make_source_tar, source_dir) + extract(unifdef_source_tar, source_dir) extract(mpc_source_tar, source_dir) extract(mpfr_source_tar, source_dir) extract(gmp_source_tar, source_dir) diff --git a/content/base/src/nsEventSource.cpp b/content/base/src/nsEventSource.cpp index b0860e28151..520c6633c8b 100644 --- a/content/base/src/nsEventSource.cpp +++ b/content/base/src/nsEventSource.cpp @@ -903,13 +903,6 @@ nsEventSource::SetupHttpChannel() NS_ENSURE_SUCCESS(rv, rv); } - nsCOMPtr notificationCallbacks; - mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks)); - if (notificationCallbacks != this) { - mNotificationCallbacks = notificationCallbacks; - mHttpChannel->SetNotificationCallbacks(this); - } - return NS_OK; } @@ -952,6 +945,13 @@ nsEventSource::InitChannelAndRequestEventSource() rv = SetupHttpChannel(); NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr notificationCallbacks; + mHttpChannel->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks)); + if (notificationCallbacks != this) { + mNotificationCallbacks = notificationCallbacks; + mHttpChannel->SetNotificationCallbacks(this); + } + nsCOMPtr listener = new nsCORSListenerProxy(this, mPrincipal, mHttpChannel, mWithCredentials, &rv); diff --git a/content/base/test/Makefile.in b/content/base/test/Makefile.in index 5cbfadf1bf7..7070f64e1f0 100644 --- a/content/base/test/Makefile.in +++ b/content/base/test/Makefile.in @@ -486,8 +486,13 @@ _TEST_FILES2 = \ test_blobbuilder.html \ fileutils.js \ test_bug338583.html \ + test_EventSource_redirects.html \ eventsource.resource \ eventsource.resource^headers^ \ + eventsource_redirect.resource \ + eventsource_redirect.resource^headers^ \ + eventsource_redirect_to.resource \ + eventsource_redirect_to.resource^headers^ \ badContentType.eventsource \ badContentType.eventsource^headers^ \ badEventFieldName.eventsource \ diff --git a/content/base/test/eventsource_redirect.resource b/content/base/test/eventsource_redirect.resource new file mode 100644 index 00000000000..d073527bfbd --- /dev/null +++ b/content/base/test/eventsource_redirect.resource @@ -0,0 +1,2 @@ +redirected + diff --git a/content/base/test/eventsource_redirect.resource^headers^ b/content/base/test/eventsource_redirect.resource^headers^ new file mode 100644 index 00000000000..eb79e2f8148 --- /dev/null +++ b/content/base/test/eventsource_redirect.resource^headers^ @@ -0,0 +1,3 @@ +HTTP 301 Moved Permanently +Location: eventsource_redirect_to.resource + diff --git a/content/base/test/eventsource_redirect_to.resource b/content/base/test/eventsource_redirect_to.resource new file mode 100644 index 00000000000..cbd6078c7b0 --- /dev/null +++ b/content/base/test/eventsource_redirect_to.resource @@ -0,0 +1,3 @@ +retry:500 +data: 1 + diff --git a/content/base/test/eventsource_redirect_to.resource^headers^ b/content/base/test/eventsource_redirect_to.resource^headers^ new file mode 100644 index 00000000000..6a63b5341d0 --- /dev/null +++ b/content/base/test/eventsource_redirect_to.resource^headers^ @@ -0,0 +1,3 @@ +Content-Type: text/event-stream +Cache-Control: no-cache, must-revalidate + diff --git a/content/base/test/test_EventSource_redirects.html b/content/base/test/test_EventSource_redirects.html new file mode 100644 index 00000000000..aa491d873aa --- /dev/null +++ b/content/base/test/test_EventSource_redirects.html @@ -0,0 +1,59 @@ + + + + + + Test for Bug 338583 + + + + + + +Mozilla Bug 716841 +

+ +
+
+
+ + + + diff --git a/content/canvas/src/CustomQS_Canvas2D.h b/content/canvas/src/CustomQS_Canvas2D.h index 40e9a9e4806..63b1d4fa5bc 100644 --- a/content/canvas/src/CustomQS_Canvas2D.h +++ b/content/canvas/src/CustomQS_Canvas2D.h @@ -272,7 +272,7 @@ nsIDOMCanvasRenderingContext2D_CreateImageData(JSContext *cx, uintN argc, jsval return CreateImageData(cx, data_width, data_height, NULL, 0, 0, vp); } - jsdouble width, height; + double width, height; if (!JS_ValueToNumber(cx, argv[0], &width) || !JS_ValueToNumber(cx, argv[1], &height)) return false; @@ -311,7 +311,7 @@ nsIDOMCanvasRenderingContext2D_GetImageData(JSContext *cx, uintN argc, jsval *vp jsval *argv = JS_ARGV(cx, vp); - jsdouble xd, yd, width, height; + double xd, yd, width, height; if (!JS_ValueToNumber(cx, argv[0], &xd) || !JS_ValueToNumber(cx, argv[1], &yd) || !JS_ValueToNumber(cx, argv[2], &width) || diff --git a/content/canvas/src/WebGLContext.cpp b/content/canvas/src/WebGLContext.cpp index 929413909ea..9835bfbab76 100644 --- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -489,15 +489,9 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height) // if we want EGL, try it now if (!gl && (preferEGL || useANGLE) && !preferOpenGL) { gl = gl::GLContextProviderEGL::CreateOffscreen(gfxIntSize(width, height), format); - if (gl) { - if (InitAndValidateGL()) { - if (useANGLE) { - gl->SetFlushGuaranteesResolve(true); - } - } else { - LogMessage("Error during ANGLE OpenGL ES initialization"); - return NS_ERROR_FAILURE; - } + if (gl && !InitAndValidateGL()) { + LogMessage("Error during ANGLE OpenGL ES initialization"); + return NS_ERROR_FAILURE; } } #endif diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index e666ea1961d..6fc86ebd7b7 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -960,9 +960,6 @@ nsGenericHTMLElement::InsertAdjacentHTML(const nsAString& aPosition, case eAfterEnd: destination->InsertBefore(fragment, GetNextSibling(), &rv); break; - default: - NS_NOTREACHED("Bad position."); - break; } return rv; } diff --git a/content/html/content/src/nsHTMLOptionElement.cpp b/content/html/content/src/nsHTMLOptionElement.cpp index d717a18feb7..712787a813a 100644 --- a/content/html/content/src/nsHTMLOptionElement.cpp +++ b/content/html/content/src/nsHTMLOptionElement.cpp @@ -193,41 +193,25 @@ NS_IMPL_STRING_ATTR_WITH_FALLBACK(nsHTMLOptionElement, Label, label, GetText) NS_IMPL_STRING_ATTR_WITH_FALLBACK(nsHTMLOptionElement, Value, value, GetText) NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, Disabled, disabled) -NS_IMETHODIMP +NS_IMETHODIMP nsHTMLOptionElement::GetIndex(PRInt32* aIndex) { - NS_ENSURE_ARG_POINTER(aIndex); + // When the element is not in a list of options, the index is 0. + *aIndex = 0; - *aIndex = -1; // -1 indicates the index was not found - - // Get our containing select content object. + // Only select elements can contain a list of options. nsHTMLSelectElement* selectElement = GetSelect(); - - if (selectElement) { - // Get the options from the select object. - nsCOMPtr options; - selectElement->GetOptions(getter_AddRefs(options)); - - if (options) { - // Walk the options to find out where we are in the list (ick, O(n)) - PRUint32 length = 0; - options->GetLength(&length); - - nsCOMPtr thisOption; - - for (PRUint32 i = 0; i < length; i++) { - options->Item(i, getter_AddRefs(thisOption)); - - if (thisOption.get() == static_cast(this)) { - *aIndex = i; - - break; - } - } - } + if (!selectElement) { + return NS_OK; } - return NS_OK; + nsHTMLOptionCollection* options = selectElement->GetOptions(); + if (!options) { + return NS_OK; + } + + // aIndex will not be set if GetOptionsIndex fails. + return options->GetOptionIndex(this, 0, true, aIndex); } bool diff --git a/content/html/content/src/nsHTMLSelectElement.cpp b/content/html/content/src/nsHTMLSelectElement.cpp index a7112056b66..edc2105d981 100644 --- a/content/html/content/src/nsHTMLSelectElement.cpp +++ b/content/html/content/src/nsHTMLSelectElement.cpp @@ -1992,6 +1992,8 @@ nsHTMLOptionCollection::GetOptionIndex(mozilla::dom::Element* aOption, bool aForward, PRInt32* aIndex) { + // NOTE: aIndex shouldn't be set if the returned value isn't NS_OK. + PRInt32 index; // Make the common case fast diff --git a/content/html/content/src/nsHTMLSelectElement.h b/content/html/content/src/nsHTMLSelectElement.h index 7a4efc09844..51f7f76c924 100644 --- a/content/html/content/src/nsHTMLSelectElement.h +++ b/content/html/content/src/nsHTMLSelectElement.h @@ -143,7 +143,9 @@ public: void DropReference(); /** - * Finds the index of a given option element + * Finds the index of a given option element. + * If the option isn't part of the collection, return NS_ERROR_FAILURE + * without setting aIndex. * * @param aOption the option to get the index of * @param aStartIndex the index to start looking at diff --git a/content/html/content/test/forms/Makefile.in b/content/html/content/test/forms/Makefile.in index 3a9b9266284..d722d5d95cf 100644 --- a/content/html/content/test/forms/Makefile.in +++ b/content/html/content/test/forms/Makefile.in @@ -64,6 +64,7 @@ _TEST_FILES = \ test_maxlength_attribute.html \ test_datalist_element.html \ test_form_attributes_reflection.html \ + test_option_index_attribute.html \ $(NULL) libs:: $(_TEST_FILES) diff --git a/content/html/content/test/forms/test_option_index_attribute.html b/content/html/content/test/forms/test_option_index_attribute.html new file mode 100644 index 00000000000..5d51d299127 --- /dev/null +++ b/content/html/content/test/forms/test_option_index_attribute.html @@ -0,0 +1,76 @@ + + + + + + Test for option.index + + + + +Mozilla Bug 720385 +

+ +
+
+
+ + diff --git a/content/html/content/test/test_bug353415-2.html b/content/html/content/test/test_bug353415-2.html index b5c3c71e2d4..e2d9ac60882 100644 --- a/content/html/content/test/test_bug353415-2.html +++ b/content/html/content/test/test_bug353415-2.html @@ -5,7 +5,7 @@ - +
@@ -52,13 +52,14 @@
diff --git a/content/smil/nsSMILTimedElement.cpp b/content/smil/nsSMILTimedElement.cpp index e5cbb0c63dc..1bcdbe4668d 100644 --- a/content/smil/nsSMILTimedElement.cpp +++ b/content/smil/nsSMILTimedElement.cpp @@ -2200,11 +2200,8 @@ nsSMILTimedElement::GetNextMilestone(nsSMILMilestone& aNextMilestone) const case STATE_POSTACTIVE: return false; - - default: - NS_ABORT_IF_FALSE(false, "Invalid element state"); - return false; } + MOZ_NOT_REACHED("Invalid element state"); } void @@ -2275,11 +2272,8 @@ nsSMILTimedElement::GetEffectiveBeginInstance() const const nsSMILInterval* prevInterval = GetPreviousInterval(); return prevInterval ? prevInterval->Begin() : nsnull; } - - default: - NS_NOTREACHED("Invalid element state"); - return nsnull; } + MOZ_NOT_REACHED("Invalid element state"); } const nsSMILInterval* diff --git a/content/xul/templates/src/nsXULTemplateBuilder.cpp b/content/xul/templates/src/nsXULTemplateBuilder.cpp index 9ce8d92a683..d9c2f2ae78f 100644 --- a/content/xul/templates/src/nsXULTemplateBuilder.cpp +++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp @@ -164,6 +164,8 @@ DestroyMatchList(nsISupports* aKey, nsTemplateMatch*& aMatch, void* aContext) nsXULTemplateBuilder::~nsXULTemplateBuilder(void) { + Uninit(true); + if (--gRefCnt == 0) { NS_IF_RELEASE(gRDFService); NS_IF_RELEASE(gRDFContainerUtils); @@ -171,8 +173,6 @@ nsXULTemplateBuilder::~nsXULTemplateBuilder(void) NS_IF_RELEASE(gScriptSecurityManager); NS_IF_RELEASE(gObserverService); } - - Uninit(true); } diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index bc8b3f2dc5d..e8dcf5b7898 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -4472,7 +4472,7 @@ nsDOMClassInfo::GetArrayIndexFromId(JSContext *cx, jsid id, bool *aIsNumber) JSAutoRequest ar(cx); jsval idval; - jsdouble array_index; + double array_index; if (!::JS_IdToValue(cx, id, &idval) || !::JS_ValueToNumber(cx, idval, &array_index) || !::JS_DoubleIsInt32(array_index, &i)) { diff --git a/dom/indexedDB/IDBIndex.cpp b/dom/indexedDB/IDBIndex.cpp index 492c2cf15f3..d039e66e158 100644 --- a/dom/indexedDB/IDBIndex.cpp +++ b/dom/indexedDB/IDBIndex.cpp @@ -1450,5 +1450,5 @@ nsresult CountHelper::GetSuccessResult(JSContext* aCx, jsval* aVal) { - return JS_NewNumberValue(aCx, static_cast(mCount), aVal); + return JS_NewNumberValue(aCx, static_cast(mCount), aVal); } diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 86c81d8ea2d..c2376f531f4 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -900,7 +900,7 @@ SwapBytes(PRUint32 u) #endif } -static inline jsdouble +static inline double SwapBytes(PRUint64 u) { #ifdef IS_BIG_ENDIAN @@ -913,7 +913,7 @@ SwapBytes(PRUint64 u) ((u & 0x00ff000000000000LLU) >> 40) | ((u & 0xff00000000000000LLU) >> 56); #else - return jsdouble(u); + return double(u); #endif } @@ -2019,7 +2019,7 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) // This is a duplicate of the js engine's byte munging here union { - jsdouble d; + double d; PRUint64 u; } pun; @@ -2851,5 +2851,5 @@ nsresult CountHelper::GetSuccessResult(JSContext* aCx, jsval* aVal) { - return JS_NewNumberValue(aCx, static_cast(mCount), aVal); + return JS_NewNumberValue(aCx, static_cast(mCount), aVal); } diff --git a/dom/indexedDB/Key.cpp b/dom/indexedDB/Key.cpp index cc2d39ebd09..5f354439669 100644 --- a/dom/indexedDB/Key.cpp +++ b/dom/indexedDB/Key.cpp @@ -248,7 +248,7 @@ Key::DecodeJSVal(const unsigned char*& aPos, const unsigned char* aEnd, } } else if (*aPos - aTypeOffset == eDate) { - jsdouble msec = static_cast(DecodeNumber(aPos, aEnd)); + double msec = static_cast(DecodeNumber(aPos, aEnd)); JSObject* date = JS_NewDateObjectMsec(aCx, msec); if (!date) { NS_WARNING("Failed to make date!"); diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index a8470b62967..b063c93cdda 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -457,7 +457,7 @@ JSValToNPVariant(NPP npp, JSContext *cx, jsval val, NPVariant *variant) } else if (JSVAL_IS_INT(val)) { INT32_TO_NPVARIANT(JSVAL_TO_INT(val), *variant); } else if (JSVAL_IS_DOUBLE(val)) { - jsdouble d = JSVAL_TO_DOUBLE(val); + double d = JSVAL_TO_DOUBLE(val); jsint i; if (JS_DoubleIsInt32(d, &i)) { INT32_TO_NPVARIANT(i, *variant); diff --git a/dom/sms/src/SmsMessage.cpp b/dom/sms/src/SmsMessage.cpp index 190fbf97aee..7ada2876398 100644 --- a/dom/sms/src/SmsMessage.cpp +++ b/dom/sms/src/SmsMessage.cpp @@ -108,7 +108,7 @@ SmsMessage::Create(PRInt32 aId, if (!aTimestamp.isNumber()) { return NS_ERROR_INVALID_ARG; } - jsdouble number = aTimestamp.toNumber(); + double number = aTimestamp.toNumber(); if (static_cast(number) != number) { return NS_ERROR_INVALID_ARG; } diff --git a/dom/telephony/Telephony.cpp b/dom/telephony/Telephony.cpp index 3c7317c8d6e..6bec4e5237c 100644 --- a/dom/telephony/Telephony.cpp +++ b/dom/telephony/Telephony.cpp @@ -41,13 +41,16 @@ #include "nsIDocument.h" #include "nsIURI.h" +#include "nsIURL.h" #include "nsPIDOMWindow.h" #include "jsapi.h" #include "mozilla/Preferences.h" +#include "nsCharSeparatedTokenizer.h" #include "nsContentUtils.h" #include "nsDOMClassInfo.h" #include "nsIInterfaceRequestorUtils.h" +#include "nsNetUtil.h" #include "nsServiceManagerUtils.h" #include "SystemWorkerManager.h" @@ -61,6 +64,10 @@ using mozilla::Preferences; namespace { +typedef nsAutoTArray TelephonyList; + +TelephonyList* gTelephonyList; + template inline nsresult nsTArrayToJSArray(JSContext* aCx, JSObject* aGlobal, @@ -110,6 +117,16 @@ nsTArrayToJSArray(JSContext* aCx, JSObject* aGlobal, } // anonymous namespace +Telephony::Telephony() +: mActiveCall(nsnull), mCallsArray(nsnull), mRooted(false) +{ + if (!gTelephonyList) { + gTelephonyList = new TelephonyList(); + } + + gTelephonyList->AppendElement(this); +} + Telephony::~Telephony() { if (mRIL && mRILTelephonyCallback) { @@ -119,6 +136,17 @@ Telephony::~Telephony() if (mRooted) { NS_DROP_JS_OBJECTS(this, Telephony); } + + NS_ASSERTION(gTelephonyList, "This should never be null!"); + NS_ASSERTION(gTelephonyList->Contains(this), "Should be in the list!"); + + if (gTelephonyList->Length() == 1) { + delete gTelephonyList; + gTelephonyList = nsnull; + } + else { + gTelephonyList->RemoveElement(this); + } } // static @@ -150,14 +178,37 @@ Telephony::Create(nsPIDOMWindow* aOwner, nsIRadioInterfaceLayer* aRIL) return telephony.forget(); } -void -Telephony::SwitchActiveCall(TelephonyCall* aCall) +already_AddRefed +Telephony::CreateNewDialingCall(const nsAString& aNumber) { - if (mActiveCall) { - // Put the call on hold? - NS_NOTYETIMPLEMENTED("Implement me!"); - } - mActiveCall = aCall; + nsRefPtr call = + TelephonyCall::Create(this, aNumber, + nsIRadioInterfaceLayer::CALL_STATE_DIALING); + NS_ASSERTION(call, "This should never fail!"); + + NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!"); + + return call.forget(); +} + +void +Telephony::NoteDialedCallFromOtherInstance(const nsAString& aNumber) +{ + // We don't need to hang on to this call object, it is held alive by mCalls. + nsRefPtr call = CreateNewDialingCall(aNumber); +} + +nsresult +Telephony::NotifyCallsChanged(TelephonyCall* aCall) +{ + nsRefPtr event = CallEvent::Create(aCall); + NS_ASSERTION(event, "This should never fail!"); + + nsresult rv = + event->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("callschanged")); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; } NS_IMPL_CYCLE_COLLECTION_CLASS(Telephony) @@ -166,6 +217,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Telephony, nsDOMEventTargetHelper) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(incoming) + NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(callschanged) for (PRUint32 index = 0; index < tmp->mCalls.Length(); index++) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCalls[i]"); cb.NoteXPCOMChild(tmp->mCalls[index]->ToISupports()); @@ -180,6 +232,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Telephony, nsDOMEventTargetHelper) NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(incoming) + NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(callschanged) tmp->mCalls.Clear(); tmp->mActiveCall = nsnull; tmp->mCallsArray = nsnull; @@ -216,11 +269,16 @@ Telephony::Dial(const nsAString& aNumber, nsIDOMTelephonyCall** aResult) nsresult rv = mRIL->Dial(aNumber); NS_ENSURE_SUCCESS(rv, rv); - nsRefPtr call = - TelephonyCall::Create(this, aNumber, nsIRadioInterfaceLayer::CALL_STATE_DIALING); - NS_ASSERTION(call, "This should never fail!"); + nsRefPtr call = CreateNewDialingCall(aNumber); - NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!"); + // Notify other telephony objects that we just dialed. + for (PRUint32 index = 0; index < gTelephonyList->Length(); index++) { + Telephony*& telephony = gTelephonyList->ElementAt(index); + if (telephony != this) { + nsRefPtr kungFuDeathGrip = telephony; + telephony->NoteDialedCallFromOtherInstance(aNumber); + } + } call.forget(aResult); return NS_OK; @@ -279,32 +337,6 @@ Telephony::GetActive(jsval* aActive) return NS_OK; } -NS_IMETHODIMP -Telephony::SetActive(const jsval& aActive) -{ - if (aActive.isObject()) { - nsIXPConnect* xpc = nsContentUtils::XPConnect(); - NS_ASSERTION(xpc, "This should never be null!"); - - nsISupports* native = - xpc->GetNativeOfWrapper(mScriptContext->GetNativeContext(), - &aActive.toObject()); - - nsCOMPtr call = do_QueryInterface(native); - if (call) { - // See if this call has the same telephony object. Otherwise we can't use - // it. - TelephonyCall* concreteCall = static_cast(call.get()); - if (this == concreteCall->mTelephony) { - SwitchActiveCall(concreteCall); - return NS_OK; - } - } - } - - return NS_ERROR_INVALID_ARG; -} - NS_IMETHODIMP Telephony::GetCalls(jsval* aCalls) { @@ -354,15 +386,8 @@ Telephony::StopTone() return NS_OK; } -NS_IMETHODIMP -Telephony::SendTones(const nsAString& aTones, PRUint32 aToneDuration, - PRUint32 aIntervalDuration) -{ - NS_NOTYETIMPLEMENTED("Implement me!"); - return NS_ERROR_NOT_IMPLEMENTED; -} - NS_IMPL_EVENT_HANDLER(Telephony, incoming) +NS_IMPL_EVENT_HANDLER(Telephony, callschanged) NS_IMETHODIMP Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState, @@ -378,7 +403,8 @@ Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState, nsRefPtr& tempCall = mCalls[index]; if (tempCall->CallIndex() == kOutgoingPlaceholderCallIndex) { NS_ASSERTION(!outgoingCall, "More than one outgoing call not supported!"); - NS_ASSERTION(tempCall->CallState() == nsIRadioInterfaceLayer::CALL_STATE_DIALING, + NS_ASSERTION(tempCall->CallState() == + nsIRadioInterfaceLayer::CALL_STATE_DIALING, "Something really wrong here!"); // Stash this for later, we may need it if aCallIndex doesn't match one of // our other calls. @@ -407,7 +433,7 @@ Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState, // See if this should replace our current active call. if (aCallState == nsIRadioInterfaceLayer::CALL_STATE_CONNECTED) { - SwitchActiveCall(modifiedCall); + mActiveCall = modifiedCall; } return NS_OK; @@ -486,22 +512,48 @@ NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony) // Do security checks. We assume that chrome is always allowed and we also // allow a single page specified by preferences. if (!nsContentUtils::IsSystemPrincipal(document->NodePrincipal())) { - nsCOMPtr documentURI; + nsCOMPtr originalURI; nsresult rv = - document->NodePrincipal()->GetURI(getter_AddRefs(documentURI)); + document->NodePrincipal()->GetURI(getter_AddRefs(originalURI)); NS_ENSURE_SUCCESS(rv, rv); - nsCString documentURL; - rv = documentURI->GetSpec(documentURL); + nsCOMPtr documentURI; + rv = originalURI->Clone(getter_AddRefs(documentURI)); NS_ENSURE_SUCCESS(rv, rv); + // Strip the query string (if there is one) before comparing. + nsCOMPtr documentURL = do_QueryInterface(documentURI); + if (documentURL) { + rv = documentURL->SetQuery(EmptyCString()); + NS_ENSURE_SUCCESS(rv, rv); + } + + bool allowed = false; + // The pref may not exist but in that case we deny access just as we do if // the url doesn't match. - nsCString phoneAppURL; - if (NS_FAILED(Preferences::GetCString(DOM_TELEPHONY_APP_PHONE_URL_PREF, - &phoneAppURL)) || - !phoneAppURL.Equals(documentURL, - nsCaseInsensitiveCStringComparator())) { + nsCString whitelist; + if (NS_SUCCEEDED(Preferences::GetCString(DOM_TELEPHONY_APP_PHONE_URL_PREF, + &whitelist))) { + nsCOMPtr ios = do_GetIOService(); + NS_ENSURE_TRUE(ios, NS_ERROR_FAILURE); + + nsCCharSeparatedTokenizer tokenizer(whitelist, ','); + while (tokenizer.hasMoreTokens()) { + nsCOMPtr uri; + if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), tokenizer.nextToken(), + nsnull, nsnull, ios))) { + rv = documentURI->EqualsExceptRef(uri, &allowed); + NS_ENSURE_SUCCESS(rv, rv); + + if (allowed) { + break; + } + } + } + } + + if (!allowed) { *aTelephony = nsnull; return NS_OK; } diff --git a/dom/telephony/Telephony.h b/dom/telephony/Telephony.h index 3e3f3dbd90d..c374331f51b 100644 --- a/dom/telephony/Telephony.h +++ b/dom/telephony/Telephony.h @@ -58,6 +58,7 @@ class Telephony : public nsDOMEventTargetHelper, nsCOMPtr mRILTelephonyCallback; NS_DECL_EVENT_HANDLER(incoming) + NS_DECL_EVENT_HANDLER(callschanged) TelephonyCall* mActiveCall; nsTArray > mCalls; @@ -99,6 +100,7 @@ public: NS_ASSERTION(!mCalls.Contains(aCall), "Already know about this one!"); mCalls.AppendElement(aCall); mCallsArray = nsnull; + NotifyCallsChanged(aCall); } void @@ -107,6 +109,7 @@ public: NS_ASSERTION(mCalls.Contains(aCall), "Didn't know about this one!"); mCalls.RemoveElement(aCall); mCallsArray = nsnull; + NotifyCallsChanged(aCall); } nsIRadioInterfaceLayer* @@ -128,14 +131,17 @@ public: } private: - Telephony() - : mActiveCall(nsnull), mCallsArray(nsnull), mRooted(false) - { } - + Telephony(); ~Telephony(); + already_AddRefed + CreateNewDialingCall(const nsAString& aNumber); + void - SwitchActiveCall(TelephonyCall* aCall); + NoteDialedCallFromOtherInstance(const nsAString& aNumber); + + nsresult + NotifyCallsChanged(TelephonyCall* aCall); class RILTelephonyCallback : public nsIRILTelephonyCallback { diff --git a/dom/telephony/nsIDOMTelephony.idl b/dom/telephony/nsIDOMTelephony.idl index 4f5cdb12441..f4baa79e206 100644 --- a/dom/telephony/nsIDOMTelephony.idl +++ b/dom/telephony/nsIDOMTelephony.idl @@ -43,7 +43,7 @@ interface nsIDOMEventListener; interface nsIDOMTelephonyCall; -[scriptable, builtinclass, uuid(047be0d8-a9cd-49aa-8948-2f60ff3a7a18)] +[scriptable, builtinclass, uuid(0de46b73-be83-4970-ad15-45f92cb0902a)] interface nsIDOMTelephony : nsIDOMEventTarget { nsIDOMTelephonyCall dial(in DOMString number); @@ -53,16 +53,14 @@ interface nsIDOMTelephony : nsIDOMEventTarget // The call that is "active", i.e. receives microphone input and tones // generated via startTone. - attribute jsval active; + readonly attribute jsval active; // Array of all calls that are currently connected. readonly attribute jsval calls; void startTone(in DOMString tone); void stopTone(); - void sendTones(in DOMString tones, - [optional] in unsigned long toneDuration, - [optional] in unsigned long intervalDuration); attribute nsIDOMEventListener onincoming; + attribute nsIDOMEventListener oncallschanged; }; diff --git a/dom/workers/Events.cpp b/dom/workers/Events.cpp index 8e3cd92b339..38cb392eadb 100644 --- a/dom/workers/Events.cpp +++ b/dom/workers/Events.cpp @@ -850,7 +850,7 @@ public: static JSObject* Create(JSContext* aCx, JSObject* aParent, JSString* aType, - bool aLengthComputable, jsdouble aLoaded, jsdouble aTotal) + bool aLengthComputable, double aLoaded, double aTotal) { JSString* type = JS_InternJSString(aCx, aType); if (!type) { @@ -907,8 +907,8 @@ private: static void InitProgressEventCommon(JSObject* aObj, Event* aEvent, JSString* aType, JSBool aBubbles, JSBool aCancelable, - JSBool aLengthComputable, jsdouble aLoaded, - jsdouble aTotal, bool aIsTrusted) + JSBool aLengthComputable, double aLoaded, + double aTotal, bool aIsTrusted) { Event::InitEventCommon(aObj, aEvent, aType, aBubbles, aCancelable, aIsTrusted); @@ -967,7 +967,7 @@ private: JSString* type; JSBool bubbles, cancelable, lengthComputable; - jsdouble loaded, total; + double loaded, total; if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "Sbbbdd", &type, &bubbles, &cancelable, &lengthComputable, &loaded, &total)) { @@ -1065,7 +1065,7 @@ CreateErrorEvent(JSContext* aCx, JSString* aMessage, JSString* aFilename, JSObject* CreateProgressEvent(JSContext* aCx, JSString* aType, bool aLengthComputable, - jsdouble aLoaded, jsdouble aTotal) + double aLoaded, double aTotal) { JSObject* global = JS_GetGlobalForScopeChain(aCx); return ProgressEvent::Create(aCx, global, aType, aLengthComputable, aLoaded, diff --git a/dom/workers/Events.h b/dom/workers/Events.h index 0131613c08b..0f48e744a45 100644 --- a/dom/workers/Events.h +++ b/dom/workers/Events.h @@ -69,7 +69,7 @@ CreateErrorEvent(JSContext* aCx, JSString* aMessage, JSString* aFilename, JSObject* CreateProgressEvent(JSContext* aCx, JSString* aType, bool aLengthComputable, - jsdouble aLoaded, jsdouble aTotal); + double aLoaded, double aTotal); bool IsSupportedEventClass(JSObject* aEvent); diff --git a/dom/workers/File.cpp b/dom/workers/File.cpp index 5d0f695f4ee..19ba44bba1c 100644 --- a/dom/workers/File.cpp +++ b/dom/workers/File.cpp @@ -140,7 +140,7 @@ private: ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR); } - if (!JS_NewNumberValue(aCx, jsdouble(size), aVp)) { + if (!JS_NewNumberValue(aCx, double(size), aVp)) { return false; } @@ -183,7 +183,7 @@ private: return false; } - jsdouble start = 0, end = 0; + double start = 0, end = 0; JSString* jsContentType = JS_GetEmptyString(JS_GetRuntime(aCx)); if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "/IIS", &start, &end, &jsContentType)) { diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index b1dae0bbba0..8f96197ce48 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -3533,7 +3533,7 @@ WorkerPrivate::SetTimeout(JSContext* aCx, uintN aArgc, jsval* aVp, // See if any of the optional arguments were passed. if (aArgc > 1) { - jsdouble intervalMS = 0; + double intervalMS = 0; if (!JS_ValueToNumber(aCx, argv[1], &intervalMS)) { return false; } diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla index 6cf831e5d9b..218ff0a9e52 100644 --- a/gfx/angle/README.mozilla +++ b/gfx/angle/README.mozilla @@ -10,6 +10,8 @@ In this order: angle-limit-identifiers-to-250-chars.patch - see bug 675625 angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands. angle-castrate-bug-241.patch - see bug 699033 / angle bug 241 + angle-enforce-readpixels-spec.patch - see bug 724476. + angle-impl-read-bgra.patch - see bug 724476. In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE. diff --git a/gfx/angle/angle-enforce-readpixels-spec.patch b/gfx/angle/angle-enforce-readpixels-spec.patch new file mode 100644 index 00000000000..70f20b6f513 --- /dev/null +++ b/gfx/angle/angle-enforce-readpixels-spec.patch @@ -0,0 +1,34 @@ +From: Jeff Gilbert +Bug 724476 - ANGLE Bug 293 - Enforce readPixels format/type semantics + +diff --git a/gfx/angle/src/libGLESv2/libGLESv2.cpp b/gfx/angle/src/libGLESv2/libGLESv2.cpp +--- a/gfx/angle/src/libGLESv2/libGLESv2.cpp ++++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp +@@ -98,27 +98,16 @@ bool validReadFormatType(GLenum format, + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return false; + } + break; +- case GL_BGRA_EXT: +- switch (type) +- { +- case GL_UNSIGNED_BYTE: +- case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: +- case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: +- break; +- default: +- return false; +- } +- break; + case gl::IMPLEMENTATION_COLOR_READ_FORMAT: + switch (type) + { + case gl::IMPLEMENTATION_COLOR_READ_TYPE: + break; + default: + return false; + } diff --git a/gfx/angle/angle-impl-read-bgra.patch b/gfx/angle/angle-impl-read-bgra.patch new file mode 100644 index 00000000000..b1b59cba08b --- /dev/null +++ b/gfx/angle/angle-impl-read-bgra.patch @@ -0,0 +1,71 @@ +From: Jeff Gilbert +Bug 724476 - ANGLE Bug 294 - Use BGRA/UBYTE as exposed fast format/type for readPixels + +diff --git a/gfx/angle/src/libGLESv2/Context.cpp b/gfx/angle/src/libGLESv2/Context.cpp +--- a/gfx/angle/src/libGLESv2/Context.cpp ++++ b/gfx/angle/src/libGLESv2/Context.cpp +@@ -2520,16 +2520,17 @@ void Context::readPixels(GLint x, GLint + { + if (desc.Format == D3DFMT_A8R8G8B8 && + format == GL_BGRA_EXT && + type == GL_UNSIGNED_BYTE) + { + // Fast path for EXT_read_format_bgra, given + // an RGBA source buffer. Note that buffers with no + // alpha go through the slow path below. ++ // Note that this is also the combo exposed by IMPLEMENTATION_COLOR_READ_TYPE/FORMAT + memcpy(dest + j * outputPitch, + source + j * inputPitch, + (rect.right - rect.left) * 4); + continue; + } + + for (int i = 0; i < rect.right - rect.left; i++) + { +@@ -2666,20 +2667,20 @@ void Context::readPixels(GLint x, GLint + ((unsigned short)( a + 0.5f) << 15) | + ((unsigned short)(31 * r + 0.5f) << 10) | + ((unsigned short)(31 * g + 0.5f) << 5) | + ((unsigned short)(31 * b + 0.5f) << 0); + break; + default: UNREACHABLE(); + } + break; +- case GL_RGB: // IMPLEMENTATION_COLOR_READ_FORMAT ++ case GL_RGB: + switch (type) + { +- case GL_UNSIGNED_SHORT_5_6_5: // IMPLEMENTATION_COLOR_READ_TYPE ++ case GL_UNSIGNED_SHORT_5_6_5: + dest16[i + j * outputPitch / sizeof(unsigned short)] = + ((unsigned short)(31 * b + 0.5f) << 0) | + ((unsigned short)(63 * g + 0.5f) << 5) | + ((unsigned short)(31 * r + 0.5f) << 11); + break; + default: UNREACHABLE(); + } + break; +diff --git a/gfx/angle/src/libGLESv2/Context.h b/gfx/angle/src/libGLESv2/Context.h +--- a/gfx/angle/src/libGLESv2/Context.h ++++ b/gfx/angle/src/libGLESv2/Context.h +@@ -69,18 +69,18 @@ enum + MAX_VARYING_VECTORS_SM3 = 10, + MAX_TEXTURE_IMAGE_UNITS = 16, + MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF = 4, // For devices supporting vertex texture fetch + MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF = MAX_TEXTURE_IMAGE_UNITS + MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF, + MAX_FRAGMENT_UNIFORM_VECTORS_SM2 = 32 - 3, // Reserve space for dx_Coord, dx_Depth, and dx_DepthRange. dx_PointOrLines and dx_FrontCCW use separate bool registers. + MAX_FRAGMENT_UNIFORM_VECTORS_SM3 = 224 - 3, + MAX_DRAW_BUFFERS = 1, + +- IMPLEMENTATION_COLOR_READ_FORMAT = GL_RGB, +- IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_SHORT_5_6_5 ++ IMPLEMENTATION_COLOR_READ_FORMAT = GL_BGRA_EXT, ++ IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_BYTE + }; + + enum QueryType + { + QUERY_ANY_SAMPLES_PASSED, + QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE, + + QUERY_TYPE_COUNT diff --git a/gfx/angle/src/libGLESv2/Context.cpp b/gfx/angle/src/libGLESv2/Context.cpp index fe544ca769d..6be8b701db7 100644 --- a/gfx/angle/src/libGLESv2/Context.cpp +++ b/gfx/angle/src/libGLESv2/Context.cpp @@ -2525,6 +2525,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, // Fast path for EXT_read_format_bgra, given // an RGBA source buffer. Note that buffers with no // alpha go through the slow path below. + // Note that this is also the combo exposed by IMPLEMENTATION_COLOR_READ_TYPE/FORMAT memcpy(dest + j * outputPitch, source + j * inputPitch, (rect.right - rect.left) * 4); @@ -2671,10 +2672,10 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, default: UNREACHABLE(); } break; - case GL_RGB: // IMPLEMENTATION_COLOR_READ_FORMAT + case GL_RGB: switch (type) { - case GL_UNSIGNED_SHORT_5_6_5: // IMPLEMENTATION_COLOR_READ_TYPE + case GL_UNSIGNED_SHORT_5_6_5: dest16[i + j * outputPitch / sizeof(unsigned short)] = ((unsigned short)(31 * b + 0.5f) << 0) | ((unsigned short)(63 * g + 0.5f) << 5) | diff --git a/gfx/angle/src/libGLESv2/Context.h b/gfx/angle/src/libGLESv2/Context.h index 78e7b6f1e2e..4507afebc67 100644 --- a/gfx/angle/src/libGLESv2/Context.h +++ b/gfx/angle/src/libGLESv2/Context.h @@ -74,8 +74,8 @@ enum MAX_FRAGMENT_UNIFORM_VECTORS_SM3 = 224 - 3, MAX_DRAW_BUFFERS = 1, - IMPLEMENTATION_COLOR_READ_FORMAT = GL_RGB, - IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_SHORT_5_6_5 + IMPLEMENTATION_COLOR_READ_FORMAT = GL_BGRA_EXT, + IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_BYTE }; enum QueryType diff --git a/gfx/angle/src/libGLESv2/libGLESv2.cpp b/gfx/angle/src/libGLESv2/libGLESv2.cpp index e71ec28bc70..2e4523748cd 100644 --- a/gfx/angle/src/libGLESv2/libGLESv2.cpp +++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp @@ -103,17 +103,6 @@ bool validReadFormatType(GLenum format, GLenum type) return false; } break; - case GL_BGRA_EXT: - switch (type) - { - case GL_UNSIGNED_BYTE: - case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: - case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: - break; - default: - return false; - } - break; case gl::IMPLEMENTATION_COLOR_READ_FORMAT: switch (type) { diff --git a/gfx/ots/README.mozilla b/gfx/ots/README.mozilla index 8d439531d52..50ba552a960 100644 --- a/gfx/ots/README.mozilla +++ b/gfx/ots/README.mozilla @@ -1,6 +1,6 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/. -Current revision: r77 +Current revision: r81 Applied local patches: ots-fix-vc10.patch - workaround for VS10 STL wrappers (bug 602558) diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h index c9d03c1f5d9..6a4f3008289 100644 --- a/gfx/ots/include/opentype-sanitiser.h +++ b/gfx/ots/include/opentype-sanitiser.h @@ -77,8 +77,9 @@ class OTSStream { } if (chksum_buffer_offset_ == 4) { - // TODO(yusukes): This cast breaks the strict-aliasing rule. - chksum_ += ntohl(*reinterpret_cast(chksum_buffer_)); + uint32_t chksum; + std::memcpy(&chksum, chksum_buffer_, 4); + chksum_ += ntohl(chksum); chksum_buffer_offset_ = 0; } diff --git a/gfx/ots/src/cff.cc b/gfx/ots/src/cff.cc index 73fc23399ca..a3931de0c47 100644 --- a/gfx/ots/src/cff.cc +++ b/gfx/ots/src/cff.cc @@ -760,14 +760,13 @@ bool ParseDictData(const uint8_t *data, size_t table_length, return OTS_FAILURE(); } const uint32_t private_length = operands.back().first; - if (private_offset >= table_length) { + if (private_offset > table_length) { return OTS_FAILURE(); } if (private_length >= table_length) { return OTS_FAILURE(); } if (private_length + private_offset > table_length) { - // does not overflow since table_length < 1GB return OTS_FAILURE(); } // parse "15. Private DICT Data" diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc index c6fb4b6dfbe..58f9212bca0 100644 --- a/gfx/ots/src/ots.cc +++ b/gfx/ots/src/ots.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -28,9 +29,12 @@ struct OpenTypeTable { uint32_t uncompressed_length; }; -// Round a value up to the nearest multiple of 4. Note that this can overflow -// and return zero. +// Round a value up to the nearest multiple of 4. Don't round the value in the +// case that rounding up overflows. template T Round4(T value) { + if (std::numeric_limits::max() - value < 3) { + return value; + } return (value + 3) & ~3; } @@ -280,7 +284,7 @@ bool ProcessWOFF(ots::OpenTypeFile *header, return OTS_FAILURE(); } - if (!file.ReadU16(&header->num_tables)) { + if (!file.ReadU16(&header->num_tables) || !header->num_tables) { return OTS_FAILURE(); } @@ -289,18 +293,52 @@ bool ProcessWOFF(ots::OpenTypeFile *header, return OTS_FAILURE(); } - // We don't care about these fields of the header: - // uint32_t uncompressed_size; - // uint16_t major_version, minor_version - // uint32_t meta_offset, meta_length, meta_length_orig - // uint32_t priv_offset, priv_length - if (!file.Skip(6 * 4 + 2 * 2)) { + uint32_t reported_total_sfnt_size; + if (!file.ReadU32(&reported_total_sfnt_size)) { return OTS_FAILURE(); } + // We don't care about these fields of the header: + // uint16_t major_version, minor_version + if (!file.Skip(2 * 2)) { + return OTS_FAILURE(); + } + + // Checks metadata block size. + uint32_t meta_offset; + uint32_t meta_length; + uint32_t meta_length_orig; + if (!file.ReadU32(&meta_offset) || + !file.ReadU32(&meta_length) || + !file.ReadU32(&meta_length_orig)) { + return OTS_FAILURE(); + } + if (meta_offset) { + if (meta_offset >= length || length - meta_offset < meta_length) { + return OTS_FAILURE(); + } + } + + // Checks private data block size. + uint32_t priv_offset; + uint32_t priv_length; + if (!file.ReadU32(&priv_offset) || + !file.ReadU32(&priv_length)) { + return OTS_FAILURE(); + } + if (priv_offset) { + if (priv_offset >= length || length - priv_offset < priv_length) { + return OTS_FAILURE(); + } + } + // Next up is the list of tables. std::vector tables; + uint32_t first_index = 0; + uint32_t last_index = 0; + // Size of sfnt header plus size of table records. + uint64_t total_sfnt_size = 12 + 16 * header->num_tables; for (unsigned i = 0; i < header->num_tables; ++i) { OpenTypeTable table; if (!file.ReadTag(&table.tag) || @@ -311,7 +349,60 @@ bool ProcessWOFF(ots::OpenTypeFile *header, return OTS_FAILURE(); } + total_sfnt_size += Round4(table.uncompressed_length); + if (total_sfnt_size > std::numeric_limits::max()) { + return OTS_FAILURE(); + } tables.push_back(table); + if (i == 0 || tables[first_index].offset > table.offset) + first_index = i; + if (i == 0 || tables[last_index].offset < table.offset) + last_index = i; + } + + if (reported_total_sfnt_size != total_sfnt_size) { + return OTS_FAILURE(); + } + + // Table data must follow immediately after the header. + if (tables[first_index].offset != Round4(file.offset())) { + return OTS_FAILURE(); + } + + if (tables[last_index].offset >= length || + length - tables[last_index].offset < tables[last_index].length) { + return OTS_FAILURE(); + } + // Blocks must follow immediately after the previous block. + // (Except for padding with a maximum of three null bytes) + uint64_t block_end = Round4( + static_cast(tables[last_index].offset) + + static_cast(tables[last_index].length)); + if (block_end > std::numeric_limits::max()) { + return OTS_FAILURE(); + } + if (meta_offset) { + if (block_end != meta_offset) { + return OTS_FAILURE(); + } + block_end = Round4(static_cast(meta_offset) + + static_cast(meta_length)); + if (block_end > std::numeric_limits::max()) { + return OTS_FAILURE(); + } + } + if (priv_offset) { + if (block_end != priv_offset) { + return OTS_FAILURE(); + } + block_end = Round4(static_cast(priv_offset) + + static_cast(priv_length)); + if (block_end > std::numeric_limits::max()) { + return OTS_FAILURE(); + } + } + if (block_end != Round4(length)) { + return OTS_FAILURE(); } return ProcessGeneric(header, output, data, length, tables, file); @@ -378,11 +469,11 @@ bool ProcessGeneric(ots::OpenTypeFile *header, ots::OTSStream *output, } // since we required that the file be < 1GB in length, and that the table // length is < 1GB, the following addtion doesn't overflow - const uint32_t end_byte = Round4(tables[i].offset + tables[i].length); + const uint32_t end_byte = tables[i].offset + tables[i].length; // Some fonts which are automatically generated by a font generator // called TTX seems not to add 0-padding to the final table. It might be // ok to accept these fonts so we round up the length of the font file. - if (!end_byte || end_byte > Round4(length)) { + if (!end_byte || end_byte > length) { return OTS_FAILURE(); } } diff --git a/gfx/thebes/gfx2DGlue.h b/gfx/thebes/gfx2DGlue.h index c8eb356e798..280c5561ca3 100644 --- a/gfx/thebes/gfx2DGlue.h +++ b/gfx/thebes/gfx2DGlue.h @@ -122,9 +122,8 @@ inline gfxContext::GraphicsLineCap ThebesLineCap(CapStyle aStyle) return gfxContext::LINE_CAP_ROUND; case CAP_SQUARE: return gfxContext::LINE_CAP_SQUARE; - default: - return gfxContext::LINE_CAP_BUTT; } + MOZ_NOT_REACHED("Incomplete switch"); } inline CapStyle ToCapStyle(gfxContext::GraphicsLineCap aStyle) @@ -136,9 +135,8 @@ inline CapStyle ToCapStyle(gfxContext::GraphicsLineCap aStyle) return CAP_ROUND; case gfxContext::LINE_CAP_SQUARE: return CAP_SQUARE; - default: - return CAP_BUTT; } + MOZ_NOT_REACHED("Incomplete switch"); } inline gfxContext::GraphicsLineJoin ThebesLineJoin(JoinStyle aStyle) @@ -164,9 +162,8 @@ inline JoinStyle ToJoinStyle(gfxContext::GraphicsLineJoin aStyle) return JOIN_BEVEL; case gfxContext::LINE_JOIN_ROUND: return JOIN_ROUND; - default: - return JOIN_MITER; } + MOZ_NOT_REACHED("Incomplete switch"); } inline gfxMatrix ThebesMatrix(const Matrix &aMatrix) diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 73872f035cf..f9827d50f29 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -160,10 +160,8 @@ GetBackendName(mozilla::gfx::BackendType aBackend) return "skia"; case mozilla::gfx::BACKEND_NONE: return "none"; - default: - NS_ERROR("Invalid backend type!"); - return ""; } + MOZ_NOT_REACHED("Incomplet switch"); } class THEBES_API gfxPlatform { diff --git a/gfx/thebes/gfxRect.h b/gfx/thebes/gfxRect.h index 38e7315da81..07a429018ab 100644 --- a/gfx/thebes/gfxRect.h +++ b/gfx/thebes/gfxRect.h @@ -45,6 +45,7 @@ #include "nsDebug.h" #include "mozilla/gfx/BaseMargin.h" #include "mozilla/gfx/BaseRect.h" +#include "mozilla/Assertions.h" #include "nsRect.h" struct gfxMargin : public mozilla::gfx::BaseMargin { @@ -126,11 +127,8 @@ struct THEBES_API gfxRect : case NS_SIDE_RIGHT: return TopRight(); case NS_SIDE_BOTTOM: return BottomRight(); case NS_SIDE_LEFT: return BottomLeft(); - default: - NS_ERROR("Invalid side!"); - break; } - return gfxPoint(0.0, 0.0); + MOZ_NOT_REACHED("Incomplet switch"); } gfxPoint CWCorner(mozilla::css::Side side) const { @@ -139,11 +137,8 @@ struct THEBES_API gfxRect : case NS_SIDE_RIGHT: return BottomRight(); case NS_SIDE_BOTTOM: return BottomLeft(); case NS_SIDE_LEFT: return TopLeft(); - default: - NS_ERROR("Invalid side!"); - break; } - return gfxPoint(0.0, 0.0); + MOZ_NOT_REACHED("Incomplet switch"); } /* Conditions this border to Cairo's max coordinate space. diff --git a/js/ipc/PObjectWrapper.ipdl b/js/ipc/PObjectWrapper.ipdl index 8cf8b08f244..72c3017561a 100644 --- a/js/ipc/PObjectWrapper.ipdl +++ b/js/ipc/PObjectWrapper.ipdl @@ -55,8 +55,8 @@ union JSVariant { nsString; int; double; - bool; // We'd like to use JSBool here, but JSBool is really JSIntn, - // and IPC::ParamTraits mistakes JSIntn for int. + bool; // We'd like to use JSBool here, but IPC::ParamTraits would + // treat JSBool as int. }; union OperationStatus { diff --git a/js/jsd/jsd.h b/js/jsd/jsd.h index 9078324b11c..2bd8049b20c 100644 --- a/js/jsd/jsd.h +++ b/js/jsd/jsd.h @@ -210,12 +210,12 @@ struct JSDProfileData uintN callCount; uintN recurseDepth; uintN maxRecurseDepth; - jsdouble minExecutionTime; - jsdouble maxExecutionTime; - jsdouble totalExecutionTime; - jsdouble minOwnExecutionTime; - jsdouble maxOwnExecutionTime; - jsdouble totalOwnExecutionTime; + double minExecutionTime; + double maxExecutionTime; + double totalExecutionTime; + double minOwnExecutionTime; + double maxOwnExecutionTime; + double totalOwnExecutionTime; }; struct JSDSourceText @@ -417,22 +417,22 @@ jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script); extern uintN jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script); -extern jsdouble +extern double jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script); -extern jsdouble +extern double jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script); -extern jsdouble +extern double jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script); -extern jsdouble +extern double jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script); -extern jsdouble +extern double jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script); -extern jsdouble +extern double jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script); extern void @@ -972,7 +972,7 @@ jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval); extern int32_t jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval); -extern jsdouble +extern double jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval); extern JSString* diff --git a/js/jsd/jsd_scpt.c b/js/jsd/jsd_scpt.c index 4bba0bbc320..73ba8b49beb 100644 --- a/js/jsd/jsd_scpt.c +++ b/js/jsd/jsd_scpt.c @@ -367,7 +367,7 @@ jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script) return 0; } -jsdouble +double jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script) { if (script->profileData) @@ -376,7 +376,7 @@ jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script) return 0.0; } -jsdouble +double jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script) { if (script->profileData) @@ -385,7 +385,7 @@ jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script) return 0.0; } -jsdouble +double jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script) { if (script->profileData) @@ -394,7 +394,7 @@ jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script) return 0.0; } -jsdouble +double jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script) { if (script->profileData) @@ -403,7 +403,7 @@ jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script) return 0.0; } -jsdouble +double jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script) { if (script->profileData) @@ -412,7 +412,7 @@ jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script) return 0.0; } -jsdouble +double jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script) { if (script->profileData) diff --git a/js/jsd/jsd_step.c b/js/jsd/jsd_step.c index 8da3f477052..28b5d363339 100644 --- a/js/jsd/jsd_step.c +++ b/js/jsd/jsd_step.c @@ -187,7 +187,7 @@ _callHook(JSDContext *jsdc, JSContext *cx, JSStackFrame *fp, JSBool before, hookresult = JS_TRUE; } else if (!pdata->recurseDepth && pdata->lastCallStart) { int64_t now, ll_delta; - jsdouble delta; + double delta; now = JS_Now(); ll_delta = now - pdata->lastCallStart; delta = ll_delta; diff --git a/js/jsd/jsd_val.c b/js/jsd/jsd_val.c index c51fa6a4c05..87ed2fd30fb 100644 --- a/js/jsd/jsd_val.c +++ b/js/jsd/jsd_val.c @@ -197,7 +197,7 @@ jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval) return JSVAL_TO_INT(val); } -jsdouble +double jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval) { if(!JSVAL_IS_DOUBLE(jsdval->val)) diff --git a/js/jsd/jsdebug.c b/js/jsd/jsdebug.c index 576fd8becb2..794a25de04c 100644 --- a/js/jsd/jsdebug.c +++ b/js/jsd/jsdebug.c @@ -211,42 +211,42 @@ JSD_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script) } -JSD_PUBLIC_API(jsdouble) +JSD_PUBLIC_API(double) JSD_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script) { JSD_ASSERT_VALID_CONTEXT(jsdc); return jsd_GetScriptMinExecutionTime(jsdc, script); } -JSD_PUBLIC_API(jsdouble) +JSD_PUBLIC_API(double) JSD_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script) { JSD_ASSERT_VALID_CONTEXT(jsdc); return jsd_GetScriptMaxExecutionTime(jsdc, script); } -JSD_PUBLIC_API(jsdouble) +JSD_PUBLIC_API(double) JSD_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script) { JSD_ASSERT_VALID_CONTEXT(jsdc); return jsd_GetScriptTotalExecutionTime(jsdc, script); } -JSD_PUBLIC_API(jsdouble) +JSD_PUBLIC_API(double) JSD_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script) { JSD_ASSERT_VALID_CONTEXT(jsdc); return jsd_GetScriptMinOwnExecutionTime(jsdc, script); } -JSD_PUBLIC_API(jsdouble) +JSD_PUBLIC_API(double) JSD_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script) { JSD_ASSERT_VALID_CONTEXT(jsdc); return jsd_GetScriptMaxOwnExecutionTime(jsdc, script); } -JSD_PUBLIC_API(jsdouble) +JSD_PUBLIC_API(double) JSD_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script) { JSD_ASSERT_VALID_CONTEXT(jsdc); @@ -1110,7 +1110,7 @@ JSD_GetValueInt(JSDContext* jsdc, JSDValue* jsdval) return jsd_GetValueInt(jsdc, jsdval); } -JSD_PUBLIC_API(jsdouble) +JSD_PUBLIC_API(double) JSD_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval) { JSD_ASSERT_VALID_CONTEXT(jsdc); diff --git a/js/jsd/jsdebug.h b/js/jsd/jsdebug.h index c619c309220..2d36cf1af0c 100644 --- a/js/jsd/jsdebug.h +++ b/js/jsd/jsdebug.h @@ -333,40 +333,40 @@ JSD_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script); /* * Get the shortest execution time recorded. */ -extern JSD_PUBLIC_API(jsdouble) +extern JSD_PUBLIC_API(double) JSD_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script); /* * Get the longest execution time recorded. */ -extern JSD_PUBLIC_API(jsdouble) +extern JSD_PUBLIC_API(double) JSD_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script); /* * Get the total amount of time spent in this script. */ -extern JSD_PUBLIC_API(jsdouble) +extern JSD_PUBLIC_API(double) JSD_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script); /* * Get the shortest execution time recorded, excluding time spent in called * functions. */ -extern JSD_PUBLIC_API(jsdouble) +extern JSD_PUBLIC_API(double) JSD_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script); /* * Get the longest execution time recorded, excluding time spent in called * functions. */ -extern JSD_PUBLIC_API(jsdouble) +extern JSD_PUBLIC_API(double) JSD_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script); /* * Get the total amount of time spent in this script, excluding time spent * in called functions. */ -extern JSD_PUBLIC_API(jsdouble) +extern JSD_PUBLIC_API(double) JSD_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script); /* @@ -1293,7 +1293,7 @@ JSD_GetValueInt(JSDContext* jsdc, JSDValue* jsdval); * Return double value (does NOT do conversion). * *** new for version 1.1 **** */ -extern JSD_PUBLIC_API(jsdouble) +extern JSD_PUBLIC_API(double) JSD_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval); /* diff --git a/js/src/Makefile.in b/js/src/Makefile.in index e9b761388bb..b740d810dd6 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -154,6 +154,7 @@ CPPSRCS = \ Debugger.cpp \ GlobalObject.cpp \ MethodGuard.cpp \ + ObjectImpl.cpp \ Stack.cpp \ String.cpp \ BytecodeCompiler.cpp \ diff --git a/js/src/assembler/jit/ExecutableAllocatorWin.cpp b/js/src/assembler/jit/ExecutableAllocatorWin.cpp index 457ee5de146..d65fa097e46 100644 --- a/js/src/assembler/jit/ExecutableAllocatorWin.cpp +++ b/js/src/assembler/jit/ExecutableAllocatorWin.cpp @@ -94,6 +94,8 @@ RandomizeIsBrokenImpl() static bool RandomizeIsBroken() { + // Use the compiler's intrinsic guards for |static type value = expr| to avoid some potential + // races if runtimes are created from multiple threads. static int result = RandomizeIsBrokenImpl(); return !!result; } diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index ff96e4307ff..f4c2ca00203 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -86,7 +86,7 @@ HashableValue::setValue(JSContext *cx, const Value &v) return false; value = StringValue(str); } else if (v.isDouble()) { - jsdouble d = v.toDouble(); + double d = v.toDouble(); int32_t i; if (JSDOUBLE_IS_INT32(d, &i)) { /* Normalize int32-valued doubles to int32 for faster hashing and testing. */ diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index abdf2b499b7..e7f4b19eba9 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -602,7 +602,7 @@ ExecuteRegExp(JSContext *cx, Native native, uintN argc, Value *vp) const Value &lastIndex = reobj.getLastIndex(); /* Step 5. */ - jsdouble i; + double i; if (!ToInteger(cx, lastIndex, &i)) return false; diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index e6f31b8ecad..97f4d6d358d 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -457,7 +457,7 @@ static JSFunctionSpec sModuleFunctions[] = { JS_FS_END }; -static inline bool FloatIsFinite(jsdouble f) { +static inline bool FloatIsFinite(double f) { #ifdef WIN32 return _finite(f) != 0; #else @@ -1004,8 +1004,8 @@ struct ConvertImpl { // MSVC can't perform double to unsigned __int64 conversion when the // double is greater than 2^63 - 1. Help it along a little. template<> -struct ConvertImpl { - static JS_ALWAYS_INLINE uint64_t Convert(jsdouble d) { +struct ConvertImpl { + static JS_ALWAYS_INLINE uint64_t Convert(double d) { return d > 0x7fffffffffffffffui64 ? uint64_t(d - 0x8000000000000000ui64) + 0x8000000000000000ui64 : uint64_t(d); @@ -1020,16 +1020,16 @@ struct ConvertImpl { #ifdef SPARC // Simulate x86 overflow behavior template<> -struct ConvertImpl { - static JS_ALWAYS_INLINE uint64_t Convert(jsdouble d) { +struct ConvertImpl { + static JS_ALWAYS_INLINE uint64_t Convert(double d) { return d >= 0xffffffffffffffff ? 0x8000000000000000 : uint64_t(d); } }; template<> -struct ConvertImpl { - static JS_ALWAYS_INLINE int64_t Convert(jsdouble d) { +struct ConvertImpl { + static JS_ALWAYS_INLINE int64_t Convert(double d) { return d >= 0x7fffffffffffffff ? 0x8000000000000000 : int64_t(d); } @@ -1141,7 +1141,7 @@ static JS_ALWAYS_INLINE bool IsNegative(Type i) return IsNegativeImpl::is_signed>::Test(i); } -// Implicitly convert val to bool, allowing JSBool, jsint, and jsdouble +// Implicitly convert val to bool, allowing JSBool, jsint, and double // arguments numerically equal to 0 or 1. static bool jsvalToBool(JSContext* cx, jsval val, bool* result) @@ -1156,7 +1156,7 @@ jsvalToBool(JSContext* cx, jsval val, bool* result) return i == 0 || i == 1; } if (JSVAL_IS_DOUBLE(val)) { - jsdouble d = JSVAL_TO_DOUBLE(val); + double d = JSVAL_TO_DOUBLE(val); *result = d != 0; // Allow -0. return d == 1 || d == 0; @@ -1165,7 +1165,7 @@ jsvalToBool(JSContext* cx, jsval val, bool* result) return false; } -// Implicitly convert val to IntegerType, allowing JSBool, jsint, jsdouble, +// Implicitly convert val to IntegerType, allowing JSBool, jsint, double, // Int64, UInt64, and CData integer types 't' where all values of 't' are // representable by IntegerType. template @@ -1183,7 +1183,7 @@ jsvalToInteger(JSContext* cx, jsval val, IntegerType* result) if (JSVAL_IS_DOUBLE(val)) { // Don't silently lose bits here -- check that val really is an // integer value, and has the right sign. - jsdouble d = JSVAL_TO_DOUBLE(val); + double d = JSVAL_TO_DOUBLE(val); return ConvertExact(d, result); } if (!JSVAL_IS_PRIMITIVE(val)) { @@ -1246,7 +1246,7 @@ jsvalToInteger(JSContext* cx, jsval val, IntegerType* result) return false; } -// Implicitly convert val to FloatType, allowing jsint, jsdouble, +// Implicitly convert val to FloatType, allowing jsint, double, // Int64, UInt64, and CData numeric types 't' where all values of 't' are // representable by FloatType. template @@ -1359,7 +1359,7 @@ StringToInteger(JSContext* cx, JSString* string, IntegerType* result) return true; } -// Implicitly convert val to IntegerType, allowing jsint, jsdouble, +// Implicitly convert val to IntegerType, allowing jsint, double, // Int64, UInt64, and optionally a decimal or hexadecimal string argument. // (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.) template @@ -1380,7 +1380,7 @@ jsvalToBigInteger(JSContext* cx, if (JSVAL_IS_DOUBLE(val)) { // Don't silently lose bits here -- check that val really is an // integer value, and has the right sign. - jsdouble d = JSVAL_TO_DOUBLE(val); + double d = JSVAL_TO_DOUBLE(val); return ConvertExact(d, result); } if (allowString && JSVAL_IS_STRING(val)) { @@ -1410,18 +1410,18 @@ jsvalToBigInteger(JSContext* cx, } // Implicitly convert val to a size value, where the size value is represented -// by size_t but must also fit in a jsdouble. +// by size_t but must also fit in a double. static bool jsvalToSize(JSContext* cx, jsval val, bool allowString, size_t* result) { if (!jsvalToBigInteger(cx, val, allowString, result)) return false; - // Also check that the result fits in a jsdouble. - return Convert(jsdouble(*result)) == *result; + // Also check that the result fits in a double. + return Convert(double(*result)) == *result; } -// Implicitly convert val to IntegerType, allowing jsint, jsdouble, +// Implicitly convert val to IntegerType, allowing jsint, double, // Int64, UInt64, and optionally a decimal or hexadecimal string argument. // (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.) template @@ -1466,28 +1466,28 @@ jsidToBigInteger(JSContext* cx, } // Implicitly convert val to a size value, where the size value is represented -// by size_t but must also fit in a jsdouble. +// by size_t but must also fit in a double. static bool jsidToSize(JSContext* cx, jsid val, bool allowString, size_t* result) { if (!jsidToBigInteger(cx, val, allowString, result)) return false; - // Also check that the result fits in a jsdouble. - return Convert(jsdouble(*result)) == *result; + // Also check that the result fits in a double. + return Convert(double(*result)) == *result; } // Implicitly convert a size value to a jsval, ensuring that the size_t value -// fits in a jsdouble. +// fits in a double. static JSBool SizeTojsval(JSContext* cx, size_t size, jsval* result) { - if (Convert(jsdouble(size)) != size) { + if (Convert(double(size)) != size) { JS_ReportError(cx, "size overflow"); return false; } - return JS_NewNumberValue(cx, jsdouble(size), result); + return JS_NewNumberValue(cx, double(size), result); } // Forcefully convert val to IntegerType when explicitly requested. @@ -1499,7 +1499,7 @@ jsvalToIntegerExplicit(jsval val, IntegerType* result) if (JSVAL_IS_DOUBLE(val)) { // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast. - jsdouble d = JSVAL_TO_DOUBLE(val); + double d = JSVAL_TO_DOUBLE(val); *result = FloatIsFinite(d) ? IntegerType(d) : 0; return true; } @@ -1532,11 +1532,11 @@ jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result) return true; } if (JSVAL_IS_DOUBLE(val)) { - jsdouble d = JSVAL_TO_DOUBLE(val); + double d = JSVAL_TO_DOUBLE(val); if (d < 0) { // Cast through an intptr_t intermediate to sign-extend. intptr_t i = Convert(d); - if (jsdouble(i) != d) + if (double(i) != d) return false; *result = uintptr_t(i); @@ -1546,7 +1546,7 @@ jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result) // Don't silently lose bits here -- check that val really is an // integer value, and has the right sign. *result = Convert(d); - return jsdouble(*result) == d; + return double(*result) == d; } if (!JSVAL_IS_PRIMITIVE(val)) { JSObject* obj = JSVAL_TO_OBJECT(val); @@ -1651,7 +1651,7 @@ ConvertToJS(JSContext* cx, type value = *static_cast(data); \ if (sizeof(type) < 4) \ *result = INT_TO_JSVAL(jsint(value)); \ - else if (!JS_NewNumberValue(cx, jsdouble(value), result)) \ + else if (!JS_NewNumberValue(cx, double(value), result)) \ return false; \ break; \ } @@ -1680,7 +1680,7 @@ ConvertToJS(JSContext* cx, #define DEFINE_FLOAT_TYPE(name, type, ffiType) \ case TYPE_##name: { \ type value = *static_cast(data); \ - if (!JS_NewNumberValue(cx, jsdouble(value), result)) \ + if (!JS_NewNumberValue(cx, double(value), result)) \ return false; \ break; \ } @@ -2929,7 +2929,7 @@ CType::GetSafeSize(JSObject* obj, size_t* result) jsval size = JS_GetReservedSlot(obj, SLOT_SIZE); - // The "size" property can be a jsint, a jsdouble, or JSVAL_VOID + // The "size" property can be a jsint, a double, or JSVAL_VOID // (for arrays of undefined length), and must always fit in a size_t. if (JSVAL_IS_INT(size)) { *result = JSVAL_TO_INT(size); @@ -2953,7 +2953,7 @@ CType::GetSize(JSObject* obj) JS_ASSERT(!JSVAL_IS_VOID(size)); - // The "size" property can be a jsint, a jsdouble, or JSVAL_VOID + // The "size" property can be a jsint, a double, or JSVAL_VOID // (for arrays of undefined length), and must always fit in a size_t. // For callers who know it can never be JSVAL_VOID, return a size_t directly. if (JSVAL_IS_INT(size)) @@ -2968,7 +2968,7 @@ CType::IsSizeDefined(JSObject* obj) jsval size = JS_GetReservedSlot(obj, SLOT_SIZE); - // The "size" property can be a jsint, a jsdouble, or JSVAL_VOID + // The "size" property can be a jsint, a double, or JSVAL_VOID // (for arrays of undefined length), and must always fit in a size_t. JS_ASSERT(JSVAL_IS_INT(size) || JSVAL_IS_DOUBLE(size) || JSVAL_IS_VOID(size)); return !JSVAL_IS_VOID(size); @@ -3599,7 +3599,7 @@ ArrayType::CreateInternal(JSContext* cx, jsval sizeVal = JSVAL_VOID; jsval lengthVal = JSVAL_VOID; if (lengthDefined) { - // Check for overflow, and convert to a jsint or jsdouble as required. + // Check for overflow, and convert to a jsint or double as required. size_t size = length * baseSize; if (length > 0 && size / length != baseSize) { JS_ReportError(cx, "size overflow"); @@ -3750,7 +3750,7 @@ ArrayType::GetSafeLength(JSObject* obj, size_t* result) jsval length = JS_GetReservedSlot(obj, SLOT_LENGTH); - // The "length" property can be a jsint, a jsdouble, or JSVAL_VOID + // The "length" property can be a jsint, a double, or JSVAL_VOID // (for arrays of undefined length), and must always fit in a size_t. if (JSVAL_IS_INT(length)) { *result = JSVAL_TO_INT(length); @@ -3775,7 +3775,7 @@ ArrayType::GetLength(JSObject* obj) JS_ASSERT(!JSVAL_IS_VOID(length)); - // The "length" property can be a jsint, a jsdouble, or JSVAL_VOID + // The "length" property can be a jsint, a double, or JSVAL_VOID // (for arrays of undefined length), and must always fit in a size_t. // For callers who know it can never be JSVAL_VOID, return a size_t directly. if (JSVAL_IS_INT(length)) @@ -6207,7 +6207,7 @@ Int64::Lo(JSContext* cx, uintN argc, jsval* vp) JSObject* obj = JSVAL_TO_OBJECT(argv[0]); int64_t u = Int64Base::GetInt(obj); - jsdouble d = uint32_t(INT64_LO(u)); + double d = uint32_t(INT64_LO(u)); jsval result; if (!JS_NewNumberValue(cx, d, &result)) @@ -6229,7 +6229,7 @@ Int64::Hi(JSContext* cx, uintN argc, jsval* vp) JSObject* obj = JSVAL_TO_OBJECT(argv[0]); int64_t u = Int64Base::GetInt(obj); - jsdouble d = int32_t(INT64_HI(u)); + double d = int32_t(INT64_HI(u)); jsval result; if (!JS_NewNumberValue(cx, d, &result)) @@ -6374,7 +6374,7 @@ UInt64::Lo(JSContext* cx, uintN argc, jsval* vp) JSObject* obj = JSVAL_TO_OBJECT(argv[0]); uint64_t u = Int64Base::GetInt(obj); - jsdouble d = uint32_t(INT64_LO(u)); + double d = uint32_t(INT64_LO(u)); jsval result; if (!JS_NewNumberValue(cx, d, &result)) @@ -6396,7 +6396,7 @@ UInt64::Hi(JSContext* cx, uintN argc, jsval* vp) JSObject* obj = JSVAL_TO_OBJECT(argv[0]); uint64_t u = Int64Base::GetInt(obj); - jsdouble d = uint32_t(INT64_HI(u)); + double d = uint32_t(INT64_HI(u)); jsval result; if (!JS_NewNumberValue(cx, d, &result)) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 155f8ed1805..33a20d50d5b 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -92,9 +92,6 @@ static JSBool NewTryNote(JSContext *cx, BytecodeEmitter *bce, JSTryNoteKind kind, uintN stackDepth, size_t start, size_t end); -static bool -EmitIndexOp(JSContext *cx, JSOp op, uintN index, BytecodeEmitter *bce, JSOp *psuffix = NULL); - static JSBool SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, uintN index, uintN which, ptrdiff_t offset); @@ -866,97 +863,44 @@ LookupCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom *atom, Val return JS_TRUE; } -static inline bool -FitsWithoutBigIndex(uintN index) -{ - return index < JS_BIT(16); -} - -/* - * Return JSOP_NOP to indicate that index fits 2 bytes and no index segment - * reset instruction is necessary, JSOP_FALSE to indicate an error or either - * JSOP_RESETBASE0 or JSOP_RESETBASE1 to indicate the reset bytecode to issue - * after the main bytecode sequence. - */ -static JSOp -EmitBigIndexPrefix(JSContext *cx, BytecodeEmitter *bce, uintN index) -{ - uintN indexBase; - - /* - * We have max 3 bytes for indexes and check for INDEX_LIMIT overflow only - * for big indexes. - */ - JS_STATIC_ASSERT(INDEX_LIMIT <= JS_BIT(24)); - JS_STATIC_ASSERT(INDEX_LIMIT >= - (JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 2) << 16); - - if (FitsWithoutBigIndex(index)) - return JSOP_NOP; - indexBase = index >> 16; - if (indexBase <= JSOP_INDEXBASE3 - JSOP_INDEXBASE1 + 1) { - if (Emit1(cx, bce, (JSOp)(JSOP_INDEXBASE1 + indexBase - 1)) < 0) - return JSOP_FALSE; - return JSOP_RESETBASE0; - } - - if (index >= INDEX_LIMIT) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_TOO_MANY_LITERALS); - return JSOP_FALSE; - } - - if (Emit2(cx, bce, JSOP_INDEXBASE, (JSOp)indexBase) < 0) - return JSOP_FALSE; - return JSOP_RESETBASE; -} - -/* - * Emit a bytecode and its 2-byte constant index immediate operand. If the - * index requires more than 2 bytes, emit a prefix op whose 8-bit immediate - * operand effectively extends the 16-bit immediate of the prefixed opcode, - * by changing index "segment" (see jsinterp.c). We optimize segments 1-3 - * with single-byte JSOP_INDEXBASE[123] codes. - * - * Such prefixing currently requires a suffix to restore the "zero segment" - * register setting, but this could be optimized further. - */ static bool -EmitIndexOp(JSContext *cx, JSOp op, uintN index, BytecodeEmitter *bce, JSOp *psuffix) +EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce) { - JSOp bigSuffix; - - bigSuffix = EmitBigIndexPrefix(cx, bce, index); - if (bigSuffix == JSOP_FALSE) + const size_t len = 1 + UINT32_INDEX_LEN; + JS_ASSERT(len == size_t(js_CodeSpec[op].length)); + ptrdiff_t offset = EmitCheck(cx, bce, len); + if (offset < 0) return false; - EMIT_UINT16_IMM_OP(op, index); - /* - * For decomposed ops, the suffix needs to go after the decomposed version. - * This means the suffix will run in the interpreter in both the base - * and decomposed paths, which works as suffix ops are idempotent. - */ - JS_ASSERT(!!(js_CodeSpec[op].format & JOF_DECOMPOSE) == (psuffix != NULL)); - if (psuffix) { - *psuffix = bigSuffix; - return true; - } - - return bigSuffix == JSOP_NOP || Emit1(cx, bce, bigSuffix) >= 0; + jsbytecode *next = bce->next(); + next[0] = jsbytecode(op); + SET_UINT32_INDEX(next, index); + bce->current->next = next + len; + UpdateDepth(cx, bce, offset); + CheckTypeSet(cx, bce, op); + return true; } -/* - * Slight sugar for EmitIndexOp, again accessing cx and bce from the macro - * caller's lexical environment, and embedding a false return on error. - */ -#define EMIT_INDEX_OP(op, index) \ - JS_BEGIN_MACRO \ - if (!EmitIndexOp(cx, op, index, bce)) \ - return JS_FALSE; \ - JS_END_MACRO +static bool +EmitIndexOp(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce) +{ + const size_t len = js_CodeSpec[op].length; + JS_ASSERT(len >= 1 + UINT32_INDEX_LEN); + ptrdiff_t offset = EmitCheck(cx, bce, len); + if (offset < 0) + return false; + + jsbytecode *next = bce->next(); + next[0] = jsbytecode(op); + SET_UINT32_INDEX(next, index); + bce->current->next = next + len; + UpdateDepth(cx, bce, offset); + CheckTypeSet(cx, bce, op); + return true; +} static bool -EmitAtomOp(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce, JSOp *psuffix = NULL) +EmitAtomOp(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce) { JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); @@ -969,20 +913,27 @@ EmitAtomOp(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce, JSOp *psu if (!bce->makeAtomIndex(atom, &index)) return false; - return EmitIndexOp(cx, op, index, bce, psuffix); + return EmitIndexOp(cx, op, index, bce); } static bool -EmitAtomOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce, JSOp *psuffix = NULL) +EmitAtomOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) { JS_ASSERT(pn->pn_atom != NULL); - return EmitAtomOp(cx, pn->pn_atom, op, bce, psuffix); + return EmitAtomOp(cx, pn->pn_atom, op, bce); } static bool -EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce) +EmitAtomIncDec(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce) { - const size_t len = 1 + UINT32_INDEX_LEN; + JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); + JS_ASSERT(js_CodeSpec[op].format & (JOF_INC | JOF_DEC)); + + jsatomid index; + if (!bce->makeAtomIndex(atom, &index)) + return false; + + const size_t len = 1 + UINT32_INDEX_LEN + 1; JS_ASSERT(size_t(js_CodeSpec[op].length) == len); ptrdiff_t offset = EmitCheck(cx, bce, len); if (offset < 0) @@ -1026,7 +977,7 @@ EmitSlotObjectOp(JSContext *cx, JSOp op, uintN slot, uint32_t index, BytecodeEmi return false; jsbytecode *pc = bce->code(off); - SET_UINT16(pc, slot); + SET_SLOTNO(pc, slot); pc += SLOTNO_LEN; SET_UINT32_INDEX(pc, index); return true; @@ -1887,6 +1838,7 @@ EmitNameOp(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSBool callContex return JS_FALSE; } else { if (!pn->pn_cookie.isFree()) { + JS_ASSERT(JOF_OPTYPE(op) != JOF_ATOM); EMIT_UINT16_IMM_OP(op, pn->pn_cookie.asInteger()); } else { if (!EmitAtomOp(cx, pn, op, bce)) @@ -1955,7 +1907,7 @@ EmitSpecialPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) jsatomid index; if (!bce->makeAtomIndex(pn->pn_atom, &index)) return false; - if (!EmitIndexOp(cx, JSOP_QNAMEPART, index, bce)) + if (!EmitIndex32(cx, JSOP_QNAMEPART, index, bce)) return false; if (op == JSOP_CALLELEM && Emit1(cx, bce, JSOP_DUP) < 0) @@ -1972,7 +1924,7 @@ EmitSpecialPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) static bool EmitPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce, - JSBool callContext, JSOp *psuffix = NULL) + JSBool callContext) { ParseNode *pn2, *pndot, *pnup, *pndown; ptrdiff_t top; @@ -2053,7 +2005,7 @@ EmitPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce, if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pn2->pn_offset) < 0) return false; - if (!EmitAtomOp(cx, pn, op, bce, psuffix)) + if (!EmitAtomOp(cx, pn, op, bce)) return false; if (op == JSOP_CALLPROP && Emit1(cx, bce, JSOP_SWAP) < 0) @@ -2065,10 +2017,7 @@ EmitPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce, static bool EmitPropIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) { - JSOp suffix = JSOP_NOP; - if (!EmitPropOp(cx, pn, op, bce, false, &suffix)) - return false; - if (Emit1(cx, bce, JSOP_NOP) < 0) + if (!EmitPropOp(cx, pn, op, bce, false)) return false; /* @@ -2077,9 +2026,6 @@ EmitPropIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) */ int start = bce->offset(); - if (suffix != JSOP_NOP && Emit1(cx, bce, suffix) < 0) - return false; - const JSCodeSpec *cs = &js_CodeSpec[op]; JS_ASSERT(cs->format & JOF_PROP); JS_ASSERT(cs->format & (JOF_INC | JOF_DEC)); @@ -2115,19 +2061,14 @@ EmitPropIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) UpdateDecomposeLength(bce, start); - if (suffix != JSOP_NOP && Emit1(cx, bce, suffix) < 0) - return false; - return true; } static bool EmitNameIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) { - JSOp suffix = JSOP_NOP; - if (!EmitAtomOp(cx, pn, op, bce, &suffix)) - return false; - if (Emit1(cx, bce, JSOP_NOP) < 0) + /* Emit the composite op, including the slack byte at the end. */ + if (!EmitAtomIncDec(cx, pn->pn_atom, op, bce)) return false; /* Remove the result to restore the stack depth before the INCNAME. */ @@ -2135,9 +2076,6 @@ EmitNameIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) int start = bce->offset(); - if (suffix != JSOP_NOP && Emit1(cx, bce, suffix) < 0) - return false; - const JSCodeSpec *cs = &js_CodeSpec[op]; JS_ASSERT((cs->format & JOF_NAME) || (cs->format & JOF_GNAME)); JS_ASSERT(cs->format & (JOF_INC | JOF_DEC)); @@ -2173,9 +2111,6 @@ EmitNameIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) UpdateDecomposeLength(bce, start); - if (suffix != JSOP_NOP && Emit1(cx, bce, suffix) < 0) - return false; - return true; } @@ -2301,7 +2236,7 @@ EmitElemIncDec(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) } static JSBool -EmitNumberOp(JSContext *cx, jsdouble dval, BytecodeEmitter *bce) +EmitNumberOp(JSContext *cx, double dval, BytecodeEmitter *bce) { int32_t ival; uint32_t u; @@ -2338,7 +2273,7 @@ EmitNumberOp(JSContext *cx, jsdouble dval, BytecodeEmitter *bce) if (!bce->constList.append(DoubleValue(dval))) return JS_FALSE; - return EmitIndexOp(cx, JSOP_DOUBLE, bce->constList.length() - 1, bce); + return EmitIndex32(cx, JSOP_DOUBLE, bce->constList.length() - 1, bce); } /* @@ -2612,8 +2547,8 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) * 1 offset (len) and 1 atom index (npairs) before the table, * 1 atom index and 1 jump offset per entry. */ - switchSize = (size_t)(JUMP_OFFSET_LEN + INDEX_LEN + - (INDEX_LEN + JUMP_OFFSET_LEN) * caseCount); + switchSize = (size_t)(JUMP_OFFSET_LEN + UINT16_LEN + + (UINT32_INDEX_LEN + JUMP_OFFSET_LEN) * caseCount); } /* Emit switchOp followed by switchSize bytes of jump or lookup table. */ @@ -2711,8 +2646,8 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) JS_ASSERT(switchOp == JSOP_LOOKUPSWITCH); /* Fill in the number of cases. */ - SET_INDEX(pc, caseCount); - pc += INDEX_LEN; + SET_UINT16(pc, caseCount); + pc += UINT16_LEN; } /* @@ -2761,7 +2696,7 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (NewSrcNote2(cx, bce, SRC_LABEL, ptrdiff_t(index)) < 0) goto bad; } - pc += INDEX_LEN + JUMP_OFFSET_LEN; + pc += UINT32_INDEX_LEN + JUMP_OFFSET_LEN; } } bce->current->next = savepc; @@ -2819,15 +2754,15 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) } } else if (switchOp == JSOP_LOOKUPSWITCH) { /* Skip over the already-initialized number of cases. */ - pc += INDEX_LEN; + pc += UINT16_LEN; for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { if (pn3->isKind(PNK_DEFAULT)) continue; if (!bce->constList.append(*pn3->pn_pval)) goto bad; - SET_INDEX(pc, bce->constList.length() - 1); - pc += INDEX_LEN; + SET_UINT32_INDEX(pc, bce->constList.length() - 1); + pc += UINT32_INDEX_LEN; off = pn3->pn_offset - top; SET_JUMP_OFFSET(pc, off); @@ -2911,7 +2846,8 @@ MaybeEmitVarDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode * bce->switchToProlog(); if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno)) return false; - EMIT_INDEX_OP(prologOp, atomIndex); + if (!EmitIndexOp(cx, prologOp, atomIndex, bce)) + return false; bce->switchToMain(); } @@ -3613,10 +3549,11 @@ EmitVariables(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption if (pn3) { JS_ASSERT(emitOption != DefineVars); JS_ASSERT_IF(emitOption == PushInitialValues, op == JSOP_SETLOCAL); - if (op == JSOP_SETNAME) - EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex); - else if (op == JSOP_SETGNAME) - EMIT_INDEX_OP(JSOP_BINDGNAME, atomIndex); + if (op == JSOP_SETNAME || op == JSOP_SETGNAME) { + JSOp bindOp = (op == JSOP_SETNAME) ? JSOP_BINDNAME : JSOP_BINDGNAME; + if (!EmitIndex32(cx, bindOp, atomIndex, bce)) + return false; + } if (pn->isOp(JSOP_DEFCONST) && !DefineCompileTimeConstant(cx, bce, pn2->pn_atom, pn3)) { @@ -3657,7 +3594,8 @@ EmitVariables(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption } else if (!pn2->pn_cookie.isFree()) { EMIT_UINT16_IMM_OP(op, atomIndex); } else { - EMIT_INDEX_OP(op, atomIndex); + if (!EmitIndexOp(cx, op, atomIndex, bce)) + return false; } #if JS_HAS_DESTRUCTURING @@ -3708,7 +3646,8 @@ EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, Par return false; if (!lhs->isConst()) { JSOp op = lhs->isOp(JSOP_SETGNAME) ? JSOP_BINDGNAME : JSOP_BINDNAME; - EMIT_INDEX_OP(op, atomIndex); + if (!EmitIndex32(cx, op, atomIndex, bce)) + return false; offset++; } } @@ -3761,17 +3700,23 @@ EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, Par if (lhs->isOp(JSOP_CALLEE)) { if (Emit1(cx, bce, JSOP_CALLEE) < 0) return false; + } else if (lhs->isOp(JSOP_NAME)) { + if (!EmitIndex32(cx, lhs->getOp(), atomIndex, bce)) + return false; } else { - EMIT_INDEX_OP(lhs->getOp(), atomIndex); + JS_ASSERT(JOF_OPTYPE(lhs->getOp()) != JOF_ATOM); + EMIT_UINT16_IMM_OP(lhs->getOp(), atomIndex); } } else if (lhs->isOp(JSOP_SETNAME)) { if (Emit1(cx, bce, JSOP_DUP) < 0) return false; - EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex); + if (!EmitIndex32(cx, JSOP_GETXPROP, atomIndex, bce)) + return false; } else if (lhs->isOp(JSOP_SETGNAME)) { if (!BindGlobal(cx, bce, lhs, lhs->pn_atom)) return false; - EmitAtomOp(cx, lhs, JSOP_GETGNAME, bce); + if (!EmitAtomOp(cx, lhs, JSOP_GETGNAME, bce)) + return false; } else { EMIT_UINT16_IMM_OP(lhs->isOp(JSOP_SETARG) ? JSOP_GETARG : JSOP_GETLOCAL, atomIndex); } @@ -3780,13 +3725,14 @@ EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, Par if (Emit1(cx, bce, JSOP_DUP) < 0) return false; if (lhs->pn_atom == cx->runtime->atomState.protoAtom) { - if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, bce)) + if (!EmitIndex32(cx, JSOP_QNAMEPART, atomIndex, bce)) return false; if (!EmitElemOpBase(cx, bce, JSOP_GETELEM)) return false; } else { bool isLength = (lhs->pn_atom == cx->runtime->atomState.lengthAtom); - EMIT_INDEX_OP(isLength ? JSOP_LENGTH : JSOP_GETPROP, atomIndex); + if (!EmitIndex32(cx, isLength ? JSOP_LENGTH : JSOP_GETPROP, atomIndex, bce)) + return false; } break; case PNK_LB: @@ -3850,9 +3796,17 @@ EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, Par } break; } - /* FALL THROUGH */ + if (lhs->isOp(JSOP_SETARG) || lhs->isOp(JSOP_SETLOCAL)) { + JS_ASSERT(atomIndex < UINT16_MAX); + EMIT_UINT16_IMM_OP(lhs->getOp(), atomIndex); + } else { + if (!EmitIndexOp(cx, lhs->getOp(), atomIndex, bce)) + return false; + } + break; case PNK_DOT: - EMIT_INDEX_OP(lhs->getOp(), atomIndex); + if (!EmitIndexOp(cx, lhs->getOp(), atomIndex, bce)) + return false; break; case PNK_LB: case PNK_LP: @@ -4562,7 +4516,8 @@ EmitXMLTag(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) : cx->runtime->atomState.stagoAtom; if (!bce->makeAtomIndex(tagAtom, &index)) return false; - EMIT_INDEX_OP(JSOP_STRING, index); + if (!EmitIndex32(cx, JSOP_STRING, index, bce)) + return false; } JS_ASSERT(pn->pn_count != 0); @@ -4594,7 +4549,8 @@ EmitXMLTag(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) : cx->runtime->atomState.tagcAtom; if (!bce->makeAtomIndex(tmp, &index)) return false; - EMIT_INDEX_OP(JSOP_STRING, index); + if (!EmitIndex32(cx, JSOP_STRING, index, bce)) + return false; } if (Emit1(cx, bce, JSOP_ADD) < 0) return false; @@ -4613,7 +4569,7 @@ EmitXMLProcessingInstruction(JSContext *cx, BytecodeEmitter *bce, XMLProcessingI jsatomid index; if (!bce->makeAtomIndex(pi.data(), &index)) return false; - if (!EmitIndexOp(cx, JSOP_QNAMEPART, index, bce)) + if (!EmitIndex32(cx, JSOP_QNAMEPART, index, bce)) return false; if (!EmitAtomOp(cx, pi.target(), JSOP_XMLPI, bce)) return false; @@ -6042,7 +5998,8 @@ EmitObject(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) obj = NULL; } - EMIT_INDEX_OP(op, index); + if (!EmitIndex32(cx, op, index, bce)) + return false; } } @@ -6051,18 +6008,16 @@ EmitObject(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (obj) { /* - * The object survived and has a predictable shape. Update the original bytecode, - * as long as we can do so without using a big index prefix/suffix. + * The object survived and has a predictable shape: update the original + * bytecode. */ ObjectBox *objbox = bce->parser->newObjectBox(obj); if (!objbox) return false; uintN index = bce->objectList.index(objbox); - if (FitsWithoutBigIndex(index)) { - MOZ_STATIC_ASSERT(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH, - "newinit and newobject must have equal length to edit in-place"); - EMIT_UINT32_IN_PLACE(offset, JSOP_NEWOBJECT, uint32_t(index)); - } + MOZ_STATIC_ASSERT(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH, + "newinit and newobject must have equal length to edit in-place"); + EMIT_UINT32_IN_PLACE(offset, JSOP_NEWOBJECT, uint32_t(index)); } return true; @@ -6644,7 +6599,8 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) jsatomid index; if (!bce->makeAtomIndex(atom, &index)) return JS_FALSE; - EMIT_INDEX_OP(JSOP_STRING, index); + if (!EmitIndex32(cx, JSOP_STRING, index, bce)) + return false; } if (Emit1(cx, bce, pn->getOp()) < 0) return JS_FALSE; diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index b6bd2ec6074..aec0529db79 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -109,7 +109,7 @@ FoldType(JSContext *cx, ParseNode *pn, ParseNodeKind kind) switch (kind) { case PNK_NUMBER: if (pn->isKind(PNK_STRING)) { - jsdouble d; + double d; if (!ToNumber(cx, StringValue(pn->pn_atom), &d)) return JS_FALSE; pn->pn_dval = d; @@ -146,7 +146,7 @@ static JSBool FoldBinaryNumeric(JSContext *cx, JSOp op, ParseNode *pn1, ParseNode *pn2, ParseNode *pn, TreeContext *tc) { - jsdouble d, d2; + double d, d2; int32_t i, j; JS_ASSERT(pn1->isKind(PNK_NUMBER) && pn2->isKind(PNK_NUMBER)); @@ -822,7 +822,7 @@ js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond) case PNK_POS: case PNK_NEG: if (pn1->isKind(PNK_NUMBER)) { - jsdouble d; + double d; /* Operate on one numeric constant. */ d = pn1->pn_dval; diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index ce5d219d4ea..5f9ba443bcd 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -619,7 +619,7 @@ struct ParseNode { AtomDefnMapPtr defnMap; ParseNode *tree; /* sub-tree containing name uses */ } nameset; - jsdouble dval; /* aligned numeric literal value */ + double dval; /* aligned numeric literal value */ class { friend class LoopControlStatement; PropertyName *label; /* target of break/continue statement */ diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index fae98fcd113..cb1531d0723 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -1732,7 +1732,7 @@ TokenStream::getTokenInternal() * chars, so we don't need to use tokenbuf. Instead we can just * convert the jschars in userbuf directly to the numeric value. */ - jsdouble dval; + double dval; const jschar *dummy; if (!hasFracOrExp) { if (!GetPrefixInteger(cx, numStart, userbuf.addressOfNextRawChar(), 10, &dummy, &dval)) @@ -1823,7 +1823,7 @@ TokenStream::getTokenInternal() goto error; } - jsdouble dval; + double dval; const jschar *dummy; if (!GetPrefixInteger(cx, numStart, userbuf.addressOfNextRawChar(), radix, &dummy, &dval)) goto error; diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 798729bac17..769a2fbc233 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -322,7 +322,7 @@ struct Token { PropertyName *target; /* non-empty */ JSAtom *data; /* maybe empty, never null */ } xmlpi; - jsdouble number; /* floating point number */ + double number; /* floating point number */ RegExpFlag reflags; /* regexp flags, use tokenbuf to access regexp chars */ } u; @@ -359,7 +359,7 @@ struct Token { u.reflags = flags; } - void setNumber(jsdouble n) { + void setNumber(double n) { u.number = n; } @@ -396,7 +396,7 @@ struct Token { return u.reflags; } - jsdouble number() const { + double number() const { JS_ASSERT(type == TOK_NUMBER); return u.number; } diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index a9e5a071214..fdc3a40cc5e 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -148,6 +148,8 @@ * object allocation and the assignment. */ +struct JSXML; + namespace js { /* @@ -269,6 +271,10 @@ BarrieredSetPair(JSCompartment *comp, v2.post(); } +struct Shape; +class BaseShape; +namespace types { struct TypeObject; } + typedef HeapPtr HeapPtrObject; typedef HeapPtr HeapPtrFunction; typedef HeapPtr HeapPtrString; diff --git a/js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js b/js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js index 2b2439be2b9..6cee576ee79 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js +++ b/js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js @@ -6,5 +6,5 @@ function caller(code, obj) { eval(code); // Make the compiler give up on binding analysis. return x; } -trap(caller, 13, "var x = 'success'; nop()"); +trap(caller, 15, "var x = 'success'; nop()"); assertEq(caller("var y = 'ignominy'", this), "success"); diff --git a/js/src/jit-test/tests/jaeger/bug563000/eif-trap.js b/js/src/jit-test/tests/jaeger/bug563000/eif-trap.js index e83941e1be8..0c3d2c0bbc4 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/eif-trap.js +++ b/js/src/jit-test/tests/jaeger/bug563000/eif-trap.js @@ -7,5 +7,5 @@ function caller(obj) { var x = "failure"; return x; } -trap(caller, 15, "x = 'success'; nop()"); +trap(caller, 19, "x = 'success'; nop()"); assertEq(caller(this), "success"); diff --git a/js/src/jit-test/tests/jaeger/bug563000/simple-trap-2.js b/js/src/jit-test/tests/jaeger/bug563000/simple-trap-2.js index 9f2580a73fc..05fd936bbad 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/simple-trap-2.js +++ b/js/src/jit-test/tests/jaeger/bug563000/simple-trap-2.js @@ -5,7 +5,7 @@ function main() { x = "failure"; } function success() { x = "success"; } /* The JSOP_STOP in main. */ -trap(main, 10, "success()"); +trap(main, 16, "success()"); main(); assertEq(x, "success"); diff --git a/js/src/jit-test/tests/jaeger/bug563000/trap-force-return-1.js b/js/src/jit-test/tests/jaeger/bug563000/trap-force-return-1.js index 09ae0db4042..29393db72a8 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/trap-force-return-1.js +++ b/js/src/jit-test/tests/jaeger/bug563000/trap-force-return-1.js @@ -4,5 +4,5 @@ function main() { return "failure"; } /* JSOP_RETURN in main. */ -trap(main, 3, "'success'"); +trap(main, 5, "'success'"); assertEq(main(), "success"); diff --git a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js index 9234f163765..8b7e1b89746 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js +++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js @@ -3,7 +3,7 @@ setDebug(true); x = "notset"; function main() { /* The JSOP_STOP in main. */ - a = { valueOf: function () { trap(main, 39, "success()"); } }; + a = { valueOf: function () { trap(main, 55, "success()"); } }; a + ""; x = "failure"; } diff --git a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js index 3eaec1353b5..577278229ce 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js +++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js @@ -3,7 +3,7 @@ setDebug(true); x = "notset"; function main() { /* The JSOP_STOP in main. */ - a = { valueOf: function () { trap(main, 60, "success()"); } }; + a = { valueOf: function () { trap(main, 84, "success()"); } }; b = ""; eval(); a + b; diff --git a/js/src/jit-test/tests/jaeger/bug563000/trap-parent-from-trap.js b/js/src/jit-test/tests/jaeger/bug563000/trap-parent-from-trap.js index 2b4653e7cad..239a594a5af 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/trap-parent-from-trap.js +++ b/js/src/jit-test/tests/jaeger/bug563000/trap-parent-from-trap.js @@ -5,7 +5,7 @@ x = "notset"; function child() { x = "failure1"; /* JSOP_STOP in parent. */ - trap(parent, 10, "success()"); + trap(parent, 16, "success()"); } function parent() { diff --git a/js/src/jit-test/tests/jaeger/bug563000/trap-parent.js b/js/src/jit-test/tests/jaeger/bug563000/trap-parent.js index 2baeb08b627..c26d16a9f6c 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/trap-parent.js +++ b/js/src/jit-test/tests/jaeger/bug563000/trap-parent.js @@ -3,7 +3,7 @@ setDebug(true); x = "notset"; function child() { /* JSOP_STOP in parent. */ - trap(parent, 17, "success()"); + trap(parent, 26, "success()"); } function parent() { child(); diff --git a/js/src/jit-test/tests/jaeger/bug563000/trap-self-as-parent.js b/js/src/jit-test/tests/jaeger/bug563000/trap-self-as-parent.js index 35ffb68d16f..a5ba0718384 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/trap-self-as-parent.js +++ b/js/src/jit-test/tests/jaeger/bug563000/trap-self-as-parent.js @@ -5,7 +5,7 @@ x = "notset"; function myparent(nested) { if (nested) { /* noop call in myparent */ - trap(myparent, 48, "success()"); + trap(myparent, 68, "success()"); } else { myparent(true); x = "failure"; diff --git a/js/src/jit-test/tests/jaeger/bug563000/trap-self-from-trap.js b/js/src/jit-test/tests/jaeger/bug563000/trap-self-from-trap.js index 8f9c186dbad..8eadf06950c 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/trap-self-from-trap.js +++ b/js/src/jit-test/tests/jaeger/bug563000/trap-self-from-trap.js @@ -7,14 +7,14 @@ function doNothing() { } function myparent(nested) { if (nested) { /* JSOP_CALL to doNothing in myparent with nested = true. */ - trap(myparent, 28, "success()"); + trap(myparent, 36, "success()"); doNothing(); } else { doNothing(); } } /* JSOP_CALL to doNothing in myparent with nested = false. */ -trap(myparent, 41, "myparent(true)"); +trap(myparent, 51, "myparent(true)"); function success() { x = "success"; diff --git a/js/src/jit-test/tests/jaeger/bug563000/trap-self.js b/js/src/jit-test/tests/jaeger/bug563000/trap-self.js index d02977e9600..989ae0ca584 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/trap-self.js +++ b/js/src/jit-test/tests/jaeger/bug563000/trap-self.js @@ -3,7 +3,7 @@ setDebug(true); x = "notset"; function main() { /* The JSOP_STOP in main. */ - trap(main, 25, "success()"); + trap(main, 38, "success()"); x = "failure"; } function success() { x = "success"; } diff --git a/js/src/jit-test/tests/jaeger/bug563000/untrap-own-trapsite.js b/js/src/jit-test/tests/jaeger/bug563000/untrap-own-trapsite.js index db5c2f50b79..3a263e0b16f 100644 --- a/js/src/jit-test/tests/jaeger/bug563000/untrap-own-trapsite.js +++ b/js/src/jit-test/tests/jaeger/bug563000/untrap-own-trapsite.js @@ -3,14 +3,14 @@ setDebug(true); x = "notset"; function child() { /* JSOP_STOP in parent */ - untrap(parent, 10); + untrap(parent, 16); x = "success"; } function parent() { x = "failure"; } /* JSOP_STOP in parent */ -trap(parent, 10, "child()"); +trap(parent, 16, "child()"); parent(); assertEq(x, "success"); diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp index 0c8a0e471ad..d75ae7cf02a 100644 --- a/js/src/jsanalyze.cpp +++ b/js/src/jsanalyze.cpp @@ -123,7 +123,7 @@ ScriptAnalysis::checkAliasedName(JSContext *cx, jsbytecode *pc) atom = fun->atom; } else { JS_ASSERT(JOF_TYPE(js_CodeSpec[*pc].format) == JOF_ATOM); - atom = script->getAtom(js_GetIndexFromBytecode(script, pc, 0)); + atom = script->getAtom(GET_UINT32_INDEX(pc)); } uintN index; @@ -422,7 +422,7 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx) getCode(defaultOffset).safePoint = true; while (npairs) { - pc2 += INDEX_LEN; + pc2 += UINT32_INDEX_LEN; unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2); if (!addJump(cx, targetOffset, &nextOffset, &forwardJump, stackDepth)) return; @@ -1550,7 +1550,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx) uint32_t pendingOffset = 0; while (npairs) { - pc2 += INDEX_LEN; + pc2 += UINT32_INDEX_LEN; unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2); checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth, &pending, &pendingOffset); diff --git a/js/src/jsapi-tests/testParseJSON.cpp b/js/src/jsapi-tests/testParseJSON.cpp index b6a04c82123..ad609622b18 100644 --- a/js/src/jsapi-tests/testParseJSON.cpp +++ b/js/src/jsapi-tests/testParseJSON.cpp @@ -51,7 +51,7 @@ BEGIN_TEST(testParseJSON_success) CHECK(TryParse(cx, "1", DOUBLE_TO_JSVAL(1))); CHECK(TryParse(cx, "1.75", DOUBLE_TO_JSVAL(1.75))); CHECK(TryParse(cx, "9e9", DOUBLE_TO_JSVAL(9e9))); - CHECK(TryParse(cx, "9e99999", DOUBLE_TO_JSVAL(std::numeric_limits::infinity()))); + CHECK(TryParse(cx, "9e99999", DOUBLE_TO_JSVAL(std::numeric_limits::infinity()))); JSFlatString *str; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 0a723273a50..a51a1af4896 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -285,7 +285,7 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format JSBool required; char c; JSFunction *fun; - jsdouble d; + double d; JSString *str; JSObject *obj; @@ -338,13 +338,13 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format return JS_FALSE; break; case 'd': - if (!JS_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *))) + if (!JS_ValueToNumber(cx, *sp, va_arg(ap, double *))) return JS_FALSE; break; case 'I': if (!JS_ValueToNumber(cx, *sp, &d)) return JS_FALSE; - *va_arg(ap, jsdouble *) = js_DoubleToInteger(d); + *va_arg(ap, double *) = js_DoubleToInteger(d); break; case 'S': case 'W': @@ -445,7 +445,7 @@ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp) JSBool ok; JSObject *obj; JSString *str; - jsdouble d; + double d; AssertNoGC(cx); CHECK_REQUEST(cx); @@ -536,7 +536,7 @@ JS_ValueToSource(JSContext *cx, jsval v) } JS_PUBLIC_API(JSBool) -JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) +JS_ValueToNumber(JSContext *cx, jsval v, double *dp) { AssertNoGC(cx); CHECK_REQUEST(cx); @@ -547,19 +547,19 @@ JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) } JS_PUBLIC_API(JSBool) -JS_DoubleIsInt32(jsdouble d, jsint *ip) +JS_DoubleIsInt32(double d, jsint *ip) { return JSDOUBLE_IS_INT32(d, (int32_t *)ip); } JS_PUBLIC_API(int32_t) -JS_DoubleToInt32(jsdouble d) +JS_DoubleToInt32(double d) { return js_DoubleToECMAInt32(d); } JS_PUBLIC_API(uint32_t) -JS_DoubleToUint32(jsdouble d) +JS_DoubleToUint32(double d) { return js_DoubleToECMAUint32(d); } @@ -825,6 +825,10 @@ JSRuntime::init(uint32_t maxbytes) if (!gcMarker.init()) return false; + const char *size = getenv("JSGC_MARK_STACK_LIMIT"); + if (size) + SetMarkStackLimit(this, atoi(size)); + if (!(atomsCompartment = this->new_(this)) || !atomsCompartment->init(NULL) || !compartments.append(atomsCompartment)) { @@ -2244,7 +2248,7 @@ JS_strdup(JSContext *cx, const char *s) } JS_PUBLIC_API(JSBool) -JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval) +JS_NewNumberValue(JSContext *cx, double d, jsval *rval) { AssertNoGC(cx); d = JS_CANONICALIZE_NAN(d); @@ -2907,6 +2911,9 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value) case JSGC_SLICE_TIME_BUDGET: rt->gcSliceBudget = SliceBudget::TimeBudget(value); break; + case JSGC_MARK_STACK_LIMIT: + js::SetMarkStackLimit(rt, value); + break; default: JS_ASSERT(key == JSGC_MODE); rt->gcMode = JSGCMode(value); @@ -2935,6 +2942,8 @@ JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key) return uint32_t(rt->gcChunkSet.count() + rt->gcChunkPool.getEmptyCount()); case JSGC_SLICE_TIME_BUDGET: return uint32_t(rt->gcSliceBudget > 0 ? rt->gcSliceBudget / PRMJ_USEC_PER_MSEC : 0); + case JSGC_MARK_STACK_LIMIT: + return rt->gcMarker.sizeLimit(); default: JS_ASSERT(key == JSGC_NUMBER); return uint32_t(rt->gcNumber); @@ -6276,7 +6285,7 @@ JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, } JS_PUBLIC_API(JSObject *) -JS_NewDateObjectMsec(JSContext *cx, jsdouble msec) +JS_NewDateObjectMsec(JSContext *cx, double msec) { AssertNoGC(cx); CHECK_REQUEST(cx); diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 34d92aba2b7..473d5fe3289 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1662,7 +1662,7 @@ JSVAL_IS_DOUBLE(jsval v) return JSVAL_IS_DOUBLE_IMPL(JSVAL_TO_IMPL(v)); } -static JS_ALWAYS_INLINE jsdouble +static JS_ALWAYS_INLINE double JSVAL_TO_DOUBLE(jsval v) { jsval_layout l; @@ -1672,7 +1672,7 @@ JSVAL_TO_DOUBLE(jsval v) } static JS_ALWAYS_INLINE jsval -DOUBLE_TO_JSVAL(jsdouble d) +DOUBLE_TO_JSVAL(double d) { /* This is a manually inlined version of: * d = JS_CANONICALIZE_NAN(d); @@ -1692,7 +1692,7 @@ UINT_TO_JSVAL(uint32_t i) { if (i <= JSVAL_INT_MAX) return INT_TO_JSVAL((int32_t)i); - return DOUBLE_TO_JSVAL((jsdouble)i); + return DOUBLE_TO_JSVAL((double)i); } static JS_ALWAYS_INLINE JSBool @@ -2131,8 +2131,8 @@ JS_GetEmptyString(JSRuntime *rt); * i int32_t ECMA int32_t * u uint32_t ECMA uint32_t * j int32_t Rounded int32_t (coordinate) - * d jsdouble IEEE double - * I jsdouble Integral IEEE double + * d double IEEE double + * I double Integral IEEE double * S JSString * Unicode string, accessed by a JSString pointer * W jschar * Unicode character vector, 0-terminated (W for wide) * o JSObject * Object reference @@ -2233,16 +2233,16 @@ extern JS_PUBLIC_API(JSString *) JS_ValueToSource(JSContext *cx, jsval v); extern JS_PUBLIC_API(JSBool) -JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp); +JS_ValueToNumber(JSContext *cx, jsval v, double *dp); extern JS_PUBLIC_API(JSBool) -JS_DoubleIsInt32(jsdouble d, jsint *ip); +JS_DoubleIsInt32(double d, jsint *ip); extern JS_PUBLIC_API(int32_t) -JS_DoubleToInt32(jsdouble d); +JS_DoubleToInt32(double d); extern JS_PUBLIC_API(uint32_t) -JS_DoubleToUint32(jsdouble d); +JS_DoubleToUint32(double d); /* * Convert a value to a number, then to an int32_t, according to the ECMA rules @@ -2894,7 +2894,7 @@ extern JS_PUBLIC_API(char *) JS_strdup(JSContext *cx, const char *s); extern JS_PUBLIC_API(JSBool) -JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval); +JS_NewNumberValue(JSContext *cx, double d, jsval *rval); /* * A GC root is a pointer to a jsval, JSObject * or JSString * that itself @@ -3308,7 +3308,10 @@ typedef enum JSGCParamKey { JSGC_TOTAL_CHUNKS = 8, /* Max milliseconds to spend in an incremental GC slice. */ - JSGC_SLICE_TIME_BUDGET = 9 + JSGC_SLICE_TIME_BUDGET = 9, + + /* Maximum size the GC mark stack can grow to. */ + JSGC_MARK_STACK_LIMIT = 10 } JSGCParamKey; typedef enum JSGCMode { @@ -3593,7 +3596,7 @@ extern JS_PUBLIC_API(void) JS_FinalizeStub(JSContext *cx, JSObject *obj); struct JSConstDoubleSpec { - jsdouble dval; + double dval; const char *name; uint8_t flags; uint8_t spare[3]; @@ -5169,7 +5172,7 @@ extern JS_PUBLIC_API(JSObject *) JS_NewDateObject(JSContext *cx, int year, int mon, int mday, int hour, int min, int sec); extern JS_PUBLIC_API(JSObject *) -JS_NewDateObjectMsec(JSContext *cx, jsdouble msec); +JS_NewDateObjectMsec(JSContext *cx, double msec); /* * Infallible predicate to test whether obj is a date object. diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index a3901ef720a..3eb9c5e61d2 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -305,13 +305,13 @@ JSObject::willBeSparseDenseArray(uintN requiredCapacity, uintN newElementsHint) } static bool -ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp) +ReallyBigIndexToId(JSContext* cx, double index, jsid* idp) { return js_ValueToStringId(cx, DoubleValue(index), idp); } static bool -IndexToId(JSContext* cx, JSObject* obj, jsdouble index, JSBool* hole, jsid* idp, +IndexToId(JSContext* cx, JSObject* obj, double index, JSBool* hole, jsid* idp, JSBool createAtom = JS_FALSE) { if (index <= JSID_INT_MAX) { @@ -363,7 +363,7 @@ JSObject::arrayGetOwnDataElement(JSContext *cx, size_t i, Value *vp) * properly rooted and can be used as GC-protected storage for temporaries. */ static inline JSBool -DoGetElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, Value *vp) +DoGetElement(JSContext *cx, JSObject *obj, double index, JSBool *hole, Value *vp) { AutoIdRooter idr(cx); @@ -468,7 +468,7 @@ GetElements(JSContext *cx, JSObject *aobj, jsuint length, Value *vp) * Set the value of the property at the given index to v assuming v is rooted. */ static JSBool -SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, const Value &v) +SetArrayElement(JSContext *cx, JSObject *obj, double index, const Value &v) { JS_ASSERT(index >= 0); @@ -519,7 +519,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, const Value &v) * - Return -1 if an exception occurs (that is, [[Delete]] would throw). */ static int -DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, bool strict) +DeleteArrayElement(JSContext *cx, JSObject *obj, double index, bool strict) { JS_ASSERT(index >= 0); JS_ASSERT(floor(index) == index); @@ -554,7 +554,7 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, bool strict) * its value to v assuming v is rooted. */ static JSBool -SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, +SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, double index, JSBool hole, const Value &v) { if (hole) { @@ -565,7 +565,7 @@ SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, } JSBool -js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length) +js_SetLengthProperty(JSContext *cx, JSObject *obj, double length) { Value v = NumberValue(length); @@ -604,7 +604,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value if (!ToUint32(cx, *vp, &newlen)) return false; - jsdouble d; + double d; if (!ToNumber(cx, *vp, &d)) return false; @@ -2168,7 +2168,7 @@ SortComparatorFunction::operator()(const Value &a, const Value &b, bool *lessOrE if (!Invoke(cx, ag)) return false; - jsdouble cmp; + double cmp; if (!ToNumber(cx, ag.rval(), &cmp)) return false; @@ -2374,7 +2374,7 @@ array_push_slowly(JSContext *cx, JSObject *obj, CallArgs &args) return false; /* Per ECMA-262, return the new array length. */ - jsdouble newlength = length + jsdouble(args.length()); + double newlength = length + double(args.length()); args.rval().setNumber(newlength); return js_SetLengthProperty(cx, obj, newlength); } @@ -2593,7 +2593,7 @@ array_unshift(JSContext *cx, uintN argc, Value *vp) if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; - jsdouble newlen = length; + double newlen = length; if (args.length() > 0) { /* Slide up the array to make room for all args at the bottom. */ if (length > 0) { @@ -2617,8 +2617,8 @@ array_unshift(JSContext *cx, uintN argc, Value *vp) } while (false); if (!optimized) { - jsdouble last = length; - jsdouble upperIndex = last + args.length(); + double last = length; + double upperIndex = last + args.length(); AutoValueRooter tvr(cx); do { --last, --upperIndex; @@ -2731,7 +2731,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp) /* Step 7. */ uint32_t actualDeleteCount; if (argc != 1) { - jsdouble deleteCountDouble; + double deleteCountDouble; if (!ToInteger(cx, argc >= 2 ? args[1] : Int32Value(0), &deleteCountDouble)) return false; actualDeleteCount = JS_MIN(JS_MAX(deleteCountDouble, 0), len - actualStart); @@ -2853,9 +2853,9 @@ array_splice(JSContext *cx, uintN argc, Value *vp) if (cx->typeInferenceEnabled()) obj->setDenseArrayInitializedLength(len + itemCount - actualDeleteCount); } else { - for (jsdouble k = len - actualDeleteCount; k > actualStart; k--) { - jsdouble from = k + actualDeleteCount - 1; - jsdouble to = k + itemCount - 1; + for (double k = len - actualDeleteCount; k > actualStart; k--) { + double from = k + actualDeleteCount - 1; + double to = k + itemCount - 1; JSBool hole; Value fromValue; @@ -2879,7 +2879,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp) } /* Step 16. */ - jsdouble finalLength = jsdouble(len) - actualDeleteCount + itemCount; + double finalLength = double(len) - actualDeleteCount + itemCount; if (!js_SetLengthProperty(cx, obj, finalLength)) return false; @@ -3014,7 +3014,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp) end = length; if (args.length() > 0) { - jsdouble d; + double d; if (!ToInteger(cx, args[0], &d)) return false; if (d < 0) { @@ -3097,7 +3097,7 @@ array_indexOfHelper(JSContext *cx, IndexOfKind mode, CallArgs &args) i = (mode == LastIndexOf) ? length - 1 : 0; tosearch = (args.length() != 0) ? args[0] : UndefinedValue(); } else { - jsdouble start; + double start; tosearch = args[0]; if (!ToInteger(cx, args[1], &start)) @@ -3663,9 +3663,9 @@ js_Array(JSContext *cx, uintN argc, Value *vp) } length = uint32_t(i); } else { - jsdouble d = args[0].toDouble(); + double d = args[0].toDouble(); length = js_DoubleToECMAUint32(d); - if (d != jsdouble(length)) { + if (d != double(length)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); return false; } diff --git a/js/src/jsarray.h b/js/src/jsarray.h index dc1ebfafcd7..958d017c4a4 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -141,7 +141,7 @@ extern JSBool js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp); extern JSBool -js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length); +js_SetLengthProperty(JSContext *cx, JSObject *obj, double length); namespace js { diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index 70d15727615..a57f948fdf3 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -232,7 +232,7 @@ js_ValueToBoolean(const Value &v) if (v.isNullOrUndefined()) return JS_FALSE; if (v.isDouble()) { - jsdouble d; + double d; d = v.toDouble(); return !JSDOUBLE_IS_NaN(d) && d != 0; diff --git a/js/src/jsclone.cpp b/js/src/jsclone.cpp index 496a0506821..a6dbee4dd28 100644 --- a/js/src/jsclone.cpp +++ b/js/src/jsclone.cpp @@ -195,11 +195,11 @@ CanonicalizeNan(double d) } bool -SCInput::readDouble(jsdouble *p) +SCInput::readDouble(double *p) { union { uint64_t u; - jsdouble d; + double d; } pun; if (!read(&pun.u)) return false; @@ -265,7 +265,7 @@ SCOutput::writePair(uint32_t tag, uint32_t data) { /* * As it happens, the tag word appears after the data word in the output. - * This is because exponents occupy the last 2 bytes of jsdoubles on the + * This is because exponents occupy the last 2 bytes of doubles on the * little-endian platforms we care most about. * * For example, JSVAL_TRUE is written using writePair(SCTAG_BOOLEAN, 1). @@ -276,35 +276,35 @@ SCOutput::writePair(uint32_t tag, uint32_t data) } static inline uint64_t -ReinterpretDoubleAsUInt64(jsdouble d) +ReinterpretDoubleAsUInt64(double d) { union { - jsdouble d; + double d; uint64_t u; } pun; pun.d = d; return pun.u; } -static inline jsdouble +static inline double ReinterpretUInt64AsDouble(uint64_t u) { union { uint64_t u; - jsdouble d; + double d; } pun; pun.u = u; return pun.d; } -static inline jsdouble +static inline double ReinterpretPairAsDouble(uint32_t tag, uint32_t data) { return ReinterpretUInt64AsDouble(PairToUInt64(tag, data)); } bool -SCOutput::writeDouble(jsdouble d) +SCOutput::writeDouble(double d) { return write(ReinterpretDoubleAsUInt64(CanonicalizeNan(d))); } @@ -530,7 +530,7 @@ JSStructuredCloneWriter::startWrite(const js::Value &v) return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) && writeString(SCTAG_STRING, reobj.getSource()); } else if (obj->isDate()) { - jsdouble d = js_DateGetMsecSinceEpoch(context(), obj); + double d = js_DateGetMsecSinceEpoch(context(), obj); return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d); } else if (obj->isObject() || obj->isArray()) { return startObject(obj); @@ -603,7 +603,7 @@ JSStructuredCloneWriter::write(const Value &v) } bool -JSStructuredCloneReader::checkDouble(jsdouble d) +JSStructuredCloneReader::checkDouble(double d) { jsval_layout l; l.asDouble = d; @@ -731,7 +731,7 @@ JSStructuredCloneReader::startRead(Value *vp) } case SCTAG_NUMBER_OBJECT: { - jsdouble d; + double d; if (!in.readDouble(&d) || !checkDouble(d)) return false; vp->setDouble(d); @@ -741,7 +741,7 @@ JSStructuredCloneReader::startRead(Value *vp) } case SCTAG_DATE_OBJECT: { - jsdouble d; + double d; if (!in.readDouble(&d) || !checkDouble(d)) return false; if (d == d && d != TIMECLIP(d)) { @@ -808,7 +808,7 @@ JSStructuredCloneReader::startRead(Value *vp) default: { if (tag <= SCTAG_FLOAT_MAX) { - jsdouble d = ReinterpretPairAsDouble(tag, data); + double d = ReinterpretPairAsDouble(tag, data); if (!checkDouble(d)) return false; vp->setNumber(d); diff --git a/js/src/jsclone.h b/js/src/jsclone.h index 7d202eaab93..2d9f9bd67a8 100644 --- a/js/src/jsclone.h +++ b/js/src/jsclone.h @@ -63,7 +63,7 @@ struct SCOutput { bool write(uint64_t u); bool writePair(uint32_t tag, uint32_t data); - bool writeDouble(jsdouble d); + bool writeDouble(double d); bool writeBytes(const void *p, size_t nbytes); bool writeChars(const jschar *p, size_t nchars); @@ -87,7 +87,7 @@ struct SCInput { bool read(uint64_t *p); bool readPair(uint32_t *tagp, uint32_t *datap); - bool readDouble(jsdouble *p); + bool readDouble(double *p); bool readBytes(void *p, size_t nbytes); bool readChars(jschar *p, size_t nchars); @@ -100,7 +100,7 @@ struct SCInput { void staticAssertions() { JS_STATIC_ASSERT(sizeof(jschar) == 2); JS_STATIC_ASSERT(sizeof(uint32_t) == 4); - JS_STATIC_ASSERT(sizeof(jsdouble) == 8); + JS_STATIC_ASSERT(sizeof(double) == 8); } JSContext *cx; @@ -123,7 +123,7 @@ struct JSStructuredCloneReader { private: JSContext *context() { return in.context(); } - bool checkDouble(jsdouble d); + bool checkDouble(double d); JSString *readString(uint32_t nchars); bool readTypedArray(uint32_t tag, uint32_t nelems, js::Value *vp); bool readArrayBuffer(uint32_t nbytes, js::Value *vp); diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index d40a5513f11..86a76173c8b 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -73,6 +73,7 @@ JSCompartment::JSCompartment(JSRuntime *rt) : rt(rt), principals(NULL), needsBarrier_(false), + barrierMarker_(rt->gcMarker.sizeLimit()), gcBytes(0), gcTriggerBytes(0), gcLastBytes(0), diff --git a/js/src/jscompat.h b/js/src/jscompat.h index bee2977dc05..f8f1791fa99 100644 --- a/js/src/jscompat.h +++ b/js/src/jscompat.h @@ -46,6 +46,6 @@ */ #include "jstypes.h" -typedef JSIntn intN; -typedef JSUintn uintN; +typedef int intN; +typedef unsigned uintN; #endif /* jscompat_h___ */ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 9824afcd00b..2ab41f4c08f 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -176,10 +176,10 @@ using namespace js::types; * computing the reciprocal and multiplying instead of dividing - this loses * when the reciprocal isn't representable in a double. */ -static jsdouble msPerSecond = 1000.0; -static jsdouble msPerDay = SecondsPerDay * 1000.0; -static jsdouble msPerHour = SecondsPerHour * 1000.0; -static jsdouble msPerMinute = SecondsPerMinute * 1000.0; +static double msPerSecond = 1000.0; +static double msPerDay = SecondsPerDay * 1000.0; +static double msPerHour = SecondsPerHour * 1000.0; +static double msPerMinute = SecondsPerMinute * 1000.0; #else #define msPerDay (SecondsPerDay * msPerSecond) #define msPerHour (SecondsPerHour * msPerSecond) @@ -189,10 +189,10 @@ static jsdouble msPerMinute = SecondsPerMinute * 1000.0; #define Day(t) floor((t) / msPerDay) -static jsdouble -TimeWithinDay(jsdouble t) +static double +TimeWithinDay(double t) { - jsdouble result; + double result; result = fmod(t, msPerDay); if (result < 0) result += msPerDay; @@ -225,10 +225,10 @@ DaysInFebruary(jsint year) #define TimeFromYear(y) (DayFromYear(y) * msPerDay) static jsint -YearFromTime(jsdouble t) +YearFromTime(double t) { jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970; - jsdouble t2 = (jsdouble) TimeFromYear(y); + double t2 = (double) TimeFromYear(y); /* * Adjust the year if the approximation was wrong. Since the year was @@ -250,7 +250,7 @@ YearFromTime(jsdouble t) * The following array contains the day of year for the first day of * each month, where index 0 is January, and day 0 is January 1. */ -static jsdouble firstDayOfMonth[2][13] = { +static double firstDayOfMonth[2][13] = { {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0, 365.0}, {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0, 366.0} }; @@ -266,7 +266,7 @@ DaysInMonth(jsint year, jsint month) } static intN -MonthFromTime(jsdouble t) +MonthFromTime(double t) { intN d, step; jsint year = YearFromTime(t); @@ -298,7 +298,7 @@ MonthFromTime(jsdouble t) } static intN -DateFromTime(jsdouble t) +DateFromTime(double t) { intN d, step, next; jsint year = YearFromTime(t); @@ -341,7 +341,7 @@ DateFromTime(jsdouble t) } static intN -WeekDay(jsdouble t) +WeekDay(double t) { jsint result; result = (jsint) Day(t) + 4; @@ -354,12 +354,12 @@ WeekDay(jsdouble t) #define MakeTime(hour, min, sec, ms) \ ((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms)) -static jsdouble -MakeDay(jsdouble year, jsdouble month, jsdouble date) +static double +MakeDay(double year, double month, double date) { JSBool leap; - jsdouble yearday; - jsdouble monthday; + double yearday; + double monthday; year += floor(month / 12); @@ -412,10 +412,10 @@ EquivalentYearForDST(jsint year) } /* LocalTZA gets set by js_InitDateClass() */ -static jsdouble LocalTZA; +static double LocalTZA; -static jsdouble -DaylightSavingTA(jsdouble t, JSContext *cx) +static double +DaylightSavingTA(double t, JSContext *cx) { /* abort if NaN */ if (JSDOUBLE_IS_NaN(t)) @@ -427,37 +427,37 @@ DaylightSavingTA(jsdouble t, JSContext *cx) */ if (t < 0.0 || t > 2145916800000.0) { jsint year = EquivalentYearForDST(YearFromTime(t)); - jsdouble day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); + double day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); t = MakeDate(day, TimeWithinDay(t)); } int64_t timeMilliseconds = static_cast(t); int64_t offsetMilliseconds = cx->dstOffsetCache.getDSTOffsetMilliseconds(timeMilliseconds, cx); - return static_cast(offsetMilliseconds); + return static_cast(offsetMilliseconds); } -static jsdouble -AdjustTime(jsdouble date, JSContext *cx) +static double +AdjustTime(double date, JSContext *cx) { - jsdouble t = DaylightSavingTA(date, cx) + LocalTZA; + double t = DaylightSavingTA(date, cx) + LocalTZA; t = (LocalTZA >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay); return t; } -static jsdouble -LocalTime(jsdouble t, JSContext *cx) +static double +LocalTime(double t, JSContext *cx) { return t + AdjustTime(t, cx); } -static jsdouble -UTC(jsdouble t, JSContext *cx) +static double +UTC(double t, JSContext *cx) { return t - AdjustTime(t - LocalTZA, cx); } static intN -HourFromTime(jsdouble t) +HourFromTime(double t) { intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay); if (result < 0) @@ -466,7 +466,7 @@ HourFromTime(jsdouble t) } static intN -MinFromTime(jsdouble t) +MinFromTime(double t) { intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour); if (result < 0) @@ -475,7 +475,7 @@ MinFromTime(jsdouble t) } static intN -SecFromTime(jsdouble t) +SecFromTime(double t) { intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute); if (result < 0) @@ -484,7 +484,7 @@ SecFromTime(jsdouble t) } static intN -msFromTime(jsdouble t) +msFromTime(double t) { intN result = (intN) fmod(t, msPerSecond); if (result < 0) @@ -578,13 +578,13 @@ date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off, } /* find UTC time from given date... no 1900 correction! */ -static jsdouble -date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour, - jsdouble min, jsdouble sec, jsdouble msec) +static double +date_msecFromDate(double year, double mon, double mday, double hour, + double min, double sec, double msec) { - jsdouble day; - jsdouble msec_time; - jsdouble result; + double day; + double msec_time; + double result; day = MakeDay(year, mon, mday); msec_time = MakeTime(hour, min, sec, msec); @@ -599,12 +599,12 @@ static JSBool date_msecFromArgs(JSContext *cx, CallArgs args, double *rval) { uintN loop; - jsdouble array[MAXARGS]; - jsdouble msec_time; + double array[MAXARGS]; + double msec_time; for (loop = 0; loop < MAXARGS; loop++) { if (loop < args.length()) { - jsdouble d; + double d; if (!ToNumber(cx, args[loop], &d)) return JS_FALSE; /* return NaN if any arg is not finite */ @@ -640,7 +640,7 @@ date_UTC(JSContext *cx, uintN argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); - jsdouble msec_time; + double msec_time; if (!date_msecFromArgs(cx, args, &msec_time)) return JS_FALSE; @@ -680,9 +680,9 @@ digits(size_t *result, const jschar *s, size_t *i, size_t limit) * as digits are consumed. */ static JSBool -fractional(jsdouble *result, const jschar *s, size_t *i, size_t limit) +fractional(double *result, const jschar *s, size_t *i, size_t limit) { - jsdouble factor = 0.1; + double factor = 0.1; size_t init = *i; *result = 0.0; while (*i < limit && @@ -770,9 +770,9 @@ ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit) */ static JSBool -date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx) +date_parseISOString(JSLinearString *str, double *result, JSContext *cx) { - jsdouble msec; + double msec; const jschar *s; size_t limit; @@ -785,7 +785,7 @@ date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx) size_t hour = 0; size_t min = 0; size_t sec = 0; - jsdouble frac = 0; + double frac = 0; bool isLocalTime = JS_FALSE; size_t tzHour = 0; size_t tzMin = 0; @@ -879,7 +879,7 @@ date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx) month -= 1; /* convert month to 0-based */ - msec = date_msecFromDate(dateMul * (jsdouble)year, month, day, + msec = date_msecFromDate(dateMul * (double)year, month, day, hour, min, sec, frac * 1000.0);; @@ -909,9 +909,9 @@ date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx) } static JSBool -date_parseString(JSLinearString *str, jsdouble *result, JSContext *cx) +date_parseString(JSLinearString *str, double *result, JSContext *cx) { - jsdouble msec; + double msec; const jschar *s; size_t limit; @@ -1184,7 +1184,7 @@ static JSBool date_parse(JSContext *cx, uintN argc, Value *vp) { JSString *str; - jsdouble result; + double result; if (argc == 0) { vp->setDouble(js_NaN); @@ -1208,10 +1208,10 @@ date_parse(JSContext *cx, uintN argc, Value *vp) return true; } -static inline jsdouble +static inline double NowAsMillis() { - return (jsdouble) (PRMJ_Now() / PRMJ_USEC_PER_MSEC); + return (double) (PRMJ_Now() / PRMJ_USEC_PER_MSEC); } static JSBool @@ -1225,7 +1225,7 @@ date_now(JSContext *cx, uintN argc, Value *vp) * Set UTC time to a given time and invalidate cached local time. */ static JSBool -SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL) +SetUTCTime(JSContext *cx, JSObject *obj, double t, Value *vp = NULL) { JS_ASSERT(obj->isDate()); @@ -1244,7 +1244,7 @@ SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL) static void SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL) { - jsdouble NaN = cx->runtime->NaNValue.getDoubleRef(); + double NaN = cx->runtime->NaNValue.getDoubleRef(); SetUTCTime(cx, obj, NaN, vp); } @@ -1258,7 +1258,7 @@ FillLocalTimes(JSContext *cx, JSObject *obj) { JS_ASSERT(obj->isDate()); - jsdouble utcTime = obj->getDateUTCTime().toNumber(); + double utcTime = obj->getDateUTCTime().toNumber(); if (!JSDOUBLE_IS_FINITE(utcTime)) { for (size_t ind = JSObject::JSSLOT_DATE_COMPONENTS_START; @@ -1269,12 +1269,12 @@ FillLocalTimes(JSContext *cx, JSObject *obj) return true; } - jsdouble localTime = LocalTime(utcTime, cx); + double localTime = LocalTime(utcTime, cx); obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_TIME, DoubleValue(localTime)); jsint year = (jsint) floor(localTime /(msPerDay*365.2425)) + 1970; - jsdouble yearStartTime = (jsdouble) TimeFromYear(year); + double yearStartTime = (double) TimeFromYear(year); /* Adjust the year in case the approximation was wrong, as in YearFromTime. */ jsint yearDays; @@ -1284,7 +1284,7 @@ FillLocalTimes(JSContext *cx, JSObject *obj) yearDays = DaysInYear(year); } else { yearDays = DaysInYear(year); - jsdouble nextStart = yearStartTime + (msPerDay * yearDays); + double nextStart = yearStartTime + (msPerDay * yearDays); if (nextStart <= localTime) { year++; yearStartTime = nextStart; @@ -1582,7 +1582,7 @@ date_getUTCDay(JSContext *cx, uintN argc, Value *vp) if (!obj) return ok; - jsdouble result = obj->getDateUTCTime().toNumber(); + double result = obj->getDateUTCTime().toNumber(); if (JSDOUBLE_IS_FINITE(result)) result = WeekDay(result); @@ -1740,7 +1740,7 @@ date_setTime(JSContext *cx, uintN argc, Value *vp) return true; } - jsdouble result; + double result; if (!ToNumber(cx, args[0], &result)) return false; @@ -2044,7 +2044,7 @@ static const char* months[] = // Avoid dependence on PRMJ_FormatTimeUSEnglish, because it // requires a PRMJTime... which only has 16-bit years. Sub-ECMA. static void -print_gmt_string(char* buf, size_t size, jsdouble utctime) +print_gmt_string(char* buf, size_t size, double utctime) { JS_snprintf(buf, size, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", days[WeekDay(utctime)], @@ -2057,7 +2057,7 @@ print_gmt_string(char* buf, size_t size, jsdouble utctime) } static void -print_iso_string(char* buf, size_t size, jsdouble utctime) +print_iso_string(char* buf, size_t size, double utctime) { JS_snprintf(buf, size, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ", YearFromTime(utctime), @@ -2071,7 +2071,7 @@ print_iso_string(char* buf, size_t size, jsdouble utctime) static JSBool date_utc_format(JSContext *cx, Native native, CallArgs args, - void (*printFunc)(char*, size_t, jsdouble)) + void (*printFunc)(char*, size_t, double)) { bool ok; JSObject *obj = NonGenericMethodGuard(cx, args, native, &DateClass, &ok); @@ -2160,7 +2160,7 @@ date_toJSON(JSContext *cx, uintN argc, Value *vp) /* for Date.toLocaleString; interface to PRMJTime date struct. */ static void -new_explode(jsdouble timeval, PRMJTime *split, JSContext *cx) +new_explode(double timeval, PRMJTime *split, JSContext *cx) { jsint year = YearFromTime(timeval); @@ -2185,7 +2185,7 @@ typedef enum formatspec { /* helper function */ static JSBool -date_format(JSContext *cx, jsdouble date, formatspec format, CallReceiver call) +date_format(JSContext *cx, double date, formatspec format, CallReceiver call) { char buf[100]; JSString *str; @@ -2197,7 +2197,7 @@ date_format(JSContext *cx, jsdouble date, formatspec format, CallReceiver call) if (!JSDOUBLE_IS_FINITE(date)) { JS_snprintf(buf, sizeof buf, js_NaN_date_str); } else { - jsdouble local = LocalTime(date, cx); + double local = LocalTime(date, cx); /* offset from GMT in minutes. The offset includes daylight savings, if it applies. */ @@ -2307,7 +2307,7 @@ ToLocaleHelper(JSContext *cx, CallReceiver call, JSObject *obj, const char *form JS_snprintf(buf, sizeof buf, js_NaN_date_str); } else { intN result_len; - jsdouble local = LocalTime(utctime, cx); + double local = LocalTime(utctime, cx); PRMJTime split; new_explode(local, &split, cx); @@ -2595,7 +2595,7 @@ js_Date(JSContext *cx, uintN argc, Value *vp) return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, args); /* Date called as constructor. */ - jsdouble d; + double d; if (args.length() == 0) { d = NowAsMillis(); } else if (args.length() == 1) { @@ -2620,7 +2620,7 @@ js_Date(JSContext *cx, uintN argc, Value *vp) d = TIMECLIP(d); } } else { - jsdouble msec_time; + double msec_time; if (!date_msecFromArgs(cx, args, &msec_time)) return false; @@ -2689,7 +2689,7 @@ js_InitDateClass(JSContext *cx, JSObject *obj) } JS_FRIEND_API(JSObject *) -js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time) +js_NewDateObjectMsec(JSContext *cx, double msec_time) { JSObject *obj = NewBuiltinClassInstance(cx, &DateClass); if (!obj) @@ -2704,7 +2704,7 @@ js_NewDateObject(JSContext* cx, int year, int mon, int mday, int hour, int min, int sec) { JSObject *obj; - jsdouble msec_time; + double msec_time; JS_ASSERT(mon < 12); msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0); @@ -2721,7 +2721,7 @@ js_DateIsValid(JSContext *cx, JSObject* obj) JS_FRIEND_API(int) js_DateGetYear(JSContext *cx, JSObject* obj) { - jsdouble localtime; + double localtime; /* Preserve legacy API behavior of returning 0 for invalid dates. */ if (!GetAndCacheLocalTime(cx, obj, &localtime) || @@ -2735,7 +2735,7 @@ js_DateGetYear(JSContext *cx, JSObject* obj) JS_FRIEND_API(int) js_DateGetMonth(JSContext *cx, JSObject* obj) { - jsdouble localtime; + double localtime; if (!GetAndCacheLocalTime(cx, obj, &localtime) || JSDOUBLE_IS_NaN(localtime)) { @@ -2748,7 +2748,7 @@ js_DateGetMonth(JSContext *cx, JSObject* obj) JS_FRIEND_API(int) js_DateGetDate(JSContext *cx, JSObject* obj) { - jsdouble localtime; + double localtime; if (!GetAndCacheLocalTime(cx, obj, &localtime) || JSDOUBLE_IS_NaN(localtime)) { @@ -2761,7 +2761,7 @@ js_DateGetDate(JSContext *cx, JSObject* obj) JS_FRIEND_API(int) js_DateGetHours(JSContext *cx, JSObject* obj) { - jsdouble localtime; + double localtime; if (!GetAndCacheLocalTime(cx, obj, &localtime) || JSDOUBLE_IS_NaN(localtime)) { @@ -2774,7 +2774,7 @@ js_DateGetHours(JSContext *cx, JSObject* obj) JS_FRIEND_API(int) js_DateGetMinutes(JSContext *cx, JSObject* obj) { - jsdouble localtime; + double localtime; if (!GetAndCacheLocalTime(cx, obj, &localtime) || JSDOUBLE_IS_NaN(localtime)) { @@ -2796,7 +2796,7 @@ js_DateGetSeconds(JSContext *cx, JSObject* obj) return (int) SecFromTime(utctime); } -JS_FRIEND_API(jsdouble) +JS_FRIEND_API(double) js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj) { return obj->isDate() ? obj->getDateUTCTime().toNumber() : 0; diff --git a/js/src/jsdate.h b/js/src/jsdate.h index 4d3545b4797..07c3dcb570f 100644 --- a/js/src/jsdate.h +++ b/js/src/jsdate.h @@ -64,7 +64,7 @@ js_InitDateClass(JSContext *cx, JSObject *obj); * since the epoch. */ extern JS_FRIEND_API(JSObject*) -js_NewDateObjectMsec(JSContext* cx, jsdouble msec_time); +js_NewDateObjectMsec(JSContext* cx, double msec_time); /* * Construct a new Date Object from an exploded local time value. diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index b361ced0ba8..f0fa4e20ad0 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1875,8 +1875,9 @@ SliceBudget::checkOverBudget() return over; } -GCMarker::GCMarker() - : color(BLACK), +GCMarker::GCMarker(size_t sizeLimit) + : stack(sizeLimit), + color(BLACK), started(false), unmarkedArenaStackTop(NULL), markLaterArenas(0), @@ -2117,6 +2118,15 @@ GCMarker::GrayCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind) gcmarker->appendGrayRoot(*thingp, kind); } +void +SetMarkStackLimit(JSRuntime *rt, size_t limit) +{ + JS_ASSERT(!rt->gcRunning); + rt->gcMarker.setSizeLimit(limit); + for (CompartmentsIter c(rt); !c.done(); c.next()) + c->barrierMarker_.setSizeLimit(limit); +} + } /* namespace js */ #ifdef DEBUG @@ -3059,9 +3069,32 @@ EndMarkPhase(JSContext *cx) static void ValidateIncrementalMarking(JSContext *cx) { + typedef HashMap BitmapMap; + BitmapMap map; + if (!map.init()) + return; + JSRuntime *rt = cx->runtime; FullGCMarker *gcmarker = &rt->gcMarker; + /* Save existing mark bits */ + for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) { + ChunkBitmap *bitmap = &r.front()->bitmap; + uintptr_t *entry = (uintptr_t *)js_malloc(sizeof(bitmap->bitmap)); + if (!entry) + return; + + memcpy(entry, bitmap->bitmap, sizeof(bitmap->bitmap)); + if (!map.putNew(r.front(), entry)) + return; + } + + /* + * After this point, the function should run to completion, so we shouldn't + * do anything fallible. + */ + + /* Re-do all the marking, but non-incrementally. */ js::gc::State state = rt->gcIncrementalState; rt->gcIncrementalState = NO_INCREMENTAL; @@ -3071,18 +3104,6 @@ ValidateIncrementalMarking(JSContext *cx) JS_ASSERT(gcmarker->isDrained()); gcmarker->reset(); - typedef HashMap BitmapMap; - BitmapMap map(cx); - map.init(); - - for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) { - ChunkBitmap *bitmap = &r.front()->bitmap; - uintptr_t *entry = (uintptr_t *)js_malloc(sizeof(bitmap->bitmap)); - if (entry) - memcpy(entry, bitmap->bitmap, sizeof(bitmap->bitmap)); - map.putNew(r.front(), entry); - } - for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) r.front()->bitmap.clear(); @@ -3091,15 +3112,13 @@ ValidateIncrementalMarking(JSContext *cx) rt->gcMarker.drainMarkStack(budget); MarkGrayAndWeak(cx); + /* Now verify that we have the same mark bits as before. */ for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) { Chunk *chunk = r.front(); ChunkBitmap *bitmap = &chunk->bitmap; uintptr_t *entry = map.lookup(r.front())->value; ChunkBitmap incBitmap; - if (!entry) - continue; - memcpy(incBitmap.bitmap, entry, sizeof(incBitmap.bitmap)); js_free(entry); diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 6d1ec7f7c9e..ee10c1ae94f 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -1572,12 +1572,15 @@ struct MarkStack { T *ballast; T *ballastLimit; - MarkStack() + size_t sizeLimit; + + MarkStack(size_t sizeLimit) : stack(NULL), tos(NULL), limit(NULL), ballast(NULL), - ballastLimit(NULL) { } + ballastLimit(NULL), + sizeLimit(sizeLimit) { } ~MarkStack() { if (stack != ballast) @@ -1595,10 +1598,23 @@ struct MarkStack { if (!ballast) return false; ballastLimit = ballast + ballastcap; + initFromBallast(); + return true; + } + + void initFromBallast() { stack = ballast; limit = ballastLimit; + if (size_t(limit - stack) > sizeLimit) + limit = stack + sizeLimit; tos = stack; - return true; + } + + void setSizeLimit(size_t size) { + JS_ASSERT(isEmpty()); + + sizeLimit = size; + reset(); } bool push(T item) { @@ -1640,21 +1656,22 @@ struct MarkStack { } void reset() { - if (stack != ballast) { + if (stack != ballast) js_free(stack); - stack = ballast; - limit = ballastLimit; - } - tos = stack; - JS_ASSERT(limit == ballastLimit); + initFromBallast(); + JS_ASSERT(stack == ballast); } bool enlarge() { size_t tosIndex = tos - stack; size_t cap = limit - stack; + if (cap == sizeLimit) + return false; size_t newcap = cap * 2; if (newcap == 0) newcap = 32; + if (newcap > sizeLimit) + newcap = sizeLimit; T *newStack; if (stack == ballast) { @@ -1741,9 +1758,12 @@ struct GCMarker : public JSTracer { } public: - explicit GCMarker(); + explicit GCMarker(size_t sizeLimit); bool init(bool lazy); + void setSizeLimit(size_t size) { stack.setSizeLimit(size); } + size_t sizeLimit() const { return stack.sizeLimit; } + void start(JSRuntime *rt, JSContext *cx); void stop(); void reset(); @@ -1881,18 +1901,24 @@ struct GCMarker : public JSTracer { }; struct BarrierGCMarker : public GCMarker { + BarrierGCMarker(size_t sizeLimit) : GCMarker(sizeLimit) {} + bool init() { return GCMarker::init(true); } }; - struct FullGCMarker : public GCMarker { + FullGCMarker() : GCMarker(size_t(-1)) {} + bool init() { return GCMarker::init(false); } }; +void +SetMarkStackLimit(JSRuntime *rt, size_t limit); + void MarkStackRangeConservatively(JSTracer *trc, Value *begin, Value *end); diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 2454a0877d5..ca87ba8fdd3 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -2043,15 +2043,8 @@ TypeCompartment::newAllocationSiteTypeObject(JSContext *cx, const AllocationSite static inline jsid GetAtomId(JSContext *cx, JSScript *script, const jsbytecode *pc, unsigned offset) { - unsigned index = js_GetIndexFromBytecode(script, (jsbytecode*) pc, offset); - return MakeTypeId(cx, ATOM_TO_JSID(script->getAtom(index))); -} - -static inline const Value & -GetScriptConst(JSContext *cx, JSScript *script, const jsbytecode *pc) -{ - unsigned index = js_GetIndexFromBytecode(script, (jsbytecode*) pc, 0); - return script->getConst(index); + JSAtom *atom = script->getAtom(GET_UINT32_INDEX(pc + offset)); + return MakeTypeId(cx, ATOM_TO_JSID(atom)); } bool @@ -3443,12 +3436,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, case JSOP_STARTXML: case JSOP_STARTXMLEXPR: case JSOP_DEFXMLNS: - case JSOP_INDEXBASE: - case JSOP_INDEXBASE1: - case JSOP_INDEXBASE2: - case JSOP_INDEXBASE3: - case JSOP_RESETBASE: - case JSOP_RESETBASE0: case JSOP_POPV: case JSOP_DEBUGGER: case JSOP_SETCALL: @@ -4591,8 +4578,7 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO * integer properties and bail out. We can't mark the aggregate * JSID_VOID type property as being in a definite slot. */ - unsigned index = js_GetIndexFromBytecode(script, pc, 0); - jsid id = ATOM_TO_JSID(script->getAtom(index)); + jsid id = ATOM_TO_JSID(script->getAtom(GET_UINT32_INDEX(pc))); if (MakeTypeId(cx, id) != id) return false; if (id == id_prototype(cx) || id == id___proto__(cx) || id == id_constructor(cx)) diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index cdfc74de975..25c99a5da6a 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -1335,6 +1335,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) # define END_CASE_LEN3 len = 3; goto advance_pc; # define END_CASE_LEN4 len = 4; goto advance_pc; # define END_CASE_LEN5 len = 5; goto advance_pc; +# define END_CASE_LEN6 len = 6; goto advance_pc; # define END_CASE_LEN7 len = 7; goto advance_pc; # define END_VARLEN_CASE goto advance_pc; # define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP) @@ -1347,8 +1348,8 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) #define LOAD_ATOM(PCOFF, atom) \ JS_BEGIN_MACRO \ JS_ASSERT((size_t)(atoms - script->atoms) < \ - (size_t)(script->natoms - GET_INDEX(regs.pc + PCOFF))); \ - atom = atoms[GET_INDEX(regs.pc + PCOFF)]; \ + (size_t)(script->natoms - GET_UINT32_INDEX(regs.pc + PCOFF)));\ + atom = atoms[GET_UINT32_INDEX(regs.pc + PCOFF)]; \ JS_END_MACRO #define LOAD_NAME(PCOFF, name) \ @@ -1358,11 +1359,8 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) name = atom->asPropertyName(); \ JS_END_MACRO -#define GET_FULL_INDEX(PCOFF) \ - (atoms - script->atoms + GET_INDEX(regs.pc + (PCOFF))) - #define LOAD_DOUBLE(PCOFF, dbl) \ - (dbl = script->getConst(GET_FULL_INDEX(PCOFF)).toDouble()) + (dbl = script->getConst(GET_UINT32_INDEX(regs.pc + (PCOFF))).toDouble()) #if defined(JS_METHODJIT) bool useMethodJIT = false; @@ -1674,6 +1672,12 @@ ADD_EMPTY_CASE(JSOP_UNUSED14) ADD_EMPTY_CASE(JSOP_UNUSED15) ADD_EMPTY_CASE(JSOP_UNUSED16) ADD_EMPTY_CASE(JSOP_UNUSED17) +ADD_EMPTY_CASE(JSOP_UNUSED18) +ADD_EMPTY_CASE(JSOP_UNUSED19) +ADD_EMPTY_CASE(JSOP_UNUSED20) +ADD_EMPTY_CASE(JSOP_UNUSED21) +ADD_EMPTY_CASE(JSOP_UNUSED22) +ADD_EMPTY_CASE(JSOP_UNUSED23) ADD_EMPTY_CASE(JSOP_CONDSWITCH) ADD_EMPTY_CASE(JSOP_TRY) #if JS_HAS_XML_SUPPORT @@ -2367,7 +2371,7 @@ BEGIN_CASE(JSOP_NEG) /* * When the operand is int jsval, INT32_FITS_IN_JSVAL(i) implies * INT32_FITS_IN_JSVAL(-i) unless i is 0 or INT32_MIN when the - * results, -0.0 or INT32_MAX + 1, are jsdouble values. + * results, -0.0 or INT32_MAX + 1, are double values. */ Value ref = regs.sp[-1]; int32_t i; @@ -2824,25 +2828,6 @@ BEGIN_CASE(JSOP_INT32) PUSH_INT32(GET_INT32(regs.pc)); END_CASE(JSOP_INT32) -BEGIN_CASE(JSOP_INDEXBASE) - /* - * Here atoms can exceed script->natoms as we use atoms as a - * segment register for object literals as well. - */ - atoms += GET_INDEXBASE(regs.pc); -END_CASE(JSOP_INDEXBASE) - -BEGIN_CASE(JSOP_INDEXBASE1) -BEGIN_CASE(JSOP_INDEXBASE2) -BEGIN_CASE(JSOP_INDEXBASE3) - atoms += (op - JSOP_INDEXBASE1 + 1) << 16; -END_CASE(JSOP_INDEXBASE3) - -BEGIN_CASE(JSOP_RESETBASE0) -BEGIN_CASE(JSOP_RESETBASE) - atoms = script->atoms; -END_CASE(JSOP_RESETBASE) - BEGIN_CASE(JSOP_DOUBLE) { double dbl; @@ -2968,9 +2953,9 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH) bool match; #define SEARCH_PAIRS(MATCH_CODE) \ for (;;) { \ - Value rval = script->getConst(GET_INDEX(pc2)); \ + Value rval = script->getConst(GET_UINT32_INDEX(pc2)); \ MATCH_CODE \ - pc2 += INDEX_LEN; \ + pc2 += UINT32_INDEX_LEN; \ if (match) \ break; \ pc2 += off; \ @@ -3070,7 +3055,7 @@ END_CASE(JSOP_GETFCSLOT) BEGIN_CASE(JSOP_DEFCONST) BEGIN_CASE(JSOP_DEFVAR) { - PropertyName *dn = atoms[GET_INDEX(regs.pc)]->asPropertyName(); + PropertyName *dn = atoms[GET_UINT32_INDEX(regs.pc)]->asPropertyName(); /* ES5 10.5 step 8 (with subsequent errata). */ uintN attrs = JSPROP_ENUMERATE; @@ -3273,7 +3258,8 @@ BEGIN_CASE(JSOP_LAMBDA) JSObject *obj2 = &lref.toObject(); JS_ASSERT(obj2->isObject()); #endif - JS_ASSERT(fun->methodAtom() == script->getAtom(GET_FULL_INDEX(JSOP_LAMBDA_LENGTH))); + JS_ASSERT(fun->methodAtom() == + script->getAtom(GET_UINT32_INDEX(regs.pc + JSOP_LAMBDA_LENGTH))); break; } @@ -3284,7 +3270,8 @@ BEGIN_CASE(JSOP_LAMBDA) #endif const Value &lref = regs.sp[-1]; if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) { - JS_ASSERT(fun->methodAtom() == script->getAtom(GET_FULL_INDEX(JSOP_LAMBDA_LENGTH))); + JS_ASSERT(fun->methodAtom() == + script->getAtom(GET_UINT32_INDEX(regs.pc + JSOP_LAMBDA_LENGTH))); break; } } else if (op2 == JSOP_CALL) { @@ -3360,23 +3347,12 @@ END_CASE(JSOP_CALLEE) BEGIN_CASE(JSOP_GETTER) BEGIN_CASE(JSOP_SETTER) { - do_getter_setter: JSOp op2 = JSOp(*++regs.pc); jsid id; Value rval; jsint i; JSObject *obj; switch (op2) { - case JSOP_INDEXBASE: - atoms += GET_INDEXBASE(regs.pc); - regs.pc += JSOP_INDEXBASE_LENGTH - 1; - goto do_getter_setter; - case JSOP_INDEXBASE1: - case JSOP_INDEXBASE2: - case JSOP_INDEXBASE3: - atoms += (op2 - JSOP_INDEXBASE1 + 1) << 16; - goto do_getter_setter; - case JSOP_SETNAME: case JSOP_SETPROP: { @@ -4000,10 +3976,8 @@ BEGIN_CASE(JSOP_XMLCDATA) { JS_ASSERT(!script->strictModeCode); - JSAtom *atom; - LOAD_ATOM(0, atom); - JSString *str = atom; - JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str); + JSAtom *atom = script->getAtom(GET_UINT32_INDEX(regs.pc)); + JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, atom); if (!obj) goto error; PUSH_OBJECT(*obj); @@ -4014,10 +3988,8 @@ BEGIN_CASE(JSOP_XMLCOMMENT) { JS_ASSERT(!script->strictModeCode); - JSAtom *atom; - LOAD_ATOM(0, atom); - JSString *str = atom; - JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str); + JSAtom *atom = script->getAtom(GET_UINT32_INDEX(regs.pc)); + JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, atom); if (!obj) goto error; PUSH_OBJECT(*obj); @@ -4028,12 +4000,10 @@ BEGIN_CASE(JSOP_XMLPI) { JS_ASSERT(!script->strictModeCode); - JSAtom *atom; - LOAD_ATOM(0, atom); - JSString *str = atom; + JSAtom *atom = script->getAtom(GET_UINT32_INDEX(regs.pc)); Value rval = regs.sp[-1]; JSString *str2 = rval.toString(); - JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_PROCESSING_INSTRUCTION, str, str2); + JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_PROCESSING_INSTRUCTION, atom, str2); if (!obj) goto error; regs.sp[-1].setObject(*obj); diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index bf6087cd0fd..e1980ba0038 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -119,7 +119,7 @@ Class js::MathClass = { JSBool js_math_abs(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -135,7 +135,7 @@ js_math_abs(JSContext *cx, uintN argc, Value *vp) static JSBool math_acos(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -160,7 +160,7 @@ math_acos(JSContext *cx, uintN argc, Value *vp) static JSBool math_asin(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -185,7 +185,7 @@ math_asin(JSContext *cx, uintN argc, Value *vp) static JSBool math_atan(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -201,8 +201,8 @@ math_atan(JSContext *cx, uintN argc, Value *vp) return JS_TRUE; } -static inline jsdouble JS_FASTCALL -math_atan2_kernel(jsdouble x, jsdouble y) +static inline double JS_FASTCALL +math_atan2_kernel(double x, double y) { #if defined(_MSC_VER) /* @@ -213,7 +213,7 @@ math_atan2_kernel(jsdouble x, jsdouble y) * - The sign of y determines the multiplicator, 1 or 3. */ if (JSDOUBLE_IS_INFINITE(x) && JSDOUBLE_IS_INFINITE(y)) { - jsdouble z = js_copysign(M_PI / 4, x); + double z = js_copysign(M_PI / 4, x); if (y < 0) z *= 3; return z; @@ -234,7 +234,7 @@ math_atan2_kernel(jsdouble x, jsdouble y) static JSBool math_atan2(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, y, z; + double x, y, z; if (argc <= 1) { vp->setDouble(js_NaN); @@ -247,8 +247,8 @@ math_atan2(JSContext *cx, uintN argc, Value *vp) return JS_TRUE; } -jsdouble -js_math_ceil_impl(jsdouble x) +double +js_math_ceil_impl(double x) { #ifdef __APPLE__ if (x < 0 && x > -1.0) @@ -260,7 +260,7 @@ js_math_ceil_impl(jsdouble x) JSBool js_math_ceil(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -276,7 +276,7 @@ js_math_ceil(JSContext *cx, uintN argc, Value *vp) static JSBool math_cos(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -309,7 +309,7 @@ math_exp_body(double d) static JSBool math_exp(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -325,8 +325,8 @@ math_exp(JSContext *cx, uintN argc, Value *vp) return JS_TRUE; } -jsdouble -js_math_floor_impl(jsdouble x) +double +js_math_floor_impl(double x) { return floor(x); } @@ -334,7 +334,7 @@ js_math_floor_impl(jsdouble x) JSBool js_math_floor(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -350,7 +350,7 @@ js_math_floor(JSContext *cx, uintN argc, Value *vp) static JSBool math_log(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -375,7 +375,7 @@ math_log(JSContext *cx, uintN argc, Value *vp) JSBool js_math_max(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z = js_NegativeInfinity; + double x, z = js_NegativeInfinity; Value *argv; uintN i; @@ -405,7 +405,7 @@ js_math_max(JSContext *cx, uintN argc, Value *vp) JSBool js_math_min(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z = js_PositiveInfinity; + double x, z = js_PositiveInfinity; Value *argv; uintN i; @@ -432,12 +432,12 @@ js_math_min(JSContext *cx, uintN argc, Value *vp) return JS_TRUE; } -static jsdouble -powi(jsdouble x, jsint y) +static double +powi(double x, jsint y) { jsuint n = (y < 0) ? -y : y; - jsdouble m = x; - jsdouble p = 1; + double m = x; + double p = 1; while (true) { if ((n & 1) != 0) p *= m; n >>= 1; @@ -448,9 +448,9 @@ powi(jsdouble x, jsint y) // internal precision in the pow() implementation would have // given us a finite p. This happens very rarely. - jsdouble result = 1.0 / p; + double result = 1.0 / p; return (result == 0 && JSDOUBLE_IS_INFINITE(p)) - ? pow(x, static_cast(y)) // Avoid pow(double, int). + ? pow(x, static_cast(y)) // Avoid pow(double, int). : result; } @@ -463,7 +463,7 @@ powi(jsdouble x, jsint y) JSBool js_math_pow(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, y, z; + double x, y, z; if (argc <= 1) { vp->setDouble(js_NaN); @@ -511,7 +511,7 @@ js_math_pow(JSContext *cx, uintN argc, Value *vp) static const int64_t RNG_MULTIPLIER = 0x5DEECE66DLL; static const int64_t RNG_ADDEND = 0xBLL; static const int64_t RNG_MASK = (1LL << 48) - 1; -static const jsdouble RNG_DSCALE = jsdouble(1LL << 53); +static const double RNG_DSCALE = double(1LL << 53); /* * Math.random() support, lifted from java.util.Random.java. @@ -544,17 +544,17 @@ random_next(int64_t *rngSeed, int bits) return nextseed >> (48 - bits); } -static inline jsdouble +static inline double random_nextDouble(JSContext *cx) { - return jsdouble((random_next(&cx->rngSeed, 26) << 27) + random_next(&cx->rngSeed, 27)) / + return double((random_next(&cx->rngSeed, 26) << 27) + random_next(&cx->rngSeed, 27)) / RNG_DSCALE; } static JSBool math_random(JSContext *cx, uintN argc, Value *vp) { - jsdouble z = random_nextDouble(cx); + double z = random_nextDouble(cx); vp->setDouble(z); return JS_TRUE; } @@ -612,7 +612,7 @@ js_math_round(JSContext *cx, uintN argc, Value *vp) static JSBool math_sin(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -631,7 +631,7 @@ math_sin(JSContext *cx, uintN argc, Value *vp) JSBool js_math_sqrt(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); @@ -650,7 +650,7 @@ js_math_sqrt(JSContext *cx, uintN argc, Value *vp) static JSBool math_tan(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, z; + double x, z; if (argc == 0) { vp->setDouble(js_NaN); diff --git a/js/src/jsmath.h b/js/src/jsmath.h index 9e2efa69fcf..0b7ad5e6579 100644 --- a/js/src/jsmath.h +++ b/js/src/jsmath.h @@ -115,10 +115,10 @@ js_math_sqrt(JSContext *cx, uintN argc, js::Value *vp); extern JSBool js_math_pow(JSContext *cx, uintN argc, js::Value *vp); -extern jsdouble -js_math_ceil_impl(jsdouble x); +extern double +js_math_ceil_impl(double x); -extern jsdouble -js_math_floor_impl(jsdouble x); +extern double +js_math_floor_impl(double x); #endif /* jsmath_h___ */ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index de208c784c6..372d48bf375 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -93,7 +93,7 @@ using namespace js::types; * js_strtod_harder to get the correct answer. */ static bool -ComputeAccurateDecimalInteger(JSContext *cx, const jschar *start, const jschar *end, jsdouble *dp) +ComputeAccurateDecimalInteger(JSContext *cx, const jschar *start, const jschar *end, double *dp) { size_t length = end - start; char *cstr = static_cast(cx->malloc_(length + 1)); @@ -167,7 +167,7 @@ class BinaryDigitReader * down. An example occurs when reading the number 0x1000000000000081, which * rounds to 0x1000000000000000 instead of 0x1000000000000100. */ -static jsdouble +static double ComputeAccurateBinaryBaseInteger(JSContext *cx, const jschar *start, const jschar *end, int base) { BinaryDigitReader bdr(base, start, end); @@ -181,7 +181,7 @@ ComputeAccurateBinaryBaseInteger(JSContext *cx, const jschar *start, const jscha JS_ASSERT(bit == 1); // guaranteed by GetPrefixInteger /* Gather the 53 significant bits (including the leading 1). */ - jsdouble value = 1.0; + double value = 1.0; for (int j = 52; j > 0; j--) { bit = bdr.nextDigit(); if (bit < 0) @@ -192,7 +192,7 @@ ComputeAccurateBinaryBaseInteger(JSContext *cx, const jschar *start, const jscha /* bit2 is the 54th bit (the first dropped from the mantissa). */ int bit2 = bdr.nextDigit(); if (bit2 >= 0) { - jsdouble factor = 2.0; + double factor = 2.0; int sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */ int bit3; @@ -211,13 +211,13 @@ namespace js { bool GetPrefixInteger(JSContext *cx, const jschar *start, const jschar *end, int base, - const jschar **endp, jsdouble *dp) + const jschar **endp, double *dp) { JS_ASSERT(start <= end); JS_ASSERT(2 <= base && base <= 36); const jschar *s = start; - jsdouble d = 0.0; + double d = 0.0; for (; s < end; s++) { int digit; jschar c = *s; @@ -263,7 +263,7 @@ num_isNaN(JSContext *cx, uintN argc, Value *vp) vp->setBoolean(true); return JS_TRUE; } - jsdouble x; + double x; if (!ToNumber(cx, vp[2], &x)) return false; vp->setBoolean(JSDOUBLE_IS_NaN(x)); @@ -277,7 +277,7 @@ num_isFinite(JSContext *cx, uintN argc, Value *vp) vp->setBoolean(false); return JS_TRUE; } - jsdouble x; + double x; if (!ToNumber(cx, vp[2], &x)) return JS_FALSE; vp->setBoolean(JSDOUBLE_IS_FINITE(x)); @@ -288,7 +288,7 @@ static JSBool num_parseFloat(JSContext *cx, uintN argc, Value *vp) { JSString *str; - jsdouble d; + double d; const jschar *bp, *end, *ep; if (argc == 0) { @@ -314,7 +314,7 @@ num_parseFloat(JSContext *cx, uintN argc, Value *vp) static bool ParseIntStringHelper(JSContext *cx, const jschar *ws, const jschar *end, int maybeRadix, - bool stripPrefix, jsdouble *dp) + bool stripPrefix, double *dp) { JS_ASSERT(maybeRadix == 0 || (2 <= maybeRadix && maybeRadix <= 36)); JS_ASSERT(ws <= end); @@ -439,7 +439,7 @@ js::num_parseInt(JSContext *cx, uintN argc, Value *vp) return false; const jschar *end = ws + inputString->length(); - jsdouble number; + double number; if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number)) return false; @@ -610,7 +610,7 @@ IntToCString(ToCStringBuf *cbuf, jsint i, jsint base = 10) } static JSString * JS_FASTCALL -js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base); +js_NumberToStringWithBase(JSContext *cx, double d, jsint base); static JS_ALWAYS_INLINE bool num_toStringHelper(JSContext *cx, Native native, uintN argc, Value *vp) @@ -624,7 +624,7 @@ num_toStringHelper(JSContext *cx, Native native, uintN argc, Value *vp) int32_t base = 10; if (args.length() != 0 && !args[0].isUndefined()) { - jsdouble d2; + double d2; if (!ToInteger(cx, args[0], &d2)) return false; @@ -893,9 +893,9 @@ static JSConstDoubleSpec number_constants[] = { {0,0,0,{0,0,0}} }; -jsdouble js_NaN; -jsdouble js_PositiveInfinity; -jsdouble js_NegativeInfinity; +double js_NaN; +double js_PositiveInfinity; +double js_NegativeInfinity; #if (defined __GNUC__ && defined __i386__) || \ (defined __SUNPRO_CC && defined __i386) @@ -1064,7 +1064,7 @@ extern char* DoubleToCString(double v, char* buffer, int buflen); namespace js { static char * -FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base = 10) +FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, jsint base = 10) { #ifdef DEBUG { @@ -1096,7 +1096,7 @@ FracNumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base = } char * -NumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base/* = 10*/) +NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, jsint base/* = 10*/) { int32_t i; return (JSDOUBLE_IS_INT32(d, &i)) @@ -1107,7 +1107,7 @@ NumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base/* = 10 } static JSString * JS_FASTCALL -js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) +js_NumberToStringWithBase(JSContext *cx, double d, jsint base) { ToCStringBuf cbuf; char *numStr; @@ -1160,7 +1160,7 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) } JSString * JS_FASTCALL -js_NumberToString(JSContext *cx, jsdouble d) +js_NumberToString(JSContext *cx, double d) { return js_NumberToStringWithBase(cx, d, 10); } @@ -1168,7 +1168,7 @@ js_NumberToString(JSContext *cx, jsdouble d) namespace js { JSFixedString * -NumberToString(JSContext *cx, jsdouble d) +NumberToString(JSContext *cx, double d) { if (JSString *str = js_NumberToStringWithBase(cx, d, 10)) return &str->asFixed(); @@ -1239,7 +1239,7 @@ ToNumberSlow(JSContext *cx, Value v, double *out) } skip_int_double: if (v.isString()) - return StringToNumberType(cx, v.toString(), out); + return StringToNumberType(cx, v.toString(), out); if (v.isBoolean()) { if (v.toBoolean()) { *out = 1.0; @@ -1270,7 +1270,7 @@ bool ToInt32Slow(JSContext *cx, const Value &v, int32_t *out) { JS_ASSERT(!v.isInt32()); - jsdouble d; + double d; if (v.isDouble()) { d = v.toDouble(); } else { @@ -1285,7 +1285,7 @@ bool ToUint32Slow(JSContext *cx, const Value &v, uint32_t *out) { JS_ASSERT(!v.isInt32()); - jsdouble d; + double d; if (v.isDouble()) { d = v.toDouble(); } else { @@ -1304,7 +1304,7 @@ bool NonstandardToInt32Slow(JSContext *cx, const Value &v, int32_t *out) { JS_ASSERT(!v.isInt32()); - jsdouble d; + double d; if (v.isDouble()) { d = v.toDouble(); } else if (!ToNumberSlow(cx, v, &d)) { @@ -1324,7 +1324,7 @@ bool ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out) { JS_ASSERT(!v.isInt32()); - jsdouble d; + double d; if (v.isDouble()) { d = v.toDouble(); } else if (!ToNumberSlow(cx, v, &d)) { @@ -1337,7 +1337,7 @@ ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out) } uint16_t u = (uint16_t) d; - if ((jsdouble)u == d) { + if ((double)u == d) { *out = u; return true; } @@ -1357,13 +1357,13 @@ ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out) JSBool js_strtod(JSContext *cx, const jschar *s, const jschar *send, - const jschar **ep, jsdouble *dp) + const jschar **ep, double *dp) { size_t i; char cbuf[32]; char *cstr, *istr, *estr; JSBool negative; - jsdouble d; + double d; const jschar *s1 = SkipSpace(s, send); size_t length = send - s1; diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 76b9db03618..6d6520c9670 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -83,11 +83,11 @@ typedef union jsdpun { #endif } s; uint64_t u64; - jsdouble d; + double d; } jsdpun; static inline int -JSDOUBLE_IS_NaN(jsdouble d) +JSDOUBLE_IS_NaN(double d) { jsdpun u; u.d = d; @@ -96,7 +96,7 @@ JSDOUBLE_IS_NaN(jsdouble d) } static inline int -JSDOUBLE_IS_FINITE(jsdouble d) +JSDOUBLE_IS_FINITE(double d) { /* -0 is finite. NaNs are not. */ jsdpun u; @@ -105,7 +105,7 @@ JSDOUBLE_IS_FINITE(jsdouble d) } static inline int -JSDOUBLE_IS_INFINITE(jsdouble d) +JSDOUBLE_IS_INFINITE(double d) { jsdpun u; u.d = d; @@ -113,7 +113,7 @@ JSDOUBLE_IS_INFINITE(jsdouble d) } static inline bool -JSDOUBLE_IS_NEG(jsdouble d) +JSDOUBLE_IS_NEG(double d) { jsdpun u; u.d = d; @@ -121,16 +121,16 @@ JSDOUBLE_IS_NEG(jsdouble d) } static inline uint32_t -JS_HASH_DOUBLE(jsdouble d) +JS_HASH_DOUBLE(double d) { jsdpun u; u.d = d; return u.s.lo ^ u.s.hi; } -extern jsdouble js_NaN; -extern jsdouble js_PositiveInfinity; -extern jsdouble js_NegativeInfinity; +extern double js_NaN; +extern double js_PositiveInfinity; +extern double js_NegativeInfinity; namespace js { @@ -168,7 +168,7 @@ js_IntToString(JSContext *cx, jsint i); * performance. See also js::NumberToCString(). */ extern JSString * JS_FASTCALL -js_NumberToString(JSContext *cx, jsdouble d); +js_NumberToString(JSContext *cx, double d); namespace js { @@ -181,7 +181,7 @@ NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb); /* Same as js_NumberToString, different signature. */ extern JSFixedString * -NumberToString(JSContext *cx, jsdouble d); +NumberToString(JSContext *cx, double d); extern JSFixedString * IndexToString(JSContext *cx, uint32_t index); @@ -213,7 +213,7 @@ struct ToCStringBuf * js_NumberToCString(). */ extern char * -NumberToCString(JSContext *cx, ToCStringBuf *cbuf, jsdouble d, jsint base = 10); +NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, jsint base = 10); /* * The largest positive integer such that all positive integers less than it @@ -235,7 +235,7 @@ const double DOUBLE_INTEGRAL_PRECISION_LIMIT = uint64_t(1) << 53; */ extern bool GetPrefixInteger(JSContext *cx, const jschar *start, const jschar *end, int base, - const jschar **endp, jsdouble *dp); + const jschar **endp, double *dp); /* ES5 9.3 ToNumber. */ JS_ALWAYS_INLINE bool @@ -341,7 +341,7 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp); * otherwise return Result(4). */ static inline int32_t -js_DoubleToECMAInt32(jsdouble d) +js_DoubleToECMAInt32(double d) { #if defined(__i386__) || defined(__i386) || defined(__x86_64__) || \ defined(_M_IX86) || defined(_M_X64) @@ -539,13 +539,13 @@ js_DoubleToECMAInt32(jsdouble d) return i; #else int32_t i; - jsdouble two32, two31; + double two32, two31; if (!JSDOUBLE_IS_FINITE(d)) return 0; i = (int32_t) d; - if ((jsdouble) i == d) + if ((double) i == d) return i; two32 = 4294967296.0; @@ -557,17 +557,17 @@ js_DoubleToECMAInt32(jsdouble d) } inline uint32_t -js_DoubleToECMAUint32(jsdouble d) +js_DoubleToECMAUint32(double d) { return uint32_t(js_DoubleToECMAInt32(d)); } /* - * Convert a jsdouble to an integral number, stored in a jsdouble. + * Convert a double to an integral number, stored in a double. * If d is NaN, return 0. If d is an infinity, return it without conversion. */ -static inline jsdouble -js_DoubleToInteger(jsdouble d) +static inline double +js_DoubleToInteger(double d) { if (d == 0) return d; @@ -596,7 +596,7 @@ js_DoubleToInteger(jsdouble d) */ extern JSBool js_strtod(JSContext *cx, const jschar *s, const jschar *send, - const jschar **ep, jsdouble *dp); + const jschar **ep, double *dp); extern JSBool js_num_valueOf(JSContext *cx, uintN argc, js::Value *vp); @@ -641,7 +641,7 @@ IsDefinitelyIndex(const Value &v, uint32_t *indexp) /* ES5 9.4 ToInteger. */ static inline bool -ToInteger(JSContext *cx, const js::Value &v, jsdouble *dp) +ToInteger(JSContext *cx, const js::Value &v, double *dp) { if (v.isInt32()) { *dp = v.toInt32(); diff --git a/js/src/jsnuminlines.h b/js/src/jsnuminlines.h index 771eba5ccd9..169fb022cbb 100644 --- a/js/src/jsnuminlines.h +++ b/js/src/jsnuminlines.h @@ -51,12 +51,12 @@ template struct NumberTraits { }; template<> struct NumberTraits { static JS_ALWAYS_INLINE int32_t NaN() { return 0; } static JS_ALWAYS_INLINE int32_t toSelfType(int32_t i) { return i; } - static JS_ALWAYS_INLINE int32_t toSelfType(jsdouble d) { return js_DoubleToECMAUint32(d); } + static JS_ALWAYS_INLINE int32_t toSelfType(double d) { return js_DoubleToECMAUint32(d); } }; -template<> struct NumberTraits { - static JS_ALWAYS_INLINE jsdouble NaN() { return js_NaN; } - static JS_ALWAYS_INLINE jsdouble toSelfType(int32_t i) { return i; } - static JS_ALWAYS_INLINE jsdouble toSelfType(jsdouble d) { return d; } +template<> struct NumberTraits { + static JS_ALWAYS_INLINE double NaN() { return js_NaN; } + static JS_ALWAYS_INLINE double toSelfType(int32_t i) { return i; } + static JS_ALWAYS_INLINE double toSelfType(double d) { return d; } }; template diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index bc87fad4fa0..063565c3e0d 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3021,61 +3021,47 @@ js_CreateThisForFunction(JSContext *cx, JSObject *callee, bool newType) * access is "object-detecting" in the sense used by web scripts, e.g., when * checking whether document.all is defined. */ -JSBool +static bool Detecting(JSContext *cx, jsbytecode *pc) { - jsbytecode *endpc; - JSOp op; + /* General case: a branch or equality op follows the access. */ + JSOp op = JSOp(*pc); + if (js_CodeSpec[op].format & JOF_DETECTING) + return true; + JSAtom *atom; JSScript *script = cx->stack.currentScript(); - endpc = script->code + script->length; - for (;; pc += js_CodeSpec[op].length) { - JS_ASSERT(script->code <= pc && pc < endpc); + jsbytecode *endpc = script->code + script->length; + JS_ASSERT(script->code <= pc && pc < endpc); - /* General case: a branch or equality op follows the access. */ - op = JSOp(*pc); - if (js_CodeSpec[op].format & JOF_DETECTING) - return JS_TRUE; + if (op == JSOP_NULL) { + /* + * Special case #1: handle (document.all == null). Don't sweat + * about JS1.2's revision of the equality operators here. + */ + if (++pc < endpc) { + op = JSOp(*pc); + return op == JSOP_EQ || op == JSOP_NE; + } + return false; + } - switch (op) { - case JSOP_NULL: - /* - * Special case #1: handle (document.all == null). Don't sweat - * about JS1.2's revision of the equality operators here. - */ - if (++pc < endpc) { - op = JSOp(*pc); - return op == JSOP_EQ || op == JSOP_NE; - } - return JS_FALSE; - - case JSOP_GETGNAME: - case JSOP_NAME: - /* - * Special case #2: handle (document.all == undefined). Don't - * worry about someone redefining undefined, which was added by - * Edition 3, so is read/write for backward compatibility. - */ - GET_ATOM_FROM_BYTECODE(script, pc, 0, atom); - if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] && - (pc += js_CodeSpec[op].length) < endpc) { - op = JSOp(*pc); - return op == JSOP_EQ || op == JSOP_NE || - op == JSOP_STRICTEQ || op == JSOP_STRICTNE; - } - return JS_FALSE; - - default: - /* - * At this point, anything but an extended atom index prefix means - * we're not detecting. - */ - if (!(js_CodeSpec[op].format & JOF_INDEXBASE)) - return JS_FALSE; - break; + if (op == JSOP_GETGNAME || op == JSOP_NAME) { + /* + * Special case #2: handle (document.all == undefined). Don't worry + * about a local variable named |undefined| shadowing the immutable + * global binding...because, really? + */ + atom = script->getAtom(GET_UINT32_INDEX(pc)); + if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] && + (pc += js_CodeSpec[op].length) < endpc) { + op = JSOp(*pc); + return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE; } } + + return false; } /* @@ -3973,20 +3959,6 @@ JSObject::setSlotSpan(JSContext *cx, uint32_t span) return true; } -#if defined(_MSC_VER) && _MSC_VER >= 1500 -/* Work around a compiler bug in MSVC9 and above, where inlining this function - causes stack pointer offsets to go awry and spp to refer to something higher - up the stack. */ -MOZ_NEVER_INLINE -#endif -const js::Shape * -JSObject::nativeLookup(JSContext *cx, jsid id) -{ - JS_ASSERT(isNative()); - js::Shape **spp; - return js::Shape::search(cx, lastProperty(), id, &spp); -} - bool JSObject::growSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount) { @@ -5370,8 +5342,8 @@ js::CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname) JSMSG_UNDECLARED_VAR, bytes.ptr()); } -bool -JSObject::reportReadOnly(JSContext *cx, jsid id, uintN report) +static bool +ReportReadOnly(JSContext *cx, jsid id, uintN report) { return js_ReportValueErrorFlags(cx, report, JSMSG_READ_ONLY, JSDVG_IGNORE_STACK, IdToValue(id), NULL, @@ -5462,9 +5434,9 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, if (pd.attrs & JSPROP_READONLY) { if (strict) - return obj->reportReadOnly(cx, id); + return ReportReadOnly(cx, id, JSREPORT_ERROR); if (cx->hasStrictOption()) - return obj->reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING); + return ReportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING); return true; } } @@ -5505,9 +5477,9 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, if (!shape->writable()) { /* Error in strict mode code, warn with strict option, otherwise do nothing. */ if (strict) - return obj->reportReadOnly(cx, id); + return ReportReadOnly(cx, id, JSREPORT_ERROR); if (cx->hasStrictOption()) - return obj->reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING); + return ReportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING); return JS_TRUE; } } @@ -6256,10 +6228,6 @@ js_ClearNative(JSContext *cx, JSObject *obj) return true; } -static ObjectElements emptyObjectHeader(0, 0); -HeapValue *js::emptyObjectElements = - (HeapValue *) (uintptr_t(&emptyObjectHeader) + sizeof(ObjectElements)); - JSBool js_ReportGetterOnlyAssignment(JSContext *cx) { diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 10aa3aa76ce..0e346eb2d30 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -61,6 +61,8 @@ #include "jscell.h" #include "gc/Barrier.h" + +#include "vm/ObjectImpl.h" #include "vm/String.h" namespace js { @@ -391,142 +393,33 @@ class StringObject; class RegExpObject; class WithObject; -/* - * Header structure for object element arrays. This structure is immediately - * followed by an array of elements, with the elements member in an object - * pointing to the beginning of that array (the end of this structure). - * See below for usage of this structure. - */ -class ObjectElements -{ - friend struct ::JSObject; - - /* Number of allocated slots. */ - uint32_t capacity; - - /* - * Number of initialized elements. This is <= the capacity, and for arrays - * is <= the length. Memory for elements above the initialized length is - * uninitialized, but values between the initialized length and the proper - * length are conceptually holes. - */ - uint32_t initializedLength; - - /* 'length' property of array objects, unused for other objects. */ - uint32_t length; - - /* :XXX: bug 586842 store state about sparse slots. */ - uint32_t unused; - - void staticAsserts() { - JS_STATIC_ASSERT(sizeof(ObjectElements) == VALUES_PER_HEADER * sizeof(Value)); - } - - public: - - ObjectElements(uint32_t capacity, uint32_t length) - : capacity(capacity), initializedLength(0), length(length) - {} - - HeapValue * elements() { return (HeapValue *)(uintptr_t(this) + sizeof(ObjectElements)); } - static ObjectElements * fromElements(HeapValue *elems) { - return (ObjectElements *)(uintptr_t(elems) - sizeof(ObjectElements)); - } - - static int offsetOfCapacity() { - return (int)offsetof(ObjectElements, capacity) - (int)sizeof(ObjectElements); - } - static int offsetOfInitializedLength() { - return (int)offsetof(ObjectElements, initializedLength) - (int)sizeof(ObjectElements); - } - static int offsetOfLength() { - return (int)offsetof(ObjectElements, length) - (int)sizeof(ObjectElements); - } - - static const size_t VALUES_PER_HEADER = 2; -}; - -/* Shared singleton for objects with no elements. */ -extern HeapValue *emptyObjectElements; - } /* namespace js */ /* - * JSObject struct. The JSFunction struct is an extension of this struct - * allocated from a larger GC size-class. + * The public interface for an object. * - * The |shape_| member stores the shape of the object, which includes the - * object's class and the layout of all its properties. + * Implementation of the underlying structure occurs in ObjectImpl, from which + * this struct inherits. This inheritance is currently public, but it will + * eventually be made protected. For full details, see vm/ObjectImpl.{h,cpp}. * - * The type member stores the type of the object, which contains its prototype - * object and the possible types of its properties. - * - * The rest of the object stores its named properties and indexed elements. - * These are stored separately from one another. Objects are followed by an - * variable-sized array of values for inline storage, which may be used by - * either properties of native objects (fixed slots) or by elements. - * - * Two native objects with the same shape are guaranteed to have the same - * number of fixed slots. - * - * Named property storage can be split between fixed slots and a dynamically - * allocated array (the slots member). For an object with N fixed slots, shapes - * with slots [0..N-1] are stored in the fixed slots, and the remainder are - * stored in the dynamic array. If all properties fit in the fixed slots, the - * 'slots' member is NULL. - * - * Elements are indexed via the 'elements' member. This member can point to - * either the shared emptyObjectElements singleton, into the inline value array - * (the address of the third value, to leave room for a ObjectElements header; - * in this case numFixedSlots() is zero) or to a dynamically allocated array. - * - * Only certain combinations of properties and elements storage are currently - * possible. This will be changing soon :XXX: bug 586842. - * - * - For objects other than arrays and typed arrays, the elements are empty. - * - * - For 'slow' arrays, both elements and properties are used, but the - * elements have zero capacity --- only the length member is used. - * - * - For dense arrays, elements are used and properties are not used. - * - * - For typed array buffers, elements are used and properties are not used. - * The data indexed by the elements do not represent Values, but primitive - * unboxed integers or floating point values. + * The JSFunction struct is an extension of this struct allocated from a larger + * GC size-class. */ -struct JSObject : js::gc::Cell +struct JSObject : public js::ObjectImpl { private: friend struct js::Shape; friend struct js::GCMarker; friend class js::NewObjectCache; - /* - * Shape of the object, encodes the layout of the object's properties and - * all other information about its structure. See jsscope.h. - */ - js::HeapPtrShape shape_; - #ifdef DEBUG void checkShapeConsistency(); #endif - /* - * The object's type and prototype. For objects with the LAZY_TYPE flag - * set, this is the prototype's default 'new' type and can only be used - * to get that prototype. - */ - js::HeapPtrTypeObject type_; - /* Make the type object to use for LAZY_TYPE objects. */ void makeLazyType(JSContext *cx); public: - inline js::Shape *lastProperty() const { - JS_ASSERT(shape_); - return shape_; - } - /* * Update the last property, keeping the number of allocated slots in sync * with the object's new slot span. @@ -564,40 +457,13 @@ struct JSObject : js::gc::Cell */ bool setSlotSpan(JSContext *cx, uint32_t span); - static inline size_t offsetOfShape() { return offsetof(JSObject, shape_); } - inline js::HeapPtrShape *addressOfShape() { return &shape_; } - - const js::Shape *nativeLookup(JSContext *cx, jsid id); - inline bool nativeContains(JSContext *cx, jsid id); inline bool nativeContains(JSContext *cx, const js::Shape &shape); /* Upper bound on the number of elements in an object. */ static const uint32_t NELEMENTS_LIMIT = JS_BIT(28); - private: - js::HeapValue *slots; /* Slots for object properties. */ - js::HeapValue *elements; /* Slots for object elements. */ - public: - - inline bool isNative() const; - - inline js::Class *getClass() const; - inline JSClass *getJSClass() const; - inline bool hasClass(const js::Class *c) const; - inline const js::ObjectOps *getOps() const; - - /* - * An object is a delegate if it is on another object's prototype or scope - * chain, and therefore the delegate might be asked implicitly to get or - * set a property on behalf of another object. Delegates may be accessed - * directly too, as may any object, but only those objects linked after the - * head of any prototype or scope chain are flagged as delegates. This - * definition helps to optimize shape-based property cache invalidation - * (see Purge{Scope,Proto}Chain in jsobj.cpp). - */ - inline bool isDelegate() const; inline bool setDelegate(JSContext *cx); inline bool isBoundFunction() const; @@ -663,31 +529,19 @@ struct JSObject : js::gc::Cell /* Whether there may be indexed properties on this object. */ inline bool isIndexed() const; - /* - * Return true if this object is a native one that has been converted from - * shared-immutable prototype-rooted shape storage to dictionary-shapes in - * a doubly-linked list. - */ - inline bool inDictionaryMode() const; - inline uint32_t propertyCount() const; inline bool hasPropertyTable() const; - inline size_t sizeOfThis() const; inline size_t computedSizeOfThisSlotsElements() const; inline void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *slotsSize, size_t *elementsSize, size_t *miscSize) const; - inline size_t numFixedSlots() const; - static const uint32_t MAX_FIXED_SLOTS = 16; private: - inline js::HeapValue* fixedSlots() const; - /* * Get internal pointers to the range of values starting at start and * running for length. @@ -708,14 +562,6 @@ struct JSObject : js::gc::Cell /* Get a raw pointer to the object's properties. */ inline const js::HeapValue *getRawSlots(); - /* JIT Accessors */ - static inline size_t getFixedSlotOffset(size_t slot); - static inline size_t getPrivateDataOffset(size_t nfixed); - static inline size_t offsetOfSlots() { return offsetof(JSObject, slots); } - - /* Minimum size for dynamically allocated slots. */ - static const uint32_t SLOT_CAPACITY_MIN = 8; - /* * Grow or shrink slots immediately before changing the slot span. * The number of allocated slots is not stored explicitly, and changes to @@ -726,14 +572,6 @@ struct JSObject : js::gc::Cell bool hasDynamicSlots() const { return slots != NULL; } - /* - * Get the number of dynamic slots to allocate to cover the properties in - * an object with the given number of fixed slots and slot span. The slot - * capacity is not stored explicitly, and the allocated size of the slot - * array is kept in sync with this count. - */ - static inline size_t dynamicSlotsCount(size_t nfixed, size_t span); - /* Compute dynamicSlotsCount() for this object. */ inline size_t numDynamicSlots() const; @@ -843,18 +681,6 @@ struct JSObject : js::gc::Cell inline void setFixedSlot(uintN slot, const js::Value &value); inline void initFixedSlot(uintN slot, const js::Value &value); - /* - * Whether this is the only object which has its specified type. This - * object will have its type constructed lazily as needed by analysis. - */ - bool hasSingletonType() const { return !!type_->singleton; } - - /* - * Whether the object's type has not been constructed yet. If an object - * might have a lazy type, use getType() below, otherwise type(). - */ - bool hasLazyType() const { return type_->lazy(); } - /* * Marks this object as having a singleton type, and leave the type lazy. * Constructs a new, unique shape for the object. @@ -863,19 +689,11 @@ struct JSObject : js::gc::Cell inline js::types::TypeObject *getType(JSContext *cx); - js::types::TypeObject *type() const { - JS_ASSERT(!hasLazyType()); - return type_; - } - js::HeapPtr &typeFromGC() { /* Direct field access for use by GC. */ return type_; } - static inline size_t offsetOfType() { return offsetof(JSObject, type_); } - inline js::HeapPtrTypeObject *addressOfType() { return &type_; } - inline void setType(js::types::TypeObject *newType); js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL); @@ -906,10 +724,6 @@ struct JSObject : js::gc::Cell */ bool shouldSplicePrototype(JSContext *cx); - JSObject * getProto() const { - return type_->proto; - } - /* * Parents and scope chains. * @@ -988,7 +802,6 @@ struct JSObject : js::gc::Cell inline void *&privateRef(uint32_t nfixed) const; public: - inline bool isExtensible() const; bool preventExtensions(JSContext *cx, js::AutoIdVector *props); /* ES5 15.2.3.8: non-extensible, all props non-configurable */ @@ -1001,38 +814,10 @@ struct JSObject : js::gc::Cell /* Accessors for elements. */ - js::ObjectElements *getElementsHeader() const { - return js::ObjectElements::fromElements(elements); - } - inline bool ensureElements(JSContext *cx, uintN cap); bool growElements(JSContext *cx, uintN cap); void shrinkElements(JSContext *cx, uintN cap); - inline js::HeapValue* fixedElements() const { - JS_STATIC_ASSERT(2 * sizeof(js::Value) == sizeof(js::ObjectElements)); - return &fixedSlots()[2]; - } - - void setFixedElements() { this->elements = fixedElements(); } - - inline bool hasDynamicElements() const { - /* - * Note: for objects with zero fixed slots this could potentially give - * a spurious 'true' result, if the end of this object is exactly - * aligned with the end of its arena and dynamic slots are allocated - * immediately afterwards. Such cases cannot occur for dense arrays - * (which have at least two fixed slots) and can only result in a leak. - */ - return elements != js::emptyObjectElements && elements != fixedElements(); - } - - /* JIT Accessors */ - static inline size_t offsetOfElements() { return offsetof(JSObject, elements); } - static inline size_t offsetOfFixedElements() { - return sizeof(JSObject) + sizeof(js::ObjectElements); - } - inline js::ElementIteratorObject *asElementIterator(); /* @@ -1206,7 +991,6 @@ struct JSObject : js::gc::Cell void freeSlot(JSContext *cx, uint32_t slot); public: - bool reportReadOnly(JSContext* cx, jsid id, uintN report = JSREPORT_ERROR); bool reportNotConfigurable(JSContext* cx, jsid id, uintN report = JSREPORT_ERROR); bool reportNotExtensible(JSContext *cx, uintN report = JSREPORT_ERROR); @@ -1354,12 +1138,6 @@ struct JSObject : js::gc::Cell inline void initArrayClass(); - static inline void writeBarrierPre(JSObject *obj); - static inline void writeBarrierPost(JSObject *obj, void *addr); - static inline void readBarrier(JSObject *obj); - inline void privateWriteBarrierPre(void **oldval); - inline void privateWriteBarrierPost(void **oldval); - /* * In addition to the generic object interface provided by JSObject, * specific types of objects may provide additional operations. To access, @@ -1464,13 +1242,12 @@ struct JSObject : js::gc::Cell private: static void staticAsserts() { - /* Check alignment for any fixed slots allocated after the object. */ - JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(js::Value) == 0); - - JS_STATIC_ASSERT(offsetof(JSObject, shape_) == offsetof(js::shadow::Object, shape)); - JS_STATIC_ASSERT(offsetof(JSObject, slots) == offsetof(js::shadow::Object, slots)); - JS_STATIC_ASSERT(offsetof(JSObject, type_) == offsetof(js::shadow::Object, type)); - JS_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::shadow::Object)); + MOZ_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::shadow::Object), + "shadow interface must match actual interface"); + MOZ_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::ObjectImpl), + "JSObject itself must not have any fields"); + MOZ_STATIC_ASSERT(sizeof(JSObject) % sizeof(js::Value) == 0, + "fixed slots after an object must be aligned"); } }; @@ -1491,28 +1268,6 @@ operator!=(const JSObject &lhs, const JSObject &rhs) return &lhs != &rhs; } -inline js::HeapValue* -JSObject::fixedSlots() const -{ - return (js::HeapValue *) (uintptr_t(this) + sizeof(JSObject)); -} - -inline size_t -JSObject::numFixedSlots() const -{ - return reinterpret_cast(this)->numFixedSlots(); -} - -/* static */ inline size_t -JSObject::getFixedSlotOffset(size_t slot) { - return sizeof(JSObject) + (slot * sizeof(js::Value)); -} - -/* static */ inline size_t -JSObject::getPrivateDataOffset(size_t nfixed) { - return getFixedSlotOffset(nfixed); -} - struct JSObject_Slots2 : JSObject { js::Value fslots[2]; }; struct JSObject_Slots4 : JSObject { js::Value fslots[4]; }; struct JSObject_Slots8 : JSObject { js::Value fslots[8]; }; diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index a3f6033d11f..b54cc289a97 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -80,8 +80,10 @@ #include "jsscriptinlines.h" #include "gc/Barrier-inl.h" -#include "vm/String-inl.h" + +#include "vm/ObjectImpl-inl.h" #include "vm/RegExpStatics-inl.h" +#include "vm/String-inl.h" inline bool JSObject::hasPrivate() const @@ -363,20 +365,6 @@ JSObject::dynamicSlotIndex(size_t slot) return slot - numFixedSlots(); } -/*static*/ inline size_t -JSObject::dynamicSlotsCount(size_t nfixed, size_t span) -{ - if (span <= nfixed) - return 0; - span -= nfixed; - if (span <= SLOT_CAPACITY_MIN) - return SLOT_CAPACITY_MIN; - - size_t slots = js::RoundUpPow2(span); - JS_ASSERT(slots >= span); - return slots; -} - inline size_t JSObject::numDynamicSlots() const { @@ -866,11 +854,6 @@ inline bool JSObject::setSystem(JSContext *cx) return setFlag(cx, js::BaseShape::SYSTEM); } -inline bool JSObject::isDelegate() const -{ - return lastProperty()->hasObjectFlag(js::BaseShape::DELEGATE); -} - inline bool JSObject::setDelegate(JSContext *cx) { return setFlag(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE); @@ -901,11 +884,6 @@ inline bool JSObject::setUncacheableProto(JSContext *cx) return setFlag(cx, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE); } -inline bool JSObject::isExtensible() const -{ - return !lastProperty()->hasObjectFlag(js::BaseShape::NOT_EXTENSIBLE); -} - inline bool JSObject::isBoundFunction() const { return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION); @@ -1171,12 +1149,6 @@ JSObject::nativeSetSlotWithType(JSContext *cx, const js::Shape *shape, const js: js::types::AddTypePropertyId(cx, this, shape->propid(), value); } -inline bool -JSObject::isNative() const -{ - return lastProperty()->isNative(); -} - inline bool JSObject::nativeContains(JSContext *cx, jsid id) { @@ -1195,12 +1167,6 @@ JSObject::nativeEmpty() const return lastProperty()->isEmptyShape(); } -inline bool -JSObject::inDictionaryMode() const -{ - return lastProperty()->inDictionary(); -} - inline uint32_t JSObject::propertyCount() const { @@ -1213,12 +1179,6 @@ JSObject::hasPropertyTable() const return lastProperty()->hasTable(); } -inline size_t -JSObject::sizeOfThis() const -{ - return arenaHeader()->getThingSize(); -} - inline size_t JSObject::computedSizeOfThisSlotsElements() const { @@ -2040,57 +2000,4 @@ JSObject::initFixedSlot(uintN slot, const js::Value &value) fixedSlots()[slot].init(value); } -inline void -JSObject::privateWriteBarrierPre(void **old) -{ -#ifdef JSGC_INCREMENTAL - JSCompartment *comp = compartment(); - if (comp->needsBarrier()) { - if (*old && getClass()->trace) - getClass()->trace(comp->barrierTracer(), this); - } -#endif -} - -inline void -JSObject::privateWriteBarrierPost(void **old) -{ -} - -inline void -JSObject::writeBarrierPre(JSObject *obj) -{ -#ifdef JSGC_INCREMENTAL - /* - * This would normally be a null test, but TypeScript::global uses 0x1 as a - * special value. - */ - if (uintptr_t(obj) < 32) - return; - - JSCompartment *comp = obj->compartment(); - if (comp->needsBarrier()) { - JS_ASSERT(!comp->rt->gcRunning); - MarkObjectUnbarriered(comp->barrierTracer(), obj, "write barrier"); - } -#endif -} - -inline void -JSObject::readBarrier(JSObject *obj) -{ -#ifdef JSGC_INCREMENTAL - JSCompartment *comp = obj->compartment(); - if (comp->needsBarrier()) { - JS_ASSERT(!comp->rt->gcRunning); - MarkObjectUnbarriered(comp->barrierTracer(), obj, "read barrier"); - } -#endif -} - -inline void -JSObject::writeBarrierPost(JSObject *obj, void *addr) -{ -} - #endif /* jsobjinlines_h___ */ diff --git a/js/src/json.cpp b/js/src/json.cpp index 4f930addd59..bbadc43d4bb 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -709,7 +709,7 @@ js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, Value space, StringBu if (space.isObject()) { JSObject &spaceObj = space.toObject(); if (ObjectClassIs(spaceObj, ESClass_Number, cx)) { - jsdouble d; + double d; if (!ToNumber(cx, space, &d)) return false; space = NumberValue(d); @@ -725,7 +725,7 @@ js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, Value space, StringBu if (space.isNumber()) { /* Step 6. */ - jsdouble d; + double d; JS_ALWAYS_TRUE(ToInteger(cx, space, &d)); d = JS_MIN(10, d); if (d >= 1 && !gap.appendN(' ', uint32_t(d))) diff --git a/js/src/jsonparser.cpp b/js/src/jsonparser.cpp index 7b14205e97a..bd21ffc4806 100644 --- a/js/src/jsonparser.cpp +++ b/js/src/jsonparser.cpp @@ -217,7 +217,7 @@ JSONParser::readNumber() /* Fast path: no fractional or exponent part. */ if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) { const jschar *dummy; - jsdouble d; + double d; if (!GetPrefixInteger(cx, digitStart.get(), current.get(), 10, &dummy, &d)) return token(OOM); JS_ASSERT(current == dummy); @@ -262,7 +262,7 @@ JSONParser::readNumber() } } - jsdouble d; + double d; const jschar *finish; if (!js_strtod(cx, digitStart.get(), current.get(), &finish, &d)) return token(OOM); diff --git a/js/src/jsonparser.h b/js/src/jsonparser.h index cfc658a3a24..21b4bdf278c 100644 --- a/js/src/jsonparser.h +++ b/js/src/jsonparser.h @@ -152,7 +152,7 @@ class JSONParser return String; } - Token numberToken(jsdouble d) { + Token numberToken(double d) { this->v = js::NumberValue(d); #ifdef DEBUG lastToken = Number; diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index a29e93d3516..8aabb813f8a 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -144,33 +144,6 @@ Dup(const char *chars, DupBuffer *cb) return cb->append(chars, strlen(chars) + 1); } -uintN -js_GetIndexFromBytecode(JSScript *script, jsbytecode *pc, ptrdiff_t pcoff) -{ - JSOp op = JSOp(*pc); - JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN); - JS_ASSERT(js_CodeSpec[op].format & JOF_ATOM); - - /* - * We need to detect index base prefix. It presents when resetbase - * follows the bytecode. - */ - uintN span = js_CodeSpec[op].length; - uintN base = 0; - if (pc - script->code + span < script->length) { - JSOp next = JSOp(pc[span]); - if (next == JSOP_RESETBASE) { - JS_ASSERT(JSOp(pc[-JSOP_INDEXBASE_LENGTH]) == JSOP_INDEXBASE); - base = GET_INDEXBASE(pc - JSOP_INDEXBASE_LENGTH); - } else if (next == JSOP_RESETBASE0) { - JSOp prev = JSOp(pc[-1]); - JS_ASSERT(JSOP_INDEXBASE1 <= prev && prev <= JSOP_INDEXBASE3); - base = (prev - JSOP_INDEXBASE1 + 1) << 16; - } - } - return base + GET_UINT16(pc + pcoff); -} - size_t js_GetVariableBytecodeLength(jsbytecode *pc) { @@ -194,7 +167,7 @@ js_GetVariableBytecodeLength(jsbytecode *pc) JS_ASSERT(op == JSOP_LOOKUPSWITCH); pc += JUMP_OFFSET_LEN; ncases = GET_UINT16(pc); - return 1 + JUMP_OFFSET_LEN + INDEX_LEN + ncases * (INDEX_LEN + JUMP_OFFSET_LEN); + return 1 + JUMP_OFFSET_LEN + UINT16_LEN + ncases * (UINT32_INDEX_LEN + JUMP_OFFSET_LEN); } } @@ -568,20 +541,20 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, } case JOF_ATOM: { - uintN index = js_GetIndexFromBytecode(script, pc, 0); - jsval v; - if (op == JSOP_DOUBLE) { - v = script->getConst(index); - } else { - JSAtom *atom = script->getAtom(index); - v = STRING_TO_JSVAL(atom); - } - { - JSAutoByteString bytes; - if (!ToDisassemblySource(cx, v, &bytes)) - return 0; - Sprint(sp, " %s", bytes.ptr()); - } + Value v = StringValue(script->getAtom(GET_UINT32_INDEX(pc))); + JSAutoByteString bytes; + if (!ToDisassemblySource(cx, v, &bytes)) + return 0; + Sprint(sp, " %s", bytes.ptr()); + break; + } + + case JOF_DOUBLE: { + Value v = script->getConst(GET_UINT32_INDEX(pc)); + JSAutoByteString bytes; + if (!ToDisassemblySource(cx, v, &bytes)) + return 0; + Sprint(sp, " %s", bytes.ptr()); break; } @@ -641,8 +614,8 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, pc2 += UINT16_LEN; Sprint(sp, " offset %d npairs %u", intN(off), uintN(npairs)); while (npairs) { - uint16_t constIndex = GET_INDEX(pc2); - pc2 += INDEX_LEN; + uint32_t constIndex = GET_UINT32_INDEX(pc2); + pc2 += UINT32_INDEX_LEN; off = GET_JUMP_OFFSET(pc2); pc2 += JUMP_OFFSET_LEN; @@ -1598,7 +1571,7 @@ CompareTableEntries(const TableEntry &a, const TableEntry &b, bool *lessOrEqualp static ptrdiff_t SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp) { - jsdouble d; + double d; ptrdiff_t todo; char *s; @@ -1894,8 +1867,7 @@ IsVarSlot(JSPrinter *jp, jsbytecode *pc, jsint *indexp) return JS_FALSE; } -#define LOAD_ATOM(PCOFF) \ - GET_ATOM_FROM_BYTECODE(jp->script, pc, PCOFF, atom) +#define LOAD_ATOM(PCOFF) (atom = (jp->script->getAtom(GET_UINT32_INDEX((pc) + PCOFF)))) typedef Vector AtomVector; typedef AtomVector::Range AtomRange; @@ -2143,7 +2115,7 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, case JSOP_INT32: d = i = GET_INT32(pc); goto do_getelem; case JSOP_DOUBLE: - GET_DOUBLE_FROM_BYTECODE(jp->script, pc, 0, d); + d = jp->script->getConst(GET_UINT32_INDEX(pc)).toDouble(); LOCAL_ASSERT(JSDOUBLE_IS_FINITE(d) && !JSDOUBLE_IS_NEGZERO(d)); i = (jsint)d; @@ -2717,18 +2689,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) lastop = saveop; op = (JSOp) *pc; cs = &js_CodeSpec[op]; - if (cs->format & JOF_INDEXBASE) { - /* - * The decompiler uses js_GetIndexFromBytecode to get atoms and - * ignores these suffix/prefix bytecodes, thus simplifying code - * that must process JSOP_GETTER/JSOP_SETTER prefixes. - */ - pc += cs->length; - if (pc >= endpc) - break; - op = (JSOp) *pc; - cs = &js_CodeSpec[op]; - } saveop = op; len = oplen = cs->length; nuses = StackUses(jp->script, pc); @@ -4740,9 +4700,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) case JSOP_DOUBLE: { - double d; - GET_DOUBLE_FROM_BYTECODE(jp->script, pc, 0, d); - val = DOUBLE_TO_JSVAL(d); + val = jp->script->getConst(GET_UINT32_INDEX(pc)); todo = SprintDoubleValue(&ss->sprinter, val, &saveop); break; } @@ -5020,8 +4978,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) } else { table[k].label = NULL; } - uint16_t constIndex = GET_INDEX(pc2); - pc2 += INDEX_LEN; + uint32_t constIndex = GET_UINT32_INDEX(pc2); + pc2 += UINT32_INDEX_LEN; off2 = GET_JUMP_OFFSET(pc2); pc2 += JUMP_OFFSET_LEN; table[k].key = jp->script->getConst(constIndex); diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index b446324dc11..be2038a1a2d 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -82,7 +82,7 @@ typedef enum JSOp { #define JOF_LOOKUPSWITCH 5 /* lookup switch */ #define JOF_QARG 6 /* quickened get/set function argument ops */ #define JOF_LOCAL 7 /* var or block-local variable */ -/* 8 is unused */ +#define JOF_DOUBLE 8 /* uint32_t index for double value */ #define JOF_UINT24 12 /* extended unsigned 24-bit literal (index) */ #define JOF_UINT8 13 /* uint8_t immediate, e.g. top 8 bits of 24-bit atom index */ @@ -113,7 +113,7 @@ typedef enum JSOp { #define JOF_BACKPATCH (1U<<15) /* backpatch placeholder during codegen */ #define JOF_LEFTASSOC (1U<<16) /* left-associative operator */ #define JOF_DECLARING (1U<<17) /* var, const, or function declaration op */ -#define JOF_INDEXBASE (1U<<18) /* atom segment base setting prefix op */ +/* (1U<<18) is unused */ #define JOF_PARENHEAD (1U<<20) /* opcode consumes value of expression in parenthesized statement head */ #define JOF_INVOKE (1U<<21) /* JSOP_CALL, JSOP_NEW, JSOP_EVAL */ @@ -192,7 +192,7 @@ SET_JUMP_OFFSET(jsbytecode *pc, int32_t off) #define UINT32_INDEX_LEN 4 static JS_ALWAYS_INLINE uint32_t -GET_UINT32_INDEX(jsbytecode *pc) +GET_UINT32_INDEX(const jsbytecode *pc) { return (pc[1] << 24) | (pc[2] << 16) | (pc[3] << 8) | pc[4]; } @@ -206,22 +206,6 @@ SET_UINT32_INDEX(jsbytecode *pc, uint32_t index) pc[4] = (jsbytecode)index; } -/* - * A literal is indexed by a per-script atom map. Most scripts have relatively - * few literals, so the standard JOF_ATOM format specifies a fixed 16 bits of - * immediate operand index. A script with more than 64K literals must wrap the - * bytecode into an JSOP_INDEXBASE and JSOP_RESETBASE pair. - */ -#define INDEX_LEN 2 -#define INDEX_HI(i) ((jsbytecode)((i) >> 8)) -#define INDEX_LO(i) ((jsbytecode)(i)) -#define GET_INDEX(pc) GET_UINT16(pc) -#define SET_INDEX(pc,i) ((pc)[1] = INDEX_HI(i), (pc)[2] = INDEX_LO(i)) - -#define GET_INDEXBASE(pc) (JS_ASSERT(*(pc) == JSOP_INDEXBASE), \ - ((uintN)((pc)[1])) << 16) -#define INDEXBASE_LEN 1 - #define UINT24_HI(i) ((jsbytecode)((i) >> 16)) #define UINT24_MID(i) ((jsbytecode)((i) >> 8)) #define UINT24_LO(i) ((jsbytecode)(i)) @@ -320,26 +304,10 @@ js_printf(JSPrinter *jp, const char *format, ...); extern JSBool js_puts(JSPrinter *jp, const char *s); -/* - * Get index operand from the bytecode using a bytecode analysis to deduce the - * the index register. This function is infallible, in spite of taking cx as - * its first parameter; it uses only cx->runtime when calling JS_GetTrapOpcode. - * The GET_*_FROM_BYTECODE macros that call it pick up cx from their caller's - * lexical environments. - */ -uintN -js_GetIndexFromBytecode(JSScript *script, jsbytecode *pc, ptrdiff_t pcoff); - -/* - * A slower version of GET_ATOM when the caller does not want to maintain - * the index segment register itself. - */ #define GET_ATOM_FROM_BYTECODE(script, pc, pcoff, atom) \ JS_BEGIN_MACRO \ - JS_ASSERT(*(pc) != JSOP_DOUBLE); \ JS_ASSERT(js_CodeSpec[*(pc)].format & JOF_ATOM); \ - uintN index_ = js_GetIndexFromBytecode((script), (pc), (pcoff)); \ - (atom) = (script)->getAtom(index_); \ + (atom) = (script)->getAtom(GET_UINT32_INDEX((pc) + (pcoff))); \ JS_END_MACRO #define GET_NAME_FROM_BYTECODE(script, pc, pcoff, name) \ @@ -350,13 +318,6 @@ js_GetIndexFromBytecode(JSScript *script, jsbytecode *pc, ptrdiff_t pcoff); (name) = atom_->asPropertyName(); \ JS_END_MACRO -#define GET_DOUBLE_FROM_BYTECODE(script, pc, pcoff, dbl) \ - JS_BEGIN_MACRO \ - uintN index_ = js_GetIndexFromBytecode((script), (pc), (pcoff)); \ - JS_ASSERT(index_ < (script)->consts()->length); \ - (dbl) = (script)->getConst(index_).toDouble(); \ - JS_END_MACRO - namespace js { extern uintN @@ -529,8 +490,8 @@ static inline uintN GetDecomposeLength(jsbytecode *pc, size_t len) { /* - * The last byte of a DECOMPOSE op stores the decomposed length. This can - * vary across different instances of an opcode due to INDEXBASE ops. + * The last byte of a DECOMPOSE op stores the decomposed length. This is a + * constant: perhaps we should just hardcode values instead? */ JS_ASSERT(size_t(js_CodeSpec[*pc].length) == len); return (uintN) pc[len - 1]; diff --git a/js/src/jsopcode.tbl b/js/src/jsopcode.tbl index 534e59f226f..cf0f26ab0b6 100644 --- a/js/src/jsopcode.tbl +++ b/js/src/jsopcode.tbl @@ -131,7 +131,7 @@ OPDEF(JSOP_POPN, 11, "popn", NULL, 3, -1, 0, 0, JOF_UINT16 /* More long-standing bytecodes. */ OPDEF(JSOP_DUP, 12, "dup", NULL, 1, 1, 2, 0, JOF_BYTE) OPDEF(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, 0, JOF_BYTE) -OPDEF(JSOP_SETCONST, 14, "setconst", NULL, 3, 1, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET) +OPDEF(JSOP_SETCONST, 14, "setconst", NULL, 5, 1, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET) OPDEF(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, 7, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) OPDEF(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, 8, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) OPDEF(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, 9, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) @@ -153,34 +153,34 @@ OPDEF(JSOP_NOT, 32, "not", "!", 1, 1, 1, 15, JOF_BYTE|J OPDEF(JSOP_BITNOT, 33, "bitnot", "~", 1, 1, 1, 15, JOF_BYTE|JOF_ARITH) OPDEF(JSOP_NEG, 34, "neg", "- ", 1, 1, 1, 15, JOF_BYTE|JOF_ARITH) OPDEF(JSOP_POS, 35, "pos", "+ ", 1, 1, 1, 15, JOF_BYTE|JOF_ARITH) -OPDEF(JSOP_DELNAME, 36, "delname", NULL, 3, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEL) -OPDEF(JSOP_DELPROP, 37, "delprop", NULL, 3, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEL) +OPDEF(JSOP_DELNAME, 36, "delname", NULL, 5, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEL) +OPDEF(JSOP_DELPROP, 37, "delprop", NULL, 5, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEL) OPDEF(JSOP_DELELEM, 38, "delelem", NULL, 1, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_DEL) OPDEF(JSOP_TYPEOF, 39, js_typeof_str,NULL, 1, 1, 1, 15, JOF_BYTE|JOF_DETECTING) OPDEF(JSOP_VOID, 40, js_void_str, NULL, 1, 1, 1, 15, JOF_BYTE) -OPDEF(JSOP_INCNAME, 41, "incname", NULL, 4, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE) -OPDEF(JSOP_INCPROP, 42, "incprop", NULL, 4, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_INCNAME, 41, "incname", NULL, 6, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_INCPROP, 42, "incprop", NULL, 6, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE) OPDEF(JSOP_INCELEM, 43, "incelem", NULL, 2, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_INC|JOF_TMPSLOT2|JOF_DECOMPOSE) -OPDEF(JSOP_DECNAME, 44, "decname", NULL, 4, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE) -OPDEF(JSOP_DECPROP, 45, "decprop", NULL, 4, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_DECNAME, 44, "decname", NULL, 6, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_DECPROP, 45, "decprop", NULL, 6, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE) OPDEF(JSOP_DECELEM, 46, "decelem", NULL, 2, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_DEC|JOF_TMPSLOT2|JOF_DECOMPOSE) -OPDEF(JSOP_NAMEINC, 47, "nameinc", NULL, 4, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) -OPDEF(JSOP_PROPINC, 48, "propinc", NULL, 4, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_NAMEINC, 47, "nameinc", NULL, 6, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_PROPINC, 48, "propinc", NULL, 6, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) OPDEF(JSOP_ELEMINC, 49, "eleminc", NULL, 2, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_INC|JOF_POST|JOF_TMPSLOT2|JOF_DECOMPOSE) -OPDEF(JSOP_NAMEDEC, 50, "namedec", NULL, 4, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) -OPDEF(JSOP_PROPDEC, 51, "propdec", NULL, 4, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_NAMEDEC, 50, "namedec", NULL, 6, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) +OPDEF(JSOP_PROPDEC, 51, "propdec", NULL, 6, 1, 1, 15, JOF_ATOM|JOF_PROP|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE) OPDEF(JSOP_ELEMDEC, 52, "elemdec", NULL, 2, 2, 1, 15, JOF_BYTE |JOF_ELEM|JOF_DEC|JOF_POST|JOF_TMPSLOT2|JOF_DECOMPOSE) -OPDEF(JSOP_GETPROP, 53, "getprop", NULL, 3, 1, 1, 18, JOF_ATOM|JOF_PROP|JOF_TYPESET) -OPDEF(JSOP_SETPROP, 54, "setprop", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_GETPROP, 53, "getprop", NULL, 5, 1, 1, 18, JOF_ATOM|JOF_PROP|JOF_TYPESET) +OPDEF(JSOP_SETPROP, 54, "setprop", NULL, 5, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) OPDEF(JSOP_GETELEM, 55, "getelem", NULL, 1, 2, 1, 18, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) OPDEF(JSOP_SETELEM, 56, "setelem", NULL, 1, 3, 1, 3, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING) -OPDEF(JSOP_CALLNAME, 57, "callname", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET) +OPDEF(JSOP_CALLNAME, 57, "callname", NULL, 5, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET) OPDEF(JSOP_CALL, 58, "call", NULL, 3, -1, 1, 18, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) -OPDEF(JSOP_NAME, 59, "name", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET) -OPDEF(JSOP_DOUBLE, 60, "double", NULL, 3, 0, 1, 16, JOF_ATOM) -OPDEF(JSOP_STRING, 61, "string", NULL, 3, 0, 1, 19, JOF_ATOM) +OPDEF(JSOP_NAME, 59, "name", NULL, 5, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET) +OPDEF(JSOP_DOUBLE, 60, "double", NULL, 5, 0, 1, 16, JOF_DOUBLE) +OPDEF(JSOP_STRING, 61, "string", NULL, 5, 0, 1, 19, JOF_ATOM) OPDEF(JSOP_ZERO, 62, "zero", "0", 1, 0, 1, 16, JOF_BYTE) OPDEF(JSOP_ONE, 63, "one", "1", 1, 0, 1, 16, JOF_BYTE) OPDEF(JSOP_NULL, 64, js_null_str, js_null_str, 1, 0, 1, 19, JOF_BYTE) @@ -255,7 +255,7 @@ OPDEF(JSOP_NEWINIT, 89, "newinit", NULL, 5, 0, 1, 19, JOF_UINT8| OPDEF(JSOP_NEWARRAY, 90, "newarray", NULL, 4, 0, 1, 19, JOF_UINT24|JOF_TYPESET) OPDEF(JSOP_NEWOBJECT, 91, "newobject", NULL, 5, 0, 1, 19, JOF_OBJECT|JOF_TYPESET) OPDEF(JSOP_ENDINIT, 92, "endinit", NULL, 1, 0, 0, 19, JOF_BYTE) -OPDEF(JSOP_INITPROP, 93, "initprop", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_INITPROP, 93, "initprop", NULL, 5, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) OPDEF(JSOP_INITELEM, 94, "initelem", NULL, 1, 3, 1, 3, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) OPDEF(JSOP_UNUSED14, 95, "unused14", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_UNUSED15, 96, "unused15", NULL, 1, 0, 0, 0, JOF_BYTE) @@ -285,8 +285,8 @@ OPDEF(JSOP_FUNCALL, 108,"funcall", NULL, 3, -1, 1, 18, JOF_UINT16 OPDEF(JSOP_LOOPHEAD, 109,"loophead", NULL, 1, 0, 0, 0, JOF_BYTE) /* ECMA-compliant assignment ops. */ -OPDEF(JSOP_BINDNAME, 110,"bindname", NULL, 3, 0, 1, 0, JOF_ATOM|JOF_NAME|JOF_SET) -OPDEF(JSOP_SETNAME, 111,"setname", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_BINDNAME, 110,"bindname", NULL, 5, 0, 1, 0, JOF_ATOM|JOF_NAME|JOF_SET) +OPDEF(JSOP_SETNAME, 111,"setname", NULL, 5, 2, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING) /* Exception handling ops. */ OPDEF(JSOP_THROW, 112,js_throw_str, NULL, 1, 1, 0, 0, JOF_BYTE) @@ -339,8 +339,8 @@ OPDEF(JSOP_SETTER, 126,js_setter_str,NULL, 1, 0, 0, 0, JOF_BYTE) * Prolog bytecodes for defining function, var, and const names. */ OPDEF(JSOP_DEFFUN, 127,"deffun", NULL, 5, 0, 0, 0, JOF_OBJECT|JOF_DECLARING) -OPDEF(JSOP_DEFCONST, 128,"defconst", NULL, 3, 0, 0, 0, JOF_ATOM|JOF_DECLARING) -OPDEF(JSOP_DEFVAR, 129,"defvar", NULL, 3, 0, 0, 0, JOF_ATOM|JOF_DECLARING) +OPDEF(JSOP_DEFCONST, 128,"defconst", NULL, 5, 0, 0, 0, JOF_ATOM|JOF_DECLARING) +OPDEF(JSOP_DEFVAR, 129,"defvar", NULL, 5, 0, 0, 0, JOF_ATOM|JOF_DECLARING) /* Push a closure for a named or anonymous function expression. */ OPDEF(JSOP_LAMBDA, 130, "lambda", NULL, 5, 0, 1, 19, JOF_OBJECT) @@ -403,12 +403,12 @@ OPDEF(JSOP_SETRVAL, 152,"setrval", NULL, 1, 1, 0, 2, JOF_BYTE) OPDEF(JSOP_RETRVAL, 153,"retrval", NULL, 1, 0, 0, 0, JOF_BYTE) /* Free variable references that must either be found on the global or a ReferenceError */ -OPDEF(JSOP_GETGNAME, 154,"getgname", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME) -OPDEF(JSOP_SETGNAME, 155,"setgname", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME) -OPDEF(JSOP_INCGNAME, 156,"incgname", NULL, 4, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE) -OPDEF(JSOP_DECGNAME, 157,"decgname", NULL, 4, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE) -OPDEF(JSOP_GNAMEINC, 158,"gnameinc", NULL, 4, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE) -OPDEF(JSOP_GNAMEDEC, 159,"gnamedec", NULL, 4, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE) +OPDEF(JSOP_GETGNAME, 154,"getgname", NULL, 5, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME) +OPDEF(JSOP_SETGNAME, 155,"setgname", NULL, 5, 2, 1, 3, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME) +OPDEF(JSOP_INCGNAME, 156,"incgname", NULL, 6, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE) +OPDEF(JSOP_DECGNAME, 157,"decgname", NULL, 6, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE) +OPDEF(JSOP_GNAMEINC, 158,"gnameinc", NULL, 6, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE) +OPDEF(JSOP_GNAMEDEC, 159,"gnamedec", NULL, 6, 0, 1, 15, JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE) /* Regular expression literal requiring special "fork on exec" handling. */ OPDEF(JSOP_REGEXP, 160,"regexp", NULL, 5, 0, 1, 19, JOF_REGEXP) @@ -416,8 +416,8 @@ OPDEF(JSOP_REGEXP, 160,"regexp", NULL, 5, 0, 1, 19, JOF_REGEXP /* XML (ECMA-357, a.k.a. "E4X") support. */ OPDEF(JSOP_DEFXMLNS, 161,"defxmlns", NULL, 1, 1, 0, 0, JOF_BYTE) OPDEF(JSOP_ANYNAME, 162,"anyname", NULL, 1, 0, 1, 19, JOF_BYTE|JOF_XMLNAME) -OPDEF(JSOP_QNAMEPART, 163,"qnamepart", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_XMLNAME) -OPDEF(JSOP_QNAMECONST, 164,"qnameconst", NULL, 3, 1, 1, 19, JOF_ATOM|JOF_XMLNAME) +OPDEF(JSOP_QNAMEPART, 163,"qnamepart", NULL, 5, 0, 1, 19, JOF_ATOM|JOF_XMLNAME) +OPDEF(JSOP_QNAMECONST, 164,"qnameconst", NULL, 5, 1, 1, 19, JOF_ATOM|JOF_XMLNAME) OPDEF(JSOP_QNAME, 165,"qname", NULL, 1, 2, 1, 0, JOF_BYTE|JOF_XMLNAME) OPDEF(JSOP_TOATTRNAME, 166,"toattrname", NULL, 1, 1, 1, 19, JOF_BYTE|JOF_XMLNAME) OPDEF(JSOP_TOATTRVAL, 167,"toattrval", NULL, 1, 1, 1, 19, JOF_BYTE) @@ -433,12 +433,12 @@ OPDEF(JSOP_TOXML, 176,"toxml", NULL, 1, 1, 1, 19, JOF_BYTE) OPDEF(JSOP_TOXMLLIST, 177,"toxmllist", NULL, 1, 1, 1, 19, JOF_BYTE) OPDEF(JSOP_XMLTAGEXPR, 178,"xmltagexpr", NULL, 1, 1, 1, 0, JOF_BYTE) OPDEF(JSOP_XMLELTEXPR, 179,"xmleltexpr", NULL, 1, 1, 1, 0, JOF_BYTE) -OPDEF(JSOP_XMLCDATA, 180,"xmlcdata", NULL, 3, 0, 1, 19, JOF_ATOM) -OPDEF(JSOP_XMLCOMMENT, 181,"xmlcomment", NULL, 3, 0, 1, 19, JOF_ATOM) -OPDEF(JSOP_XMLPI, 182,"xmlpi", NULL, 3, 1, 1, 19, JOF_ATOM) +OPDEF(JSOP_XMLCDATA, 180,"xmlcdata", NULL, 5, 0, 1, 19, JOF_ATOM) +OPDEF(JSOP_XMLCOMMENT, 181,"xmlcomment", NULL, 5, 0, 1, 19, JOF_ATOM) +OPDEF(JSOP_XMLPI, 182,"xmlpi", NULL, 5, 1, 1, 19, JOF_ATOM) OPDEF(JSOP_DELDESC, 183,"deldesc", NULL, 1, 2, 1, 15, JOF_BYTE|JOF_ELEM|JOF_DEL) -OPDEF(JSOP_CALLPROP, 184,"callprop", NULL, 3, 1, 1, 18, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_TMPSLOT3) +OPDEF(JSOP_CALLPROP, 184,"callprop", NULL, 5, 1, 1, 18, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_TMPSLOT3) /* Enter a let block/expr whose slots are at the top of the stack. */ OPDEF(JSOP_ENTERLET0, 185,"enterlet0", NULL, 5, -1, -1, 0, JOF_OBJECT) @@ -451,15 +451,9 @@ OPDEF(JSOP_ENTERLET1, 186,"enterlet1", NULL, 5, -1, -1, 0, JOF_OBJECT */ OPDEF(JSOP_UINT24, 187,"uint24", NULL, 4, 0, 1, 16, JOF_UINT24) -/* - * Opcodes to allow 24-bit atom or object indexes. Whenever an index exceeds - * the 16-bit limit, the index-accessing bytecode must be bracketed by - * JSOP_INDEXBASE and JSOP_RESETBASE to provide the upper bits of the index. - * See jsemit.c, EmitIndexOp. - */ -OPDEF(JSOP_INDEXBASE, 188,"indexbase", NULL, 2, 0, 0, 0, JOF_UINT8|JOF_INDEXBASE) -OPDEF(JSOP_RESETBASE, 189,"resetbase", NULL, 1, 0, 0, 0, JOF_BYTE) -OPDEF(JSOP_RESETBASE0, 190,"resetbase0", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED18, 188,"unused18", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED19, 189,"unused19", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED20, 190,"unused20", NULL, 1, 0, 0, 0, JOF_BYTE) /* * Opcodes to help the decompiler deal with XML. @@ -479,7 +473,7 @@ OPDEF(JSOP_STOP, 194,"stop", NULL, 1, 0, 0, 0, JOF_BYTE) * Get an extant property value, throwing ReferenceError if the identified * property does not exist. */ -OPDEF(JSOP_GETXPROP, 195,"getxprop", NULL, 3, 1, 1, 18, JOF_ATOM|JOF_PROP|JOF_TYPESET) +OPDEF(JSOP_GETXPROP, 195,"getxprop", NULL, 5, 1, 1, 18, JOF_ATOM|JOF_PROP|JOF_TYPESET) OPDEF(JSOP_CALLXMLNAME, 196, "callxmlname", NULL, 1, 1, 2, 19, JOF_BYTE) @@ -520,19 +514,15 @@ OPDEF(JSOP_ENUMCONSTELEM, 206,"enumconstelem",NULL, 1, 3, 0, 3, JOF_BYTE|J * which must be moved down when the block pops. */ OPDEF(JSOP_LEAVEBLOCKEXPR,207,"leaveblockexpr",NULL, 3, -1, 1, 3, JOF_UINT16) -\ -/* - * Optimize atom segments 1-3. These must be followed by JSOP_RESETBASE0 after - * the opcode that they prefix. - */ -OPDEF(JSOP_INDEXBASE1, 208,"indexbase1", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE) -OPDEF(JSOP_INDEXBASE2, 209,"indexbase2", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE) -OPDEF(JSOP_INDEXBASE3, 210,"indexbase3", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE) -OPDEF(JSOP_CALLGNAME, 211, "callgname", NULL, 3, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME) +OPDEF(JSOP_UNUSED21, 208, "unused21", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED22, 209, "unused22", NULL, 1, 0, 0, 0, JOF_BYTE) +OPDEF(JSOP_UNUSED23, 210, "unused23", NULL, 1, 0, 0, 0, JOF_BYTE) + +OPDEF(JSOP_CALLGNAME, 211, "callgname", NULL, 5, 0, 1, 19, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME) OPDEF(JSOP_CALLLOCAL, 212, "calllocal", NULL, 3, 0, 1, 19, JOF_LOCAL|JOF_NAME) OPDEF(JSOP_CALLARG, 213, "callarg", NULL, 3, 0, 1, 19, JOF_QARG |JOF_NAME) -OPDEF(JSOP_BINDGNAME, 214, "bindgname", NULL, 3, 0, 1, 0, JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME) +OPDEF(JSOP_BINDGNAME, 214, "bindgname", NULL, 5, 0, 1, 0, JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME) /* * Opcodes to hold 8-bit and 32-bit immediate integer operands. @@ -543,7 +533,7 @@ OPDEF(JSOP_INT32, 216, "int32", NULL, 5, 0, 1, 16, JOF_INT32) /* * Get the value of the 'length' property from a stacked object. */ -OPDEF(JSOP_LENGTH, 217, "length", NULL, 3, 1, 1, 18, JOF_ATOM|JOF_PROP|JOF_TYPESET) +OPDEF(JSOP_LENGTH, 217, "length", NULL, 5, 1, 1, 18, JOF_ATOM|JOF_PROP|JOF_TYPESET) /* * Push a JSVAL_HOLE value onto the stack, representing an omitted property in @@ -563,8 +553,8 @@ OPDEF(JSOP_LAMBDA_FC, 221,"lambda_fc", NULL, 5, 0, 1, 19, JOF_OBJECT /* * Joined function object as method optimization support. */ -OPDEF(JSOP_SETMETHOD, 222,"setmethod", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) -OPDEF(JSOP_INITMETHOD, 223,"initmethod", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_SETMETHOD, 222,"setmethod", NULL, 5, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) +OPDEF(JSOP_INITMETHOD, 223,"initmethod", NULL, 5, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) OPDEF(JSOP_UNUSED16, 224,"unused16", NULL, 1, 0, 0, 0, JOF_BYTE) @@ -572,7 +562,7 @@ OPDEF(JSOP_UNUSED16, 224,"unused16", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_TOID, 225, "toid", NULL, 1, 1, 1, 0, JOF_BYTE) /* Push the implicit 'this' value for calls to the associated name. */ -OPDEF(JSOP_IMPLICITTHIS, 226, "implicitthis", "", 3, 0, 1, 0, JOF_ATOM) +OPDEF(JSOP_IMPLICITTHIS, 226, "implicitthis", "", 5, 0, 1, 0, JOF_ATOM) /* This opcode is the target of the entry jump for some loop. */ OPDEF(JSOP_LOOPENTRY, 227, "loopentry", NULL, 1, 0, 0, 0, JOF_BYTE) diff --git a/js/src/jsprf.cpp b/js/src/jsprf.cpp index 5a058dccc18..48f4985ce60 100644 --- a/js/src/jsprf.cpp +++ b/js/src/jsprf.cpp @@ -580,7 +580,7 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, nas[ cn ].type = TYPE_UINT32; } else if (sizeof(void *) == sizeof(int64_t)) { nas[ cn ].type = TYPE_UINT64; - } else if (sizeof(void *) == sizeof(JSIntn)) { + } else if (sizeof(void *) == sizeof(int)) { nas[ cn ].type = TYPE_UINTN; } else { nas[ cn ].type = TYPE_UNKNOWN; @@ -642,7 +642,7 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, case TYPE_INT16: case TYPE_UINT16: case TYPE_INTN: - case TYPE_UINTN: (void)va_arg( ap, JSIntn ); break; + case TYPE_UINTN: (void)va_arg( ap, int ); break; case TYPE_INT32: (void)va_arg( ap, int32_t ); break; @@ -656,7 +656,7 @@ static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, case TYPE_WSTRING: (void)va_arg( ap, jschar* ); break; - case TYPE_INTSTR: (void)va_arg( ap, JSIntn* ); break; + case TYPE_INTSTR: (void)va_arg( ap, int* ); break; case TYPE_DOUBLE: (void)va_arg( ap, double ); break; diff --git a/js/src/jsprf.h b/js/src/jsprf.h index 6c3b168742a..9efbd641317 100644 --- a/js/src/jsprf.h +++ b/js/src/jsprf.h @@ -98,7 +98,7 @@ extern JS_PUBLIC_API(char*) JS_sprintf_append(char *last, const char *fmt, ...); ** data. The return value is a count of the number of characters fed to ** the stuff function, or (uint32_t)-1 if an error occurs. */ -typedef JSIntn (*JSStuffFunc)(void *arg, const char *s, uint32_t slen); +typedef int (*JSStuffFunc)(void *arg, const char *s, uint32_t slen); extern JS_PUBLIC_API(uint32_t) JS_sxprintf(JSStuffFunc f, void *arg, const char *fmt, ...); diff --git a/js/src/jspropertycacheinlines.h b/js/src/jspropertycacheinlines.h index 6d757292f66..e425ccda35e 100644 --- a/js/src/jspropertycacheinlines.h +++ b/js/src/jspropertycacheinlines.h @@ -46,8 +46,6 @@ #include "jspropertycache.h" #include "jsscope.h" -using namespace js; - /* * This method is designed to inline the fast path in js_Interpret, so it makes * "just-so" restrictions on parameters, e.g. pobj and obj should not be the @@ -64,8 +62,8 @@ using namespace js; * caches (on all threads) by re-generating JSObject::shape(). */ JS_ALWAYS_INLINE void -PropertyCache::test(JSContext *cx, jsbytecode *pc, JSObject *&obj, - JSObject *&pobj, PropertyCacheEntry *&entry, PropertyName *&name) +js::PropertyCache::test(JSContext *cx, jsbytecode *pc, JSObject *&obj, + JSObject *&pobj, PropertyCacheEntry *&entry, PropertyName *&name) { JS_ASSERT(this == &JS_PROPERTY_CACHE(cx)); @@ -95,8 +93,8 @@ PropertyCache::test(JSContext *cx, jsbytecode *pc, JSObject *&obj, } JS_ALWAYS_INLINE bool -PropertyCache::testForSet(JSContext *cx, jsbytecode *pc, JSObject *obj, - PropertyCacheEntry **entryp, JSObject **obj2p, PropertyName **namep) +js::PropertyCache::testForSet(JSContext *cx, jsbytecode *pc, JSObject *obj, + PropertyCacheEntry **entryp, JSObject **obj2p, PropertyName **namep) { JS_ASSERT(this == &JS_PROPERTY_CACHE(cx)); diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index be3721bf30b..bf6a9509c9f 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -97,7 +97,6 @@ JS_BEGIN_EXTERN_C /* Scalar typedefs. */ typedef int32_t jsint; typedef uint32_t jsuint; -typedef double jsdouble; typedef int32_t jsrefcount; /* PRInt32 if JS_THREADSAFE, see jslock.h */ #ifdef WIN32 diff --git a/js/src/jsscope.h b/js/src/jsscope.h index 6d608ae810e..2111f233af9 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -461,9 +461,10 @@ struct Shape : public js::gc::Cell { friend struct ::JSObject; friend struct ::JSFunction; - friend class js::StaticBlockObject; - friend class js::PropertyTree; friend class js::Bindings; + friend class js::ObjectImpl; + friend class js::PropertyTree; + friend class js::StaticBlockObject; friend struct js::StackShape; friend struct js::StackBaseShape; @@ -1113,30 +1114,6 @@ Shape::search(JSContext *cx, Shape *start, jsid id, Shape ***pspp, bool adding) #pragma warning(pop) #endif -inline js::Class * -JSObject::getClass() const -{ - return lastProperty()->getObjectClass(); -} - -inline JSClass * -JSObject::getJSClass() const -{ - return Jsvalify(getClass()); -} - -inline bool -JSObject::hasClass(const js::Class *c) const -{ - return getClass() == c; -} - -inline const js::ObjectOps * -JSObject::getOps() const -{ - return &getClass()->ops; -} - namespace JS { template<> class AnchorPermitted { }; template<> class AnchorPermitted { }; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 8e425c43932..d4d890233db 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1065,7 +1065,7 @@ JSScript::NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t * We assume that calloc aligns on sizeof(Value) if the size we ask to * allocate divides sizeof(Value). */ - JS_STATIC_ASSERT(sizeof(Value) == sizeof(jsdouble)); + JS_STATIC_ASSERT(sizeof(Value) == sizeof(double)); data = static_cast(cx->calloc_(JS_ROUNDUP(size, sizeof(Value)))); if (!data) return NULL; @@ -1581,9 +1581,6 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) * Special case: function definition needs no line number note because * the function's script contains its starting line number. */ - JSOp op = JSOp(*pc); - if (js_CodeSpec[op].format & JOF_INDEXBASE) - pc += js_CodeSpec[op].length; if (*pc == JSOP_DEFFUN) return script->getFunction(GET_UINT32_INDEX(pc))->script()->lineno; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 2367fb298d6..f31d3a09c6f 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1178,7 +1178,7 @@ str_indexOf(JSContext *cx, uintN argc, Value *vp) textlen -= start; } } else { - jsdouble d; + double d; if (!ToInteger(cx, args[1], &d)) return false; if (d <= 0) { @@ -2556,7 +2556,7 @@ js::str_split(JSContext *cx, uintN argc, Value *vp) /* Step 5: Use the second argument as the split limit, if given. */ uint32_t limit; if (args.length() > 1 && !args[1].isUndefined()) { - jsdouble d; + double d; if (!ToNumber(cx, args[1], &d)) return false; limit = js_DoubleToECMAUint32(d); diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 701bf129557..62d3cd03d77 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -93,12 +93,12 @@ ValueIsLength(JSContext *cx, const Value &v, jsuint *len) } if (v.isDouble()) { - jsdouble d = v.toDouble(); + double d = v.toDouble(); if (JSDOUBLE_IS_NaN(d)) return false; jsuint length = jsuint(d); - if (d != jsdouble(length)) + if (d != double(length)) return false; *len = length; @@ -951,7 +951,7 @@ js_TypedArray_uint8_clamp_double(const double x) if (x > 255) return 255; - jsdouble toTruncate = x + 0.5; + double toTruncate = x + 0.5; uint8_t y = uint8_t(toTruncate); /* @@ -987,7 +987,7 @@ struct uint8_clamped { uint8_clamped(int8_t x) { *this = x; } uint8_clamped(int16_t x) { *this = x; } uint8_clamped(int32_t x) { *this = x; } - uint8_clamped(jsdouble x) { *this = x; } + uint8_clamped(double x) { *this = x; } inline uint8_clamped& operator= (const uint8_clamped& x) { val = x.val; @@ -1032,7 +1032,7 @@ struct uint8_clamped { return *this; } - inline uint8_clamped& operator= (const jsdouble x) { + inline uint8_clamped& operator= (const double x) { val = uint8_t(js_TypedArray_uint8_clamp_double(x)); return *this; } @@ -1209,7 +1209,7 @@ class TypedArrayTemplate return true; } - jsdouble d; + double d; if (vp->isDouble()) { d = vp->toDouble(); } else if (vp->isNull()) { @@ -1811,7 +1811,7 @@ class TypedArrayTemplate * are treated identically. */ if (v.isPrimitive() && !v.isMagic() && !v.isUndefined()) { - jsdouble dval; + double dval; JS_ALWAYS_TRUE(ToNumber(cx, v, &dval)); return nativeFromDouble(dval); } diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 68e9c8d1790..b9aaa0ff945 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -219,19 +219,6 @@ JS_BEGIN_EXTERN_C -/************************************************************************ -** TYPES: JSUintn -** JSIntn -** DESCRIPTION: -** The JSIntn types are most appropriate for automatic variables. They are -** guaranteed to be at least 16 bits, though various architectures may -** define them to be wider (e.g., 32 or even 64 bits). These types are -** never valid for fields of a structure. -************************************************************************/ - -typedef int JSIntn; -typedef unsigned int JSUintn; - /************************************************************************ ** TYPES: JSBool ** DESCRIPTION: @@ -240,9 +227,9 @@ typedef unsigned int JSUintn; ** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans ** just as you would C int-valued conditions. ************************************************************************/ -typedef JSIntn JSBool; -#define JS_TRUE (JSIntn)1 -#define JS_FALSE (JSIntn)0 +typedef int JSBool; +#define JS_TRUE (int)1 +#define JS_FALSE (int)0 /************************************************************************ ** TYPES: JSPackedBool diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp index 5968e70e71c..db0b72c2441 100644 --- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -69,13 +69,42 @@ JS_PUBLIC_DATA(uint32_t) OOM_counter = 0; */ JS_STATIC_ASSERT(sizeof(void *) == sizeof(void (*)())); -/* - * |JS_Assert| historically took |JSIntn ln| as its last argument. We've - * boiled |JSIntn ln| down to simply |int ln| so that mfbt may declare the - * function without depending on the |JSIntn| typedef, so we must manually - * verify that the |JSIntn| typedef is consistent. - */ -JS_STATIC_ASSERT((tl::IsSameType::result)); +static JS_NEVER_INLINE void +CrashInJS() +{ + /* + * We write 123 here so that the machine code for this function is + * unique. Otherwise the linker, trying to be smart, might use the + * same code for CrashInJS and for some other function. That + * messes up the signature in minidumps. + */ + +#if defined(WIN32) + /* + * We used to call DebugBreak() on Windows, but amazingly, it causes + * the MSVS 2010 debugger not to be able to recover a call stack. + */ + *((volatile int *) NULL) = 123; + exit(3); +#elif defined(__APPLE__) + /* + * On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are + * trapped. + */ + *((volatile int *) NULL) = 123; /* To continue from here in GDB: "return" then "continue". */ + raise(SIGABRT); /* In case above statement gets nixed by the optimizer. */ +#else + raise(SIGABRT); /* To continue from here in GDB: "signal 0". */ +#endif +} + +JS_PUBLIC_API(void) +JS_Assert(const char *s, const char *file, int ln) +{ + fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln); + fflush(stderr); + CrashInJS(); +} #ifdef JS_BASIC_STATS diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index 963bb08fae9..15b153ab516 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -318,7 +318,7 @@ WeakMap_finalize(JSContext *cx, JSObject *obj) map->check(); #ifdef DEBUG map->~ObjectValueMap(); - memset(map, 0xdc, sizeof(ObjectValueMap)); + memset(static_cast(map), 0xdc, sizeof(*map)); cx->free_(map); #else cx->delete_(map); diff --git a/js/src/jsxdrapi.cpp b/js/src/jsxdrapi.cpp index 7eeaa9f5e9f..cfddb60323e 100644 --- a/js/src/jsxdrapi.cpp +++ b/js/src/jsxdrapi.cpp @@ -473,7 +473,7 @@ JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp) } JS_PUBLIC_API(JSBool) -JS_XDRDouble(JSXDRState *xdr, jsdouble *dp) +JS_XDRDouble(JSXDRState *xdr, double *dp) { jsdpun u; diff --git a/js/src/jsxdrapi.h b/js/src/jsxdrapi.h index 514429b06a6..678d58ecd37 100644 --- a/js/src/jsxdrapi.h +++ b/js/src/jsxdrapi.h @@ -158,7 +158,7 @@ extern JS_PUBLIC_API(JSBool) JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp); extern JS_PUBLIC_API(JSBool) -JS_XDRDouble(JSXDRState *xdr, jsdouble *dp); +JS_XDRDouble(JSXDRState *xdr, double *dp); extern JS_PUBLIC_API(JSBool) JS_XDRFunctionObject(JSXDRState *xdr, JSObject **objp); @@ -192,7 +192,7 @@ JS_XDRScript(JSXDRState *xdr, JSScript **scriptp); * and saved versions. If deserialization fails, the data should be * invalidated if possible. */ -#define JSXDR_BYTECODE_VERSION (0xb973c0de - 108) +#define JSXDR_BYTECODE_VERSION (0xb973c0de - 109) JS_END_EXTERN_C diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 19a3e3d8196..29446af7cac 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -5242,7 +5242,7 @@ js_TestXMLEquality(JSContext *cx, const Value &v1, const Value &v2, JSBool *bp) JSObject *vobj; JSBool ok; JSString *str, *vstr; - jsdouble d, d2; + double d, d2; JSObject *obj; jsval v; diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 9525e5862bd..23df1ccf981 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -768,7 +768,7 @@ MakeJITScript(JSContext *cx, JSScript *script, bool construct) return NULL; while (npairs) { - pc2 += INDEX_LEN; + pc2 += UINT32_INDEX_LEN; unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2); CrossChunkEdge edge; edge.source = offset; @@ -2501,7 +2501,7 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_DELNAME) { - uint32_t index = fullAtomIndex(PC); + uint32_t index = GET_UINT32_INDEX(PC); PropertyName *name = script->getName(index); prepareStubCall(Uses(0)); @@ -2513,7 +2513,7 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_DELPROP) { - uint32_t index = fullAtomIndex(PC); + uint32_t index = GET_UINT32_INDEX(PC); PropertyName *name = script->getName(index); prepareStubCall(Uses(1)); @@ -2546,7 +2546,7 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_GETPROP) BEGIN_CASE(JSOP_CALLPROP) BEGIN_CASE(JSOP_LENGTH) - if (!jsop_getprop(script->getName(fullAtomIndex(PC)), knownPushedType(0))) + if (!jsop_getprop(script->getName(GET_UINT32_INDEX(PC)), knownPushedType(0))) return Compile_Error; END_CASE(JSOP_GETPROP) @@ -2623,7 +2623,7 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_NAME) BEGIN_CASE(JSOP_CALLNAME) { - PropertyName *name = script->getName(fullAtomIndex(PC)); + PropertyName *name = script->getName(GET_UINT32_INDEX(PC)); jsop_name(name, knownPushedType(0)); frame.extra(frame.peek(-1)).name = name; } @@ -2632,7 +2632,7 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_IMPLICITTHIS) { prepareStubCall(Uses(0)); - masm.move(ImmPtr(script->getName(fullAtomIndex(PC))), Registers::ArgReg1); + masm.move(ImmPtr(script->getName(GET_UINT32_INDEX(PC))), Registers::ArgReg1); INLINE_STUBCALL(stubs::ImplicitThis, REJOIN_FALLTHROUGH); frame.pushSynced(JSVAL_TYPE_UNKNOWN); } @@ -2640,14 +2640,13 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_DOUBLE) { - uint32_t index = fullAtomIndex(PC); - double d = script->getConst(index).toDouble(); + double d = script->getConst(GET_UINT32_INDEX(PC)).toDouble(); frame.push(Value(DoubleValue(d))); } END_CASE(JSOP_DOUBLE) BEGIN_CASE(JSOP_STRING) - frame.push(StringValue(script->getAtom(fullAtomIndex(PC)))); + frame.push(StringValue(script->getAtom(GET_UINT32_INDEX(PC)))); END_CASE(JSOP_STRING) BEGIN_CASE(JSOP_ZERO) @@ -2935,14 +2934,14 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_LOCALDEC) BEGIN_CASE(JSOP_BINDNAME) - jsop_bindname(script->getName(fullAtomIndex(PC))); + jsop_bindname(script->getName(GET_UINT32_INDEX(PC))); END_CASE(JSOP_BINDNAME) BEGIN_CASE(JSOP_SETPROP) { jsbytecode *next = &PC[JSOP_SETPROP_LENGTH]; bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next); - if (!jsop_setprop(script->getName(fullAtomIndex(PC)), pop)) + if (!jsop_setprop(script->getName(GET_UINT32_INDEX(PC)), pop)) return Compile_Error; } END_CASE(JSOP_SETPROP) @@ -2952,7 +2951,7 @@ mjit::Compiler::generateMethod() { jsbytecode *next = &PC[JSOP_SETNAME_LENGTH]; bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next); - if (!jsop_setprop(script->getName(fullAtomIndex(PC)), pop)) + if (!jsop_setprop(script->getName(GET_UINT32_INDEX(PC)), pop)) return Compile_Error; } END_CASE(JSOP_SETNAME) @@ -3030,8 +3029,7 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_DEFVAR) BEGIN_CASE(JSOP_DEFCONST) { - uint32_t index = fullAtomIndex(PC); - PropertyName *name = script->getName(index); + PropertyName *name = script->getName(GET_UINT32_INDEX(PC)); prepareStubCall(Uses(0)); masm.move(ImmPtr(name), Registers::ArgReg1); @@ -3041,8 +3039,7 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_SETCONST) { - uint32_t index = fullAtomIndex(PC); - PropertyName *name = script->getName(index); + PropertyName *name = script->getName(GET_UINT32_INDEX(PC)); prepareStubCall(Uses(1)); masm.move(ImmPtr(name), Registers::ArgReg1); @@ -3153,7 +3150,7 @@ mjit::Compiler::generateMethod() BEGIN_CASE(JSOP_GETGNAME) BEGIN_CASE(JSOP_CALLGNAME) { - uint32_t index = fullAtomIndex(PC); + uint32_t index = GET_UINT32_INDEX(PC); jsop_getgname(index); frame.extra(frame.peek(-1)).name = script->getName(index); } @@ -3163,7 +3160,7 @@ mjit::Compiler::generateMethod() { jsbytecode *next = &PC[JSOP_SETGNAME_LENGTH]; bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next); - jsop_setgname(script->getName(fullAtomIndex(PC)), pop); + jsop_setgname(script->getName(GET_UINT32_INDEX(PC)), pop); } END_CASE(JSOP_SETGNAME) @@ -3193,7 +3190,7 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_STOP) BEGIN_CASE(JSOP_GETXPROP) - if (!jsop_xname(script->getName(fullAtomIndex(PC)))) + if (!jsop_xname(script->getName(GET_UINT32_INDEX(PC)))) return Compile_Error; END_CASE(JSOP_GETXPROP) @@ -3582,17 +3579,6 @@ mjit::Compiler::labelOf(jsbytecode *pc, uint32_t inlineIndex) return a->jumpMap[offs]; } -uint32_t -mjit::Compiler::fullAtomIndex(jsbytecode *pc) -{ - return GET_SLOTNO(pc); - - /* If we ever enable INDEXBASE garbage, use this below. */ -#if 0 - return GET_SLOTNO(pc) + (atoms - script->atoms); -#endif -} - bool mjit::Compiler::knownJump(jsbytecode *pc) { diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h index 951caf39328..70c1667d648 100644 --- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -606,7 +606,6 @@ private: /* Non-emitting helpers. */ void pushSyncedEntry(uint32_t pushed); - uint32_t fullAtomIndex(jsbytecode *pc); bool jumpInScript(Jump j, jsbytecode *pc); bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs); bool canUseApplyTricks(); diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp index 011507b07fe..c182d8884a8 100644 --- a/js/src/methodjit/FastOps.cpp +++ b/js/src/methodjit/FastOps.cpp @@ -748,7 +748,7 @@ mjit::Compiler::jsop_typeof() JSOp op = JSOp(PC[JSOP_TYPEOF_LENGTH + JSOP_STRING_LENGTH]); if (op == JSOP_STRICTEQ || op == JSOP_EQ || op == JSOP_STRICTNE || op == JSOP_NE) { - JSAtom *atom = script->getAtom(fullAtomIndex(PC + JSOP_TYPEOF_LENGTH)); + JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC + JSOP_TYPEOF_LENGTH)); JSRuntime *rt = cx->runtime; JSValueType type = JSVAL_TYPE_UNKNOWN; Assembler::Condition cond = (op == JSOP_STRICTEQ || op == JSOP_EQ) @@ -2664,7 +2664,7 @@ mjit::Compiler::jsop_initmethod() #ifdef DEBUG FrameEntry *obj = frame.peek(-2); #endif - JSAtom *atom = script->getAtom(fullAtomIndex(PC)); + JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC)); /* Initializers with INITMETHOD are not fast yet. */ JS_ASSERT(!frame.extra(obj).initObject); @@ -2679,7 +2679,7 @@ mjit::Compiler::jsop_initprop() { FrameEntry *obj = frame.peek(-2); FrameEntry *fe = frame.peek(-1); - JSAtom *atom = script->getAtom(fullAtomIndex(PC)); + JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC)); JSObject *baseobj = frame.extra(obj).initObject; diff --git a/js/src/methodjit/InvokeHelpers.cpp b/js/src/methodjit/InvokeHelpers.cpp index f6f4c95f605..990c5931dcf 100644 --- a/js/src/methodjit/InvokeHelpers.cpp +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -735,6 +735,10 @@ FinishVarIncOp(VMFrame &f, RejoinState rejoin, Value ov, Value nv, Value *vp) JSContext *cx = f.cx; JSOp op = JSOp(*f.pc()); + JS_ASSERT(op == JSOP_LOCALINC || op == JSOP_INCLOCAL || + op == JSOP_LOCALDEC || op == JSOP_DECLOCAL || + op == JSOP_ARGINC || op == JSOP_INCARG || + op == JSOP_ARGDEC || op == JSOP_DECARG); const JSCodeSpec *cs = &js_CodeSpec[op]; unsigned i = GET_SLOTNO(f.pc()); diff --git a/js/src/methodjit/LoopState.cpp b/js/src/methodjit/LoopState.cpp index 3e74ca4fbc6..7f78c6bc2b4 100644 --- a/js/src/methodjit/LoopState.cpp +++ b/js/src/methodjit/LoopState.cpp @@ -1869,7 +1869,7 @@ LoopState::analyzeLoopBody(unsigned frame) case JSOP_SETPROP: case JSOP_SETMETHOD: { - JSAtom *atom = script->getAtom(js_GetIndexFromBytecode(script, pc, 0)); + JSAtom *atom = script->getAtom(GET_UINT32_INDEX(pc)); jsid id = MakeTypeId(cx, ATOM_TO_JSID(atom)); TypeSet *objTypes = analysis->poppedTypes(pc, 1); @@ -2181,7 +2181,7 @@ LoopState::getEntryValue(const CrossSSAValue &iv, uint32_t *pslot, int32_t *pcon } case JSOP_GETPROP: { - JSAtom *atom = script->getAtom(js_GetIndexFromBytecode(script, pc, 0)); + JSAtom *atom = script->getAtom(GET_UINT32_INDEX(pc)); jsid id = ATOM_TO_JSID(atom); CrossSSAValue objcv(cv.frame, analysis->poppedValue(v.pushedOffset(), 0)); FrameEntry *tmp = invariantProperty(objcv, id); diff --git a/js/src/methodjit/MonoIC.cpp b/js/src/methodjit/MonoIC.cpp index 70ff14fc60e..c5b4752a56e 100644 --- a/js/src/methodjit/MonoIC.cpp +++ b/js/src/methodjit/MonoIC.cpp @@ -87,7 +87,7 @@ void JS_FASTCALL ic::GetGlobalName(VMFrame &f, ic::GetGlobalNameIC *ic) { JSObject &obj = f.fp()->scopeChain().global(); - PropertyName *name = f.script()->getName(GET_INDEX(f.pc())); + PropertyName *name = f.script()->getName(GET_UINT32_INDEX(f.pc())); RecompilationMonitor monitor(f.cx); @@ -126,7 +126,7 @@ template static void JS_FASTCALL DisabledSetGlobal(VMFrame &f, ic::SetGlobalNameIC *ic) { - stubs::SetGlobalName(f, f.script()->getName(GET_INDEX(f.pc()))); + stubs::SetGlobalName(f, f.script()->getName(GET_UINT32_INDEX(f.pc()))); } template void JS_FASTCALL DisabledSetGlobal(VMFrame &f, ic::SetGlobalNameIC *ic); @@ -193,7 +193,7 @@ ic::SetGlobalName(VMFrame &f, ic::SetGlobalNameIC *ic) { JSObject &obj = f.fp()->scopeChain().global(); JSScript *script = f.script(); - PropertyName *name = script->getName(GET_INDEX(f.pc())); + PropertyName *name = script->getName(GET_UINT32_INDEX(f.pc())); RecompilationMonitor monitor(f.cx); diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index 7f5ed1c483c..784c80b327e 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -1115,7 +1115,7 @@ stubs::LambdaJoinableForInit(VMFrame &f, JSFunction *fun) { JS_ASSERT(fun->joinable()); DebugOnly nextpc = f.regs.pc + JSOP_LAMBDA_LENGTH; - JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_SLOTNO(nextpc))); + JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_UINT32_INDEX(nextpc))); return fun; } @@ -1126,7 +1126,7 @@ stubs::LambdaJoinableForSet(VMFrame &f, JSFunction *fun) const Value &lref = f.regs.sp[-1]; if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) { DebugOnly nextpc = f.regs.pc + JSOP_LAMBDA_LENGTH; - JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_SLOTNO(nextpc))); + JS_ASSERT(fun->methodAtom() == f.script()->getAtom(GET_UINT32_INDEX(nextpc))); return fun; } return Lambda(f, fun); @@ -1518,8 +1518,8 @@ stubs::LookupSwitch(VMFrame &f, jsbytecode *pc) if (!str) THROWV(NULL); for (uint32_t i = 1; i <= npairs; i++) { - Value rval = script->getConst(GET_INDEX(pc)); - pc += INDEX_LEN; + Value rval = script->getConst(GET_UINT32_INDEX(pc)); + pc += UINT32_INDEX_LEN; if (rval.isString()) { JSLinearString *rhs = &rval.toString()->asLinear(); if (rhs == str || EqualStrings(str, rhs)) @@ -1530,16 +1530,16 @@ stubs::LookupSwitch(VMFrame &f, jsbytecode *pc) } else if (lval.isNumber()) { double d = lval.toNumber(); for (uint32_t i = 1; i <= npairs; i++) { - Value rval = script->getConst(GET_INDEX(pc)); - pc += INDEX_LEN; + Value rval = script->getConst(GET_UINT32_INDEX(pc)); + pc += UINT32_INDEX_LEN; if (rval.isNumber() && d == rval.toNumber()) return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc)); pc += JUMP_OFFSET_LEN; } } else { for (uint32_t i = 1; i <= npairs; i++) { - Value rval = script->getConst(GET_INDEX(pc)); - pc += INDEX_LEN; + Value rval = script->getConst(GET_UINT32_INDEX(pc)); + pc += UINT32_INDEX_LEN; if (lval == rval) return FindNativeCode(f, jpc + GET_JUMP_OFFSET(pc)); pc += JUMP_OFFSET_LEN; @@ -1563,7 +1563,7 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc) /* Note: compiler adjusts the stack beforehand. */ Value rval = f.regs.sp[-1]; - jsint tableIdx; + int32_t tableIdx; if (rval.isInt32()) { tableIdx = rval.toInt32(); } else if (rval.isDouble()) { @@ -1571,7 +1571,7 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc) if (d == 0) { /* Treat -0 (double) as 0. */ tableIdx = 0; - } else if (!JSDOUBLE_IS_INT32(d, (int32_t *)&tableIdx)) { + } else if (!JSDOUBLE_IS_INT32(d, &tableIdx)) { goto finally; } } else { diff --git a/js/src/methodjit/TypedArrayIC.h b/js/src/methodjit/TypedArrayIC.h index 132967cb8c0..a852a3fc201 100644 --- a/js/src/methodjit/TypedArrayIC.h +++ b/js/src/methodjit/TypedArrayIC.h @@ -82,10 +82,10 @@ ConstantFoldForFloatArray(JSContext *cx, ValueRemat *vr) if (vr->knownType() == JSVAL_TYPE_DOUBLE) return true; - jsdouble d = 0; + double d = 0; Value v = vr->value(); if (v.isString()) { - if (!StringToNumberType(cx, v.toString(), &d)) + if (!StringToNumberType(cx, v.toString(), &d)) return false; } else if (v.isBoolean()) { d = v.toBoolean() ? 1 : 0; diff --git a/js/src/perf/jsperf.cpp b/js/src/perf/jsperf.cpp index 9982fca5802..80396ec9935 100644 --- a/js/src/perf/jsperf.cpp +++ b/js/src/perf/jsperf.cpp @@ -91,7 +91,7 @@ pm_finalize(JSContext* cx, JSObject* obj) PerfMeasurement* p = GetPM(cx, obj, #name); \ if (!p) \ return JS_FALSE; \ - return JS_NewNumberValue(cx, jsdouble(p->name), vp); \ + return JS_NewNumberValue(cx, double(p->name), vp); \ } GETTER(cpu_cycles) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 087cc7964d3..b24de35466a 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -150,8 +150,8 @@ static uintptr_t gStackBase; * Limit the timeout to 30 minutes to prevent an overflow on platfoms * that represent the time internally in microseconds using 32-bit int. */ -static jsdouble MAX_TIMEOUT_INTERVAL = 1800.0; -static jsdouble gTimeoutInterval = -1.0; +static double MAX_TIMEOUT_INTERVAL = 1800.0; +static double gTimeoutInterval = -1.0; static volatile bool gCanceled = false; static bool enableMethodJit = false; @@ -161,7 +161,7 @@ static bool enableDisassemblyDumps = false; static bool printTiming = false; static JSBool -SetTimeoutValue(JSContext *cx, jsdouble t); +SetTimeoutValue(JSContext *cx, double t); static bool InitWatchdog(JSRuntime *rt); @@ -170,7 +170,7 @@ static void KillWatchdog(); static bool -ScheduleWatchdog(JSRuntime *rt, jsdouble t); +ScheduleWatchdog(JSRuntime *rt, double t); static void CancelExecution(JSRuntime *rt); @@ -683,7 +683,7 @@ Version(JSContext *cx, uintN argc, jsval *vp) if (JSVAL_IS_INT(argv[0])) { v = JSVAL_TO_INT(argv[0]); } else if (JSVAL_IS_DOUBLE(argv[0])) { - jsdouble fv = JSVAL_TO_DOUBLE(argv[0]); + double fv = JSVAL_TO_DOUBLE(argv[0]); if (int32_t(fv) == fv) v = int32_t(fv); } @@ -1113,7 +1113,7 @@ PutStr(JSContext *cx, uintN argc, jsval *vp) static JSBool Now(JSContext *cx, uintN argc, jsval *vp) { - jsdouble now = PRMJ_Now() / double(PRMJ_USEC_PER_MSEC); + double now = PRMJ_Now() / double(PRMJ_USEC_PER_MSEC); JS_SET_RVAL(cx, vp, DOUBLE_TO_JSVAL(now)); return true; } @@ -1289,7 +1289,8 @@ static const struct ParamPair { {"maxMallocBytes", JSGC_MAX_MALLOC_BYTES}, {"gcBytes", JSGC_BYTES}, {"gcNumber", JSGC_NUMBER}, - {"sliceTimeBudget", JSGC_SLICE_TIME_BUDGET} + {"sliceTimeBudget", JSGC_SLICE_TIME_BUDGET}, + {"markStackLimit", JSGC_MARK_STACK_LIMIT} }; static JSBool @@ -1612,7 +1613,7 @@ CountHeap(JSContext *cx, uintN argc, jsval *vp) } JS_DHashTableFinish(&countTracer.visited); - return countTracer.ok && JS_NewNumberValue(cx, (jsdouble) counter, vp); + return countTracer.ok && JS_NewNumberValue(cx, (double) counter, vp); } static jsrefcount finalizeCount = 0; @@ -1924,8 +1925,8 @@ UpdateSwitchTableBounds(JSContext *cx, JSScript *script, uintN offset, case JSOP_LOOKUPSWITCH: jmplen = JUMP_OFFSET_LEN; pc += jmplen; - n = GET_INDEX(pc); - pc += INDEX_LEN; + n = GET_UINT16(pc); + pc += UINT16_LEN; jmplen += JUMP_OFFSET_LEN; break; @@ -2658,7 +2659,7 @@ ZZ_formatter(JSContext *cx, const char *format, JSBool fromJS, jsval **vpp, { jsval *vp; va_list ap; - jsdouble re, im; + double re, im; printf("entering ZZ_formatter"); vp = *vpp; @@ -2668,11 +2669,11 @@ ZZ_formatter(JSContext *cx, const char *format, JSBool fromJS, jsval **vpp, return JS_FALSE; if (!JS_ValueToNumber(cx, vp[1], &im)) return JS_FALSE; - *va_arg(ap, jsdouble *) = re; - *va_arg(ap, jsdouble *) = im; + *va_arg(ap, double *) = re; + *va_arg(ap, double *) = im; } else { - re = va_arg(ap, jsdouble); - im = va_arg(ap, jsdouble); + re = va_arg(ap, double); + im = va_arg(ap, double); if (!JS_NewNumberValue(cx, re, &vp[0])) return JS_FALSE; if (!JS_NewNumberValue(cx, im, &vp[1])) @@ -2691,7 +2692,7 @@ ConvertArgs(JSContext *cx, uintN argc, jsval *vp) jschar c = 0; int32_t i = 0, j = 0; uint32_t u = 0; - jsdouble d = 0, I = 0, re = 0, im = 0; + double d = 0, I = 0, re = 0, im = 0; JSString *str = NULL; jschar *w = NULL; JSObject *obj2 = NULL; @@ -3317,7 +3318,7 @@ Sleep_fn(JSContext *cx, uintN argc, jsval *vp) if (argc == 0) { t_ticks = 0; } else { - jsdouble t_secs; + double t_secs; if (!JS_ValueToNumber(cx, argc == 0 ? JSVAL_VOID : vp[2], &t_secs)) return JS_FALSE; @@ -3425,7 +3426,7 @@ WatchdogMain(void *arg) } static bool -ScheduleWatchdog(JSRuntime *rt, jsdouble t) +ScheduleWatchdog(JSRuntime *rt, double t) { if (t <= 0) { PR_Lock(gWatchdogLock); @@ -3494,7 +3495,7 @@ KillWatchdog() } static bool -ScheduleWatchdog(JSRuntime *rt, jsdouble t) +ScheduleWatchdog(JSRuntime *rt, double t) { #ifdef XP_WIN if (gTimerHandle) { @@ -3551,7 +3552,7 @@ CancelExecution(JSRuntime *rt) } static JSBool -SetTimeoutValue(JSContext *cx, jsdouble t) +SetTimeoutValue(JSContext *cx, double t) { /* NB: The next condition also filter out NaNs. */ if (!(t <= MAX_TIMEOUT_INTERVAL)) { @@ -3577,7 +3578,7 @@ Timeout(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } - jsdouble t; + double t; if (!JS_ValueToNumber(cx, JS_ARGV(cx, vp)[0], &t)) return JS_FALSE; @@ -3911,7 +3912,7 @@ MJitChunkLimit(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } - jsdouble t; + double t; if (!JS_ValueToNumber(cx, JS_ARGV(cx, vp)[0], &t)) return JS_FALSE; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 17503ff5a18..a22ad02424b 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -1967,7 +1967,7 @@ DebuggerScript_getLineCount(JSContext *cx, uintN argc, Value *vp) THIS_DEBUGSCRIPT_SCRIPT(cx, argc, vp, "getLineCount", args, obj, script); uintN maxLine = js_GetScriptLineExtent(script); - args.rval().setNumber(jsdouble(maxLine)); + args.rval().setNumber(double(maxLine)); return true; } @@ -2160,7 +2160,7 @@ class FlowGraphSummary : public Vector { for (jsint i = 0; i < ncases; i++) { if (op == JSOP_LOOKUPSWITCH) - pc += INDEX_LEN; + pc += UINT32_INDEX_LEN; size_t target = offset + GET_JUMP_OFFSET(pc); addEdge(lineno, target); pc += step; @@ -2243,7 +2243,7 @@ DebuggerScript_getLineOffsets(JSContext *cx, uintN argc, Value *vp) size_t lineno; bool ok = false; if (args[0].isNumber()) { - jsdouble d = args[0].toNumber(); + double d = args[0].toNumber(); lineno = size_t(d); ok = (lineno == d); } diff --git a/js/src/vm/NumberObject-inl.h b/js/src/vm/NumberObject-inl.h index 4b611c10d71..73b6b4b0a1c 100644 --- a/js/src/vm/NumberObject-inl.h +++ b/js/src/vm/NumberObject-inl.h @@ -53,7 +53,7 @@ JSObject::asNumber() namespace js { inline NumberObject * -NumberObject::create(JSContext *cx, jsdouble d) +NumberObject::create(JSContext *cx, double d) { JSObject *obj = NewBuiltinClassInstance(cx, &NumberClass); if (!obj) @@ -64,7 +64,7 @@ NumberObject::create(JSContext *cx, jsdouble d) } inline NumberObject * -NumberObject::createWithProto(JSContext *cx, jsdouble d, JSObject &proto) +NumberObject::createWithProto(JSContext *cx, double d, JSObject &proto) { JSObject *obj = NewObjectWithClassProto(cx, &NumberClass, &proto, NULL, gc::GetGCObjectKind(RESERVED_SLOTS)); diff --git a/js/src/vm/NumberObject.h b/js/src/vm/NumberObject.h index c2d4cdb9b1e..0ff8e5cb717 100644 --- a/js/src/vm/NumberObject.h +++ b/js/src/vm/NumberObject.h @@ -59,20 +59,20 @@ class NumberObject : public JSObject * Creates a new Number object boxing the given number. The object's * [[Prototype]] is determined from context. */ - static inline NumberObject *create(JSContext *cx, jsdouble d); + static inline NumberObject *create(JSContext *cx, double d); /* * Identical to create(), but uses |proto| as [[Prototype]]. This method * must not be used to create |Number.prototype|. */ - static inline NumberObject *createWithProto(JSContext *cx, jsdouble d, JSObject &proto); + static inline NumberObject *createWithProto(JSContext *cx, double d, JSObject &proto); double unbox() const { return getFixedSlot(PRIMITIVE_VALUE_SLOT).toNumber(); } private: - inline void setPrimitiveValue(jsdouble d) { + inline void setPrimitiveValue(double d) { setFixedSlot(PRIMITIVE_VALUE_SLOT, NumberValue(d)); } diff --git a/js/src/vm/ObjectImpl-inl.h b/js/src/vm/ObjectImpl-inl.h new file mode 100644 index 00000000000..20d6b4b77fb --- /dev/null +++ b/js/src/vm/ObjectImpl-inl.h @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ObjectImpl_inl_h___ +#define ObjectImpl_inl_h___ + +#include "mozilla/Assertions.h" + +#include "jscell.h" +#include "jscompartment.h" +#include "jsgc.h" +#include "jsgcmark.h" + +#include "js/TemplateLib.h" + +#include "ObjectImpl.h" + +inline bool +js::ObjectImpl::isNative() const +{ + return lastProperty()->isNative(); +} + +inline js::Class * +js::ObjectImpl::getClass() const +{ + return lastProperty()->getObjectClass(); +} + +inline JSClass * +js::ObjectImpl::getJSClass() const +{ + return Jsvalify(getClass()); +} + +inline bool +js::ObjectImpl::hasClass(const Class *c) const +{ + return getClass() == c; +} + +inline const js::ObjectOps * +js::ObjectImpl::getOps() const +{ + return &getClass()->ops; +} + +inline bool +js::ObjectImpl::isDelegate() const +{ + return lastProperty()->hasObjectFlag(BaseShape::DELEGATE); +} + +inline bool +js::ObjectImpl::inDictionaryMode() const +{ + return lastProperty()->inDictionary(); +} + +/* static */ inline size_t +js::ObjectImpl::dynamicSlotsCount(size_t nfixed, size_t span) +{ + if (span <= nfixed) + return 0; + span -= nfixed; + if (span <= SLOT_CAPACITY_MIN) + return SLOT_CAPACITY_MIN; + + size_t slots = RoundUpPow2(span); + MOZ_ASSERT(slots >= span); + return slots; +} + +inline size_t +js::ObjectImpl::sizeOfThis() const +{ + return arenaHeader()->getThingSize(); +} + +/* static */ inline void +js::ObjectImpl::readBarrier(ObjectImpl *obj) +{ +#ifdef JSGC_INCREMENTAL + JSCompartment *comp = obj->compartment(); + if (comp->needsBarrier()) { + MOZ_ASSERT(!comp->rt->gcRunning); + MarkObjectUnbarriered(comp->barrierTracer(), obj->asObjectPtr(), "read barrier"); + } +#endif +} + +inline void +js::ObjectImpl::privateWriteBarrierPre(void **old) +{ +#ifdef JSGC_INCREMENTAL + JSCompartment *comp = compartment(); + if (comp->needsBarrier()) { + if (*old && getClass()->trace) + getClass()->trace(comp->barrierTracer(), this->asObjectPtr()); + } +#endif +} + +inline void +js::ObjectImpl::privateWriteBarrierPost(void **old) +{ +} + +/* static */ inline void +js::ObjectImpl::writeBarrierPre(ObjectImpl *obj) +{ +#ifdef JSGC_INCREMENTAL + /* + * This would normally be a null test, but TypeScript::global uses 0x1 as a + * special value. + */ + if (uintptr_t(obj) < 32) + return; + + JSCompartment *comp = obj->compartment(); + if (comp->needsBarrier()) { + MOZ_ASSERT(!comp->rt->gcRunning); + MarkObjectUnbarriered(comp->barrierTracer(), obj->asObjectPtr(), "write barrier"); + } +#endif +} + +/* static */ inline void +js::ObjectImpl::writeBarrierPost(ObjectImpl *obj, void *addr) +{ +} + +inline bool +js::ObjectImpl::isExtensible() const +{ + return !lastProperty()->hasObjectFlag(BaseShape::NOT_EXTENSIBLE); +} + +#endif /* ObjectImpl_inl_h__ */ diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp new file mode 100644 index 00000000000..812fd9dcbbd --- /dev/null +++ b/js/src/vm/ObjectImpl.cpp @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" + +#include "jsscope.h" + +#include "ObjectImpl.h" + +#include "ObjectImpl-inl.h" + +using namespace js; + +static ObjectElements emptyElementsHeader(0, 0); + +/* Objects with no elements share one empty set of elements. */ +HeapValue *js::emptyObjectElements = + reinterpret_cast(uintptr_t(&emptyElementsHeader) + sizeof(ObjectElements)); + +#if defined(_MSC_VER) && _MSC_VER >= 1500 +/* + * Work around a compiler bug in MSVC9 and above, where inlining this function + * causes stack pointer offsets to go awry and spp to refer to something higher + * up the stack. + */ +MOZ_NEVER_INLINE +#endif +const Shape * +js::ObjectImpl::nativeLookup(JSContext *cx, jsid id) +{ + MOZ_ASSERT(isNative()); + Shape **spp; + return Shape::search(cx, lastProperty(), id, &spp); +} diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h new file mode 100644 index 00000000000..143f3598f8f --- /dev/null +++ b/js/src/vm/ObjectImpl.h @@ -0,0 +1,319 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef ObjectImpl_h___ +#define ObjectImpl_h___ + +#include "mozilla/Assertions.h" +#include "mozilla/StdInt.h" + +#include "jsfriendapi.h" +#include "jsinfer.h" +#include "jsval.h" + +#include "gc/Barrier.h" + +namespace js { + +/* + * Header structure for object element arrays. This structure is immediately + * followed by an array of elements, with the elements member in an object + * pointing to the beginning of that array (the end of this structure). + * See below for usage of this structure. + */ +class ObjectElements +{ + friend struct ::JSObject; + + /* Number of allocated slots. */ + uint32_t capacity; + + /* + * Number of initialized elements. This is <= the capacity, and for arrays + * is <= the length. Memory for elements above the initialized length is + * uninitialized, but values between the initialized length and the proper + * length are conceptually holes. + */ + uint32_t initializedLength; + + /* 'length' property of array objects, unused for other objects. */ + uint32_t length; + + /* :XXX: bug 586842 store state about sparse slots. */ + uint32_t unused; + + void staticAsserts() { + MOZ_STATIC_ASSERT(sizeof(ObjectElements) == VALUES_PER_HEADER * sizeof(Value), + "Elements size and values-per-Elements mismatch"); + } + + public: + + ObjectElements(uint32_t capacity, uint32_t length) + : capacity(capacity), initializedLength(0), length(length) + {} + + HeapValue * elements() { return (HeapValue *)(uintptr_t(this) + sizeof(ObjectElements)); } + static ObjectElements * fromElements(HeapValue *elems) { + return (ObjectElements *)(uintptr_t(elems) - sizeof(ObjectElements)); + } + + static int offsetOfCapacity() { + return (int)offsetof(ObjectElements, capacity) - (int)sizeof(ObjectElements); + } + static int offsetOfInitializedLength() { + return (int)offsetof(ObjectElements, initializedLength) - (int)sizeof(ObjectElements); + } + static int offsetOfLength() { + return (int)offsetof(ObjectElements, length) - (int)sizeof(ObjectElements); + } + + static const size_t VALUES_PER_HEADER = 2; +}; + +/* Shared singleton for objects with no elements. */ +extern HeapValue *emptyObjectElements; + +struct Class; +struct GCMarker; +struct ObjectOps; +struct Shape; + +class NewObjectCache; + +/* + * ObjectImpl specifies the internal implementation of an object. (In contrast + * JSObject specifies an "external" interface, at the conceptual level of that + * exposed in ECMAScript.) + * + * The |shape_| member stores the shape of the object, which includes the + * object's class and the layout of all its properties. + * + * The type member stores the type of the object, which contains its prototype + * object and the possible types of its properties. + * + * The rest of the object stores its named properties and indexed elements. + * These are stored separately from one another. Objects are followed by an + * variable-sized array of values for inline storage, which may be used by + * either properties of native objects (fixed slots) or by elements. + * + * Two native objects with the same shape are guaranteed to have the same + * number of fixed slots. + * + * Named property storage can be split between fixed slots and a dynamically + * allocated array (the slots member). For an object with N fixed slots, shapes + * with slots [0..N-1] are stored in the fixed slots, and the remainder are + * stored in the dynamic array. If all properties fit in the fixed slots, the + * 'slots' member is NULL. + * + * Elements are indexed via the 'elements' member. This member can point to + * either the shared emptyObjectElements singleton, into the inline value array + * (the address of the third value, to leave room for a ObjectElements header; + * in this case numFixedSlots() is zero) or to a dynamically allocated array. + * + * Only certain combinations of properties and elements storage are currently + * possible. This will be changing soon :XXX: bug 586842. + * + * - For objects other than arrays and typed arrays, the elements are empty. + * + * - For 'slow' arrays, both elements and properties are used, but the + * elements have zero capacity --- only the length member is used. + * + * - For dense arrays, elements are used and properties are not used. + * + * - For typed array buffers, elements are used and properties are not used. + * The data indexed by the elements do not represent Values, but primitive + * unboxed integers or floating point values. + * + * The members of this class are currently protected; in the long run this will + * will change so that some members are private, and only certain methods that + * act upon them will be protected. + */ +class ObjectImpl : public gc::Cell +{ + protected: + /* + * Shape of the object, encodes the layout of the object's properties and + * all other information about its structure. See jsscope.h. + */ + HeapPtrShape shape_; + + /* + * The object's type and prototype. For objects with the LAZY_TYPE flag + * set, this is the prototype's default 'new' type and can only be used + * to get that prototype. + */ + HeapPtrTypeObject type_; + + HeapValue *slots; /* Slots for object properties. */ + HeapValue *elements; /* Slots for object elements. */ + + private: + static void staticAsserts() { + MOZ_STATIC_ASSERT(sizeof(ObjectImpl) == sizeof(shadow::Object), + "shadow interface must match actual implementation"); + MOZ_STATIC_ASSERT(sizeof(ObjectImpl) % sizeof(Value) == 0, + "fixed slots after an object must be aligned"); + + MOZ_STATIC_ASSERT(offsetof(ObjectImpl, shape_) == offsetof(shadow::Object, shape), + "shadow shape must match actual shape"); + MOZ_STATIC_ASSERT(offsetof(ObjectImpl, type_) == offsetof(shadow::Object, type), + "shadow type must match actual type"); + MOZ_STATIC_ASSERT(offsetof(ObjectImpl, slots) == offsetof(shadow::Object, slots), + "shadow slots must match actual slots"); + MOZ_STATIC_ASSERT(offsetof(ObjectImpl, elements) == offsetof(shadow::Object, _1), + "shadow placeholder must match actual elements"); + } + + JSObject * asObjectPtr() { return reinterpret_cast(this); } + + protected: + friend struct GCMarker; + friend struct Shape; + friend class NewObjectCache; + + /* Minimum size for dynamically allocated slots. */ + static const uint32_t SLOT_CAPACITY_MIN = 8; + + HeapValue * fixedSlots() const { + return reinterpret_cast(uintptr_t(this) + sizeof(ObjectImpl)); + } + + /* + * These functions are currently public for simplicity; in the long run + * it may make sense to make at least some of them private. + */ + + public: + Shape * lastProperty() const { + MOZ_ASSERT(shape_); + return shape_; + } + + types::TypeObject *type() const { + MOZ_ASSERT(!hasLazyType()); + return type_; + } + + size_t numFixedSlots() const { + return reinterpret_cast(this)->numFixedSlots(); + } + + /* + * Whether this is the only object which has its specified type. This + * object will have its type constructed lazily as needed by analysis. + */ + bool hasSingletonType() const { return !!type_->singleton; } + + /* + * Whether the object's type has not been constructed yet. If an object + * might have a lazy type, use getType() below, otherwise type(). + */ + bool hasLazyType() const { return type_->lazy(); } + + inline bool isNative() const; + + const Shape * nativeLookup(JSContext *cx, jsid id); + + inline Class *getClass() const; + inline JSClass *getJSClass() const; + inline bool hasClass(const Class *c) const; + inline const ObjectOps *getOps() const; + + /* + * An object is a delegate if it is on another object's prototype or scope + * chain, and therefore the delegate might be asked implicitly to get or + * set a property on behalf of another object. Delegates may be accessed + * directly too, as may any object, but only those objects linked after the + * head of any prototype or scope chain are flagged as delegates. This + * definition helps to optimize shape-based property cache invalidation + * (see Purge{Scope,Proto}Chain in jsobj.cpp). + */ + inline bool isDelegate() const; + + /* + * Return true if this object is a native one that has been converted from + * shared-immutable prototype-rooted shape storage to dictionary-shapes in + * a doubly-linked list. + */ + inline bool inDictionaryMode() const; + + /* + * Get the number of dynamic slots to allocate to cover the properties in + * an object with the given number of fixed slots and slot span. The slot + * capacity is not stored explicitly, and the allocated size of the slot + * array is kept in sync with this count. + */ + static inline size_t dynamicSlotsCount(size_t nfixed, size_t span); + + /* Memory usage functions. */ + inline size_t sizeOfThis() const; + + /* Elements accessors. */ + + ObjectElements * getElementsHeader() const { + return ObjectElements::fromElements(elements); + } + + inline HeapValue * fixedElements() const { + MOZ_STATIC_ASSERT(2 * sizeof(Value) == sizeof(ObjectElements), + "when elements are stored inline, the first two " + "slots will hold the ObjectElements header"); + return &fixedSlots()[2]; + } + + void setFixedElements() { this->elements = fixedElements(); } + + inline bool hasDynamicElements() const { + /* + * Note: for objects with zero fixed slots this could potentially give + * a spurious 'true' result, if the end of this object is exactly + * aligned with the end of its arena and dynamic slots are allocated + * immediately afterwards. Such cases cannot occur for dense arrays + * (which have at least two fixed slots) and can only result in a leak. + */ + return elements != emptyObjectElements && elements != fixedElements(); + } + + /* Write barrier support. */ + static inline void readBarrier(ObjectImpl *obj); + static inline void writeBarrierPre(ObjectImpl *obj); + static inline void writeBarrierPost(ObjectImpl *obj, void *addr); + inline void privateWriteBarrierPre(void **oldval); + inline void privateWriteBarrierPost(void **oldval); + + /* JIT Accessors */ + static size_t offsetOfShape() { return offsetof(ObjectImpl, shape_); } + HeapPtrShape *addressOfShape() { return &shape_; } + + static size_t offsetOfType() { return offsetof(ObjectImpl, type_); } + HeapPtrTypeObject *addressOfType() { return &type_; } + + static size_t offsetOfElements() { return offsetof(ObjectImpl, elements); } + static size_t offsetOfFixedElements() { + return sizeof(ObjectImpl) + sizeof(ObjectElements); + } + + static size_t getFixedSlotOffset(size_t slot) { + return sizeof(ObjectImpl) + slot * sizeof(Value); + } + static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); } + static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); } + + /* These functions are public, and they should remain public. */ + + public: + JSObject * getProto() const { + return type_->proto; + } + + inline bool isExtensible() const; +}; + +} /* namespace js */ + +#endif /* ObjectImpl_h__ */ diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 94522160b15..980ca155298 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -1428,7 +1428,7 @@ nsXPCComponents_Results::NewResolve(nsIXPConnectWrappedNative *wrapper, jsval val; *objp = obj; - if (!JS_NewNumberValue(cx, (jsdouble)rv, &val) || + if (!JS_NewNumberValue(cx, (double)rv, &val) || !JS_DefinePropertyById(cx, obj, id, val, nsnull, nsnull, JSPROP_ENUMERATE | @@ -4165,7 +4165,7 @@ nsXPCComponents::GetProperty(nsIXPConnectWrappedNative *wrapper, nsresult rv = NS_OK; if (doResult) { - if (!JS_NewNumberValue(cx, (jsdouble) res, vp)) + if (!JS_NewNumberValue(cx, (double) res, vp)) return NS_ERROR_OUT_OF_MEMORY; rv = NS_SUCCESS_I_DID_SOMETHING; } diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index 675214f23f8..fe4a24d9f2e 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -144,11 +144,11 @@ XPCConvert::NativeData2JS(XPCLazyCallContext& lccx, jsval* d, const void* s, case nsXPTType::T_I8 : *d = INT_TO_JSVAL(int32_t(*((int8_t*)s))); break; case nsXPTType::T_I16 : *d = INT_TO_JSVAL(int32_t(*((int16_t*)s))); break; case nsXPTType::T_I32 : *d = INT_TO_JSVAL(*((int32_t*)s)); break; - case nsXPTType::T_I64 : *d = DOUBLE_TO_JSVAL(jsdouble(*((int64_t*)s))); break; + case nsXPTType::T_I64 : *d = DOUBLE_TO_JSVAL(double(*((int64_t*)s))); break; case nsXPTType::T_U8 : *d = INT_TO_JSVAL(int32_t(*((uint8_t*)s))); break; case nsXPTType::T_U16 : *d = INT_TO_JSVAL(int32_t(*((uint16_t*)s))); break; case nsXPTType::T_U32 : *d = UINT_TO_JSVAL(*((uint32_t*)s)); break; - case nsXPTType::T_U64 : *d = DOUBLE_TO_JSVAL(jsdouble(*((uint64_t*)s))); break; + case nsXPTType::T_U64 : *d = DOUBLE_TO_JSVAL(double(*((uint64_t*)s))); break; case nsXPTType::T_FLOAT : *d = DOUBLE_TO_JSVAL(*((float*)s)); break; case nsXPTType::T_DOUBLE: *d = DOUBLE_TO_JSVAL(*((double*)s)); break; case nsXPTType::T_BOOL : @@ -410,7 +410,7 @@ XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s, int32_t ti; uint32_t tu; - jsdouble td; + double td; JSBool tb; JSBool isDOMString = true; diff --git a/js/xpconnect/src/XPCQuickStubs.h b/js/xpconnect/src/XPCQuickStubs.h index f903ed633f4..4c1a35d2136 100644 --- a/js/xpconnect/src/XPCQuickStubs.h +++ b/js/xpconnect/src/XPCQuickStubs.h @@ -235,13 +235,13 @@ xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool stric inline JSBool xpc_qsInt64ToJsval(JSContext *cx, PRInt64 i, jsval *rv) { - return JS_NewNumberValue(cx, static_cast(i), rv); + return JS_NewNumberValue(cx, static_cast(i), rv); } inline JSBool xpc_qsUint64ToJsval(JSContext *cx, PRUint64 u, jsval *rv) { - return JS_NewNumberValue(cx, static_cast(u), rv); + return JS_NewNumberValue(cx, static_cast(u), rv); } @@ -667,7 +667,7 @@ xpc_qsValueToInt64(JSContext *cx, return false; *result = static_cast(intval); } else { - jsdouble doubleval; + double doubleval; if (!JS_ValueToNumber(cx, v, &doubleval)) return false; *result = static_cast(doubleval); @@ -689,7 +689,7 @@ xpc_qsValueToUint64(JSContext *cx, return false; *result = static_cast(intval); } else { - jsdouble doubleval; + double doubleval; if (!JS_ValueToNumber(cx, v, &doubleval)) return false; *result = static_cast(doubleval); diff --git a/js/xpconnect/src/codegen.py b/js/xpconnect/src/codegen.py index 4a9e3b9cd49..c88ac8907fb 100644 --- a/js/xpconnect/src/codegen.py +++ b/js/xpconnect/src/codegen.py @@ -137,13 +137,13 @@ argumentUnboxingTemplates = { " return JS_FALSE;\n", 'float': - " jsdouble ${name}_dbl;\n" + " double ${name}_dbl;\n" " if (!JS_ValueToNumber(cx, ${argVal}, &${name}_dbl))\n" " return JS_FALSE;\n" " float ${name} = (float) ${name}_dbl;\n", 'double': - " jsdouble ${name};\n" + " double ${name};\n" " if (!JS_ValueToNumber(cx, ${argVal}, &${name}))\n" " return JS_FALSE;\n", diff --git a/js/xpconnect/src/dombindings.cpp b/js/xpconnect/src/dombindings.cpp index 88aa3229f56..27f1214117e 100644 --- a/js/xpconnect/src/dombindings.cpp +++ b/js/xpconnect/src/dombindings.cpp @@ -603,7 +603,7 @@ IdToInt32(JSContext *cx, jsid id) JSAutoRequest ar(cx); jsval idval; - jsdouble array_index; + double array_index; int32_t i; if (!::JS_IdToValue(cx, id, &idval) || !::JS_ValueToNumber(cx, idval, &array_index) || diff --git a/js/xpconnect/src/qsgen.py b/js/xpconnect/src/qsgen.py index a997c028fb1..08851090bb1 100644 --- a/js/xpconnect/src/qsgen.py +++ b/js/xpconnect/src/qsgen.py @@ -466,13 +466,13 @@ argumentUnboxingTemplates = { " return JS_FALSE;\n", 'float': - " jsdouble ${name}_dbl;\n" + " double ${name}_dbl;\n" " if (!JS_ValueToNumber(cx, ${argVal}, &${name}_dbl))\n" " return JS_FALSE;\n" " float ${name} = (float) ${name}_dbl;\n", 'double': - " jsdouble ${name};\n" + " double ${name};\n" " if (!JS_ValueToNumber(cx, ${argVal}, &${name}))\n" " return JS_FALSE;\n", diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index cc12176e61a..3b38f8e9eb1 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -110,8 +110,7 @@ JSClass HolderClass = { JSCLASS_HAS_RESERVED_SLOTS(3), JS_PropertyStub, JS_PropertyStub, holder_get, holder_set, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL + JSCLASS_NO_OPTIONAL_MEMBERS }; } diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index 901f1ae75fb..25a57c1a793 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -464,12 +464,16 @@ pref("dom.ipc.content.nice", 1); // product URLs // The breakpad report server to link to in about:crashes pref("breakpad.reportURL", "http://crash-stats.mozilla.com/report/index/"); -pref("app.releaseNotesURL", "http://www.mozilla.com/%LOCALE%/mobile/%VERSION%/releasenotes/"); pref("app.support.baseURL", "http://support.mozilla.org/mobile"); pref("app.feedbackURL", "http://input.mozilla.com/feedback/"); pref("app.privacyURL", "http://www.mozilla.com/%LOCALE%/m/privacy.html"); pref("app.creditsURL", "http://www.mozilla.org/credits/"); pref("app.channelURL", "http://www.mozilla.org/%LOCALE%/firefox/channel/"); +#if MOZ_UPDATE_CHANNEL == aurora +pref("app.releaseNotesURL", "http://www.mozilla.com/%LOCALE%/mobile/%VERSION%/auroranotes/"); +#else +pref("app.releaseNotesURL", "http://www.mozilla.com/%LOCALE%/mobile/%VERSION%/releasenotes/"); +#endif #if MOZ_UPDATE_CHANNEL == beta pref("app.featuresURL", "http://www.mozilla.com/%LOCALE%/mobile/beta/features/"); pref("app.faqURL", "http://www.mozilla.com/%LOCALE%/mobile/beta/faq/"); diff --git a/mobile/android/base/AboutHomeContent.java b/mobile/android/base/AboutHomeContent.java index 067f053e7f3..5420865f875 100644 --- a/mobile/android/base/AboutHomeContent.java +++ b/mobile/android/base/AboutHomeContent.java @@ -154,7 +154,7 @@ public class AboutHomeContent extends ScrollView { } }); } - }, GeckoAppShell.getHandler(), true); + }, GeckoAppShell.getHandler(), false); mTopSitesGrid = (GridView)findViewById(R.id.top_sites_grid); mTopSitesGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() { diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index c2dbc218bdf..fc6f76e3dca 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -390,7 +390,7 @@ abstract public class GeckoApp { sMenu = menu; MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.layout.gecko_menu, menu); + inflater.inflate(R.menu.gecko_menu, menu); return true; } @@ -436,7 +436,6 @@ abstract public class GeckoApp MenuItem forward = aMenu.findItem(R.id.forward); MenuItem share = aMenu.findItem(R.id.share); MenuItem saveAsPDF = aMenu.findItem(R.id.save_as_pdf); - MenuItem downloads = aMenu.findItem(R.id.downloads); MenuItem charEncoding = aMenu.findItem(R.id.char_encoding); if (tab == null) { @@ -470,10 +469,6 @@ abstract public class GeckoApp saveAsPDF.setEnabled(!(tab.getURL().equals("about:home") || tab.getContentType().equals("application/vnd.mozilla.xul+xml"))); - // DownloadManager support is tied to level 12 and higher - if (Build.VERSION.SDK_INT < 12) - downloads.setVisible(false); - charEncoding.setVisible(GeckoPreferences.getCharEncodingState()); return true; @@ -2136,10 +2131,6 @@ abstract public class GeckoApp refreshActionBar(); } - // Just in case. Normally we start in onNewIntent - if (checkLaunchState(LaunchState.Launching)) - onNewIntent(getIntent()); - registerReceiver(mConnectivityReceiver, mConnectivityFilter); GeckoNetworkManager.getInstance().start(); diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index a7d4aedb94f..59b0eef990e 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -897,10 +897,12 @@ public class GeckoAppShell String aClassName, String aAction, String aTitle) { Intent intent = getIntentForActionString(aAction); if (aAction.equalsIgnoreCase(Intent.ACTION_SEND)) { - intent.putExtra(Intent.EXTRA_TEXT, aUriSpec); - intent.putExtra(Intent.EXTRA_SUBJECT, aTitle); + Intent shareIntent = getIntentForActionString(aAction); + shareIntent.putExtra(Intent.EXTRA_TEXT, aUriSpec); + shareIntent.putExtra(Intent.EXTRA_SUBJECT, aTitle); if (aMimeType != null && aMimeType.length() > 0) - intent.setType(aMimeType); + shareIntent.setType(aMimeType); + intent = Intent.createChooser(shareIntent, GeckoApp.mAppContext.getResources().getString(R.string.share_title)); } else if (aMimeType.length() > 0) { intent.setDataAndType(Uri.parse(aUriSpec), aMimeType); } else { diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 478d43a0bc6..25bd4d07874 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -232,7 +232,6 @@ RES_LAYOUT = \ res/layout/doorhangerpopup.xml \ res/layout/doorhanger.xml \ res/layout/gecko_app.xml \ - res/layout/gecko_menu.xml \ res/layout/launch_app_list.xml \ res/layout/launch_app_listitem.xml \ res/layout/notification_icon_text.xml \ @@ -490,6 +489,11 @@ RES_COLOR = \ RES_MENU = \ res/menu/awesomebar_contextmenu.xml \ + res/menu/gecko_menu.xml \ + $(NULL) + +RES_MENU_V11 = \ + res/menu-v11/gecko_menu.xml \ $(NULL) JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar @@ -552,7 +556,7 @@ MOZ_ANDROID_DRAWABLES += \ MOZ_ANDROID_DRAWABLES += $(shell if test -e $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn; then cat $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn | tr '\n' ' '; fi) -RESOURCES=$(RES_LAYOUT) $(RES_LAYOUT_V11) $(RES_LAYOUT_LAND_V14) $(RES_VALUES) $(RES_VALUES_V11) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_NODPI) $(RES_DRAWABLE_BASE) $(RES_DRAWABLE_LDPI) $(RES_DRAWABLE_HDPI) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_DRAWABLE_LAND_MDPI_V14) $(RES_DRAWABLE_LAND_HDPI_V14) $(RES_DRAWABLE_LAND_XHDPI_V14) $(RES_COLOR) $(RES_MENU) +RESOURCES=$(RES_LAYOUT) $(RES_LAYOUT_V11) $(RES_LAYOUT_LAND_V14) $(RES_VALUES) $(RES_VALUES_V11) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_NODPI) $(RES_DRAWABLE_BASE) $(RES_DRAWABLE_LDPI) $(RES_DRAWABLE_HDPI) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_DRAWABLE_LAND_MDPI_V14) $(RES_DRAWABLE_LAND_HDPI_V14) $(RES_DRAWABLE_LAND_XHDPI_V14) $(RES_COLOR) $(RES_MENU) $(RES_MENU_V11) RES_DIRS= \ res/layout \ diff --git a/mobile/android/base/ProfileMigrator.java b/mobile/android/base/ProfileMigrator.java index de1a239a1ab..b0d702cb2de 100644 --- a/mobile/android/base/ProfileMigrator.java +++ b/mobile/android/base/ProfileMigrator.java @@ -523,7 +523,9 @@ public class ProfileMigrator { // that we can't add, we remember what these are and try again // on the next iteration. The number of iterations scales // according to the depth of the folders. - Set processedBookmarks = new HashSet(); + // No need to import root folders for which we have a remapping. + Set processedBookmarks = new HashSet(mRerootMap.keySet()); + int iterations = 0; do { // Reset the set of missing folders that block us from diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd index 7006f225d06..953d9b20c54 100644 --- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -79,6 +79,7 @@ + diff --git a/mobile/android/base/resources/layout/gecko_menu.xml b/mobile/android/base/resources/menu-v11/gecko_menu.xml similarity index 100% rename from mobile/android/base/resources/layout/gecko_menu.xml rename to mobile/android/base/resources/menu-v11/gecko_menu.xml diff --git a/mobile/android/base/resources/menu/gecko_menu.xml b/mobile/android/base/resources/menu/gecko_menu.xml new file mode 100644 index 00000000000..e009c24c84f --- /dev/null +++ b/mobile/android/base/resources/menu/gecko_menu.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/base/strings.xml.in b/mobile/android/base/strings.xml.in index 1c7bf4eed89..0947fb388af 100644 --- a/mobile/android/base/strings.xml.in +++ b/mobile/android/base/strings.xml.in @@ -45,6 +45,7 @@ &history_older_section; &share; + &share_title; &save_as_pdf; &settings; diff --git a/mobile/android/base/tests/testBookmark.java.in b/mobile/android/base/tests/testBookmark.java.in index a6ee0a906fd..a6a8d93873b 100644 --- a/mobile/android/base/tests/testBookmark.java.in +++ b/mobile/android/base/tests/testBookmark.java.in @@ -64,6 +64,9 @@ public class testBookmark extends BaseTest { } private void checkRootFolderView(ListView bookmarksList) { + // Wait for the folders to be displayed + mSolo.waitForText("Mobile Bookmarks"); + mAsserter.ok(bookmarksList != null, "checking that bookmarks list exists", "bookmarks list exists"); // The root view should have 5 children diff --git a/mobile/android/base/ui/Axis.java b/mobile/android/base/ui/Axis.java index 9921a8777a8..292052a76eb 100644 --- a/mobile/android/base/ui/Axis.java +++ b/mobile/android/base/ui/Axis.java @@ -61,7 +61,7 @@ abstract class Axis { // The rate of deceleration when the surface has overscrolled. private static final float OVERSCROLL_DECEL_RATE = 0.04f; // The percentage of the surface which can be overscrolled before it must snap back. - private static final float SNAP_LIMIT = 0.75f; + private static final float SNAP_LIMIT = 0.3f; // The minimum amount of space that must be present for an axis to be considered scrollable, // in pixels. diff --git a/mobile/xul/app/mobile.js b/mobile/xul/app/mobile.js index 1f9d6bc6a31..27b106108d5 100644 --- a/mobile/xul/app/mobile.js +++ b/mobile/xul/app/mobile.js @@ -527,7 +527,7 @@ pref("app.update.auto", false); pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@"); pref("app.update.mode", 1); pref("app.update.silent", false); -pref("app.update.url", "https://aus2.mozilla.org/update/4/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PLATFORM_VERSION%/update.xml"); +pref("app.update.url", "https://aus2.mozilla.org/update/4/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%-xul/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PLATFORM_VERSION%/update.xml"); pref("app.update.promptWaitTime", 43200); pref("app.update.idletime", 60); pref("app.update.showInstalledUI", false); diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index b50943de813..5da86bd7536 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -930,6 +930,7 @@ pref("network.IDN.whitelist.pl", true); pref("network.IDN.whitelist.pr", true); pref("network.IDN.whitelist.se", true); pref("network.IDN.whitelist.sh", true); +pref("network.IDN.whitelist.si", true); pref("network.IDN.whitelist.th", true); pref("network.IDN.whitelist.tm", true); pref("network.IDN.whitelist.tw", true); diff --git a/services/sync/modules/engines/bookmarks.js b/services/sync/modules/engines/bookmarks.js index a2ccf716d77..c9f75138273 100644 --- a/services/sync/modules/engines/bookmarks.js +++ b/services/sync/modules/engines/bookmarks.js @@ -47,23 +47,6 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; -const ALLBOOKMARKS_ANNO = "AllBookmarks"; -const DESCRIPTION_ANNO = "bookmarkProperties/description"; -const SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar"; -const FEEDURI_ANNO = "livemark/feedURI"; -const SITEURI_ANNO = "livemark/siteURI"; -const MOBILEROOT_ANNO = "mobile/bookmarksRoot"; -const MOBILE_ANNO = "MobileBookmarks"; -const EXCLUDEBACKUP_ANNO = "places/excludeFromBackup"; -const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark"; -const PARENT_ANNO = "sync/parent"; -const ORGANIZERQUERY_ANNO = "PlacesOrganizer/OrganizerQuery"; -const ANNOS_TO_TRACK = [DESCRIPTION_ANNO, SIDEBAR_ANNO, - FEEDURI_ANNO, SITEURI_ANNO]; - -const SERVICE_NOT_SUPPORTED = "Service not supported on this platform"; -const FOLDER_SORTINDEX = 1000000; - Cu.import("resource://gre/modules/PlacesUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://services-sync/engines.js"); @@ -74,6 +57,21 @@ Cu.import("resource://services-sync/constants.js"); Cu.import("resource://services-sync/main.js"); // For access to Service. +const ALLBOOKMARKS_ANNO = "AllBookmarks"; +const DESCRIPTION_ANNO = "bookmarkProperties/description"; +const SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar"; +const MOBILEROOT_ANNO = "mobile/bookmarksRoot"; +const MOBILE_ANNO = "MobileBookmarks"; +const EXCLUDEBACKUP_ANNO = "places/excludeFromBackup"; +const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark"; +const PARENT_ANNO = "sync/parent"; +const ORGANIZERQUERY_ANNO = "PlacesOrganizer/OrganizerQuery"; +const ANNOS_TO_TRACK = [DESCRIPTION_ANNO, SIDEBAR_ANNO, + PlacesUtils.LMANNO_FEEDURI, PlacesUtils.LMANNO_SITEURI]; + +const SERVICE_NOT_SUPPORTED = "Service not supported on this platform"; +const FOLDER_SORTINDEX = 1000000; + function PlacesItem(collection, id, type) { CryptoWrapper.call(this, collection, id); this.type = type || "item"; @@ -633,14 +631,17 @@ BookmarksStore.prototype = { switch (type) { case bms.TYPE_FOLDER: - if (PlacesUtils.itemIsLivemark(itemId)) + if (PlacesUtils.annotations + .itemHasAnnotation(itemId, PlacesUtils.LMANNO_FEEDURI)) { return "livemark"; + } return "folder"; case bms.TYPE_BOOKMARK: let bmkUri = bms.getBookmarkURI(itemId).spec; - if (bmkUri.search(/^place:/) == 0) + if (bmkUri.indexOf("place:") == 0) { return "query"; + } return "bookmark"; case bms.TYPE_SEPARATOR: @@ -718,7 +719,8 @@ BookmarksStore.prototype = { this._log.debug("No feed URI: skipping livemark record " + record.id); return; } - if (PlacesUtils.itemIsLivemark(record._parent)) { + if (PlacesUtils.annotations + .itemHasAnnotation(record._parent, PlacesUtils.LMANNO_FEEDURI)) { this._log.debug("Invalid parent: skipping livemark record " + record.id); return; } @@ -726,14 +728,31 @@ BookmarksStore.prototype = { if (record.siteUri != null) siteURI = Utils.makeURI(record.siteUri); - // Use createLivemarkFolderOnly, not createLivemark, to avoid it - // automatically updating during a sync. - newId = PlacesUtils.livemarks.createLivemarkFolderOnly( - record._parent, record.title, siteURI, Utils.makeURI(record.feedUri), - PlacesUtils.bookmarks.DEFAULT_INDEX); - this._log.debug("Created livemark " + newId + " under " + record._parent + - " as " + record.title + ", " + record.siteUri + ", " + - record.feedUri + ", GUID " + record.id); + // Until this engine can handle asynchronous error reporting, we need to + // detect errors on creation synchronously. + let spinningCb = Async.makeSpinningCallback(); + + let livemarkObj = {title: record.title, + parentId: record._parent, + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + feedURI: Utils.makeURI(record.feedUri), + siteURI: siteURI, + guid: record.id}; + PlacesUtils.livemarks.addLivemark(livemarkObj, + function (aStatus, aLivemark) { + spinningCb(null, [aStatus, aLivemark]); + }); + + let [status, livemark] = spinningCb.wait(); + if (!Components.isSuccessCode(status)) { + throw status; + } + + this._log.debug("Created livemark " + livemark.id + " under " + + livemark.parentId + " as " + livemark.title + + ", " + livemark.siteURI.spec + ", " + + livemark.feedURI.spec + ", GUID " + + livemark.guid); break; case "separator": newId = PlacesUtils.bookmarks.insertSeparator( @@ -748,8 +767,12 @@ BookmarksStore.prototype = { return; } - this._log.trace("Setting GUID of new item " + newId + " to " + record.id); - this._setGUID(newId, record.id); + if (newId) { + // Livemarks can set the GUID through the API, so there's no need to + // do that here. + this._log.trace("Setting GUID of new item " + newId + " to " + record.id); + this._setGUID(newId, record.id); + } }, // Factored out of `remove` to avoid redundant DB queries when the Places ID @@ -859,12 +882,6 @@ BookmarksStore.prototype = { itemId, SMART_BOOKMARKS_ANNO, val, 0, PlacesUtils.annotations.EXPIRE_NEVER); break; - case "siteUri": - PlacesUtils.livemarks.setSiteURI(itemId, Utils.makeURI(val)); - break; - case "feedUri": - PlacesUtils.livemarks.setFeedURI(itemId, Utils.makeURI(val)); - break; } } }, @@ -973,7 +990,7 @@ BookmarksStore.prototype = { switch (PlacesUtils.bookmarks.getItemType(placeId)) { case PlacesUtils.bookmarks.TYPE_BOOKMARK: let bmkUri = PlacesUtils.bookmarks.getBookmarkURI(placeId).spec; - if (bmkUri.search(/^place:/) == 0) { + if (bmkUri.indexOf("place:") == 0) { record = new BookmarkQuery(collection, id); // Get the actual tag name instead of the local itemId @@ -1013,14 +1030,14 @@ BookmarksStore.prototype = { break; case PlacesUtils.bookmarks.TYPE_FOLDER: - if (PlacesUtils.itemIsLivemark(placeId)) { + if (PlacesUtils.annotations + .itemHasAnnotation(placeId, PlacesUtils.LMANNO_FEEDURI)) { record = new Livemark(collection, id); - - let siteURI = PlacesUtils.livemarks.getSiteURI(placeId); - if (siteURI != null) - record.siteUri = siteURI.spec; - record.feedUri = PlacesUtils.livemarks.getFeedURI(placeId).spec; - + let as = PlacesUtils.annotations; + record.feedUri = as.getItemAnnotation(placeId, PlacesUtils.LMANNO_FEEDURI); + try { + record.siteUri = as.getItemAnnotation(placeId, PlacesUtils.LMANNO_SITEURI); + } catch (ex) {} } else { record = new BookmarkFolder(collection, id); } @@ -1181,8 +1198,7 @@ BookmarksStore.prototype = { node = this._getNode(nodeID); } - if (node.type == node.RESULT_TYPE_FOLDER && - !PlacesUtils.itemIsLivemark(node.itemId)) { + if (node.type == node.RESULT_TYPE_FOLDER) { node.QueryInterface(Ci.nsINavHistoryQueryResultNode); node.containerOpen = true; try { @@ -1312,8 +1328,7 @@ BookmarksTracker.prototype = { }, /** - * Determine if a change should be ignored: we're ignoring everything or the - * folder is for livemarks. + * Determine if a change should be ignored. * * @param itemId * Item under consideration to ignore @@ -1339,10 +1354,6 @@ BookmarksTracker.prototype = { } } - // Ignore livemark children. - if (PlacesUtils.itemIsLivemark(folder)) - return true; - // Ignore changes to tags (folders under the tags folder). let tags = kSpecialIds.tags; if (folder == tags) @@ -1423,8 +1434,7 @@ BookmarksTracker.prototype = { // This method is oddly structured, but the idea is to return as quickly as // possible -- this handler gets called *every time* a bookmark changes, for - // *each change*. That's particularly bad when a bunch of livemarks are - // updated. + // *each change*. onItemChanged: function BMT_onItemChanged(itemId, property, isAnno, value, lastModified, itemType, parentId, guid, parentGuid) { diff --git a/services/sync/tests/unit/test_bookmark_engine.js b/services/sync/tests/unit/test_bookmark_engine.js index 16221f3e9cb..78abf1955e9 100644 --- a/services/sync/tests/unit/test_bookmark_engine.js +++ b/services/sync/tests/unit/test_bookmark_engine.js @@ -356,7 +356,8 @@ add_test(function test_mismatched_types() { let oldID = store.idForGUID(oldR.id); _("Old ID: " + oldID); do_check_eq(bms.getItemType(oldID), bms.TYPE_FOLDER); - do_check_false(PlacesUtils.livemarks.isLivemark(oldID)); + do_check_false(PlacesUtils.annotations + .itemHasAnnotation(oldID, PlacesUtils.LMANNO_FEEDURI)); store.applyIncoming(newR); let newID = store.idForGUID(newR.id); @@ -364,7 +365,8 @@ add_test(function test_mismatched_types() { _("Applied new. It's a livemark."); do_check_eq(bms.getItemType(newID), bms.TYPE_FOLDER); - do_check_true(PlacesUtils.livemarks.isLivemark(newID)); + do_check_true(PlacesUtils.annotations + .itemHasAnnotation(newID, PlacesUtils.LMANNO_FEEDURI)); } finally { store.wipe(); diff --git a/services/sync/tps/extensions/tps/modules/bookmarks.jsm b/services/sync/tps/extensions/tps/modules/bookmarks.jsm index ab8a687f775..2eb065b3db2 100644 --- a/services/sync/tps/extensions/tps/modules/bookmarks.jsm +++ b/services/sync/tps/extensions/tps/modules/bookmarks.jsm @@ -50,7 +50,7 @@ const CU = Components.utils; CU.import("resource://tps/logger.jsm"); CU.import("resource://gre/modules/Services.jsm"); CU.import("resource://gre/modules/PlacesUtils.jsm"); - +CU.import("resource://services-sync/async.js"); var DumpBookmarks = function TPS_Bookmarks__DumpBookmarks() { let writer = { @@ -801,12 +801,26 @@ Livemark.prototype = { let siteURI = null; if (this.props.siteUri != null) siteURI = Services.io.newURI(this.props.siteUri, null, null); - this.props.item_id = PlacesUtils.livemarks.createLivemark( - this.props.folder_id, - this.props.livemark, - siteURI, - Services.io.newURI(this.props.feedUri, null, null), - -1); + let livemarkObj = {parentId: this.props.folder_id, + title: this.props.livemark, + siteURI: siteURI, + feedURI: Services.io.newURI(this.props.feedUri, null, null), + index: PlacesUtils.bookmarks.DEFAULT_INDEX}; + + // Until this can handle asynchronous creation, we need to spin. + let spinningCb = Async.makeSpinningCallback(); + + PlacesUtils.livemarks.addLivemark(livemarkObj, + function (aStatus, aLivemark) { + spinningCb(null, [aStatus, aLivemark]); + }); + + let [status, livemark] = spinningCb.wait(); + if (!Components.isSuccessCode(status)) { + throw status; + } + + this.props.item_id = livemark.id; return this.props.item_id; }, @@ -828,26 +842,31 @@ Livemark.prototype = { this.props.folder_id, CI.nsINavHistoryResultNode.RESULT_TYPE_FOLDER, this.props.livemark); - if (!PlacesUtils.livemarks.isLivemark(this.props.item_id)) { + if (!PlacesUtils.annotations + .itemHasAnnotation(this.props.item_id, PlacesUtils.LMANNO_FEEDURI)) { Logger.logPotentialError("livemark folder found, but it's just a regular folder, for " + this.toString()); this.props.item_id = -1; return -1; } let feedURI = Services.io.newURI(this.props.feedUri, null, null); - let lmFeedURI = PlacesUtils.livemarks.getFeedURI(this.props.item_id); - if (feedURI.spec != lmFeedURI.spec) { + let lmFeedURISpec = + PlacesUtils.annotations.getItemAnnotation(this.props.item_id, + PlacesUtils.LMANNO_FEEDURI); + if (feedURI.spec != lmFeedURISpec) { Logger.logPotentialError("livemark feed uri not correct, expected: " + - this.props.feedUri + ", actual: " + lmFeedURI.spec + + this.props.feedUri + ", actual: " + lmFeedURISpec + " for " + this.toString()); return -1; } if (this.props.siteUri != null) { let siteURI = Services.io.newURI(this.props.siteUri, null, null); - let lmSiteURI = PlacesUtils.livemarks.getSiteURI(this.props.item_id); - if (siteURI.spec != lmSiteURI.spec) { + let lmSiteURISpec = + PlacesUtils.annotations.getItemAnnotation(this.props.item_id, + PlacesUtils.LMANNO_SITEURI); + if (siteURI.spec != lmSiteURISpec) { Logger.logPotentialError("livemark site uri not correct, expected: " + - this.props.siteUri + ", actual: " + lmSiteURI.spec + " for " + + this.props.siteUri + ", actual: " + lmSiteURISpec + " for " + this.toString()); return -1; } @@ -859,36 +878,6 @@ Livemark.prototype = { return this.props.item_id; }, - /** - * SetSiteUri - * - * Sets the siteURI property for this livemark. - * - * @param siteUri the URI to set; if null, no changes are made - * @return nothing - */ - SetSiteUri: function(siteUri) { - if (siteUri) { - let siteURI = Services.io.newURI(siteUri, null, null); - PlacesUtils.livemarks.setSiteURI(this.props.item_id, siteURI); - } - }, - - /** - * SetFeedUri - * - * Sets the feedURI property for this livemark. - * - * @param feedUri the URI to set; if null, no changes are made - * @return nothing - */ - SetFeedUri: function(feedUri) { - if (feedUri) { - let feedURI = Services.io.newURI(feedUri, null, null); - PlacesUtils.livemarks.setFeedURI(this.props.item_id, feedURI); - } - }, - /** * Update * @@ -902,8 +891,6 @@ Livemark.prototype = { "Invalid item_id during Update"); this.SetLocation(this.updateProps.location); this.SetPosition(this.updateProps.position); - this.SetSiteUri(this.updateProps.siteUri); - this.SetFeedUri(this.updateProps.feedUri); this.SetTitle(this.updateProps.livemark); return true; }, diff --git a/toolkit/components/places/Database.cpp b/toolkit/components/places/Database.cpp index e3c62bd5d1a..a284f308144 100644 --- a/toolkit/components/places/Database.cpp +++ b/toolkit/components/places/Database.cpp @@ -95,6 +95,10 @@ // Places string bundle, contains internationalized bookmark root names. #define PLACES_BUNDLE "chrome://places/locale/places.properties" +// Livemarks annotations. +#define LMANNO_FEEDURI "livemark/feedURI" +#define LMANNO_SITEURI "livemark/siteURI" + using namespace mozilla; namespace mozilla { @@ -749,7 +753,12 @@ Database::InitSchema(bool* aDatabaseMigrated) NS_ENSURE_SUCCESS(rv, rv); } - // Firefox 13 uses schema version 18. + if (currentSchemaVersion < 19) { + rv = MigrateV19Up(); + NS_ENSURE_SUCCESS(rv, rv); + } + + // Firefox 13 uses schema version 19. // Schema Upgrades must add migration code here. @@ -1750,6 +1759,85 @@ Database::MigrateV18Up() return NS_OK; } +nsresult +Database::MigrateV19Up() +{ + MOZ_ASSERT(NS_IsMainThread()); + + // Livemarks children are no longer bookmarks. + + // Remove all children of folders annotated as livemarks. + nsCOMPtr deleteLivemarksChildrenStmt; + nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING( + "DELETE FROM moz_bookmarks WHERE parent IN(" + "SELECT b.id FROM moz_bookmarks b " + "JOIN moz_items_annos a ON a.item_id = b.id " + "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " + "WHERE b.type = :item_type AND n.name = :anno_name " + ")" + ), getter_AddRefs(deleteLivemarksChildrenStmt)); + rv = deleteLivemarksChildrenStmt->BindUTF8StringByName( + NS_LITERAL_CSTRING("anno_name"), NS_LITERAL_CSTRING(LMANNO_FEEDURI) + ); + NS_ENSURE_SUCCESS(rv, rv); + rv = deleteLivemarksChildrenStmt->BindInt32ByName( + NS_LITERAL_CSTRING("item_type"), nsINavBookmarksService::TYPE_FOLDER + ); + NS_ENSURE_SUCCESS(rv, rv); + rv = deleteLivemarksChildrenStmt->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + // Clear obsolete livemark prefs. + (void)Preferences::ClearUser("browser.bookmarks.livemark_refresh_seconds"); + (void)Preferences::ClearUser("browser.bookmarks.livemark_refresh_limit_count"); + (void)Preferences::ClearUser("browser.bookmarks.livemark_refresh_delay_time"); + + // Remove the old status annotations. + nsCOMPtr deleteLivemarksAnnosStmt; + rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING( + "DELETE FROM moz_items_annos WHERE anno_attribute_id IN(" + "SELECT id FROM moz_anno_attributes " + "WHERE name IN (:anno_loading, :anno_loadfailed, :anno_expiration) " + ")" + ), getter_AddRefs(deleteLivemarksAnnosStmt)); + rv = deleteLivemarksAnnosStmt->BindUTF8StringByName( + NS_LITERAL_CSTRING("anno_loading"), NS_LITERAL_CSTRING("livemark/loading") + ); + NS_ENSURE_SUCCESS(rv, rv); + rv = deleteLivemarksAnnosStmt->BindUTF8StringByName( + NS_LITERAL_CSTRING("anno_loadfailed"), NS_LITERAL_CSTRING("livemark/loadfailed") + ); + NS_ENSURE_SUCCESS(rv, rv); + rv = deleteLivemarksAnnosStmt->BindUTF8StringByName( + NS_LITERAL_CSTRING("anno_expiration"), NS_LITERAL_CSTRING("livemark/expiration") + ); + NS_ENSURE_SUCCESS(rv, rv); + rv = deleteLivemarksAnnosStmt->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + // Remove orphan annotation names. + rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING( + "DELETE FROM moz_anno_attributes " + "WHERE name IN (:anno_loading, :anno_loadfailed, :anno_expiration) " + ), getter_AddRefs(deleteLivemarksAnnosStmt)); + rv = deleteLivemarksAnnosStmt->BindUTF8StringByName( + NS_LITERAL_CSTRING("anno_loading"), NS_LITERAL_CSTRING("livemark/loading") + ); + NS_ENSURE_SUCCESS(rv, rv); + rv = deleteLivemarksAnnosStmt->BindUTF8StringByName( + NS_LITERAL_CSTRING("anno_loadfailed"), NS_LITERAL_CSTRING("livemark/loadfailed") + ); + NS_ENSURE_SUCCESS(rv, rv); + rv = deleteLivemarksAnnosStmt->BindUTF8StringByName( + NS_LITERAL_CSTRING("anno_expiration"), NS_LITERAL_CSTRING("livemark/expiration") + ); + NS_ENSURE_SUCCESS(rv, rv); + rv = deleteLivemarksAnnosStmt->Execute(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + void Database::Shutdown() { diff --git a/toolkit/components/places/Database.h b/toolkit/components/places/Database.h index 09570e4939a..121f283fdd1 100644 --- a/toolkit/components/places/Database.h +++ b/toolkit/components/places/Database.h @@ -47,7 +47,7 @@ // This is the schema version. Update it at any schema change and add a // corresponding migrateVxx method below. -#define DATABASE_SCHEMA_VERSION 18 +#define DATABASE_SCHEMA_VERSION 19 // Fired after Places inited. #define TOPIC_PLACES_INIT_COMPLETE "places-init-complete" @@ -301,6 +301,7 @@ protected: nsresult MigrateV16Up(); nsresult MigrateV17Up(); nsresult MigrateV18Up(); + nsresult MigrateV19Up(); nsresult UpdateBookmarkRootTitles(); nsresult CheckAndUpdateGUIDs(); diff --git a/toolkit/components/places/Helpers.cpp b/toolkit/components/places/Helpers.cpp index 0f6f7499dce..1a5806ee791 100644 --- a/toolkit/components/places/Helpers.cpp +++ b/toolkit/components/places/Helpers.cpp @@ -46,6 +46,7 @@ #if defined(XP_OS2) #include "nsIRandomGenerator.h" #endif +#include "nsContentUtils.h" // The length of guids that are used by history and bookmarks. #define GUID_LENGTH 12 @@ -444,5 +445,64 @@ AsyncStatementTelemetryTimer::HandleCompletion(PRUint16 aReason) return NS_OK; } +// This is a temporary converter used by nsPlacesImportExportService until +// bug 482911 completes its js rewrite. +jsval +livemarkInfoToJSVal(PRInt64 aId, + const nsACString& aGUID, + const nsAString& aTitle, + PRInt64 aParentId, + PRInt32 aIndex, + nsCOMPtr& aFeedURI, + nsCOMPtr& aSiteURI) +{ + nsCOMPtr xpc = mozilla::services::GetXPConnect(); + NS_ENSURE_TRUE(xpc, JSVAL_NULL); + + nsAXPCNativeCallContext *ncc; + nsresult rv = xpc->GetCurrentNativeCallContext(&ncc); + NS_ENSURE_SUCCESS(rv, JSVAL_NULL); + JSContext *cx = nsnull; + rv = ncc->GetJSContext(&cx); + NS_ENSURE_SUCCESS(rv, JSVAL_NULL); + JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL); + NS_ENSURE_TRUE(obj, JSVAL_NULL); + + jsval id; + NS_ENSURE_TRUE(JS_NewNumberValue(cx, double(aId), &id), JSVAL_NULL); + + JSString* guid = JS_NewStringCopyN(cx, PromiseFlatCString(aGUID).get(), + aGUID.Length()); + NS_ENSURE_TRUE(guid, JSVAL_NULL); + + JSString* title = JS_NewUCStringCopyN(cx, PromiseFlatString(aTitle).get(), + aTitle.Length()); + NS_ENSURE_TRUE(title, JSVAL_NULL); + + jsval parentId; + NS_ENSURE_TRUE(JS_NewNumberValue(cx, double(aParentId), &parentId), JSVAL_NULL); + + jsval feedURI; + rv = nsContentUtils::WrapNative(cx, JS_GetGlobalForScopeChain(cx), + NS_ISUPPORTS_CAST(nsIURI*, aFeedURI), &feedURI); + NS_ENSURE_SUCCESS(rv, JSVAL_NULL); + + jsval siteURI; + rv = nsContentUtils::WrapNative(cx, JS_GetGlobalForScopeChain(cx), + NS_ISUPPORTS_CAST(nsIURI*, aSiteURI), &siteURI); + NS_ENSURE_SUCCESS(rv, JSVAL_NULL); + + if (!JS_DefineProperty(cx, obj, "id", id, NULL, NULL, JSPROP_ENUMERATE) || + !JS_DefineProperty(cx, obj, "guid", STRING_TO_JSVAL(guid), NULL, NULL, JSPROP_ENUMERATE) || + !JS_DefineProperty(cx, obj, "title", STRING_TO_JSVAL(title), NULL, NULL, JSPROP_ENUMERATE) || + !JS_DefineProperty(cx, obj, "parentId", parentId, NULL, NULL, JSPROP_ENUMERATE) || + !JS_DefineProperty(cx, obj, "index", INT_TO_JSVAL(aIndex), NULL, NULL, JSPROP_ENUMERATE) || + !JS_DefineProperty(cx, obj, "feedURI", feedURI, NULL, NULL, JSPROP_ENUMERATE) || + !JS_DefineProperty(cx, obj, "siteURI", siteURI, NULL, NULL, JSPROP_ENUMERATE)) { + return JSVAL_NULL; + } + return OBJECT_TO_JSVAL(obj); +} + } // namespace places } // namespace mozilla diff --git a/toolkit/components/places/Helpers.h b/toolkit/components/places/Helpers.h index ebfeb5e4ba8..600fa67df6b 100644 --- a/toolkit/components/places/Helpers.h +++ b/toolkit/components/places/Helpers.h @@ -48,6 +48,7 @@ #include "nsThreadUtils.h" #include "nsProxyRelease.h" #include "mozilla/Telemetry.h" +#include "jsapi.h" namespace mozilla { namespace places { @@ -295,6 +296,16 @@ private: const Telemetry::ID mHistogramId; const TimeStamp mStart; }; + +jsval +livemarkInfoToJSVal(PRInt64 aId, + const nsACString& aGUID, + const nsAString& aTitle, + PRInt64 aParentId, + PRInt32 aIndex, + nsCOMPtr& aFeedURI, + nsCOMPtr& aSiteURI); + } // namespace places } // namespace mozilla diff --git a/toolkit/components/places/History.cpp b/toolkit/components/places/History.cpp index 4017dfd2084..e30c5cc96a8 100644 --- a/toolkit/components/places/History.cpp +++ b/toolkit/components/places/History.cpp @@ -292,7 +292,7 @@ GetIntFromJSObject(JSContext* aCtx, NS_ENSURE_ARG(JSVAL_IS_PRIMITIVE(value)); NS_ENSURE_ARG(JSVAL_IS_NUMBER(value)); - jsdouble num; + double num; rc = JS_ValueToNumber(aCtx, value, &num); NS_ENSURE_TRUE(rc, NS_ERROR_UNEXPECTED); NS_ENSURE_ARG(IntType(num) == num); diff --git a/toolkit/components/places/Makefile.in b/toolkit/components/places/Makefile.in index 0235027184c..59120d76e38 100644 --- a/toolkit/components/places/Makefile.in +++ b/toolkit/components/places/Makefile.in @@ -59,6 +59,7 @@ IS_COMPONENT = 1 XPIDLSRCS += \ mozIAsyncHistory.idl \ mozIAsyncFavicons.idl \ + mozIAsyncLivemarks.idl \ mozIPlacesAutoComplete.idl \ nsIAnnotationService.idl \ nsIBrowserHistory.idl \ diff --git a/toolkit/components/places/PlacesDBUtils.jsm b/toolkit/components/places/PlacesDBUtils.jsm index 646e641345c..ee655e23594 100644 --- a/toolkit/components/places/PlacesDBUtils.jsm +++ b/toolkit/components/places/PlacesDBUtils.jsm @@ -611,18 +611,6 @@ let PlacesDBUtils = { "DROP TABLE moz_bm_reindex_temp " )); - // D.11 remove old livemarks status items - // Livemark status items are now static but some livemark has still old - // status items bookmarks inside it. We should remove them. - let removeLivemarkStaticItems = DBConn.createAsyncStatement( - "DELETE FROM moz_bookmarks WHERE type = :bookmark_type AND fk IN ( " + - "SELECT id FROM moz_places WHERE url = :lmloading OR url = :lmfailed " + - ")"); - removeLivemarkStaticItems.params["bookmark_type"] = PlacesUtils.bookmarks.TYPE_BOOKMARK; - removeLivemarkStaticItems.params["lmloading"] = "about:livemark-loading"; - removeLivemarkStaticItems.params["lmfailed"] = "about:livemark-failed"; - cleanupStatements.push(removeLivemarkStaticItems); - // D.12 Fix empty-named tags. // Tags were allowed to have empty names due to a UI bug. Fix them // replacing their title with "(notitle)". diff --git a/toolkit/components/places/PlacesUtils.jsm b/toolkit/components/places/PlacesUtils.jsm index 0729dbc6051..b4e63fa3930 100644 --- a/toolkit/components/places/PlacesUtils.jsm +++ b/toolkit/components/places/PlacesUtils.jsm @@ -55,8 +55,6 @@ const EXPORTED_SYMBOLS = [ , "PlacesSetPageAnnotationTransaction" , "PlacesEditBookmarkKeywordTransaction" , "PlacesEditBookmarkPostDataTransaction" -, "PlacesEditLivemarkSiteURITransaction" -, "PlacesEditLivemarkFeedURITransaction" , "PlacesEditItemDateAddedTransaction" , "PlacesEditItemLastModifiedTransaction" , "PlacesSortFolderByNameTransaction" @@ -327,8 +325,8 @@ var PlacesUtils = { case "bookmarks-service-ready": this._bookmarksServiceReady = true; while (this._bookmarksServiceObserversQueue.length > 0) { - let observer = this._bookmarksServiceObserversQueue.shift(); - this.bookmarks.addObserver(observer, false); + let observerInfo = this._bookmarksServiceObserversQueue.shift(); + this.bookmarks.addObserver(observerInfo.observer, observerInfo.weak); } break; } @@ -497,8 +495,13 @@ var PlacesUtils = { * @param aItemId * The id of the potential livemark. * @returns true if the item is a livemark. + * @deprecated see the new API in mozIAsyncLivemarks. */ itemIsLivemark: function PU_itemIsLivemark(aItemId) { + Cu.reportError("Synchronous livemarks methods and PlacesUtils livemarks " + + "utils (itemIsLivemark, nodeIsLivemarkContainer, " + + "nodeIsLivemarkItem) are deprecated and will be removed " + + "in a future release."); // If the Livemark service hasn't yet been initialized then // use the annotations service directly to avoid instanciating // it on startup. (bug 398300) @@ -513,6 +516,7 @@ var PlacesUtils = { * @param aNode * A result Node * @returns true if the node is a livemark container item + * @deprecated see the new API in mozIAsyncLivemarks. */ nodeIsLivemarkContainer: function PU_nodeIsLivemarkContainer(aNode) { return this.nodeIsFolder(aNode) && this.itemIsLivemark(aNode.itemId); @@ -523,6 +527,7 @@ var PlacesUtils = { * @param aNode * A result node * @returns true if the node is a livemark container item + * @deprecated see the new API in mozIAsyncLivemarks. */ nodeIsLivemarkItem: function PU_nodeIsLivemarkItem(aNode) { return aNode.parent && this.nodeIsLivemarkContainer(aNode.parent); @@ -588,6 +593,22 @@ var PlacesUtils = { return [cNode, false]; } + function gatherLivemarkUrl(aNode) { + try { + return PlacesUtils.annotations.getItemAnnotation(aNode.itemId, + this.LMANNO_SITEURI); + } catch (ex) { + return PlacesUtils.annotations.getItemAnnotation(aNode.itemId, + this.LMANNO_FEEDURI); + } + } + + function isLivemark(aNode) { + return PlacesUtils.nodeIsFolder(aNode) && + PlacesUtils.annotations.itemHasAnnotation(aNode.itemId, + this.LMANNO_FEEDURI); + } + switch (aType) { case this.TYPE_X_MOZ_PLACE: case this.TYPE_X_MOZ_PLACE_SEPARATOR: @@ -608,11 +629,10 @@ var PlacesUtils = { } case this.TYPE_X_MOZ_URL: { function gatherDataUrl(bNode) { - if (PlacesUtils.nodeIsLivemarkContainer(bNode)) { - let uri = PlacesUtils.livemarks.getSiteURI(bNode.itemId) || - PlacesUtils.livemarks.getFeedURI(bNode.itemId); - return uri.spec + NEWLINE + bNode.title; + if (isLivemark(bNode)) { + return gatherLivemarkUrl(bNode) + NEWLINE + bNode.title; } + if (PlacesUtils.nodeIsURI(bNode)) return (aOverrideURI || bNode.uri) + NEWLINE + bNode.title; // ignore containers and separators - items without valid URIs @@ -638,11 +658,11 @@ var PlacesUtils = { } // escape out potential HTML in the title let escapedTitle = bNode.title ? htmlEscape(bNode.title) : ""; - if (PlacesUtils.nodeIsLivemarkContainer(bNode)) { - let uri = PlacesUtils.livemarks.getSiteURI(bNode.itemId) || - PlacesUtils.livemarks.getFeedURI(bNode.itemId); - return "" + escapedTitle + "" + NEWLINE; + + if (isLivemark(bNode)) { + return "" + escapedTitle + "" + NEWLINE; } + if (PlacesUtils.nodeIsContainer(bNode)) { asContainer(bNode); let wasOpen = bNode.containerOpen; @@ -678,9 +698,10 @@ var PlacesUtils = { // Otherwise, we wrap as TYPE_UNICODE. function gatherDataText(bNode) { - if (PlacesUtils.nodeIsLivemarkContainer(bNode)) - return PlacesUtils.livemarks.getSiteURI(bNode.itemId) || - PlacesUtils.livemarks.getFeedURI(bNode.itemId); + if (isLivemark(bNode)) { + return gatherLivemarkUrl(bNode); + } + if (PlacesUtils.nodeIsContainer(bNode)) { asContainer(bNode); let wasOpen = bNode.containerOpen; @@ -1040,8 +1061,7 @@ var PlacesUtils = { }, /** - * Get all bookmarks for a URL, excluding items under tag or livemark - * containers. + * Get all bookmarks for a URL, excluding items under tags. */ getBookmarksForURI: function PU_getBookmarksForURI(aURI) { @@ -1050,9 +1070,6 @@ var PlacesUtils = { // filter the ids list return bmkIds.filter(function(aID) { var parentId = this.bookmarks.getFolderIdForItem(aID); - // Livemark child - if (this.itemIsLivemark(parentId)) - return false; var grandparentId = this.bookmarks.getFolderIdForItem(parentId); // item under a tag container if (grandparentId == this.tagsFolderId) @@ -1063,7 +1080,7 @@ var PlacesUtils = { /** * Get the most recently added/modified bookmark for a URL, excluding items - * under tag or livemark containers. + * under tags. * * @param aURI * nsIURI of the page we will look for. @@ -1084,42 +1101,12 @@ var PlacesUtils = { return itemId; var grandparentId = this.bookmarks.getFolderIdForItem(parentId); - if (grandparentId != this.tagsFolderId && - !this.itemIsLivemark(parentId)) + if (grandparentId != this.tagsFolderId) return itemId; } return -1; }, - /** - * Get the most recent folder item id for a feed URI. - * - * @param aURI - * nsIURI of the feed we will look for. - * @returns folder item id of the found livemark, or -1 if nothing is found. - */ - getMostRecentFolderForFeedURI: - function PU_getMostRecentFolderForFeedURI(aFeedURI) { - // If the Livemark service hasn't yet been initialized then - // use the annotations service directly to avoid instanciating - // it on startup. (bug 398300) - if (Object.getOwnPropertyDescriptor(this, "livemarks").value === undefined) { - var feedSpec = aFeedURI.spec - var annosvc = this.annotations; - var livemarks = annosvc.getItemsWithAnnotation(this.LMANNO_FEEDURI); - for (var i = 0; i < livemarks.length; i++) { - if (annosvc.getItemAnnotation(livemarks[i], this.LMANNO_FEEDURI) == feedSpec) - return livemarks[i]; - } - } - else { - // If the livemark service has already been instanciated, use it. - return this.livemarks.getLivemarkIdForFeedURI(aFeedURI); - } - - return -1; - }, - /** * Returns a nsNavHistoryContainerResultNode with forced excludeItems and * expandQueries. @@ -1409,10 +1396,24 @@ var PlacesUtils = { }, this); if (feedURI) { - id = this.livemarks.createLivemarkFolderOnly(aContainer, - aData.title, - siteURI, feedURI, - aIndex); + this.livemarks.addLivemark( + { title: aData.title + , feedURI: feedURI + , parentId: aContainer + , index: aIndex + , lastModified: aData.lastModified + , siteURI: siteURI + }, + (function(aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + let id = aLivemark.id; + if (aData.dateAdded) + this.bookmarks.setItemDateAdded(id, aData.dateAdded); + if (aData.annos && aData.annos.length) + this.setAnnotationsForItem(id, aData.annos); + } + }).bind(this) + ); } } else { @@ -2086,11 +2087,6 @@ var PlacesUtils = { + "FROM moz_bookmarks b " + "JOIN moz_places h on h.id = b.fk " + "WHERE h.url = :url " - + "AND NOT EXISTS( " - + "SELECT 1 FROM moz_items_annos a " - + "JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id " - + "WHERE a.item_id = b.parent AND n.name = :name " - + ") " ); this.registerShutdownFunction(function () { this._asyncGetBookmarksStmt.finalize(); @@ -2099,7 +2095,6 @@ var PlacesUtils = { let url = aURI instanceof Ci.nsIURI ? aURI.spec : aURI; this._asyncGetBookmarksStmt.params.url = url; - this._asyncGetBookmarksStmt.params.name = this.LMANNO_FEEDURI; // Storage does not guarantee that invoking cancel() on a statement // will cause a REASON_CANCELED. Thus we wrap the statement. @@ -2127,6 +2122,9 @@ var PlacesUtils = { * * @param aObserver * Object implementing nsINavBookmarkObserver + * @param [optional]aWeakOwner + * Whether to use weak ownership. + * * @note Correct functionality of lazy observers relies on the fact Places * notifies categories before real observers, and uses * PlacesCategoriesStarter component to kick-off the registration. @@ -2134,12 +2132,13 @@ var PlacesUtils = { _bookmarksServiceReady: false, _bookmarksServiceObserversQueue: [], addLazyBookmarkObserver: - function PU_addLazyBookmarkObserver(aObserver) { + function PU_addLazyBookmarkObserver(aObserver, aWeakOwner) { if (this._bookmarksServiceReady) { - this.bookmarks.addObserver(aObserver, false); + this.bookmarks.addObserver(aObserver, aWeakOwner === true); return; } - this._bookmarksServiceObserversQueue.push(aObserver); + this._bookmarksServiceObserversQueue.push({ observer: aObserver, + weak: aWeakOwner === true }); }, /** @@ -2151,14 +2150,19 @@ var PlacesUtils = { removeLazyBookmarkObserver: function PU_removeLazyBookmarkObserver(aObserver) { if (this._bookmarksServiceReady) { - this.bookmarks.removeObserver(aObserver, false); + this.bookmarks.removeObserver(aObserver); return; } - let index = this._bookmarksServiceObserversQueue.indexOf(aObserver); + let index = -1; + for (let i = 0; + i < this._bookmarksServiceObserversQueue.length && index == -1; i++) { + if (this._bookmarksServiceObserversQueue[i].observer === aObserver) + index = i; + } if (index != -1) { this._bookmarksServiceObserversQueue.splice(index, 1); } - }, + } }; /** @@ -2224,9 +2228,11 @@ XPCOMUtils.defineLazyServiceGetter(PlacesUtils, "tagging", "@mozilla.org/browser/tagging-service;1", "nsITaggingService"); -XPCOMUtils.defineLazyServiceGetter(PlacesUtils, "livemarks", - "@mozilla.org/browser/livemark-service;2", - "nsILivemarkService"); +XPCOMUtils.defineLazyGetter(PlacesUtils, "livemarks", function() { + return Cc["@mozilla.org/browser/livemark-service;2"]. + getService(Ci.nsILivemarkService). + QueryInterface(Ci.mozIAsyncLivemarks); +}); XPCOMUtils.defineLazyGetter(PlacesUtils, "transactionManager", function() { let tm = Cc["@mozilla.org/transactionmanager;1"]. @@ -2629,8 +2635,7 @@ PlacesCreateSeparatorTransaction.prototype = { /** * Transaction for creating a new livemark item. * - * @see nsILivemarksService::createLivemark for documentation regarding the - * first three arguments. + * @see mozIAsyncLivemarks for documentation regarding the arguments. * * @param aFeedURI * nsIURI of the feed @@ -2664,25 +2669,41 @@ PlacesCreateLivemarkTransaction.prototype = { doTransaction: function CLTXN_doTransaction() { - this.item.id = PlacesUtils.livemarks.createLivemark(this.item.parentId, - this.item.title, - this.item.siteURI, - this.item.feedURI, - this.item.index); - if (this.item.annotations && this.item.annotations.length > 0) - PlacesUtils.setAnnotationsForItem(this.item.id, this.item.annotations); - if (this.item.guid) - PlacesUtils.bookmarks.setItemGUID(this.item.id, this.item.guid); + PlacesUtils.livemarks.addLivemark( + { title: this.item.title + , feedURI: this.item.feedURI + , parentId: this.item.parentId + , index: this.item.index + , siteURI: this.item.siteURI + }, + (function(aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + this.item.id = aLivemark.id; + if (this.item.annotations && this.item.annotations.length > 0) { + PlacesUtils.setAnnotationsForItem(this.item.id, + this.item.annotations); + } + if (this.item.guid) + PlacesUtils.bookmarks.setItemGUID(this.item.id, this.item.guid); + } + }).bind(this) + ); }, undoTransaction: function CLTXN_undoTransaction() { - // If a GUID exists for this item, preserve it before removing the item. - if (PlacesUtils.annotations.itemHasAnnotation(this.item.id, - PlacesUtils.GUID_ANNO)) - this.item.guid = PlacesUtils.bookmarks.getItemGUID(this.item.id); + // The getLivemark callback is expected to receive a failure status but it + // is used just to serialize, so doesn't matter. + PlacesUtils.livemarks.getLivemark( + { id: this.item.id }, + (function (aStatus, aLivemark) { + // If a GUID exists for this item, preserve it before removing the item. + if (PlacesUtils.annotations.itemHasAnnotation(this.item.id, PlacesUtils.GUID_ANNO)) + this.item.guid = PlacesUtils.bookmarks.getItemGUID(this.item.id); - PlacesUtils.bookmarks.removeItem(this.item.id); + PlacesUtils.bookmarks.removeItem(this.item.id); + }).bind(this) + ); } }; @@ -2713,8 +2734,6 @@ function PlacesRemoveLivemarkTransaction(aLivemarkId) this.item.annotations = annos.filter(function(aValue, aIndex, aArray) { return annosToExclude.indexOf(aValue.name) == -1; }); - this.item.feedURI = PlacesUtils.livemarks.getFeedURI(this.item.id); - this.item.siteURI = PlacesUtils.livemarks.getSiteURI(this.item.id); this.item.dateAdded = PlacesUtils.bookmarks.getItemDateAdded(this.item.id); this.item.lastModified = PlacesUtils.bookmarks.getItemLastModified(this.item.id); @@ -2725,22 +2744,45 @@ PlacesRemoveLivemarkTransaction.prototype = { doTransaction: function RLTXN_doTransaction() { - this.item.index = PlacesUtils.bookmarks.getItemIndex(this.item.id); - PlacesUtils.bookmarks.removeItem(this.item.id); + PlacesUtils.livemarks.getLivemark( + { id: this.item.id }, + (function (aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + this.item.feedURI = aLivemark.feedURI; + this.item.siteURI = aLivemark.siteURI; + + PlacesUtils.bookmarks.removeItem(this.item.id); + } + }).bind(this) + ); }, undoTransaction: function RLTXN_undoTransaction() { - this.item.id = PlacesUtils.livemarks.createLivemark(this.item.parentId, - this.item.title, - this.item.siteURI, - this.item.feedURI, - this.item.index); - PlacesUtils.bookmarks.setItemDateAdded(this.item.id, this.item.dateAdded); - PlacesUtils.bookmarks.setItemLastModified(this.item.id, - this.item.lastModified); - // Restore annotations - PlacesUtils.setAnnotationsForItem(this.item.id, this.item.annotations); + // Undo work must be serialized, otherwise won't be able to know the + // feedURI and siteURI of the livemark. + // The getLivemark callback is expected to receive a failure status but it + // is used just to serialize, so doesn't matter. + PlacesUtils.livemarks.getLivemark( + { id: this.item.id }, + (function () { + let addLivemarkCallback = (function(aStatus, aLivemark) { + if (Components.isSuccessCode(aStatus)) { + let itemId = aLivemark.id; + PlacesUtils.bookmarks.setItemDateAdded(itemId, this.item.dateAdded); + PlacesUtils.setAnnotationsForItem(itemId, this.item.annotations); + } + }).bind(this); + PlacesUtils.livemarks.addLivemark({ parentId: this.item.parentId + , title: this.item.title + , siteURI: this.item.siteURI + , feedURI: this.item.feedURI + , index: this.item.index + , lastModified: this.item.lastModified + }, + addLivemarkCallback); + }).bind(this) + ); } }; @@ -2816,9 +2858,9 @@ function PlacesRemoveItemTransaction(aItemId) return new PlacesUntagURITransaction(uri, [parent]); } - // if the item is a livemark container we will not save its children and - // will use createLivemark to undo. - if (PlacesUtils.itemIsLivemark(aItemId)) + // if the item is a livemark container we will not save its children. + if (PlacesUtils.annotations.itemHasAnnotation(aItemId, + PlacesUtils.LMANNO_FEEDURI)) return new PlacesRemoveLivemarkTransaction(aItemId); this.item = new TransactionItemCache(); @@ -2865,8 +2907,8 @@ PlacesRemoveItemTransaction.prototype = { PlacesUtils.bookmarks.removeItem(this.item.id); - // If this was the last bookmark (excluding tag-items and livemark - // children) for this url, persist the tags. + // If this was the last bookmark (excluding tag-items) for this url, + // persist the tags. if (tags && PlacesUtils.getMostRecentBookmarkForURI(this.item.uri) == -1) { this.item.tags = tags; } @@ -3194,76 +3236,6 @@ PlacesEditBookmarkPostDataTransaction.prototype = { }; -/** - * Transaction for editing a live bookmark's site URI. - * - * @param aLivemarkId - * id of the livemark - * @param aSiteURI - * new site uri - * - * @return nsITransaction object - */ -function PlacesEditLivemarkSiteURITransaction(aLivemarkId, aSiteURI) -{ - this.item = new TransactionItemCache(); - this.item.id = aLivemarkId; - this.new = new TransactionItemCache(); - this.new.siteURI = aSiteURI; -} - -PlacesEditLivemarkSiteURITransaction.prototype = { - __proto__: BaseTransaction.prototype, - - doTransaction: function ELSUTXN_doTransaction() - { - this.item.siteURI = PlacesUtils.livemarks.getSiteURI(this.item.id); - PlacesUtils.livemarks.setSiteURI(this.item.id, this.new.siteURI); - }, - - undoTransaction: function ELSUTXN_undoTransaction() - { - PlacesUtils.livemarks.setSiteURI(this.item.id, this.item.siteURI); - } -}; - - -/** - * Transaction for editting a live bookmark's feed URI. - * - * @param aLivemarkId - * id of the livemark - * @param aFeedURI - * new feed uri - * - * @return nsITransaction object - */ -function PlacesEditLivemarkFeedURITransaction(aLivemarkId, aFeedURI) -{ - this.item = new TransactionItemCache(); - this.item.id = aLivemarkId; - this.new = new TransactionItemCache(); - this.new.feedURI = aFeedURI; -} - -PlacesEditLivemarkFeedURITransaction.prototype = { - __proto__: BaseTransaction.prototype, - - doTransaction: function ELFUTXN_doTransaction() - { - this.item.feedURI = PlacesUtils.livemarks.getFeedURI(this.item.id); - PlacesUtils.livemarks.setFeedURI(this.item.id, this.new.feedURI); - PlacesUtils.livemarks.reloadLivemarkFolder(this.item.id); - }, - - undoTransaction: function ELFUTXN_undoTransaction() - { - PlacesUtils.livemarks.setFeedURI(this.item.id, this.item.feedURI); - PlacesUtils.livemarks.reloadLivemarkFolder(this.item.id); - } -}; - - /** * Transaction for editing an item's date added property. * diff --git a/toolkit/components/places/SQLFunctions.cpp b/toolkit/components/places/SQLFunctions.cpp index 443b58bee95..7b143d29dec 100644 --- a/toolkit/components/places/SQLFunctions.cpp +++ b/toolkit/components/places/SQLFunctions.cpp @@ -492,17 +492,7 @@ namespace places { nsRefPtr getPageInfo = DB->GetStatement( "SELECT typed, hidden, visit_count, " "(SELECT count(*) FROM moz_historyvisits WHERE place_id = :page_id), " - "EXISTS ( " - "SELECT 1 FROM moz_bookmarks " - "WHERE fk = :page_id " - "AND NOT EXISTS( " - "SELECT 1 " - "FROM moz_items_annos a " - "JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id " - "WHERE n.name = :anno_name " - "AND a.item_id = parent " - ") " - "), " + "EXISTS (SELECT 1 FROM moz_bookmarks WHERE fk = :page_id), " "(url > 'place:' AND url < 'place;') " "FROM moz_places " "WHERE id = :page_id " @@ -512,9 +502,6 @@ namespace places { rv = getPageInfo->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId); NS_ENSURE_SUCCESS(rv, rv); - rv = getPageInfo->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), - NS_LITERAL_CSTRING("livemark/feedURI")); - NS_ENSURE_SUCCESS(rv, rv); bool hasResult; rv = getPageInfo->ExecuteStep(&hasResult); diff --git a/toolkit/components/places/mozIAsyncLivemarks.idl b/toolkit/components/places/mozIAsyncLivemarks.idl new file mode 100644 index 00000000000..15c6f43fe53 --- /dev/null +++ b/toolkit/components/places/mozIAsyncLivemarks.idl @@ -0,0 +1,200 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +%{C++ +#include "jsapi.h" +%} + +interface nsIURI; + +interface mozILivemarkCallback; +interface mozILivemarkInfo; +interface mozILivemark; + +interface nsINavHistoryResultObserver; + +[scriptable, uuid(addaa7c5-bd85-4c83-9c21-81c8a825c358)] +interface mozIAsyncLivemarks : nsISupports +{ + /** + * Creates a new livemark + * + * @param aLivemarkInfo + * mozILivemarkInfo object containing at least title, parentId, + * index and feedURI of the livemark to create. + * @param [optional] aCallback + * Invoked when the creation process is done. In case of failure will + * receive an error code. + * + * @throws NS_ERROR_INVALID_ARG if the supplied information is insufficient + * for the creation. + */ + void addLivemark(in jsval aLivemarkInfo, + [optional]in mozILivemarkCallback aCallback); + + /** + * Removes an existing livemark. + * + * @param aLivemarkInfo + * mozILivemarkInfo object containing either an id or a guid of the + * livemark to remove. + * @param [optional] aCallback + * Invoked when the removal process is done. In case of failure will + * receive an error code. + * + * @throws NS_ERROR_INVALID_ARG if the id/guid is invalid. + */ + void removeLivemark(in jsval aLivemarkInfo, + [optional]in mozILivemarkCallback aCallback); + + /** + * Gets an existing livemark. + * + * @param aLivemarkInfo + * mozILivemarkInfo object containing either an id or a guid of the + * livemark to retrieve. + * @param aCallback + * Invoked when the fetching process is done. In case of failure will + * receive an error code. + * + * @throws NS_ERROR_INVALID_ARG if the id/guid is invalid or an invalid + * callback is provided. + */ + void getLivemark(in jsval aLivemarkInfo, + in mozILivemarkCallback aCallback); + + /** + * Forces a reload of all livemarks, whether or not they've expired. + */ + void reloadLivemarks(); +}; + +[scriptable, function, uuid(62a426f9-39a6-42f0-ad48-b7404d48188f)] +interface mozILivemarkCallback : nsISupports +{ + /** + * Invoked when a livemark is added, removed or retrieved. + * + * @param aStatus + * Whether the request was completed successfully. + * Use Components.isSuccessCode(aStatus) to check this. + * @param aLivemark + * A mozILivemark object representing the livemark, or null on removal. + */ + void onCompletion(in nsresult aStatus, + in mozILivemark aLivemark); +}; + +[scriptable, uuid(6e40d5b1-ce48-4458-8b68-6bee17d30ef3)] +interface mozILivemarkInfo : nsISupports +{ + /** + * Id of the bookmarks folder representing this livemark. + */ + readonly attribute long long id; + + /** + * The globally unique identifier of this livemark. + */ + readonly attribute ACString guid; + + /** + * Title of this livemark. + */ + readonly attribute AString title; + + /** + * Id of the bookmarks parent folder containing this livemark. + */ + readonly attribute long long parentId; + + /** + * The position of this livemark in the bookmarks parent folder. + */ + readonly attribute long index; + + /** + * Time this livemark's details were last modified. Doesn't track changes to + * the livemark contents. + */ + readonly attribute PRTime lastModified; + + /** + * The URI of the syndication feed associated with this livemark. + */ + readonly attribute nsIURI feedURI; + + /** + * The URI of the website associated with this livemark. + */ + readonly attribute nsIURI siteURI; +}; + +[scriptable, uuid(9f6fdfae-db9a-4bd8-bde1-148758cf1b18)] +interface mozILivemark : mozILivemarkInfo +{ + // Indicates the livemark is inactive. + const unsigned short STATUS_READY = 0; + // Indicates the livemark is fetching new contents. + const unsigned short STATUS_LOADING = 1; + // Indicates the livemark failed to fetch new contents. + const unsigned short STATUS_FAILED = 2; + + /** + * Status of this livemark. One of the STATUS_* constants above. + */ + readonly attribute unsigned short status; + + /** + * Reload livemark contents if they are expired or if forced to do so. + * + * @param [optional]aForceUpdate + * If set to true forces a reload even if contents are still valid. + * + * @note The update process is asynchronous, it's possible to register a + * result observer to be notified of updated contents through + * registerForUpdates. + */ + void reload([optional]in boolean aForceUpdate); + + /** + * Returns an array of nsINavHistoryResultNode objects, representing children + * of this livemark. The nodes will have aContainerNode as parent. + * + * @param aContainerNode + * Object implementing nsINavHistoryContainerResultNode, to be used as + * parent of the livemark nodes. + */ + jsval getNodesForContainer(in jsval aContainerNode); + + /** + * Registers a container node for updates on this livemark. + * When the livemark contents change, an invalidateContainer(aContainerNode) + * request is sent to aResultObserver. + * + * @param aContainerNode + * Object implementing nsINavHistoryContainerResultNode, representing + * this livemark. + * @param aResultObserver + * The nsINavHistoryResultObserver that should be notified of changes + * to the livemark contents. + */ + void registerForUpdates(in jsval aContainerNode, + in nsINavHistoryResultObserver aResultObserver); + + /** + * Unregisters a previously registered container node. + * + * @param aContainerNode + * Object implementing nsINavHistoryContainerResultNode, representing + * this livemark. + * + * @note it's suggested to always unregister containers that are no more used, + * to free up the associated resources. A good time to do so is when + * the container gets closed. + */ + void unregisterForUpdates(in jsval aContainerNode); +}; diff --git a/toolkit/components/places/nsILivemarkService.idl b/toolkit/components/places/nsILivemarkService.idl index eab87ae30e5..2d62473824e 100644 --- a/toolkit/components/places/nsILivemarkService.idl +++ b/toolkit/components/places/nsILivemarkService.idl @@ -40,6 +40,13 @@ #include "nsISupports.idl" +/** + * WARNING: + * + * This interface is deprecated and will be removed in a future release. + * Use the mozIAsyncLivemarks interface instead. + */ + interface nsIURI; interface nsINavBookmarksService; @@ -50,11 +57,19 @@ interface nsILivemarkService : nsISupports * Starts the livemark refresh timer. * Being able to manually control this allows activity such * as bookmarks import to occur without kicking off HTTP traffic. + * + * @note This is a no-op and exists just as a compatibility shim. + * + * @deprecated use the mozIAsyncLivemarks interface instead. */ void start(); /** * Stop the livemark refresh timer. + * + * @note This is a no-op and exists just as a compatibility shim. + * + * @deprecated use the mozIAsyncLivemarks interface instead. */ void stopUpdateLivemarks(); @@ -67,6 +82,8 @@ interface nsILivemarkService : nsISupports * @param index The index to insert at, or * nsINavBookmarksService.DEFAULT_INDEX to append. * @returns the ID of the folder for the livemark + * + * @deprecated use the mozIAsyncLivemarks interface instead. */ long long createLivemark(in long long folder, in AString name, @@ -93,6 +110,8 @@ interface nsILivemarkService : nsISupports * false otherwise * * @throws NS_ERROR_INVALID_ARG if the folder ID isn't known + * + * @deprecated use the mozIAsyncLivemarks interface instead. */ boolean isLivemark(in long long folder); @@ -103,6 +122,8 @@ interface nsILivemarkService : nsISupports * Feed URI to look for. * * @returns the found livemark folder id, or -1 if nothing was found. + * + * @deprecated use the mozIAsyncLivemarks interface instead. */ long long getLivemarkIdForFeedURI(in nsIURI aFeedURI); @@ -118,6 +139,8 @@ interface nsILivemarkService : nsISupports * a folder that isn't a livemark container * @throws NS_ERROR_MALFORMED_URI if the site URI annotation has * somehow been corrupted (and can't be turned into an nsIURI) + * + * @deprecated use the mozIAsyncLivemarks interface instead. */ nsIURI getSiteURI(in long long container); @@ -131,6 +154,10 @@ interface nsILivemarkService : nsISupports * @throws NS_ERROR_INVALID_ARG if the folder ID isn't known or identifies * a folder that isn't a livemark container; also if the siteURI * argument isn't a valid nsIURI object (or null) + * + * @note This is a no-op and exists just as a compatibility shim. + * + * @deprecated use the mozIAsyncLivemarks interface instead. */ void setSiteURI(in long long container, in nsIURI siteURI); @@ -147,6 +174,8 @@ interface nsILivemarkService : nsISupports * a folder that isn't a livemark container * @throws NS_ERROR_MALFORMED_URI if the site URI annotation has * somehow been corrupted (and can't be turned into an nsIURI) + * + * @deprecated use the mozIAsyncLivemarks interface instead. */ nsIURI getFeedURI(in long long container); @@ -163,18 +192,26 @@ interface nsILivemarkService : nsISupports * @throws NS_ERROR_INVALID_ARG if the folder ID isn't known or identifies * a folder that isn't a livemark container; also if the feedURI * argument isn't a valid nsIURI object + * + * @note This is a no-op and exists just as a compatibility shim. + * + * @deprecated use the mozIAsyncLivemarks interface instead. */ void setFeedURI(in long long container, in nsIURI feedURI); - /** - * Reloads all livemark subscriptions, whether or not they've expired. - */ + /** + * Reloads all livemark subscriptions, whether or not they've expired. + * + * @deprecated use the mozIAsyncLivemarks interface instead. + */ void reloadAllLivemarks(); - /** - * Reloads the livemark with this folder ID, whether or not it's expired. - * @param folderID The ID of the folder to be reloaded - */ + /** + * Reloads the livemark with this folder ID, whether or not it's expired. + * @param folderID The ID of the folder to be reloaded + * + * @deprecated use the mozIAsyncLivemarks interface instead. + */ void reloadLivemarkFolder(in long long folderID); }; diff --git a/toolkit/components/places/nsINavHistoryService.idl b/toolkit/components/places/nsINavHistoryService.idl index fdcf3ef0029..c22783f6d63 100644 --- a/toolkit/components/places/nsINavHistoryService.idl +++ b/toolkit/components/places/nsINavHistoryService.idl @@ -1040,7 +1040,7 @@ interface nsINavHistoryQuery : nsISupports /** * This object represents the global options for executing a query. */ -[scriptable, uuid(2d8ff86b-f8c2-451c-8a1a-1ff0749a074e)] +[scriptable, uuid(d46a1ae7-aef8-47a2-9a5c-e6347253f9b2)] interface nsINavHistoryQueryOptions : nsISupports { /** @@ -1188,15 +1188,6 @@ interface nsINavHistoryQueryOptions : nsISupports */ attribute boolean excludeReadOnlyFolders; - /** - * This option excludes items from a bookmarks query - * if the parent of the item has this annotation. - * An example is to exclude livemark items - * (parent folders have the "livemark/feedURI" annotation) - * Ignored for queries over history. - */ - attribute AUTF8String excludeItemIfParentHasAnnotation; - /** * When set, allows items with "place:" URIs to appear as containers, * with the container's contents filled in from the stored query. diff --git a/toolkit/components/places/nsLivemarkService.js b/toolkit/components/places/nsLivemarkService.js index 802cbddb9ce..1f527906b28 100644 --- a/toolkit/components/places/nsLivemarkService.js +++ b/toolkit/components/places/nsLivemarkService.js @@ -1,362 +1,606 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License - * at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and - * limitations under the License. - * - * The Original Code is the Places JS Livemark Service. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Annie Sullivan (C++ author) - * Joe Hughes - * Vladimir Vukicevic - * Masayuki Nakano - * Robert Sayre (JS port) - * Phil Ringnalda - * Marco Bonardo - * Takeshi Ichimaru - * - * Alternatively, the contents of this file may be used under the - * terms of either the GNU General Public License Version 2 or later - * (the "GPL"), or the GNU Lesser General Public License Version 2.1 - * or later (the "LGPL"), in which case the provisions of the GPL or - * the LGPL are applicable instead of those above. If you wish to - * allow use of your version of this file only under the terms of - * either the GPL or the LGPL, and not to allow others to use your - * version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the - * notice and other provisions required by the GPL or the LGPL. If you - * do not delete the provisions above, a recipient may use your - * version of this file under the terms of any one of the MPL, the GPL - * or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - -/* Update Behavior: - * - * The update timer is started via nsILivemarkService.start(). it fires - * immediately and by default every 15 minutes (is dynamically calculated as - * gExpiration/4), with a maximum limit of 1 hour. - * - * When the update timer fires, it iterates over the list of livemarks, and will - * refresh a livemark *only* if it's expired. The update is done in chunks and - * each chunk is separated by a delay. - * - * The expiration time for a livemark is determined by using information - * provided by the server when the feed was requested, specifically - * nsICacheEntryInfo.expirationTime. If no information was provided by the - * server, the default expiration time is 1 hour. - * - * Users can modify the default expiration time via the following preferences: - * browser.bookmarks.livemark_refresh_seconds: seconds between updates. - * browser.bookmarks.livemark_refresh_limit_count: number of livemarks in a chunk. - * browser.bookmarks.livemark_refresh_delay_time: seconds between each chunk. - */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; +const Cu = Components.utils; -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); +//////////////////////////////////////////////////////////////////////////////// +//// Modules +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"); - XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); -XPCOMUtils.defineLazyServiceGetter(this, "idle", - "@mozilla.org/widget/idleservice;1", - "nsIIdleService"); +//////////////////////////////////////////////////////////////////////////////// +//// Services XPCOMUtils.defineLazyServiceGetter(this, "secMan", "@mozilla.org/scriptsecuritymanager;1", "nsIScriptSecurityManager"); +XPCOMUtils.defineLazyGetter(this, "asyncHistory", function () { + // Lazily add an history observer when it's actually needed. + PlacesUtils.history.addObserver(PlacesUtils.livemarks, true); + return Cc["@mozilla.org/browser/history;1"].getService(Ci.mozIAsyncHistory); +}); +//////////////////////////////////////////////////////////////////////////////// +//// Constants + +// Security flags for checkLoadURIWithPrincipal. const SEC_FLAGS = Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL; -const PREF_REFRESH_SECONDS = "browser.bookmarks.livemark_refresh_seconds"; -const PREF_REFRESH_LIMIT_COUNT = "browser.bookmarks.livemark_refresh_limit_count"; -const PREF_REFRESH_DELAY_TIME = "browser.bookmarks.livemark_refresh_delay_time"; +// Delay between reloads of consecute livemarks. +const RELOAD_DELAY_MS = 500; +// Expire livemarks after this time. +const EXPIRE_TIME_MS = 3600000; // 1 hour. +// Expire livemarks after this time on error. +const ONERROR_EXPIRE_TIME_MS = 300000; // 5 minutes. -// Expire livemarks after 1 hour by default (milliseconds). -let gExpiration = 3600000; - -// Number of livemarks that are read at once. -let gLimitCount = 1; - -// Interval in seconds between refreshes of each group of livemarks. -let gDelayTime = 3; - -// Expire livemarks after this time on error (milliseconds). -const ERROR_EXPIRATION = 600000; - -// Time after which we will stop checking for livemarks updates (milliseconds). -const IDLE_TIMELIMIT = 1800000; - -// Maximum time between update checks (milliseconds). -// This cap is used only if the user sets a very high expiration time (>4h) -const MAX_REFRESH_TIME = 3600000; -// Minimum time between update checks, used to avoid flooding servers. -const MIN_REFRESH_TIME = 600000; - -// Tracks the loading status -const STATUS = { - IDLE: 0, - LOADING: 1, - FAILED: 2, -} - -function LivemarkService() { - this._loadPrefs(); - - // Cache of Livemark objects, hashed by folderId. - XPCOMUtils.defineLazyGetter(this, "_livemarks", function () { - let livemarks = {}; - PlacesUtils.annotations - .getItemsWithAnnotation(PlacesUtils.LMANNO_FEEDURI) - .forEach(function (aFolderId) { - livemarks[aFolderId] = new Livemark(aFolderId); - }); - return livemarks; - }); +//////////////////////////////////////////////////////////////////////////////// +//// LivemarkService +function LivemarkService() +{ // Cleanup on shutdown. - Services.obs.addObserver(this, PlacesUtils.TOPIC_SHUTDOWN, false); + Services.obs.addObserver(this, PlacesUtils.TOPIC_SHUTDOWN, true); + + // Observe bookmarks and history, but don't init the services just for that. + PlacesUtils.addLazyBookmarkObserver(this, true); - // Observe bookmarks changes. - PlacesUtils.addLazyBookmarkObserver(this); + // Asynchronously build the livemarks cache. + this._ensureAsynchronousCache(); } LivemarkService.prototype = { - _updateTimer: null, - start: function LS_start() { - if (this._updateTimer) { + // Cache of Livemark objects, hashed by bookmarks folder ids. + _livemarks: {}, + // Hash associating guids to bookmarks folder ids. + _guids: {}, + + get _populateCacheSQL() + { + function getAnnoSQLFragment(aAnnoParam) { + return "SELECT a.content " + + "FROM moz_items_annos a " + + "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " + + "WHERE a.item_id = b.id " + + "AND n.name = " + aAnnoParam; + } + + return "SELECT b.id, b.title, b.parent, b.position, b.guid, b.lastModified, " + + "(" + getAnnoSQLFragment(":feedURI_anno") + ") AS feedURI, " + + "(" + getAnnoSQLFragment(":siteURI_anno") + ") AS siteURI " + + "FROM moz_bookmarks b " + + "JOIN moz_items_annos a ON a.item_id = b.id " + + "JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id " + + "WHERE b.type = :folder_type " + + "AND n.name = :feedURI_anno "; + }, + + _ensureAsynchronousCache: function LS__ensureAsynchronousCache() + { + let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + let stmt = db.createAsyncStatement(this._populateCacheSQL); + stmt.params.folder_type = Ci.nsINavBookmarksService.TYPE_FOLDER; + stmt.params.feedURI_anno = PlacesUtils.LMANNO_FEEDURI; + stmt.params.siteURI_anno = PlacesUtils.LMANNO_SITEURI; + + let livemarkSvc = this; + this._pendingStmt = stmt.executeAsync({ + handleResult: function LS_handleResult(aResults) + { + for (let row = aResults.getNextRow(); row; row = aResults.getNextRow()) { + let id = row.getResultByName("id"); + let siteURL = row.getResultByName("siteURI"); + let guid = row.getResultByName("guid"); + livemarkSvc._livemarks[id] = + new Livemark({ id: id, + guid: guid, + title: row.getResultByName("title"), + parentId: row.getResultByName("parent"), + index: row.getResultByName("position"), + lastModified: row.getResultByName("lastModified"), + feedURI: NetUtil.newURI(row.getResultByName("feedURI")), + siteURI: siteURL ? NetUtil.newURI(siteURL) : null, + }); + livemarkSvc._guids[guid] = id; + } + }, + handleError: function LS_handleError(aErr) + { + Cu.reportError("AsyncStmt error (" + aErr.result + "): '" + aErr.message); + }, + handleCompletion: function LS_handleCompletion() { + livemarkSvc._pendingStmt = null; + } + }); + stmt.finalize(); + }, + + _onCacheReady: function LS__onCacheReady(aCallback) + { + if (this._pendingStmt) { + // The cache is still being populated, so enqueue the job to the Storage + // async thread. Ideally this should just dispatch a runnable to it, + // that would call back on the main thread, but bug 608142 made that + // impossible. Thus just enqueue the cheapest query possible. + let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + let stmt = db.createAsyncStatement("PRAGMA encoding"); + stmt.executeAsync({ + handleError: function () {}, + handleResult: function () {}, + handleCompletion: function ETAT_handleCompletion() + { + aCallback(); + } + }); + stmt.finalize(); + } + else { + // The callbacks should always be enqueued per the interface. + // Just enque on the main thread. + Services.tm.mainThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL); + } + }, + + _startReloadTimer: function LS__startReloadTimer() + { + if (this._reloadTimer) { + this._reloadTimer.cancel(); + } + else { + this._reloadTimer = Cc["@mozilla.org/timer;1"] + .createInstance(Ci.nsITimer); + } + this._reloadTimer.initWithCallback(this._reloadNextLivemark.bind(this), + RELOAD_DELAY_MS, + Ci.nsITimer.TYPE_ONE_SHOT); + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsIObserver + + observe: function LS_observe(aSubject, aTopic, aData) + { + if (aTopic == PlacesUtils.TOPIC_SHUTDOWN) { + if (this._pendingStmt) { + this._pendingStmt.cancel(); + this._pendingStmt = null; + // Initialization never finished, so just bail out. + return; + } + + if (this._reloadTimer) { + this._reloadTimer.cancel(); + delete this._reloadTimer; + } + + // Stop any ongoing update. + for each (let livemark in this._livemarks) { + livemark.terminate(); + } + this._livemarks = {}; + } + }, + + ////////////////////////////////////////////////////////////////////////////// + //// Deprecated nsILivemarkService methods + + _reportDeprecatedMethod: function DEPRECATED_LS__reportDeprecatedMethod() + { + let oldFuncName = arguments.callee.caller.name.slice(14); + Cu.reportError(oldFuncName + " is deprecated and will be removed in a " + + "future release. Check the nsILivemarkService interface."); + }, + + _ensureSynchronousCache: function DEPRECATED_LS__ensureSynchronousCache() + { + if (!this._pendingStmt) { return; } + this._pendingStmt.cancel(); + this._pendingStmt = null; - // start is called in delayed startup, 5s after browser startup - // we do a first check of the livemarks here, next checks will be on timer - // browser start => 5s => this.start() => check => refresh_time => check - this._checkAllLivemarks(); + let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + let stmt = db.createStatement(this._populateCacheSQL); + stmt.params.folder_type = Ci.nsINavBookmarksService.TYPE_FOLDER; + stmt.params.feedURI_anno = PlacesUtils.LMANNO_FEEDURI; + stmt.params.siteURI_anno = PlacesUtils.LMANNO_SITEURI; + + while (stmt.executeStep()) { + let id = stmt.row.id; + let siteURL = stmt.row.siteURI; + let guid = stmt.row.guid; + this._livemarks[id] = + new Livemark({ id: id, + guid: guid, + title: stmt.row.title, + parentId: stmt.row.parent, + index: stmt.row.position, + lastModified: stmt.row.lastModified, + feedURI: NetUtil.newURI(stmt.row.feedURI), + siteURI: siteURL ? NetUtil.newURI(siteURL) : null, + }); + this._guids[guid] = id; + } + stmt.finalize(); }, - stopUpdateLivemarks: function LS_stopUpdateLivemarks() { - for each (let livemark in this._livemarks) { - livemark.abort(); - } - // Stop the update timer. - if (this._updateTimer) { - this._updateTimer.cancel(); - this._updateTimer = null; - } + start: function DEPRECATED_LS_start() + { + this._reportDeprecatedMethod(); }, - _loadPrefs: function LS__loadPrefs() { - try { - let livemarkRefresh = Services.prefs.getIntPref(PREF_REFRESH_SECONDS); - // Don't allow setting a too small timeout. - gExpiration = Math.max(livemarkRefresh * 1000, MIN_REFRESH_TIME); - } - catch (ex) { /* no pref, use default */ } - - try { - let limitCount = Services.prefs.getIntPref(PREF_REFRESH_LIMIT_COUNT); - // Don't allow 0 or negative values. - gLimitCount = Math.max(limitCount, gLimitCount); - } - catch (ex) { /* no pref, use default */ } - - try { - let delayTime = Services.prefs.getIntPref(PREF_REFRESH_DELAY_TIME); - // Don't allow too small delays. - gDelayTime = Math.max(delayTime, gDelayTime); - } - catch (ex) { /* no pref, use default */ } + stopUpdateLivemarks: function DEPRECATED_LS_stopUpdateLivemarks() + { + this._reportDeprecatedMethod(); }, - // nsIObserver - observe: function LS_observe(aSubject, aTopic, aData) { - if (aTopic == PlacesUtils.TOPIC_SHUTDOWN) { - Services.obs.removeObserver(this, aTopic); - // Remove bookmarks observer. - PlacesUtils.removeLazyBookmarkObserver(this); - // Stop updating livemarks. - this.stopUpdateLivemarks(); - } - }, + createLivemark: function LS_createLivemark(aParentId, aTitle, aSiteURI, + aFeedURI, aIndex) + { + this._reportDeprecatedMethod(); + this._ensureSynchronousCache(); - // We try to distribute the load of the livemark update. - // load gLimitCount Livemarks per gDelayTime sec. - _updatedLivemarks: [], - _forceUpdate: false, - _checkAllLivemarks: function LS__checkAllLivemarks(aForceUpdate) { - if (aForceUpdate && !this._forceUpdate) - this._forceUpdate = true; - let updateCount = 0; - for each (let livemark in this._livemarks) { - if (this._updatedLivemarks.indexOf(livemark.folderId) == -1) { - this._updatedLivemarks.push(livemark.folderId); - // Check if livemarks are expired, update if needed. - if (livemark.updateChildren(this._forceUpdate)) { - if (++updateCount == gLimitCount) { - break; - } - } - } - } - - let refresh_time = gDelayTime * 1000; - if (this._updatedLivemarks.length >= Object.keys(this._livemarks).length) { - // All livemarks are up-to-date, sleep until next period. - this._updatedLivemarks.length = 0; - this._forceUpdate = false; - refresh_time = Math.min(Math.floor(gExpiration / 4), MAX_REFRESH_TIME); - } - this._newTimer(refresh_time); - }, - - _newTimer: function LS__newTimer(aTime) { - if (this._updateTimer) { - this._updateTimer.cancel(); - } - this._updateTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this._updateTimer.initWithCallback(this._checkAllLivemarks.bind(this), - aTime, Ci.nsITimer.TYPE_ONE_SHOT); - }, - - createLivemark: function LS_createLivemark(aParentId, aName, aSiteURI, - aFeedURI, aIndex) { - let folderId = this.createLivemarkFolderOnly(aParentId, aName, aSiteURI, - aFeedURI, aIndex); - this._livemarks[folderId].updateChildren(); - return folderId; - }, - - createLivemarkFolderOnly: - function LS_createLivemarkFolderOnly(aParentId, aName, aSiteURI, - aFeedURI, aIndex) { - if (!aParentId || aParentId < 1 || !aFeedURI || - this.isLivemark(aParentId)) { + if (!aParentId || aParentId < 1 || + aIndex < -1 || + !aFeedURI || !(aFeedURI instanceof Ci.nsIURI) || + (aSiteURI && !(aSiteURI instanceof Ci.nsIURI)) || + aParentId in this._livemarks) { throw Cr.NS_ERROR_INVALID_ARG; } - let livemark = new Livemark({ parentId: aParentId, - index: aIndex, - title: aName }); - - // Add to the cache before setting the feedURI, otherwise isLivemark may - // fail identifying it, when invoked by an annotation observer. - this._livemarks[livemark.folderId] = livemark; - - livemark.feedURI = aFeedURI; - if (aSiteURI) { - livemark.siteURI = aSiteURI; + let livemark = new Livemark({ title: aTitle + , parentId: aParentId + , index: aIndex + , feedURI: aFeedURI + , siteURI: aSiteURI + }); + if (this._itemAdded && this._itemAdded.id == livemark.id) { + livemark.guid = this._itemAdded.guid; + livemark.index = this._itemAdded.index; + livemark.lastModified = this._itemAdded.lastModified; } - return livemark.folderId; + this._livemarks[livemark.id] = livemark; + this._guids[livemark.guid] = livemark.id; + return livemark.id; }, - isLivemark: function LS_isLivemark(aFolderId) { - if (aFolderId < 1) { + createLivemarkFolderOnly: function DEPRECATED_LS_(aParentId, aTitle, aSiteURI, + aFeedURI, aIndex) + { + return this.createLivemark(aParentId, aTitle, aSiteURI, aFeedURI, aIndex); + }, + + isLivemark: function DEPRECATED_LS_isLivemark(aId) + { + this._reportDeprecatedMethod(); + if (!aId || aId < 1) { throw Cr.NS_ERROR_INVALID_ARG; } + this._ensureSynchronousCache(); - return aFolderId in this._livemarks; + return aId in this._livemarks; }, - getLivemarkIdForFeedURI: function LS_getLivemarkIdForFeedURI(aFeedURI) { + getLivemarkIdForFeedURI: + function DEPRECATED_LS_getLivemarkIdForFeedURI(aFeedURI) + { + this._reportDeprecatedMethod(); if (!(aFeedURI instanceof Ci.nsIURI)) { throw Cr.NS_ERROR_INVALID_ARG; } + this._ensureSynchronousCache(); for each (livemark in this._livemarks) { if (livemark.feedURI.equals(aFeedURI)) { - return livemark.folderId; + return livemark.id; } } - return -1; }, - _ensureLivemark: function LS__ensureLivemark(aFolderId) { - if (!this.isLivemark(aFolderId)) { + getSiteURI: function DEPRECATED_LS_getSiteURI(aId) + { + this._reportDeprecatedMethod(); + this._ensureSynchronousCache(); + + if (!(aId in this._livemarks)) { + throw Cr.NS_ERROR_INVALID_ARG; + } + return this._livemarks[aId].siteURI; + }, + + setSiteURI: function DEPRECATED_LS_writeSiteURI(aId, aSiteURI) + { + this._reportDeprecatedMethod(); + if (!aSiteURI || !(aSiteURI instanceof Ci.nsIURI)) { throw Cr.NS_ERROR_INVALID_ARG; } }, - getSiteURI: function LS_getSiteURI(aFolderId) { - this._ensureLivemark(aFolderId); + getFeedURI: function DEPRECATED_LS_getFeedURI(aId) + { + this._reportDeprecatedMethod(); + this._ensureSynchronousCache(); - return this._livemarks[aFolderId].siteURI; - }, - - setSiteURI: function LS_setSiteURI(aFolderId, aSiteURI) { - if (aSiteURI && !(aSiteURI instanceof Ci.nsIURI)) { - throw Cr.NS_ERROR_INVALID_ARG; + if (!(aId in this._livemarks)) { + throw Cr.NS_ERROR_INVALID_ARG; } - this._ensureLivemark(aFolderId); - - this._livemarks[aFolderId].siteURI = aSiteURI; + return this._livemarks[aId].feedURI; }, - getFeedURI: function LS_getFeedURI(aFolderId) { - this._ensureLivemark(aFolderId); - - return this._livemarks[aFolderId].feedURI; - }, - - setFeedURI: function LS_setFeedURI(aFolderId, aFeedURI) { + setFeedURI: function DEPRECATED_LS_writeFeedURI(aId, aFeedURI) + { + this._reportDeprecatedMethod(); if (!aFeedURI || !(aFeedURI instanceof Ci.nsIURI)) { throw Cr.NS_ERROR_INVALID_ARG; } - this._ensureLivemark(aFolderId); - - this._livemarks[aFolderId].feedURI = aFeedURI; }, - reloadAllLivemarks: function LS_reloadAllLivemarks() { - this._checkAllLivemarks(true); + reloadLivemarkFolder: function DEPRECATED_LS_reloadLivemarkFolder(aId) + { + this._reportDeprecatedMethod(); + this._ensureSynchronousCache(); + + if (!(aId in this._livemarks)) { + throw Cr.NS_ERROR_INVALID_ARG; + } + this._livemarks[aId].reload(); }, - reloadLivemarkFolder: function LS_reloadLivemarkFolder(aFolderId) { - this._ensureLivemark(aFolderId); + reloadAllLivemarks: function DEPRECATED_LS_reloadAllLivemarks() + { + this._reportDeprecatedMethod(); - this._livemarks[aFolderId].updateChildren(true); + this._reloadLivemarks(); }, - // nsINavBookmarkObserver - onBeginUpdateBatch: function() { }, - onEndUpdateBatch: function() { }, - onItemAdded: function() { }, - onItemChanged: function() { }, - onItemVisited: function() { }, - onItemMoved: function() { }, - onBeforeItemRemoved: function() { }, + ////////////////////////////////////////////////////////////////////////////// + //// mozIAsyncLivemarks - onItemRemoved: function(aItemId, aParentId, aIndex, aItemType) { - // we don't need to remove annotations since itemAnnotations - // are already removed with the bookmark - if (!this.isLivemark(aItemId)) { - return; + addLivemark: function LS_addLivemark(aLivemarkInfo, + aLivemarkCallback) + { + // Must provide at least non-null parentId, index and feedURI. + if (!aLivemarkInfo || + ("parentId" in aLivemarkInfo && aLivemarkInfo.parentId < 1) || + !("index" in aLivemarkInfo) || aLivemarkInfo.index < Ci.nsINavBookmarksService.DEFAULT_INDEX || + !(aLivemarkInfo.feedURI instanceof Ci.nsIURI) || + (aLivemarkInfo.siteURI && !(aLivemarkInfo.siteURI instanceof Ci.nsIURI)) || + (aLivemarkInfo.guid && !/^[a-zA-Z0-9\-_]{12}$/.test(aLivemarkInfo.guid))) { + throw Cr.NS_ERROR_INVALID_ARG; } - this._livemarks[aItemId].terminate(); - delete this._livemarks[aItemId]; + // The addition is done synchronously due to the fact importExport service + // and JSON backups require that. The notification is async though. + // Once bookmarks are async, this may be properly fixed. + let result = Cr.NS_OK; + let livemark = null; + try { + // Disallow adding a livemark inside another livemark. + if (aLivemarkInfo.parentId in this._livemarks) { + throw new Components.Exception("", Cr.NS_ERROR_INVALID_ARG); + } + + livemark = new Livemark(aLivemarkInfo); + if (this._itemAdded && this._itemAdded.id == livemark.id) { + livemark.index = this._itemAdded.index; + if (!aLivemarkInfo.guid) { + livemark.guid = this._itemAdded.guid; + } + if (!aLivemarkInfo.lastModified) { + livemark.lastModified = this._itemAdded.lastModified; + } + } + + // Updating the cache even if it has not yet been populated doesn't + // matter since it will just be overwritten. But it must be done now, + // otherwise checking for the livemark using any deprecated synchronous + // API from an onItemAnnotation notification would give a wrong result. + this._livemarks[livemark.id] = livemark; + this._guids[livemark.guid] = livemark.id; + } + catch (ex) { + result = ex.result; + livemark = null; + } + finally { + if (aLivemarkCallback) { + this._onCacheReady(function LS_addLivemark_ETAT() { + try { + aLivemarkCallback.onCompletion(result, livemark); + } catch(ex2) {} + }); + } + } + }, + + removeLivemark: function LS_removeLivemark(aLivemarkInfo, aLivemarkCallback) + { + if (!aLivemarkInfo) { + throw Cr.NS_ERROR_INVALID_ARG; + } + + // Accept either a guid or an id. + let id = aLivemarkInfo.guid || aLivemarkInfo.id; + if (("guid" in aLivemarkInfo && !/^[a-zA-Z0-9\-_]{12}$/.test(aLivemarkInfo.guid)) || + ("id" in aLivemarkInfo && aLivemarkInfo.id < 1) || + !id) { + throw Cr.NS_ERROR_INVALID_ARG; + } + + // Convert the guid to an id. + if (id in this._guids) { + id = this._guids[id]; + } + let result = Cr.NS_OK; + try { + if (!(id in this._livemarks)) { + throw new Components.Exception("", Cr.NS_ERROR_INVALID_ARG); + } + this._livemarks[id].remove(); + } + catch (ex) { + result = ex.result; + } + finally { + if (aLivemarkCallback) { + // Enqueue the notification, per interface definition. + this._onCacheReady(function LS_removeLivemark_ETAT() { + try { + aLivemarkCallback.onCompletion(result, null); + } catch(ex2) {} + }); + } + } + }, + + _reloaded: [], + _reloadNextLivemark: function LS__reloadNextLivemark() + { + // Find first livemark to be reloaded. + for (let id in this._livemarks) { + if (this._reloaded.indexOf(id) == -1) { + this._reloaded.push(id); + this._livemarks[id].reload(); + this._startReloadTimer(); + break; + } + } + }, + + reloadLivemarks: function LS_reloadLivemarks() + { + this._onCacheReady((function LS_reloadAllLivemarks_ETAT() { + this._reloaded = []; + // Livemarks reloads happen on a timer, and are delayed for performance + // reasons. + this._startReloadTimer(); + }).bind(this)); + }, + + getLivemark: function LS_getLivemark(aLivemarkInfo, aLivemarkCallback) + { + if (!aLivemarkInfo) { + throw Cr.NS_ERROR_INVALID_ARG; + } + // Accept either a guid or an id. + let id = aLivemarkInfo.guid || aLivemarkInfo.id; + if (("guid" in aLivemarkInfo && !/^[a-zA-Z0-9\-_]{12}$/.test(aLivemarkInfo.guid)) || + ("id" in aLivemarkInfo && aLivemarkInfo.id < 1) || + !id) { + throw Cr.NS_ERROR_INVALID_ARG; + } + + this._onCacheReady((function LS_getLivemark_ETAT() { + // Convert the guid to an id. + if (id in this._guids) { + id = this._guids[id]; + } + if (id in this._livemarks) { + try { + aLivemarkCallback.onCompletion(Cr.NS_OK, this._livemarks[id]); + } catch (ex) {} + } + else { + try { + aLivemarkCallback.onCompletion(Cr.NS_ERROR_INVALID_ARG, null); + } catch (ex) {} + } + }).bind(this)); + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsINavBookmarkObserver + + onBeginUpdateBatch: function () {}, + onEndUpdateBatch: function () {}, + onItemVisited: function () {}, + onBeforeItemRemoved: function () {}, + + _itemAdded: null, + onItemAdded: function LS_onItemAdded(aItemId, aParentId, aIndex, aItemType, + aURI, aTitle, aDateAdded, aGUID) + { + if (aItemType == Ci.nsINavBookmarksService.TYPE_FOLDER) { + this._itemAdded = { id: aItemId + , guid: aGUID + , index: aIndex + , lastModified: aDateAdded + }; + } + }, + + onItemChanged: function LS_onItemChanged(aItemId, aProperty, aIsAnno, aValue, + aLastModified, aItemType) + { + if (aItemType == Ci.nsINavBookmarksService.TYPE_FOLDER) { + if (this._itemAdded && this._itemAdded.id == aItemId) { + this._itemAdded.lastModified = aLastModified; + } + if (aItemId in this._livemarks) { + if (aProperty == "title") { + this._livemarks[aItemId].title = aValue; + } + this._livemarks[aItemId].lastModified = aLastModified; + } + } + }, + + onItemMoved: function LS_onItemMoved(aItemId, aOldParentId, aOldIndex, + aNewParentId, aNewIndex, aItemType) + { + if (aItemType == Ci.nsINavBookmarksService.TYPE_FOLDER && + aItemId in this._livemarks) { + this._livemarks[aItemId].parentId = aNewParentId; + this._livemarks[aItemId].index = aNewIndex; + } + }, + + onItemRemoved: function LS_onItemRemoved(aItemId, aParentId, aIndex, + aItemType, aURI, aGUID) + { + if (aItemType == Ci.nsINavBookmarksService.TYPE_FOLDER && + aItemId in this._livemarks) { + this._livemarks[aItemId].terminate(); + delete this._livemarks[aItemId]; + delete this._guids[aGUID]; + } + }, + + ////////////////////////////////////////////////////////////////////////////// + //// nsINavHistoryObserver + + onBeginUpdateBatch: function () {}, + onEndUpdateBatch: function () {}, + onPageChanged: function () {}, + onTitleChanged: function () {}, + onDeleteVisits: function () {}, + onBeforeDeleteURI: function () {}, + + onClearHistory: function () {}, + + onDeleteURI: function PS_onDeleteURI(aURI) { + for each (let livemark in this._livemarks) { + livemark.updateURIVisitedStatus(aURI, false); + } + }, + + onVisit: function PS_onVisit(aURI) { + for each (let livemark in this._livemarks) { + livemark.updateURIVisitedStatus(aURI, true); + } }, ////////////////////////////////////////////////////////////////////////////// @@ -368,118 +612,124 @@ LivemarkService.prototype = { QueryInterface: XPCOMUtils.generateQI([ Ci.nsILivemarkService + , Ci.mozIAsyncLivemarks , Ci.nsINavBookmarkObserver + , Ci.nsINavHistoryObserver , Ci.nsIObserver + , Ci.nsISupportsWeakReference ]) }; +//////////////////////////////////////////////////////////////////////////////// +//// Livemark + /** * Object used internally to represent a livemark. * - * @param aFolderIdOrCreationInfo - * Item id of the bookmarks folder representing an existing livemark, or - * object containing information (parentId, title, index) to create a - * new livemark. + * @param aLivemarkInfo + * Object containing information on the livemark. If the livemark is + * not included in the object, a new livemark will be created. * * @note terminate() must be invoked before getting rid of this object. */ -function Livemark(aFolderIdOrCreationInfo) +function Livemark(aLivemarkInfo) { - if (typeof(aFolderIdOrCreationInfo) == "number") { - this.folderId = aFolderIdOrCreationInfo; - } - else if (typeof(aFolderIdOrCreationInfo) == "object"){ - this.folderId = - PlacesUtils.bookmarks.createFolder(aFolderIdOrCreationInfo.parentId, - aFolderIdOrCreationInfo.title, - aFolderIdOrCreationInfo.index); - PlacesUtils.bookmarks.setFolderReadonly(this.folderId, true); + this.title = aLivemarkInfo.title; + this.parentId = aLivemarkInfo.parentId; + this.index = aLivemarkInfo.index; - // Setup the status to avoid some useless lazy getter work. - this._loadStatus = STATUS.IDLE; + this._status = Ci.mozILivemark.STATUS_READY; + + // Hash of resultObservers, hashed by container. + this._resultObservers = new WeakMap(); + // This keeps a list of the containers used as keys in the weakmap, since + // it's not iterable. In future may use an iterable Map. + this._resultObserversList = []; + + // Sorted array of objects representing livemark children in the form + // { uri, title, visited }. + this._children = []; + + // Keeps a separate array of nodes for each requesting container, hashed by + // the container itself. + this._nodes = new WeakMap(); + + this._guid = ""; + this._lastModified = 0; + + this.loadGroup = null; + this.feedURI = null; + this.siteURI = null; + this.expireTime = 0; + + if (aLivemarkInfo.id) { + // This request comes from the cache. + this.id = aLivemarkInfo.id; + this.guid = aLivemarkInfo.guid; + this.feedURI = aLivemarkInfo.feedURI; + this.siteURI = aLivemarkInfo.siteURI; + this.lastModified = aLivemarkInfo.lastModified; } else { - throw Cr.NS_ERROR_UNEXPECTED; + // Create a new livemark. + this.id = PlacesUtils.bookmarks.createFolder(aLivemarkInfo.parentId, + aLivemarkInfo.title, + aLivemarkInfo.index); + PlacesUtils.bookmarks.setFolderReadonly(this.id, true); + if (aLivemarkInfo.guid) { + this.writeGuid(aLivemarkInfo.guid); + } + this.writeFeedURI(aLivemarkInfo.feedURI); + if (aLivemarkInfo.siteURI) { + this.writeSiteURI(aLivemarkInfo.siteURI); + } + // Last modified time must be the last change. + if (aLivemarkInfo.lastModified) { + this.lastModified = aLivemarkInfo.lastModified; + PlacesUtils.bookmarks.setItemLastModified(this.id, this.lastModified); + } } } Livemark.prototype = { - loadGroup: null, - locked: null, + get status() this._status, + set status(val) { + if (this._status != val) { + this._status = val; + this._invalidateRegisteredContainers(); + } + return this._status; + }, /** - * Whether this Livemark is valid or has been terminate()d. - */ - get alive() !!this.folderId, - - /** - * Sets an item annotation on the folderId representing this livemark. + * Sets an annotation on the bookmarks folder id representing the livemark. * - * @param aName + * @param aAnnoName * Name of the annotation. * @param aValue * Value of the annotation. * @return The annotation value. * @throws If the folder is invalid. */ - _setAnno: function LM__setAnno(aName, aValue) + _setAnno: function LM__setAnno(aAnnoName, aValue) { - if (this.alive) { - PlacesUtils.annotations - .setItemAnnotation(this.folderId, aName, aValue, 0, - PlacesUtils.annotations.EXPIRE_NEVER); - } - return aValue; + PlacesUtils.annotations + .setItemAnnotation(this.id, aAnnoName, aValue, 0, + PlacesUtils.annotations.EXPIRE_NEVER); }, - /** - * Gets a item annotation from the folderId representing this livemark. - * - * @param aName - * Name of the annotation. - * @return The annotation value. - * @throws If the folder is invalid or the annotation does not exist. - */ - _getAnno: function LM__getAnno(aName) - { - if (this.alive) { - return PlacesUtils.annotations.getItemAnnotation(this.folderId, aName); - } - return null; - }, - - /** - * Removes a item annotation from the folderId representing this livemark. - * - * @param aName - * Name of the annotation. - * @throws If the folder is invalid or the annotation does not exist. - */ - _removeAnno: function LM__removeAnno(aName) - { - if (this.alive) { - return PlacesUtils.annotations.removeItemAnnotation(this.folderId, aName); - } - }, - - set feedURI(aFeedURI) + writeFeedURI: function LM_writeFeedURI(aFeedURI) { this._setAnno(PlacesUtils.LMANNO_FEEDURI, aFeedURI.spec); - this._feedURI = aFeedURI; - }, - get feedURI() - { - if (this._feedURI === undefined) { - this._feedURI = NetUtil.newURI(this._getAnno(PlacesUtils.LMANNO_FEEDURI)); - } - return this._feedURI; + this.feedURI = aFeedURI; }, - set siteURI(aSiteURI) + writeSiteURI: function LM_writeSiteURI(aSiteURI) { if (!aSiteURI) { - this._removeAnno(PlacesUtils.LMANNO_SITEURI); - this._siteURI = null; + PlacesUtils.annotations.removeItemAnnotation(this.id, + PlacesUtils.LMANNO_SITEURI) + this.siteURI = null; return; } @@ -493,87 +743,81 @@ Livemark.prototype = { } this._setAnno(PlacesUtils.LMANNO_SITEURI, aSiteURI.spec) - this._siteURI = aSiteURI; + this.siteURI = aSiteURI; }, - get siteURI() + + writeGuid: function LM_writeGuid(aGUID) { - if (this._siteURI === undefined) { + // There isn't a way to create a bookmark with a given guid yet, nor to + // set a guid on an existing one. So, for now, just go the dirty way. + let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + let stmt = db.createAsyncStatement("UPDATE moz_bookmarks " + + "SET guid = :guid " + + "WHERE id = :item_id"); + stmt.params.guid = aGUID; + stmt.params.item_id = this.id; + let livemark = this; + stmt.executeAsync({ + handleError: function () {}, + handleResult: function () {}, + handleCompletion: function ETAT_handleCompletion(aReason) + { + if (aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED) { + livemark._guid = aGUID; + } + } + }); + stmt.finalize(); + }, + + set guid(aGUID) { + this._guid = aGUID; + return aGUID; + }, + get guid() + { + if (!/^[a-zA-Z0-9\-_]{12}$/.test(this._guid)) { + // The old synchronous interface is not guid-aware, so this may still have + // to be populated manually. + let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + let stmt = db.createStatement("SELECT guid FROM moz_bookmarks " + + "WHERE id = :item_id"); + stmt.params.item_id = this.id; try { - this._siteURI = NetUtil.newURI(this._getAnno(PlacesUtils.LMANNO_SITEURI)); - } catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { - // siteURI is optional. - return this._siteURI = null; + if (stmt.executeStep()) { + this._guid = stmt.row.guid; + } + } finally { + stmt.finalize(); } } - return this._siteURI; + return this._guid; }, - set expireTime(aExpireTime) - { - this._expireTime = this._setAnno(PlacesUtils.LMANNO_EXPIRATION, - aExpireTime); + set lastModified(aLastModified) { + this._lastModified = aLastModified; + return aLastModified; }, - get expireTime() + get lastModified() { - if (this._expireTime === undefined) { + if (!this._lastModified) { + // The old synchronous interface ignores the last modified time. + let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) + .DBConnection; + let stmt = db.createStatement("SELECT lastModified FROM moz_bookmarks " + + "WHERE id = :item_id"); + stmt.params.item_id = this.id; try { - this._expireTime = this._getAnno(PlacesUtils.LMANNO_EXPIRATION); - } catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { - // Expiration time may not be set yet. - return this._expireTime = 0; + if (stmt.executeStep()) { + this._lastModified = stmt.row.lastModified; + } + } finally { + stmt.finalize(); } } - return this._expireTime; - }, - - set loadStatus(aStatus) - { - // Avoid setting the same status multiple times. - if (this.loadStatus == aStatus) { - return; - } - - switch (aStatus) { - case STATUS.FAILED: - if (this.loadStatus == STATUS.LOADING) { - this._removeAnno(PlacesUtils.LMANNO_LOADING); - } - this._setAnno(PlacesUtils.LMANNO_LOADFAILED, true); - break; - case STATUS.LOADING: - if (this.loadStatus == STATUS.FAILED) { - this._removeAnno(PlacesUtils.LMANNO_LOADFAILED); - } - this._setAnno(PlacesUtils.LMANNO_LOADING, true); - break; - default: - if (this.loadStatus == STATUS.LOADING) { - this._removeAnno(PlacesUtils.LMANNO_LOADING); - } - else if (this.loadStatus == STATUS.FAILED) { - this._removeAnno(PlacesUtils.LMANNO_LOADFAILED); - } - break; - } - - this._loadStatus = aStatus; - }, - get loadStatus() - { - if (this._loadStatus === undefined) { - if (PlacesUtils.annotations.itemHasAnnotation(this.folderId, - PlacesUtils.LMANNO_LOADFAILED)) { - this._loadStatus = STATUS.FAILED; - } - else if (PlacesUtils.annotations.itemHasAnnotation(this.folderId, - PlacesUtils.LMANNO_LOADING)) { - this._loadStatus = STATUS.LOADING; - } - else { - this._loadStatus = STATUS.IDLE; - } - } - return this._loadStatus; + return this._lastModified; }, /** @@ -583,46 +827,26 @@ Livemark.prototype = { * @param [optional] aForceUpdate * If true will try to update the livemark even if its contents have * not yet expired. - * @return true if the livemarks will be updated, false otherwise. */ updateChildren: function LM_updateChildren(aForceUpdate) { - if (this.locked) { - return false; - } + // Check if the livemark is already updating. + if (this.status == Ci.mozILivemark.STATUS_LOADING) + return; - this.locked = true; + // Check the TTL/expiration on this, to check if there is no need to update + // this livemark. + if (!aForceUpdate && this.children.length && this.expireTime > Date.now()) + return; - // Check the TTL/expiration on this. If there isn't one, - // then we assume it's never been loaded. We perform this - // check even when the update is being forced, in case the - // livemark has somehow never been loaded. - if (!aForceUpdate && this.expireTime > Date.now()) { - // No need to refresh this livemark. - this.locked = false; - return false; - } + this.status = Ci.mozILivemark.STATUS_LOADING; - // Check the user idle time. - // If the user is away from the computer, don't bother updating, - // so we save some bandwidth. - // If we can't get the idle time, assume the user is not idle. - try { - let idleTime = idle.idleTime; - if (idleTime > IDLE_TIMELIMIT && !aForceUpdate) { - this.locked = false; - return false; - } - } - catch (ex) {} - - let loadgroup; try { // Create a load group for the request. This will allow us to // automatically keep track of redirects, so we can always // cancel the channel. - loadgroup = Cc["@mozilla.org/network/load-group;1"]. - createInstance(Ci.nsILoadGroup); + let loadgroup = Cc["@mozilla.org/network/load-group;1"]. + createInstance(Ci.nsILoadGroup); let channel = NetUtil.newChannel(this.feedURI.spec). QueryInterface(Ci.nsIHttpChannel); channel.loadGroup = loadgroup; @@ -634,41 +858,143 @@ Livemark.prototype = { // Stream the result to the feed parser with this listener let listener = new LivemarkLoadListener(this); channel.notificationCallbacks = listener; - - this.loadStatus = STATUS.LOADING; channel.asyncOpen(listener, null); + + this.loadGroup = loadgroup; } catch (ex) { - this.loadStatus = STATUS.FAILED; - this.locked = false; - return false; + this.status = Ci.mozILivemark.STATUS_FAILED; } - this.loadGroup = loadgroup; - return true; }, - /** - * Replaces all children of the livemark. - * - * @param aChildren - * Array of new children in the form of { uri, title } objects. - */ - replaceChildren: function LM_replaceChildren(aChildren) { - let self = this; - PlacesUtils.bookmarks.runInBatchMode({ - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsINavHistoryBatchCallback - ]), - runBatched: function LM_runBatched(aUserData) { - PlacesUtils.bookmarks.removeFolderChildren(self.folderId); - aChildren.forEach(function (aChild) { - PlacesUtils.bookmarks.insertBookmark(self.folderId, - aChild.uri, - PlacesUtils.bookmarks.DEFAULT_INDEX, - aChild.title); - }); + reload: function LM_reload(aForceUpdate) + { + this.updateChildren(aForceUpdate); + }, + + remove: function LM_remove() { + PlacesUtils.bookmarks.removeItem(this.id); + }, + + get children() this._children, + set children(val) { + this._children = val; + + // Discard the previous cached nodes, new ones should be generated. + for (let i = 0; i < this._resultObserversList.length; i++) { + let container = this._resultObserversList[i]; + this._nodes.delete(container); + } + + // Update visited status for each entry. + for (let i = 0; i < this._children.length; i++) { + let child = this._children[i]; + asyncHistory.isURIVisited(child.uri, + (function(aURI, aIsVisited) { + this.updateURIVisitedStatus(aURI, aIsVisited); + }).bind(this)); + } + + return this._children; + }, + + _isURIVisited: function LM__isURIVisited(aURI) { + for (let i = 0; i < this.children.length; i++) { + if (this.children[i].uri.equals(aURI)) { + return this.children[i].visited; } - }, null); + } + }, + + getNodesForContainer: function LM_getNodesForContainer(aContainerNode) + { + if (this._nodes.has(aContainerNode)) { + return this._nodes.get(aContainerNode); + } + + let livemark = this; + let nodes = []; + let now = Date.now() * 1000; + for (let i = 0; i < this._children.length; i++) { + let child = this._children[i]; + let node = { + // The QueryInterface is needed cause aContainerNode is a jsval. + // This is required to avoid issues with scriptable wrappers that would + // not allow the view to correctly set expandos. + get parent() + aContainerNode.QueryInterface(Ci.nsINavHistoryContainerResultNode), + get parentResult() this.parent.parentResult, + get uri() child.uri.spec, + get type() Ci.nsINavHistoryResultNode.RESULT_TYPE_URI, + get title() child.title, + get accessCount() + Number(livemark._isURIVisited(NetUtil.newURI(this.uri))), + get time() 0, + get icon() "", + get indentLevel() this.parent.indentLevel + 1, + get bookmarkIndex() -1, + get itemId() -1, + get dateAdded() now + i, + get lastModified() now + i, + get tags() + PlacesUtils.tagging.getTagsForURI(NetUtil.newURI(this.uri)).join(", "), + QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryResultNode]) + }; + nodes.push(node); + } + this._nodes.set(aContainerNode, nodes); + return nodes; + }, + + registerForUpdates: function LM_registerForUpdates(aContainerNode, + aResultObserver) + { + this._resultObservers.set(aContainerNode, aResultObserver); + this._resultObserversList.push(aContainerNode); + }, + + unregisterForUpdates: function LM_unregisterForUpdates(aContainerNode) + { + this._resultObservers.delete(aContainerNode); + let index = this._resultObserversList.indexOf(aContainerNode); + this._resultObserversList.splice(index, 1); + + this._nodes.delete(aContainerNode); + }, + + _invalidateRegisteredContainers: function LM__invalidateRegisteredContainers() + { + for (let i = 0; i < this._resultObserversList.length; i++) { + let container = this._resultObserversList[i]; + let observer = this._resultObservers.get(container); + observer.invalidateContainer(container); + } + }, + + updateURIVisitedStatus: + function LM_updateURIVisitedStatus(aURI, aVisitedStatus) + { + for (let i = 0; i < this.children.length; i++) { + if (this.children[i].uri.equals(aURI)) { + this.children[i].visited = aVisitedStatus; + } + } + + for (let i = 0; i < this._resultObserversList.length; i++) { + let container = this._resultObserversList[i]; + let observer = this._resultObservers.get(container); + if (this._nodes.has(container)) { + let nodes = this._nodes.get(container); + for (let j = 0; j < nodes.length; j++) { + let node = nodes[j]; + if (node.uri == aURI.spec) { + Services.tm.mainThread.dispatch((function () { + observer.nodeHistoryDetailsChanged(node, 0, aVisitedStatus); + }).bind(this), Ci.nsIThread.DISPATCH_NORMAL); + } + } + } + } }, /** @@ -677,44 +1003,57 @@ Livemark.prototype = { */ terminate: function LM_terminate() { - this.folderId = null; + delete this._resultObserversList; this.abort(); }, /** * Aborts the livemark loading if needed. */ - abort: function LM_abort() { - this.locked = false; + abort: function LM_abort() + { + this.status = Ci.mozILivemark.STATUS_FAILED; if (this.loadGroup) { - this.loadStatus = STATUS.FAILED; this.loadGroup.cancel(Cr.NS_BINDING_ABORTED); this.loadGroup = null; } }, + + QueryInterface: XPCOMUtils.generateQI([ + Ci.mozILivemark + ]) } +//////////////////////////////////////////////////////////////////////////////// +//// LivemarkLoadListener + /** * Object used internally to handle loading a livemark's contents. * * @param aLivemark * The Livemark that is loading. */ -function LivemarkLoadListener(aLivemark) { +function LivemarkLoadListener(aLivemark) +{ this._livemark = aLivemark; this._processor = null; this._isAborted = false; - this._ttl = gExpiration; + this._ttl = EXPIRE_TIME_MS; } LivemarkLoadListener.prototype = { - abort: function LLL_abort() { - this._isAborted = true; - this._livemark.abort(); + abort: function LLL_abort(aException) + { + if (!this._isAborted) { + this._isAborted = true; + this._livemark.abort(); + this._setResourceTTL(ONERROR_EXPIRE_TIME_MS); + } }, // nsIFeedResultListener - handleResult: function LLL_handleResult(aResult) { + handleResult: function LLL_handleResult(aResult) + { if (this._isAborted) { return; } @@ -725,41 +1064,40 @@ LivemarkLoadListener.prototype = { // Enforce well-formedness because the existing code does if (!aResult || !aResult.doc || aResult.bozo) { - this.abort(); - this._ttl = gExpiration; - throw Cr.NS_ERROR_FAILURE; + throw new Components.Exception("", Cr.NS_ERROR_FAILURE); } let feed = aResult.doc.QueryInterface(Ci.nsIFeed); let siteURI = this._livemark.siteURI; if (feed.link && (!siteURI || !feed.link.equals(siteURI))) { - this._livemark.siteURI = siteURI = feed.link; + siteURI = feed.link; + this._livemark.writeSiteURI(siteURI); } // Insert feed items. let livemarkChildren = []; for (let i = 0; i < feed.items.length; ++i) { let entry = feed.items.queryElementAt(i, Ci.nsIFeedEntry); - let href = entry.link || siteURI; - if (!href) { + let uri = entry.link || siteURI; + if (!uri) { continue; } try { - secMan.checkLoadURIWithPrincipal(feedPrincipal, href, SEC_FLAGS); + secMan.checkLoadURIWithPrincipal(feedPrincipal, uri, SEC_FLAGS); } catch(ex) { continue; } let title = entry.title ? entry.title.plainText() : ""; - livemarkChildren.push({ uri: href, title: title }); + livemarkChildren.push({ uri: uri, title: title, visited: false }); } - this._livemark.replaceChildren(livemarkChildren); + this._livemark.children = livemarkChildren; } catch (ex) { - this.abort(); + this.abort(ex); } finally { this._processor.listener = null; @@ -767,48 +1105,44 @@ LivemarkLoadListener.prototype = { } }, - onDataAvailable: function LLL_onDataAvailable(aRequest, aContext, aInputStream, - aSourceOffset, aCount) { + onDataAvailable: function LLL_onDataAvailable(aRequest, aContext, + aInputStream, aSourceOffset, + aCount) + { if (this._processor) { this._processor.onDataAvailable(aRequest, aContext, aInputStream, aSourceOffset, aCount); } }, - onStartRequest: function LLL_onStartRequest(aRequest, aContext) { + onStartRequest: function LLL_onStartRequest(aRequest, aContext) + { if (this._isAborted) { throw Cr.NS_ERROR_UNEXPECTED; } - this._livemark.loadStatus = STATUS.LOADING; - let channel = aRequest.QueryInterface(Ci.nsIChannel); - - // Parse feed data as it comes in - this._processor = Cc["@mozilla.org/feed-processor;1"]. - createInstance(Ci.nsIFeedProcessor); - this._processor.listener = this; - this._processor.parseAsync(null, channel.URI); - try { + // Parse feed data as it comes in + this._processor = Cc["@mozilla.org/feed-processor;1"]. + createInstance(Ci.nsIFeedProcessor); + this._processor.listener = this; + this._processor.parseAsync(null, channel.URI); this._processor.onStartRequest(aRequest, aContext); } catch (ex) { Components.utils.reportError("Livemark Service: feed processor received an invalid channel for " + channel.URI.spec); + this.abort(ex); } }, - onStopRequest: function LLL_onStopRequest(aRequest, aContext, aStatus) { + onStopRequest: function LLL_onStopRequest(aRequest, aContext, aStatus) + { if (!Components.isSuccessCode(aStatus)) { this.abort(); - this._setResourceTTL(ERROR_EXPIRATION); return; } - if (this._livemark.loadStatus == STATUS.LOADING) { - this._livemark.loadStatus = STATUS.IDLE; - } - // Set an expiration on the livemark, to reloading the data in future. try { if (this._processor) { @@ -820,46 +1154,51 @@ LivemarkLoadListener.prototype = { if (channel) { let entryInfo = channel.cacheToken.QueryInterface(Ci.nsICacheEntryInfo); if (entryInfo) { - // nsICacheEntryInfo returns value as seconds, - // expireTime stores as milliseconds + // nsICacheEntryInfo returns value as seconds. let expireTime = entryInfo.expirationTime * 1000; let nowTime = Date.now(); - - // note, expireTime can be 0, see bug 383538 + // Note, expireTime can be 0, see bug 383538. if (expireTime > nowTime) { - this._setResourceTTL(Math.max((expireTime - nowTime), gExpiration)); + this._setResourceTTL(Math.max((expireTime - nowTime), + EXPIRE_TIME_MS)); return; } } } + this._setResourceTTL(EXPIRE_TIME_MS); } catch (ex) { - this.abort(); + this.abort(ex); } finally { + if (this._livemark.status == Ci.mozILivemark.STATUS_LOADING) { + this._livemark.status = Ci.mozILivemark.STATUS_READY; + } this._livemark.locked = false; this._livemark.loadGroup = null; } - this._setResourceTTL(this._ttl); }, - _setResourceTTL: function LLL__setResourceTTL(aMilliseconds) { + _setResourceTTL: function LLL__setResourceTTL(aMilliseconds) + { this._livemark.expireTime = Date.now() + aMilliseconds; }, // nsIBadCertListener2 - notifyCertProblem: - function LLL_certProblem(aSocketInfo, aStatus, aTargetSite) { + notifyCertProblem: function LLL_certProblem(aSocketInfo, aStatus, aTargetSite) + { return true; }, // nsISSLErrorListener - notifySSLError: function LLL_SSLError(aSocketInfo, aError, aTargetSite) { + notifySSLError: function LLL_SSLError(aSocketInfo, aError, aTargetSite) + { return true; }, // nsIInterfaceRequestor - getInterface: function LLL_getInterface(aIID) { + getInterface: function LLL_getInterface(aIID) + { return this.QueryInterface(aIID); }, diff --git a/toolkit/components/places/nsNavBookmarks.cpp b/toolkit/components/places/nsNavBookmarks.cpp index 00260c3ee59..87522a604d3 100644 --- a/toolkit/components/places/nsNavBookmarks.cpp +++ b/toolkit/components/places/nsNavBookmarks.cpp @@ -43,7 +43,6 @@ #include "nsNavHistory.h" #include "nsAnnotationService.h" -#include "nsILivemarkService.h" #include "nsPlacesMacros.h" #include "Helpers.h" @@ -1052,6 +1051,48 @@ nsNavBookmarks::GetRemoveFolderTransaction(PRInt64 aFolderId, nsITransaction** a } +nsresult +nsNavBookmarks::GetDescendantFolders(PRInt64 aFolderId, + nsTArray& aDescendantFoldersArray) { + nsresult rv; + // New descendant folders will be added from this index on. + PRUint32 startIndex = aDescendantFoldersArray.Length(); + { + nsCOMPtr stmt = mDB->GetStatement( + "SELECT id " + "FROM moz_bookmarks " + "WHERE parent = :parent " + "AND type = :item_type " + ); + NS_ENSURE_STATE(stmt); + mozStorageStatementScoper scoper(stmt); + + rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aFolderId); + NS_ENSURE_SUCCESS(rv, rv); + rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("item_type"), TYPE_FOLDER); + NS_ENSURE_SUCCESS(rv, rv); + + bool hasMore = false; + while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) && hasMore) { + PRInt64 itemId; + rv = stmt->GetInt64(0, &itemId); + NS_ENSURE_SUCCESS(rv, rv); + aDescendantFoldersArray.AppendElement(itemId); + } + } + + // Recursively call GetDescendantFolders for added folders. + // We start at startIndex since previous folders are checked + // by previous calls to this method. + PRUint32 childCount = aDescendantFoldersArray.Length(); + for (PRUint32 i = startIndex; i < childCount; ++i) { + GetDescendantFolders(aDescendantFoldersArray[i], aDescendantFoldersArray); + } + + return NS_OK; +} + + nsresult nsNavBookmarks::GetDescendantChildren(PRInt64 aFolderId, const nsACString& aFolderGuid, diff --git a/toolkit/components/places/nsNavBookmarks.h b/toolkit/components/places/nsNavBookmarks.h index cd9d2ae3b51..01f4073d3b6 100644 --- a/toolkit/components/places/nsNavBookmarks.h +++ b/toolkit/components/places/nsNavBookmarks.h @@ -255,6 +255,17 @@ public: */ void NotifyItemChanged(const ItemChangeData& aData); + /** + * Recursively builds an array of descendant folders inside a given folder. + * + * @param aFolderId + * The folder to fetch descendants from. + * @param aDescendantFoldersArray + * Output array to put descendant folders id. + */ + nsresult GetDescendantFolders(PRInt64 aFolderId, + nsTArray& aDescendantFoldersArray); + private: static nsNavBookmarks* gBookmarksService; diff --git a/toolkit/components/places/nsNavHistory.cpp b/toolkit/components/places/nsNavHistory.cpp index f346ac26f50..396f31ae630 100644 --- a/toolkit/components/places/nsNavHistory.cpp +++ b/toolkit/components/places/nsNavHistory.cpp @@ -51,7 +51,6 @@ #include "nsNavHistory.h" #include "mozIPlacesAutoComplete.h" -#include "nsILivemarkService.h" #include "nsNavBookmarks.h" #include "nsAnnotationService.h" #include "nsFaviconService.h" @@ -1198,19 +1197,11 @@ nsNavHistory::GetHasHistoryEntries(bool* aHasEntries) nsresult nsNavHistory::invalidateFrecencies(const nsCString& aPlaceIdsQueryString) { - // Exclude place: queries and unvisited livemark children from autocomplete, - // by setting their frecency to zero. + // Exclude place: queries by setting their frecency to zero. nsCAutoString invalideFrecenciesSQLFragment( "UPDATE moz_places SET frecency = (CASE " "WHEN url BETWEEN 'place:' AND 'place;' " "THEN 0 " - "WHEN id IN (SELECT b.fk FROM moz_bookmarks b " - "JOIN moz_bookmarks bp ON bp.id = b.parent " - "JOIN moz_items_annos a ON a.item_id = bp.id " - "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " - "WHERE b.fk = moz_places.id AND visit_count = 0 " - "AND n.name = :anno_name) " - "THEN 0 " "ELSE -1 " "END) " ); @@ -1226,13 +1217,8 @@ nsNavHistory::invalidateFrecencies(const nsCString& aPlaceIdsQueryString) ); NS_ENSURE_STATE(stmt); - nsresult rv = stmt->BindUTF8StringByName( - NS_LITERAL_CSTRING("anno_name"), NS_LITERAL_CSTRING(LMANNO_FEEDURI) - ); - NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr ps; - rv = stmt->ExecuteAsync(nsnull, getter_AddRefs(ps)); + nsresult rv = stmt->ExecuteAsync(nsnull, getter_AddRefs(ps)); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; @@ -1718,32 +1704,8 @@ static bool NeedToFilterResultSet(const nsCOMArray& aQueries, nsNavHistoryQueryOptions *aOptions) { - // Never filter queries returning queries PRUint16 resultType = aOptions->ResultType(); - if (resultType == nsINavHistoryQueryOptions::RESULTS_AS_DATE_QUERY || - resultType == nsINavHistoryQueryOptions::RESULTS_AS_DATE_SITE_QUERY || - resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_QUERY || - resultType == nsINavHistoryQueryOptions::RESULTS_AS_SITE_QUERY) - return false; - - // Always filter bookmarks queries to avoid the inclusion of query nodes, - // but RESULTS AS TAG QUERY never needs to be filtered. - if (aOptions->QueryType() == nsINavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS) - return true; - - nsCString parentAnnotationToExclude; - nsresult rv = aOptions->GetExcludeItemIfParentHasAnnotation(parentAnnotationToExclude); - NS_ENSURE_SUCCESS(rv, true); - if (!parentAnnotationToExclude.IsEmpty()) - return true; - - // Need to filter on parent if any folder is set. - for (PRInt32 i = 0; i < aQueries.Count(); ++i) { - if (aQueries[i]->Folders().Length() != 0) { - return true; - } - } - return false; + return resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS; } // ** Helper class for ConstructQueryString **/ @@ -4040,6 +4002,7 @@ nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const nsCString* aClause) { bool hasIt; + bool excludeQueries = aOptions->ExcludeQueries(); ConditionBuilder clause(aQueryIndex); @@ -4065,6 +4028,8 @@ nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const .Str(", h.url, page_title, tags, ") .Str(nsPrintfCString(17, "0, 0, 0, 0, %d, 0)", mozIPlacesAutoComplete::MATCH_ANYWHERE_UNMODIFIED).get()); + // Serching by terms implicitly exclude queries. + excludeQueries = true; } // min and max visit count @@ -4156,11 +4121,35 @@ nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const ).Param(param.get()).Str(" LIMIT 1)"); } - // parent parameter is used in tag contents queries. - // Only one folder should be defined for them. - if (aOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS && - aQuery->Folders().Length() == 1) { - clause.Condition("b.parent =").Param(":parent"); + // folders + const nsTArray& folders = aQuery->Folders(); + if (folders.Length() > 0) { + nsTArray includeFolders; + includeFolders.AppendElements(folders); + + nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService(); + NS_ENSURE_STATE(bookmarks); + + for (nsTArray::size_type i = 0; i < folders.Length(); ++i) { + nsTArray subFolders; + if (NS_FAILED(bookmarks->GetDescendantFolders(folders[i], subFolders))) + continue; + includeFolders.AppendElements(subFolders); + } + + clause.Condition("b.parent IN("); + for (nsTArray::size_type i = 0; i < includeFolders.Length(); ++i) { + clause.Str(nsPrintfCString("%d", includeFolders[i]).get()); + if (i < includeFolders.Length() - 1) { + clause.Str(","); + } + } + clause.Str(")"); + } + + if (excludeQueries) { + // Serching by terms implicitly exclude queries. + clause.Condition("NOT h.url BETWEEN 'place:' AND 'place;'"); } clause.GetClauseString(*aClause); @@ -4318,15 +4307,6 @@ nsNavHistory::BindQueryClauseParameters(mozIStorageBaseStatement* statement, } } - // parent parameter - if (aOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS && - aQuery->Folders().Length() == 1) { - rv = statement->BindInt64ByName( - NS_LITERAL_CSTRING("parent") + qIndex, aQuery->Folders()[0] - ); - NS_ENSURE_SUCCESS(rv, rv); - } - return NS_OK; } @@ -4403,12 +4383,8 @@ nsNavHistory::GetTagsFolder() // nsNavHistory::FilterResultSet // // This does some post-query-execution filtering: -// - searching on title & url -// - parent folder (recursively) -// - excludeQueries -// - tags +// - searching on title, url and tags // - limit count -// - excludingLivemarkItems // // Note: changes to filtering in FilterResultSet() // may require changes to NeedToFilterResultSet() @@ -4420,8 +4396,6 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode, const nsCOMArray& aQueries, nsNavHistoryQueryOptions *aOptions) { - nsresult rv; - // get the bookmarks service nsNavBookmarks *bookmarks = nsNavBookmarks::GetBookmarksService(); NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY); @@ -4430,59 +4404,6 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode, nsTArray*> terms; ParseSearchTermsFromQueries(aQueries, &terms); - // The includeFolders array for each query is initialized with its - // query's folders array. We add sub-folders as we check items. - nsTArray< nsTArray* > includeFolders; - nsTArray< nsTArray* > excludeFolders; - for (PRInt32 queryIndex = 0; - queryIndex < aQueries.Count(); queryIndex++) { - includeFolders.AppendElement(new nsTArray(aQueries[queryIndex]->Folders())); - excludeFolders.AppendElement(new nsTArray()); - } - - // Filter against query options. - // XXX Only excludeQueries and excludeItemIfParentHasAnnotation are supported - // at the moment. - bool excludeQueries = false; - if (aQueryNode) { - rv = aQueryNode->mOptions->GetExcludeQueries(&excludeQueries); - NS_ENSURE_SUCCESS(rv, rv); - } - - nsCString parentAnnotationToExclude; - nsTArray parentFoldersToExclude; - if (aQueryNode) { - rv = aQueryNode->mOptions->GetExcludeItemIfParentHasAnnotation(parentAnnotationToExclude); - NS_ENSURE_SUCCESS(rv, rv); - } - - if (!parentAnnotationToExclude.IsEmpty()) { - // Find all the folders with the annotation we are excluding and save their - // item ids. When doing filtering, if item id of a result's parent - // matches one of the saved item ids, the result will be excluded. - nsCOMPtr stmt = mDB->GetStatement( - "SELECT a.item_id, a.content " - "FROM moz_anno_attributes n " - "JOIN moz_items_annos a ON n.id = a.anno_attribute_id " - "WHERE n.name = :anno_name " - ); - NS_ENSURE_STATE(stmt); - mozStorageStatementScoper scoper(stmt); - - rv = stmt->BindUTF8StringByName( - NS_LITERAL_CSTRING("anno_name"), parentAnnotationToExclude - ); - NS_ENSURE_SUCCESS(rv, rv); - - bool hasMore = false; - while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) && hasMore) { - PRInt64 folderId = 0; - rv = stmt->GetInt64(0, &folderId); - NS_ENSURE_SUCCESS(rv, rv); - parentFoldersToExclude.AppendElement(folderId); - } - } - PRUint16 resultType = aOptions->ResultType(); for (PRInt32 nodeIndex = 0; nodeIndex < aSet.Count(); nodeIndex++) { // exclude-queries is implicit when searching, we're only looking at @@ -4504,12 +4425,6 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode, parentId = aSet[nodeIndex]->mFolderId; } - // if we are excluding items by parent annotation, - // exclude items who's parent is a folder with that annotation - if (!parentAnnotationToExclude.IsEmpty() && - parentFoldersToExclude.Contains(parentId)) - continue; - // Append the node only if it matches one of the queries. bool appendNode = false; for (PRInt32 queryIndex = 0; @@ -4542,55 +4457,13 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode, continue; } - // Filter bookmarks on parent folder. - // RESULTS_AS_TAG_CONTENTS changes bookmarks' parents, so we cannot filter - // this kind of result based on the parent. - if (includeFolders[queryIndex]->Length() != 0 && - resultType != nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS) { - // Filter out the node if its parent is in the excludeFolders - // cache or it has no parent. - if (excludeFolders[queryIndex]->Contains(parentId) || parentId == -1) { - continue; - } - - if (!includeFolders[queryIndex]->Contains(parentId)) { - // If parent is not found in current includeFolders cache, we check - // its ancestors. - PRInt64 ancestor = parentId; - bool belongs = false; - nsTArray ancestorFolders; - - while (!belongs) { - // Avoid using |ancestor| itself if GetFolderIdForItem failed. - ancestorFolders.AppendElement(ancestor); - - // GetFolderIdForItems throws when called for the places-root - if (NS_FAILED(bookmarks->GetFolderIdForItem(ancestor, &ancestor))) { - break; - } else if (excludeFolders[queryIndex]->Contains(ancestor)) { - break; - } else if (includeFolders[queryIndex]->Contains(ancestor)) { - belongs = true; - } - } - // if the parentId or any of its ancestors "belong", - // include all of them. otherwise, exclude all of them. - if (belongs) { - includeFolders[queryIndex]->AppendElements(ancestorFolders); - } else { - excludeFolders[queryIndex]->AppendElements(ancestorFolders); - continue; - } - } - } - // We passed all filters, so we can append the node to filtered results. appendNode = true; } if (appendNode) aFiltered->AppendObject(aSet[nodeIndex]); - + // Stop once we have reached max results. if (aOptions->MaxResults() > 0 && (PRUint32)aFiltered->Count() >= aOptions->MaxResults()) @@ -4600,8 +4473,6 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode, // De-allocate the temporary matrixes. for (PRInt32 i = 0; i < aQueries.Count(); i++) { delete terms[i]; - delete includeFolders[i]; - delete excludeFolders[i]; } return NS_OK; diff --git a/toolkit/components/places/nsNavHistoryQuery.cpp b/toolkit/components/places/nsNavHistoryQuery.cpp index 51c5bd5b472..2578290df3e 100644 --- a/toolkit/components/places/nsNavHistoryQuery.cpp +++ b/toolkit/components/places/nsNavHistoryQuery.cpp @@ -168,7 +168,6 @@ static void SetOptionsKeyUint32(const nsCString& aValue, #define QUERYKEY_EXCLUDE_ITEMS "excludeItems" #define QUERYKEY_EXCLUDE_QUERIES "excludeQueries" #define QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS "excludeReadOnlyFolders" -#define QUERYKEY_EXCLUDE_ITEM_IF_PARENT_HAS_ANNOTATION "excludeItemIfParentHasAnnotation" #define QUERYKEY_EXPAND_QUERIES "expandQueries" #define QUERYKEY_FORCE_ORIGINAL_TITLE "originalTitle" #define QUERYKEY_INCLUDE_HIDDEN "includeHidden" @@ -583,18 +582,6 @@ nsNavHistory::QueriesToQueryString(nsINavHistoryQuery **aQueries, queryString += NS_LITERAL_CSTRING(QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS "=1"); } - // exclude item if parent has annotation - nsCAutoString parentAnnotationToExclude; - if (NS_SUCCEEDED(options->GetExcludeItemIfParentHasAnnotation(parentAnnotationToExclude)) && - !parentAnnotationToExclude.IsEmpty()) { - nsCString escaped; - if (!NS_Escape(parentAnnotationToExclude, escaped, url_XAlphas)) - return NS_ERROR_OUT_OF_MEMORY; - AppendAmpersandIfNonempty(queryString); - queryString += NS_LITERAL_CSTRING(QUERYKEY_EXCLUDE_ITEM_IF_PARENT_HAS_ANNOTATION "="); - queryString.Append(escaped); - } - // expand queries if (!options->ExpandQueries()) { AppendAmpersandIfNonempty(queryString); @@ -881,13 +868,6 @@ nsNavHistory::TokensToQueries(const nsTArray& aTokens, SetOptionsKeyBool(kvp.value, aOptions, &nsINavHistoryQueryOptions::SetExcludeReadOnlyFolders); - // exclude item if parent has annotation - } else if (kvp.key.EqualsLiteral(QUERYKEY_EXCLUDE_ITEM_IF_PARENT_HAS_ANNOTATION)) { - nsCString parentAnnotationToExclude = kvp.value; - NS_UnescapeURL(parentAnnotationToExclude); - rv = aOptions->SetExcludeItemIfParentHasAnnotation(parentAnnotationToExclude); - NS_ENSURE_SUCCESS(rv, rv); - // expand queries } else if (kvp.key.EqualsLiteral(QUERYKEY_EXPAND_QUERIES)) { SetOptionsKeyBool(kvp.value, aOptions, @@ -1513,19 +1493,6 @@ nsNavHistoryQueryOptions::SetExcludeReadOnlyFolders(bool aExclude) return NS_OK; } -// excludeItemIfParentHasAnnotation -NS_IMETHODIMP -nsNavHistoryQueryOptions::GetExcludeItemIfParentHasAnnotation(nsACString& _result) { - _result.Assign(mParentAnnotationToExclude); - return NS_OK; -} - -NS_IMETHODIMP -nsNavHistoryQueryOptions::SetExcludeItemIfParentHasAnnotation(const nsACString& aParentAnnotationToExclude) { - mParentAnnotationToExclude.Assign(aParentAnnotationToExclude); - return NS_OK; -} - // expandQueries NS_IMETHODIMP nsNavHistoryQueryOptions::GetExpandQueries(bool* aExpand) diff --git a/toolkit/components/places/nsNavHistoryResult.cpp b/toolkit/components/places/nsNavHistoryResult.cpp index 25206552995..9cf1eb11d05 100644 --- a/toolkit/components/places/nsNavHistoryResult.cpp +++ b/toolkit/components/places/nsNavHistoryResult.cpp @@ -3709,15 +3709,10 @@ nsNavHistoryFolderResultNode::StartIncrementalUpdate() { // if any items are excluded, we can not do incremental updates since the // indices from the bookmark service will not be valid - nsCAutoString parentAnnotationToExclude; - nsresult rv = mOptions->GetExcludeItemIfParentHasAnnotation(parentAnnotationToExclude); - NS_ENSURE_SUCCESS(rv, false); - - if (!mOptions->ExcludeItems() && - !mOptions->ExcludeQueries() && - !mOptions->ExcludeReadOnlyFolders() && - parentAnnotationToExclude.IsEmpty()) { + if (!mOptions->ExcludeItems() && + !mOptions->ExcludeQueries() && + !mOptions->ExcludeReadOnlyFolders()) { // easy case: we are visible, always do incremental update if (mExpanded || AreChildrenVisible()) return true; diff --git a/toolkit/components/places/nsPlacesImportExportService.cpp b/toolkit/components/places/nsPlacesImportExportService.cpp index af8b1cc3291..8f137c10e0f 100644 --- a/toolkit/components/places/nsPlacesImportExportService.cpp +++ b/toolkit/components/places/nsPlacesImportExportService.cpp @@ -106,8 +106,10 @@ #include "nsISupportsPrimitives.h" #include "nsPlacesMacros.h" #include "mozilla/Util.h" +#include "Helpers.h" using namespace mozilla; +using namespace mozilla::places; static NS_DEFINE_CID(kParserCID, NS_PARSER_CID); @@ -143,6 +145,9 @@ static NS_DEFINE_CID(kParserCID, NS_PARSER_CID); #define RESTORE_NSIOBSERVER_DATA NS_LITERAL_STRING("html") #define RESTORE_INITIAL_NSIOBSERVER_DATA NS_LITERAL_STRING("html-initial") +#define LMANNO_FEEDURI "livemark/feedURI" +#define LMANNO_SITEURI "livemark/siteURI" + // define to get debugging messages on console about import/export //#define DEBUG_IMPORT //#define DEBUG_EXPORT @@ -378,7 +383,7 @@ protected: nsCOMPtr mBookmarksService; nsCOMPtr mHistoryService; nsCOMPtr mAnnotationService; - nsCOMPtr mLivemarkService; + nsCOMPtr mLivemarkService; // If set, we will move root items to from their existing position // in the hierarchy, to where we find them in the bookmarks file @@ -982,30 +987,19 @@ BookmarkContentSink::HandleLinkEnd() if (frame.mPreviousFeed) { // The is a live bookmark. We create it here since in HandleLinkBegin we // don't know the title. + jsval livemark = livemarkInfoToJSVal( + 0, EmptyCString(), frame.mPreviousText, frame.mContainerID, + mBookmarksService->DEFAULT_INDEX, frame.mPreviousFeed, frame.mPreviousLink + ); + + // Create the live bookmark. + rv = mLivemarkService->AddLivemark(livemark, nsnull); + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "AddLivemark failed!"); - if (mIsImportDefaults) { - // Create the live bookmark but don't update it immediately. - rv = mLivemarkService->CreateLivemarkFolderOnly(frame.mContainerID, - frame.mPreviousText, - frame.mPreviousLink, - frame.mPreviousFeed, - -1, - &frame.mPreviousId); - NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "CreateLivemarkFolderOnly failed!"); - } - else { - rv = mLivemarkService->CreateLivemark(frame.mContainerID, - frame.mPreviousText, - frame.mPreviousLink, - frame.mPreviousFeed, - -1, - &frame.mPreviousId); - NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "CreateLivemark failed!"); - } #ifdef DEBUG_IMPORT PrintNesting(); - printf("Created livemark '%s' %lld\n", - NS_ConvertUTF16toUTF8(frame.mPreviousText).get(), frame.mPreviousId); + printf("Created livemark '%s'\n", + NS_ConvertUTF16toUTF8(frame.mPreviousText).get()); #endif } else if (frame.mPreviousLink) { @@ -1852,36 +1846,31 @@ nsPlacesImportExportService::WriteLivemark(nsINavHistoryResultNode* aFolder, con NS_ENSURE_SUCCESS(rv, rv); // get feed URI - nsCOMPtr feedURI; - rv = mLivemarkService->GetFeedURI(folderId, getter_AddRefs(feedURI)); + nsString feedSpec; + rv = mAnnotationService->GetItemAnnotationString(folderId, + NS_LITERAL_CSTRING(LMANNO_FEEDURI), + feedSpec); + NS_ENSURE_SUCCESS(rv, rv); - if (feedURI) { - nsCString feedSpec; - rv = feedURI->GetSpec(feedSpec); - NS_ENSURE_SUCCESS(rv, rv); - // write feed URI - rv = aOutput->Write(kFeedURIAttribute, sizeof(kFeedURIAttribute)-1, &dummy); - NS_ENSURE_SUCCESS(rv, rv); - rv = WriteEscapedUrl(feedSpec, aOutput); - NS_ENSURE_SUCCESS(rv, rv); - rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy); - NS_ENSURE_SUCCESS(rv, rv); - } + // write feed URI + rv = aOutput->Write(kFeedURIAttribute, sizeof(kFeedURIAttribute)-1, &dummy); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteEscapedUrl(NS_ConvertUTF16toUTF8(feedSpec), aOutput); + NS_ENSURE_SUCCESS(rv, rv); + rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy); + NS_ENSURE_SUCCESS(rv, rv); // get the optional site URI - nsCOMPtr siteURI; - rv = mLivemarkService->GetSiteURI(folderId, getter_AddRefs(siteURI)); - NS_ENSURE_SUCCESS(rv, rv); - if (siteURI) { - nsCString siteSpec; - rv = siteURI->GetSpec(siteSpec); - NS_ENSURE_SUCCESS(rv, rv); - + nsString siteSpec; + rv = mAnnotationService->GetItemAnnotationString(folderId, + NS_LITERAL_CSTRING(LMANNO_SITEURI), + siteSpec); + if (NS_SUCCEEDED(rv) && !siteSpec.IsEmpty()) { // write site URI rv = aOutput->Write(kHrefAttribute, sizeof(kHrefAttribute)-1, &dummy); NS_ENSURE_SUCCESS(rv, rv); - rv = WriteEscapedUrl(siteSpec, aOutput); + rv = WriteEscapedUrl(NS_ConvertUTF16toUTF8(siteSpec), aOutput); NS_ENSURE_SUCCESS(rv, rv); rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy); NS_ENSURE_SUCCESS(rv, rv); @@ -2023,9 +2012,13 @@ nsPlacesImportExportService::WriteContainerContents(nsINavHistoryResultNode* aFo rv = child->GetItemId(&childFolderId); NS_ENSURE_SUCCESS(rv, rv); - // it could be a regular folder or it could be a livemark + // it could be a regular folder or it could be a livemark. + // Livemarks service is async, for now just workaround using annotations + // service. bool isLivemark; - rv = mLivemarkService->IsLivemark(childFolderId, &isLivemark); + nsresult rv = mAnnotationService->ItemHasAnnotation(childFolderId, + NS_LITERAL_CSTRING(LMANNO_FEEDURI), + &isLivemark); NS_ENSURE_SUCCESS(rv, rv); if (isLivemark) diff --git a/toolkit/components/places/nsPlacesImportExportService.h b/toolkit/components/places/nsPlacesImportExportService.h index b15984cafb0..ba647ccdbf8 100644 --- a/toolkit/components/places/nsPlacesImportExportService.h +++ b/toolkit/components/places/nsPlacesImportExportService.h @@ -8,7 +8,7 @@ #include "nsIOutputStream.h" #include "nsIFaviconService.h" #include "nsIAnnotationService.h" -#include "nsILivemarkService.h" +#include "mozIAsyncLivemarks.h" #include "nsINavHistoryService.h" #include "nsINavBookmarksService.h" #include "nsIChannel.h" @@ -41,7 +41,7 @@ class nsPlacesImportExportService : public nsIPlacesImportExportService, nsCOMPtr mAnnotationService; nsCOMPtr mBookmarksService; nsCOMPtr mHistoryService; - nsCOMPtr mLivemarkService; + nsCOMPtr mLivemarkService; nsCOMPtr mImportChannel; bool mIsImportDefaults; diff --git a/toolkit/components/places/tests/autocomplete/head_autocomplete.js b/toolkit/components/places/tests/autocomplete/head_autocomplete.js index 36df844c35b..90ba75d1c65 100644 --- a/toolkit/components/places/tests/autocomplete/head_autocomplete.js +++ b/toolkit/components/places/tests/autocomplete/head_autocomplete.js @@ -187,77 +187,12 @@ var iosvc = Cc["@mozilla.org/network/io-service;1"]. getService(Ci.nsIIOService); var prefs = Cc["@mozilla.org/preferences-service;1"]. getService(Ci.nsIPrefBranch); -var lmsvc = Cc["@mozilla.org/browser/livemark-service;2"]. - getService(Ci.nsILivemarkService); // Some date not too long ago let gDate = new Date(Date.now() - 1000 * 60 * 60) * 1000; // Store the page info for each uri let gPages = []; - -/** - * Adds a livemark container with a single child, and creates various properties - * for it depending on the parameters passed in. - * - * @param aContainerSiteURI - * An index into kURIs that holds the string for the URI of site of the - * livemark container we are to add. - * @param aContainerFeedURI - * An index into kURIs that holds the string for the URI of feed of the - * livemark container we are to add. - * @param aContainerTitle - * An index into kTitles that holds the string for the title we are to - * associate with the livemark container. - * @param aChildURI - * An index into kURIs that holds the string for the URI of single - * livemark child we are to add. - * @param aChildTitle - * An index into kTitles that holds the string for the title we are to - * associate with the single livemark child. - * @param aTransitionType [optional] - * The transition type to use when adding the visit. The default is - * nsINavHistoryService::TRANSITION_LINK. - * @param aNoChildVisit [optional] - * If true, no visit is added for the child's URI. If false or - * undefined, a visit is added. - */ -function addLivemark(aContainerSiteURI, aContainerFeedURI, aContainerTitle, - aChildURI, aChildTitle, aTransitionType, aNoChildVisit) -{ - // Add a page entry for the child uri - gPages[aChildURI] = [aChildURI, aChildTitle, null]; - - let out = [aChildURI, aChildTitle]; - out.push("\nchild uri=" + kURIs[aChildURI]); - out.push("\nchild title=" + kTitles[aChildTitle]); - - // Create the container - let containerSiteURI = toURI(kURIs[aContainerSiteURI]); - let containerFeedURI = toURI(kURIs[aContainerFeedURI]); - let containerTitle = kTitles[aContainerTitle]; - let containerId = lmsvc.createLivemarkFolderOnly(bmsvc.unfiledBookmarksFolder, - containerTitle, - containerSiteURI, - containerFeedURI, - bmsvc.DEFAULT_INDEX); - // Insert the child - let childURI = toURI(kURIs[aChildURI]); - let childTitle = kTitles[aChildTitle]; - bmsvc.insertBookmark(containerId, childURI, bmsvc.DEFAULT_INDEX, childTitle); - - // Add a visit to the child if we need to - if (!aNoChildVisit) { - let tt = aTransitionType || TRANSITION_LINK; - let isRedirect = tt == TRANSITION_REDIRECT_PERMANENT || - tt == TRANSITION_REDIRECT_TEMPORARY; - histsvc.addVisit(childURI, gDate, null, tt, isRedirect, 0); - out.push("\nwith visit"); - } - - print("\nAdding livemark: " + out.join(", ")); -} - /** * Adds a page, and creates various properties for it depending on the * parameters passed in. This function will also add one visit, unless diff --git a/toolkit/components/places/tests/autocomplete/test_livemarks.js b/toolkit/components/places/tests/autocomplete/test_livemarks.js deleted file mode 100644 index 787647767a8..00000000000 --- a/toolkit/components/places/tests/autocomplete/test_livemarks.js +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - vim:set ts=2 sw=2 sts=2 et: - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Places Test code. - * - * The Initial Developer of the Original Code is the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Drew Willcoxon (Original Author) - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * Bug 479082 - * https://bugzilla.mozilla.org/show_bug.cgi?id=479082 - * - * Ensures that unvisited livemarks that are not bookmarked elsewhere do not - * show up in AutoComplete results. Also does some related checking that - * visited and/or separately bookmarked livemarks *do* show up. - */ - -let kURIs = [ - "http://example.com/", - "http://example.com/container", - // URIs that themselves should match our searches - "http://example.com/unvisited-not-bookmarked-elsewhere/vy-__--D", - "http://example.com/visited-not-bookmarked-elsewhere/_0YlX-9L", - "http://example.com/unvisited-bookmarked-elsewhere/X132H20w", - "http://example.com/visited-bookmarked-elsewhere/n_6D_Pw5", - // URIs whose titles should match our searches - "http://example.com/unvisited-not-bookmarked-elsewhere", - "http://example.com/visited-not-bookmarked-elsewhere", - "http://example.com/unvisited-bookmarked-elsewhere", - "http://example.com/visited-bookmarked-elsewhere", -]; -let kTitles = [ - "container title", - // titles for URIs that should match our searches - "unvisited not-bookmarked-elsewhere child title", - "visited not-bookmarked-elsewhere child title", - "unvisited bookmarked-elsewhere child title", - "visited bookmarked-elsewhere child title", - // titles that themselves should match our searches - "unvisited not-bookmarked-elsewhere child title P-13U-z-", - "visited not-bookmarked-elsewhere child title _3-X4_Qd", - "unvisited bookmarked-elsewhere child title I4jOt6o4", - "visited bookmarked-elsewhere child title 9-RVT4D5", -]; - -// our searches will match URIs on these livemarks -addLivemark(0, 1, 0, 2, 1, null, true); -addLivemark(0, 1, 0, 3, 2, null, false); -addLivemark(0, 1, 0, 4, 3, null, true); -addPageBook(4, 3, 3, null, null, null, true); -addLivemark(0, 1, 0, 5, 4, null, false); - -// we'll match titles on these livemarks -addLivemark(0, 1, 0, 6, 5, null, true); -addLivemark(0, 1, 0, 7, 6, null, false); -addLivemark(0, 1, 0, 8, 7, null, true); -addPageBook(8, 7, 7, null, null, null, true); -addLivemark(0, 1, 0, 9, 8, null, false); - -let gTests = [ - // URIs should match these searches - ["0: unvisited not-bookmarked-elsewhere livemark child (should be empty)", - "vy-__--D", []], - ["1: visited not-bookmarked-elsewhere livemark child (should not be empty)", - "_0YlX-9L", [3]], - ["2: unvisited bookmarked-elsewhere livemark child (should not be empty)", - "X132H20w", [4]], - ["3: visited bookmarked-elsewhere livemark child (should not be empty)", - "n_6D_Pw5", [5]], - // titles should match these - ["4: unvisited not-bookmarked-elsewhere livemark child (should be empty)", - "P-13U-z-", []], - ["5: visited not-bookmarked-elsewhere livemark child (should not be empty)", - "_3-X4_Qd", [7]], - ["6: unvisited bookmarked-elsewhere livemark child (should not be empty)", - "I4jOt6o4", [8]], - ["7: visited bookmarked-elsewhere livemark child (should not be empty)", - "9-RVT4D5", [9]], -]; diff --git a/toolkit/components/places/tests/autocomplete/xpcshell.ini b/toolkit/components/places/tests/autocomplete/xpcshell.ini index f67bfe32025..220a62af600 100644 --- a/toolkit/components/places/tests/autocomplete/xpcshell.ini +++ b/toolkit/components/places/tests/autocomplete/xpcshell.ini @@ -20,7 +20,6 @@ fail-if = os == "android" [test_escape_self.js] [test_ignore_protocol.js] [test_keyword_search.js] -[test_livemarks.js] [test_match_beginning.js] [test_multi_word_search.js] [test_special_search.js] diff --git a/toolkit/components/places/tests/bookmarks/test_livemarks.js b/toolkit/components/places/tests/bookmarks/test_livemarks.js index 92b9913296a..0e9e2f69f12 100644 --- a/toolkit/components/places/tests/bookmarks/test_livemarks.js +++ b/toolkit/components/places/tests/bookmarks/test_livemarks.js @@ -37,58 +37,45 @@ * * ***** END LICENSE BLOCK ***** */ -// Get livemark service -try { - var lmsvc = Cc["@mozilla.org/browser/livemark-service;2"]. - getService(Ci.nsILivemarkService); -} catch(ex) { - do_throw("Could not get livemark-service\n"); -} +// This tests the deprecated livemarks interface. -// Get bookmark service -try { - var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); -} catch(ex) { - do_throw("Could not get nav-bookmarks-service\n"); -} +function run_test() +{ + let livemarkId = PlacesUtils.livemarks.createLivemarkFolderOnly( + PlacesUtils.bookmarksMenuFolderId, "foo", uri("http://example.com/"), + uri("http://example.com/rss.xml"), PlacesUtils.bookmarks.DEFAULT_INDEX + ); -// get bookmarks root index -var root = bmsvc.bookmarksMenuFolder; - -// main -function run_test() { - var livemarkId = - lmsvc.createLivemarkFolderOnly(root, "foo", - uri("http://example.com/"), - uri("http://example.com/rss.xml"), -1); - - do_check_true(lmsvc.isLivemark(livemarkId)); - do_check_true(lmsvc.getSiteURI(livemarkId).spec == "http://example.com/"); - do_check_true(lmsvc.getFeedURI(livemarkId).spec == "http://example.com/rss.xml"); - do_check_true(bmsvc.getFolderReadonly(livemarkId)); - - lmsvc.setSiteURI(livemarkId, uri("http://foo.example.com/")); - do_check_true(lmsvc.getSiteURI(livemarkId).spec == "http://foo.example.com/"); - - lmsvc.setFeedURI(livemarkId, uri("http://foo.example.com/rss.xml")); - do_check_true(lmsvc.getFeedURI(livemarkId).spec == "http://foo.example.com/rss.xml"); + do_check_true(PlacesUtils.livemarks.isLivemark(livemarkId)); + do_check_eq(PlacesUtils.livemarks.getSiteURI(livemarkId).spec, "http://example.com/"); + do_check_eq(PlacesUtils.livemarks.getFeedURI(livemarkId).spec, "http://example.com/rss.xml"); + do_check_true(PlacesUtils.bookmarks.getFolderReadonly(livemarkId)); // Make sure we can't add a livemark to a livemark - var livemarkId2 = null; + let livemarkId2 = null; try { - var livemarkId2 = lmsvc.createLivemark(livemarkId, "foo", uri("http://example.com/"), - uri("http://example.com/rss.xml"), -1); + let livemarkId2 = PlacesUtils.livemarks.createLivemark( + livemarkId, "foo", uri("http://example.com/"), + uri("http://example.com/rss.xml"), PlacesUtils.bookmarks.DEFAULT_INDEX + ); } catch (ex) { livemarkId2 = null; } do_check_true(livemarkId2 == null); // make sure it didn't screw up the first one - do_check_true(lmsvc.isLivemark(livemarkId)); - + do_check_true(PlacesUtils.livemarks.isLivemark(livemarkId)); + + do_check_eq( + PlacesUtils.livemarks.getLivemarkIdForFeedURI(uri("http://example.com/rss.xml")), + livemarkId + ); + // make sure folders don't get counted as bookmarks // create folder - var randomFolder = bmsvc.createFolder(root, "Random", -1); - do_check_true(!lmsvc.isLivemark(randomFolder)); + let randomFolder = PlacesUtils.bookmarks.createFolder( + PlacesUtils.bookmarksMenuFolderId, "Random", + PlacesUtils.bookmarks.DEFAULT_INDEX + ); + do_check_true(!PlacesUtils.livemarks.isLivemark(randomFolder)); } diff --git a/toolkit/components/places/tests/chrome/Makefile.in b/toolkit/components/places/tests/chrome/Makefile.in index 66fea3547be..12e9f579d26 100644 --- a/toolkit/components/places/tests/chrome/Makefile.in +++ b/toolkit/components/places/tests/chrome/Makefile.in @@ -54,10 +54,10 @@ _HTTP_FILES = \ $(NULL) _CHROME_FILES = \ - test_329534.xul \ test_371798.xul \ test_342484.xul \ test_341972a.xul \ + test_341972b.xul \ test_favicon_annotations.xul \ test_303567.xul \ test_381357.xul \ diff --git a/toolkit/components/places/tests/chrome/test_303567.xul b/toolkit/components/places/tests/chrome/test_303567.xul index 11fd6e84359..139f57c543a 100644 --- a/toolkit/components/places/tests/chrome/test_303567.xul +++ b/toolkit/components/places/tests/chrome/test_303567.xul @@ -4,7 +4,8 @@ href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTest()"> @@ -12,10 +13,10 @@ diff --git a/toolkit/components/places/tests/chrome/test_329534.xul b/toolkit/components/places/tests/chrome/test_329534.xul deleted file mode 100644 index 9f2d101cbb3..00000000000 --- a/toolkit/components/places/tests/chrome/test_329534.xul +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - - - - - diff --git a/toolkit/components/places/tests/chrome/test_341972a.xul b/toolkit/components/places/tests/chrome/test_341972a.xul index 4013fbcaa2a..fe859f7a522 100644 --- a/toolkit/components/places/tests/chrome/test_341972a.xul +++ b/toolkit/components/places/tests/chrome/test_341972a.xul @@ -4,7 +4,8 @@ href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTest()"> @@ -21,58 +22,64 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; -var iosvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/NetUtil.jsm"); +Components.utils.import("resource://gre/modules/PlacesUtils.jsm"); -function uri(spec) { - return iosvc.newURI(spec, null, null); +function runTest() { + const FEEDSPEC = "http://mochi.test:8888/tests/toolkit/components/places/tests/chrome/sample_feed.atom"; + const INITIALSITESPEC = "http://mochi.test:8888/"; + const FEEDSITESPEC = "http://example.org/"; + + PlacesUtils.livemarks.addLivemark( + { title: "foo" + , parentId: PlacesUtils.toolbarFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: NetUtil.newURI(FEEDSPEC) + , siteURI: NetUtil.newURI(INITIALSITESPEC) + }, + function (aStatus, aLivemark) { + ok(Components.isSuccessCode(aStatus), "Get livemark"); + is(aLivemark.siteURI.spec, INITIALSITESPEC, + "Has correct initial livemark site URI"); + + waitForLivemarkLoad(aLivemark, function (aLivemark) { + is(aLivemark.siteURI.spec, FEEDSITESPEC, + "livemark site URI set to value in feed"); + + PlacesUtils.bookmarks.removeItem(aLivemark.id); + SimpleTest.finish(); + }); + } + ); } -var lmsvc = Cc["@mozilla.org/browser/livemark-service;2"]. - getService(Ci.nsILivemarkService); -var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); -var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService); -var annosvc = Cc["@mozilla.org/browser/annotation-service;1"]. - getService(Ci.nsIAnnotationService); - -var toolbarFolderId = bmsvc.toolbarFolder; - -var observer = -{ - QueryInterface: function(iid) { - if (iid.equals(Ci.nsIAnnotationObserver) || - iid.equals(Ci.nsISupports)) - return this; - throw Cr.NS_ERROR_NO_INTERFACE; - }, - - // nsIAnnotationObserver - onItemAnnotationSet: function(aItemId, aAnnotationName) { - if (aAnnotationName == "livemark/siteURI" && - aItemId == gLivemarkId) { - var newSiteURI = annosvc.getItemAnnotation(aItemId, aAnnotationName); - ok(newSiteURI == FEEDSITESPEC, - "livemark site URI changed to " + newSiteURI + " not to value in feed"); - annosvc.removeObserver(this); - bmsvc.removeItem(gLivemarkId); - SimpleTest.finish(); +function waitForLivemarkLoad(aLivemark, aCallback) { + // Don't need a real node here. + let node = {}; + let resultObserver = { + nodeInserted: function() {}, + nodeRemoved: function() {}, + nodeAnnotationChanged: function() {}, + nodeTitleChanged: function() {}, + nodeHistoryDetailsChanged: function() {}, + nodeReplaced: function() {}, + nodeMoved: function() {}, + ontainerStateChanged: function () {}, + sortingChanged: function() {}, + batching: function() {}, + invalidateContainer: function(node) { + isnot(aLivemark.status, Ci.mozILivemark.STATUS_FAILED, + "Loading livemark should success"); + if (aLivemark.status == Ci.mozILivemark.STATUS_READY) { + aLivemark.unregisterForUpdates(node, resultObserver); + aCallback(aLivemark); + } } - }, - onItemAnnotationRemoved: function(aItemId, aAnnotationName) {}, - onPageAnnotationSet: function(aUri, aAnnotationName) {}, - onPageAnnotationRemoved: function(aUri, aAnnotationName) {} -}; - -const FEEDSPEC = "http://mochi.test:8888/tests/toolkit/components/places/tests/chrome/sample_feed.atom"; -const INITIALSITESPEC = "http://mochi.test:8888/"; -const FEEDSITESPEC = "http://example.org/"; - -gLivemarkId = lmsvc.createLivemarkFolderOnly(toolbarFolderId, "foo", - uri(INITIALSITESPEC), - uri(FEEDSPEC), -1); -annosvc.addObserver(observer, false); -lmsvc.reloadLivemarkFolder(gLivemarkId); + }; + aLivemark.registerForUpdates(node, resultObserver); + aLivemark.reload(); +} ]]> diff --git a/toolkit/components/places/tests/chrome/test_341972b.xul b/toolkit/components/places/tests/chrome/test_341972b.xul index 61af47ec5a6..f43e158fbd0 100644 --- a/toolkit/components/places/tests/chrome/test_341972b.xul +++ b/toolkit/components/places/tests/chrome/test_341972b.xul @@ -4,7 +4,8 @@ href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTest()"> @@ -14,7 +15,6 @@ diff --git a/toolkit/components/places/tests/chrome/test_342484.xul b/toolkit/components/places/tests/chrome/test_342484.xul index 9204a84c73e..8a981e90ac2 100644 --- a/toolkit/components/places/tests/chrome/test_342484.xul +++ b/toolkit/components/places/tests/chrome/test_342484.xul @@ -26,61 +26,61 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/NetUtil.jsm"); Components.utils.import("resource://gre/modules/PlacesUtils.jsm"); -let gLivemarkId = -1; - function runTest() { const FEEDSPEC = "http://mochi.test:8888/tests/toolkit/components/places/tests/chrome/bad_links.atom"; - - let bookmarksObserver = { - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsINavBookmarkObserver - ]), - - onItemAdded: function (aItemId, aParentId, aIndex, aItemType, aURI) { - if (aURI.spec == "http://example.org/last") - this._updateFinished = true; - }, - onEndUpdateBatch: function () { - if (this._updateFinished) { - PlacesUtils.bookmarks.removeObserver(this); - setTimeout(continueTest, 0); - } - }, - onBeginUpdateBatch: function () {}, - onBeforeItemRemoved: function () {}, - onItemRemoved: function () {}, - onItemChanged: function () {}, - onItemVisited: function () {}, - onItemMoved: function () {}, - }; - - gLivemarkId = PlacesUtils.livemarks.createLivemarkFolderOnly( - PlacesUtils.toolbarFolderId, "foo", NetUtil.newURI("http://mochi.test/"), - NetUtil.newURI(FEEDSPEC), PlacesUtils.bookmarks.DEFAULT_INDEX - ); - PlacesUtils.bookmarks.addObserver(bookmarksObserver, false); - PlacesUtils.livemarks.reloadLivemarkFolder(gLivemarkId); -} - -function continueTest() { const GOOD_URLS = ["http://example.org/first", "http://example.org/last"]; - let options = PlacesUtils.history.getNewQueryOptions(); - let query = PlacesUtils.history.getNewQuery(); - query.setFolders([gLivemarkId], 1); - let root = PlacesUtils.history.executeQuery(query, options).root; - root.containerOpen = true; + PlacesUtils.livemarks.addLivemark( + { title: "foo" + , parentId: PlacesUtils.toolbarFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: NetUtil.newURI(FEEDSPEC) + , siteURI: NetUtil.newURI("http:/mochi.test/") + }, + function (aStatus, aLivemark) { + ok(Components.isSuccessCode(aStatus), "Get livemark"); - let cc = root.childCount; - is(cc, 2, "failed to create the two good livemark items"); - for (let i = 0; i < cc; ++i) { - let node = root.getChild(i); - ok(GOOD_URLS.indexOf(node.uri) != -1, "livemark item created with bad uri " + node.uri); - } + waitForLivemarkLoad(aLivemark, function (aLivemark) { + let nodes = aLivemark.getNodesForContainer({}); - root.containerOpen = false; - PlacesUtils.bookmarks.removeItem(gLivemarkId); - SimpleTest.finish(); + is(nodes.length, 2, "Created the two good livemark items"); + for (let i = 0; i < nodes.length; ++i) { + let node = nodes[i]; + ok(GOOD_URLS.indexOf(node.uri) != -1, "livemark item created with bad uri " + node.uri); + } + + PlacesUtils.bookmarks.removeItem(aLivemark.id); + SimpleTest.finish(); + }); + } + ); +} + +function waitForLivemarkLoad(aLivemark, aCallback) { + // Don't need a real node here. + let node = {}; + let resultObserver = { + nodeInserted: function() {}, + nodeRemoved: function() {}, + nodeAnnotationChanged: function() {}, + nodeTitleChanged: function() {}, + nodeHistoryDetailsChanged: function() {}, + nodeReplaced: function() {}, + nodeMoved: function() {}, + ontainerStateChanged: function () {}, + sortingChanged: function() {}, + batching: function() {}, + invalidateContainer: function(node) { + isnot(aLivemark.status, Ci.mozILivemark.STATUS_FAILED, + "Loading livemark should success"); + if (aLivemark.status == Ci.mozILivemark.STATUS_READY) { + aLivemark.unregisterForUpdates(node, resultObserver); + aCallback(aLivemark); + } + } + }; + aLivemark.registerForUpdates(node, resultObserver); + aLivemark.reload(); } ]]> diff --git a/toolkit/components/places/tests/chrome/test_381357.xul b/toolkit/components/places/tests/chrome/test_381357.xul index 0cac6630b57..2a937dfdcf7 100644 --- a/toolkit/components/places/tests/chrome/test_381357.xul +++ b/toolkit/components/places/tests/chrome/test_381357.xul @@ -4,7 +4,8 @@ href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?> + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="runTest()"> @@ -21,56 +22,64 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cr = Components.results; -var iosvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/NetUtil.jsm"); +Components.utils.import("resource://gre/modules/PlacesUtils.jsm"); -function uri(spec) { - return iosvc.newURI(spec, null, null); +function runTest() { + const FEEDSPEC = "http://mochi.test:8888/tests/toolkit/components/places/tests/chrome/rss_as_html.rss"; + + PlacesUtils.livemarks.addLivemark( + { title: "foo" + , parentId: PlacesUtils.toolbarFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: NetUtil.newURI(FEEDSPEC) + , siteURI: NetUtil.newURI("http:/mochi.test/") + }, + function (aStatus, aLivemark) { + ok(Components.isSuccessCode(aStatus), "Get livemark"); + + waitForLivemarkLoad(aLivemark, function (aLivemark) { + let nodes = aLivemark.getNodesForContainer({}); + ok(Components.isSuccessCode(aStatus), "Get livemark entries"); + + is(nodes[0].title, "The First Title", + "livemark site URI set to value in feed"); + + PlacesUtils.bookmarks.removeItem(aLivemark.id); + SimpleTest.finish(); + }); + } + ); } -var lmsvc = Cc["@mozilla.org/browser/livemark-service;2"]. - getService(Ci.nsILivemarkService); -var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); -var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"]. - getService(Ci.nsINavHistoryService); - -var toolbarFolderId = bmsvc.toolbarFolder; - -var observer = -{ - QueryInterface: function(iid) { - if (iid.equals(Ci.nsINavBookmarkObserver) || - iid.equals(Ci.nsISupports)) - return this; - throw Cr.NS_ERROR_NO_INTERFACE; - }, - - // nsINavBookmarkObserve - onBeginUpdateBatch: function(){}, - onEndUpdateBatch: function(){ - }, - onItemAdded: function(itemId, folder, index, itemType, uri, title) { - if (title == "The First Title") { - ok(true, "Item with title loaded"); - bmsvc.removeObserver(this); - SimpleTest.finish(); +function waitForLivemarkLoad(aLivemark, aCallback) { + // Don't need a real node here. + let node = {}; + let resultObserver = { + nodeInserted: function() {}, + nodeRemoved: function() {}, + nodeAnnotationChanged: function() {}, + nodeTitleChanged: function() {}, + nodeHistoryDetailsChanged: function() {}, + nodeReplaced: function() {}, + nodeMoved: function() {}, + ontainerStateChanged: function () {}, + sortingChanged: function() {}, + batching: function() {}, + invalidateContainer: function(node) { + isnot(aLivemark.status, Ci.mozILivemark.STATUS_FAILED, + "Loading livemark should success"); + if (aLivemark.status == Ci.mozILivemark.STATUS_READY) { + aLivemark.unregisterForUpdates(node, resultObserver); + aCallback(aLivemark); + } } - }, - onBeforeItemRemoved: function(){}, - onItemRemoved: function(){}, - onItemChanged: function(){}, - onItemVisited: function(){}, - onItemMoved: function(){}, + }; + aLivemark.registerForUpdates(node, resultObserver); + aLivemark.reload(); +} -}; - -const FEEDSPEC = "http://mochi.test:8888/tests/toolkit/components/places/tests/chrome/rss_as_html.rss"; - -gLivemarkId = lmsvc.createLivemarkFolderOnly(toolbarFolderId, "foo", - uri("http:/mochi.test/"), - uri(FEEDSPEC), -1); -bmsvc.addObserver(observer, false); -lmsvc.reloadLivemarkFolder(gLivemarkId); ]]> diff --git a/toolkit/components/places/tests/head_common.js b/toolkit/components/places/tests/head_common.js index 1eba000c58b..e1924d3dbb2 100644 --- a/toolkit/components/places/tests/head_common.js +++ b/toolkit/components/places/tests/head_common.js @@ -35,7 +35,7 @@ * * ***** END LICENSE BLOCK ***** */ -const CURRENT_SCHEMA_VERSION = 18; +const CURRENT_SCHEMA_VERSION = 19; const NS_APP_USER_PROFILE_50_DIR = "ProfD"; const NS_APP_PROFILE_DIR_STARTUP = "ProfDS"; @@ -74,11 +74,7 @@ XPCOMUtils.defineLazyGetter(this, "FileUtils", function() { return FileUtils; }); -XPCOMUtils.defineLazyGetter(this, "PlacesUtils", function() { - Cu.import("resource://gre/modules/PlacesUtils.jsm"); - return PlacesUtils; -}); - +Cu.import("resource://gre/modules/PlacesUtils.jsm"); function LOG(aMsg) { aMsg = ("*** PLACES TESTS: " + aMsg); @@ -86,7 +82,6 @@ function LOG(aMsg) { print(aMsg); } - let gTestDir = do_get_cwd(); // Ensure history is enabled. @@ -723,6 +718,53 @@ function do_check_guid_for_uri(aURI, } } +/** + * Retrieves the guid for a given bookmark. + * + * @param aId + * The bookmark id to check. + * @param [optional] aStack + * The stack frame used to report the error. + * @return the associated the guid. + */ +function do_get_guid_for_bookmark(aId, + aStack) +{ + if (!aStack) { + aStack = Components.stack.caller; + } + let stmt = DBConn().createStatement( + "SELECT guid " + + "FROM moz_bookmarks " + + "WHERE id = :item_id " + ); + stmt.params.item_id = aId; + do_check_true(stmt.executeStep(), aStack); + let guid = stmt.row.guid; + stmt.finalize(); + do_check_valid_places_guid(guid, aStack); + return guid; +} + +/** + * Tests that a guid was set in moz_places for a given bookmark. + * + * @param aId + * The bookmark id to check. + * @param [optional] aGUID + * The expected guid in the database. + */ +function do_check_guid_for_bookmark(aId, + aGUID) +{ + let caller = Components.stack.caller; + let guid = do_get_guid_for_bookmark(aId, caller); + if (aGUID) { + do_check_valid_places_guid(aGUID, caller); + do_check_eq(guid, aGUID, caller); + } +} + /** * Logs info to the console in the standard way (includes the filename). * diff --git a/toolkit/components/places/tests/queries/head_queries.js b/toolkit/components/places/tests/queries/head_queries.js index 9fe826b9f7d..531eccbf40c 100644 --- a/toolkit/components/places/tests/queries/head_queries.js +++ b/toolkit/components/places/tests/queries/head_queries.js @@ -200,11 +200,12 @@ function populateDB(aArray) { } if (qdata.isLivemark) { - PlacesUtils.livemarks.createLivemark(qdata.parentFolder, - qdata.title, - uri(qdata.uri), - uri(qdata.feedURI), - qdata.index); + PlacesUtils.livemarks.addLivemark({ title: qdata.title + , parentId: qdata.parentFolder + , index: qdata.index + , feedURI: uri(qdata.feedURI) + , siteURI: uri(qdata.uri) + }); } if (qdata.isBookmark) { diff --git a/toolkit/components/places/tests/queries/test_querySerialization.js b/toolkit/components/places/tests/queries/test_querySerialization.js index 2baf8210c55..dd68fa89cfc 100644 --- a/toolkit/components/places/tests/queries/test_querySerialization.js +++ b/toolkit/components/places/tests/queries/test_querySerialization.js @@ -458,21 +458,6 @@ const queryOptionSwitches = [ } ] }, - // excludeItemIfParentHasAnnotation - { - property: "excludeItemIfParentHasAnnotation", - desc: "nsINavHistoryQueryOptions.excludeItemIfParentHasAnnotation", - matches: simplePropertyMatches, - runs: [ - function (aQuery, aQueryOptions) { - aQueryOptions.excludeItemIfParentHasAnnotation = - "bookmarks/toolbarFolder"; - }, - function (aQuery, aQueryOptions) { - aQueryOptions.excludeItemIfParentHasAnnotation = ""; - } - ] - }, // expandQueries { property: "expandQueries", diff --git a/toolkit/components/places/tests/unit/test_412132.js b/toolkit/components/places/tests/unit/test_412132.js index 4931deefcd8..b59a333e06c 100644 --- a/toolkit/components/places/tests/unit/test_412132.js +++ b/toolkit/components/places/tests/unit/test_412132.js @@ -44,70 +44,6 @@ * https://bugzilla.mozilla.org/show_bug.cgi?id=412132 */ -add_test(function unvisited_bookmarked_livemarkItem() -{ - do_log_info("Frecency of unvisited, separately bookmarked livemark item's " + - "URI should be zero after bookmark's URI changed."); - - // Add livemark and bookmark. Bookmark's URI is the URI of the livemark's - // only item. - const TEST_URI = NetUtil.newURI("http://example.com/livemark-item"); - createLivemark(TEST_URI); - let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark title"); - waitForAsyncUpdates(function () - { - do_log_info("Bookmarked => frecency of URI should be != 0."); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - PlacesUtils.bookmarks.changeBookmarkURI(id, NetUtil.newURI("http://example.com/new-uri")); - - waitForAsyncUpdates(function () - { - do_log_info("URI's only bookmark is now unvisited livemark item => frecency = 0"); - do_check_eq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - waitForClearHistory(run_next_test); - }); - }); -}); - -add_test(function visited_bookmarked_livemarkItem() -{ - do_log_info("Frecency of visited, separately bookmarked livemark item's " + - "URI should not be zero after bookmark's URI changed."); - - // Add livemark and bookmark. Bookmark's URI is the URI of the livemark's - // only item. - const TEST_URI = NetUtil.newURI("http://example.com/livemark-item"); - createLivemark(TEST_URI); - let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark title"); - waitForAsyncUpdates(function () - { - do_log_info("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - visit(TEST_URI); - - PlacesUtils.bookmarks.changeBookmarkURI(id, uri("http://example.com/new-uri")); - - waitForAsyncUpdates(function () - { - do_log_info("URI's only bookmark is now *visited* livemark item => frecency != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - waitForClearHistory(run_next_test); - }); - }); -}); - add_test(function changeuri_unvisited_bookmark() { do_log_info("After changing URI of bookmark, frecency of bookmark's " + @@ -232,25 +168,6 @@ add_test(function changeuri_nonexistent_bookmark() /////////////////////////////////////////////////////////////////////////////// -/** - * Creates a livemark with a single child item. - * - * @param aChildURI - * the URI of the livemark's single child item - * @return the item ID of the single child item - */ -function createLivemark(aChildURI) -{ - let livemarkId = PlacesUtils.livemarks.createLivemarkFolderOnly( - PlacesUtils.unfiledBookmarksFolderId, "livemark title", - uri("http://example.com/"), uri("http://example.com/rdf"), -1 - ); - return PlacesUtils.bookmarks.insertBookmark(livemarkId, - aChildURI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "livemark item title"); -} - /** * Adds a visit for aURI. * diff --git a/toolkit/components/places/tests/unit/test_bug636917_isLivemark.js b/toolkit/components/places/tests/unit/test_bug636917_isLivemark.js index bd98a9ada6e..bf655532e3c 100644 --- a/toolkit/components/places/tests/unit/test_bug636917_isLivemark.js +++ b/toolkit/components/places/tests/unit/test_bug636917_isLivemark.js @@ -13,12 +13,14 @@ function run_test() { if (aAnnotationName == PlacesUtils.LMANNO_FEEDURI) { PlacesUtils.annotations.removeObserver(this); - do_check_true(PlacesUtils.livemarks.isLivemark(aItemId)); - do_execute_soon(function () { - PlacesUtils.bookmarks.removeItem(aItemId); - do_check_false(PlacesUtils.livemarks.isLivemark(aItemId)); - do_test_finished(); - }); + PlacesUtils.livemarks.getLivemark( + { id: aItemId }, + function (aStatus, aLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + PlacesUtils.bookmarks.removeItem(aItemId); + do_test_finished(); + } + ); } }, @@ -30,11 +32,12 @@ function run_test() ]), } PlacesUtils.annotations.addObserver(annoObserver, false); - PlacesUtils.livemarks.createLivemarkFolderOnly( - PlacesUtils.unfiledBookmarksFolderId, - "livemark title", - uri("http://example.com/"), - uri("http://example.com/rdf"), - PlacesUtils.bookmarks.DEFAULT_INDEX + PlacesUtils.livemarks.addLivemark( + { title: "livemark title" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , siteURI: uri("http://example.com/") + , feedURI: uri("http://example.com/rdf") + } ); } diff --git a/toolkit/components/places/tests/unit/test_exclude_livemarks.js b/toolkit/components/places/tests/unit/test_exclude_livemarks.js deleted file mode 100644 index 6efc66016ad..00000000000 --- a/toolkit/components/places/tests/unit/test_exclude_livemarks.js +++ /dev/null @@ -1,114 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is Google Inc. - * Portions created by the Initial Developer are Copyright (C) 2005 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Darin Fisher - * Dietrich Ayala - * Seth Spitzer - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// Get livemark service -try { - var lmsvc = Cc["@mozilla.org/browser/livemark-service;2"]. - getService(Ci.nsILivemarkService); -} catch(ex) { - do_throw("Could not get livemark-service\n"); -} - -// Get bookmark service -try { - var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. - getService(Ci.nsINavBookmarksService); -} catch(ex) { - do_throw("Could not get nav-bookmarks-service\n"); -} - -// Get history service -try { - var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].getService(Ci.nsINavHistoryService); -} catch(ex) { - do_throw("Could not get history service\n"); -} - -// get bookmarks root index -var root = bmsvc.bookmarksMenuFolder; - -// main -function run_test() { - var livemarkId = - lmsvc.createLivemarkFolderOnly(root, "foo", - uri("http://example.com/"), - uri("http://example.com/rss.xml"), -1); - - do_check_true(lmsvc.isLivemark(livemarkId)); - do_check_true(lmsvc.getSiteURI(livemarkId).spec == "http://example.com/"); - do_check_true(lmsvc.getFeedURI(livemarkId).spec == "http://example.com/rss.xml"); - var livemarkItem = bmsvc.insertBookmark(livemarkId, uri("http://example.com/item1.html"), bmsvc.DEFAULT_INDEX, "item 1"); - - // create a folder - var parent = bmsvc.createFolder(root, "test", bmsvc.DEFAULT_INDEX); - // create a non livemark item under the folder - var nonLivemarkItem = bmsvc.insertBookmark(parent, uri("http://example.com/item2.html"), bmsvc.DEFAULT_INDEX, "item 2"); - - // don't exclude livemark items, search for "item", should get two results - var options = histsvc.getNewQueryOptions(); - options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS; - var query = histsvc.getNewQuery(); - query.searchTerms = "item"; - var result = histsvc.executeQuery(query, options); - var rootNode = result.root; - rootNode.containerOpen = true; - var cc = rootNode.childCount; - do_check_eq(cc, 2); - var node = rootNode.getChild(0); - do_check_eq(node.itemId, livemarkItem); - node = rootNode.getChild(1); - do_check_eq(node.itemId, nonLivemarkItem); - rootNode.containerOpen = false; - - // exclude livemark items, search for "item", should get one result - options = histsvc.getNewQueryOptions(); - options.excludeItemIfParentHasAnnotation = "livemark/feedURI"; - options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS; - query = histsvc.getNewQuery(); - query.searchTerms = "item"; - result = histsvc.executeQuery(query, options); - rootNode = result.root; - rootNode.containerOpen = true; - cc = rootNode.childCount; - do_check_eq(cc, 1); - var node = rootNode.getChild(0); - do_check_eq(node.itemId, nonLivemarkItem); - rootNode.containerOpen = false; -} diff --git a/toolkit/components/places/tests/unit/test_history_removeAllPages.js b/toolkit/components/places/tests/unit/test_history_removeAllPages.js index d46a561ee25..03b904c2c3d 100644 --- a/toolkit/components/places/tests/unit/test_history_removeAllPages.js +++ b/toolkit/components/places/tests/unit/test_history_removeAllPages.js @@ -39,28 +39,6 @@ let mDBConn = DBConn(); -function add_fake_livemark() { - let lmId = PlacesUtils.livemarks.createLivemarkFolderOnly( - PlacesUtils.toolbarFolderId, "Livemark", - uri("http://www.mozilla.org/"), uri("http://www.mozilla.org/test.xml"), - PlacesUtils.bookmarks.DEFAULT_INDEX - ); - // Add a visited child. - PlacesUtils.bookmarks.insertBookmark(lmId, - uri("http://visited.livemark.com/"), - PlacesUtils.bookmarks.DEFAULT_INDEX, - "visited"); - PlacesUtils.history.addVisit(uri("http://visited.livemark.com/"), - Date.now(), null, - Ci.nsINavHistoryService.TRANSITION_BOOKMARK, - false, 0); - // Add an unvisited child. - PlacesUtils.bookmarks.insertBookmark(lmId, - uri("http://unvisited.livemark.com/"), - PlacesUtils.bookmarks.DEFAULT_INDEX, - "unvisited"); -} - let historyObserver = { onBeginUpdateBatch: function() {}, onEndUpdateBatch: function() {}, @@ -143,17 +121,6 @@ let historyObserver = { do_check_false(stmt.executeStep()); stmt.finalize(); - // Check that livemarks children don't have frecency <> 0 - stmt = mDBConn.createStatement( - "SELECT h.id FROM moz_places h " + - "JOIN moz_bookmarks b ON h.id = b.fk " + - "JOIN moz_bookmarks bp ON bp.id = b.parent " + - "JOIN moz_items_annos t ON t.item_id = bp.id " + - "JOIN moz_anno_attributes n ON t.anno_attribute_id = n.id " + - "WHERE n.name = 'livemark/feedURI' AND h.frecency <> 0 LIMIT 1"); - do_check_false(stmt.executeStep()); - stmt.finalize(); - do_test_finished(); }); }, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false); @@ -178,8 +145,6 @@ function run_test() { } function continue_test() { - // Add a livemark with a visited and an unvisited child - add_fake_livemark(); PlacesUtils.history.addVisit(uri("http://typed.mozilla.org/"), Date.now(), null, Ci.nsINavHistoryService.TRANSITION_TYPED, false, 0); diff --git a/toolkit/components/places/tests/unit/test_livemarkService_getLivemarkIdForFeedURI.js b/toolkit/components/places/tests/unit/test_livemarkService_getLivemarkIdForFeedURI.js deleted file mode 100644 index efd21edd937..00000000000 --- a/toolkit/components/places/tests/unit/test_livemarkService_getLivemarkIdForFeedURI.js +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Places unit test code. - * - * The Initial Developer of the Original Code is - * Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2009 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Marco Bonardo - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -const LMANNO_FEEDURI = "livemark/feedURI"; - -var PU = PlacesUtils; -var bs = PU.bookmarks; -var as = PU.annotations; - -/** - * Creates a fake livemark without using the livemark service. - * - * @param aParentId - * folder where we will create the livemark. - * @param aTitle - * title for the livemark. - * @param aSiteURI - * siteURI, currently unused. - * @param aFeedURI - * feed URI for the livemark. - * @param aIndex - * index of the new folder inside parent. - * - * @returns the new folder id. - */ -function createFakeLivemark(aParentId, aTitle, aSiteURI, aFeedURI, aIndex) { - var folderId = bs.createFolder(aParentId, aTitle, aIndex); - bs.setFolderReadonly(folderId, true); - - // Add an annotation to map the folder id to the livemark feed URI. - as.setItemAnnotation(folderId, LMANNO_FEEDURI, aFeedURI.spec, - 0, as.EXPIRE_NEVER); - return folderId; -} - -// main -function run_test() { - var feedURI = uri("http://example.com/rss.xml"); - - // Create a fake livemark, and use getMostRecentFolderForFeedURI before - // livemark service is initialized. - var fakeLivemarkId = createFakeLivemark(bs.bookmarksMenuFolder, "foo", - uri("http://example.com/"), - feedURI, bs.DEFAULT_INDEX); - do_check_eq(PU.getMostRecentFolderForFeedURI(feedURI), fakeLivemarkId); - - bs.removeItem(fakeLivemarkId); - do_check_eq(PU.getMostRecentFolderForFeedURI(feedURI), -1); - - // Create livemark service and repeat the test. - var ls = PU.livemarks; - var livemarkId = ls.createLivemarkFolderOnly(bs.bookmarksMenuFolder, "foo", - uri("http://example.com/"), - feedURI, bs.DEFAULT_INDEX); - - do_check_eq(ls.getLivemarkIdForFeedURI(feedURI), livemarkId); - do_check_eq(PU.getMostRecentFolderForFeedURI(feedURI), livemarkId); - - bs.removeItem(livemarkId); - do_check_eq(ls.getLivemarkIdForFeedURI(feedURI), -1); - do_check_eq(PU.getMostRecentFolderForFeedURI(feedURI), -1); -} diff --git a/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js b/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js new file mode 100644 index 00000000000..3a57d19317f --- /dev/null +++ b/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js @@ -0,0 +1,551 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Tests functionality of the mozIAsyncLivemarks interface. + +const FEED_URI = NetUtil.newURI("http://feed.rss/"); +const SITE_URI = NetUtil.newURI("http://site.org/"); + +function run_test() +{ + run_next_test(); +} + +add_test(function test_addLivemark_noArguments_throws() +{ + try { + PlacesUtils.livemarks.addLivemark(); + do_throw("Invoking addLivemark with no arguments should throw"); + } catch (ex) { + // The error is actually generated by XPConnect. + do_check_eq(ex.result, Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS); + } + run_next_test(); +}); + +add_test(function test_addLivemark_emptyObject_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({}); + do_throw("Invoking addLivemark with empty object should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_addLivemark_badParentId_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({ parentId: "test" }); + do_throw("Invoking addLivemark with a bad parent id should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_addLivemark_invalidParentId_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({ parentId: -2 }); + do_throw("Invoking addLivemark with an invalid parent id should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_addLivemark_noIndex_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId }); + do_throw("Invoking addLivemark with no index should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_addLivemark_badIndex_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: "test" + }); + do_throw("Invoking addLivemark with a bad index should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_addLivemark_invalidIndex_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: -2 + }); + do_throw("Invoking addLivemark with an invalid index should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_addLivemark_noFeedURI_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + }); + do_throw("Invoking addLivemark with no feedURI should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_addLivemark_badFeedURI_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: "test" + }); + do_throw("Invoking addLivemark with a bad feedURI should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_addLivemark_badSiteURI_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , siteURI: "test" + }); + do_throw("Invoking addLivemark with a bad siteURI should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_addLivemark_badGuid_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "123456" + }); + do_throw("Invoking addLivemark with a bad guid should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_addLivemark_badCallback_throws() +{ + try { + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, "test"); + do_throw("Invoking addLivemark with a bad callback should throw"); + } catch (ex) { + // The error is actually generated by XPConnect. + do_check_eq(ex.result, Cr.NS_ERROR_XPC_BAD_CONVERT_JS); + } + run_next_test(); +}); + +add_test(function test_addLivemark_noCallback_succeeds() +{ + PlacesUtils.bookmarks.addObserver({ + onItemAdded: function onItemAdded(aItemId, aParentId, aIndex, aItemType, + aURI, aTitle) + { + PlacesUtils.bookmarks.removeObserver(this); + do_check_eq(aParentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aIndex, 0); + do_check_eq(aItemType, Ci.nsINavBookmarksService.TYPE_FOLDER); + do_check_eq(aTitle, "test"); + run_next_test(); + }, + onBeginUpdateBatch: function onBeginUpdateBatch() {}, + onEndUpdateBatch: function onEndUpdateBatch() {}, + onBeforeItemRemoved: function onBeforeItemRemoved() {}, + onItemRemoved: function onItemRemoved() {}, + onItemChanged: function onItemChanged() {}, + onItemVisited: function onItemVisited() {}, + onItemMoved: function onItemMoved() {}, + }, false); + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }); +}); + +add_test(function test_addLivemark_noSiteURI_callback_succeeds() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_true(aLivemark.id > 0); + do_check_valid_places_guid(aLivemark.guid); + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + do_check_eq(aLivemark.lastModified, PlacesUtils.bookmarks.getItemLastModified(aLivemark.id)); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_eq(aLivemark.siteURI, null); + run_next_test(); + }); +}); + +add_test(function test_addLivemark_callback_succeeds() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , siteURI: SITE_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_true(aLivemark.id > 0); + do_check_valid_places_guid(aLivemark.guid); + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + do_check_eq(aLivemark.lastModified, PlacesUtils.bookmarks.getItemLastModified(aLivemark.id)); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_true(aLivemark.siteURI.equals(SITE_URI)); + + do_check_true(PlacesUtils.annotations + .itemHasAnnotation(aLivemark.id, + PlacesUtils.LMANNO_FEEDURI)); + do_check_true(PlacesUtils.annotations + .itemHasAnnotation(aLivemark.id, + PlacesUtils.LMANNO_SITEURI)); + run_next_test(); + }); +}); + +add_test(function test_addLivemark_bogusParent_callback_fails() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: 187 + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + run_next_test(); + }); +}); + +add_test(function test_addLivemark_intoLivemark_callback_fails() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: aLivemark.id + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + run_next_test(); + }); + }); +}); + +add_test(function test_addLivemark_forceGuid_callback_succeeds() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "1234567890AB" + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.guid, "1234567890AB"); + do_check_guid_for_bookmark(aLivemark.id, "1234567890AB"); + + run_next_test(); + }); +}); + +add_test(function test_addLivemark_lastModified_callback_succeeds() +{ + let now = Date.now() * 1000; + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , lastModified: now + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.lastModified, now); + + run_next_test(); + }); +}); + +add_test(function test_removeLivemark_emptyObject_throws() +{ + try { + PlacesUtils.livemarks.removeLivemark({}); + do_throw("Invoking removeLivemark with empty object should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_removeLivemark_noValidId_throws() +{ + try { + PlacesUtils.livemarks.removeLivemark({ id: -10, guid: "test"}); + do_throw("Invoking removeLivemark with no valid id should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_removeLivemark_nonExistent_fails() +{ + PlacesUtils.livemarks.removeLivemark( + { id: 1337 }, + function (aStatus, aLivemark) { + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + run_next_test(); + } + ); +}); + +add_test(function test_removeLivemark_guid_succeeds() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "234567890ABC" + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.guid, "234567890ABC"); + // invalid id to check the guid wins. + PlacesUtils.livemarks.removeLivemark( + { id: 789, guid: "234567890ABC" }, + function (aStatus, aRemovedLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(PlacesUtils.bookmarks.getItemIndex(aLivemark.id), -1); + do_check_eq(aRemovedLivemark, null); + run_next_test(); + } + ); + }); +}); + +add_test(function test_removeLivemark_id_succeeds() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + PlacesUtils.livemarks.removeLivemark( + { id: aLivemark.id }, + function (aStatus, aRemovedLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(PlacesUtils.bookmarks.getItemIndex(aLivemark.id), -1); + do_check_eq(aRemovedLivemark, null); + run_next_test(); + } + ); + }); +}); + +add_test(function test_getLivemark_emptyObject_throws() +{ + try { + PlacesUtils.livemarks.getLivemark({}, function () {}); + do_throw("Invoking getLivemark with empty object should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_getLivemark_noValidId_throws() +{ + try { + PlacesUtils.livemarks.getLivemark({ id: -10, guid: "test"}, function () {}); + do_throw("Invoking getLivemark with no valid id should throw"); + } catch (ex) { + do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + run_next_test(); +}); + +add_test(function test_getLivemark_nonExistentId_fails() +{ + PlacesUtils.livemarks.getLivemark({ id: 1234 }, + function (aStatus, aLivemark){ + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + run_next_test(); + } + ); +}); + +add_test(function test_getLivemark_nonExistentGUID_fails() +{ + PlacesUtils.livemarks.getLivemark({ guid: "34567890ABCD" }, + function (aStatus, aLivemark){ + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + run_next_test(); + } + ); +}); + +add_test(function test_getLivemark_guid_succeeds() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "34567890ABCD" + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + + // invalid id to check the guid wins. + PlacesUtils.livemarks.getLivemark({ id: 789, guid: "34567890ABCD" }, + function(aStatus, aLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_eq(aLivemark.siteURI, null); + do_check_eq(aLivemark.guid, "34567890ABCD"); + run_next_test(); + } + ); + }); +}); + +add_test(function test_getLivemark_id_succeeds() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + + // invalid id to check the guid wins. + PlacesUtils.livemarks.getLivemark({ id: aLivemark.id }, + function(aStatus, aLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_eq(aLivemark.siteURI, null); + do_check_guid_for_bookmark(aLivemark.id, aLivemark.guid); + run_next_test(); + } + ); + }); +}); + +add_test(function test_getLivemark_removeItem_contention() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }); + PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId); + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }); + let id = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX); + + PlacesUtils.livemarks.getLivemark( + { id: id }, + function(aStatus, aLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_eq(aLivemark.siteURI, null); + do_check_guid_for_bookmark(aLivemark.id, aLivemark.guid); + run_next_test(); + } + ); +}); + +add_test(function test_title_change() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function(aStatus, aLivemark) { + PlacesUtils.bookmarks.setItemTitle(aLivemark.id, "test2"); + do_check_eq(aLivemark.title, "test2"); + run_next_test(); + }); +}); + +add_test(function test_livemark_move() +{ + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function(aStatus, aLivemark) { + PlacesUtils.bookmarks.moveItem(aLivemark.id, + PlacesUtils.toolbarFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX); + do_check_eq(aLivemark.parentId, PlacesUtils.toolbarFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + run_next_test(); + }); +}); diff --git a/toolkit/components/places/tests/unit/test_null_interfaces.js b/toolkit/components/places/tests/unit/test_null_interfaces.js index 38c46201d97..23fab10fbf0 100644 --- a/toolkit/components/places/tests/unit/test_null_interfaces.js +++ b/toolkit/components/places/tests/unit/test_null_interfaces.js @@ -56,6 +56,7 @@ let testServices = [ ["browser/nav-bookmarks-service;1","nsINavBookmarksService", ["createFolder", "getItemIdForGUID"]], ["browser/livemark-service;2","nsILivemarkService", []], + ["browser/livemark-service;2","mozIAsyncLivemarks", []], ["browser/annotation-service;1","nsIAnnotationService", []], ["browser/favicon-service;1","nsIFaviconService", []], ["browser/tagging-service;1","nsITaggingService", []], diff --git a/toolkit/components/places/tests/unit/test_preventive_maintenance.js b/toolkit/components/places/tests/unit/test_preventive_maintenance.js index dd9009137da..04c42663a5f 100644 --- a/toolkit/components/places/tests/unit/test_preventive_maintenance.js +++ b/toolkit/components/places/tests/unit/test_preventive_maintenance.js @@ -728,49 +728,6 @@ tests.push({ //------------------------------------------------------------------------------ -tests.push({ - name: "D.11", - desc: "Remove old livemarks status items", - - _bookmarkId: null, - _livemarkLoadingStatusId: null, - _livemarkFailedStatusId: null, - _placeId: null, - _lmLoadingPlaceId: null, - _lmFailedPlaceId: null, - - setup: function() { - // Add a place to ensure place_id = 1 is valid - this._placeId = addPlace(); - - // Insert a bookmark - this._bookmarkId = addBookmark(this._placeId); - // Add livemark status item - this._lmLoadingPlaceId = addPlace("about:livemark-loading"); - this._lmFailedPlaceId = addPlace("about:livemark-failed"); - // Bookmark it - this._livemarkLoadingStatusId = addBookmark(this._lmLoadingPlaceId); - this._livemarkFailedStatusId = addBookmark(this._lmFailedPlaceId); - }, - - check: function() { - // Check that valid bookmark is still there - let stmt = mDBConn.createStatement("SELECT id FROM moz_bookmarks WHERE id = :item_id"); - stmt.params["item_id"] = this._bookmarkId; - do_check_true(stmt.executeStep()); - stmt.reset(); - // Check that livemark status items have been removed - stmt.params["item_id"] = this._livemarkLoadingStatusId; - do_check_false(stmt.executeStep()); - stmt.reset(); - stmt.params["item_id"] = this._livemarkFailedStatusId; - do_check_false(stmt.executeStep()); - stmt.finalize(); - } -}); - -//------------------------------------------------------------------------------ - tests.push({ name: "D.12", desc: "Fix empty-named tags", diff --git a/toolkit/components/places/tests/unit/test_update_frecency_after_delete.js b/toolkit/components/places/tests/unit/test_update_frecency_after_delete.js index cd81dfd86c8..029e0433d69 100644 --- a/toolkit/components/places/tests/unit/test_update_frecency_after_delete.js +++ b/toolkit/components/places/tests/unit/test_update_frecency_after_delete.js @@ -45,67 +45,6 @@ * bookmark is deleted. */ -add_test(function unvisited_bookmarked_livemarkItem() -{ - do_log_info("Frecency of unvisited, separately bookmarked livemark item's " + - "URI should be zero after bookmark removed."); - // Add livemark and bookmark. Bookmark's URI is the URI of the livemark's - // only item. - const TEST_URI = NetUtil.newURI("http://example.com/livemark-item"); - createLivemark(TEST_URI); - let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark title"); - waitForAsyncUpdates(function () - { - do_log_info("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - PlacesUtils.bookmarks.removeItem(id); - - waitForAsyncUpdates(function () - { - do_log_info("URI's only bookmark is now unvisited livemark item => frecency = 0"); - do_check_eq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - waitForClearHistory(run_next_test); - }); - }); -}); - -add_test(function visited_bookmarked_livemarkItem() -{ - do_log_info("Frecency of visited, separately bookmarked livemark item's " + - "URI should not be zero after bookmark removed."); - // Add livemark and bookmark. Bookmark's URI is the URI of the livemark's - // only item. - const TEST_URI = NetUtil.newURI("http://example.com/livemark-item"); - createLivemark(TEST_URI); - let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark title"); - waitForAsyncUpdates(function () - { - do_log_info("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - visit(TEST_URI); - PlacesUtils.bookmarks.removeItem(id); - - waitForAsyncUpdates(function () - { - do_log_info("URI's only bookmark is now *visited* livemark item => frecency != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - waitForClearHistory(run_next_test); - }); - }); -}); - add_test(function removed_bookmark() { do_log_info("After removing bookmark, frecency of bookmark's URI should be " + @@ -192,98 +131,6 @@ add_test(function remove_bookmark_still_bookmarked() }); }); -add_test(function cleared_parent_of_unvisited_bookmark_to_livemarkItem() -{ - do_log_info("Frecency of unvisited, separately bookmarked livemark item's " + - "URI should be zero after all children removed from bookmark's " + - "parent."); - // Add livemark and bookmark. Bookmark's URI is the URI of the livemark's - // only item. - const TEST_URI = NetUtil.newURI("http://example.com/livemark-item"); - createLivemark(TEST_URI); - - let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark title"); - waitForAsyncUpdates(function () - { - do_log_info("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId); - - waitForAsyncUpdates(function () - { - do_log_info("URI's only bookmark is now unvisited livemark item => frecency = 0"); - do_check_eq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - waitForClearHistory(run_next_test); - }); - }); -}); - -add_test(function cleared_parent_of_visited_bookmark_to_livemarkItem() -{ - do_log_info("Frecency of visited, separately bookmarked livemark item's " + - "URI should not be zero after all children removed from " + - "bookmark's parent."); - // Add livemark and bookmark. Bookmark's URI is the URI of the livemark's - // only item. - const TEST_URI = NetUtil.newURI("http://example.com/livemark-item"); - createLivemark(TEST_URI); - let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark title"); - waitForAsyncUpdates(function () - { - do_log_info("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - visit(TEST_URI); - PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId); - - waitForAsyncUpdates(function () - { - do_log_info("URI's only bookmark is now *visited* livemark item => frecency != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - waitForClearHistory(run_next_test); - }); - }); -}); - -add_test(function cleared_parent_of_unvisited_unbookmarked_livemarkItem() -{ - do_log_info("After removing all children from bookmark's parent, frecency " + - "of bookmark's URI should be zero if URI is unvisited and no " + - "longer bookmarked."); - const TEST_URI = NetUtil.newURI("http://example.com/1"); - let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, - TEST_URI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "bookmark title"); - waitForAsyncUpdates(function () - { - do_log_info("Bookmarked => frecency of URI should be != 0"); - do_check_neq(frecencyForUrl(TEST_URI), 0); - - PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId); - - waitForAsyncUpdates(function () - { - do_log_info("Unvisited URI no longer bookmarked => frecency should = 0"); - do_check_eq(frecencyForUrl(TEST_URI), 0); - - remove_all_bookmarks(); - waitForClearHistory(run_next_test); - }); - }); -}); - add_test(function cleared_parent_of_visited_bookmark() { do_log_info("After removing all children from bookmark's parent, frecency " + @@ -347,25 +194,6 @@ add_test(function cleared_parent_of_bookmark_still_bookmarked() /////////////////////////////////////////////////////////////////////////////// -/** - * Creates a livemark with a single child item. - * - * @param aChildURI - * the URI of the livemark's single child item - * @return the item ID of the single child item - */ -function createLivemark(aChildURI) -{ - let livemarkId = PlacesUtils.livemarks.createLivemarkFolderOnly( - PlacesUtils.unfiledBookmarksFolderId, "livemark title", - uri("http://example.com/"), uri("http://example.com/rdf"), -1 - ); - return PlacesUtils.bookmarks.insertBookmark(livemarkId, - aChildURI, - PlacesUtils.bookmarks.DEFAULT_INDEX, - "livemark item title"); -} - /** * Adds a visit for aURI. * diff --git a/toolkit/components/places/tests/unit/xpcshell.ini b/toolkit/components/places/tests/unit/xpcshell.ini index 58a7b438e6a..fb57bf24ef1 100644 --- a/toolkit/components/places/tests/unit/xpcshell.ini +++ b/toolkit/components/places/tests/unit/xpcshell.ini @@ -71,7 +71,6 @@ fail-if = os == "android" [test_download_history.js] # Bug 676989: test fails consistently on Android fail-if = os == "android" -[test_exclude_livemarks.js] [test_faviconService_expireAllFavicons.js] [test_favicons.js] # Bug 676989: test fails consistently on Android @@ -93,8 +92,8 @@ skip-if = os == "android" [test_isURIVisited.js] [test_isvisited.js] [test_lastModified.js] -[test_livemarkService_getLivemarkIdForFeedURI.js] [test_markpageas.js] +[test_mozIAsyncLivemarks.js] [test_moz-anno_favicon_mime_type.js] [test_multi_queries.js] # Bug 676989: test fails consistently on Android diff --git a/toolkit/components/telemetry/TelemetryHistograms.h b/toolkit/components/telemetry/TelemetryHistograms.h index fa4f35ab776..2ceab0a130a 100644 --- a/toolkit/components/telemetry/TelemetryHistograms.h +++ b/toolkit/components/telemetry/TelemetryHistograms.h @@ -57,9 +57,9 @@ */ HISTOGRAM_BOOLEAN(A11Y_INSTANTIATED, "has accessibility support been instantiated") HISTOGRAM(A11Y_CONSUMERS, 1, 6, 7, LINEAR, "Accessibility client by enum id") -HISTOGRAM_BOOLEAN(ISIMPLE_DOM_USAGE, "have the ISimpleDOM* accessibility interfaces been used") -HISTOGRAM_BOOLEAN(IACCESSIBLE_TABLE_USAGE, "has the IAccessibleTable accessibility interface been used") -HISTOGRAM_BOOLEAN(XFORMS_ACCESSIBLE_USED, "has XForms accessibility been instantiated") +HISTOGRAM_BOOLEAN(A11Y_ISIMPLEDOM_USAGE, "have the ISimpleDOM* accessibility interfaces been used") +HISTOGRAM_BOOLEAN(A11Y_IATABLE_USAGE, "has the IAccessibleTable accessibility interface been used") +HISTOGRAM_BOOLEAN(A11Y_XFORMS_USAGE, "has XForms accessibility been instantiated") /** * Cycle collector telemetry diff --git a/toolkit/content/widgets/autocomplete.xml b/toolkit/content/widgets/autocomplete.xml index 5e31d8a35e5..c926d67d4a6 100644 --- a/toolkit/content/widgets/autocomplete.xml +++ b/toolkit/content/widgets/autocomplete.xml @@ -278,7 +278,8 @@ diff --git a/tools/profiler/TableTicker.cpp b/tools/profiler/TableTicker.cpp index 714ff7fb243..23164fe808d 100644 --- a/tools/profiler/TableTicker.cpp +++ b/tools/profiler/TableTicker.cpp @@ -516,11 +516,8 @@ unsigned int sCurrentEventGeneration = 0; void TableTicker::Tick(TickSample* sample) { // Marker(s) come before the sample - int i = 0; - const char *marker = mStack->getMarker(i++); - for (int i = 0; marker != NULL; i++) { - mProfile.addTag(ProfileEntry('m', marker)); - marker = mStack->getMarker(i++); + for (int i = 0; mStack->getMarker(i) != NULL; i++) { + mProfile.addTag(ProfileEntry('m', mStack->getMarker(i))); } mStack->mQueueClearMarker = true; diff --git a/widget/xpwidgets/GfxInfoX11.cpp b/widget/xpwidgets/GfxInfoX11.cpp index 90c31fb2d4b..bb0ea7ebbe4 100644 --- a/widget/xpwidgets/GfxInfoX11.cpp +++ b/widget/xpwidgets/GfxInfoX11.cpp @@ -65,12 +65,14 @@ pid_t glxtest_pid = 0; nsresult GfxInfo::Init() { + mGLMajorVersion = 0; mMajorVersion = 0; mMinorVersion = 0; mRevisionVersion = 0; mIsMesa = false; mIsNVIDIA = false; mIsFGLRX = false; + mIsNouveau = false; mHasTextureFromPixmap = false; return GfxInfoBase::Init(); } @@ -207,6 +209,9 @@ GfxInfo::GetData() CrashReporter::AppendAppNotesToCrashReport(note); #endif + // determine the major OpenGL version. That's the first integer in the version string. + mGLMajorVersion = strtol(mVersion.get(), 0, 10); + // determine driver type (vendor) and where in the version string // the actual driver version numbers should be expected to be found (whereToReadVersionNumbers) const char *whereToReadVersionNumbers = nsnull; @@ -216,6 +221,8 @@ GfxInfo::GetData() // with Mesa, the version string contains "Mesa major.minor" and that's all the version information we get: // there is no actual driver version info. whereToReadVersionNumbers = Mesa_in_version_string + strlen("Mesa"); + if (strcasestr(mVendor.get(), "nouveau")) + mIsNouveau = true; } else if (strstr(mVendor.get(), "NVIDIA Corporation")) { mIsNVIDIA = true; // with the NVIDIA driver, the version string contains "NVIDIA major.minor" @@ -231,7 +238,7 @@ GfxInfo::GetData() whereToReadVersionNumbers = mVersion.get(); } - // read major.minor version numbers + // read major.minor version numbers of the driver (not to be confused with the OpenGL version) if (whereToReadVersionNumbers) { // copy into writable buffer, for tokenization strncpy(buf, whereToReadVersionNumbers, buf_size); @@ -283,6 +290,14 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, if (aOS) *aOS = os; + if (mGLMajorVersion == 1) { + // We're on OpenGL 1. In most cases that indicates really old hardware. + // We better block them, rather than rely on them to fail gracefully, because they don't! + // see bug 696636 + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE; + return NS_OK; + } + #ifdef MOZ_PLATFORM_MAEMO *aStatus = nsIGfxInfo::FEATURE_NO_INFO; // on Maemo, the glxtest probe doesn't build, and we don't really need GfxInfo anyway @@ -318,7 +333,10 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, } if (mIsMesa) { - if (version(mMajorVersion, mMinorVersion, mRevisionVersion) < version(7,10,3)) { + if (mIsNouveau) { + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION; + aSuggestedDriverVersion.AssignLiteral(""); + } else if (version(mMajorVersion, mMinorVersion, mRevisionVersion) < version(7,10,3)) { *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION; aSuggestedDriverVersion.AssignLiteral("Mesa 7.10.3"); } diff --git a/widget/xpwidgets/GfxInfoX11.h b/widget/xpwidgets/GfxInfoX11.h index c89336a2bb2..8a7e9555b9f 100644 --- a/widget/xpwidgets/GfxInfoX11.h +++ b/widget/xpwidgets/GfxInfoX11.h @@ -98,9 +98,9 @@ private: nsCString mRenderer; nsCString mVersion; nsCString mAdapterDescription; - bool mIsMesa, mIsNVIDIA, mIsFGLRX; + bool mIsMesa, mIsNVIDIA, mIsFGLRX, mIsNouveau; bool mHasTextureFromPixmap; - int mMajorVersion, mMinorVersion, mRevisionVersion; + int mGLMajorVersion, mMajorVersion, mMinorVersion, mRevisionVersion; void AddCrashReportAnnotations(); };