diff options
author | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-08-23 01:43:12 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@wolfbeast.com> | 2019-08-23 01:43:12 +0200 |
commit | dd33cb382321351aa3b960a6824cb9ec43bba05b (patch) | |
tree | 729b4065b2a1c849d1fb6ad28b7e0c510f1a6a67 | |
parent | 6a6e4bd25d61ecf21a28ea47f2a74927553fe959 (diff) | |
parent | ab6242a93b849b0a3c7525b16bc01dd3172fc167 (diff) | |
download | UXP-dd33cb382321351aa3b960a6824cb9ec43bba05b.tar UXP-dd33cb382321351aa3b960a6824cb9ec43bba05b.tar.gz UXP-dd33cb382321351aa3b960a6824cb9ec43bba05b.tar.lz UXP-dd33cb382321351aa3b960a6824cb9ec43bba05b.tar.xz UXP-dd33cb382321351aa3b960a6824cb9ec43bba05b.zip |
Merge branch 'master' into Pale_Moon-release
647 files changed, 18502 insertions, 26188 deletions
@@ -22,4 +22,4 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Clobber for NSS Update +Clobber for SpiderMonkey Update diff --git a/application/basilisk/app/Makefile.in b/application/basilisk/app/Makefile.in index 83d6cb36a..b0c1570f6 100644 --- a/application/basilisk/app/Makefile.in +++ b/application/basilisk/app/Makefile.in @@ -75,22 +75,22 @@ MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_A .PHONY: repackage tools repackage:: $(DIST)/bin/$(MOZ_APP_NAME) - $(MKDIR) -p $(dist_dest)/Contents/MacOS - $(MKDIR) -p $(dist_dest)/$(LPROJ) - rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj - rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/$(LPROJ) - sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist - sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/$(LPROJ)/InfoPlist.strings - rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(dist_dest)/Contents/Resources - rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(dist_dest)/Contents/MacOS - $(RM) $(dist_dest)/Contents/MacOS/$(MOZ_APP_NAME) - rsync -aL $(DIST)/bin/$(MOZ_APP_NAME) $(dist_dest)/Contents/MacOS - cp -RL $(DIST)/branding/firefox.icns $(dist_dest)/Contents/Resources/firefox.icns - cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns + $(MKDIR) -p '$(dist_dest)/Contents/MacOS' + $(MKDIR) -p '$(dist_dest)/$(LPROJ)' + rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents '$(dist_dest)' --exclude English.lproj + rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ '$(dist_dest)/$(LPROJ)' + sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' $(srcdir)/macbuild/Contents/Info.plist.in > '$(dist_dest)/Contents/Info.plist' + sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > '$(dist_dest)/$(LPROJ)/InfoPlist.strings' + rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ '$(dist_dest)/Contents/Resources' + rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ '$(dist_dest)/Contents/MacOS' + $(RM) '$(dist_dest)/Contents/MacOS/$(MOZ_APP_NAME)' + rsync -aL $(DIST)/bin/$(MOZ_APP_NAME) '$(dist_dest)/Contents/MacOS' + cp -RL $(DIST)/branding/firefox.icns '$(dist_dest)/Contents/Resources/firefox.icns' + cp -RL $(DIST)/branding/document.icns '$(dist_dest)/Contents/Resources/document.icns' ifdef MOZ_UPDATER - $(MKDIR) -p $(dist_dest)/Contents/Library/LaunchServices - mv -f $(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater $(dist_dest)/Contents/Library/LaunchServices - ln -s ../../../../Library/LaunchServices/org.mozilla.updater $(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater + $(MKDIR) -p '$(dist_dest)/Contents/Library/LaunchServices' + mv -f '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater' '$(dist_dest)/Contents/Library/LaunchServices' + ln -s ../../../../Library/LaunchServices/org.mozilla.updater '$(dist_dest)/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater' endif - printf APPLMOZB > $(dist_dest)/Contents/PkgInfo + printf APPLMOZB > '$(dist_dest)/Contents/PkgInfo' endif diff --git a/application/basilisk/app/profile/basilisk.js b/application/basilisk/app/profile/basilisk.js index c229f3523..a773bc60e 100644 --- a/application/basilisk/app/profile/basilisk.js +++ b/application/basilisk/app/profile/basilisk.js @@ -53,12 +53,6 @@ pref("extensions.getAddons.recommended.browseURL", "https://@AM_DOMAIN@/?compone pref("extensions.update.autoUpdateDefault", true); -// Leave these for the moment... -pref("extensions.hotfix.id", "firefox-hotfix@mozilla.org"); -pref("extensions.hotfix.cert.checkAttributes", true); -pref("extensions.hotfix.certs.1.sha1Fingerprint", "91:53:98:0C:C1:86:DF:47:8F:35:22:9E:11:C9:A7:31:04:49:A1:AA"); -pref("extensions.hotfix.certs.2.sha1Fingerprint", "39:E7:2B:7A:5B:CF:37:78:F9:5D:4A:E0:53:2D:2F:3D:68:53:C5:60"); - // Also, leave this for the moment... // Check AUS for system add-on updates. pref("extensions.systemAddon.update.url", "https://aus5.mozilla.org/update/3/SystemAddons/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml"); @@ -1015,12 +1009,7 @@ pref("services.sync.syncedTabs.showRemoteIcons", true); pref("services.sync.sendTabToDevice.enabled", true); -// Developer edition preferences -#ifdef MOZ_DEV_EDITION -sticky_pref("lightweightThemes.selectedThemeID", "firefox-devedition@mozilla.org"); -#else sticky_pref("lightweightThemes.selectedThemeID", ""); -#endif // Whether the character encoding menu is under the main Firefox button. This // preference is a string so that localizers can alter it. diff --git a/application/basilisk/base/content/browser-devedition.js b/application/basilisk/base/content/browser-devedition.js deleted file mode 100644 index 0dc1e94da..000000000 --- a/application/basilisk/base/content/browser-devedition.js +++ /dev/null @@ -1,142 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Listeners for the DevEdition theme. This adds an extra stylesheet - * to browser.xul if a pref is set and no other themes are applied. - */ -var DevEdition = { - _devtoolsThemePrefName: "devtools.theme", - styleSheetLocation: "chrome://browser/skin/devedition.css", - styleSheet: null, - initialized: false, - - get isStyleSheetEnabled() { - return this.styleSheet && !this.styleSheet.sheet.disabled; - }, - - get isThemeCurrentlyApplied() { - let theme = LightweightThemeManager.currentTheme; - return theme && theme.id == "firefox-devedition@mozilla.org"; - }, - - init: function () { - this.initialized = true; - Services.prefs.addObserver(this._devtoolsThemePrefName, this, false); - Services.obs.addObserver(this, "lightweight-theme-styling-update", false); - Services.obs.addObserver(this, "lightweight-theme-window-updated", false); - this._updateDevtoolsThemeAttribute(); - - if (this.isThemeCurrentlyApplied) { - this._toggleStyleSheet(true); - } - }, - - createStyleSheet: function() { - let styleSheetAttr = `href="${this.styleSheetLocation}" type="text/css"`; - this.styleSheet = document.createProcessingInstruction( - "xml-stylesheet", styleSheetAttr); - this.styleSheet.addEventListener("load", this); - document.insertBefore(this.styleSheet, document.documentElement); - this.styleSheet.sheet.disabled = true; - }, - - observe: function (subject, topic, data) { - if (topic == "lightweight-theme-styling-update") { - let newTheme = JSON.parse(data); - if (newTheme && newTheme.id == "firefox-devedition@mozilla.org") { - this._toggleStyleSheet(true); - } else { - this._toggleStyleSheet(false); - } - } else if (topic == "lightweight-theme-window-updated" && subject == window) { - this._updateLWTBrightness(); - } - - if (topic == "nsPref:changed" && data == this._devtoolsThemePrefName) { - this._updateDevtoolsThemeAttribute(); - } - }, - - _inferBrightness: function() { - ToolbarIconColor.inferFromText(); - // Get an inverted full screen button if the dark theme is applied. - if (this.isStyleSheetEnabled && - document.documentElement.getAttribute("devtoolstheme") == "dark") { - document.documentElement.setAttribute("brighttitlebarforeground", "true"); - } else { - document.documentElement.removeAttribute("brighttitlebarforeground"); - } - }, - - _updateLWTBrightness() { - if (this.isThemeCurrentlyApplied) { - let devtoolsTheme = Services.prefs.getCharPref(this._devtoolsThemePrefName); - let textColor = devtoolsTheme == "dark" ? "bright" : "dark"; - document.documentElement.setAttribute("lwthemetextcolor", textColor); - } - }, - - _updateDevtoolsThemeAttribute: function() { - // Set an attribute on root element to make it possible - // to change colors based on the selected devtools theme. - let devtoolsTheme = Services.prefs.getCharPref(this._devtoolsThemePrefName); - if (devtoolsTheme != "dark") { - devtoolsTheme = "light"; - } - document.documentElement.setAttribute("devtoolstheme", devtoolsTheme); - this._updateLWTBrightness(); - this._inferBrightness(); - }, - - handleEvent: function(e) { - if (e.type === "load") { - this.styleSheet.removeEventListener("load", this); - this.refreshBrowserDisplay(); - } - }, - - refreshBrowserDisplay: function() { - // Don't touch things on the browser if gBrowserInit.onLoad hasn't - // yet fired. - if (this.initialized) { - gBrowser.tabContainer._positionPinnedTabs(); - this._inferBrightness(); - } - }, - - _toggleStyleSheet: function(deveditionThemeEnabled) { - let wasEnabled = this.isStyleSheetEnabled; - if (deveditionThemeEnabled && !wasEnabled) { - // The stylesheet may not have been created yet if it wasn't - // needed on initial load. Make it now. - if (!this.styleSheet) { - this.createStyleSheet(); - } - this.styleSheet.sheet.disabled = false; - this.refreshBrowserDisplay(); - } else if (!deveditionThemeEnabled && wasEnabled) { - this.styleSheet.sheet.disabled = true; - this.refreshBrowserDisplay(); - } - }, - - uninit: function () { - Services.prefs.removeObserver(this._devtoolsThemePrefName, this); - Services.obs.removeObserver(this, "lightweight-theme-styling-update", false); - Services.obs.removeObserver(this, "lightweight-theme-window-updated", false); - if (this.styleSheet) { - this.styleSheet.removeEventListener("load", this); - } - this.styleSheet = null; - } -}; - -// If the DevEdition theme is going to be applied in gBrowserInit.onLoad, -// then preload it now. This prevents a flash of unstyled content where the -// normal theme is applied while the DevEdition stylesheet is loading. -if (!AppConstants.RELEASE_OR_BETA && - this != Services.appShell.hiddenDOMWindow && DevEdition.isThemeCurrentlyApplied) { - DevEdition.createStyleSheet(); -} diff --git a/application/basilisk/base/content/browser.js b/application/basilisk/base/content/browser.js index 1dee19a1d..bbd240e69 100644 --- a/application/basilisk/base/content/browser.js +++ b/application/basilisk/base/content/browser.js @@ -956,7 +956,6 @@ var gBrowserInit = { gPageStyleMenu.init(); BrowserOnClick.init(); FeedHandler.init(); - DevEdition.init(); AboutPrivateBrowsingListener.init(); TrackingProtection.init(); RefreshBlocker.init(); @@ -1479,8 +1478,6 @@ var gBrowserInit = { FeedHandler.uninit(); - DevEdition.uninit(); - TrackingProtection.uninit(); RefreshBlocker.uninit(); diff --git a/application/basilisk/base/content/global-scripts.inc b/application/basilisk/base/content/global-scripts.inc index db8496cfc..6edb11214 100644 --- a/application/basilisk/base/content/global-scripts.inc +++ b/application/basilisk/base/content/global-scripts.inc @@ -14,7 +14,6 @@ <script type="application/javascript" src="chrome://browser/content/browser-captivePortal.js"/> <script type="application/javascript" src="chrome://browser/content/browser-ctrlTab.js"/> <script type="application/javascript" src="chrome://browser/content/browser-customization.js"/> -<script type="application/javascript" src="chrome://browser/content/browser-devedition.js"/> <script type="application/javascript" src="chrome://browser/content/browser-feeds.js"/> <script type="application/javascript" src="chrome://browser/content/browser-fullScreenAndPointerLock.js"/> <script type="application/javascript" src="chrome://browser/content/browser-fullZoom.js"/> diff --git a/application/basilisk/base/content/tabbrowser.xml b/application/basilisk/base/content/tabbrowser.xml index 0e819a3ed..85f923923 100644 --- a/application/basilisk/base/content/tabbrowser.xml +++ b/application/basilisk/base/content/tabbrowser.xml @@ -6906,21 +6906,22 @@ <handlers> <handler event="popupshowing"> <![CDATA[ - document.getElementById("alltabs_undoCloseTab").disabled = - SessionStore.getClosedTabCount(window) == 0; - - // Listen for changes in the tab bar. - tabcontainer.addEventListener("TabAttrModified", this, false); - tabcontainer.addEventListener("TabClose", this, false); - tabcontainer.mTabstrip.addEventListener("scroll", this, false); - - let tabs = gBrowser.visibleTabs; - for (var i = 0; i < tabs.length; i++) { - if (!tabs[i].pinned) - this._createTabMenuItem(tabs[i]); - } - this._updateTabsVisibilityStatus(); + document.getElementById("alltabs_undoCloseTab").disabled = + SessionStore.getClosedTabCount(window) == 0; + + var tabcontainer = gBrowser.tabContainer; + + // Listen for changes in the tab bar. + tabcontainer.addEventListener("TabAttrModified", this, false); + tabcontainer.addEventListener("TabClose", this, false); + tabcontainer.mTabstrip.addEventListener("scroll", this, false); + + let tabs = gBrowser.visibleTabs; + for (var i = 0; i < tabs.length; i++) { + if (!tabs[i].pinned) + this._createTabMenuItem(tabs[i]); } + this._updateTabsVisibilityStatus(); ]]></handler> <handler event="popuphidden"> diff --git a/application/basilisk/base/jar.mn b/application/basilisk/base/jar.mn index 76727731b..f546ec4bd 100644 --- a/application/basilisk/base/jar.mn +++ b/application/basilisk/base/jar.mn @@ -63,7 +63,6 @@ browser.jar: content/browser/browser-ctrlTab.js (content/browser-ctrlTab.js) content/browser/browser-customization.js (content/browser-customization.js) content/browser/browser-data-submission-info-bar.js (content/browser-data-submission-info-bar.js) - content/browser/browser-devedition.js (content/browser-devedition.js) content/browser/browser-feeds.js (content/browser-feeds.js) content/browser/browser-fullScreenAndPointerLock.js (content/browser-fullScreenAndPointerLock.js) content/browser/browser-fullZoom.js (content/browser-fullZoom.js) diff --git a/application/basilisk/components/customizableui/CustomizableUI.jsm b/application/basilisk/components/customizableui/CustomizableUI.jsm index d56d63d99..ce395121c 100644 --- a/application/basilisk/components/customizableui/CustomizableUI.jsm +++ b/application/basilisk/components/customizableui/CustomizableUI.jsm @@ -38,7 +38,6 @@ const kPrefCustomizationState = "browser.uiCustomization.state"; const kPrefCustomizationAutoAdd = "browser.uiCustomization.autoAdd"; const kPrefCustomizationDebug = "browser.uiCustomization.debug"; const kPrefDrawInTitlebar = "browser.tabs.drawInTitlebar"; -const kPrefWebIDEInNavbar = "devtools.webide.widget.inNavbarByDefault"; const kExpectedWindowURL = "chrome://browser/content/browser.xul"; @@ -199,9 +198,7 @@ var CustomizableUIInternal = { "add-ons-button", ]; - if (!AppConstants.MOZ_DEV_EDITION) { - panelPlacements.splice(-1, 0, "developer-button"); - } + panelPlacements.splice(-1, 0, "developer-button"); let showCharacterEncoding = Services.prefs.getComplexValue( "browser.menu.showCharacterEncoding", @@ -226,14 +223,6 @@ var CustomizableUIInternal = { "home-button", ]; - if (AppConstants.MOZ_DEV_EDITION) { - navbarPlacements.splice(2, 0, "developer-button"); - } - - if (Services.prefs.getBoolPref(kPrefWebIDEInNavbar)) { - navbarPlacements.push("webide-button"); - } - // Place this last, when createWidget is called for pocket, it will // append to the toolbar. if (Services.prefs.getPrefType("extensions.pocket.enabled") != Services.prefs.PREF_INVALID && diff --git a/application/basilisk/components/nsBrowserGlue.js b/application/basilisk/components/nsBrowserGlue.js index d29009b13..5d3e4689b 100644 --- a/application/basilisk/components/nsBrowserGlue.js +++ b/application/basilisk/components/nsBrowserGlue.js @@ -676,19 +676,6 @@ BrowserGlue.prototype = { // Ensure we keep track of places/pw-mananager undo by init'ing this early. Cu.import("resource:///modules/AutoMigrate.jsm"); - if (!AppConstants.RELEASE_OR_BETA) { - let themeName = gBrowserBundle.GetStringFromName("deveditionTheme.name"); - let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName"); - - LightweightThemeManager.addBuiltInTheme({ - id: "firefox-devedition@mozilla.org", - name: themeName, - headerURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.header.png", - iconURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.icon.png", - author: vendorShortName, - }); - } - TabCrashHandler.init(); Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); @@ -1054,10 +1041,6 @@ BrowserGlue.prototype = { // All initial windows have opened. _onWindowsRestored: function BG__onWindowsRestored() { - if (AppConstants.MOZ_DEV_EDITION) { - this._createExtraDefaultProfile(); - } - this._initServiceDiscovery(); // Show update notification, if needed. @@ -1074,7 +1057,7 @@ BrowserGlue.prototype = { // them to the user. let changedIDs = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_INSTALLED); if (changedIDs.length > 0) { - let win = this.getMostRecentBrowserWindow(); + let win = RecentWindow.getMostRecentBrowserWindow(); AddonManager.getAddonsByIDs(changedIDs, function(aAddons) { aAddons.forEach(function(aAddon) { // If the add-on isn't user disabled or can't be enabled then skip it. @@ -1193,40 +1176,6 @@ BrowserGlue.prototype = { E10SAccessibilityCheck.onWindowsRestored(); }, - _createExtraDefaultProfile: function () { - if (!AppConstants.MOZ_DEV_EDITION) { - return; - } - // If Developer Edition is the only installed Firefox version and no other - // profiles are present, create a second one for use by other versions. - // This helps Firefox versions earlier than 35 avoid accidentally using the - // unsuitable Developer Edition profile. - let profileService = Cc["@mozilla.org/toolkit/profile-service;1"] - .getService(Ci.nsIToolkitProfileService); - let profileCount = profileService.profileCount; - if (profileCount == 1 && profileService.selectedProfile.name != "default") { - let newProfile; - try { - newProfile = profileService.createProfile(null, "default"); - profileService.defaultProfile = newProfile; - profileService.flush(); - } catch (e) { - Cu.reportError("Could not create profile 'default': " + e); - } - if (newProfile) { - // We don't want a default profile with Developer Edition settings, an - // empty profile directory will do. The profile service of the other - // Firefox will populate it with its own stuff. - let newProfilePath = newProfile.rootDir.path; - OS.File.removeDir(newProfilePath).then(() => { - return OS.File.makeDir(newProfilePath); - }).then(null, e => { - Cu.reportError("Could not empty profile 'default': " + e); - }); - } - } - }, - _onQuitRequest: function BG__onQuitRequest(aCancelQuit, aQuitType) { // If user has already dismissed quit request, then do nothing if ((aCancelQuit instanceof Ci.nsISupportsPRBool) && aCancelQuit.data) @@ -1981,14 +1930,8 @@ BrowserGlue.prototype = { defaultThemeSelected = Services.prefs.getCharPref("general.skins.selectedSkin") == "classic/1.0"; } catch (e) {} - // If we are on the devedition channel, the devedition theme is on by - // default. But we need to handle the case where they didn't want it - // applied, and unapply the theme. - let userChoseToNotUseDeveditionTheme = - !defaultThemeSelected || - (lightweightThemeSelected && selectedThemeID != "firefox-devedition@mozilla.org"); - - if (userChoseToNotUseDeveditionTheme && selectedThemeID == "firefox-devedition@mozilla.org") { + // If we have the dev edition theme selected, reset it. + if (selectedThemeID == "firefox-devedition@mozilla.org") { Services.prefs.setCharPref("lightweightThemes.selectedThemeID", ""); } diff --git a/application/basilisk/components/places/content/controller.js b/application/basilisk/components/places/content/controller.js index ebdab60f4..931c8fac1 100644 --- a/application/basilisk/components/places/content/controller.js +++ b/application/basilisk/components/places/content/controller.js @@ -461,7 +461,11 @@ PlacesController.prototype = { if (parentNode) { if (PlacesUtils.nodeIsTagQuery(parentNode)) nodeData["tagChild"] = true; - else if (this.hasCachedLivemarkInfo(parentNode)) + } + } else { + var parentNode = node.parent; + if (parentNode) { + if (this.hasCachedLivemarkInfo(parentNode)) nodeData["livemarkChild"] = true; } } diff --git a/application/basilisk/components/places/content/placesOverlay.xul b/application/basilisk/components/places/content/placesOverlay.xul index 512eb923e..2dbef0f04 100644 --- a/application/basilisk/components/places/content/placesOverlay.xul +++ b/application/basilisk/components/places/content/placesOverlay.xul @@ -198,7 +198,7 @@ accesskey="&cmd.delete.accesskey;" closemenu="single" selection="link" - forcehideselection="bookmark"/> + forcehideselection="bookmark|livemarkChild"/> <menuitem id="placesContext_deleteHost" command="placesCmd_deleteDataHost" label="&cmd.deleteDomainData.label;" @@ -207,7 +207,7 @@ selection="link|host" selectiontype="single" hideifprivatebrowsing="true" - forcehideselection="bookmark"/> + forcehideselection="bookmark|livemarkChild"/> <menuseparator id="placesContext_deleteSeparator"/> <menuitem id="placesContext_sortBy:name" command="placesCmd_sortBy:name" diff --git a/application/basilisk/components/preferences/in-content/main.js b/application/basilisk/components/preferences/in-content/main.js index bac771bec..8f3dffa57 100644 --- a/application/basilisk/components/preferences/in-content/main.js +++ b/application/basilisk/components/preferences/in-content/main.js @@ -78,18 +78,6 @@ var gMainPane = { setEventListener("chooseFolder", "command", gMainPane.chooseFolder); - if (AppConstants.MOZ_DEV_EDITION) { - let uAppData = OS.Constants.Path.userApplicationDataDir; - let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile"); - - setEventListener("separateProfileMode", "command", gMainPane.separateProfileModeChange); - let separateProfileModeCheckbox = document.getElementById("separateProfileMode"); - setEventListener("getStarted", "click", gMainPane.onGetStarted); - - OS.File.stat(ignoreSeparateProfile).then(() => separateProfileModeCheckbox.checked = false, - () => separateProfileModeCheckbox.checked = true); - } - // Notify observers that the UI is now ready Components.classes["@mozilla.org/observer-service;1"] .getService(Components.interfaces.nsIObserverService) @@ -101,71 +89,6 @@ var gMainPane = { // **STUB** }, - separateProfileModeChange: function () - { - if (AppConstants.MOZ_DEV_EDITION) { - function quitApp() { - Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestartNotSameProfile); - } - function revertCheckbox(error) { - separateProfileModeCheckbox.checked = !separateProfileModeCheckbox.checked; - if (error) { - Cu.reportError("Failed to toggle separate profile mode: " + error); - } - } - function createOrRemoveSpecialDevEditionFile(onSuccess) { - let uAppData = OS.Constants.Path.userApplicationDataDir; - let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile"); - - if (separateProfileModeCheckbox.checked) { - OS.File.remove(ignoreSeparateProfile).then(onSuccess, revertCheckbox); - } else { - OS.File.writeAtomic(ignoreSeparateProfile, new Uint8Array()).then(onSuccess, revertCheckbox); - } - } - - let separateProfileModeCheckbox = document.getElementById("separateProfileMode"); - let button_index = confirmRestartPrompt(separateProfileModeCheckbox.checked, - 0, false, true); - switch (button_index) { - case CONFIRM_RESTART_PROMPT_CANCEL: - revertCheckbox(); - return; - case CONFIRM_RESTART_PROMPT_RESTART_NOW: - const Cc = Components.classes, Ci = Components.interfaces; - let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"] - .createInstance(Ci.nsISupportsPRBool); - Services.obs.notifyObservers(cancelQuit, "quit-application-requested", - "restart"); - if (!cancelQuit.data) { - createOrRemoveSpecialDevEditionFile(quitApp); - return; - } - - // Revert the checkbox in case we didn't quit - revertCheckbox(); - return; - case CONFIRM_RESTART_PROMPT_RESTART_LATER: - createOrRemoveSpecialDevEditionFile(); - return; - } - } - }, - - onGetStarted: function (aEvent) { - if (AppConstants.MOZ_DEV_EDITION) { - const Cc = Components.classes, Ci = Components.interfaces; - let wm = Cc["@mozilla.org/appshell/window-mediator;1"] - .getService(Ci.nsIWindowMediator); - let win = wm.getMostRecentWindow("navigator:browser"); - - if (win) { - let accountsTab = win.gBrowser.addTab("about:accounts?action=signin&entrypoint=dev-edition-setup"); - win.gBrowser.selectedTab = accountsTab; - } - } - }, - // HOME PAGE /* diff --git a/application/basilisk/components/preferences/in-content/main.xul b/application/basilisk/components/preferences/in-content/main.xul index 8eca11877..f695b308b 100644 --- a/application/basilisk/components/preferences/in-content/main.xul +++ b/application/basilisk/components/preferences/in-content/main.xul @@ -112,17 +112,6 @@ hidden="true"> <caption><label>&startup.label;</label></caption> -#ifdef MOZ_DEV_EDITION - <vbox id="separateProfileBox"> - <checkbox id="separateProfileMode" - label="&separateProfileMode.label;"/> - <hbox align="center" class="indent"> - <label id="useFirefoxSync">&useFirefoxSync.label;</label> - <label id="getStarted" class="text-link">&getStarted.label;</label> - </hbox> - </vbox> -#endif - #ifdef HAVE_SHELL_SERVICE <vbox id="defaultBrowserBox"> <hbox align="center"> diff --git a/application/basilisk/installer/Makefile.in b/application/basilisk/installer/Makefile.in index 4de368db7..1ca3b8ee0 100644 --- a/application/basilisk/installer/Makefile.in +++ b/application/basilisk/installer/Makefile.in @@ -99,19 +99,19 @@ include $(topsrcdir)/toolkit/mozapps/installer/packager.mk ifeq (bundle, $(MOZ_FS_LAYOUT)) BINPATH = $(_BINPATH) -DEFINES += -DAPPNAME=$(_APPNAME) +DEFINES += -DAPPNAME='$(_APPNAME)' else # Every other platform just winds up in dist/bin BINPATH = bin endif -DEFINES += -DBINPATH=$(BINPATH) +DEFINES += -DBINPATH='$(BINPATH)' ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) RESPATH = $(_APPNAME)/Contents/Resources else RESPATH = $(BINPATH) endif -DEFINES += -DRESPATH=$(RESPATH) +DEFINES += -DRESPATH='$(RESPATH)' LPROJ_ROOT = $(firstword $(subst -, ,$(AB_CD))) ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) @@ -164,7 +164,7 @@ FINDPATH=bin endif package-compare:: - cd $(DIST); find $(PKGCOMP_FIND_OPTS) $(FINDPATH) -type f | sort > bin-list.txt + cd $(DIST); find $(PKGCOMP_FIND_OPTS) '$(FINDPATH)' -type f | sort > bin-list.txt $(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $(MOZ_PKG_MANIFEST)) | grep '^$(BINPATH)' | sed -e 's/^\///' | sort > $(DIST)/pack-list.txt -diff -u $(DIST)/pack-list.txt $(DIST)/bin-list.txt rm -f $(DIST)/pack-list.txt $(DIST)/bin-list.txt diff --git a/application/basilisk/installer/package-manifest.in b/application/basilisk/installer/package-manifest.in index 71f775904..bffab0f6e 100644 --- a/application/basilisk/installer/package-manifest.in +++ b/application/basilisk/installer/package-manifest.in @@ -183,6 +183,7 @@ @RESPATH@/components/dom.xpt @RESPATH@/components/dom_apps.xpt @RESPATH@/components/dom_base.xpt +@RESPATH@/components/dom_bindings.xpt @RESPATH@/components/dom_system.xpt @RESPATH@/components/dom_canvas.xpt @RESPATH@/components/dom_core.xpt @@ -354,8 +355,6 @@ @RESPATH@/browser/components/nsSetDefaultBrowser.js @RESPATH@/browser/components/devtools-startup.manifest @RESPATH@/browser/components/devtools-startup.js -@RESPATH@/browser/components/webideCli.js -@RESPATH@/browser/components/webideComponents.manifest @RESPATH@/browser/components/browser-newtab.xpt @RESPATH@/browser/components/aboutNewTabService.js @RESPATH@/browser/components/NewTabComponents.manifest @@ -595,11 +594,6 @@ @RESPATH@/browser/chrome/icons/default/default48.png #endif -; [Webide Files] -@RESPATH@/browser/chrome/webide@JAREXT@ -@RESPATH@/browser/chrome/webide.manifest -@RESPATH@/browser/@PREF_DIR@/webide-prefs.js - ; DevTools @RESPATH@/browser/chrome/devtools@JAREXT@ @RESPATH@/browser/chrome/devtools.manifest diff --git a/application/basilisk/locales/Makefile.in b/application/basilisk/locales/Makefile.in index 527922b11..0d8b1d86a 100644 --- a/application/basilisk/locales/Makefile.in +++ b/application/basilisk/locales/Makefile.in @@ -170,10 +170,10 @@ endif ident: @printf 'fx_revision ' @$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \ - $(STAGEDIST)/application.ini App SourceStamp + '$(STAGEDIST)'/application.ini App SourceStamp @printf 'buildid ' @$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \ - $(STAGEDIST)/application.ini App BuildID + '$(STAGEDIST)'/application.ini App BuildID merge-%: ifdef LOCALE_MERGEDIR diff --git a/application/basilisk/modules/ProcessHangMonitor.jsm b/application/basilisk/modules/ProcessHangMonitor.jsm index b1f6f2a97..80c506ac7 100644 --- a/application/basilisk/modules/ProcessHangMonitor.jsm +++ b/application/basilisk/modules/ProcessHangMonitor.jsm @@ -304,16 +304,6 @@ var ProcessHangMonitor = { } }]; - if (AppConstants.MOZ_DEV_EDITION && report.hangType == report.SLOW_SCRIPT) { - buttons.push({ - label: bundle.getString("processHang.button_debug.label"), - accessKey: bundle.getString("processHang.button_debug.accessKey"), - callback: function() { - ProcessHangMonitor.debugScript(win); - } - }); - } - nb.appendNotification(bundle.getString("processHang.label"), "process-hang", "chrome://browser/skin/slowStartup-16.png", diff --git a/application/basilisk/themes/linux/devedition.css b/application/basilisk/themes/linux/devedition.css deleted file mode 100644 index 1f16d5d63..000000000 --- a/application/basilisk/themes/linux/devedition.css +++ /dev/null @@ -1,106 +0,0 @@ -% This Source Code Form is subject to the terms of the Mozilla Public -% License, v. 2.0. If a copy of the MPL was not distributed with this -% file, You can obtain one at http://mozilla.org/MPL/2.0/. - -%include ../shared/devedition.inc.css - -:root { - --forwardbutton-width: 29px; -} - -:root[devtoolstheme="light"] { - --urlbar-dropmarker-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg"); - --urlbar-dropmarker-region: rect(0px, 11px, 14px, 0px); - --urlbar-dropmarker-hover-region: rect(0, 22px, 14px, 11px); - --urlbar-dropmarker-active-region: rect(0px, 33px, 14px, 22px); - --urlbar-dropmarker-2x-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg"); - --urlbar-dropmarker-2x-region: rect(0px, 11px, 14px, 0px); - --urlbar-dropmarker-hover-2x-region: rect(0, 22px, 14px, 11px); - --urlbar-dropmarker-active-2x-region: rect(0px, 33px, 14px, 22px); -} - -:root[devtoolstheme="dark"] .findbar-closebutton:not(:hover), -:root[devtoolstheme="dark"] #sidebar-header > .close-icon:not(:hover), -.tab-close-button[selected]:not(:hover) { - background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64); -} - -/* The menubar and tabs toolbar should match the devedition theme */ -#TabsToolbar, -#toolbar-menubar { - -moz-appearance: none !important; -} -#main-menubar { - color: var(--chrome-color); -} -#main-menubar > menu:not([open]) { - color: inherit; -} - -/* Allow buttons with -moz-appearance set to look normal on hover and open states */ -#navigator-toolbox .toolbarbutton-1:-moz-any(:hover, [open="true"]), -#PlacesToolbar toolbarbutton.bookmark-item:-moz-any(:hover, [open="true"]) { - color: initial; -} - -/* Square back and forward buttons */ -#back-button > .toolbarbutton-icon, -#forward-button > .toolbarbutton-icon { - margin: 0; - border: 1px solid var(--chrome-nav-bar-controls-border-color); - padding: 2px 5px; - background: var(--chrome-nav-buttons-background); - box-shadow: none !important; -} - -#forward-button > .toolbarbutton-icon { - border-inline-start: none; -} - -/* Override a box shadow for disabled back button */ -#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon { - box-shadow: none !important; -} - -#back-button:hover:not([disabled="true"]) > .toolbarbutton-icon, -#forward-button:hover:not([disabled="true"]) > .toolbarbutton-icon { - background: var(--chrome-nav-buttons-hover-background) !important; -} - -#back-button > .toolbarbutton-icon { - border-radius: 2px 0 0 2px !important; -} - -.urlbar-history-dropmarker { - -moz-appearance: none; - padding: 0 3px; - list-style-image: var(--urlbar-dropmarker-url); - -moz-image-region: var(--urlbar-dropmarker-region); -} - -/* Add the proper background for tab overflow */ -#alltabs-button, -#new-tab-button { - background: var(--chrome-background-color); -} - -#new-tab-button:hover > .toolbarbutton-icon { - border-color: transparent !important; -} - -/* Prevent double border below tabs toolbar */ -#TabsToolbar:not([collapsed="true"]) + #nav-bar { - border-top-width: 0 !important; -} - -/* Fix the bad-looking text-shadow in the sidebar header: */ -.sidebar-header, -#sidebar-header { - text-shadow: none; -} - -.ac-type-icon { - /* Left-align the type icon in awesomebar popup results with the icon in the - urlbar. */ - margin-inline-start: 11px; -} diff --git a/application/basilisk/themes/linux/jar.mn b/application/basilisk/themes/linux/jar.mn index e9f666418..81581dfaa 100644 --- a/application/basilisk/themes/linux/jar.mn +++ b/application/basilisk/themes/linux/jar.mn @@ -13,7 +13,6 @@ browser.jar: #endif skin/classic/browser/actionicon-tab.png * skin/classic/browser/browser.css -* skin/classic/browser/devedition.css * skin/classic/browser/browser-lightweightTheme.css skin/classic/browser/click-to-play-warning-stripes.png skin/classic/browser/Info.png diff --git a/application/basilisk/themes/osx/devedition.css b/application/basilisk/themes/osx/devedition.css deleted file mode 100644 index c7a2bdd71..000000000 --- a/application/basilisk/themes/osx/devedition.css +++ /dev/null @@ -1,121 +0,0 @@ -% This Source Code Form is subject to the terms of the Mozilla Public -% License, v. 2.0. If a copy of the MPL was not distributed with this -% file, You can obtain one at http://mozilla.org/MPL/2.0/. - -%include ../shared/devedition.inc.css - -:root { - --forwardbutton-width: 32px; -} - -/* Use only 1px separator between nav toolbox and page content */ -#navigator-toolbox::after { - border-top-style: none; - margin-top: -1px; -} - -/* Include extra space on left/right for dragging since there is no space above - the tabs */ -#main-window[tabsintitlebar] #TabsToolbar { - padding-left: 50px; - padding-right: 50px; - margin-bottom: 0; /* Don't overlap the inner highlight at the top of the nav-bar */ -} - -/* Get rid of 1px bright strip at the top of window */ -#main-window[tabsintitlebar] #titlebar-content { - background: var(--chrome-background-color); -} - -/* Resize things so that the native titlebar is in line with the tabs */ -#main-window[tabsintitlebar] > #titlebar > #titlebar-content > #titlebar-buttonbox-container, -#main-window[tabsintitlebar] > #titlebar > #titlebar-content > #titlebar-secondary-buttonbox > #titlebar-fullscreen-button { - margin-top: 6px; -} - -/* Square back and forward buttons. Need !important on these because there - are a lot of more specific selectors sprinkled around elsewhere for changing - background / shadows for different states */ -#back-button, -#forward-button { - height: 24px !important; - box-shadow: none !important; - border: 1px solid var(--chrome-nav-bar-controls-border-color) !important; - background: var(--chrome-nav-buttons-background) !important; -} - -#forward-button { - border-inline-start: none !important; - /* browser.css and friends set up the width of the button to be 32px. - * They then set margin-left to -2px to ensure the button is not too wide - * compared to the back button, and set padding-left to center the icon - * correctly. - * In our theme, the back and forward buttons are the same width, with the - * back button being 32px with 1px border on both sides. To ensure the - * forward button's content box looks like it is the same size with width - * set to 32px and a 1px border on only 1 side, we overlap by 1px, so both - * buttons end up with a content box that looks like it's 30px. - */ - margin-left: -1px; - padding-left: 1px; -} - -#forward-button > .toolbarbutton-icon { - margin-left: 0; - margin-right: 0; -} - -#back-button:hover:not([disabled="true"]), -#forward-button:hover:not([disabled="true"]) { - background: var(--chrome-nav-buttons-hover-background) !important; -} - -#back-button { - border-radius: 3px 0 0 3px !important; - padding: 0 !important; - margin: 0 !important; -} - -#back-button:hover:active:not([disabled="true"]) { - -moz-image-region: rect(18px, 54px, 36px, 36px); -} - -/* Use smaller back button icon */ -@media (min-resolution: 2dppx) { - #back-button:hover:active:not([disabled="true"]) { - -moz-image-region: rect(36px, 108px, 72px, 72px); - } -} - -/* Don't use the default background for tabs toolbar */ -#TabsToolbar { - -moz-appearance: none !important; -} - -/* Prevent the hover styling from on the identity icon from overlapping the - urlbar border. */ -#identity-box { - margin-top: -1px !important; - margin-bottom: -1px !important; - padding-top: 3px !important; - padding-bottom: 3px !important; -} - -:root[devtoolstheme="dark"] .findbar-closebutton:not(:hover), -/* Tab styling - make sure to use an inverted icon for the selected tab - (brighttext only covers the unselected tabs) */ -.tab-close-button[selected=true]:not(:hover) { - -moz-image-region: rect(0, 64px, 16px, 48px); -} -@media (min-resolution: 2dppx) { - :root[devtoolstheme="dark"] .findbar-closebutton:not(:hover), - .tab-close-button[selected=true]:not(:hover) { - -moz-image-region: rect(0, 128px, 32px, 96px); - } -} - -.ac-type-icon { - /* Left-align the type icon in awesomebar popup results with the icon in the - urlbar. */ - margin-inline-start: 14px; -} diff --git a/application/basilisk/themes/osx/jar.mn b/application/basilisk/themes/osx/jar.mn index 92d2ceedf..5dec6559a 100644 --- a/application/basilisk/themes/osx/jar.mn +++ b/application/basilisk/themes/osx/jar.mn @@ -13,7 +13,6 @@ browser.jar: skin/classic/browser/actionicon-tab.png skin/classic/browser/actionicon-tab@2x.png * skin/classic/browser/browser.css -* skin/classic/browser/devedition.css * skin/classic/browser/browser-lightweightTheme.css skin/classic/browser/click-to-play-warning-stripes.png skin/classic/browser/Info.png diff --git a/application/basilisk/themes/shared/devedition.inc.css b/application/basilisk/themes/shared/devedition.inc.css deleted file mode 100644 index a5c0db948..000000000 --- a/application/basilisk/themes/shared/devedition.inc.css +++ /dev/null @@ -1,311 +0,0 @@ -% This Source Code Form is subject to the terms of the Mozilla Public -% License, v. 2.0. If a copy of the MPL was not distributed with this -% file, You can obtain one at http://mozilla.org/MPL/2.0/. - -/* devedition.css is loaded in browser.xul after browser.css when it is - preffed on. The bulk of the styling is here in the shared file, but - there are overrides for each platform in their devedition.css files. */ - -:root { - --tab-toolbar-navbar-overlap: 0px; - --navbar-tab-toolbar-highlight-overlap: 0px; - --space-above-tabbar: 0px; - --toolbarbutton-text-shadow: none; - --backbutton-urlbar-overlap: 0px; -} - -:root[devtoolstheme="dark"] { - /* Chrome */ - --chrome-background-color: #272b35; - --chrome-color: #F5F7FA; - --chrome-secondary-background-color: #393F4C; - --chrome-navigator-toolbox-separator-color: rgba(0,0,0,.2); - --chrome-nav-bar-separator-color: rgba(0,0,0,.2); - --chrome-nav-buttons-background: #252C33; - --chrome-nav-buttons-hover-background: #1B2127; - --chrome-nav-bar-controls-border-color: #1D2328; - --chrome-selection-color: #fff; - --chrome-selection-background-color: #5675B9; - - /* Tabs */ - --tabs-toolbar-color: #F5F7FA; - --tab-background-color: #272b35; - --tab-hover-background-color: #07090a; - --tab-selection-color: #f5f7fa; - --tab-selection-background-color: #5675B9; - --tab-selection-box-shadow: none; - --pinned-tab-glow: radial-gradient(22px at center calc(100% - 2px), rgba(76,158,217,0.9) 13%, rgba(0,0,0,0.4) 16%, transparent 70%); - - /* Url and search bars */ - --url-and-searchbar-background-color: #171B1F; - --urlbar-separator-color: #5F6670; - --urlbar-dropmarker-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg"); - --urlbar-dropmarker-region: rect(0px, 11px, 14px, 0px); - --urlbar-dropmarker-hover-region: rect(0, 22px, 14px, 11px); - --urlbar-dropmarker-active-region: rect(0px, 33px, 14px, 22px); - --urlbar-dropmarker-2x-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg"); - --urlbar-dropmarker-2x-region: rect(0px, 11px, 14px, 0px); - --urlbar-dropmarker-hover-2x-region: rect(0, 22px, 14px, 11px); - --urlbar-dropmarker-active-2x-region: rect(0px, 33px, 14px, 22px); -} - -/* Override the lwtheme-specific styling for toolbar buttons */ -:root[devtoolstheme="dark"], -:root[devtoolstheme="dark"] toolbar:-moz-lwtheme { - --toolbarbutton-hover-background: rgba(25,33, 38,.6) linear-gradient(rgba(25,33,38,.6), rgba(25,33,38,.6)) padding-box; - --toolbarbutton-hover-boxshadow: none; - --toolbarbutton-hover-bordercolor: rgba(25,33,38,.6); - --toolbarbutton-active-background: rgba(25,33,38,1) linear-gradient(rgba(25,33,38,1), rgba(25,33,38,1)) border-box; - --toolbarbutton-active-boxshadow: none; - --toolbarbutton-active-bordercolor: rgba(25,33,38,.8); - --toolbarbutton-checkedhover-backgroundcolor: #3C5283; - -} - -:root[devtoolstheme="light"] { - --url-and-searchbar-background-color: #fff; - - --chrome-background-color: #E3E4E6; - --chrome-color: #18191a; - --chrome-secondary-background-color: #f5f6f7; - --chrome-navigator-toolbox-separator-color: #cccccc; - --chrome-nav-bar-separator-color: #B6B6B8; - --chrome-nav-buttons-background: #ffffff; /* --theme-body-background */ - --chrome-nav-buttons-hover-background: #DADBDB; - --chrome-nav-bar-controls-border-color: #ccc; - --chrome-selection-color: #f5f7fa; - --chrome-selection-background-color: #4c9ed9; - - --tab-background-color: #E3E4E6; - --tab-hover-background-color: #D7D8DA; - --tab-selection-color: #f5f7fa; - --tab-selection-background-color: #4c9ed9; - --tab-selection-box-shadow: none; - --pinned-tab-glow: radial-gradient(22px at center calc(100% - 2px), rgba(76,158,217,0.9) 13%, transparent 16%); -} - -/* Override the lwtheme-specific styling for toolbar buttons */ -:root[devtoolstheme="light"], -:root[devtoolstheme="light"] toolbar:-moz-lwtheme { - --toolbarbutton-hover-background: #eaeaea; - --toolbarbutton-hover-boxshadow: none; - --toolbarbutton-hover-bordercolor: rgba(0,0,0,0.1); - --toolbarbutton-active-background: #d7d7d8 border-box; - --toolbarbutton-active-boxshadow: none; - --toolbarbutton-active-bordercolor: rgba(0,0,0,0.15); - --toolbarbutton-checkedhover-backgroundcolor: #d7d7d8; -} - -/* Give some space to drag the window around while customizing - (normal space to left and right of tabs doesn't work in this case) */ -#main-window[tabsintitlebar][customizing] { - --space-above-tabbar: 9px; -} - -/* Override @tabCurveHalfWidth@ and @tabCurveWidth@. XXX: Switch to a CSS variable once the perf is sorted out - bug 1088771 */ -.tab-background-middle { - border-left-width: 0; - border-right-width: 0; - margin: 0; -} - -.tab-background, -.tabs-newtab-button { - margin-inline-end: 0; - margin-inline-start: 0; -} - -.tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox { - padding-inline-end: 0; - padding-inline-start: 0; -} - -.tab-background-start[selected=true]::after, -.tab-background-start[selected=true]::before, -.tab-background-start, -.tab-background-end, -.tab-background-end[selected=true]::after, -.tab-background-end[selected=true]::before { - width: 0; -} - -.tab-background-start[selected=true]::after, -.tab-background-end[selected=true]::after { - margin-inline-start: 0; -} -/* End override @tabCurveHalfWidth@ and @tabCurveWidth@ */ - -#urlbar ::-moz-selection, -#navigator-toolbox .searchbar-textbox ::-moz-selection, -.browserContainer > findbar ::-moz-selection { - background-color: var(--chrome-selection-background-color); - color: var(--chrome-selection-color); -} - -/* Change the base colors for the browser chrome */ - -#tabbrowser-tabs, -#TabsToolbar, -#browser-panel { - background: var(--chrome-background-color); - color: var(--chrome-color); -} - -#navigator-toolbox:-moz-lwtheme::after { - border-bottom-color: var(--chrome-navigator-toolbox-separator-color); -} - -#navigator-toolbox > toolbar:not(#TabsToolbar):not(#toolbar-menubar), -.browserContainer > findbar, -#browser-bottombox { - background-color: var(--chrome-secondary-background-color) !important; - background-image: none !important; - color: var(--chrome-color); -} - -/* Default findbar text color doesn't look good - Bug 1125677 */ -.browserContainer > findbar .findbar-find-status, -.browserContainer > findbar .found-matches { - color: inherit; -} - -#navigator-toolbox .toolbarbutton-1, -.browserContainer > findbar .findbar-button, -#PlacesToolbar toolbarbutton.bookmark-item { - color: var(--chrome-color); - text-shadow: var(--toolbarbutton-text-shadow); -} - -/* Using toolbar[brighttext] instead of important to override linux */ -toolbar[brighttext] #downloads-indicator-counter { - text-shadow: var(--toolbarbutton-text-shadow); - color: var(--chrome-color); -} - -#TabsToolbar { - text-shadow: none !important; -} - -/* URL bar and search bar*/ -#urlbar, -#navigator-toolbox .searchbar-textbox { - background-color: var(--url-and-searchbar-background-color) !important; - background-image: none !important; - color: inherit !important; - border: 1px solid var(--chrome-nav-bar-controls-border-color) !important; - box-shadow: none !important; -} - -%filter substitution -%define selectorPrefix :root[devtoolstheme="dark"] -%define selectorSuffix :-moz-lwtheme -%define iconVariant -white -%include identity-block/icons.inc.css - -#urlbar { - border-inline-start: none !important; - opacity: 1 !important; -} - -window:not([chromehidden~="toolbar"]) #urlbar-wrapper { - overflow: -moz-hidden-unscrollable; - clip-path: none; - margin-inline-start: 0; -} - -:root[devtoolstheme="dark"] #urlbar-zoom-button:hover { - background-color: rgba(255,255,255,.2); -} - -:root[devtoolstheme="dark"] #urlbar-zoom-button:hover:active { - background-color: rgba(255,255,255,.3); -} - -/* Nav bar specific stuff */ -#nav-bar { - margin-top: 0 !important; - border-top: none !important; - border-bottom: none !important; - border-radius: 0 !important; - box-shadow: 0 -1px var(--chrome-nav-bar-separator-color) !important; -} - -/* No extra vertical padding for nav bar */ -#nav-bar-customization-target, -#nav-bar { - padding-top: 0; - padding-bottom: 0; -} - -/* Use smaller back button icon */ -#back-button { - -moz-image-region: rect(0, 54px, 18px, 36px); -} - -@media (min-resolution: 1.1dppx) { - #back-button { - -moz-image-region: rect(0, 108px, 36px, 72px); - } -} - -.tab-background { - visibility: hidden; -} - -/* Tab separators */ -.tabbrowser-tab::after, -.tabbrowser-tab::before { - background: currentColor; - opacity: 0.2 !important; -} - -.tabbrowser-arrowscrollbox > .scrollbutton-down, -.tabbrowser-arrowscrollbox > .scrollbutton-up { - background-color: var(--tab-background-color); - border-color: transparent; -} - -.tabbrowser-tab { - /* We normally rely on other tab elements for pointer events, but this - theme hides those so we need it set here instead */ - pointer-events: auto; -} - -.tabbrowser-tab:-moz-any([image], [pinned]) > .tab-stack > .tab-content[attention]:not([selected="true"]), -.tabbrowser-tab > .tab-stack > .tab-content[pinned][titlechanged]:not([selected="true"]) { - background-image: var(--pinned-tab-glow); - background-position: center; - background-size: 100%; -} - -.tabbrowser-tab[image] > .tab-stack > .tab-content[attention]:not([pinned]):not([selected="true"]) { - background-position: left bottom var(--tab-toolbar-navbar-overlap); - background-size: 34px 100%; -} - -.tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):hover, -.tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):hover, -.tabbrowser-tab:hover { - background-color: var(--tab-hover-background-color); -} - -.tabbrowser-tab[visuallyselected] { - color: var(--tab-selection-color) !important; /* Override color: inherit */ - background-color: var(--tab-selection-background-color); -} - -.tab-icon-sound[soundplaying], -.tab-icon-sound[muted] { - filter: url(chrome://browser/skin/filters.svg#fill) !important; /* removes drop-shadow filter */ -} - -/* Don't need space for the tab curves (66px - 30px) */ -.tabs-newtab-button { - width: 36px; -} - -.tabs-newtab-button:hover { - /* Important needed because !important is used in browser.css */ - background-color: var(--tab-hover-background-color) !important; - background-image: none; -} diff --git a/application/basilisk/themes/shared/devedition/urlbar-history-dropmarker.svg b/application/basilisk/themes/shared/devedition/urlbar-history-dropmarker.svg deleted file mode 100644 index 115fbf127..000000000 --- a/application/basilisk/themes/shared/devedition/urlbar-history-dropmarker.svg +++ /dev/null @@ -1,22 +0,0 @@ -<!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="33" height="14" viewBox="0 0 33 14"> - <defs> - <polygon points="0,0 5.5,7 11,0" id="dropmarker-shape"/> - </defs> - <style> - use { - fill: #b6babf; - } - .hover { - fill: #61bdeb; - } - .active { - fill: #39ace6; - } - </style> - <use xlink:href="#dropmarker-shape" style="transform: translate(0, 4px)"/> - <use xlink:href="#dropmarker-shape" style="transform: translate(11px, 4px)" class="hover"/> - <use xlink:href="#dropmarker-shape" style="transform: translate(22px, 4px)" class="active"/> -</svg> diff --git a/application/basilisk/themes/shared/jar.inc.mn b/application/basilisk/themes/shared/jar.inc.mn index 5750d2dc5..d12971a4b 100644 --- a/application/basilisk/themes/shared/jar.inc.mn +++ b/application/basilisk/themes/shared/jar.inc.mn @@ -137,6 +137,5 @@ skin/classic/browser/privatebrowsing/private-browsing.svg (../shared/privatebrowsing/private-browsing.svg) skin/classic/browser/privatebrowsing/tracking-protection-off.svg (../shared/privatebrowsing/tracking-protection-off.svg) skin/classic/browser/privatebrowsing/tracking-protection.svg (../shared/privatebrowsing/tracking-protection.svg) - skin/classic/browser/devedition/urlbar-history-dropmarker.svg (../shared/devedition/urlbar-history-dropmarker.svg) skin/classic/browser/urlbar-star.svg (../shared/urlbar-star.svg) skin/classic/browser/urlbar-tab.svg (../shared/urlbar-tab.svg) diff --git a/application/basilisk/themes/windows/browser.css b/application/basilisk/themes/windows/browser.css index 334265e60..9a965520a 100644 --- a/application/basilisk/themes/windows/browser.css +++ b/application/basilisk/themes/windows/browser.css @@ -193,9 +193,6 @@ toolbar:-moz-lwtheme { @media not all and (-moz-windows-compositor), not all and (-moz-windows-default-theme) { - /* Please keep the menu text colors in this media block in sync with - * devedition.css, minus the :not(:-moz-lwtheme) condition - see Bug 1165718. - */ :root[tabsintitlebar]:not([inFullscreen]):not(:-moz-lwtheme) { --titlebar-text-color: CaptionText; } diff --git a/application/basilisk/themes/windows/devedition.css b/application/basilisk/themes/windows/devedition.css deleted file mode 100644 index bdf4bb80e..000000000 --- a/application/basilisk/themes/windows/devedition.css +++ /dev/null @@ -1,316 +0,0 @@ -% This Source Code Form is subject to the terms of the Mozilla Public -% License, v. 2.0. If a copy of the MPL was not distributed with this -% file, You can obtain one at http://mozilla.org/MPL/2.0/. - -%include ../shared/devedition.inc.css - -:root { - --forwardbutton-width: 29px; -} - -:root[devtoolstheme="dark"], -:root[devtoolstheme="light"] { - /* Matches the #browser-border-start, #browser-border-end color */ - --chrome-nav-bar-separator-color: rgba(10, 31, 51, 0.35); -} - -/* The window background is white due to no accentcolor in the lightweight - theme. It can't be changed to transparent when there is no compositor - (Win 7 in classic / basic theme), or else dragging and focus become - broken. So instead just show the normal titlebar in that case, and override - the window color as transparent when the compositor is available. */ -@media not all and (-moz-windows-compositor) { - #main-window[tabsintitlebar] #titlebar:-moz-lwtheme { - visibility: visible; - } - - #main-window { - background: var(--chrome-background-color) !important; - } -} - -@media (-moz-windows-compositor) { - #main-window { - background: transparent !important; - } -} - -#TabsToolbar::after { - display: none; -} - -#back-button > .toolbarbutton-icon, -#forward-button > .toolbarbutton-icon { - background: var(--chrome-nav-buttons-background) !important; - border-radius: 0 !important; - height: auto !important; - padding: var(--toolbarbutton-vertical-inner-padding) 5px !important; - margin: 0 !important; - border: 1px solid var(--chrome-nav-bar-controls-border-color) !important; - box-shadow: none !important; -} - -#back-button > .toolbarbutton-icon { - /* 18px icon + 2 * 5px padding + 2 * 1px border */ - width: 30px !important; -} - -#forward-button > .toolbarbutton-icon { - /* 18px icon + 2 * 5px padding + 1 * 1px border */ - width: 29px !important; -} - -/* the normal theme adds box-shadow: <stuff> !important when the back-button is [open]. Fix: */ -#back-button[open="true"] > .toolbarbutton-icon { - box-shadow: none !important; -} - -#forward-button > .toolbarbutton-icon { - border-inline-start: none !important; -} - -/* Override a box shadow for disabled back button */ -#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon { - box-shadow: none !important; -} - -/* Override !important properties for hovered back button */ -#main-window #back-button:hover:not([disabled="true"]) > .toolbarbutton-icon, -#main-window #forward-button:hover:not([disabled="true"]) > .toolbarbutton-icon { - background: var(--chrome-nav-buttons-hover-background) !important; - box-shadow: none !important; -} - -#back-button > .toolbarbutton-icon { - border-radius: 2px 0 0 2px !important; -} - -#nav-bar .toolbarbutton-1:not([type=menu-button]), -#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button, -#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker { - padding-top: 2px; - padding-bottom: 2px; -} - -.tabbrowser-tab { - background-color: var(--tab-background-color); -} - -#toolbar-menubar { - text-shadow: none !important; -} - -:root[devtoolstheme="dark"] .findbar-closebutton, -:root[devtoolstheme="dark"] #sidebar-header > .close-icon, -/* Tab styling - make sure to use an inverted icon for the selected tab - (brighttext only covers the unselected tabs) */ -.tab-close-button[selected=true] { - list-style-image: url("chrome://global/skin/icons/close-inverted.png"); -} - -@media (min-resolution: 1.1dppx) { - :root[devtoolstheme="dark"] .findbar-closebutton, - :root[devtoolstheme="dark"] #sidebar-header > .close-icon, - .tab-close-button[selected=true] { - list-style-image: url("chrome://global/skin/icons/close-inverted@2x.png"); - } -} - -@media (-moz-os-version: windows-win7), - (-moz-os-version: windows-win8) { - :root { - --space-above-tabbar: 15px; - } - - /* It'd be nice if there was an element in the scrollbox's inner content - that collapsed to the current width of the tabs. Since there isn't we - need to handle overflowing and non-overflowing tabs separately. - - In the case of overflowing tabs, set a border-top on the entire container, - otherwise we need to set it on each element individually */ - #main-window[sizemode=normal] .tabbrowser-tabs[overflow="true"] { - background-clip: padding-box; - border-top: 1px solid var(--chrome-nav-bar-separator-color); - border-inline-end: 1px solid var(--chrome-nav-bar-separator-color); - background-color: var(--tab-background-color); /* Make sure there is no transparent gap during tab close animation */ - } - - /* Add a border to the left of the first tab (or scroll arrow). Using .tabbrowser-tabs - instead of #TabsToolbar because it will work even in customize mode. */ - #main-window[sizemode=normal] .tabbrowser-tabs { - background-clip: padding-box; - border-inline-start: 1px solid var(--chrome-nav-bar-separator-color); - border-inline-end: 1px solid transparent; - } - - #main-window[sizemode=normal] .tabbrowser-tabs:not([overflow="true"]) .tabbrowser-tab, - #main-window[sizemode=normal] .tabbrowser-tabs:not([overflow="true"]) .tabbrowser-arrowscrollbox > .scrollbutton-down, - #main-window[sizemode=normal] .tabbrowser-tabs:not([overflow="true"]) .tabbrowser-arrowscrollbox > .scrollbutton-up, - #main-window[sizemode=normal] .tabbrowser-tabs:not([overflow="true"]) .tabs-newtab-button { - background-clip: padding-box; - border-top: 1px solid var(--chrome-nav-bar-separator-color); - } - - /* Allow the border-top rule to take effect */ - #main-window[sizemode=normal] .tabbrowser-tabs:not([overflow="true"]) .tabbrowser-tab { - -moz-border-top-colors: none; - } - - #main-window[sizemode=normal] .tabbrowser-tabs:not([overflow="true"]) .closing-tabs-spacer { - background-clip: padding-box; - border-inline-start: 1px solid var(--chrome-nav-bar-separator-color); - } - - .tabs-newtab-button { - background: var(--tab-background-color); - } - - /* Use default window colors when in non-maximized mode */ - #tabbrowser-tabs, - #TabsToolbar, - #browser-panel, - #titlebar-content { - background: transparent; - } - - /* Ensure that the entire background is styled when maximized/fullscreen */ - #main-window:not([sizemode="normal"]):not([customizing]) #browser-panel { - background: var(--chrome-background-color) !important; - } - - /* The menu items need to be visible when the entire background is styled */ - #main-window:not([sizemode="normal"]) #main-menubar { - color: var(--chrome-color); - background-color: transparent; - } - - #main-window[sizemode="maximized"] #main-menubar > menu:not(:-moz-window-inactive) { - color: inherit; - } - - /* Use proper menu text styling in Win7 classic mode (copied from browser.css) */ - @media not all and (-moz-windows-compositor), - not all and (-moz-windows-default-theme) { - :root[tabsintitlebar]:not([inFullscreen]) { - --titlebar-text-color: CaptionText; - } - - :root[tabsintitlebar]:not([inFullscreen]):-moz-window-inactive { - --titlebar-text-color: InactiveCaptionText; - } - - #main-window[tabsintitlebar] #main-menubar > menu { - color: inherit; - } - } - - /* Use less opacity than normal since this is very dark, and on top of the default toolbar color */ - .tabbrowser-arrowscrollbox > .scrollbutton-up[disabled], - .tabbrowser-arrowscrollbox > .scrollbutton-down[disabled] { - opacity: .6; - } - - /* Override scrollbutton gradients in normal and hover state */ - .tabbrowser-arrowscrollbox > .scrollbutton-down, - .tabbrowser-arrowscrollbox > .scrollbutton-up { - background-image: none !important; - transition: none; /* scrollbutton-down has an unwanted transition on background color */ - } - - /* Restore draggable space on the sides of tabs when maximized */ - #main-window[sizemode="maximized"] .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox { - padding-left: 15px; - padding-right: 15px; - } - - /* Override the padding that's intended to compensate for tabs that can overlap border-radius on nav-bar in default theme. */ - #main-window[sizemode=normal]:not([customizing]) #TabsToolbar { - padding-left: 0; - padding-right: 0; - } -} - -/* Restored windows get an artificial border on windows, because the lwtheme background - * overlaps the regular window border. That isn't the case for us, so we avoid painting - * over the native border with our custom borders: */ -#browser-panel { - /* These are !important to avoid specificity-wars with the selectors that add borders here. */ - background-image: none !important; - border-top: none !important; -} - -#navigator-toolbox { - /* The side borders on the toolbox also look out-of-place because we don't paint over - * the native background color at all, and these are !important for the same reason as above. */ - border-left: none !important; - border-right: none !important; -} - -/* Disable dragging like in the default theme: */ -#main-window[tabsintitlebar] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):-moz-lwtheme { - -moz-window-dragging: no-drag; -} - -/* The sidebar header has no background now that the background of the #browser-panel - * has no image and is transparent. Fix: */ -.sidebar-header:-moz-lwtheme, -#sidebar-header { - background-color: var(--chrome-background-color); - color: var(--chrome-color); -} - -@media (-moz-os-version: windows-win7), - (-moz-os-version: windows-win8) { - /* And then we add them back on toolbars so that they don't look borderless: */ - #main-window:not([customizing])[sizemode=normal] #navigator-toolbox::after, - #main-window:not([customizing])[sizemode=normal] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { - border-left: 1px solid hsla(209,67%,12%,0.35); - border-right: 1px solid hsla(209,67%,12%,0.35); - } -} - -@media (-moz-os-version: windows-win10) { - /* Always keep draggable space on the sides of tabs since there is no top margin on Win10 */ - #main-window .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox { - padding-left: 15px; - padding-right: 15px; - } - - /* Force white caption buttons for the dark theme on Windows 10 */ - :root[devtoolstheme="dark"] #titlebar-min { - list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize-white); - } - :root[devtoolstheme="dark"] #titlebar-max { - list-style-image: url(chrome://browser/skin/caption-buttons.svg#maximize-white); - } - #main-window[devtoolstheme="dark"][sizemode="maximized"] #titlebar-max { - list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore-white); - } - :root[devtoolstheme="dark"] #titlebar-close { - list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-white); - } - - /* ... and normal ones for the light theme on Windows 10 */ - :root[devtoolstheme="light"] #titlebar-min { - list-style-image: url(chrome://browser/skin/caption-buttons.svg#minimize); - } - :root[devtoolstheme="light"] #titlebar-max { - list-style-image: url(chrome://browser/skin/caption-buttons.svg#maximize); - } - #main-window[devtoolstheme="light"][sizemode="maximized"] #titlebar-max { - list-style-image: url(chrome://browser/skin/caption-buttons.svg#restore); - } - :root[devtoolstheme="light"] #titlebar-close { - list-style-image: url(chrome://browser/skin/caption-buttons.svg#close); - } - - :root[devtoolstheme="light"] #titlebar-close:hover { - list-style-image: url(chrome://browser/skin/caption-buttons.svg#close-white); - } -} - -.ac-type-icon { - /* Left-align the type icon in awesomebar popup results with the icon in the - urlbar. */ - margin-inline-start: 13px; -} diff --git a/application/basilisk/themes/windows/jar.mn b/application/basilisk/themes/windows/jar.mn index 28c6c6465..b0b9ca454 100644 --- a/application/basilisk/themes/windows/jar.mn +++ b/application/basilisk/themes/windows/jar.mn @@ -14,7 +14,6 @@ browser.jar: skin/classic/browser/actionicon-tab@2x.png skin/classic/browser/actionicon-tab-win7.png * skin/classic/browser/browser.css -* skin/classic/browser/devedition.css * skin/classic/browser/browser-lightweightTheme.css skin/classic/browser/caption-buttons.svg skin/classic/browser/click-to-play-warning-stripes.png diff --git a/application/basilisk/tools/mozscreenshots/mozscreenshots/extension/configurations/DevEdition.jsm b/application/basilisk/tools/mozscreenshots/mozscreenshots/extension/configurations/DevEdition.jsm deleted file mode 100644 index fd981bca3..000000000 --- a/application/basilisk/tools/mozscreenshots/mozscreenshots/extension/configurations/DevEdition.jsm +++ /dev/null @@ -1,42 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = ["DevEdition"]; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; -const THEME_ID = "firefox-devedition@mozilla.org"; - -Cu.import("resource://gre/modules/LightweightThemeManager.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); - -this.DevEdition = { - init(libDir) {}, - - configurations: { - devEditionLight: { - applyConfig: Task.async(() => { - Services.prefs.setCharPref("devtools.theme", "light"); - LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(THEME_ID); - Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true); - }), - }, - devEditionDark: { - applyConfig: Task.async(() => { - Services.prefs.setCharPref("devtools.theme", "dark"); - LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(THEME_ID); - Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true); - }), - }, - devEditionOff: { - applyConfig: Task.async(() => { - Services.prefs.clearUserPref("devtools.theme"); - LightweightThemeManager.currentTheme = null; - Services.prefs.clearUserPref("browser.devedition.theme.showCustomizeButton"); - }), - }, - }, -}; diff --git a/application/palemoon/app/Makefile.in b/application/palemoon/app/Makefile.in index c0f01212c..d008010ec 100644 --- a/application/palemoon/app/Makefile.in +++ b/application/palemoon/app/Makefile.in @@ -80,26 +80,26 @@ MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_A .PHONY: repackage tools repackage:: $(PROGRAM) - $(MKDIR) -p $(dist_dest)/Contents/MacOS - $(MKDIR) -p $(dist_dest)/Contents/Resources/$(AB).lproj - rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj - rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/Contents/Resources/$(AB).lproj - sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist - sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings - rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(dist_dest)/Contents/Resources - rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(dist_dest)/Contents/MacOS - $(RM) $(dist_dest)/Contents/MacOS/$(PROGRAM) - rsync -aL $(PROGRAM) $(dist_dest)/Contents/MacOS - cp -RL $(DIST)/branding/firefox.icns $(dist_dest)/Contents/Resources/firefox.icns - cp -RL $(DIST)/branding/document.icns $(dist_dest)/Contents/Resources/document.icns - printf APPLMOZB > $(dist_dest)/Contents/PkgInfo + $(MKDIR) -p '$(dist_dest)/Contents/MacOS' + $(MKDIR) -p '$(dist_dest)/Contents/Resources/$(AB).lproj' + rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents '$(dist_dest)' --exclude English.lproj + rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ '$(dist_dest)/Contents/Resources/$(AB).lproj' + sed -e 's/%APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' -e 's/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/' -e 's/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/' $(srcdir)/macbuild/Contents/Info.plist.in > '$(dist_dest)/Contents/Info.plist' + sed -e 's/%MAC_APP_NAME%/$(MAC_APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > '$(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings' + rsync -a --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ '$(dist_dest)/Contents/Resources' + rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ '$(dist_dest)/Contents/MacOS' + $(RM) '$(dist_dest)/Contents/MacOS/$(PROGRAM)' + rsync -aL $(PROGRAM) '$(dist_dest)/Contents/MacOS' + cp -RL $(DIST)/branding/firefox.icns '$(dist_dest)/Contents/Resources/firefox.icns' + cp -RL $(DIST)/branding/document.icns '$(dist_dest)/Contents/Resources/document.icns' + printf APPLMOZB > '$(dist_dest)/Contents/PkgInfo' endif ifdef LIBXUL_SDK #{ ifndef SKIP_COPY_XULRUNNER #{ libs:: ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) #{ - rsync -a --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework $(dist_dest)/Contents/Frameworks + rsync -a --copy-unsafe-links $(LIBXUL_DIST)/XUL.framework '$(dist_dest)/Contents/Frameworks' else $(NSINSTALL) -D $(DIST)/bin/xulrunner (cd $(LIBXUL_SDK)/bin && tar $(TAR_CREATE_FLAGS) - .) | (cd $(DIST)/bin/xulrunner && tar -xf -) diff --git a/application/palemoon/base/content/browser.js b/application/palemoon/base/content/browser.js index a5d77a90d..7615bc92a 100644 --- a/application/palemoon/base/content/browser.js +++ b/application/palemoon/base/content/browser.js @@ -2445,16 +2445,12 @@ function BrowserOnAboutPageLoad(doc) { // Inject search engine and snippets URL. let docElt = doc.documentElement; - // set the following attributes BEFORE searchEngineURL, which triggers to - // show the snippets when it's set. - docElt.setAttribute("snippetsURL", AboutHomeUtils.snippetsURL); if (AboutHomeUtils.showKnowYourRights) { docElt.setAttribute("showKnowYourRights", "true"); // Set pref to indicate we've shown the notification. let currentVersion = Services.prefs.getIntPref("browser.rights.version"); Services.prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true); } - docElt.setAttribute("snippetsVersion", AboutHomeUtils.snippetsVersion); function updateSearchEngine() { let engine = AboutHomeUtils.defaultSearchEngine; diff --git a/application/palemoon/branding/official/configure.sh b/application/palemoon/branding/official/configure.sh index a9818b4a7..8943f5819 100644 --- a/application/palemoon/branding/official/configure.sh +++ b/application/palemoon/branding/official/configure.sh @@ -2,5 +2,5 @@ # 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/. -MOZ_APP_DISPLAYNAME=PaleMoon +MOZ_APP_DISPLAYNAME="Pale Moon" # MOZ_UA_BUILDID=20100101 diff --git a/application/palemoon/branding/official/palemoon.desktop b/application/palemoon/branding/official/palemoon.desktop index 3f678e1bf..440092b33 100644 --- a/application/palemoon/branding/official/palemoon.desktop +++ b/application/palemoon/branding/official/palemoon.desktop @@ -87,8 +87,9 @@ Type=Application Icon=palemoon Categories=Network;WebBrowser; MimeType=text/html;text/xml;application/xhtml+xml;application/vnd.mozilla.xul+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ftp; -StartupNotify=true +StartupNotify=false Actions=NewTab;NewWindow;NewPrivateWindow; +StartupWMClass="pale moon" [Desktop Action NewTab] Name=Open new tab diff --git a/application/palemoon/branding/shared/pref/uaoverrides.inc b/application/palemoon/branding/shared/pref/uaoverrides.inc index 487d083a9..028b29b41 100644 --- a/application/palemoon/branding/shared/pref/uaoverrides.inc +++ b/application/palemoon/branding/shared/pref/uaoverrides.inc @@ -57,8 +57,6 @@ pref("@GUAO_PREF@.www.amazon.com","Mozilla/5.0 (@OS_SLICE@ rv:45.9) @GK_SLICE@ F pref("@GUAO_PREF@.soundcloud.com","Mozilla/5.0 (@OS_SLICE@ rv:@GRE_VERSION@) @GRE_DATE_SLICE@ @PM_SLICE@");
// Daily motion only likes strict Firefox UAs
pref("@GUAO_PREF@.dailymotion.com","Mozilla/5.0 (@OS_SLICE@ rv:52.0) @GK_SLICE@ Firefox/52.0");
-// Financial Times' polyfill.io breaks horribly on a Pale Moon UA. Send a strict Firefox UA instead.
-pref("@GUAO_PREF@.polyfill.io","Mozilla/5.0 (@OS_SLICE@ rv:60.9) @GK_SLICE@ Firefox/60.9");
// The following requires native mode. Or it blocks.. "too old firefox", breakage, etc.
diff --git a/application/palemoon/branding/unofficial/configure.sh b/application/palemoon/branding/unofficial/configure.sh index 05a1e1b87..c03b8382a 100644 --- a/application/palemoon/branding/unofficial/configure.sh +++ b/application/palemoon/branding/unofficial/configure.sh @@ -2,4 +2,4 @@ # 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/. -MOZ_APP_DISPLAYNAME=NewMoon +MOZ_APP_DISPLAYNAME="New Moon" diff --git a/application/palemoon/branding/unofficial/newmoon.desktop b/application/palemoon/branding/unofficial/newmoon.desktop index 6dcf32477..3b337fdd4 100644 --- a/application/palemoon/branding/unofficial/newmoon.desktop +++ b/application/palemoon/branding/unofficial/newmoon.desktop @@ -87,8 +87,9 @@ Type=Application Icon=palemoon Categories=Network;WebBrowser; MimeType=text/html;text/xml;application/xhtml+xml;application/vnd.mozilla.xul+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ftp; -StartupNotify=true +StartupNotify=false Actions=NewTab;NewWindow;NewPrivateWindow; +StartupWMClass="new moon" [Desktop Action NewTab] Name=Open new tab diff --git a/application/palemoon/branding/unstable/configure.sh b/application/palemoon/branding/unstable/configure.sh index 814133dfa..8943f5819 100644 --- a/application/palemoon/branding/unstable/configure.sh +++ b/application/palemoon/branding/unstable/configure.sh @@ -2,5 +2,5 @@ # 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/. -MOZ_APP_DISPLAYNAME=Palemoon +MOZ_APP_DISPLAYNAME="Pale Moon" # MOZ_UA_BUILDID=20100101 diff --git a/application/palemoon/branding/unstable/firefox.icns b/application/palemoon/branding/unstable/firefox.icns Binary files differindex 117ddb195..3df606a01 100644 --- a/application/palemoon/branding/unstable/firefox.icns +++ b/application/palemoon/branding/unstable/firefox.icns diff --git a/application/palemoon/components/moz.build b/application/palemoon/components/moz.build index eb2771c48..48d4552ba 100644 --- a/application/palemoon/components/moz.build +++ b/application/palemoon/components/moz.build @@ -20,11 +20,9 @@ DIRS += [ 'search', 'sessionstore', 'shell', + 'statusbar', ] -if CONFIG['MOZ_BROWSER_STATUSBAR']: - DIRS += ['statusbar'] - if CONFIG['MOZ_SERVICES_SYNC']: DIRS += ['sync'] diff --git a/application/palemoon/components/places/content/browserPlacesViews.js b/application/palemoon/components/places/content/browserPlacesViews.js index eec7274a4..8b90dd280 100644 --- a/application/palemoon/components/places/content/browserPlacesViews.js +++ b/application/palemoon/components/places/content/browserPlacesViews.js @@ -109,8 +109,15 @@ PlacesViewBase.prototype = { get selectedNode() { if (this._contextMenuShown) { - let popup = document.popupNode; - return popup._placesNode || popup.parentNode._placesNode || null; + let anchor = this._contextMenuShown.triggerNode; + if (!anchor) + return null; + + if (anchor._placesNode) + return this._rootElt == anchor ? null : anchor._placesNode; + + anchor = anchor.parentNode; + return this._rootElt == anchor ? null : (anchor._placesNode || null); } return null; }, @@ -176,13 +183,13 @@ PlacesViewBase.prototype = { }, buildContextMenu: function PVB_buildContextMenu(aPopup) { - this._contextMenuShown = true; + this._contextMenuShown = aPopup; window.updateCommands("places"); return this.controller.buildContextMenu(aPopup); }, destroyContextMenu: function PVB_destroyContextMenu(aPopup) { - this._contextMenuShown = false; + this._contextMenuShown = null; }, _cleanPopup: function PVB_cleanPopup(aPopup, aDelay) { diff --git a/application/palemoon/components/places/content/controller.js b/application/palemoon/components/places/content/controller.js index 7f5f7f652..f4e272e2f 100644 --- a/application/palemoon/components/places/content/controller.js +++ b/application/palemoon/components/places/content/controller.js @@ -334,20 +334,6 @@ PlacesController.prototype = { }, /** - * Determines whether or not the root node for the view is selected - */ - rootNodeIsSelected: function PC_rootNodeIsSelected() { - var nodes = this._view.selectedNodes; - var root = this._view.result.root; - for (var i = 0; i < nodes.length; ++i) { - if (nodes[i] == root) - return true; - } - - return false; - }, - - /** * Looks at the data on the clipboard to see if it is paste-able. * Paste-able data is: * - in a format that the view can receive @@ -400,7 +386,7 @@ PlacesController.prototype = { * Gathers information about the selected nodes according to the following * rules: * "link" node is a URI - * "bookmark" node is a bookamrk + * "bookmark" node is a bookmark * "livemarkChild" node is a child of a livemark * "tagChild" node is a child of a tag * "folder" node is a folder @@ -414,15 +400,10 @@ PlacesController.prototype = { * node are set on its corresponding object as properties. * Notes: * 1) This can be slow, so don't call it anywhere performance critical! - * 2) A single-object array corresponding the root node is returned if - * there's no selection. */ _buildSelectionMetadata: function PC__buildSelectionMetadata() { var metadata = []; - var root = this._view.result.root; var nodes = this._view.selectedNodes; - if (nodes.length == 0) - nodes.push(root); // See the second note above for (var i = 0; i < nodes.length; i++) { var nodeData = {}; @@ -463,7 +444,11 @@ PlacesController.prototype = { if (parentNode) { if (PlacesUtils.nodeIsTagQuery(parentNode)) nodeData["tagChild"] = true; - else if (this.hasCachedLivemarkInfo(parentNode)) + } + } else { + var parentNode = node.parent; + if (parentNode) { + if (this.hasCachedLivemarkInfo(parentNode)) nodeData["livemarkChild"] = true; } } @@ -501,10 +486,23 @@ PlacesController.prototype = { */ _shouldShowMenuItem: function PC__shouldShowMenuItem(aMenuItem, aMetaData) { var selectiontype = aMenuItem.getAttribute("selectiontype"); - if (selectiontype == "multiple" && aMetaData.length == 1) + if (!selectiontype) { + selectiontype = "single|multiple"; + } + var selectionTypes = selectiontype.split("|"); + if (selectionTypes.indexOf("any") != -1) { + return true; + } + var count = aMetaData.length; + if (count > 1 && selectionTypes.indexOf("multiple") == -1) return false; - if (selectiontype == "single" && aMetaData.length != 1) + if (count == 1 && selectionTypes.indexOf("single") == -1) return false; + // NB: if there is no selection, we show the item if (and only if) + // the selectiontype includes 'none' - the metadata list will be + // empty so none of the other criteria will apply anyway. + if (count == 0) + return selectionTypes.indexOf("none") != -1; var forceHideAttr = aMenuItem.getAttribute("forcehideselection"); if (forceHideAttr) { @@ -551,9 +549,11 @@ PlacesController.prototype = { * 1) The "selectiontype" attribute may be set on a menu-item to "single" * if the menu-item should be visible only if there is a single node * selected, or to "multiple" if the menu-item should be visible only if - * multiple nodes are selected. If the attribute is not set or if it is - * set to an invalid value, the menu-item may be visible for both types of - * selection. + * multiple nodes are selected, or to "none" if the menuitems should be + * visible for if there are no selected nodes, or to a |-separated + * combination of these. + * If the attribute is not set or set to an invalid value, the menu-item + * may be visible irrespective of the selection. * 2) The "selection" attribute may be set on a menu-item to the various * meta-data rules for which it may be visible. The rules should be * separated with the | character. @@ -584,7 +584,7 @@ PlacesController.prototype = { var separator = null; var visibleItemsBeforeSep = false; - var anyVisible = false; + var usableItemCount = 0; for (var i = 0; i < aPopup.childNodes.length; ++i) { var item = aPopup.childNodes[i]; if (item.localName != "menuseparator") { @@ -598,12 +598,13 @@ PlacesController.prototype = { (!/tree/i.test(this._view.localName) || ip); var hideIfPrivate = item.getAttribute("hideifprivatebrowsing") == "true" && PrivateBrowsingUtils.isWindowPrivate(window); - item.hidden = hideIfNoIP || hideIfPrivate || hideParentFolderItem || - !this._shouldShowMenuItem(item, metadata); + var shouldHideItem = hideIfNoIP || hideIfPrivate || hideParentFolderItem || + !this._shouldShowMenuItem(item, metadata); + item.hidden = item.disabled = shouldHideItem; if (!item.hidden) { visibleItemsBeforeSep = true; - anyVisible = true; + usableItemCount++; // Show the separator above the menu-item if any if (separator) { @@ -627,21 +628,21 @@ PlacesController.prototype = { } // Set Open Folder/Links In Tabs items enabled state if they're visible - if (anyVisible) { + if (usableItemCount > 0) { var openContainerInTabsItem = document.getElementById("placesContext_openContainer:tabs"); - if (!openContainerInTabsItem.hidden && this._view.selectedNode && - PlacesUtils.nodeIsContainer(this._view.selectedNode)) { - openContainerInTabsItem.disabled = - !PlacesUtils.hasChildURIs(this._view.selectedNode); - } - else { - // see selectiontype rule in the overlay - var openLinksInTabsItem = document.getElementById("placesContext_openLinks:tabs"); - openLinksInTabsItem.disabled = openLinksInTabsItem.hidden; + if (!openContainerInTabsItem.hidden) { + var containerToUse = this._view.selectedNode || this._view.result.root; + if (PlacesUtils.nodeIsContainer(containerToUse)) { + if (!PlacesUtils.hasChildURIs(containerToUse, true)) { + openContainerInTabsItem.disabled = true; + // Ensure that we don't display the menu if nothing is enabled: + usableItemCount--; + } + } } } - return anyVisible; + return usableItemCount > 0; }, /** @@ -707,10 +708,15 @@ PlacesController.prototype = { */ openSelectionInTabs: function PC_openLinksInTabs(aEvent) { var node = this._view.selectedNode; + var nodes = this._view.selectedNodes; + // In the case of no selection, open the root node: + if (!node && !nodes.length) { + node = this._view.result.root; + } if (node && PlacesUtils.nodeIsContainer(node)) - PlacesUIUtils.openContainerNodeInTabs(this._view.selectedNode, aEvent, this._view); + PlacesUIUtils.openContainerNodeInTabs(node, aEvent, this._view); else - PlacesUIUtils.openURINodesInTabs(this._view.selectedNodes, aEvent, this._view); + PlacesUIUtils.openURINodesInTabs(nodes, aEvent, this._view); }, /** diff --git a/application/palemoon/components/places/content/placesOverlay.xul b/application/palemoon/components/places/content/placesOverlay.xul index dd4d50f01..59115a57f 100644 --- a/application/palemoon/components/places/content/placesOverlay.xul +++ b/application/palemoon/components/places/content/placesOverlay.xul @@ -149,20 +149,20 @@ command="placesCmd_new:bookmark" label="&cmd.new_bookmark.label;" accesskey="&cmd.new_bookmark.accesskey;" - selection="any" + selectiontype="any" hideifnoinsertionpoint="true"/> <menuitem id="placesContext_new:folder" command="placesCmd_new:folder" label="&cmd.new_folder.label;" accesskey="&cmd.context_new_folder.accesskey;" - selection="any" + selectiontype="any" hideifnoinsertionpoint="true"/> <menuitem id="placesContext_new:separator" command="placesCmd_new:separator" label="&cmd.new_separator.label;" accesskey="&cmd.new_separator.accesskey;" closemenu="single" - selection="any" + selectiontype="any" hideifnoinsertionpoint="true"/> <menuseparator id="placesContext_newSeparator"/> <menuitem id="placesContext_createBookmark" @@ -182,14 +182,13 @@ command="placesCmd_copy" label="©Cmd.label;" closemenu="single" - accesskey="©Cmd.accesskey;" - selection="any"/> + accesskey="©Cmd.accesskey;"/> <menuitem id="placesContext_paste" command="placesCmd_paste" label="&pasteCmd.label;" closemenu="single" accesskey="&pasteCmd.accesskey;" - selection="any" + selectiontype="any" hideifnoinsertionpoint="true"/> <menuseparator id="placesContext_editSeparator"/> <menuitem id="placesContext_delete" @@ -204,7 +203,7 @@ accesskey="&cmd.delete.accesskey;" closemenu="single" selection="link" - forcehideselection="bookmark"/> + forcehideselection="bookmark|livemarkChild"/> <menuitem id="placesContext_deleteHost" command="placesCmd_deleteDataHost" label="&cmd.deleteDomainData.label;" @@ -213,7 +212,7 @@ selection="link|host" selectiontype="single" hideifprivatebrowsing="true" - forcehideselection="bookmark"/> + forcehideselection="bookmark|livemarkChild"/> <menuseparator id="placesContext_deleteSeparator"/> <menuitem id="placesContext_reload" command="placesCmd_reload" diff --git a/application/palemoon/components/places/content/sidebarUtils.js b/application/palemoon/components/places/content/sidebarUtils.js index 8ffb70348..06ed53753 100644 --- a/application/palemoon/components/places/content/sidebarUtils.js +++ b/application/palemoon/components/places/content/sidebarUtils.js @@ -40,7 +40,7 @@ var SidebarUtils = { var openInTabs = isContainer && (aEvent.button == 1 || (aEvent.button == 0 && modifKey)) && - PlacesUtils.hasChildURIs(tbo.view.nodeForTreeIndex(cell.row)); + PlacesUtils.hasChildURIs(tbo.view.nodeForTreeIndex(cell.row), true); if (aEvent.button == 0 && isContainer && !openInTabs) { tbo.view.toggleOpenState(cell.row); diff --git a/application/palemoon/components/preferences/advanced.xul b/application/palemoon/components/preferences/advanced.xul index 34998c1b8..e5f3bb160 100644 --- a/application/palemoon/components/preferences/advanced.xul +++ b/application/palemoon/components/preferences/advanced.xul @@ -106,6 +106,8 @@ <preference id="general.smoothScroll.scrollbars" name="general.smoothScroll.scrollbars" type="bool"/> <preference id="general.smoothScroll.scrollbars.durationMinMS" name="general.smoothScroll.scrollbars.durationMinMS" type="int"/> <preference id="general.smoothScroll.scrollbars.durationMaxMS" name="general.smoothScroll.scrollbars.durationMaxMS" type="int"/> + + <preference id="mousewheel.default.delta_multiplier_y" name="mousewheel.default.delta_multiplier_y" type="int"/> </preferences> #ifdef HAVE_SHELL_SERVICE @@ -445,6 +447,13 @@ preference="general.smoothScroll.scrollbars.durationMaxMS"/> <label flex="1">ms.</label> </hbox> + + <hbox align="center"> + <label value="&smoothscroll.overall.yspeed.label;"/> + <textbox type="number" size="3" min="1" max="999" + preference="mousewheel.default.delta_multiplier_y"/> + <label flex="1">%.</label> + </hbox> </groupbox> </tabpanel> <!-- end Smooth scrolling tab --> diff --git a/application/palemoon/components/preferences/privacy.js b/application/palemoon/components/preferences/privacy.js index 05c2f9b8a..e2a871acc 100644 --- a/application/palemoon/components/preferences/privacy.js +++ b/application/palemoon/components/preferences/privacy.js @@ -298,36 +298,6 @@ var gPrivacyPane = { // HISTORY - /** - * Read the location bar enabled and suggestion prefs - * @return Int value for suggestion menulist - */ - readSuggestionPref: function PPP_readSuggestionPref() - { - let getVal = function(aPref) - document.getElementById("browser.urlbar." + aPref).value; - - // Suggest nothing if autocomplete is not enabled - if (!getVal("autocomplete.enabled")) - return -1; - - // Bottom 2 bits of default.behavior specify history/bookmark - return getVal("default.behavior") & 3; - }, - - /** - * Update browser.urlbar.autocomplete.enabled when a - * browser.urlbar.suggest.* pref is changed from the ui. - */ - writeSuggestionPref: function PPP_writeSuggestionPref() { - let getVal = (aPref) => { - return document.getElementById("browser.urlbar.suggest." + aPref).value; - } - // autocomplete.enabled is true if any of the suggestions is true - let enabled = ["history", "bookmark", "openpage"].map(getVal).some(v => v); - Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", enabled); - }, - /* * Preferences: * diff --git a/application/palemoon/components/preferences/privacy.xul b/application/palemoon/components/preferences/privacy.xul index bdb227c63..d2f8106d1 100644 --- a/application/palemoon/components/preferences/privacy.xul +++ b/application/palemoon/components/preferences/privacy.xul @@ -254,15 +254,12 @@ <vbox id="tabPrefsBox" align="start" flex="1"> <checkbox id="historySuggestion" label="&locbar.history.label;" - onsyncfrompreference="return gPrivacyPane.writeSuggestionPref();" accesskey="&locbar.history.accesskey;" preference="browser.urlbar.suggest.history"/> <checkbox id="bookmarkSuggestion" label="&locbar.bookmarks.label;" - onsyncfrompreference="return gPrivacyPane.writeSuggestionPref();" accesskey="&locbar.bookmarks.accesskey;" preference="browser.urlbar.suggest.bookmark"/> <checkbox id="openpageSuggestion" label="&locbar.openpage.label;" - onsyncfrompreference="return gPrivacyPane.writeSuggestionPref();" accesskey="&locbar.openpage.accesskey;" preference="browser.urlbar.suggest.openpage"/> </vbox> diff --git a/application/palemoon/configure.in b/application/palemoon/configure.in index 9d820f6d4..70ddf6621 100644 --- a/application/palemoon/configure.in +++ b/application/palemoon/configure.in @@ -15,20 +15,6 @@ AC_SUBST(MOZ_PHOENIX_EXTENSIONS) dnl Optional parts of the build. dnl ======================================================== -dnl = Disable the status bar code -dnl ======================================================== -MOZ_ARG_DISABLE_BOOL(browser-statusbar, -[ --disable-browser-statusbar Disable Browser Status bar], - MOZ_BROWSER_STATUSBAR=, - MOZ_BROWSER_STATUSBAR=1) - -if test -n "$MOZ_BROWSER_STATUSBAR"; then - AC_DEFINE(MOZ_BROWSER_STATUSBAR) -fi - -AC_SUBST(MOZ_BROWSER_STATUSBAR) - -dnl ======================================================== dnl = Disable Sync dnl ======================================================== MOZ_ARG_DISABLE_BOOL(sync, diff --git a/application/palemoon/confvars.sh b/application/palemoon/confvars.sh index 79681f013..ee8e38412 100644 --- a/application/palemoon/confvars.sh +++ b/application/palemoon/confvars.sh @@ -43,9 +43,6 @@ MC_PALEMOON=1 # Firefox-like browsers MOZ_PHOENIX=1 -# Browser Feature: Status bar Component -MOZ_BROWSER_STATUSBAR=1 - # Lightweight Themes MOZ_PERSONAS=1 diff --git a/application/palemoon/installer/Makefile.in b/application/palemoon/installer/Makefile.in index 3f009c51c..a0c38f282 100644 --- a/application/palemoon/installer/Makefile.in +++ b/application/palemoon/installer/Makefile.in @@ -113,19 +113,19 @@ include $(topsrcdir)/toolkit/mozapps/installer/packager.mk ifeq (bundle, $(MOZ_FS_LAYOUT)) BINPATH = $(_BINPATH) -DEFINES += -DAPPNAME=$(_APPNAME) +DEFINES += -DAPPNAME='$(_APPNAME)' else # Every other platform just winds up in dist/bin BINPATH = bin endif -DEFINES += -DBINPATH=$(BINPATH) +DEFINES += -DBINPATH='$(BINPATH)' ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) RESPATH = $(_APPNAME)/Contents/Resources else RESPATH = $(BINPATH) endif -DEFINES += -DRESPATH=$(RESPATH) +DEFINES += -DRESPATH='$(RESPATH)' AB = $(firstword $(subst -, ,$(AB_CD))) DEFINES += -DAB=$(AB) @@ -173,7 +173,7 @@ endif package-compare:: $(MOZ_PKG_MANIFEST) ifdef MOZ_PKG_MANIFEST_P - cd $(DIST); find $(PKGCOMP_FIND_OPTS) $(FINDPATH) -type f | sort > bin-list.txt + cd $(DIST); find $(PKGCOMP_FIND_OPTS) '$(FINDPATH)' -type f | sort > bin-list.txt grep '^$(BINPATH)' $(MOZ_PKG_MANIFEST) | sed -e 's/^\///' | sort > $(DIST)/pack-list.txt -diff -u $(DIST)/pack-list.txt $(DIST)/bin-list.txt rm -f $(DIST)/pack-list.txt $(DIST)/bin-list.txt diff --git a/application/palemoon/installer/package-manifest.in b/application/palemoon/installer/package-manifest.in index 0d80e15f9..f95f18f77 100644 --- a/application/palemoon/installer/package-manifest.in +++ b/application/palemoon/installer/package-manifest.in @@ -206,11 +206,6 @@ #endif #ifdef MOZ_DEVTOOLS -; [Webide Files] -@RESPATH@/browser/chrome/webide@JAREXT@ -@RESPATH@/browser/chrome/webide.manifest -@RESPATH@/browser/@PREF_DIR@/webide-prefs.js - ; DevTools @RESPATH@/browser/chrome/devtools@JAREXT@ @RESPATH@/browser/chrome/devtools.manifest diff --git a/application/palemoon/locales/Makefile.in b/application/palemoon/locales/Makefile.in index 38a867658..897fa0bca 100644 --- a/application/palemoon/locales/Makefile.in +++ b/application/palemoon/locales/Makefile.in @@ -198,10 +198,10 @@ endif ident: @printf "fx_revision " @$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \ - $(STAGEDIST)/application.ini App SourceStamp + '$(STAGEDIST)'/application.ini App SourceStamp @printf "buildid " @$(PYTHON) $(topsrcdir)/config/printconfigsetting.py \ - $(STAGEDIST)/application.ini App BuildID + '$(STAGEDIST)'/application.ini App BuildID merge-%: ifdef LOCALE_MERGEDIR diff --git a/application/palemoon/locales/en-US/chrome/browser/preferences/advanced.dtd b/application/palemoon/locales/en-US/chrome/browser/preferences/advanced.dtd index dcb7b0e90..bb8dd12d2 100644 --- a/application/palemoon/locales/en-US/chrome/browser/preferences/advanced.dtd +++ b/application/palemoon/locales/en-US/chrome/browser/preferences/advanced.dtd @@ -147,3 +147,5 @@ <!ENTITY smoothscroll.pagekeys.duration "Page up/down scroll duration:"> <!ENTITY smoothscroll.scrollbar.label "Smooth scroll with scrollbars"> <!ENTITY smoothscroll.scrollbar.duration "Scrollbar smooth scroll duration:"> + +<!ENTITY smoothscroll.overall.yspeed.label "Overall smooth scroll speed:"> diff --git a/application/palemoon/locales/generic/profile/bookmarks.html.in b/application/palemoon/locales/generic/profile/bookmarks.html.in index 96270641a..90e3adfe9 100644 --- a/application/palemoon/locales/generic/profile/bookmarks.html.in +++ b/application/palemoon/locales/generic/profile/bookmarks.html.in @@ -11,9 +11,9 @@ <DT><H3 PERSONAL_TOOLBAR_FOLDER="true" ID="rdf:#$FvPhC3">@bookmarks_toolbarfolder@</H3> <DD>@bookmarks_toolbarfolder_description@ <DL><p> - <DT><A HREF="http://www.palemoon.org/" ICON_URI="http://www.palemoon.org/favicon.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADe0lEQVQ4jW2T7VPTBQDHfwd/gpZW57bwuvJFIQ1lPgy9g7KzNCO4A9sDA8FNTCyg0KD9GBuCIrYhHYPw6Ygd2xB0rAFrEfxikA03YibyIO4pYGwONlhbx923F72I2/V5/f18X32/BBHDrox6ejKnlTxSaqRKlROuK5op1w3DHKUfdZC1d36hxeY3Qca9lVFH7uG2RFLPdKGo0YqOQTcouw/T7hBcy2E4l9YjuhGHmCDJuFg7bmd6mXrXMRleO9EEZp4axc2T6DH/CddyGN5ABMH1vxGObMC/GoVp3N1JEJtKXmadEdPY50FLJ/FGphIHzurx5Y1HMFiW8HB2BX84gvD4wghHNvBXdAMeXxi3fpj5+l+ZWUjbzsyL0NjFeDOjAcm823inxIjSVjuMD72g7D5YZ1fw2BmEbzWCQCgK29wK6rXTEYF0aAexPTmX3MbkY+fhYqQKlMgW/wiObAzFzZNo1s9D/2ARk/OrGPrdB5PVC5PVi7HHz3FaYUN29ZCYePFt/vDW3VwkfnARR4tuouAyBUGdGbw6C9r6HTDZlmF/tgoN5UFbnwPynjk06+chUz1B2vn7Q8RLyTzX1kQOEg59iiOF3+IkOQCejIJQboXi3lOMzwQw7Q5h5JEf6mEPbhudEF2fwNGKEbBOqZ0ELYXn2pLIwQvMPLB5cmSU68C7NIqSlilcveuCweLH+EwI1tkg9A8WofrZDW6tBccvDoN9Wu0k6Ck8alsSB6+kFCDpIylOlPUgR0JB+I0V4g43FL1+dFIhGH5bR1v/EiTfP4VIPoHMykGkCjXDBC1FUEXbywFjfz7Y2VJkXtAhp2oQIrkNEvUC6nV+NPaH0NgXQv19PyranTjbZEeOhMLBQhVJMFhCBmPvJ9GE/Twwj5fj/c+04NaMoKT1CRp6A7g+sAZFXxByQxBXdc8h1S6hst2BD8sHIkknv6MTBEEQ9H25klf3ccE8VobMLzQQXrNA0ulB08AamoxraOwPoaE3gNruZZAqN0QKGw6JtFWblpwVT2fxtQkH8pFeoAS/hsKFW7O4cs+Ha/oA6rq9qOlahLjDBaHchrRz3VqCyIqPuUNW/A5WfvXr71VE3z3XBX7tGMraplHZ/gxf3ZnH5y1T4MhGo6kiTfX/yP/BOEwyducopWlFXeYs8U8Lgsu/LvAvmc0fV5ikrFwVIzb/D6b/QY5z63dPAAAAAElFTkSuQmCC">Pale Moon</A> - <DT><A HREF="https://forum.palemoon.org/index.php" ICON_URI="https://forum.palemoon.org/favicon.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADWUlEQVQ4jW1T60+Tdxj9Bf4CyXRR21Kixgheq1baAo2IaLkIpi0tpdQCBZHLNIIgQvGlpVkHOnnpFKrOTafUtjIuVYmXKBZREzLB4A0NbOVFghVtcEOqJid+YMlI50meb+ecPM/JeQgJQESymcNTNVHx+7vcJdYBps7+dNTS9tz9s2uQ0pQ7OIH8OaCCVqb+QG3ItPqj81tRYHmIltsMeh5PYoh5D8Y7Dc/EPzNnrzw5TCgqKFAdtCSuzL480YQlO34CL8uO4qZBtN0bB+OdxmvfDKamP2Ha/xmTU3503h25SMgck0XCosOsqO/AiqXAiinFvDAhlvK2ImpLEuIkKdgqSUG2bje8kz588H/G2JsPOGZ/qJ8VxxSwv12f7V8sLELEzqMIl1SAEPLV6fvjEd69/4iBYR/qnS9mlJXtbLKIn0ct4GkQJi5GtNYKhf464tP2ghACmUyOevokpHIlVoSHw+a6h5v9Xtx/9ha5dD+Sy69WkwXrte6Q1WqsSqyApOAMdHVuiNMNIIRAkZ6Byz1D6HvyCiftt9HUPgi6fRjNV/5ErW0I4sLWO2ThBg0TsjoDYTFFiM89gfTqa4hW1IAQAhabg81xCdiWmIraY7/A3j2KX294kG95BMmhu4jUOTyEzc9kQlap8M26LESpG7CzzIWYdNP/7lepNfi9+yVs3WNQm/uQfNANUd7FUcKJ3NUzf40KC/k6rE01YkdpOwSy2Q2ksjQYjpzG9/Q5NJ5qRXPnCGouDCOfHoC06hYEOS13CEeQW8PaqEKoIAsihRHS8k4IZfrZEBVq1DleorHLh8arPtR3TKLyvAeFxx9DaXCDrz1LkbDYktBQvsrPjczEuqQyJOx1IurfDGTKTNAdDBq7ptDQNYUjrneodU6g6rwHKRXXZyLk9Gy1Q0U6A3dTBnhJJZAecCClsBkrwlciZ3cx6M4xWK79jR8v+2Bue4Nq2xjy6QEIcltq5jRZHsyJ1F7iCrMRm2OFxtSNcsstmM704mjHa5jbvDBdmoC+hUFeQz/EBU4nIfLggHeQB7NFeYZl2yr9ccWt0JgfoPT0C1T99hcqzo1gn/UZ1KZev0hnM3xF/B+42ynumrQTRvEeR69Mf3Nca34wnmF09yYccBnXKpu4gfwvLIL1Qrog43cAAAAASUVORK5CYII=" LAST_CHARSET="UTF-8">Pale Moon forum</A> - <DT><A HREF="http://www.palemoon.org/faq.shtml" ICON_URI="http://www.palemoon.org/favicon.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADe0lEQVQ4jW2T7VPTBQDHfwd/gpZW57bwuvJFIQ1lPgy9g7KzNCO4A9sDA8FNTCyg0KD9GBuCIrYhHYPw6Ygd2xB0rAFrEfxikA03YibyIO4pYGwONlhbx923F72I2/V5/f18X32/BBHDrox6ejKnlTxSaqRKlROuK5op1w3DHKUfdZC1d36hxeY3Qca9lVFH7uG2RFLPdKGo0YqOQTcouw/T7hBcy2E4l9YjuhGHmCDJuFg7bmd6mXrXMRleO9EEZp4axc2T6DH/CddyGN5ABMH1vxGObMC/GoVp3N1JEJtKXmadEdPY50FLJ/FGphIHzurx5Y1HMFiW8HB2BX84gvD4wghHNvBXdAMeXxi3fpj5+l+ZWUjbzsyL0NjFeDOjAcm823inxIjSVjuMD72g7D5YZ1fw2BmEbzWCQCgK29wK6rXTEYF0aAexPTmX3MbkY+fhYqQKlMgW/wiObAzFzZNo1s9D/2ARk/OrGPrdB5PVC5PVi7HHz3FaYUN29ZCYePFt/vDW3VwkfnARR4tuouAyBUGdGbw6C9r6HTDZlmF/tgoN5UFbnwPynjk06+chUz1B2vn7Q8RLyTzX1kQOEg59iiOF3+IkOQCejIJQboXi3lOMzwQw7Q5h5JEf6mEPbhudEF2fwNGKEbBOqZ0ELYXn2pLIwQvMPLB5cmSU68C7NIqSlilcveuCweLH+EwI1tkg9A8WofrZDW6tBccvDoN9Wu0k6Ck8alsSB6+kFCDpIylOlPUgR0JB+I0V4g43FL1+dFIhGH5bR1v/EiTfP4VIPoHMykGkCjXDBC1FUEXbywFjfz7Y2VJkXtAhp2oQIrkNEvUC6nV+NPaH0NgXQv19PyranTjbZEeOhMLBQhVJMFhCBmPvJ9GE/Twwj5fj/c+04NaMoKT1CRp6A7g+sAZFXxByQxBXdc8h1S6hst2BD8sHIkknv6MTBEEQ9H25klf3ccE8VobMLzQQXrNA0ulB08AamoxraOwPoaE3gNruZZAqN0QKGw6JtFWblpwVT2fxtQkH8pFeoAS/hsKFW7O4cs+Ha/oA6rq9qOlahLjDBaHchrRz3VqCyIqPuUNW/A5WfvXr71VE3z3XBX7tGMraplHZ/gxf3ZnH5y1T4MhGo6kiTfX/yP/BOEwyducopWlFXeYs8U8Lgsu/LvAvmc0fV5ikrFwVIzb/D6b/QY5z63dPAAAAAElFTkSuQmCC">F.A.Q.</A> - <DT><A HREF="http://www.palemoon.org/releasenotes.shtml" ICON_URI="http://www.palemoon.org/favicon.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADe0lEQVQ4jW2T7VPTBQDHfwd/gpZW57bwuvJFIQ1lPgy9g7KzNCO4A9sDA8FNTCyg0KD9GBuCIrYhHYPw6Ygd2xB0rAFrEfxikA03YibyIO4pYGwONlhbx923F72I2/V5/f18X32/BBHDrox6ejKnlTxSaqRKlROuK5op1w3DHKUfdZC1d36hxeY3Qca9lVFH7uG2RFLPdKGo0YqOQTcouw/T7hBcy2E4l9YjuhGHmCDJuFg7bmd6mXrXMRleO9EEZp4axc2T6DH/CddyGN5ABMH1vxGObMC/GoVp3N1JEJtKXmadEdPY50FLJ/FGphIHzurx5Y1HMFiW8HB2BX84gvD4wghHNvBXdAMeXxi3fpj5+l+ZWUjbzsyL0NjFeDOjAcm823inxIjSVjuMD72g7D5YZ1fw2BmEbzWCQCgK29wK6rXTEYF0aAexPTmX3MbkY+fhYqQKlMgW/wiObAzFzZNo1s9D/2ARk/OrGPrdB5PVC5PVi7HHz3FaYUN29ZCYePFt/vDW3VwkfnARR4tuouAyBUGdGbw6C9r6HTDZlmF/tgoN5UFbnwPynjk06+chUz1B2vn7Q8RLyTzX1kQOEg59iiOF3+IkOQCejIJQboXi3lOMzwQw7Q5h5JEf6mEPbhudEF2fwNGKEbBOqZ0ELYXn2pLIwQvMPLB5cmSU68C7NIqSlilcveuCweLH+EwI1tkg9A8WofrZDW6tBccvDoN9Wu0k6Ck8alsSB6+kFCDpIylOlPUgR0JB+I0V4g43FL1+dFIhGH5bR1v/EiTfP4VIPoHMykGkCjXDBC1FUEXbywFjfz7Y2VJkXtAhp2oQIrkNEvUC6nV+NPaH0NgXQv19PyranTjbZEeOhMLBQhVJMFhCBmPvJ9GE/Twwj5fj/c+04NaMoKT1CRp6A7g+sAZFXxByQxBXdc8h1S6hst2BD8sHIkknv6MTBEEQ9H25klf3ccE8VobMLzQQXrNA0ulB08AamoxraOwPoaE3gNruZZAqN0QKGw6JtFWblpwVT2fxtQkH8pFeoAS/hsKFW7O4cs+Ha/oA6rq9qOlahLjDBaHchrRz3VqCyIqPuUNW/A5WfvXr71VE3z3XBX7tGMraplHZ/gxf3ZnH5y1T4MhGo6kiTfX/yP/BOEwyducopWlFXeYs8U8Lgsu/LvAvmc0fV5ikrFwVIzb/D6b/QY5z63dPAAAAAElFTkSuQmCC">Release notes</A> + <DT><A HREF="http://www.palemoon.org/" ICON_URI="http://www.palemoon.org/favicon.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfjBQQNKi3s6zvVAAAAB3RJTUUH4wUFDiY4QniqfgAAAAlwSFlzAAAK8AAACvABQqw0mAAAAn1JREFUeNpVU9FKW0EUnLO7NzdFY5uqRSMSoSj1F/paP0EEoU/2H/pWIkiLX+GzH5HnQj9BENQqpSgWkdbeu/fubudsCKQ3CSS7M3PmzDmRb5f3mH1SShsGcmAF7wTYaGMC35cQjBNwYoxczeJlKpASrAFGHYOP3cKUJMO3Cb4JMPwhIggJdZNwLEaOKBiU52bIp73S7jp+iyyJFNG2/JBlSBYC6KrsWhnR1XYQ2Sc1GuRKcTTXMbudwqpcfokxUPtamV/heGWdgaVKYWXPpvRp0sLF/ZB3Z72uKx0B3ocswis8VQ0CRf7yTMWflRZTh00bq1awpS18IK8kXltBQWDbBroK2X7Byxc9m9tIk7Qyju66EThwjHhHyS3DQpG0dSYVEELM9rWdyKskmmDMEpaphjpAnOw4VhuayAMGBi85cX0UzF7xVEfUdJNyV5Ltu5wNYIJsOK1GPji6TFKBkm3wJxq6iLQkMWVXhkmqkAktHHF/qgDnfXsZUhi03mTVqm7gFKiDzuPUXWg4FabPqbdRRVWcZOcuiJXx02P1VgjU8HJM2rtWysFOzh1dcXSaPizolEKdue5Yvp7fDn+efz+LtS81Bt2YIHn1Jn0SqLO31ubwtLzlGfekerm5vuWss1fzz3vHtxc/RpE9q4cmkcCKUW2yGc2EFLQpTdcei8OVL8a567zKCyuLR78f6u37m7s9iS0rE1HrhD1qilXC6vyIddCr/mr/dH516bNy8ypz3mHwZrD/anPt0JuyqkOBqtJlKrhMFk2dUPkID1MtvV45XNsevCcn/vdvnD6+btbvbn4dPNw+7lSVH+pZOde96i8vjJcH/ZNO6a5n8f8A5KRcUpQlS3kAAAAASUVORK5CYII=">Pale Moon</A> + <DT><A HREF="https://forum.palemoon.org/index.php" ICON_URI="https://forum.palemoon.org/favicon.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfjBQQNKi3s6zvVAAAAB3RJTUUH4wUFDiY4QniqfgAAAAlwSFlzAAAK8AAACvABQqw0mAAAAn1JREFUeNpVU9FKW0EUnLO7NzdFY5uqRSMSoSj1F/paP0EEoU/2H/pWIkiLX+GzH5HnQj9BENQqpSgWkdbeu/fubudsCKQ3CSS7M3PmzDmRb5f3mH1SShsGcmAF7wTYaGMC35cQjBNwYoxczeJlKpASrAFGHYOP3cKUJMO3Cb4JMPwhIggJdZNwLEaOKBiU52bIp73S7jp+iyyJFNG2/JBlSBYC6KrsWhnR1XYQ2Sc1GuRKcTTXMbudwqpcfokxUPtamV/heGWdgaVKYWXPpvRp0sLF/ZB3Z72uKx0B3ocswis8VQ0CRf7yTMWflRZTh00bq1awpS18IK8kXltBQWDbBroK2X7Byxc9m9tIk7Qyju66EThwjHhHyS3DQpG0dSYVEELM9rWdyKskmmDMEpaphjpAnOw4VhuayAMGBi85cX0UzF7xVEfUdJNyV5Ltu5wNYIJsOK1GPji6TFKBkm3wJxq6iLQkMWVXhkmqkAktHHF/qgDnfXsZUhi03mTVqm7gFKiDzuPUXWg4FabPqbdRRVWcZOcuiJXx02P1VgjU8HJM2rtWysFOzh1dcXSaPizolEKdue5Yvp7fDn+efz+LtS81Bt2YIHn1Jn0SqLO31ubwtLzlGfekerm5vuWss1fzz3vHtxc/RpE9q4cmkcCKUW2yGc2EFLQpTdcei8OVL8a567zKCyuLR78f6u37m7s9iS0rE1HrhD1qilXC6vyIddCr/mr/dH516bNy8ypz3mHwZrD/anPt0JuyqkOBqtJlKrhMFk2dUPkID1MtvV45XNsevCcn/vdvnD6+btbvbn4dPNw+7lSVH+pZOde96i8vjJcH/ZNO6a5n8f8A5KRcUpQlS3kAAAAASUVORK5CYII=" LAST_CHARSET="UTF-8">Pale Moon forum</A> + <DT><A HREF="http://www.palemoon.org/faq.shtml" ICON_URI="http://www.palemoon.org/favicon.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfjBQQNKi3s6zvVAAAAB3RJTUUH4wUFDiY4QniqfgAAAAlwSFlzAAAK8AAACvABQqw0mAAAAn1JREFUeNpVU9FKW0EUnLO7NzdFY5uqRSMSoSj1F/paP0EEoU/2H/pWIkiLX+GzH5HnQj9BENQqpSgWkdbeu/fubudsCKQ3CSS7M3PmzDmRb5f3mH1SShsGcmAF7wTYaGMC35cQjBNwYoxczeJlKpASrAFGHYOP3cKUJMO3Cb4JMPwhIggJdZNwLEaOKBiU52bIp73S7jp+iyyJFNG2/JBlSBYC6KrsWhnR1XYQ2Sc1GuRKcTTXMbudwqpcfokxUPtamV/heGWdgaVKYWXPpvRp0sLF/ZB3Z72uKx0B3ocswis8VQ0CRf7yTMWflRZTh00bq1awpS18IK8kXltBQWDbBroK2X7Byxc9m9tIk7Qyju66EThwjHhHyS3DQpG0dSYVEELM9rWdyKskmmDMEpaphjpAnOw4VhuayAMGBi85cX0UzF7xVEfUdJNyV5Ltu5wNYIJsOK1GPji6TFKBkm3wJxq6iLQkMWVXhkmqkAktHHF/qgDnfXsZUhi03mTVqm7gFKiDzuPUXWg4FabPqbdRRVWcZOcuiJXx02P1VgjU8HJM2rtWysFOzh1dcXSaPizolEKdue5Yvp7fDn+efz+LtS81Bt2YIHn1Jn0SqLO31ubwtLzlGfekerm5vuWss1fzz3vHtxc/RpE9q4cmkcCKUW2yGc2EFLQpTdcei8OVL8a567zKCyuLR78f6u37m7s9iS0rE1HrhD1qilXC6vyIddCr/mr/dH516bNy8ypz3mHwZrD/anPt0JuyqkOBqtJlKrhMFk2dUPkID1MtvV45XNsevCcn/vdvnD6+btbvbn4dPNw+7lSVH+pZOde96i8vjJcH/ZNO6a5n8f8A5KRcUpQlS3kAAAAASUVORK5CYII=">F.A.Q.</A> + <DT><A HREF="http://www.palemoon.org/releasenotes.shtml" ICON_URI="http://www.palemoon.org/favicon.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAFXRFWHRDcmVhdGlvbiBUaW1lAAfjBQQNKi3s6zvVAAAAB3RJTUUH4wUFDiY4QniqfgAAAAlwSFlzAAAK8AAACvABQqw0mAAAAn1JREFUeNpVU9FKW0EUnLO7NzdFY5uqRSMSoSj1F/paP0EEoU/2H/pWIkiLX+GzH5HnQj9BENQqpSgWkdbeu/fubudsCKQ3CSS7M3PmzDmRb5f3mH1SShsGcmAF7wTYaGMC35cQjBNwYoxczeJlKpASrAFGHYOP3cKUJMO3Cb4JMPwhIggJdZNwLEaOKBiU52bIp73S7jp+iyyJFNG2/JBlSBYC6KrsWhnR1XYQ2Sc1GuRKcTTXMbudwqpcfokxUPtamV/heGWdgaVKYWXPpvRp0sLF/ZB3Z72uKx0B3ocswis8VQ0CRf7yTMWflRZTh00bq1awpS18IK8kXltBQWDbBroK2X7Byxc9m9tIk7Qyju66EThwjHhHyS3DQpG0dSYVEELM9rWdyKskmmDMEpaphjpAnOw4VhuayAMGBi85cX0UzF7xVEfUdJNyV5Ltu5wNYIJsOK1GPji6TFKBkm3wJxq6iLQkMWVXhkmqkAktHHF/qgDnfXsZUhi03mTVqm7gFKiDzuPUXWg4FabPqbdRRVWcZOcuiJXx02P1VgjU8HJM2rtWysFOzh1dcXSaPizolEKdue5Yvp7fDn+efz+LtS81Bt2YIHn1Jn0SqLO31ubwtLzlGfekerm5vuWss1fzz3vHtxc/RpE9q4cmkcCKUW2yGc2EFLQpTdcei8OVL8a567zKCyuLR78f6u37m7s9iS0rE1HrhD1qilXC6vyIddCr/mr/dH516bNy8ypz3mHwZrD/anPt0JuyqkOBqtJlKrhMFk2dUPkID1MtvV45XNsevCcn/vdvnD6+btbvbn4dPNw+7lSVH+pZOde96i8vjJcH/ZNO6a5n8f8A5KRcUpQlS3kAAAAASUVORK5CYII=">Release notes</A> </DL><p> </DL><p> diff --git a/application/palemoon/themes/linux/jar.mn b/application/palemoon/themes/linux/jar.mn index a79487c7f..a7c426bce 100644 --- a/application/palemoon/themes/linux/jar.mn +++ b/application/palemoon/themes/linux/jar.mn @@ -107,7 +107,6 @@ browser.jar: #endif * skin/classic/browser/preferences/preferences.css (preferences/preferences.css) skin/classic/browser/preferences/applications.css (preferences/applications.css) -#ifdef MOZ_BROWSER_STATUSBAR skin/classic/browser/statusbar/dynamic.css (../shared/statusbar/dynamic.css) * skin/classic/browser/statusbar/overlay.css (statusbar/overlay.css) * skin/classic/browser/statusbar/prefs.css (statusbar/prefs.css) @@ -116,7 +115,6 @@ browser.jar: skin/classic/browser/statusbar/pms24.png (../shared/statusbar/pms24.png) skin/classic/browser/statusbar/throbber-idle.png (../shared/statusbar/throbber-idle.png) skin/classic/browser/statusbar/throbberStatic.png (../shared/statusbar/throbberStatic.png) -#endif skin/classic/browser/tabbrowser/alltabs.png (tabbrowser/alltabs.png) skin/classic/browser/tabbrowser/connecting.png (tabbrowser/connecting.png) skin/classic/browser/tabbrowser/loading.png (tabbrowser/loading.png) diff --git a/application/palemoon/themes/osx/jar.mn b/application/palemoon/themes/osx/jar.mn index c59fb1c72..67339c7cc 100644 --- a/application/palemoon/themes/osx/jar.mn +++ b/application/palemoon/themes/osx/jar.mn @@ -146,7 +146,6 @@ browser.jar: skin/classic/browser/preferences/saveFile.png (preferences/saveFile.png) * skin/classic/browser/preferences/preferences.css (preferences/preferences.css) skin/classic/browser/preferences/applications.css (preferences/applications.css) -#ifdef MOZ_BROWSER_STATUSBAR skin/classic/browser/statusbar/dynamic.css (../shared/statusbar/dynamic.css) * skin/classic/browser/statusbar/overlay.css (statusbar/overlay.css) * skin/classic/browser/statusbar/prefs.css (statusbar/prefs.css) @@ -155,7 +154,6 @@ browser.jar: skin/classic/browser/statusbar/pms24.png (../shared/statusbar/pms24.png) skin/classic/browser/statusbar/throbber-idle.png (../shared/statusbar/throbber-idle.png) skin/classic/browser/statusbar/throbberStatic.png (../shared/statusbar/throbberStatic.png) -#endif skin/classic/browser/tabbrowser/alltabs.png (tabbrowser/alltabs.png) skin/classic/browser/tabbrowser/alltabs-inverted.png (tabbrowser/alltabs-inverted.png) skin/classic/browser/tabbrowser/newtab.png (tabbrowser/newtab.png) diff --git a/application/palemoon/themes/windows/jar.mn b/application/palemoon/themes/windows/jar.mn index 604466c9f..4422bb666 100644 --- a/application/palemoon/themes/windows/jar.mn +++ b/application/palemoon/themes/windows/jar.mn @@ -131,7 +131,6 @@ browser.jar: skin/classic/browser/preferences/saveFile.png (preferences/saveFile.png) * skin/classic/browser/preferences/preferences.css (preferences/preferences.css) skin/classic/browser/preferences/applications.css (preferences/applications.css) -#ifdef MOZ_BROWSER_STATUSBAR skin/classic/browser/statusbar/dynamic.css (../shared/statusbar/dynamic.css) * skin/classic/browser/statusbar/overlay.css (statusbar/overlay.css) * skin/classic/browser/statusbar/prefs.css (statusbar/prefs.css) @@ -140,7 +139,6 @@ browser.jar: skin/classic/browser/statusbar/pms24.png (../shared/statusbar/pms24.png) skin/classic/browser/statusbar/throbber-idle.png (../shared/statusbar/throbber-idle.png) skin/classic/browser/statusbar/throbberStatic.png (../shared/statusbar/throbberStatic.png) -#endif skin/classic/browser/tabbrowser/alltabs.png (tabbrowser/alltabs.png) skin/classic/browser/tabbrowser/alltabs-inverted.png (tabbrowser/alltabs-inverted.png) skin/classic/browser/tabbrowser/newtab.png (tabbrowser/newtab.png) diff --git a/caps/moz.build b/caps/moz.build index 58b45e360..dc47ecbba 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -34,12 +34,7 @@ EXPORTS.mozilla = [ ] SOURCES += [ - # Compile this separately since nsExceptionHandler.h conflicts - # with something from nsNullPrincipal.cpp. 'BasePrincipal.cpp', -] - -UNIFIED_SOURCES += [ 'DomainPolicy.cpp', 'nsJSPrincipals.cpp', 'nsNullPrincipal.cpp', diff --git a/caps/nsJSPrincipals.cpp b/caps/nsJSPrincipals.cpp index 0f3afa14e..8349aed53 100644 --- a/caps/nsJSPrincipals.cpp +++ b/caps/nsJSPrincipals.cpp @@ -15,6 +15,7 @@ #include "nsMemory.h" #include "nsStringBuffer.h" +#include "mozilla/ipc/PBackgroundSharedTypes.h" #include "mozilla/dom/StructuredCloneTags.h" // for mozilla::dom::workers::kJSPrincipalsDebugToken #include "mozilla/dom/workers/Workers.h" @@ -22,6 +23,7 @@ using namespace mozilla; using namespace mozilla::ipc; +using namespace mozilla::dom; NS_IMETHODIMP_(MozExternalRefCountType) nsJSPrincipals::AddRef() diff --git a/caps/nsNullPrincipal.cpp b/caps/nsNullPrincipal.cpp index 6ebf0f129..386344e37 100644 --- a/caps/nsNullPrincipal.cpp +++ b/caps/nsNullPrincipal.cpp @@ -20,6 +20,8 @@ #include "nsIClassInfoImpl.h" #include "nsNetCID.h" #include "nsError.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" #include "nsIScriptSecurityManager.h" #include "nsPrincipal.h" #include "nsScriptSecurityManager.h" diff --git a/caps/nsNullPrincipalURI.cpp b/caps/nsNullPrincipalURI.cpp index f8b867160..159928ba6 100644 --- a/caps/nsNullPrincipalURI.cpp +++ b/caps/nsNullPrincipalURI.cpp @@ -6,8 +6,12 @@ #include "nsNullPrincipalURI.h" +#include "mozilla/ArrayUtils.h" + #include "mozilla/DebugOnly.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/Services.h" +#include "mozilla/Unused.h" #include "mozilla/ipc/URIParams.h" @@ -15,6 +19,8 @@ #include "nsCRT.h" #include "nsIUUIDGenerator.h" +using namespace mozilla; + //////////////////////////////////////////////////////////////////////////////// //// nsNullPrincipalURI diff --git a/caps/nsPrincipal.cpp b/caps/nsPrincipal.cpp index 129cdf9a0..d111042c1 100644 --- a/caps/nsPrincipal.cpp +++ b/caps/nsPrincipal.cpp @@ -19,6 +19,8 @@ #include "nsJSPrincipals.h" #include "nsIEffectiveTLDService.h" #include "nsIClassInfoImpl.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" #include "nsIProtocolHandler.h" #include "nsError.h" #include "nsIContentSecurityPolicy.h" diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 129a4d0da..bf5f33599 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -59,6 +59,7 @@ #include "mozIApplication.h" #include "mozilla/Preferences.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/ContentParent.h" #include <stdint.h> #include "mozilla/dom/ScriptSettings.h" #include "mozilla/ClearOnShutdown.h" @@ -70,6 +71,7 @@ using namespace mozilla; using namespace mozilla::dom; +using namespace mozilla::ipc; nsIIOService *nsScriptSecurityManager::sIOService = nullptr; nsIStringBundle *nsScriptSecurityManager::sStrBundle = nullptr; diff --git a/chrome/moz.build b/chrome/moz.build index b75e9435d..15439356a 100644 --- a/chrome/moz.build +++ b/chrome/moz.build @@ -17,7 +17,7 @@ EXPORTS.mozilla.chrome += [ 'RegistryMessageUtils.h', ] -UNIFIED_SOURCES += [ +SOURCES += [ 'nsChromeProtocolHandler.cpp', 'nsChromeRegistry.cpp', 'nsChromeRegistryChrome.cpp', diff --git a/chrome/nsChromeRegistry.cpp b/chrome/nsChromeRegistry.cpp index 485ca002c..4bd8b4dca 100644 --- a/chrome/nsChromeRegistry.cpp +++ b/chrome/nsChromeRegistry.cpp @@ -14,6 +14,7 @@ #include "nsError.h" #include "nsEscape.h" #include "nsNetUtil.h" +#include "nsIURL.h" #include "nsString.h" #include "nsQueryObject.h" diff --git a/config/check_spidermonkey_style.py b/config/check_spidermonkey_style.py index 647f403c4..3b5f20037 100644 --- a/config/check_spidermonkey_style.py +++ b/config/check_spidermonkey_style.py @@ -63,7 +63,7 @@ included_inclnames_to_ignore = set([ 'devtools/Instruments.h', # we ignore devtools/ in general 'double-conversion.h', # strange MFBT case 'javascript-trace.h', # generated in $OBJDIR if HAVE_DTRACE is defined - 'jsautokw.h', # generated in $OBJDIR + 'frontend/ReservedWordsGenerated.h', # generated in $OBJDIR 'jscustomallocator.h', # provided by embedders; allowed to be missing 'js-config.h', # generated in $OBJDIR 'fdlibm.h', # fdlibm @@ -99,7 +99,7 @@ included_inclnames_to_ignore = set([ # ignore #includes of them when checking #include ordering. oddly_ordered_inclnames = set([ 'ctypes/typedefs.h', # Included multiple times in the body of ctypes/CTypes.h - 'jsautokw.h', # Included in the body of frontend/TokenStream.h + 'frontend/ReservedWordsGenerated.h', # Included in the body of frontend/TokenStream.h 'jswin.h', # Must be #included before <psapi.h> 'machine/endian.h', # Must be included after <sys/types.h> on BSD 'winbase.h', # Must precede other system headers(?) diff --git a/config/milestone.txt b/config/milestone.txt index 493ad3bbd..67b4fdd4e 100644 --- a/config/milestone.txt +++ b/config/milestone.txt @@ -10,4 +10,4 @@ # hardcoded milestones in the tree from these two files. #-------------------------------------------------------- -4.3.0 +4.4.1
\ No newline at end of file diff --git a/db/sqlite3/src/sqlite3.c b/db/sqlite3/src/sqlite3.c index 4729f4572..61bfdeb76 100644 --- a/db/sqlite3/src/sqlite3.c +++ b/db/sqlite3/src/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.27.2. By combining all the individual C code files into this +** version 3.29.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -39,7 +39,7 @@ ** SQLite was built with. */ -#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */ /* ** Include the configuration header output by 'configure' if we're using the @@ -888,6 +888,11 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){ #pragma warning(disable : 4706) #endif /* defined(_MSC_VER) */ +#if defined(_MSC_VER) && !defined(_WIN64) +#undef SQLITE_4_BYTE_ALIGNED_MALLOC +#define SQLITE_4_BYTE_ALIGNED_MALLOC +#endif /* defined(_MSC_VER) && !defined(_WIN64) */ + #endif /* SQLITE_MSVC_H */ /************** End of msvc.h ************************************************/ @@ -1162,9 +1167,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.27.2" -#define SQLITE_VERSION_NUMBER 3027002 -#define SQLITE_SOURCE_ID "2019-02-25 16:06:06 bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0f6d7" +#define SQLITE_VERSION "3.29.0" +#define SQLITE_VERSION_NUMBER 3029000 +#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -1228,6 +1233,9 @@ SQLITE_API int sqlite3_libversion_number(void); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_API int sqlite3_compileoption_used(const char *zOptName); SQLITE_API const char *sqlite3_compileoption_get(int N); +#else +# define sqlite3_compileoption_used(X) 0 +# define sqlite3_compileoption_get(X) ((void*)0) #endif /* @@ -2332,8 +2340,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] -** to test whether a file is at least readable. The file can be a -** directory. +** to test whether a file is at least readable. The SQLITE_ACCESS_READ +** flag is never actually used and is not implemented in the built-in +** VFSes of SQLite. The file is named by the second argument and can be a +** directory. The xAccess method returns [SQLITE_OK] on success or some +** non-zero error code if there is an I/O error or if the name of +** the file given in the second argument is illegal. If SQLITE_OK +** is returned, then non-zero or zero is written into *pResOut to indicate +** whether or not the file is accessible. ** ** ^SQLite will always allocate at least mxPathname+1 bytes for the ** output buffer xFullPathname. The exact size of the output buffer @@ -3125,8 +3139,8 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] ** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt> -** <dd> ^This option is used to enable or disable the two-argument -** version of the [fts3_tokenizer()] function which is part of the +** <dd> ^This option is used to enable or disable the +** [fts3_tokenizer()] function which is part of the ** [FTS3] full-text search engine extension. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable fts3_tokenizer() or @@ -3234,10 +3248,50 @@ struct sqlite3_mem_methods { ** features include but are not limited to the following: ** <ul> ** <li> The [PRAGMA writable_schema=ON] statement. +** <li> The [PRAGMA journal_mode=OFF] statement. ** <li> Writes to the [sqlite_dbpage] virtual table. ** <li> Direct writes to [shadow tables]. ** </ul> ** </dd> +** +** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]] <dt>SQLITE_DBCONFIG_WRITABLE_SCHEMA</dt> +** <dd>The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the +** "writable_schema" flag. This has the same effect and is logically equivalent +** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF]. +** The first argument to this setting is an integer which is 0 to disable +** the writable_schema, positive to enable writable_schema, or negative to +** leave the setting unchanged. The second parameter is a pointer to an +** integer into which is written 0 or 1 to indicate whether the writable_schema +** is enabled or disabled following this call. +** </dd> +** +** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] +** <dt>SQLITE_DBCONFIG_LEGACY_ALTER_TABLE</dt> +** <dd>The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates +** the legacy behavior of the [ALTER TABLE RENAME] command such it +** behaves as it did prior to [version 3.24.0] (2018-06-04). See the +** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for +** additional information. This feature can also be turned on and off +** using the [PRAGMA legacy_alter_table] statement. +** </dd> +** +** [[SQLITE_DBCONFIG_DQS_DML]] +** <dt>SQLITE_DBCONFIG_DQS_DML</td> +** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DML statement +** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. +** </dd> +** +** [[SQLITE_DBCONFIG_DQS_DDL]] +** <dt>SQLITE_DBCONFIG_DQS_DDL</td> +** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DDL statements, +** such as CREATE TABLE and CREATE INDEX. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. +** </dd> ** </dl> */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -3251,7 +3305,11 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ #define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ #define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1010 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ +#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -4934,6 +4992,18 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); /* +** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement +** METHOD: sqlite3_stmt +** +** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the +** prepared statement S is an EXPLAIN statement, or 2 if the +** statement S is an EXPLAIN QUERY PLAN. +** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is +** an ordinary statement or a NULL pointer. +*/ +SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); + +/* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt ** @@ -5072,7 +5142,9 @@ typedef struct sqlite3_context sqlite3_context; ** ^The fifth argument to the BLOB and string binding interfaces ** is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor is called -** to dispose of the BLOB or string even if the call to bind API fails. +** to dispose of the BLOB or string even if the call to the bind API fails, +** except the destructor is not called if the third parameter is a NULL +** pointer or the fourth parameter is negative. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. @@ -5989,6 +6061,8 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** <tr><td><b>sqlite3_value_nochange </b> ** <td>→ <td>True if the column is unchanged in an UPDATE ** against a virtual table. +** <tr><td><b>sqlite3_value_frombind </b> +** <td>→ <td>True if value originated from a [bound parameter] ** </table></blockquote> ** ** <b>Details:</b> @@ -6050,6 +6124,11 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** than within an [xUpdate] method call for an UPDATE statement, then ** the return value is arbitrary and meaningless. ** +** ^The sqlite3_value_frombind(X) interface returns non-zero if the +** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] +** interfaces. ^If X comes from an SQL literal value, or a table column, +** and expression, then sqlite3_value_frombind(X) returns zero. +** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to @@ -6095,6 +6174,7 @@ SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); +SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values @@ -6830,7 +6910,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); ** associated with database N of connection D. ^The main database file ** has the name "main". If there is no attached database N on the database ** connection D, or if database N is a temporary or in-memory database, then -** a NULL pointer is returned. +** this function will return either a NULL pointer or an empty string. ** ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename @@ -8321,7 +8401,8 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_IMPOSTER 25 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26 -#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_RESULT_INTREAL 27 +#define SQLITE_TESTCTRL_LAST 27 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -11931,7 +12012,7 @@ SQLITE_API int sqlite3rebaser_configure( ** in size. This function allocates and populates a buffer with a copy ** of the changeset rebased rebased according to the configuration of the ** rebaser object passed as the first argument. If successful, (*ppOut) -** is set to point to the new buffer containing the rebased changset and +** is set to point to the new buffer containing the rebased changeset and ** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the ** responsibility of the caller to eventually free the new buffer using ** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut) @@ -12340,7 +12421,7 @@ struct Fts5PhraseIter { ** Save the pointer passed as the second argument as the extension functions ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of -** of the same MATCH query using the xGetAuxdata() API. +** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for ** each FTS query (MATCH expression). If the extension function is invoked @@ -12355,7 +12436,7 @@ struct Fts5PhraseIter { ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** -** If an error (e.g. an OOM condition) occurs within this function, an +** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. @@ -13381,7 +13462,7 @@ struct Hash { unsigned int count; /* Number of entries in this table */ HashElem *first; /* The first element of the array */ struct _ht { /* the hash table */ - int count; /* Number of entries with this hash */ + unsigned int count; /* Number of entries with this hash */ HashElem *chain; /* Pointer to first entry with this hash */ } *ht; }; @@ -13522,99 +13603,94 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); #define TK_PRECEDING 85 #define TK_RANGE 86 #define TK_UNBOUNDED 87 -#define TK_REINDEX 88 -#define TK_RENAME 89 -#define TK_CTIME_KW 90 -#define TK_ANY 91 -#define TK_BITAND 92 -#define TK_BITOR 93 -#define TK_LSHIFT 94 -#define TK_RSHIFT 95 -#define TK_PLUS 96 -#define TK_MINUS 97 -#define TK_STAR 98 -#define TK_SLASH 99 -#define TK_REM 100 -#define TK_CONCAT 101 -#define TK_COLLATE 102 -#define TK_BITNOT 103 -#define TK_ON 104 -#define TK_INDEXED 105 -#define TK_STRING 106 -#define TK_JOIN_KW 107 -#define TK_CONSTRAINT 108 -#define TK_DEFAULT 109 -#define TK_NULL 110 -#define TK_PRIMARY 111 -#define TK_UNIQUE 112 -#define TK_CHECK 113 -#define TK_REFERENCES 114 -#define TK_AUTOINCR 115 -#define TK_INSERT 116 -#define TK_DELETE 117 -#define TK_UPDATE 118 -#define TK_SET 119 -#define TK_DEFERRABLE 120 -#define TK_FOREIGN 121 -#define TK_DROP 122 -#define TK_UNION 123 -#define TK_ALL 124 -#define TK_EXCEPT 125 -#define TK_INTERSECT 126 -#define TK_SELECT 127 -#define TK_VALUES 128 -#define TK_DISTINCT 129 -#define TK_DOT 130 -#define TK_FROM 131 -#define TK_JOIN 132 -#define TK_USING 133 -#define TK_ORDER 134 -#define TK_GROUP 135 -#define TK_HAVING 136 -#define TK_LIMIT 137 -#define TK_WHERE 138 -#define TK_INTO 139 -#define TK_NOTHING 140 -#define TK_FLOAT 141 -#define TK_BLOB 142 -#define TK_INTEGER 143 -#define TK_VARIABLE 144 -#define TK_CASE 145 -#define TK_WHEN 146 -#define TK_THEN 147 -#define TK_ELSE 148 -#define TK_INDEX 149 -#define TK_ALTER 150 -#define TK_ADD 151 -#define TK_WINDOW 152 -#define TK_OVER 153 -#define TK_FILTER 154 -#define TK_TRUEFALSE 155 -#define TK_ISNOT 156 -#define TK_FUNCTION 157 -#define TK_COLUMN 158 -#define TK_AGG_FUNCTION 159 -#define TK_AGG_COLUMN 160 -#define TK_UMINUS 161 -#define TK_UPLUS 162 -#define TK_TRUTH 163 -#define TK_REGISTER 164 -#define TK_VECTOR 165 -#define TK_SELECT_COLUMN 166 -#define TK_IF_NULL_ROW 167 -#define TK_ASTERISK 168 -#define TK_SPAN 169 -#define TK_END_OF_FILE 170 -#define TK_UNCLOSED_STRING 171 -#define TK_SPACE 172 -#define TK_ILLEGAL 173 - -/* The token codes above must all fit in 8 bits */ -#define TKFLG_MASK 0xff - -/* Flags that can be added to a token code when it is not -** being stored in a u8: */ -#define TKFLG_DONTFOLD 0x100 /* Omit constant folding optimizations */ +#define TK_EXCLUDE 88 +#define TK_GROUPS 89 +#define TK_OTHERS 90 +#define TK_TIES 91 +#define TK_REINDEX 92 +#define TK_RENAME 93 +#define TK_CTIME_KW 94 +#define TK_ANY 95 +#define TK_BITAND 96 +#define TK_BITOR 97 +#define TK_LSHIFT 98 +#define TK_RSHIFT 99 +#define TK_PLUS 100 +#define TK_MINUS 101 +#define TK_STAR 102 +#define TK_SLASH 103 +#define TK_REM 104 +#define TK_CONCAT 105 +#define TK_COLLATE 106 +#define TK_BITNOT 107 +#define TK_ON 108 +#define TK_INDEXED 109 +#define TK_STRING 110 +#define TK_JOIN_KW 111 +#define TK_CONSTRAINT 112 +#define TK_DEFAULT 113 +#define TK_NULL 114 +#define TK_PRIMARY 115 +#define TK_UNIQUE 116 +#define TK_CHECK 117 +#define TK_REFERENCES 118 +#define TK_AUTOINCR 119 +#define TK_INSERT 120 +#define TK_DELETE 121 +#define TK_UPDATE 122 +#define TK_SET 123 +#define TK_DEFERRABLE 124 +#define TK_FOREIGN 125 +#define TK_DROP 126 +#define TK_UNION 127 +#define TK_ALL 128 +#define TK_EXCEPT 129 +#define TK_INTERSECT 130 +#define TK_SELECT 131 +#define TK_VALUES 132 +#define TK_DISTINCT 133 +#define TK_DOT 134 +#define TK_FROM 135 +#define TK_JOIN 136 +#define TK_USING 137 +#define TK_ORDER 138 +#define TK_GROUP 139 +#define TK_HAVING 140 +#define TK_LIMIT 141 +#define TK_WHERE 142 +#define TK_INTO 143 +#define TK_NOTHING 144 +#define TK_FLOAT 145 +#define TK_BLOB 146 +#define TK_INTEGER 147 +#define TK_VARIABLE 148 +#define TK_CASE 149 +#define TK_WHEN 150 +#define TK_THEN 151 +#define TK_ELSE 152 +#define TK_INDEX 153 +#define TK_ALTER 154 +#define TK_ADD 155 +#define TK_WINDOW 156 +#define TK_OVER 157 +#define TK_FILTER 158 +#define TK_TRUEFALSE 159 +#define TK_ISNOT 160 +#define TK_FUNCTION 161 +#define TK_COLUMN 162 +#define TK_AGG_FUNCTION 163 +#define TK_AGG_COLUMN 164 +#define TK_UMINUS 165 +#define TK_UPLUS 166 +#define TK_TRUTH 167 +#define TK_REGISTER 168 +#define TK_VECTOR 169 +#define TK_SELECT_COLUMN 170 +#define TK_IF_NULL_ROW 171 +#define TK_ASTERISK 172 +#define TK_SPAN 173 +#define TK_SPACE 174 +#define TK_ILLEGAL 175 /************** End of parse.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ @@ -13920,12 +13996,13 @@ typedef INT16_TYPE LogEst; ** at run-time. */ #ifndef SQLITE_BYTEORDER -# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ - defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ - defined(__arm__) || defined(_M_ARM64) +# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ + defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64) # define SQLITE_BYTEORDER 1234 -# elif defined(sparc) || defined(__ppc__) +# elif defined(sparc) || defined(__ppc__) || \ + defined(__ARMEB__) || defined(__AARCH64EB__) # define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 @@ -14546,9 +14623,6 @@ struct BtreePayload { SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload, int flags, int seekResult); SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); -#ifndef SQLITE_OMIT_WINDOWFUNC -SQLITE_PRIVATE void sqlite3BtreeSkipNext(BtCursor*); -#endif SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags); SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); @@ -14906,25 +14980,25 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Offset 89 /* synopsis: r[P3] = sqlite_offset(P1) */ #define OP_Column 90 /* synopsis: r[P3]=PX */ #define OP_Affinity 91 /* synopsis: affinity(r[P1@P2]) */ -#define OP_BitAnd 92 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ -#define OP_BitOr 93 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ -#define OP_ShiftLeft 94 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */ -#define OP_ShiftRight 95 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */ -#define OP_Add 96 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ -#define OP_Subtract 97 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ -#define OP_Multiply 98 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ -#define OP_Divide 99 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ -#define OP_Remainder 100 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ -#define OP_Concat 101 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ -#define OP_MakeRecord 102 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_BitNot 103 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ -#define OP_Count 104 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 105 -#define OP_String8 106 /* same as TK_STRING, synopsis: r[P2]='P4' */ -#define OP_SetCookie 107 -#define OP_ReopenIdx 108 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenRead 109 /* synopsis: root=P2 iDb=P3 */ -#define OP_OpenWrite 110 /* synopsis: root=P2 iDb=P3 */ +#define OP_MakeRecord 92 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 93 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 94 +#define OP_SetCookie 95 +#define OP_BitAnd 96 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ +#define OP_BitOr 97 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ +#define OP_ShiftLeft 98 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */ +#define OP_ShiftRight 99 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */ +#define OP_Add 100 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */ +#define OP_Subtract 101 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */ +#define OP_Multiply 102 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */ +#define OP_Divide 103 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */ +#define OP_Remainder 104 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */ +#define OP_Concat 105 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */ +#define OP_ReopenIdx 106 /* synopsis: root=P2 iDb=P3 */ +#define OP_BitNot 107 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */ +#define OP_OpenRead 108 /* synopsis: root=P2 iDb=P3 */ +#define OP_OpenWrite 109 /* synopsis: root=P2 iDb=P3 */ +#define OP_String8 110 /* same as TK_STRING, synopsis: r[P2]='P4' */ #define OP_OpenDup 111 #define OP_OpenAutoindex 112 /* synopsis: nColumn=P2 */ #define OP_OpenEphemeral 113 /* synopsis: nColumn=P2 */ @@ -14955,11 +15029,11 @@ typedef struct VdbeOpList VdbeOpList; #define OP_ResetSorter 138 #define OP_CreateBtree 139 /* synopsis: r[P2]=root iDb=P1 flags=P3 */ #define OP_SqlExec 140 -#define OP_Real 141 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ -#define OP_ParseSchema 142 -#define OP_LoadAnalysis 143 -#define OP_DropTable 144 -#define OP_DropIndex 145 +#define OP_ParseSchema 141 +#define OP_LoadAnalysis 142 +#define OP_DropTable 143 +#define OP_DropIndex 144 +#define OP_Real 145 /* same as TK_FLOAT, synopsis: r[P2]=P4 */ #define OP_DropTrigger 146 #define OP_IntegrityCk 147 #define OP_RowSetAdd 148 /* synopsis: rowset(P1)=r[P2] */ @@ -15010,14 +15084,14 @@ typedef struct VdbeOpList VdbeOpList; /* 64 */ 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10,\ /* 72 */ 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,\ /* 80 */ 0x10, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\ -/* 88 */ 0x12, 0x20, 0x00, 0x00, 0x26, 0x26, 0x26, 0x26,\ -/* 96 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00, 0x12,\ -/* 104 */ 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 88 */ 0x12, 0x20, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,\ +/* 96 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ +/* 104 */ 0x26, 0x26, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00,\ /* 112 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 120 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 128 */ 0x10, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10,\ -/* 136 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00,\ -/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\ +/* 136 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ +/* 144 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\ /* 152 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\ /* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00,} @@ -16325,6 +16399,7 @@ struct sqlite3 { void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); + Parse *pParse; /* Current parse */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void *pPreUpdateArg; /* First argument to xPreUpdateCallback */ void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */ @@ -16440,6 +16515,8 @@ struct sqlite3 { #define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */ #define SQLITE_NoSchemaError 0x08000000 /* Do not report schema parse errors*/ #define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */ +#define SQLITE_DqsDDL 0x20000000 /* dbl-quoted strings allowed in DDL*/ +#define SQLITE_DqsDML 0x40000000 /* dbl-quoted strings allowed in DML*/ /* Flags used only if debugging */ #define HI(X) ((u64)(X)<<32) @@ -16458,7 +16535,8 @@ struct sqlite3 { #define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */ #define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */ #define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */ -#define DBFLAG_SchemaKnownOk 0x0008 /* Schema is known to be valid */ +#define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */ +#define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */ /* ** Bits of the sqlite3.dbOptFlags field that are used by the @@ -16466,7 +16544,7 @@ struct sqlite3 { ** selectively disable various optimizations. */ #define SQLITE_QueryFlattener 0x0001 /* Query flattening */ - /* 0x0002 available for reuse */ +#define SQLITE_WindowFunc 0x0002 /* Use xInverse for window functions */ #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ #define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */ @@ -16584,7 +16662,6 @@ struct FuncDestructor { #define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */ #define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */ #define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */ -#define SQLITE_FUNC_WINDOW_SIZE 0x20000 /* Requires partition size as arg. */ #define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */ /* @@ -17146,6 +17223,7 @@ struct Index { unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */ + unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int nSample; /* Number of elements in aSample[] */ int nSampleCol; /* Size of IndexSample.anEq[] and so on */ @@ -17373,7 +17451,7 @@ struct Expr { ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ - u8 op2; /* TK_REGISTER: original value of Expr.op + u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ @@ -17390,12 +17468,16 @@ struct Expr { /* ** The following are the meanings of bits in the Expr.flags field. +** Value restrictions: +** +** EP_Agg == NC_HasAgg == SF_HasAgg +** EP_Win == NC_HasWin */ #define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ -#define EP_Agg 0x000002 /* Contains one or more aggregate functions */ +#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */ #define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */ #define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */ -#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */ +#define EP_Agg 0x000010 /* Contains one or more aggregate functions */ #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ @@ -17403,10 +17485,10 @@ struct Expr { #define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ #define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ -#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */ +#define EP_Skip 0x001000 /* Operator does not contribute to affinity */ #define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ -#define EP_Static 0x008000 /* Held in memory not obtained from malloc() */ +#define EP_Win 0x008000 /* Contains window functions */ #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ #define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ @@ -17418,6 +17500,9 @@ struct Expr { #define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */ #define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */ #define EP_Quoted 0x4000000 /* TK_ID was originally quoted */ +#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */ +#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */ +#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */ /* ** The EP_Propagate mask is a set of properties that automatically propagate @@ -17433,6 +17518,8 @@ struct Expr { #define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) #define ExprSetProperty(E,P) (E)->flags|=(P) #define ExprClearProperty(E,P) (E)->flags&=~(P) +#define ExprAlwaysTrue(E) (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue) +#define ExprAlwaysFalse(E) (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse) /* The ExprSetVVAProperty() macro is used for Verification, Validation, ** and Accreditation only. It works like ExprSetProperty() during VVA @@ -17649,7 +17736,7 @@ struct NameContext { NameContext *pNext; /* Next outer name context. NULL for outermost */ int nRef; /* Number of names resolved by this context */ int nErr; /* Number of errors encountered while resolving names */ - u16 ncFlags; /* Zero or more NC_* flags defined below */ + int ncFlags; /* Zero or more NC_* flags defined below */ Select *pWinSelect; /* SELECT statement for any window functions */ }; @@ -17657,8 +17744,9 @@ struct NameContext { ** Allowed values for the NameContext, ncFlags field. ** ** Value constraints (all checked via assert()): -** NC_HasAgg == SF_HasAgg +** NC_HasAgg == SF_HasAgg == EP_Agg ** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX +** NC_HasWin == EP_Win ** */ #define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ @@ -17674,6 +17762,8 @@ struct NameContext { #define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ #define NC_Complex 0x2000 /* True if a function or subquery seen */ #define NC_AllowWin 0x4000 /* Window functions are allowed here */ +#define NC_HasWin 0x8000 /* One or more window functions seen */ +#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */ /* ** An instance of the following object describes a single ON CONFLICT @@ -17988,6 +18078,7 @@ struct Parse { AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ + Parse *pParentParse; /* Parent parser if this parser is nested */ int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */ u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */ u32 oldmask; /* Mask of old.* columns referenced */ @@ -18428,7 +18519,7 @@ struct TreeView { #endif /* SQLITE_DEBUG */ /* -** This object is used in varioius ways, all related to window functions +** This object is used in various ways, all related to window functions ** ** (1) A single instance of this structure is attached to the ** the Expr.pWin field for each window function in an expression tree. @@ -18443,15 +18534,18 @@ struct TreeView { ** object on a linked list attached to Select.pWinDefn. ** ** The uses (1) and (2) are really the same Window object that just happens -** to be accessible in two different ways. Use (3) is are separate objects. +** to be accessible in two different ways. Use case (3) are separate objects. */ struct Window { char *zName; /* Name of window (may be NULL) */ + char *zBase; /* Name of base window for chaining (may be NULL) */ ExprList *pPartition; /* PARTITION BY clause */ ExprList *pOrderBy; /* ORDER BY clause */ - u8 eType; /* TK_RANGE or TK_ROWS */ + u8 eFrmType; /* TK_RANGE, TK_GROUPS, TK_ROWS, or 0 */ u8 eStart; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ u8 eEnd; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */ + u8 bImplicitFrame; /* True if frame was implicitly specified */ + u8 eExclude; /* TK_NO, TK_CURRENT, TK_TIES, TK_GROUP, or 0 */ Expr *pStart; /* Expression for "<expr> PRECEDING" */ Expr *pEnd; /* Expression for "<expr> FOLLOWING" */ Window *pNextWin; /* Next window function belonging to this SELECT */ @@ -18462,17 +18556,19 @@ struct Window { int regResult; int csrApp; /* Function cursor (used by min/max) */ int regApp; /* Function register (also used by min/max) */ - int regPart; /* First in a set of registers holding PARTITION BY - ** and ORDER BY values for the window */ + int regPart; /* Array of registers for PARTITION BY values */ Expr *pOwner; /* Expression object this window is attached to */ int nBufferCol; /* Number of columns in buffer table */ int iArgCol; /* Offset of first argument for this function */ + int regOne; /* Register containing constant value 1 */ + int regStartRowid; + int regEndRowid; }; #ifndef SQLITE_OMIT_WINDOWFUNC SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*); SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p); -SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*); +SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*); SQLITE_PRIVATE int sqlite3WindowCompare(Parse*, Window*, Window*); SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Window*); @@ -18483,6 +18579,8 @@ SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*); SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p); SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p); SQLITE_PRIVATE void sqlite3WindowFunctions(void); +SQLITE_PRIVATE void sqlite3WindowChain(Parse*, Window*, Window*); +SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprList*, Token*); #else # define sqlite3WindowDelete(a,b) # define sqlite3WindowFunctions() @@ -18672,8 +18770,12 @@ SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*); #endif #ifndef SQLITE_OMIT_FLOATING_POINT +# define EXP754 (((u64)0x7ff)<<52) +# define MAN754 ((((u64)1)<<52)-1) +# define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0) SQLITE_PRIVATE int sqlite3IsNaN(double); #else +# define IsNaN(X) 0 # define sqlite3IsNaN(X) 0 #endif @@ -18712,6 +18814,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8); SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*); SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...); +SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3*,int); SQLITE_PRIVATE void sqlite3Dequote(char*); SQLITE_PRIVATE void sqlite3DequoteExpr(Expr*); SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*); @@ -18731,10 +18834,12 @@ SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*); SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); -SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); +SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*); +SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*); SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*); +SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int); @@ -19043,6 +19148,7 @@ SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*); SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); +SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64); SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3Atoi(const char*); @@ -19144,6 +19250,9 @@ SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*); SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*); +#ifndef SQLITE_UNTESTABLE +SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context*); +#endif SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *); #ifndef SQLITE_OMIT_UTF16 SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); @@ -19706,8 +19815,15 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = { ** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if ** that compile-time option is omitted. */ -#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN +#if !defined(SQLITE_ALLOW_COVERING_INDEX_SCAN) # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 +#else +# if !SQLITE_ALLOW_COVERING_INDEX_SCAN +# error "Compile-time disabling of covering index scan using the\ + -DSQLITE_ALLOW_COVERING_INDEX_SCAN=0 option is deprecated.\ + Contact SQLite developers if this is a problem for you, and\ + delete this #error macro to continue with your build." +# endif #endif /* The minimum PMA size is set to this value multiplied by the database @@ -20134,12 +20250,12 @@ struct sqlite3_value { #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ -#define MEM_AffMask 0x001f /* Mask of affinity bits */ -/* Available 0x0020 */ -/* Available 0x0040 */ +#define MEM_IntReal 0x0020 /* MEM_Int that stringifies like MEM_Real */ +#define MEM_AffMask 0x003f /* Mask of affinity bits */ +#define MEM_FromBind 0x0040 /* Value originates from sqlite3_bind() */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ -#define MEM_TypeMask 0xc1ff /* Mask of type bits */ +#define MEM_TypeMask 0xc1bf /* Mask of type bits */ /* Whenever Mem contains a valid string or blob representation, one of @@ -20172,6 +20288,12 @@ struct sqlite3_value { ((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f) /* +** True if Mem X is a NULL-nochng type. +*/ +#define MemNullNochng(X) \ + ((X)->flags==(MEM_Null|MEM_Zero) && (X)->n==0 && (X)->u.nZero==0) + +/* ** Return true if a memory cell is not marked as invalid. This macro ** is for use inside assert() statements only. */ @@ -21253,7 +21375,7 @@ static int parseDateOrTime( return 0; }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); - }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){ + }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){ setRawDateNumber(p, r); return 0; } @@ -21587,7 +21709,7 @@ static int parseModifier( ** date is already on the appropriate weekday, this is a no-op. */ if( sqlite3_strnicmp(z, "weekday ", 8)==0 - && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8) + && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0 && (n=(int)r)==r && n>=0 && r<7 ){ sqlite3_int64 Z; computeYMD_HMS(p); @@ -21646,7 +21768,7 @@ static int parseModifier( double rRounder; int i; for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} - if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){ + if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){ rc = 1; break; } @@ -27120,6 +27242,9 @@ SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){ db->u1.isInterrupted = 1; } db->lookaside.bDisable++; + if( db->pParse ){ + db->pParse->rc = SQLITE_NOMEM_BKPT; + } } } @@ -27276,6 +27401,12 @@ static const et_info fmtinfo[] = { { 'r', 10, 1, etORDINAL, 0, 0 }, }; +/* Floating point constants used for rounding */ +static const double arRound[] = { + 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05, + 5.0e-06, 5.0e-07, 5.0e-08, 5.0e-09, 5.0e-10, +}; + /* ** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point ** conversions will work. @@ -27313,7 +27444,8 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ static void setStrAccumError(StrAccum *p, u8 eError){ assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); p->accError = eError; - p->nAlloc = 0; + if( p->mxAlloc ) sqlite3_str_reset(p); + if( eError==SQLITE_TOOBIG ) sqlite3ErrorToParser(p->db, eError); } /* @@ -27343,6 +27475,7 @@ static char *getTextArg(PrintfArguments *p){ */ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){ char *z; + if( pAccum->accError ) return 0; if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){ setStrAccumError(pAccum, SQLITE_TOOBIG); return 0; @@ -27692,8 +27825,18 @@ SQLITE_API void sqlite3_str_vappendf( } if( xtype==etGENERIC && precision>0 ) precision--; testcase( precision>0xfff ); - for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){} - if( xtype==etFLOAT ) realvalue += rounder; + idx = precision & 0xfff; + rounder = arRound[idx%10]; + while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; } + if( xtype==etFLOAT ){ + double rx = (double)realvalue; + sqlite3_uint64 u; + int ex; + memcpy(&u, &rx, sizeof(u)); + ex = -1023 + (int)((u>>52)&0x7ff); + if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16; + realvalue += rounder; + } /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; if( sqlite3IsNaN((double)realvalue) ){ @@ -28062,9 +28205,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ return 0; } if( p->mxAlloc==0 ){ - N = p->nAlloc - p->nChar - 1; setStrAccumError(p, SQLITE_TOOBIG); - return N; + return p->nAlloc - p->nChar - 1; }else{ char *zOld = isMalloced(p) ? p->zText : 0; i64 szNew = p->nChar; @@ -28136,7 +28278,7 @@ SQLITE_API void sqlite3_str_append(sqlite3_str *p, const char *z, int N){ assert( z!=0 || N==0 ); assert( p->zText!=0 || p->nChar==0 || p->accError ); assert( N>=0 ); - assert( p->accError==0 || p->nAlloc==0 ); + assert( p->accError==0 || p->nAlloc==0 || p->mxAlloc==0 ); if( p->nChar+N >= p->nAlloc ){ enlargeAndAppend(p,z,N); }else if( N ){ @@ -28769,24 +28911,62 @@ SQLITE_PRIVATE void sqlite3TreeViewBound( ** Generate a human-readable explanation for a Window object */ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){ + int nElement = 0; + if( pWin->pFilter ){ + sqlite3TreeViewItem(pView, "FILTER", 1); + sqlite3TreeViewExpr(pView, pWin->pFilter, 0); + sqlite3TreeViewPop(pView); + } pView = sqlite3TreeViewPush(pView, more); if( pWin->zName ){ - sqlite3TreeViewLine(pView, "OVER %s", pWin->zName); + sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin); }else{ - sqlite3TreeViewLine(pView, "OVER"); + sqlite3TreeViewLine(pView, "OVER (%p)", pWin); + } + if( pWin->zBase ) nElement++; + if( pWin->pOrderBy ) nElement++; + if( pWin->eFrmType ) nElement++; + if( pWin->eExclude ) nElement++; + if( pWin->zBase ){ + sqlite3TreeViewPush(pView, (--nElement)>0); + sqlite3TreeViewLine(pView, "window: %s", pWin->zBase); + sqlite3TreeViewPop(pView); } if( pWin->pPartition ){ - sqlite3TreeViewExprList(pView, pWin->pPartition, 1, "PARTITION-BY"); + sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY"); } if( pWin->pOrderBy ){ - sqlite3TreeViewExprList(pView, pWin->pOrderBy, 1, "ORDER-BY"); - } - if( pWin->eType ){ - sqlite3TreeViewItem(pView, pWin->eType==TK_RANGE ? "RANGE" : "ROWS", 0); + sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY"); + } + if( pWin->eFrmType ){ + char zBuf[30]; + const char *zFrmType = "ROWS"; + if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE"; + if( pWin->eFrmType==TK_GROUPS ) zFrmType = "GROUPS"; + sqlite3_snprintf(sizeof(zBuf),zBuf,"%s%s",zFrmType, + pWin->bImplicitFrame ? " (implied)" : ""); + sqlite3TreeViewItem(pView, zBuf, (--nElement)>0); sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1); sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0); sqlite3TreeViewPop(pView); } + if( pWin->eExclude ){ + char zBuf[30]; + const char *zExclude; + switch( pWin->eExclude ){ + case TK_NO: zExclude = "NO OTHERS"; break; + case TK_CURRENT: zExclude = "CURRENT ROW"; break; + case TK_GROUP: zExclude = "GROUP"; break; + case TK_TIES: zExclude = "TIES"; break; + default: + sqlite3_snprintf(sizeof(zBuf),zBuf,"invalid(%d)", pWin->eExclude); + zExclude = zBuf; + break; + } + sqlite3TreeViewPush(pView, 0); + sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude); + sqlite3TreeViewPop(pView); + } sqlite3TreeViewPop(pView); } #endif /* SQLITE_OMIT_WINDOWFUNC */ @@ -28936,7 +29116,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m }; assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT ); assert( pExpr->pRight ); - assert( pExpr->pRight->op==TK_TRUEFALSE ); + assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE ); x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); zUniOp = azOp[x]; break; @@ -29766,11 +29946,11 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read( ** encoding, or if *pMem does not contain a string value. */ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){ - int len; /* Maximum length of output string in bytes */ - unsigned char *zOut; /* Output buffer */ - unsigned char *zIn; /* Input iterator */ - unsigned char *zTerm; /* End of input */ - unsigned char *z; /* Output iterator */ + sqlite3_int64 len; /* Maximum length of output string in bytes */ + unsigned char *zOut; /* Output buffer */ + unsigned char *zIn; /* Input iterator */ + unsigned char *zTerm; /* End of input */ + unsigned char *z; /* Output iterator */ unsigned int c; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); @@ -29819,14 +29999,14 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired ** nul-terminator. */ pMem->n &= ~1; - len = pMem->n * 2 + 1; + len = 2 * (sqlite3_int64)pMem->n + 1; }else{ /* When converting from UTF-8 to UTF-16 the maximum growth is caused ** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16 ** character. Two bytes are required in the output buffer for the ** nul-terminator. */ - len = pMem->n * 2 + 2; + len = 2 * (sqlite3_int64)pMem->n + 2; } /* Set zIn to point at the start of the input buffer and zTerm to point 1 @@ -30118,9 +30298,7 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){ */ /* #include "sqliteInt.h" */ /* #include <stdarg.h> */ -#if HAVE_ISNAN || SQLITE_HAVE_ISNAN -# include <math.h> -#endif +#include <math.h> /* ** Routine needed to support the testcase() macro. @@ -30133,15 +30311,23 @@ SQLITE_PRIVATE void sqlite3Coverage(int x){ #endif /* -** Give a callback to the test harness that can be used to simulate faults -** in places where it is difficult or expensive to do so purely by means -** of inputs. +** Calls to sqlite3FaultSim() are used to simulate a failure during testing, +** or to bypass normal error detection during testing in order to let +** execute proceed futher downstream. +** +** In deployment, sqlite3FaultSim() *always* return SQLITE_OK (0). The +** sqlite3FaultSim() function only returns non-zero during testing. ** -** The intent of the integer argument is to let the fault simulator know -** which of multiple sqlite3FaultSim() calls has been hit. +** During testing, if the test harness has set a fault-sim callback using +** a call to sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL), then +** each call to sqlite3FaultSim() is relayed to that application-supplied +** callback and the integer return value form the application-supplied +** callback is returned by sqlite3FaultSim(). ** -** Return whatever integer value the test callback returns, or return -** SQLITE_OK if no test callback is installed. +** The integer argument to sqlite3FaultSim() is a code to identify which +** sqlite3FaultSim() instance is being invoked. Each call to sqlite3FaultSim() +** should have a unique code. To prevent legacy testing applications from +** breaking, the codes should not be changed or reused. */ #ifndef SQLITE_UNTESTABLE SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ @@ -30153,47 +30339,11 @@ SQLITE_PRIVATE int sqlite3FaultSim(int iTest){ #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Return true if the floating point value is Not a Number (NaN). -** -** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN. -** Otherwise, we have our own implementation that works on most systems. */ SQLITE_PRIVATE int sqlite3IsNaN(double x){ - int rc; /* The value return */ -#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN - /* - ** Systems that support the isnan() library function should probably - ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have - ** found that many systems do not have a working isnan() function so - ** this implementation is provided as an alternative. - ** - ** This NaN test sometimes fails if compiled on GCC with -ffast-math. - ** On the other hand, the use of -ffast-math comes with the following - ** warning: - ** - ** This option [-ffast-math] should never be turned on by any - ** -O option since it can result in incorrect output for programs - ** which depend on an exact implementation of IEEE or ISO - ** rules/specifications for math functions. - ** - ** Under MSVC, this NaN test may fail if compiled with a floating- - ** point precision mode other than /fp:precise. From the MSDN - ** documentation: - ** - ** The compiler [with /fp:precise] will properly handle comparisons - ** involving NaN. For example, x != x evaluates to true if x is NaN - ** ... - */ -#ifdef __FAST_MATH__ -# error SQLite will not work correctly with the -ffast-math option of GCC. -#endif - volatile double y = x; - volatile double z = y; - rc = (y!=z); -#else /* if HAVE_ISNAN */ - rc = isnan(x); -#endif /* HAVE_ISNAN */ - testcase( rc ); - return rc; + u64 y; + memcpy(&y,&x,sizeof(y)); + return IsNaN(y); } #endif /* SQLITE_OMIT_FLOATING_POINT */ @@ -30327,6 +30477,19 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ } /* +** If database connection db is currently parsing SQL, then transfer +** error code errCode to that parser if the parser has not already +** encountered some other kind of error. +*/ +SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3 *db, int errCode){ + Parse *pParse; + if( db==0 || (pParse = db->pParse)==0 ) return errCode; + pParse->rc = errCode; + pParse->nErr++; + return errCode; +} + +/* ** Convert an SQL-style quoted string into a normal string by removing ** the quote characters. The conversion is done in-place. If the ** input does not begin with a quote character, then this routine @@ -30402,12 +30565,18 @@ SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){ } SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){ unsigned char *a, *b; - int c; + int c, x; a = (unsigned char *)zLeft; b = (unsigned char *)zRight; for(;;){ - c = (int)UpperToLower[*a] - (int)UpperToLower[*b]; - if( c || *a==0 ) break; + c = *a; + x = *b; + if( c==x ){ + if( c==0 ) break; + }else{ + c = (int)UpperToLower[c] - (int)UpperToLower[x]; + if( c ) break; + } a++; b++; } @@ -30435,15 +30604,15 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ static LONGDOUBLE_TYPE sqlite3Pow10(int E){ #if defined(_MSC_VER) static const LONGDOUBLE_TYPE x[] = { - 1.0e+001, - 1.0e+002, - 1.0e+004, - 1.0e+008, - 1.0e+016, - 1.0e+032, - 1.0e+064, - 1.0e+128, - 1.0e+256 + 1.0e+001L, + 1.0e+002L, + 1.0e+004L, + 1.0e+008L, + 1.0e+016L, + 1.0e+032L, + 1.0e+064L, + 1.0e+128L, + 1.0e+256L }; LONGDOUBLE_TYPE r = 1.0; int i; @@ -30473,8 +30642,15 @@ static LONGDOUBLE_TYPE sqlite3Pow10(int E){ ** uses the encoding enc. The string is not necessarily zero-terminated. ** ** Return TRUE if the result is a valid real number (or integer) and FALSE -** if the string is empty or contains extraneous text. Valid numbers -** are in one of these formats: +** if the string is empty or contains extraneous text. More specifically +** return +** 1 => The input string is a pure integer +** 2 or more => The input has a decimal point or eNNN clause +** 0 or less => The input string is not a valid number +** -1 => Not a valid number, but has a valid prefix which +** includes a decimal point and/or an eNNN clause +** +** Valid numbers are in one of these formats: ** ** [+-]digits[E[+-]digits] ** [+-]digits.[digits][E[+-]digits] @@ -30499,8 +30675,8 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en int e = 0; /* exponent */ int eValid = 1; /* True exponent is either not used or is well-formed */ double result; - int nDigits = 0; - int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ + int nDigit = 0; /* Number of digits processed */ + int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ @@ -30511,8 +30687,10 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en int i; incr = 2; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); + testcase( enc==SQLITE_UTF16LE ); + testcase( enc==SQLITE_UTF16BE ); for(i=3-enc; i<length && z[i]==0; i+=2){} - nonNum = i<length; + if( i<length ) eType = -100; zEnd = &z[i^1]; z += (enc&1); } @@ -30530,27 +30708,30 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en } /* copy max significant digits to significand */ - while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ + while( z<zEnd && sqlite3Isdigit(*z) ){ s = s*10 + (*z - '0'); - z+=incr; nDigits++; + z+=incr; nDigit++; + if( s>=((LARGEST_INT64-9)/10) ){ + /* skip non-significant significand digits + ** (increase exponent by d to shift decimal left) */ + while( z<zEnd && sqlite3Isdigit(*z) ){ z+=incr; d++; } + } } - - /* skip non-significant significand digits - ** (increase exponent by d to shift decimal left) */ - while( z<zEnd && sqlite3Isdigit(*z) ){ z+=incr; nDigits++; d++; } if( z>=zEnd ) goto do_atof_calc; /* if decimal point is present */ if( *z=='.' ){ z+=incr; + eType++; /* copy digits from after decimal to significand ** (decrease exponent by d to shift decimal right) */ while( z<zEnd && sqlite3Isdigit(*z) ){ if( s<((LARGEST_INT64-9)/10) ){ s = s*10 + (*z - '0'); d--; + nDigit++; } - z+=incr; nDigits++; + z+=incr; } } if( z>=zEnd ) goto do_atof_calc; @@ -30559,6 +30740,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en if( *z=='e' || *z=='E' ){ z+=incr; eValid = 0; + eType++; /* This branch is needed to avoid a (harmless) buffer overread. The ** special comment alerts the mutation tester that the correct answer @@ -30657,7 +30839,13 @@ do_atof_calc: *pResult = result; /* return true if number and no extra non-whitespace chracters after */ - return z==zEnd && nDigits>0 && eValid && nonNum==0; + if( z==zEnd && nDigit>0 && eValid && eType>0 ){ + return eType; + }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){ + return -1; + }else{ + return 0; + } #else return !sqlite3Atoi64(z, pResult, length, enc); #endif /* SQLITE_OMIT_FLOATING_POINT */ @@ -30700,6 +30888,7 @@ static int compare2pow63(const char *zNum, int incr){ ** ** Returns: ** +** -1 Not even a prefix of the input text looks like an integer ** 0 Successful transformation. Fits in a 64-bit signed integer. ** 1 Excess non-space text after the integer value ** 2 Integer too large for a 64-bit signed integer or is malformed @@ -30759,9 +30948,9 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc *pNum = (i64)u; } rc = 0; - if( (i==0 && zStart==zNum) /* No digits */ - || nonNum /* UTF16 with high-order bytes non-zero */ - ){ + if( i==0 && zStart==zNum ){ /* No digits */ + rc = -1; + }else if( nonNum ){ /* UTF16 with high-order bytes non-zero */ rc = 1; }else if( &zNum[i]<zEnd ){ /* Extra bytes at the end */ int jj = i; @@ -30992,23 +31181,12 @@ SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ u32 a,b,s; - a = *p; - /* a: p0 (unmasked) */ - if (!(a&0x80)) - { - *v = a; + if( ((signed char*)p)[0]>=0 ){ + *v = *p; return 1; } - - p++; - b = *p; - /* b: p1 (unmasked) */ - if (!(b&0x80)) - { - a &= 0x7f; - a = a<<7; - a |= b; - *v = a; + if( ((signed char*)p)[1]>=0 ){ + *v = ((u32)(p[0]&0x7f)<<7) | p[1]; return 2; } @@ -31016,8 +31194,9 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){ assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); - p++; - a = a<<14; + a = ((u32)p[0])<<14; + b = p[1]; + p += 2; a |= *p; /* a: p0<<14 | p2 (unmasked) */ if (!(a&0x80)) @@ -31677,7 +31856,7 @@ SQLITE_PRIVATE VList *sqlite3VListAdd( assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */ if( pIn==0 || pIn[1]+nInt > pIn[0] ){ /* Enlarge the allocation */ - int nAlloc = (pIn ? pIn[0]*2 : 10) + nInt; + sqlite3_int64 nAlloc = (pIn ? 2*(sqlite3_int64)pIn[0] : 10) + nInt; VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int)); if( pOut==0 ) return pIn; if( pIn==0 ) pOut[1] = 2; @@ -31883,7 +32062,7 @@ static HashElem *findElementWithHash( unsigned int *pHash /* Write the hash value here */ ){ HashElem *elem; /* Used to loop thru the element list */ - int count; /* Number of elements left to test */ + unsigned int count; /* Number of elements left to test */ unsigned int h; /* The computed hash */ static HashElem nullElement = { 0, 0, 0, 0 }; @@ -31931,8 +32110,8 @@ static void removeElementGivenHash( if( pEntry->chain==elem ){ pEntry->chain = elem->next; } + assert( pEntry->count>0 ); pEntry->count--; - assert( pEntry->count>=0 ); } sqlite3_free( elem ); pH->count--; @@ -32107,25 +32286,25 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 89 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), /* 90 */ "Column" OpHelp("r[P3]=PX"), /* 91 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 92 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), - /* 93 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), - /* 94 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"), - /* 95 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"), - /* 96 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), - /* 97 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), - /* 98 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), - /* 99 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), - /* 100 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), - /* 101 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), - /* 102 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 103 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), - /* 104 */ "Count" OpHelp("r[P2]=count()"), - /* 105 */ "ReadCookie" OpHelp(""), - /* 106 */ "String8" OpHelp("r[P2]='P4'"), - /* 107 */ "SetCookie" OpHelp(""), - /* 108 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), - /* 109 */ "OpenRead" OpHelp("root=P2 iDb=P3"), - /* 110 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 92 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 93 */ "Count" OpHelp("r[P2]=count()"), + /* 94 */ "ReadCookie" OpHelp(""), + /* 95 */ "SetCookie" OpHelp(""), + /* 96 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), + /* 97 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), + /* 98 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"), + /* 99 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"), + /* 100 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"), + /* 101 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"), + /* 102 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"), + /* 103 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"), + /* 104 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"), + /* 105 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"), + /* 106 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 107 */ "BitNot" OpHelp("r[P2]= ~r[P1]"), + /* 108 */ "OpenRead" OpHelp("root=P2 iDb=P3"), + /* 109 */ "OpenWrite" OpHelp("root=P2 iDb=P3"), + /* 110 */ "String8" OpHelp("r[P2]='P4'"), /* 111 */ "OpenDup" OpHelp(""), /* 112 */ "OpenAutoindex" OpHelp("nColumn=P2"), /* 113 */ "OpenEphemeral" OpHelp("nColumn=P2"), @@ -32156,11 +32335,11 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 138 */ "ResetSorter" OpHelp(""), /* 139 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"), /* 140 */ "SqlExec" OpHelp(""), - /* 141 */ "Real" OpHelp("r[P2]=P4"), - /* 142 */ "ParseSchema" OpHelp(""), - /* 143 */ "LoadAnalysis" OpHelp(""), - /* 144 */ "DropTable" OpHelp(""), - /* 145 */ "DropIndex" OpHelp(""), + /* 141 */ "ParseSchema" OpHelp(""), + /* 142 */ "LoadAnalysis" OpHelp(""), + /* 143 */ "DropTable" OpHelp(""), + /* 144 */ "DropIndex" OpHelp(""), + /* 145 */ "Real" OpHelp("r[P2]=P4"), /* 146 */ "DropTrigger" OpHelp(""), /* 147 */ "IntegrityCk" OpHelp(""), /* 148 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), @@ -47887,9 +48066,10 @@ static int numberOfCachePages(PCache *p){ ** suggested cache size is set to N. */ return p->szCache; }else{ - /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then - ** the number of cache pages is adjusted to use approximately abs(N*1024) - ** bytes of memory. */ + /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the + ** number of cache pages is adjusted to be a number of pages that would + ** use approximately abs(N*1024) bytes of memory based on the current + ** page size. */ return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); } } @@ -49016,9 +49196,7 @@ static void pcache1FreePage(PgHdr1 *p){ ** exists, this function falls back to sqlite3Malloc(). */ SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){ - /* During rebalance operations on a corrupt database file, it is sometimes - ** (rarely) possible to overread the temporary page buffer by a few bytes. - ** Enlarge the allocation slightly so that this does not cause problems. */ + assert( sz<=65536+8 ); /* These allocations are never very large */ return pcache1Alloc(sz); } @@ -49307,6 +49485,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ }else{ pGroup = &pcache1.grp; } + pcache1EnterMutex(pGroup); if( pGroup->lru.isAnchor==0 ){ pGroup->lru.isAnchor = 1; pGroup->lru.pLruPrev = pGroup->lru.pLruNext = &pGroup->lru; @@ -49316,7 +49495,6 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){ pCache->szExtra = szExtra; pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1)); pCache->bPurgeable = (bPurgeable ? 1 : 0); - pcache1EnterMutex(pGroup); pcache1ResizeHash(pCache); if( bPurgeable ){ pCache->nMin = 10; @@ -51302,6 +51480,9 @@ static const unsigned char aJournalMagic[] = { SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ if( pPager->fd->pMethods==0 ) return 0; if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; +#ifdef SQLITE_HAS_CODEC + if( pPager->xCodec!=0 ) return 0; +#endif #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; @@ -54251,8 +54432,14 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR rc = sqlite3OsFileSize(pPager->fd, &nByte); } if( rc==SQLITE_OK ){ - pNew = (char *)sqlite3PageMalloc(pageSize); - if( !pNew ) rc = SQLITE_NOMEM_BKPT; + /* 8 bytes of zeroed overrun space is sufficient so that the b-tree + * cell header parser will never run off the end of the allocation */ + pNew = (char *)sqlite3PageMalloc(pageSize+8); + if( !pNew ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + memset(pNew+pageSize, 0, 8); + } } if( rc==SQLITE_OK ){ @@ -57633,8 +57820,12 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i */ pPg->flags &= ~PGHDR_NEED_SYNC; pPgOld = sqlite3PagerLookup(pPager, pgno); - assert( !pPgOld || pPgOld->nRef==1 ); + assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB ); if( pPgOld ){ + if( pPgOld->nRef>1 ){ + sqlite3PagerUnrefNotNull(pPgOld); + return SQLITE_CORRUPT_BKPT; + } pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); if( pPager->tempFile ){ /* Do not discard pages from an in-memory database since we might @@ -58162,7 +58353,7 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pS */ SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager){ assert( pPager->pWal ); - return sqlite3WalSnapshotUnlock(pPager->pWal); + sqlite3WalSnapshotUnlock(pPager->pWal); } #endif /* SQLITE_ENABLE_SNAPSHOT */ @@ -58763,7 +58954,7 @@ static SQLITE_NOINLINE int walIndexPageRealloc( /* Enlarge the pWal->apWiData[] array if required */ if( pWal->nWiData<=iPage ){ - int nByte = sizeof(u32*)*(iPage+1); + sqlite3_int64 nByte = sizeof(u32*)*(iPage+1); volatile u32 **apNew; apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte); if( !apNew ){ @@ -58867,6 +59058,7 @@ static void walChecksumBytes( assert( nByte>=8 ); assert( (nByte&0x00000007)==0 ); + assert( nByte<=65536 ); if( nativeCksum ){ do { @@ -59174,6 +59366,7 @@ static void walCleanupHash(Wal *pWal){ int iLimit = 0; /* Zero values greater than this */ int nByte; /* Number of bytes to zero in aPgno[] */ int i; /* Used to iterate through aHash[] */ + int rc; /* Return code form walHashGet() */ assert( pWal->writeLock ); testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 ); @@ -59184,11 +59377,12 @@ static void walCleanupHash(Wal *pWal){ /* Obtain pointers to the hash-table and page-number array containing ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed - ** that the page said hash-table and array reside on is already mapped. + ** that the page said hash-table and array reside on is already mapped.(1) */ assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) ); assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] ); - walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc); + rc = walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc); + if( NEVER(rc) ) return; /* Defense-in-depth, in case (1) above is wrong */ /* Zero all hash-table entries that correspond to frame numbers greater ** than pWal->hdr.mxFrame. @@ -59802,7 +59996,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){ WalIterator *p; /* Return value */ int nSegment; /* Number of segments to merge */ u32 iLast; /* Last frame in log */ - int nByte; /* Number of bytes to allocate */ + sqlite3_int64 nByte; /* Number of bytes to allocate */ int i; /* Iterator variable */ ht_slot *aTmp; /* Temp space used by merge-sort */ int rc = SQLITE_OK; /* Return Code */ @@ -61093,9 +61287,9 @@ SQLITE_PRIVATE int sqlite3WalFindFrame( } nCollide = HASHTABLE_NSLOT; for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ - u32 iFrame = sLoc.aHash[iKey] + sLoc.iZero; - if( iFrame<=iLast && iFrame>=pWal->minFrame - && sLoc.aPgno[sLoc.aHash[iKey]]==pgno ){ + u32 iH = sLoc.aHash[iKey]; + u32 iFrame = iH + sLoc.iZero; + if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH]==pgno ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } @@ -62338,7 +62532,7 @@ struct MemPage { u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ - u16 nFree; /* Number of free bytes on the page */ + int nFree; /* Number of free bytes on the page. -1 for unknown */ u16 nCell; /* Number of cells on this page, local and ovfl */ u16 maskPage; /* Mask for page offset */ u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th @@ -63892,14 +64086,18 @@ moveto_done: */ static int btreeRestoreCursorPosition(BtCursor *pCur){ int rc; - int skipNext; + int skipNext = 0; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState>=CURSOR_REQUIRESEEK ); if( pCur->eState==CURSOR_FAULT ){ return pCur->skipNext; } pCur->eState = CURSOR_INVALID; - rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); + if( sqlite3FaultSim(410) ){ + rc = SQLITE_IOERR; + }else{ + rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext); + } if( rc==SQLITE_OK ){ sqlite3_free(pCur->pKey); pCur->pKey = 0; @@ -64480,7 +64678,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ hdr = pPage->hdrOffset; cellOffset = pPage->cellOffset; nCell = pPage->nCell; - assert( nCell==get2byte(&data[hdr+3]) ); + assert( nCell==get2byte(&data[hdr+3]) || CORRUPT_DB ); iCellFirst = cellOffset + 2*nCell; usableSize = pPage->pBt->usableSize; @@ -64491,11 +64689,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** reconstruct the entire page. */ if( (int)data[hdr+7]<=nMaxFrag ){ int iFree = get2byte(&data[hdr+1]); - - /* If the initial freeblock offset were out of bounds, that would - ** have been detected by btreeInitPage() when it was computing the - ** number of free bytes on the page. */ - assert( iFree<=usableSize-4 ); + if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); if( iFree ){ int iFree2 = get2byte(&data[iFree]); if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); @@ -64514,7 +64708,10 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); sz += sz2; + }else if( iFree+sz>usableSize ){ + return SQLITE_CORRUPT_PAGE(pPage); } + cbrk = top+sz; assert( cbrk+(iFree-top) <= usableSize ); memmove(&data[cbrk], &data[top], iFree-top); @@ -64565,6 +64762,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ data[hdr+7] = 0; defragment_out: + assert( pPage->nFree>=0 ); if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ return SQLITE_CORRUPT_PAGE(pPage); } @@ -64592,16 +64790,16 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ ** causes the fragmentation count to exceed 60. */ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ - const int hdr = pPg->hdrOffset; - u8 * const aData = pPg->aData; - int iAddr = hdr + 1; - int pc = get2byte(&aData[iAddr]); - int x; - int usableSize = pPg->pBt->usableSize; - int size; /* Size of the free slot */ + const int hdr = pPg->hdrOffset; /* Offset to page header */ + u8 * const aData = pPg->aData; /* Page data */ + int iAddr = hdr + 1; /* Address of ptr to pc */ + int pc = get2byte(&aData[iAddr]); /* Address of a free slot */ + int x; /* Excess size of the slot */ + int maxPC = pPg->pBt->usableSize - nByte; /* Max address for a usable slot */ + int size; /* Size of the free slot */ assert( pc>0 ); - while( pc<=usableSize-4 ){ + while( pc<=maxPC ){ /* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each ** freeblock form a big-endian integer which is the size of the freeblock ** in bytes, including the 4-byte header. */ @@ -64609,10 +64807,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ if( (x = size - nByte)>=0 ){ testcase( x==4 ); testcase( x==3 ); - if( size+pc > usableSize ){ - *pRc = SQLITE_CORRUPT_PAGE(pPg); - return 0; - }else if( x<4 ){ + if( x<4 ){ /* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total ** number of bytes in fragments may not exceed 60. */ if( aData[hdr+7]>57 ) return 0; @@ -64621,21 +64816,31 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ ** fragmented bytes within the page. */ memcpy(&aData[iAddr], &aData[pc], 2); aData[hdr+7] += (u8)x; + }else if( x+pc > maxPC ){ + /* This slot extends off the end of the usable part of the page */ + *pRc = SQLITE_CORRUPT_PAGE(pPg); + return 0; }else{ /* The slot remains on the free-list. Reduce its size to account - ** for the portion used by the new allocation. */ + ** for the portion used by the new allocation. */ put2byte(&aData[pc+2], x); } return &aData[pc + x]; } iAddr = pc; pc = get2byte(&aData[pc]); - if( pc<iAddr+size ) break; + if( pc<=iAddr+size ){ + if( pc ){ + /* The next slot in the chain is not past the end of the current slot */ + *pRc = SQLITE_CORRUPT_PAGE(pPg); + } + return 0; + } } - if( pc ){ + if( pc>maxPC+nByte-4 ){ + /* The free slot chain extends off the end of the page */ *pRc = SQLITE_CORRUPT_PAGE(pPg); } - return 0; } @@ -64676,7 +64881,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ ** However, that integer is too large to be stored in a 2-byte unsigned ** integer, so a value of 0 is used in its place. */ top = get2byte(&data[hdr+5]); - assert( top<=(int)pPage->pBt->usableSize ); /* Prevent by getAndInitPage() */ + assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */ if( gap>top ){ if( top==0 && pPage->pBt->usableSize==65536 ){ top = 65536; @@ -64685,9 +64890,9 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ } } - /* If there is enough space between gap and top for one more cell pointer - ** array entry offset, and if the freelist is not empty, then search the - ** freelist looking for a free slot big enough to satisfy the request. + /* If there is enough space between gap and top for one more cell pointer, + ** and if the freelist is not empty, then search the + ** freelist looking for a slot big enough to satisfy the request. */ testcase( gap+2==top ); testcase( gap+1==top ); @@ -64709,6 +64914,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ testcase( gap+2+nByte==top ); if( gap+2+nByte>top ){ assert( pPage->nCell>0 || CORRUPT_DB ); + assert( pPage->nFree>=0 ); rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte))); if( rc ) return rc; top = get2byteNotZero(&data[hdr+5]); @@ -64717,7 +64923,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ /* Allocate memory from the gap in between the cell pointer array - ** and the cell content area. The btreeInitPage() call has already + ** and the cell content area. The btreeComputeFreeSpace() call has already ** validated the freelist. Given that the freelist is valid, there ** is no way that the allocation can extend off the end of the page. ** The assert() below verifies the previous sentence. @@ -64736,7 +64942,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ ** ** Adjacent freeblocks are coalesced. ** -** Note that even though the freeblock list was checked by btreeInitPage(), +** Even though the freeblock list was checked by btreeComputeFreeSpace(), ** that routine will not detect overlap between cells or freeblocks. Nor ** does it detect cells or freeblocks that encrouch into the reserved bytes ** at the end of the page. So do additional corruption checks inside this @@ -64898,21 +65104,14 @@ static int decodeFlags(MemPage *pPage, int flagByte){ } /* -** Initialize the auxiliary information for a disk block. -** -** Return SQLITE_OK on success. If we see that the page does -** not contain a well-formed database page, then return -** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not -** guarantee that the page is well-formed. It only shows that -** we failed to detect any corruption. +** Compute the amount of freespace on the page. In other words, fill +** in the pPage->nFree field. */ -static int btreeInitPage(MemPage *pPage){ +static int btreeComputeFreeSpace(MemPage *pPage){ int pc; /* Address of a freeblock within pPage->aData[] */ u8 hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ - BtShared *pBt; /* The main btree structure */ int usableSize; /* Amount of usable space on each page */ - u16 cellOffset; /* Offset from start of page to first cell pointer */ int nFree; /* Number of unused bytes on the page */ int top; /* First byte of the cell content area */ int iCellFirst; /* First allowable cell or freeblock offset */ @@ -64924,71 +65123,18 @@ static int btreeInitPage(MemPage *pPage){ assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); - assert( pPage->isInit==0 ); + assert( pPage->isInit==1 ); + assert( pPage->nFree<0 ); - pBt = pPage->pBt; + usableSize = pPage->pBt->usableSize; hdr = pPage->hdrOffset; data = pPage->aData; - /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating - ** the b-tree page type. */ - if( decodeFlags(pPage, data[hdr]) ){ - return SQLITE_CORRUPT_PAGE(pPage); - } - assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); - pPage->maskPage = (u16)(pBt->pageSize - 1); - pPage->nOverflow = 0; - usableSize = pBt->usableSize; - pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize; - pPage->aDataEnd = &data[usableSize]; - pPage->aCellIdx = &data[cellOffset]; - pPage->aDataOfst = &data[pPage->childPtrSize]; /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates ** the start of the cell content area. A zero value for this integer is ** interpreted as 65536. */ top = get2byteNotZero(&data[hdr+5]); - /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the - ** number of cells on the page. */ - pPage->nCell = get2byte(&data[hdr+3]); - if( pPage->nCell>MX_CELL(pBt) ){ - /* To many cells for a single page. The page must be corrupt */ - return SQLITE_CORRUPT_PAGE(pPage); - } - testcase( pPage->nCell==MX_CELL(pBt) ); - /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only - ** possible for a root page of a table that contains no rows) then the - ** offset to the cell content area will equal the page size minus the - ** bytes of reserved space. */ - assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB ); - - /* A malformed database page might cause us to read past the end - ** of page when parsing a cell. - ** - ** The following block of code checks early to see if a cell extends - ** past the end of a page boundary and causes SQLITE_CORRUPT to be - ** returned if it does. - */ - iCellFirst = cellOffset + 2*pPage->nCell; + iCellFirst = hdr + 8 + pPage->childPtrSize + 2*pPage->nCell; iCellLast = usableSize - 4; - if( pBt->db->flags & SQLITE_CellSizeCk ){ - int i; /* Index into the cell pointer array */ - int sz; /* Size of a cell */ - - if( !pPage->leaf ) iCellLast--; - for(i=0; i<pPage->nCell; i++){ - pc = get2byteAligned(&data[cellOffset+i*2]); - testcase( pc==iCellFirst ); - testcase( pc==iCellLast ); - if( pc<iCellFirst || pc>iCellLast ){ - return SQLITE_CORRUPT_PAGE(pPage); - } - sz = pPage->xCellSize(pPage, &data[pc]); - testcase( pc+sz==usableSize ); - if( pc+sz>usableSize ){ - return SQLITE_CORRUPT_PAGE(pPage); - } - } - if( !pPage->leaf ) iCellLast++; - } /* Compute the total free space on the page ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the @@ -65032,11 +65178,104 @@ static int btreeInitPage(MemPage *pPage){ ** serves to verify that the offset to the start of the cell-content ** area, according to the page header, lies within the page. */ - if( nFree>usableSize ){ + if( nFree>usableSize || nFree<iCellFirst ){ return SQLITE_CORRUPT_PAGE(pPage); } pPage->nFree = (u16)(nFree - iCellFirst); + return SQLITE_OK; +} + +/* +** Do additional sanity check after btreeInitPage() if +** PRAGMA cell_size_check=ON +*/ +static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ + int iCellFirst; /* First allowable cell or freeblock offset */ + int iCellLast; /* Last possible cell or freeblock offset */ + int i; /* Index into the cell pointer array */ + int sz; /* Size of a cell */ + int pc; /* Address of a freeblock within pPage->aData[] */ + u8 *data; /* Equal to pPage->aData */ + int usableSize; /* Maximum usable space on the page */ + int cellOffset; /* Start of cell content area */ + + iCellFirst = pPage->cellOffset + 2*pPage->nCell; + usableSize = pPage->pBt->usableSize; + iCellLast = usableSize - 4; + data = pPage->aData; + cellOffset = pPage->cellOffset; + if( !pPage->leaf ) iCellLast--; + for(i=0; i<pPage->nCell; i++){ + pc = get2byteAligned(&data[cellOffset+i*2]); + testcase( pc==iCellFirst ); + testcase( pc==iCellLast ); + if( pc<iCellFirst || pc>iCellLast ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + sz = pPage->xCellSize(pPage, &data[pc]); + testcase( pc+sz==usableSize ); + if( pc+sz>usableSize ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + } + return SQLITE_OK; +} + +/* +** Initialize the auxiliary information for a disk block. +** +** Return SQLITE_OK on success. If we see that the page does +** not contain a well-formed database page, then return +** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not +** guarantee that the page is well-formed. It only shows that +** we failed to detect any corruption. +*/ +static int btreeInitPage(MemPage *pPage){ + u8 *data; /* Equal to pPage->aData */ + BtShared *pBt; /* The main btree structure */ + + assert( pPage->pBt!=0 ); + assert( pPage->pBt->db!=0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); + assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); + assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); + assert( pPage->isInit==0 ); + + pBt = pPage->pBt; + data = pPage->aData + pPage->hdrOffset; + /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating + ** the b-tree page type. */ + if( decodeFlags(pPage, data[0]) ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); + pPage->maskPage = (u16)(pBt->pageSize - 1); + pPage->nOverflow = 0; + pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize; + pPage->aCellIdx = data + pPage->childPtrSize + 8; + pPage->aDataEnd = pPage->aData + pBt->usableSize; + pPage->aDataOfst = pPage->aData + pPage->childPtrSize; + /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the + ** number of cells on the page. */ + pPage->nCell = get2byte(&data[3]); + if( pPage->nCell>MX_CELL(pBt) ){ + /* To many cells for a single page. The page must be corrupt */ + return SQLITE_CORRUPT_PAGE(pPage); + } + testcase( pPage->nCell==MX_CELL(pBt) ); + /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only + ** possible for a root page of a table that contains no rows) then the + ** offset to the cell content area will equal the page size minus the + ** bytes of reserved space. */ + assert( pPage->nCell>0 + || get2byteNotZero(&data[5])==(int)pBt->usableSize + || CORRUPT_DB ); + pPage->nFree = -1; /* Indicate that this value is yet uncomputed */ pPage->isInit = 1; + if( pBt->db->flags & SQLITE_CellSizeCk ){ + return btreeCellSizeCheck(pPage); + } return SQLITE_OK; } @@ -65179,19 +65418,18 @@ static int getAndInitPage( if( pgno>btreePagecount(pBt) ){ rc = SQLITE_CORRUPT_BKPT; - goto getAndInitPage_error; + goto getAndInitPage_error1; } rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); if( rc ){ - goto getAndInitPage_error; + goto getAndInitPage_error1; } *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); if( (*ppPage)->isInit==0 ){ btreePageFromDbPage(pDbPage, pgno, pBt); rc = btreeInitPage(*ppPage); if( rc!=SQLITE_OK ){ - releasePage(*ppPage); - goto getAndInitPage_error; + goto getAndInitPage_error2; } } assert( (*ppPage)->pgno==pgno ); @@ -65201,12 +65439,13 @@ static int getAndInitPage( ** compatible with the root page. */ if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ rc = SQLITE_CORRUPT_PGNO(pgno); - releasePage(*ppPage); - goto getAndInitPage_error; + goto getAndInitPage_error2; } return SQLITE_OK; -getAndInitPage_error: +getAndInitPage_error2: + releasePage(*ppPage); +getAndInitPage_error1: if( pCur ){ pCur->iPage--; pCur->pPage = pCur->apPage[pCur->iPage]; @@ -67168,6 +67407,18 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr } /* +** Set the pBt->nPage field correctly, according to the current +** state of the database. Assume pBt->pPage1 is valid. +*/ +static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){ + int nPage = get4byte(&pPage1->aData[28]); + testcase( nPage==0 ); + if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); + testcase( pBt->nPage!=nPage ); + pBt->nPage = nPage; +} + +/* ** Rollback the transaction in progress. ** ** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped). @@ -67212,11 +67463,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){ ** call btreeGetPage() on page 1 again to make ** sure pPage1->aData is set correctly. */ if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ - int nPage = get4byte(28+(u8*)pPage1->aData); - testcase( nPage==0 ); - if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); - testcase( pBt->nPage!=nPage ); - pBt->nPage = nPage; + btreeSetNPage(pBt, pPage1); releasePageOne(pPage1); } assert( countValidCursors(pBt, 1)==0 ); @@ -67296,12 +67543,11 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){ pBt->nPage = 0; } rc = newDatabase(pBt); - pBt->nPage = get4byte(28 + pBt->pPage1->aData); + btreeSetNPage(pBt, pBt->pPage1); - /* The database size was written into the offset 28 of the header - ** when the transaction started, so we know that the value at offset - ** 28 is nonzero. */ - assert( pBt->nPage>0 ); + /* pBt->nPage might be zero if the database was corrupt when + ** the transaction was started. Otherwise, it must be at least 1. */ + assert( CORRUPT_DB || pBt->nPage>0 ); } sqlite3BtreeLeave(p); } @@ -68287,23 +68533,6 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ return rc; } -/* -** This function is a no-op if cursor pCur does not point to a valid row. -** Otherwise, if pCur is valid, configure it so that the next call to -** sqlite3BtreeNext() is a no-op. -*/ -#ifndef SQLITE_OMIT_WINDOWFUNC -SQLITE_PRIVATE void sqlite3BtreeSkipNext(BtCursor *pCur){ - /* We believe that the cursor must always be in the valid state when - ** this routine is called, but the proof is difficult, so we add an - ** ALWaYS() test just in case we are wrong. */ - if( ALWAYS(pCur->eState==CURSOR_VALID) ){ - pCur->eState = CURSOR_SKIPNEXT; - pCur->skipNext = 1; - } -} -#endif /* SQLITE_OMIT_WINDOWFUNC */ - /* Move the cursor to the last entry in the table. Return SQLITE_OK ** on success. Set *pRes to 0 if the cursor actually points to something ** or set *pRes to 1 if the table is empty. @@ -68326,6 +68555,7 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ assert( pCur->ix==pCur->pPage->nCell-1 ); assert( pCur->pPage->leaf ); #endif + *pRes = 0; return SQLITE_OK; } @@ -68547,6 +68777,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( ** case this happens. */ void *pCellKey; u8 * const pCellBody = pCell - pPage->childPtrSize; + const int nOverrun = 18; /* Size of the overrun padding */ pPage->xParseCell(pPage, pCellBody, &pCur->info); nCell = (int)pCur->info.nKey; testcase( nCell<0 ); /* True if key size is 2^32 or more */ @@ -68557,19 +68788,20 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( rc = SQLITE_CORRUPT_PAGE(pPage); goto moveto_finish; } - pCellKey = sqlite3Malloc( nCell+18 ); + pCellKey = sqlite3Malloc( nCell+nOverrun ); if( pCellKey==0 ){ rc = SQLITE_NOMEM_BKPT; goto moveto_finish; } pCur->ix = (u16)idx; rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); + memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */ pCur->curFlags &= ~BTCF_ValidOvfl; if( rc ){ sqlite3_free(pCellKey); goto moveto_finish; } - c = xRecordCompare(nCell, pCellKey, pIdxKey); + c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); sqlite3_free(pCellKey); } assert( @@ -69201,13 +69433,15 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ MemPage *pPage1 = pBt->pPage1; /* Local reference to page 1 */ MemPage *pPage; /* Page being freed. May be NULL. */ int rc; /* Return Code */ - int nFree; /* Initial number of pages on free-list */ + u32 nFree; /* Initial number of pages on free-list */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( CORRUPT_DB || iPage>1 ); assert( !pMemPage || pMemPage->pgno==iPage ); - if( iPage<2 ) return SQLITE_CORRUPT_BKPT; + if( iPage<2 || iPage>pBt->nPage ){ + return SQLITE_CORRUPT_BKPT; + } if( pMemPage ){ pPage = pMemPage; sqlite3PagerRef(pPage->pDbPage); @@ -69618,6 +69852,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->nFree>=0 ); data = pPage->aData; ptr = &pPage->aCellIdx[2*idx]; pc = get2byte(ptr); @@ -69688,6 +69923,7 @@ static void insertCell( ** might be less than 8 (leaf-size + pointer) on the interior node. Hence ** the term after the || in the following assert(). */ assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) ); + assert( pPage->nFree>=0 ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ memcpy(pTemp, pCell, sz); @@ -69745,7 +69981,7 @@ static void insertCell( pPage->nCell++; /* increment the cell count */ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++; - assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell ); + assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB ); #ifndef SQLITE_OMIT_AUTOVACUUM if( pPage->pBt->autoVacuum ){ /* The cell may contain a pointer to an overflow page. If so, write @@ -69832,8 +70068,13 @@ static void insertCell( ** are used and they point to the leaf pages only, and the ixNx value are: ** ** ixNx[0] = Number of cells in Child-1. -** ixNx[1] = Number of cells in Child-1 and Child-2 + 1 for 1st divider. -** ixNx[2] = Number of cells in Child-1 and Child-2 + both divider cells +** ixNx[1] = Number of cells in Child-1 and Child-2. +** ixNx[2] = Total number of cells. +** +** Sometimes when deleting, a child page can have zero cells. In those +** cases, ixNx[] entries with higher indexes, and the corresponding apEnd[] +** entries, shift down. The end result is that each ixNx[] entry should +** be larger than the previous */ typedef struct CellArray CellArray; struct CellArray { @@ -70162,8 +70403,9 @@ static int editPage( int iCell = (iOld + pPg->aiOvfl[i]) - iNew; if( iCell>=0 && iCell<nNew ){ pCellptr = &pPg->aCellIdx[iCell * 2]; - assert( nCell>=iCell ); - memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); + if( nCell>iCell ){ + memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2); + } nCell++; if( pageInsertArray( pPg, pBegin, &pData, pCellptr, @@ -70239,8 +70481,10 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); assert( pPage->nOverflow==1 ); - + if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */ + assert( pPage->nFree>=0 ); + assert( pParent->nFree>=0 ); /* Allocate a new page. This page will become the right-sibling of ** pPage. Make the parent page writable, so that the new divider cell @@ -70410,6 +70654,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ */ pTo->isInit = 0; rc = btreeInitPage(pTo); + if( rc==SQLITE_OK ) rc = btreeComputeFreeSpace(pTo); if( rc!=SQLITE_OK ){ *pRC = rc; return; @@ -70518,6 +70763,7 @@ static int balance_nonroot( if( !aOvflSpace ){ return SQLITE_NOMEM_BKPT; } + assert( pParent->nFree>=0 ); /* Find the sibling pages to balance. Also locate the cells in pParent ** that divide the siblings. An attempt is made to find NN siblings on @@ -70557,7 +70803,13 @@ static int balance_nonroot( memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; } - nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; + if( apOld[i]->nFree<0 ){ + rc = btreeComputeFreeSpace(apOld[i]); + if( rc ){ + memset(apOld, 0, (i)*sizeof(MemPage*)); + goto balance_cleanup; + } + } if( (i--)==0 ) break; if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){ @@ -70601,6 +70853,7 @@ static int balance_nonroot( /* Make nMaxCells a multiple of 4 in order to preserve 8-byte ** alignment */ + nMaxCells = nOld*(MX_CELL(pBt) + ArraySize(pParent->apOvfl)); nMaxCells = (nMaxCells + 3)&~3; /* @@ -70611,7 +70864,7 @@ static int balance_nonroot( + nMaxCells*sizeof(u16) /* b.szCell */ + pBt->pageSize; /* aSpace1 */ - assert( szScratch<=6*(int)pBt->pageSize ); + assert( szScratch<=7*(int)pBt->pageSize ); b.apCell = sqlite3StackAllocRaw(0, szScratch ); if( b.apCell==0 ){ rc = SQLITE_NOMEM_BKPT; @@ -70647,6 +70900,7 @@ static int balance_nonroot( u16 maskPage = pOld->maskPage; u8 *piCell = aData + pOld->cellOffset; u8 *piEnd; + VVA_ONLY( int nCellAtStart = b.nCell; ) /* Verify that all sibling pages are of the same "type" (table-leaf, ** table-interior, index-leaf, or index-interior). @@ -70675,6 +70929,10 @@ static int balance_nonroot( */ memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow)); if( pOld->nOverflow>0 ){ + if( limit<pOld->aiOvfl[0] ){ + rc = SQLITE_CORRUPT_BKPT; + goto balance_cleanup; + } limit = pOld->aiOvfl[0]; for(j=0; j<limit; j++){ b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell)); @@ -70694,6 +70952,7 @@ static int balance_nonroot( piCell += 2; b.nCell++; } + assert( (b.nCell-nCellAtStart)==(pOld->nCell+pOld->nOverflow) ); cntOld[i] = b.nCell; if( i<nOld-1 && !leafData){ @@ -70751,11 +71010,15 @@ static int balance_nonroot( MemPage *p = apOld[i]; b.apEnd[k] = p->aDataEnd; b.ixNx[k] = cntOld[i]; + if( k && b.ixNx[k]==b.ixNx[k-1] ){ + k--; /* Omit b.ixNx[] entry for child pages with no cells */ + } if( !leafData ){ k++; b.apEnd[k] = pParent->aDataEnd; b.ixNx[k] = cntOld[i]+1; } + assert( p->nFree>=0 ); szNew[i] = usableSpace - p->nFree; for(j=0; j<p->nOverflow; j++){ szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]); @@ -70981,18 +71244,18 @@ static int balance_nonroot( if( ISAUTOVACUUM ){ MemPage *pOld; MemPage *pNew = pOld = apNew[0]; - u8 *aOld = pNew->aData; int cntOldNext = pNew->nCell + pNew->nOverflow; - int usableSize = pBt->usableSize; int iNew = 0; int iOld = 0; for(i=0; i<b.nCell; i++){ u8 *pCell = b.apCell[i]; - if( i==cntOldNext ){ - pOld = (++iOld)<nNew ? apNew[iOld] : apOld[iOld]; + while( i==cntOldNext ){ + iOld++; + assert( iOld<nNew || iOld<nOld ); + assert( iOld>=0 && iOld<NB ); + pOld = iOld<nNew ? apNew[iOld] : apOld[iOld]; cntOldNext += pOld->nCell + pOld->nOverflow + !leafData; - aOld = pOld->aData; } if( i==cntNew[iNew] ){ pNew = apNew[++iNew]; @@ -71007,7 +71270,7 @@ static int balance_nonroot( ** overflow cell), we can skip updating the pointer map entries. */ if( iOld>=nNew || pNew->pgno!=aPgno[iOld] - || !SQLITE_WITHIN(pCell,aOld,&aOld[usableSize]) + || !SQLITE_WITHIN(pCell,pOld->aData,pOld->aDataEnd) ){ if( !leafCorrection ){ ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc); @@ -71158,7 +71421,8 @@ static int balance_nonroot( rc = defragmentPage(apNew[0], -1); testcase( rc!=SQLITE_OK ); assert( apNew[0]->nFree == - (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) + (get2byteNotZero(&apNew[0]->aData[5]) - apNew[0]->cellOffset + - apNew[0]->nCell*2) || rc!=SQLITE_OK ); copyNodeContent(apNew[0], pParent, &rc); @@ -71257,7 +71521,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){ } assert( sqlite3PagerIswriteable(pChild->pDbPage) ); assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); - assert( pChild->nCell==pRoot->nCell ); + assert( pChild->nCell==pRoot->nCell || CORRUPT_DB ); TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno)); @@ -71299,6 +71563,7 @@ static int balance(BtCursor *pCur){ int iPage = pCur->iPage; MemPage *pPage = pCur->pPage; + if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break; if( iPage==0 ){ if( pPage->nOverflow ){ /* The root page of the b-tree is overfull. In this case call the @@ -71327,6 +71592,9 @@ static int balance(BtCursor *pCur){ int const iIdx = pCur->aiIdx[iPage-1]; rc = sqlite3PagerWrite(pParent->pDbPage); + if( rc==SQLITE_OK && pParent->nFree<0 ){ + rc = btreeComputeFreeSpace(pParent); + } if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_QUICKBALANCE if( pPage->intKeyLeaf @@ -71673,6 +71941,10 @@ SQLITE_PRIVATE int sqlite3BtreeInsert( pPage = pCur->pPage; assert( pPage->intKey || pX->nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); + if( pPage->nFree<0 ){ + rc = btreeComputeFreeSpace(pPage); + if( rc ) return rc; + } TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, @@ -71815,14 +72087,18 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); - assert( pCur->ix<pCur->pPage->nCell ); - assert( pCur->eState==CURSOR_VALID ); assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 ); + if( pCur->eState==CURSOR_REQUIRESEEK ){ + rc = btreeRestoreCursorPosition(pCur); + if( rc ) return rc; + } + assert( pCur->eState==CURSOR_VALID ); iCellDepth = pCur->iPage; iCellIdx = pCur->ix; pPage = pCur->pPage; pCell = findCell(pPage, iCellIdx); + if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ) return SQLITE_CORRUPT; /* If the bPreserve flag is set to true, then the cursor position must ** be preserved following this delete operation. If the current delete @@ -71893,6 +72169,10 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ Pgno n; unsigned char *pTmp; + if( pLeaf->nFree<0 ){ + rc = btreeComputeFreeSpace(pLeaf); + if( rc ) return rc; + } if( iCellDepth<pCur->iPage-1 ){ n = pCur->apPage[iCellDepth+1]->pgno; }else{ @@ -72251,6 +72531,9 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){ assert( sqlite3BtreeHoldsMutex(p) ); assert( p->inTrans==TRANS_WRITE ); assert( iTable>=2 ); + if( iTable>btreePagecount(pBt) ){ + return SQLITE_CORRUPT_BKPT; + } rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( rc ) return rc; @@ -72599,10 +72882,10 @@ static void checkList( IntegrityCk *pCheck, /* Integrity checking context */ int isFreeList, /* True for a freelist. False for overflow page list */ int iPage, /* Page number for first page in the list */ - int N /* Expected number of pages in the list */ + u32 N /* Expected number of pages in the list */ ){ int i; - int expected = N; + u32 expected = N; int nErrAtStart = pCheck->nErr; while( iPage!=0 && pCheck->mxErr ){ DbPage *pOvflPage; @@ -72784,6 +73067,11 @@ static int checkTreePage( "btreeInitPage() returns error code %d", rc); goto end_of_check; } + if( (rc = btreeComputeFreeSpace(pPage))!=0 ){ + assert( rc==SQLITE_CORRUPT ); + checkAppendMsg(pCheck, "free space corruption", rc); + goto end_of_check; + } data = pPage->aData; hdr = pPage->hdrOffset; @@ -72856,7 +73144,7 @@ static int checkTreePage( /* Check the content overflow list */ if( info.nPayload>info.nLocal ){ - int nPage; /* Number of pages on the overflow chain */ + u32 nPage; /* Number of pages on the overflow chain */ Pgno pgnoOvfl; /* First page of the overflow chain */ assert( pc + info.nSize - 4 <= usableSize ); nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4); @@ -72916,9 +73204,9 @@ static int checkTreePage( i = get2byte(&data[hdr+1]); while( i>0 ){ int size, j; - assert( (u32)i<=usableSize-4 ); /* Enforced by btreeInitPage() */ + assert( (u32)i<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ size = get2byte(&data[i+2]); - assert( (u32)(i+size)<=usableSize ); /* Enforced by btreeInitPage() */ + assert( (u32)(i+size)<=usableSize ); /* due to btreeComputeFreeSpace() */ btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1)); /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a ** big-endian integer which is the offset in the b-tree page of the next @@ -72927,8 +73215,8 @@ static int checkTreePage( j = get2byte(&data[i]); /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of ** increasing offset. */ - assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */ - assert( (u32)j<=usableSize-4 ); /* Enforced by btreeInitPage() */ + assert( j==0 || j>i+size ); /* Enforced by btreeComputeFreeSpace() */ + assert( (u32)j<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ i = j; } /* Analyze the min-heap looking for overlap between cells and/or @@ -73686,7 +73974,7 @@ static int backupOnePage( if( nSrcReserve!=nDestReserve ){ u32 newPgsz = nSrcPgsz; rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); - if( rc==SQLITE_OK && newPgsz!=nSrcPgsz ) rc = SQLITE_READONLY; + if( rc==SQLITE_OK && newPgsz!=(u32)nSrcPgsz ) rc = SQLITE_READONLY; } #endif @@ -74233,6 +74521,11 @@ copy_finished: /* #include "sqliteInt.h" */ /* #include "vdbeInt.h" */ +/* True if X is a power of two. 0 is considered a power of two here. +** In other words, return true if X has at most one bit set. +*/ +#define ISPOWEROF2(X) (((X)&((X)-1))==0) + #ifdef SQLITE_DEBUG /* ** Check invariants on a Mem object. @@ -74252,8 +74545,8 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ ** That saves a few cycles in inner loops. */ assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 ); - /* Cannot be both MEM_Int and MEM_Real at the same time */ - assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); + /* Cannot have more than one of MEM_Int, MEM_Real, or MEM_IntReal */ + assert( ISPOWEROF2(p->flags & (MEM_Int|MEM_Real|MEM_IntReal)) ); if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ @@ -74272,7 +74565,7 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 ); /* No other bits set */ - assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype + assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype|MEM_FromBind |MEM_Dyn|MEM_Ephem|MEM_Static))==0 ); }else{ /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn, @@ -74307,9 +74600,31 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ } #endif +/* +** Render a Mem object which is one of MEM_Int, MEM_Real, or MEM_IntReal +** into a buffer. +*/ +static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ + StrAccum acc; + assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) ); + sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0); + if( p->flags & MEM_Int ){ + sqlite3_str_appendf(&acc, "%lld", p->u.i); + }else if( p->flags & MEM_IntReal ){ + sqlite3_str_appendf(&acc, "%!.15g", (double)p->u.i); + }else{ + sqlite3_str_appendf(&acc, "%!.15g", p->u.r); + } + assert( acc.zText==zBuf && acc.mxAlloc<=0 ); + zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */ +} + #ifdef SQLITE_DEBUG /* -** Check that string value of pMem agrees with its integer or real value. +** Validity checks on pMem. pMem holds a string. +** +** (1) Check that string value of pMem agrees with its integer or real value. +** (2) Check that the string is correctly zero terminated ** ** A single int or real value always converts to the same strings. But ** many different strings can be converted into the same int or real. @@ -74327,17 +74642,24 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){ ** ** This routine is for use inside of assert() statements only. */ -SQLITE_PRIVATE int sqlite3VdbeMemConsistentDualRep(Mem *p){ +SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){ char zBuf[100]; char *z; int i, j, incr; if( (p->flags & MEM_Str)==0 ) return 1; - if( (p->flags & (MEM_Int|MEM_Real))==0 ) return 1; - if( p->flags & MEM_Int ){ - sqlite3_snprintf(sizeof(zBuf),zBuf,"%lld",p->u.i); - }else{ - sqlite3_snprintf(sizeof(zBuf),zBuf,"%!.15g",p->u.r); - } + if( p->flags & MEM_Term ){ + /* Insure that the string is properly zero-terminated. Pay particular + ** attention to the case where p->n is odd */ + if( p->szMalloc>0 && p->z==p->zMalloc ){ + assert( p->enc==SQLITE_UTF8 || p->szMalloc >= ((p->n+1)&~1)+2 ); + assert( p->enc!=SQLITE_UTF8 || p->szMalloc >= p->n+1 ); + } + assert( p->z[p->n]==0 ); + assert( p->enc==SQLITE_UTF8 || p->z[(p->n+1)&~1]==0 ); + assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 ); + } + if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1; + vdbeMemRenderNum(sizeof(zBuf), zBuf, p); z = p->z; i = j = 0; incr = 1; @@ -74393,8 +74715,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ } /* -** Make sure pMem->z points to a writable allocation of at least -** min(n,32) bytes. +** Make sure pMem->z points to a writable allocation of at least n bytes. ** ** If the bPreserve argument is true, then copy of the content of ** pMem->z into the new allocation. pMem must be either a string or @@ -74413,7 +74734,6 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre assert( pMem->szMalloc==0 || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) ); - if( n<32 ) n = 32; if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); bPreserve = 0; @@ -74451,8 +74771,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre ** ** Any prior string or blob content in the pMem object may be discarded. ** The pMem->xDel destructor is called, if it exists. Though MEM_Str -** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null -** values are preserved. +** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, MEM_IntReal, +** and MEM_Null values are preserved. ** ** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM) ** if unable to complete the resizing. @@ -74465,20 +74785,26 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ } assert( (pMem->flags & MEM_Dyn)==0 ); pMem->z = pMem->zMalloc; - pMem->flags &= (MEM_Null|MEM_Int|MEM_Real); + pMem->flags &= (MEM_Null|MEM_Int|MEM_Real|MEM_IntReal); return SQLITE_OK; } /* ** It is already known that pMem contains an unterminated string. ** Add the zero terminator. +** +** Three bytes of zero are added. In this way, there is guaranteed +** to be a double-zero byte at an even byte boundary in order to +** terminate a UTF16 string, even if the initial size of the buffer +** is an odd number of bytes. */ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ - if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ + if( sqlite3VdbeMemGrow(pMem, pMem->n+3, 1) ){ return SQLITE_NOMEM_BKPT; } pMem->z[pMem->n] = 0; pMem->z[pMem->n+1] = 0; + pMem->z[pMem->n+2] = 0; pMem->flags |= MEM_Term; return SQLITE_OK; } @@ -74515,13 +74841,15 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; assert( pMem->flags & MEM_Zero ); - assert( pMem->flags&MEM_Blob ); + assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) ); + testcase( sqlite3_value_nochange(pMem) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); /* Set nByte to the number of bytes required to store the expanded blob. */ nByte = pMem->n + pMem->u.nZero; if( nByte<=0 ){ + if( (pMem->flags & MEM_Blob)==0 ) return SQLITE_OK; nByte = 1; } if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ @@ -74550,12 +74878,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ } /* -** Add MEM_Str to the set of representations for the given Mem. Numbers -** are converted using sqlite3_snprintf(). Converting a BLOB to a string -** is a no-op. +** Add MEM_Str to the set of representations for the given Mem. This +** routine is only called if pMem is a number of some kind, not a NULL +** or a BLOB. ** -** Existing representations MEM_Int and MEM_Real are invalidated if -** bForce is true but are retained if bForce is false. +** Existing representations MEM_Int, MEM_Real, or MEM_IntReal are invalidated +** if bForce is true but are retained if bForce is false. ** ** A MEM_Null value will never be passed to this function. This function is ** used for converting values to text for returning to the user (i.e. via @@ -74564,13 +74892,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){ ** user and the latter is an internal programming error. */ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ - int fg = pMem->flags; const int nByte = 32; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( !(fg&MEM_Zero) ); - assert( !(fg&(MEM_Str|MEM_Blob)) ); - assert( fg&(MEM_Int|MEM_Real) ); + assert( !(pMem->flags&MEM_Zero) ); + assert( !(pMem->flags&(MEM_Str|MEM_Blob)) ); + assert( pMem->flags&(MEM_Int|MEM_Real|MEM_IntReal) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -74580,23 +74907,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ return SQLITE_NOMEM_BKPT; } - /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 - ** string representation of the value. Then, if the required encoding - ** is UTF-16le or UTF-16be do a translation. - ** - ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. - */ - if( fg & MEM_Int ){ - sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i); - }else{ - assert( fg & MEM_Real ); - sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r); - } + vdbeMemRenderNum(nByte, pMem->z, pMem); assert( pMem->z!=0 ); pMem->n = sqlite3Strlen30NN(pMem->z); pMem->enc = SQLITE_UTF8; pMem->flags |= MEM_Str|MEM_Term; - if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real); + if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal); sqlite3VdbeChangeEncoding(pMem, enc); return SQLITE_OK; } @@ -74770,7 +75086,8 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); flags = pMem->flags; - if( flags & MEM_Int ){ + if( flags & (MEM_Int|MEM_IntReal) ){ + testcase( flags & MEM_IntReal ); return pMem->u.i; }else if( flags & MEM_Real ){ return doubleToInt64(pMem->u.r); @@ -74799,7 +75116,8 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( pMem->flags & MEM_Real ){ return pMem->u.r; - }else if( pMem->flags & MEM_Int ){ + }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_IntReal ); return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ return memRealValue(pMem); @@ -74814,7 +75132,8 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ ** Return the value ifNull if pMem is NULL. */ SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ - if( pMem->flags & MEM_Int ) return pMem->u.i!=0; + testcase( pMem->flags & MEM_IntReal ); + if( pMem->flags & (MEM_Int|MEM_IntReal) ) return pMem->u.i!=0; if( pMem->flags & MEM_Null ) return ifNull; return sqlite3VdbeRealValue(pMem)!=0.0; } @@ -74877,17 +75196,21 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){ /* Compare a floating point value to an integer. Return true if the two ** values are the same within the precision of the floating point value. ** +** This function assumes that i was obtained by assignment from r1. +** ** For some versions of GCC on 32-bit machines, if you do the more obvious ** comparison of "r1==(double)i" you sometimes get an answer of false even ** though the r1 and (double)i values are bit-for-bit the same. */ -static int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ +SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ double r2 = (double)i; - return memcmp(&r1, &r2, sizeof(r1))==0; + return r1==0.0 + || (memcmp(&r1, &r2, sizeof(r1))==0 + && i >= -2251799813685248LL && i < 2251799813685248LL); } /* -** Convert pMem so that it has types MEM_Real or MEM_Int or both. +** Convert pMem so that it has type MEM_Real or MEM_Int. ** Invalidate any prior representations. ** ** Every effort is made to force the conversion, even if the input @@ -74895,25 +75218,26 @@ static int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ ** as much of the string as we can and ignore the rest. */ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ - if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_Real ); + testcase( pMem->flags & MEM_IntReal ); + testcase( pMem->flags & MEM_Null ); + if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){ int rc; + sqlite3_int64 ix; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc); - if( rc==0 ){ + rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1) + || sqlite3RealSameAsInt(pMem->u.r, (ix = (i64)pMem->u.r)) + ){ + pMem->u.i = ix; MemSetTypeFlag(pMem, MEM_Int); }else{ - i64 i = pMem->u.i; - sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); - if( rc==1 && sqlite3RealSameAsInt(pMem->u.r, i) ){ - pMem->u.i = i; - MemSetTypeFlag(pMem, MEM_Int); - }else{ - MemSetTypeFlag(pMem, MEM_Real); - } + MemSetTypeFlag(pMem, MEM_Real); } } - assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 ); + assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))!=0 ); pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero); return SQLITE_OK; } @@ -74956,7 +75280,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ pMem->flags |= (pMem->flags&MEM_Blob)>>3; sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding); assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); - pMem->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero); + pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero); break; } } @@ -75140,7 +75464,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ ** dual type, are allowed, as long as the underlying value is the ** same. */ u16 mFlags = pMem->flags & pX->flags & pX->mScopyFlags; - assert( (mFlags&MEM_Int)==0 || pMem->u.i==pX->u.i ); + assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i ); assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r ); assert( (mFlags&MEM_Str)==0 || (pMem->n==pX->n && pMem->z==pX->z) ); assert( (mFlags&MEM_Blob)==0 || sqlite3BlobCompare(pMem,pX)==0 ); @@ -75262,7 +75586,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( assert( enc!=0 ); if( enc==SQLITE_UTF8 ){ nByte = 0x7fffffff & (int)strlen(z); - if( nByte>iLimit ) nByte = iLimit+1; }else{ for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){} } @@ -75274,29 +75597,30 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( ** management (one of MEM_Dyn or MEM_Static). */ if( xDel==SQLITE_TRANSIENT ){ - int nAlloc = nByte; + u32 nAlloc = nByte; if( flags&MEM_Term ){ nAlloc += (enc==SQLITE_UTF8?1:2); } if( nByte>iLimit ){ - return SQLITE_TOOBIG; + return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); } testcase( nAlloc==0 ); testcase( nAlloc==31 ); testcase( nAlloc==32 ); - if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){ + if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){ return SQLITE_NOMEM_BKPT; } memcpy(pMem->z, z, nAlloc); - }else if( xDel==SQLITE_DYNAMIC ){ - sqlite3VdbeMemRelease(pMem); - pMem->zMalloc = pMem->z = (char *)z; - pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); }else{ sqlite3VdbeMemRelease(pMem); pMem->z = (char *)z; - pMem->xDel = xDel; - flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); + if( xDel==SQLITE_DYNAMIC ){ + pMem->zMalloc = pMem->z; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); + }else{ + pMem->xDel = xDel; + flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); + } } pMem->n = nByte; @@ -75415,7 +75739,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ - assert( sqlite3VdbeMemConsistentDualRep(pVal) ); + assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; }else{ return 0; @@ -75438,7 +75762,7 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ - assert( sqlite3VdbeMemConsistentDualRep(pVal) ); + assert( sqlite3VdbeMemValidStrRep(pVal) ); return pVal->z; } if( pVal->flags&MEM_Null ){ @@ -75703,7 +76027,12 @@ static int valueFromExpr( }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } - if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str; + assert( (pVal->flags & MEM_IntReal)==0 ); + if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ){ + testcase( pVal->flags & MEM_Int ); + testcase( pVal->flags & MEM_Real ); + pVal->flags &= ~MEM_Str; + } if( enc!=SQLITE_UTF8 ){ rc = sqlite3VdbeChangeEncoding(pVal, enc); } @@ -75726,7 +76055,7 @@ static int valueFromExpr( }else if( op==TK_NULL ){ pVal = valueNew(db, pCtx); if( pVal==0 ) goto no_mem; - sqlite3VdbeMemNumerify(pVal); + sqlite3VdbeMemSetNull(pVal); } #ifndef SQLITE_OMIT_BLOB_LITERAL else if( op==TK_BLOB ){ @@ -76264,9 +76593,11 @@ static int growOpArray(Vdbe *v, int nOp){ ** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current ** size of the op array or add 1KB of space, whichever is smaller. */ #ifdef SQLITE_TEST_REALLOC_STRESS - int nNew = (v->nOpAlloc>=512 ? v->nOpAlloc*2 : v->nOpAlloc+nOp); + sqlite3_int64 nNew = (v->nOpAlloc>=512 ? 2*(sqlite3_int64)v->nOpAlloc + : (sqlite3_int64)v->nOpAlloc+nOp); #else - int nNew = (v->nOpAlloc ? v->nOpAlloc*2 : (int)(1024/sizeof(Op))); + sqlite3_int64 nNew = (v->nOpAlloc ? 2*(sqlite3_int64)v->nOpAlloc + : (sqlite3_int64)(1024/sizeof(Op))); UNUSED_PARAMETER(nOp); #endif @@ -76736,6 +77067,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ int hasAbort = 0; int hasFkCounter = 0; int hasCreateTable = 0; + int hasCreateIndex = 0; int hasInitCoroutine = 0; Op *pOp; VdbeOpIter sIter; @@ -76746,6 +77078,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ int opcode = pOp->opcode; if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename || opcode==OP_VDestroy + || (opcode==OP_Function0 && pOp->p4.pFunc->funcFlags&SQLITE_FUNC_INTERNAL) || ((opcode==OP_Halt || opcode==OP_HaltIfNull) && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort)) ){ @@ -76753,6 +77086,14 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ break; } if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1; + if( mayAbort ){ + /* hasCreateIndex may also be set for some DELETE statements that use + ** OP_Clear. So this routine may end up returning true in the case + ** where a "DELETE FROM tbl" has a statement-journal but does not + ** require one. This is not so bad - it is an inefficiency, not a bug. */ + if( opcode==OP_CreateBtree && pOp->p3==BTREE_BLOBKEY ) hasCreateIndex = 1; + if( opcode==OP_Clear ) hasCreateIndex = 1; + } if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1; #ifndef SQLITE_OMIT_FOREIGN_KEY if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){ @@ -76768,7 +77109,8 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){ ** true for this case to prevent the assert() in the callers frame ** from failing. */ return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter - || (hasCreateTable && hasInitCoroutine) ); + || (hasCreateTable && hasInitCoroutine) || hasCreateIndex + ); } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ @@ -77053,7 +77395,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus( LogEst nEst, /* Estimated number of output rows */ const char *zName /* Name of table or index being scanned */ ){ - int nByte = (p->nScan+1) * sizeof(ScanStatus); + sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus); ScanStatus *aNew; aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte); if( aNew ){ @@ -77640,7 +77982,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ Mem *pMem = pOp->p4.pMem; if( pMem->flags & MEM_Str ){ zP4 = pMem->z; - }else if( pMem->flags & MEM_Int ){ + }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){ sqlite3_str_appendf(&x, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ sqlite3_str_appendf(&x, "%.16g", pMem->u.r); @@ -78174,9 +78516,9 @@ SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){ ** of a ReusableSpace object by the allocSpace() routine below. */ struct ReusableSpace { - u8 *pSpace; /* Available memory */ - int nFree; /* Bytes of available memory */ - int nNeeded; /* Total bytes that could not be allocated */ + u8 *pSpace; /* Available memory */ + sqlite3_int64 nFree; /* Bytes of available memory */ + sqlite3_int64 nNeeded; /* Total bytes that could not be allocated */ }; /* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf @@ -78196,7 +78538,7 @@ struct ReusableSpace { static void *allocSpace( struct ReusableSpace *p, /* Bulk memory available for allocation */ void *pBuf, /* Pointer to a prior allocation */ - int nByte /* Bytes of memory needed */ + sqlite3_int64 nByte /* Bytes of memory needed */ ){ assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) ); if( pBuf==0 ){ @@ -79002,7 +79344,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){ } /* Check for immediate foreign key violations. */ - if( p->rc==SQLITE_OK ){ + if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ sqlite3VdbeCheckFk(p, 0); } @@ -79528,6 +79870,8 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){ /* ** Return the serial-type for the value stored in pMem. +** +** This routine might convert a large MEM_IntReal value into MEM_Real. */ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ int flags = pMem->flags; @@ -79538,11 +79882,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ *pLen = 0; return 0; } - if( flags&MEM_Int ){ + if( flags&(MEM_Int|MEM_IntReal) ){ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ # define MAX_6BYTE ((((i64)0x00008000)<<32)-1) i64 i = pMem->u.i; u64 u; + testcase( flags & MEM_Int ); + testcase( flags & MEM_IntReal ); if( i<0 ){ u = ~i; }else{ @@ -79562,6 +79908,15 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ if( u<=2147483647 ){ *pLen = 4; return 4; } if( u<=MAX_6BYTE ){ *pLen = 6; return 5; } *pLen = 8; + if( flags&MEM_IntReal ){ + /* If the value is IntReal and is going to take up 8 bytes to store + ** as an integer, then we might as well make it an 8-byte floating + ** point value */ + pMem->u.r = (double)pMem->u.i; + pMem->flags &= ~MEM_IntReal; + pMem->flags |= MEM_Real; + return 7; + } return 6; } if( flags&MEM_Real ){ @@ -79735,7 +80090,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ ** routine so that in most cases the overhead of moving the stack pointer ** is avoided. */ -static u32 SQLITE_NOINLINE serialGet( +static u32 serialGet( const unsigned char *buf, /* Buffer to deserialize from */ u32 serial_type, /* Serial type to deserialize */ Mem *pMem /* Memory cell to write value into */ @@ -79767,7 +80122,7 @@ static u32 SQLITE_NOINLINE serialGet( assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 ); swapMixedEndianFloat(x); memcpy(&pMem->u.r, &x, sizeof(x)); - pMem->flags = sqlite3IsNaN(pMem->u.r) ? MEM_Null : MEM_Real; + pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real; } return 8; } @@ -80217,8 +80572,13 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C /* At least one of the two values is a number */ - if( combined_flags&(MEM_Int|MEM_Real) ){ - if( (f1 & f2 & MEM_Int)!=0 ){ + if( combined_flags&(MEM_Int|MEM_Real|MEM_IntReal) ){ + testcase( combined_flags & MEM_Int ); + testcase( combined_flags & MEM_Real ); + testcase( combined_flags & MEM_IntReal ); + if( (f1 & f2 & (MEM_Int|MEM_IntReal))!=0 ){ + testcase( f1 & f2 & MEM_Int ); + testcase( f1 & f2 & MEM_IntReal ); if( pMem1->u.i < pMem2->u.i ) return -1; if( pMem1->u.i > pMem2->u.i ) return +1; return 0; @@ -80228,15 +80588,23 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C if( pMem1->u.r > pMem2->u.r ) return +1; return 0; } - if( (f1&MEM_Int)!=0 ){ + if( (f1&(MEM_Int|MEM_IntReal))!=0 ){ + testcase( f1 & MEM_Int ); + testcase( f1 & MEM_IntReal ); if( (f2&MEM_Real)!=0 ){ return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r); + }else if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ + if( pMem1->u.i < pMem2->u.i ) return -1; + if( pMem1->u.i > pMem2->u.i ) return +1; + return 0; }else{ return -1; } } if( (f1&MEM_Real)!=0 ){ - if( (f2&MEM_Int)!=0 ){ + if( (f2&(MEM_Int|MEM_IntReal))!=0 ){ + testcase( f2 & MEM_Int ); + testcase( f2 & MEM_IntReal ); return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r); }else{ return -1; @@ -80385,7 +80753,9 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip( u32 serial_type; /* RHS is an integer */ - if( pRhs->flags & MEM_Int ){ + if( pRhs->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pRhs->flags & MEM_Int ); + testcase( pRhs->flags & MEM_IntReal ); serial_type = aKey1[idx1]; testcase( serial_type==12 ); if( serial_type>=10 ){ @@ -80730,7 +81100,9 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){ testcase( flags & MEM_Real ); testcase( flags & MEM_Null ); testcase( flags & MEM_Blob ); - if( (flags & (MEM_Real|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){ + if( (flags & (MEM_Real|MEM_IntReal|MEM_Null|MEM_Blob))==0 + && p->pKeyInfo->aColl[0]==0 + ){ assert( flags & MEM_Str ); return vdbeRecordCompareString; } @@ -81153,7 +81525,7 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){ assert( p->zSql!=0 ); sqlite3OsCurrentTimeInt64(db->pVfs, &iNow); iElapse = (iNow - p->startTime)*1000000; -#ifndef SQLITE_OMIT_DEPRECATED +#ifndef SQLITE_OMIT_DEPRECATED if( db->xProfile ){ db->xProfile(db->pProfileArg, p->zSql, iElapse); } @@ -81320,39 +81692,86 @@ SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){ */ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){ static const u8 aType[] = { - SQLITE_BLOB, /* 0x00 */ - SQLITE_NULL, /* 0x01 */ - SQLITE_TEXT, /* 0x02 */ - SQLITE_NULL, /* 0x03 */ - SQLITE_INTEGER, /* 0x04 */ - SQLITE_NULL, /* 0x05 */ - SQLITE_INTEGER, /* 0x06 */ - SQLITE_NULL, /* 0x07 */ - SQLITE_FLOAT, /* 0x08 */ - SQLITE_NULL, /* 0x09 */ - SQLITE_FLOAT, /* 0x0a */ - SQLITE_NULL, /* 0x0b */ - SQLITE_INTEGER, /* 0x0c */ - SQLITE_NULL, /* 0x0d */ - SQLITE_INTEGER, /* 0x0e */ - SQLITE_NULL, /* 0x0f */ - SQLITE_BLOB, /* 0x10 */ - SQLITE_NULL, /* 0x11 */ - SQLITE_TEXT, /* 0x12 */ - SQLITE_NULL, /* 0x13 */ - SQLITE_INTEGER, /* 0x14 */ - SQLITE_NULL, /* 0x15 */ - SQLITE_INTEGER, /* 0x16 */ - SQLITE_NULL, /* 0x17 */ - SQLITE_FLOAT, /* 0x18 */ - SQLITE_NULL, /* 0x19 */ - SQLITE_FLOAT, /* 0x1a */ - SQLITE_NULL, /* 0x1b */ - SQLITE_INTEGER, /* 0x1c */ - SQLITE_NULL, /* 0x1d */ - SQLITE_INTEGER, /* 0x1e */ - SQLITE_NULL, /* 0x1f */ + SQLITE_BLOB, /* 0x00 (not possible) */ + SQLITE_NULL, /* 0x01 NULL */ + SQLITE_TEXT, /* 0x02 TEXT */ + SQLITE_NULL, /* 0x03 (not possible) */ + SQLITE_INTEGER, /* 0x04 INTEGER */ + SQLITE_NULL, /* 0x05 (not possible) */ + SQLITE_INTEGER, /* 0x06 INTEGER + TEXT */ + SQLITE_NULL, /* 0x07 (not possible) */ + SQLITE_FLOAT, /* 0x08 FLOAT */ + SQLITE_NULL, /* 0x09 (not possible) */ + SQLITE_FLOAT, /* 0x0a FLOAT + TEXT */ + SQLITE_NULL, /* 0x0b (not possible) */ + SQLITE_INTEGER, /* 0x0c (not possible) */ + SQLITE_NULL, /* 0x0d (not possible) */ + SQLITE_INTEGER, /* 0x0e (not possible) */ + SQLITE_NULL, /* 0x0f (not possible) */ + SQLITE_BLOB, /* 0x10 BLOB */ + SQLITE_NULL, /* 0x11 (not possible) */ + SQLITE_TEXT, /* 0x12 (not possible) */ + SQLITE_NULL, /* 0x13 (not possible) */ + SQLITE_INTEGER, /* 0x14 INTEGER + BLOB */ + SQLITE_NULL, /* 0x15 (not possible) */ + SQLITE_INTEGER, /* 0x16 (not possible) */ + SQLITE_NULL, /* 0x17 (not possible) */ + SQLITE_FLOAT, /* 0x18 FLOAT + BLOB */ + SQLITE_NULL, /* 0x19 (not possible) */ + SQLITE_FLOAT, /* 0x1a (not possible) */ + SQLITE_NULL, /* 0x1b (not possible) */ + SQLITE_INTEGER, /* 0x1c (not possible) */ + SQLITE_NULL, /* 0x1d (not possible) */ + SQLITE_INTEGER, /* 0x1e (not possible) */ + SQLITE_NULL, /* 0x1f (not possible) */ + SQLITE_FLOAT, /* 0x20 INTREAL */ + SQLITE_NULL, /* 0x21 (not possible) */ + SQLITE_TEXT, /* 0x22 INTREAL + TEXT */ + SQLITE_NULL, /* 0x23 (not possible) */ + SQLITE_FLOAT, /* 0x24 (not possible) */ + SQLITE_NULL, /* 0x25 (not possible) */ + SQLITE_FLOAT, /* 0x26 (not possible) */ + SQLITE_NULL, /* 0x27 (not possible) */ + SQLITE_FLOAT, /* 0x28 (not possible) */ + SQLITE_NULL, /* 0x29 (not possible) */ + SQLITE_FLOAT, /* 0x2a (not possible) */ + SQLITE_NULL, /* 0x2b (not possible) */ + SQLITE_FLOAT, /* 0x2c (not possible) */ + SQLITE_NULL, /* 0x2d (not possible) */ + SQLITE_FLOAT, /* 0x2e (not possible) */ + SQLITE_NULL, /* 0x2f (not possible) */ + SQLITE_BLOB, /* 0x30 (not possible) */ + SQLITE_NULL, /* 0x31 (not possible) */ + SQLITE_TEXT, /* 0x32 (not possible) */ + SQLITE_NULL, /* 0x33 (not possible) */ + SQLITE_FLOAT, /* 0x34 (not possible) */ + SQLITE_NULL, /* 0x35 (not possible) */ + SQLITE_FLOAT, /* 0x36 (not possible) */ + SQLITE_NULL, /* 0x37 (not possible) */ + SQLITE_FLOAT, /* 0x38 (not possible) */ + SQLITE_NULL, /* 0x39 (not possible) */ + SQLITE_FLOAT, /* 0x3a (not possible) */ + SQLITE_NULL, /* 0x3b (not possible) */ + SQLITE_FLOAT, /* 0x3c (not possible) */ + SQLITE_NULL, /* 0x3d (not possible) */ + SQLITE_FLOAT, /* 0x3e (not possible) */ + SQLITE_NULL, /* 0x3f (not possible) */ }; +#ifdef SQLITE_DEBUG + { + int eType = SQLITE_BLOB; + if( pVal->flags & MEM_Null ){ + eType = SQLITE_NULL; + }else if( pVal->flags & (MEM_Real|MEM_IntReal) ){ + eType = SQLITE_FLOAT; + }else if( pVal->flags & MEM_Int ){ + eType = SQLITE_INTEGER; + }else if( pVal->flags & MEM_Str ){ + eType = SQLITE_TEXT; + } + assert( eType == aType[pVal->flags&MEM_AffMask] ); + } +#endif return aType[pVal->flags&MEM_AffMask]; } @@ -81361,6 +81780,11 @@ SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){ return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero); } +/* Return true if a parameter value originated from an sqlite3_bind() */ +SQLITE_API int sqlite3_value_frombind(sqlite3_value *pVal){ + return (pVal->flags&MEM_FromBind)!=0; +} + /* Make a copy of an sqlite3_value object */ SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){ @@ -81597,6 +82021,21 @@ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){ sqlite3OomFault(pCtx->pOut->db); } +#ifndef SQLITE_UNTESTABLE +/* Force the INT64 value currently stored as the result to be +** a MEM_IntReal value. See the SQLITE_TESTCTRL_RESULT_INTREAL +** test-control. +*/ +SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context *pCtx){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + if( pCtx->pOut->flags & MEM_Int ){ + pCtx->pOut->flags &= ~MEM_Int; + pCtx->pOut->flags |= MEM_IntReal; + } +} +#endif + + /* ** This function is called after a transaction has been committed. It ** invokes callbacks registered with sqlite3_wal_hook() as required. @@ -82206,10 +82645,10 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){ ** or a constant) then useTypes 2, 3, and 4 return NULL. */ static const void *columnName( - sqlite3_stmt *pStmt, - int N, - const void *(*xFunc)(Mem*), - int useType + sqlite3_stmt *pStmt, /* The statement */ + int N, /* Which column to get the name for */ + int useUtf16, /* True to return the name as UTF16 */ + int useType /* What type of name */ ){ const void *ret; Vdbe *p; @@ -82230,8 +82669,15 @@ static const void *columnName( N += useType*n; sqlite3_mutex_enter(db->mutex); assert( db->mallocFailed==0 ); - ret = xFunc(&p->aColName[N]); - /* A malloc may have failed inside of the xFunc() call. If this +#ifndef SQLITE_OMIT_UTF16 + if( useUtf16 ){ + ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]); + }else +#endif + { + ret = sqlite3_value_text((sqlite3_value*)&p->aColName[N]); + } + /* A malloc may have failed inside of the _text() call. If this ** is the case, clear the mallocFailed flag and return NULL. */ if( db->mallocFailed ){ @@ -82248,13 +82694,11 @@ static const void *columnName( ** statement pStmt. */ SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME); + return columnName(pStmt, N, 0, COLNAME_NAME); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME); + return columnName(pStmt, N, 1, COLNAME_NAME); } #endif @@ -82273,13 +82717,11 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){ ** of the result set of SQL statement pStmt. */ SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE); + return columnName(pStmt, N, 0, COLNAME_DECLTYPE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE); + return columnName(pStmt, N, 1, COLNAME_DECLTYPE); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_DECLTYPE */ @@ -82291,13 +82733,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){ ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE); + return columnName(pStmt, N, 0, COLNAME_DATABASE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE); + return columnName(pStmt, N, 1, COLNAME_DATABASE); } #endif /* SQLITE_OMIT_UTF16 */ @@ -82307,13 +82747,11 @@ SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE); + return columnName(pStmt, N, 0, COLNAME_TABLE); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE); + return columnName(pStmt, N, 1, COLNAME_TABLE); } #endif /* SQLITE_OMIT_UTF16 */ @@ -82323,13 +82761,11 @@ SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){ ** anything else which is not an unambiguous reference to a database column. */ SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN); + return columnName(pStmt, N, 0, COLNAME_COLUMN); } #ifndef SQLITE_OMIT_UTF16 SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){ - return columnName( - pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN); + return columnName(pStmt, N, 1, COLNAME_COLUMN); } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_ENABLE_COLUMN_METADATA */ @@ -82698,6 +83134,14 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){ } /* +** Return 1 if the statement is an EXPLAIN and return 2 if the +** statement is an EXPLAIN QUERY PLAN +*/ +SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){ + return pStmt ? ((Vdbe*)pStmt)->explain : 0; +} + +/* ** Return true if the prepared statement is in need of being reset. */ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ @@ -82878,7 +83322,9 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa }else if( iIdx>=p->pUnpacked->nField ){ *ppValue = (sqlite3_value *)columnNullValue(); }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){ - if( pMem->flags & MEM_Int ){ + if( pMem->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pMem); } } @@ -83197,7 +83643,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( pVar = &p->aVar[idx-1]; if( pVar->flags & MEM_Null ){ sqlite3_str_append(&out, "NULL", 4); - }else if( pVar->flags & MEM_Int ){ + }else if( pVar->flags & (MEM_Int|MEM_IntReal) ){ sqlite3_str_appendf(&out, "%lld", pVar->u.i); }else if( pVar->flags & MEM_Real ){ sqlite3_str_appendf(&out, "%!.15g", pVar->u.r); @@ -83386,12 +83832,20 @@ SQLITE_API int sqlite3_found_count = 0; ** feature is used for test suite validation only and does not appear an ** production builds. ** -** M is an integer between 2 and 4. 2 indicates a ordinary two-way -** branch (I=0 means fall through and I=1 means taken). 3 indicates -** a 3-way branch where the third way is when one of the operands is -** NULL. 4 indicates the OP_Jump instruction which has three destinations -** depending on whether the first operand is less than, equal to, or greater -** than the second. +** M is the type of branch. I is the direction taken for this instance of +** the branch. +** +** M: 2 - two-way branch (I=0: fall-thru 1: jump ) +** 3 - two-way + NULL (I=0: fall-thru 1: jump 2: NULL ) +** 4 - OP_Jump (I=0: jump p1 1: jump p2 2: jump p3) +** +** In other words, if M is 2, then I is either 0 (for fall-through) or +** 1 (for when the branch is taken). If M is 3, the I is 0 for an +** ordinary fall-through, I is 1 if the branch was taken, and I is 2 +** if the result of comparison is NULL. For M=3, I=2 the jump may or +** may not be taken, depending on the SQLITE_JUMPIFNULL flags in p5. +** When M is 4, that means that an OP_Jump is being run. I is 0, 1, or 2 +** depending on if the operands are less than, equal, or greater than. ** ** iSrcLine is the source code line (from the __LINE__ macro) that ** generated the VDBE instruction combined with flag bits. The source @@ -83402,9 +83856,9 @@ SQLITE_API int sqlite3_found_count = 0; ** alternate branch are never taken. If a branch is never taken then ** flags should be 0x06 since only the fall-through approach is allowed. ** -** Bit 0x04 of the flags indicates an OP_Jump opcode that is only +** Bit 0x08 of the flags indicates an OP_Jump opcode that is only ** interested in equal or not-equal. In other words, I==0 and I==2 -** should be treated the same. +** should be treated as equivalent ** ** Since only a line number is retained, not the filename, this macro ** only works for amalgamation builds. But that is ok, since these macros @@ -83428,6 +83882,18 @@ SQLITE_API int sqlite3_found_count = 0; mNever = iSrcLine >> 24; assert( (I & mNever)==0 ); if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/ + /* Invoke the branch coverage callback with three arguments: + ** iSrcLine - the line number of the VdbeCoverage() macro, with + ** flags removed. + ** I - Mask of bits 0x07 indicating which cases are are + ** fulfilled by this instance of the jump. 0x01 means + ** fall-thru, 0x02 means taken, 0x04 means NULL. Any + ** impossible cases (ex: if the comparison is never NULL) + ** are filled in automatically so that the coverage + ** measurement logic does not flag those impossible cases + ** as missed coverage. + ** M - Type of jump. Same as M argument above + */ I |= mNever; if( M==2 ) I |= 0x04; if( M==4 ){ @@ -83440,14 +83906,6 @@ SQLITE_API int sqlite3_found_count = 0; #endif /* -** Convert the given register into a string if it isn't one -** already. Return non-zero if a malloc() fails. -*/ -#define Stringify(P, enc) \ - if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \ - { goto no_mem; } - -/* ** An ephemeral string value (signified by the MEM_Ephem flag) contains ** a pointer to a dynamically allocated string where some other entity ** is responsible for deallocating that string. Because the register @@ -83508,7 +83966,7 @@ static VdbeCursor *allocateCursor( ** is clear. Otherwise, if this is an ephemeral cursor created by ** OP_OpenDup, the cursor will not be closed and will still be part ** of a BtShared.pCursor list. */ - p->apCsr[iCur]->isEphemeral = 0; + if( p->apCsr[iCur]->pBtx==0 ) p->apCsr[iCur]->isEphemeral = 0; sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } @@ -83529,6 +83987,21 @@ static VdbeCursor *allocateCursor( } /* +** The string in pRec is known to look like an integer and to have a +** floating point value of rValue. Return true and set *piValue to the +** integer value if the string is in range to be an integer. Otherwise, +** return false. +*/ +static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){ + i64 iValue = (double)rValue; + if( sqlite3RealSameAsInt(rValue,iValue) ){ + *piValue = iValue; + return 1; + } + return 0==sqlite3Atoi64(pRec->z, piValue, pRec->n, pRec->enc); +} + +/* ** Try to convert a value into a numeric representation if we can ** do so without loss of information. In other words, if the string ** looks like a number, convert it into a number. If it does not @@ -83545,12 +84018,12 @@ static VdbeCursor *allocateCursor( */ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ double rValue; - i64 iValue; u8 enc = pRec->enc; - assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str ); - if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; - if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ - pRec->u.i = iValue; + int rc; + assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str ); + rc = sqlite3AtoF(pRec->z, &rValue, pRec->n, enc); + if( rc<=0 ) return; + if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){ pRec->flags |= MEM_Int; }else{ pRec->u.r = rValue; @@ -83604,11 +84077,14 @@ static void applyAffinity( ** there is already a string rep, but it is pointless to waste those ** CPU cycles. */ if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/ - if( (pRec->flags&(MEM_Real|MEM_Int)) ){ + if( (pRec->flags&(MEM_Real|MEM_Int|MEM_IntReal)) ){ + testcase( pRec->flags & MEM_Int ); + testcase( pRec->flags & MEM_Real ); + testcase( pRec->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pRec, enc, 1); } } - pRec->flags &= ~(MEM_Real|MEM_Int); + pRec->flags &= ~(MEM_Real|MEM_Int|MEM_IntReal); } } @@ -83647,13 +84123,21 @@ SQLITE_PRIVATE void sqlite3ValueApplyAffinity( ** accordingly. */ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ - assert( (pMem->flags & (MEM_Int|MEM_Real))==0 ); + int rc; + sqlite3_int64 ix; + assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ); assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); ExpandBlob(pMem); - if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){ - return 0; - } - if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){ + rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + if( rc<=0 ){ + if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ + pMem->u.i = ix; + return MEM_Int; + }else{ + return MEM_Real; + } + }else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){ + pMem->u.i = ix; return MEM_Int; } return MEM_Real; @@ -83667,10 +84151,15 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ ** But it does set pMem->u.r and pMem->u.i appropriately. */ static u16 numericType(Mem *pMem){ - if( pMem->flags & (MEM_Int|MEM_Real) ){ - return pMem->flags & (MEM_Int|MEM_Real); + if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){ + testcase( pMem->flags & MEM_Int ); + testcase( pMem->flags & MEM_Real ); + testcase( pMem->flags & MEM_IntReal ); + return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal); } if( pMem->flags & (MEM_Str|MEM_Blob) ){ + testcase( pMem->flags & MEM_Str ); + testcase( pMem->flags & MEM_Blob ); return computeNumericType(pMem); } return 0; @@ -83766,6 +84255,8 @@ static void memTracePrint(Mem *p){ printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL"); }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ printf(" si:%lld", p->u.i); + }else if( (p->flags & (MEM_IntReal))!=0 ){ + printf(" ir:%lld", p->u.i); }else if( p->flags & MEM_Int ){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT @@ -83975,6 +84466,15 @@ SQLITE_PRIVATE int sqlite3VdbeExec( assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ sqlite3VdbeEnter(p); +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + if( db->xProgress ){ + u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; + assert( 0 < db->nProgressOps ); + nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); + }else{ + nProgressLimit = 0xffffffff; + } +#endif if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ @@ -83988,15 +84488,6 @@ SQLITE_PRIVATE int sqlite3VdbeExec( db->busyHandler.nBusy = 0; if( db->u1.isInterrupted ) goto abort_due_to_interrupt; sqlite3VdbeIOTraceSql(p); -#ifndef SQLITE_OMIT_PROGRESS_CALLBACK - if( db->xProgress ){ - u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP]; - assert( 0 < db->nProgressOps ); - nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps); - }else{ - nProgressLimit = 0xffffffff; - } -#endif #ifdef SQLITE_DEBUG sqlite3BeginBenignMalloc(); if( p->pc==0 @@ -84172,10 +84663,11 @@ check_for_interrupt: ** If the progress callback returns non-zero, exit the virtual machine with ** a return code SQLITE_ABORT. */ - if( nVmStep>=nProgressLimit && db->xProgress!=0 ){ + while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ assert( db->nProgressOps!=0 ); - nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps); + nProgressLimit += db->nProgressOps; if( db->xProgress(db->pProgressArg) ){ + nProgressLimit = 0xffffffff; rc = SQLITE_INTERRUPT; goto abort_due_to_error; } @@ -84454,6 +84946,7 @@ case OP_String8: { /* same as TK_STRING, out2 */ if( encoding!=SQLITE_UTF8 ){ rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC); assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG ); + if( rc ) goto too_big; if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem; assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z ); assert( VdbeMemDynamic(pOut)==0 ); @@ -84466,7 +84959,6 @@ case OP_String8: { /* same as TK_STRING, out2 */ pOp->p4.z = pOut->z; pOp->p1 = pOut->n; } - testcase( rc==SQLITE_TOOBIG ); #endif if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; @@ -84588,7 +85080,10 @@ case OP_Variable: { /* out2 */ goto too_big; } pOut = &aMem[pOp->p2]; - sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static); + if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut); + memcpy(pOut, pVar, MEMCELLSIZE); + pOut->flags &= ~(MEM_Dyn|MEM_Ephem); + pOut->flags |= MEM_Static|MEM_FromBind; UPDATE_MAX_BLOBSIZE(pOut); break; } @@ -84721,18 +85216,6 @@ case OP_ResultRow: { assert( pOp->p1>0 ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); -#ifndef SQLITE_OMIT_PROGRESS_CALLBACK - /* Run the progress counter just before returning. - */ - if( db->xProgress!=0 - && nVmStep>=nProgressLimit - && db->xProgress(db->pProgressArg)!=0 - ){ - rc = SQLITE_INTERRUPT; - goto abort_due_to_error; - } -#endif - /* If this statement has violated immediate foreign key constraints, do ** not return the number of rows modified. And do not RELEASE the statement ** transaction. It needs to be rolled back. */ @@ -84804,33 +85287,57 @@ case OP_ResultRow: { ** to avoid a memcpy(). */ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ - i64 nByte; + i64 nByte; /* Total size of the output string or blob */ + u16 flags1; /* Initial flags for P1 */ + u16 flags2; /* Initial flags for P2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; pOut = &aMem[pOp->p3]; + testcase( pIn1==pIn2 ); + testcase( pOut==pIn2 ); assert( pIn1!=pOut ); - if( (pIn1->flags | pIn2->flags) & MEM_Null ){ + flags1 = pIn1->flags; + testcase( flags1 & MEM_Null ); + testcase( pIn2->flags & MEM_Null ); + if( (flags1 | pIn2->flags) & MEM_Null ){ sqlite3VdbeMemSetNull(pOut); break; } - if( ExpandBlob(pIn1) || ExpandBlob(pIn2) ) goto no_mem; - Stringify(pIn1, encoding); - Stringify(pIn2, encoding); + if( (flags1 & (MEM_Str|MEM_Blob))==0 ){ + if( sqlite3VdbeMemStringify(pIn1,encoding,0) ) goto no_mem; + flags1 = pIn1->flags & ~MEM_Str; + }else if( (flags1 & MEM_Zero)!=0 ){ + if( sqlite3VdbeMemExpandBlob(pIn1) ) goto no_mem; + flags1 = pIn1->flags & ~MEM_Str; + } + flags2 = pIn2->flags; + if( (flags2 & (MEM_Str|MEM_Blob))==0 ){ + if( sqlite3VdbeMemStringify(pIn2,encoding,0) ) goto no_mem; + flags2 = pIn2->flags & ~MEM_Str; + }else if( (flags2 & MEM_Zero)!=0 ){ + if( sqlite3VdbeMemExpandBlob(pIn2) ) goto no_mem; + flags2 = pIn2->flags & ~MEM_Str; + } nByte = pIn1->n + pIn2->n; if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } - if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){ + if( sqlite3VdbeMemGrow(pOut, (int)nByte+3, pOut==pIn2) ){ goto no_mem; } MemSetTypeFlag(pOut, MEM_Str); if( pOut!=pIn2 ){ memcpy(pOut->z, pIn2->z, pIn2->n); + assert( (pIn2->flags & MEM_Dyn) == (flags2 & MEM_Dyn) ); + pIn2->flags = flags2; } memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); + assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); + pIn1->flags = flags1; pOut->z[nByte]=0; pOut->z[nByte+1] = 0; + pOut->z[nByte+2] = 0; pOut->flags |= MEM_Term; pOut->n = (int)nByte; pOut->enc = encoding; @@ -84881,7 +85388,6 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */ case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ - char bIntint; /* Started out as two integer operands */ u16 flags; /* Combined MEM_* flags from both inputs */ u16 type1; /* Numeric type of left operand */ u16 type2; /* Numeric type of right operand */ @@ -84899,7 +85405,6 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ if( (type1 & type2 & MEM_Int)!=0 ){ iA = pIn1->u.i; iB = pIn2->u.i; - bIntint = 1; switch( pOp->opcode ){ case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break; case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break; @@ -84922,7 +85427,6 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */ }else if( (flags & MEM_Null)!=0 ){ goto arithmetic_result_is_null; }else{ - bIntint = 0; fp_math: rA = sqlite3VdbeRealValue(pIn1); rB = sqlite3VdbeRealValue(pIn2); @@ -84954,9 +85458,6 @@ fp_math: } pOut->u.r = rB; MemSetTypeFlag(pOut, MEM_Real); - if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ - sqlite3VdbeIntegerAffinity(pOut); - } #endif } break; @@ -85098,8 +85599,8 @@ case OP_MustBeInt: { /* jump, in1 */ pIn1 = &aMem[pOp->p1]; if( (pIn1->flags & MEM_Int)==0 ){ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding); - VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2); if( (pIn1->flags & MEM_Int)==0 ){ + VdbeBranchTaken(1, 2); if( pOp->p2==0 ){ rc = SQLITE_MISMATCH; goto abort_due_to_error; @@ -85108,6 +85609,7 @@ case OP_MustBeInt: { /* jump, in1 */ } } } + VdbeBranchTaken(0, 2); MemSetTypeFlag(pIn1, MEM_Int); break; } @@ -85124,7 +85626,9 @@ case OP_MustBeInt: { /* jump, in1 */ */ case OP_RealAffinity: { /* in1 */ pIn1 = &aMem[pOp->p1]; - if( pIn1->flags & MEM_Int ){ + if( pIn1->flags & (MEM_Int|MEM_IntReal) ){ + testcase( pIn1->flags & MEM_Int ); + testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemRealify(pIn1); } break; @@ -85282,7 +85786,6 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ ** OP_Eq or OP_Ne) then take the jump or not depending on whether ** or not both operands are null. */ - assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne ); assert( (flags1 & MEM_Cleared)==0 ); assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 || CORRUPT_DB ); testcase( (pOp->p5 & SQLITE_JUMPIFNULL)!=0 ); @@ -85291,7 +85794,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ ){ res = 0; /* Operands are equal */ }else{ - res = 1; /* Operands are not equal */ + res = ((flags3 & MEM_Null) ? -1 : +1); /* Operands are not equal */ } }else{ /* SQLITE_NULLEQ is clear and at least one operand is NULL, @@ -85317,7 +85820,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ - if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); assert( flags3==pIn3->flags ); /* testcase( flags3!=pIn3->flags ); @@ -85327,7 +85830,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ ** in case our analysis is incorrect, so it is left in. */ flags3 = pIn3->flags; } - if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } @@ -85340,17 +85843,19 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ goto compare_op; } }else if( affinity==SQLITE_AFF_TEXT ){ - if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){ + if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); + testcase( pIn1->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); assert( pIn1!=pIn3 ); } - if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){ + if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); + testcase( pIn3->flags & MEM_IntReal ); sqlite3VdbeMemStringify(pIn3, encoding, 1); testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) ); flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask); @@ -85409,7 +85914,7 @@ compare_op: pOut->u.i = res2; REGISTER_TRACE(pOp->p2, pOut); }else{ - VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); + VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); if( res2 ){ goto jump_to_p2; } @@ -85959,15 +86464,15 @@ case OP_Column: { zEndHdr = zData + aOffset[0]; testcase( zHdr>=zEndHdr ); do{ - if( (t = zHdr[0])<0x80 ){ + if( (pC->aType[i] = t = zHdr[0])<0x80 ){ zHdr++; offset64 += sqlite3VdbeOneByteSerialTypeLen(t); }else{ zHdr += sqlite3GetVarint32(zHdr, &t); + pC->aType[i] = t; offset64 += sqlite3VdbeSerialTypeLen(t); } - pC->aType[i++] = t; - aOffset[i] = (u32)(offset64 & 0xffffffff); + aOffset[++i] = (u32)(offset64 & 0xffffffff); }while( i<=p2 && zHdr<zEndHdr ); /* The record is corrupt if any of the following are true: @@ -86106,12 +86611,21 @@ case OP_Affinity: { assert( pOp->p2>0 ); assert( zAffinity[pOp->p2]==0 ); pIn1 = &aMem[pOp->p1]; - do{ + while( 1 /*edit-by-break*/ ){ assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] ); assert( memIsValid(pIn1) ); - applyAffinity(pIn1, *(zAffinity++), encoding); + applyAffinity(pIn1, zAffinity[0], encoding); + if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){ + /* When applying REAL affinity, if the result is still MEM_Int, + ** indicate that REAL is actually desired */ + pIn1->flags |= MEM_IntReal; + pIn1->flags &= ~MEM_Int; + } + REGISTER_TRACE((int)(pIn1-aMem), pIn1); + zAffinity++; + if( zAffinity[0]==0 ) break; pIn1++; - }while( zAffinity[0] ); + } break; } @@ -86132,7 +86646,6 @@ case OP_Affinity: { ** If P4 is NULL then all index fields have the affinity BLOB. */ case OP_MakeRecord: { - u8 *zNewRecord; /* A buffer to hold the data for the new record */ Mem *pRec; /* The new record */ u64 nData; /* Number of bytes of data space */ int nHdr; /* Number of bytes of header space */ @@ -86145,9 +86658,9 @@ case OP_MakeRecord: { int nField; /* Number of fields in the record */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ - int i; /* Space used in zNewRecord[] header */ - int j; /* Space used in zNewRecord[] content */ u32 len; /* Length of a field */ + u8 *zHdr; /* Where to write next byte of the header */ + u8 *zPayload; /* Where to write next byte of the payload */ /* Assuming the record contains N fields, the record format looks ** like this: @@ -86186,7 +86699,14 @@ case OP_MakeRecord: { if( zAffinity ){ pRec = pData0; do{ - applyAffinity(pRec++, *(zAffinity++), encoding); + applyAffinity(pRec, zAffinity[0], encoding); + if( zAffinity[0]==SQLITE_AFF_REAL && (pRec->flags & MEM_Int) ){ + pRec->flags |= MEM_IntReal; + pRec->flags &= ~(MEM_Int); + } + REGISTER_TRACE((int)(pRec-aMem), pRec); + zAffinity++; + pRec++; assert( zAffinity[0]==0 || pRec<=pLast ); }while( zAffinity[0] ); } @@ -86274,34 +86794,34 @@ case OP_MakeRecord: { goto no_mem; } } - zNewRecord = (u8 *)pOut->z; + pOut->n = (int)nByte; + pOut->flags = MEM_Blob; + if( nZero ){ + pOut->u.nZero = nZero; + pOut->flags |= MEM_Zero; + } + UPDATE_MAX_BLOBSIZE(pOut); + zHdr = (u8 *)pOut->z; + zPayload = zHdr + nHdr; /* Write the record */ - i = putVarint32(zNewRecord, nHdr); - j = nHdr; + zHdr += putVarint32(zHdr, nHdr); assert( pData0<=pLast ); pRec = pData0; do{ serial_type = pRec->uTemp; /* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more ** additional varints, one per column. */ - i += putVarint32(&zNewRecord[i], serial_type); /* serial type */ + zHdr += putVarint32(zHdr, serial_type); /* serial type */ /* EVIDENCE-OF: R-64536-51728 The values for each column in the record ** immediately follow the header. */ - j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */ + zPayload += sqlite3VdbeSerialPut(zPayload, pRec, serial_type); /* content */ }while( (++pRec)<=pLast ); - assert( i==nHdr ); - assert( j==nByte ); + assert( nHdr==(int)(zHdr - (u8*)pOut->z) ); + assert( nByte==(int)(zPayload - (u8*)pOut->z) ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); - pOut->n = (int)nByte; - pOut->flags = MEM_Blob; - if( nZero ){ - pOut->u.nZero = nZero; - pOut->flags |= MEM_Zero; - } REGISTER_TRACE(pOp->p3, pOut); - UPDATE_MAX_BLOBSIZE(pOut); break; } @@ -86331,8 +86851,9 @@ case OP_Count: { /* out2 */ /* Opcode: Savepoint P1 * * P4 * ** ** Open, release or rollback the savepoint named by parameter P4, depending -** on the value of P1. To open a new savepoint, P1==0. To release (commit) an -** existing savepoint, P1==1, or to rollback an existing savepoint P1==2. +** on the value of P1. To open a new savepoint set P1==0 (SAVEPOINT_BEGIN). +** To release (commit) an existing savepoint set P1==1 (SAVEPOINT_RELEASE). +** To rollback an existing savepoint set P1==2 (SAVEPOINT_ROLLBACK). */ case OP_Savepoint: { int p1; /* Value of P1 operand */ @@ -86400,6 +86921,7 @@ case OP_Savepoint: { } } }else{ + assert( p1==SAVEPOINT_RELEASE || p1==SAVEPOINT_ROLLBACK ); iSavepoint = 0; /* Find the named savepoint. If there is no such savepoint, then an @@ -86453,6 +86975,7 @@ case OP_Savepoint: { if( rc!=SQLITE_OK ) goto abort_due_to_error; } }else{ + assert( p1==SAVEPOINT_RELEASE ); isSchemaChange = 0; } for(ii=0; ii<db->nDb; ii++){ @@ -86489,6 +87012,7 @@ case OP_Savepoint: { db->nSavepoint--; } }else{ + assert( p1==SAVEPOINT_ROLLBACK ); db->nDeferredCons = pSavepoint->nDeferredCons; db->nDeferredImmCons = pSavepoint->nDeferredImmCons; } @@ -86970,6 +87494,7 @@ case OP_OpenDup: { pCx->pKeyInfo = pOrig->pKeyInfo; pCx->isTable = pOrig->isTable; pCx->pgnoRoot = pOrig->pgnoRoot; + pCx->isOrdered = pOrig->isOrdered; rc = sqlite3BtreeCursor(pOrig->pBtx, pCx->pgnoRoot, BTREE_WRCSR, pCx->pKeyInfo, pCx->uc.pCursor); /* The sqlite3BtreeCursor() routine can only fail for the first cursor @@ -87026,11 +87551,15 @@ case OP_OpenEphemeral: { if( pCx ){ /* If the ephermeral table is already open, erase all existing content ** so that the table is empty again, rather than creating a new table. */ - rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0); + assert( pCx->isEphemeral ); + pCx->seqCount = 0; + pCx->cacheStatus = CACHE_STALE; + if( pCx->pBtx ){ + rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0); + } }else{ pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE); if( pCx==0 ) goto no_mem; - pCx->nullRow = 1; pCx->isEphemeral = 1; rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx, BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, @@ -87066,6 +87595,7 @@ case OP_OpenEphemeral: { pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); } if( rc ) goto abort_due_to_error; + pCx->nullRow = 1; break; } @@ -87294,6 +87824,8 @@ case OP_SeekGT: { /* jump, in3, group */ pC->seekOp = pOp->opcode; #endif + pC->deferredMoveto = 0; + pC->cacheStatus = CACHE_STALE; if( pC->isTable ){ /* The BTREE_SEEK_EQ flag is only set on index cursors */ assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 @@ -87303,20 +87835,24 @@ case OP_SeekGT: { /* jump, in3, group */ ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; - if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ + if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3, 0); } iKey = sqlite3VdbeIntValue(pIn3); /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ - if( (pIn3->flags & MEM_Int)==0 ){ + if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){ if( (pIn3->flags & MEM_Real)==0 ){ - /* If the P3 value cannot be converted into any kind of a number, - ** then the seek is not possible, so jump to P2 */ - VdbeBranchTaken(1,2); goto jump_to_p2; - break; - } + if( (pIn3->flags & MEM_Null) || oc>=OP_SeekGE ){ + VdbeBranchTaken(1,2); goto jump_to_p2; + break; + }else{ + rc = sqlite3BtreeLast(pC->uc.pCursor, &res); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + goto seek_not_found; + } + }else /* If the approximation iKey is larger than the actual real search ** term, substitute >= for > and < for <=. e.g. if the search term @@ -87340,7 +87876,7 @@ case OP_SeekGT: { /* jump, in3, group */ assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) ); if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++; } - } + } rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ if( rc!=SQLITE_OK ){ @@ -87394,8 +87930,6 @@ case OP_SeekGT: { /* jump, in3, group */ goto seek_not_found; } } - pC->deferredMoveto = 0; - pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_TEST sqlite3_search_count++; #endif @@ -87695,7 +88229,9 @@ case OP_SeekRowid: { /* jump, in3 */ u64 iKey; pIn3 = &aMem[pOp->p3]; - if( (pIn3->flags & MEM_Int)==0 ){ + testcase( pIn3->flags & MEM_Int ); + testcase( pIn3->flags & MEM_IntReal ); + if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){ /* Make sure pIn3->u.i contains a valid integer representation of ** the key value, but do not change the datatype of the register, as ** other parts of the perpared statement might be depending on the @@ -88070,7 +88606,7 @@ case OP_Delete: { ** OP_Delete will have also set the pC->movetoTarget field to the rowid of ** the row that is being deleted */ i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor); - assert( pC->movetoTarget==iKey ); + assert( CORRUPT_DB || pC->movetoTarget==iKey ); } #endif @@ -88478,7 +89014,7 @@ case OP_Sort: { /* jump */ p->aCounter[SQLITE_STMTSTATUS_SORT]++; /* Fall through into OP_Rewind */ } -/* Opcode: Rewind P1 P2 * * P5 +/* Opcode: Rewind P1 P2 * * * ** ** The next use of the Rowid or Column or Next instruction for P1 ** will refer to the first entry in the database table or index. @@ -88486,10 +89022,6 @@ case OP_Sort: { /* jump */ ** If the table or index is not empty, fall through to the following ** instruction. ** -** If P5 is non-zero and the table is not empty, then the "skip-next" -** flag is set on the cursor so that the next OP_Next instruction -** executed on it is a no-op. -** ** This opcode leaves the cursor configured to move in forward order, ** from the beginning toward the end. In other words, the cursor is ** configured to use Next, not Prev. @@ -88500,6 +89032,7 @@ case OP_Rewind: { /* jump */ int res; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); + assert( pOp->p5==0 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) ); @@ -88514,9 +89047,6 @@ case OP_Rewind: { /* jump */ pCrsr = pC->uc.pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); -#ifndef SQLITE_OMIT_WINDOWFUNC - if( pOp->p5 ) sqlite3BtreeSkipNext(pCrsr); -#endif pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } @@ -89526,8 +90056,7 @@ case OP_Program: { /* jump */ } #endif pOp = &aOp[-1]; - - break; + goto check_for_interrupt; } /* Opcode: Param P1 P2 * * * @@ -89899,6 +90428,7 @@ case OP_AggFinal: { assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 ); #ifndef SQLITE_OMIT_WINDOWFUNC if( pOp->p3 ){ + memAboutToChange(p, &aMem[pOp->p3]); rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc); pMem = &aMem[pOp->p3]; }else @@ -90936,7 +91466,16 @@ abort_due_to_error: ** release the mutexes on btrees that were acquired at the ** top. */ vdbe_return: - testcase( nVmStep>0 ); +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + while( nVmStep>=nProgressLimit && db->xProgress!=0 ){ + nProgressLimit += db->nProgressOps; + if( db->xProgress(db->pProgressArg) ){ + nProgressLimit = 0xffffffff; + rc = SQLITE_INTERRUPT; + goto abort_due_to_error; + } + } +#endif p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep; sqlite3VdbeLeave(p); assert( rc!=SQLITE_OK || nExtraDelete==0 @@ -92023,7 +92562,7 @@ static int vdbePmaReadBlob( /* Extend the p->aAlloc[] allocation if required. */ if( p->nAlloc<nByte ){ u8 *aNew; - int nNew = MAX(128, p->nAlloc*2); + sqlite3_int64 nNew = MAX(128, 2*(sqlite3_int64)p->nAlloc); while( nByte>nNew ) nNew = nNew*2; aNew = sqlite3Realloc(p->aAlloc, nNew); if( !aNew ) return SQLITE_NOMEM_BKPT; @@ -93314,15 +93853,19 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite( if( nMin>pSorter->nMemory ){ u8 *aNew; - int iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory; - int nNew = pSorter->nMemory * 2; + sqlite3_int64 nNew = 2 * (sqlite3_int64)pSorter->nMemory; + int iListOff = -1; + if( pSorter->list.pList ){ + iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory; + } while( nNew < nMin ) nNew = nNew*2; if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize; if( nNew < nMin ) nNew = nMin; - aNew = sqlite3Realloc(pSorter->list.aMemory, nNew); if( !aNew ) return SQLITE_NOMEM_BKPT; - pSorter->list.pList = (SorterRecord*)&aNew[iListOff]; + if( iListOff>=0 ){ + pSorter->list.pList = (SorterRecord*)&aNew[iListOff]; + } pSorter->list.aMemory = aNew; pSorter->nMemory = nNew; } @@ -95023,6 +95566,23 @@ SQLITE_PRIVATE int sqlite3MatchSpanName( } /* +** Return TRUE if the double-quoted string mis-feature should be supported. +*/ +static int areDoubleQuotedStringsEnabled(sqlite3 *db, NameContext *pTopNC){ + if( db->init.busy ) return 1; /* Always support for legacy schemas */ + if( pTopNC->ncFlags & NC_IsDDL ){ + /* Currently parsing a DDL statement */ + if( sqlite3WritableSchema(db) && (db->flags & SQLITE_DqsDML)!=0 ){ + return 1; + } + return (db->flags & SQLITE_DqsDDL)!=0; + }else{ + /* Currently parsing a DML statement */ + return (db->flags & SQLITE_DqsDML)!=0; + } +} + +/* ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up ** that name in the set of source tables in pSrcList and make the pExpr ** expression node refer back to that source column. The following changes @@ -95309,6 +95869,10 @@ static int lookupName( sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs); return WRC_Abort; } + if( (pNC->ncFlags&NC_AllowWin)==0 && ExprHasProperty(pOrig, EP_Win) ){ + sqlite3ErrorMsg(pParse, "misuse of aliased window function %s",zAs); + return WRC_Abort; + } if( sqlite3ExprVectorSize(pOrig)!=1 ){ sqlite3ErrorMsg(pParse, "row value misused"); return WRC_Abort; @@ -95346,7 +95910,9 @@ static int lookupName( */ if( cnt==0 && zTab==0 ){ assert( pExpr->op==TK_ID ); - if( ExprHasProperty(pExpr,EP_DblQuoted) ){ + if( ExprHasProperty(pExpr,EP_DblQuoted) + && areDoubleQuotedStringsEnabled(db, pTopNC) + ){ /* If a double-quoted identifier does not match any known column name, ** then treat it as a string. ** @@ -95599,6 +96165,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ const char *zId; /* The function name. */ FuncDef *pDef; /* Information about the function */ u8 enc = ENC(pParse->db); /* The database encoding */ + int savedAllowFlags = (pNC->ncFlags & (NC_AllowAgg | NC_AllowWin)); assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); zId = pExpr->u.zToken; @@ -95614,7 +96181,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ }else{ is_agg = pDef->xFinalize!=0; if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ - ExprSetProperty(pExpr, EP_Unlikely|EP_Skip); + ExprSetProperty(pExpr, EP_Unlikely); if( n==2 ){ pExpr->iTable = exprProbability(pList->a[1].pExpr); if( pExpr->iTable<0 ){ @@ -95720,8 +96287,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pNC->nErr++; } if( is_agg ){ + /* Window functions may not be arguments of aggregate functions. + ** Or arguments of other window functions. But aggregate functions + ** may be arguments for window functions. */ #ifndef SQLITE_OMIT_WINDOWFUNC - pNC->ncFlags &= ~(pExpr->y.pWin ? NC_AllowWin : NC_AllowAgg); + pNC->ncFlags &= ~(NC_AllowWin | (!pExpr->y.pWin ? NC_AllowAgg : 0)); #else pNC->ncFlags &= ~NC_AllowAgg; #endif @@ -95732,7 +96302,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #ifndef SQLITE_OMIT_WINDOWFUNC if( pExpr->y.pWin ){ Select *pSel = pNC->pWinSelect; - sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->y.pWin, pDef); + if( IN_RENAME_OBJECT==0 ){ + sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->y.pWin, pDef); + } sqlite3WalkExprList(pWalker, pExpr->y.pWin->pPartition); sqlite3WalkExprList(pWalker, pExpr->y.pWin->pOrderBy); sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter); @@ -95742,7 +96314,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pExpr->y.pWin->pNextWin = pSel->pWin; pSel->pWin = pExpr->y.pWin; } - pNC->ncFlags |= NC_AllowWin; + pNC->ncFlags |= NC_HasWin; }else #endif /* SQLITE_OMIT_WINDOWFUNC */ { @@ -95760,8 +96332,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); } - pNC->ncFlags |= NC_AllowAgg; } + pNC->ncFlags |= savedAllowFlags; } /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function @@ -95792,11 +96364,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } case TK_IS: case TK_ISNOT: { - Expr *pRight; + Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); assert( !ExprHasProperty(pExpr, EP_Reduced) ); /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE", ** and "x IS NOT FALSE". */ - if( (pRight = pExpr->pRight)->op==TK_ID ){ + if( pRight->op==TK_ID ){ int rc = resolveExprStep(pWalker, pRight); if( rc==WRC_Abort ) return WRC_Abort; if( pRight->op==TK_TRUEFALSE ){ @@ -96298,7 +96870,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ */ for(i=0; i<p->pSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; - if( pItem->pSelect ){ + if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ NameContext *pNC; /* Used to iterate name contexts */ int nRef = 0; /* Refcount for pOuterNC and outer contexts */ const char *zSavedContext = pParse->zAuthContext; @@ -96430,6 +97002,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ } } +#ifndef SQLITE_OMIT_WINDOWFUNC if( IN_RENAME_OBJECT ){ Window *pWin; for(pWin=p->pWinDefn; pWin; pWin=pWin->pNextWin){ @@ -96440,6 +97013,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ } } } +#endif /* If this is part of a compound SELECT, check that it has the right ** number of expressions in the select list. */ @@ -96516,12 +97090,12 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( NameContext *pNC, /* Namespace to resolve expressions in. */ Expr *pExpr /* The expression to be analyzed. */ ){ - u16 savedHasAgg; + int savedHasAgg; Walker w; if( pExpr==0 ) return SQLITE_OK; - savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg); - pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg); + savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin); + pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin); w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = resolveSelectStep; @@ -96537,9 +97111,11 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames( #if SQLITE_MAX_EXPR_DEPTH>0 w.pParse->nHeight -= pExpr->nHeight; #endif - if( pNC->ncFlags & NC_HasAgg ){ - ExprSetProperty(pExpr, EP_Agg); - } + assert( EP_Agg==NC_HasAgg ); + assert( EP_Win==NC_HasWin ); + testcase( pNC->ncFlags & NC_HasAgg ); + testcase( pNC->ncFlags & NC_HasWin ); + ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) ); pNC->ncFlags |= savedHasAgg; return pNC->nErr>0 || w.pParse->nErr>0; } @@ -96628,7 +97204,7 @@ SQLITE_PRIVATE int sqlite3ResolveSelfReference( } sNC.pParse = pParse; sNC.pSrcList = &sSrc; - sNC.ncFlags = type; + sNC.ncFlags = type | NC_IsDDL; if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc; if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList); return rc; @@ -96682,8 +97258,12 @@ SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){ */ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){ int op; - pExpr = sqlite3ExprSkipCollate(pExpr); if( pExpr->flags & EP_Generic ) return 0; + while( ExprHasProperty(pExpr, EP_Skip) ){ + assert( pExpr->op==TK_COLLATE ); + pExpr = pExpr->pLeft; + assert( pExpr!=0 ); + } op = pExpr->op; if( op==TK_SELECT ){ assert( pExpr->flags&EP_xIsSelect ); @@ -96744,7 +97324,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, con ** or likelihood() function at the root of an expression. */ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){ - while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){ + while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){ if( ExprHasProperty(pExpr, EP_Unlikely) ){ assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); assert( pExpr->x.pList->nExpr>0 ); @@ -97411,7 +97991,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( pNew->iAgg = -1; if( pToken ){ if( nExtra==0 ){ - pNew->flags |= EP_IntValue|EP_Leaf; + pNew->flags |= EP_IntValue|EP_Leaf|(iValue?EP_IsTrue:EP_IsFalse); pNew->u.iValue = iValue; }else{ pNew->u.zToken = (char*)&pNew[1]; @@ -97488,20 +98068,16 @@ SQLITE_PRIVATE Expr *sqlite3PExpr( Expr *pRight /* Right operand */ ){ Expr *p; - if( op==TK_AND && pParse->nErr==0 && !IN_RENAME_OBJECT ){ - /* Take advantage of short-circuit false optimization for AND */ - p = sqlite3ExprAnd(pParse->db, pLeft, pRight); - }else{ - p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)); - if( p ){ - memset(p, 0, sizeof(Expr)); - p->op = op & TKFLG_MASK; - p->iAgg = -1; - } + p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)); + if( p ){ + memset(p, 0, sizeof(Expr)); + p->op = op & 0xff; + p->iAgg = -1; sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight); - } - if( p ) { sqlite3ExprCheckHeight(pParse, p->nHeight); + }else{ + sqlite3ExprDelete(pParse->db, pLeft); + sqlite3ExprDelete(pParse->db, pRight); } return p; } @@ -97523,33 +98099,6 @@ SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pS /* -** If the expression is always either TRUE or FALSE (respectively), -** then return 1. If one cannot determine the truth value of the -** expression at compile-time return 0. -** -** This is an optimization. If is OK to return 0 here even if -** the expression really is always false or false (a false negative). -** But it is a bug to return 1 if the expression might have different -** boolean values in different circumstances (a false positive.) -** -** Note that if the expression is part of conditional for a -** LEFT JOIN, then we cannot determine at compile-time whether or not -** is it true or false, so always return 0. -*/ -static int exprAlwaysTrue(Expr *p){ - int v = 0; - if( ExprHasProperty(p, EP_FromJoin) ) return 0; - if( !sqlite3ExprIsInteger(p, &v) ) return 0; - return v!=0; -} -static int exprAlwaysFalse(Expr *p){ - int v = 0; - if( ExprHasProperty(p, EP_FromJoin) ) return 0; - if( !sqlite3ExprIsInteger(p, &v) ) return 0; - return v==0; -} - -/* ** Join two expressions using an AND operator. If either expression is ** NULL, then just return the other expression. ** @@ -97557,19 +98106,18 @@ static int exprAlwaysFalse(Expr *p){ ** of returning an AND expression, just return a constant expression with ** a value of false. */ -SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){ - if( pLeft==0 ){ +SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ + sqlite3 *db = pParse->db; + if( pLeft==0 ){ return pRight; }else if( pRight==0 ){ return pLeft; - }else if( exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight) ){ - sqlite3ExprDelete(db, pLeft); - sqlite3ExprDelete(db, pRight); + }else if( ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight) ){ + sqlite3ExprUnmapAndDelete(pParse, pLeft); + sqlite3ExprUnmapAndDelete(pParse, pRight); return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0); }else{ - Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0); - sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight); - return pNew; + return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); } } @@ -97726,6 +98274,18 @@ SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(db, p); } +/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the +** expression. +*/ +SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){ + if( p ){ + if( IN_RENAME_OBJECT ){ + sqlite3RenameExprUnmap(pParse, p); + } + sqlite3ExprDeleteNN(pParse->db, p); + } +} + /* ** Return the number of bytes allocated for the expression structure ** passed as the first argument. This is always one of EXPR_FULLSIZE, @@ -97960,7 +98520,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ static With *withDup(sqlite3 *db, With *p){ With *pRet = 0; if( p ){ - int nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); + sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1); pRet = sqlite3DbMallocZero(db, nByte); if( pRet ){ int i; @@ -98225,7 +98785,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend( }else if( (pList->nExpr & (pList->nExpr-1))==0 ){ ExprList *pNew; pNew = sqlite3DbRealloc(db, pList, - sizeof(*pList)+(2*pList->nExpr - 1)*sizeof(pList->a[0])); + sizeof(*pList)+(2*(sqlite3_int64)pList->nExpr-1)*sizeof(pList->a[0])); if( pNew==0 ){ goto no_mem; } @@ -98308,10 +98868,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector( } vector_append_error: - if( IN_RENAME_OBJECT ){ - sqlite3RenameExprUnmap(pParse, pExpr); - } - sqlite3ExprDelete(db, pExpr); + sqlite3ExprUnmapAndDelete(pParse, pExpr); sqlite3IdListDelete(db, pColumns); return pList; } @@ -98459,6 +99016,7 @@ SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){ || sqlite3StrICmp(pExpr->u.zToken, "false")==0) ){ pExpr->op = TK_TRUEFALSE; + ExprSetProperty(pExpr, pExpr->u.zToken[4]==0 ? EP_IsTrue : EP_IsFalse); return 1; } return 0; @@ -98469,12 +99027,40 @@ SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){ ** and 0 if it is FALSE. */ SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr *pExpr){ + pExpr = sqlite3ExprSkipCollate((Expr*)pExpr); assert( pExpr->op==TK_TRUEFALSE ); assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0 || sqlite3StrICmp(pExpr->u.zToken,"false")==0 ); return pExpr->u.zToken[4]==0; } +/* +** If pExpr is an AND or OR expression, try to simplify it by eliminating +** terms that are always true or false. Return the simplified expression. +** Or return the original expression if no simplification is possible. +** +** Examples: +** +** (x<10) AND true => (x<10) +** (x<10) AND false => false +** (x<10) AND (y=22 OR false) => (x<10) AND (y=22) +** (x<10) AND (y=22 OR true) => (x<10) +** (y=22) OR true => true +*/ +SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){ + assert( pExpr!=0 ); + if( pExpr->op==TK_AND || pExpr->op==TK_OR ){ + Expr *pRight = sqlite3ExprSimplifiedAndOr(pExpr->pRight); + Expr *pLeft = sqlite3ExprSimplifiedAndOr(pExpr->pLeft); + if( ExprAlwaysTrue(pLeft) || ExprAlwaysFalse(pRight) ){ + pExpr = pExpr->op==TK_AND ? pRight : pLeft; + }else if( ExprAlwaysTrue(pRight) || ExprAlwaysFalse(pLeft) ){ + pExpr = pExpr->op==TK_AND ? pLeft : pRight; + } + } + return pExpr; +} + /* ** These routines are Walker callbacks used to check expressions to @@ -98719,7 +99305,7 @@ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){ */ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){ int rc = 0; - if( p==0 ) return 0; /* Can only happen following on OOM */ + if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */ /* If an expression is an integer literal that fits in a signed 32-bit ** integer, then the EP_IntValue flag will have already been set */ @@ -99448,6 +100034,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( */ if( addrOnce && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, addrOnce); + ExprClearProperty(pExpr, EP_Subrtn); addrOnce = 0; } @@ -100014,7 +100601,8 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n ** register iReg. The caller must ensure that iReg already contains ** the correct value for the expression. */ -static void exprToRegister(Expr *p, int iReg){ +static void exprToRegister(Expr *pExpr, int iReg){ + Expr *p = sqlite3ExprSkipCollate(pExpr); p->op2 = p->op; p->op = TK_REGISTER; p->iTable = iReg; @@ -101066,18 +101654,23 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int if( NEVER(pExpr==0) ) return; /* No way this can happen */ op = pExpr->op; switch( op ){ - case TK_AND: { - int d2 = sqlite3VdbeMakeLabel(pParse); - testcase( jumpIfNull==0 ); - sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); - sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3VdbeResolveLabel(v, d2); - break; - } + case TK_AND: case TK_OR: { - testcase( jumpIfNull==0 ); - sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); - sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); + if( pAlt!=pExpr ){ + sqlite3ExprIfTrue(pParse, pAlt, dest, jumpIfNull); + }else if( op==TK_AND ){ + int d2 = sqlite3VdbeMakeLabel(pParse); + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, + jumpIfNull^SQLITE_JUMPIFNULL); + sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + sqlite3VdbeResolveLabel(v, d2); + }else{ + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); + sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); + } break; } case TK_NOT: { @@ -101163,9 +101756,9 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int #endif default: { default_expr: - if( exprAlwaysTrue(pExpr) ){ + if( ExprAlwaysTrue(pExpr) ){ sqlite3VdbeGoto(v, dest); - }else if( exprAlwaysFalse(pExpr) ){ + }else if( ExprAlwaysFalse(pExpr) ){ /* No-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); @@ -101233,18 +101826,23 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int assert( pExpr->op!=TK_GE || op==OP_Lt ); switch( pExpr->op ){ - case TK_AND: { - testcase( jumpIfNull==0 ); - sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); - sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - break; - } + case TK_AND: case TK_OR: { - int d2 = sqlite3VdbeMakeLabel(pParse); - testcase( jumpIfNull==0 ); - sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); - sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); - sqlite3VdbeResolveLabel(v, d2); + Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr); + if( pAlt!=pExpr ){ + sqlite3ExprIfFalse(pParse, pAlt, dest, jumpIfNull); + }else if( pExpr->op==TK_AND ){ + testcase( jumpIfNull==0 ); + sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); + sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + }else{ + int d2 = sqlite3VdbeMakeLabel(pParse); + testcase( jumpIfNull==0 ); + sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, + jumpIfNull^SQLITE_JUMPIFNULL); + sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); + sqlite3VdbeResolveLabel(v, d2); + } break; } case TK_NOT: { @@ -101333,9 +101931,9 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int #endif default: { default_expr: - if( exprAlwaysFalse(pExpr) ){ + if( ExprAlwaysFalse(pExpr) ){ sqlite3VdbeGoto(v, dest); - }else if( exprAlwaysTrue(pExpr) ){ + }else if( ExprAlwaysTrue(pExpr) ){ /* no-op */ }else{ r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); @@ -101491,6 +102089,7 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa && (combinedFlags & EP_Reduced)==0 ){ if( pA->iColumn!=pB->iColumn ) return 2; + if( pA->op2!=pB->op2 ) return 2; if( pA->iTable!=pB->iTable && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2; } @@ -101539,6 +102138,76 @@ SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ } /* +** Return non-zero if Expr p can only be true if pNN is not NULL. +*/ +static int exprImpliesNotNull( + Parse *pParse, /* Parsing context */ + Expr *p, /* The expression to be checked */ + Expr *pNN, /* The expression that is NOT NULL */ + int iTab, /* Table being evaluated */ + int seenNot /* True if p is an operand of NOT */ +){ + assert( p ); + assert( pNN ); + if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ) return 1; + switch( p->op ){ + case TK_IN: { + if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0; + assert( ExprHasProperty(p,EP_xIsSelect) + || (p->x.pList!=0 && p->x.pList->nExpr>0) ); + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_BETWEEN: { + ExprList *pList = p->x.pList; + assert( pList!=0 ); + assert( pList->nExpr==2 ); + if( seenNot ) return 0; + if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, seenNot) + || exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, seenNot) + ){ + return 1; + } + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_EQ: + case TK_NE: + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_PLUS: + case TK_MINUS: + case TK_STAR: + case TK_REM: + case TK_BITAND: + case TK_BITOR: + case TK_SLASH: + case TK_LSHIFT: + case TK_RSHIFT: + case TK_CONCAT: { + if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1; + /* Fall thru into the next case */ + } + case TK_SPAN: + case TK_COLLATE: + case TK_BITNOT: + case TK_UPLUS: + case TK_UMINUS: { + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_TRUTH: { + if( seenNot ) return 0; + if( p->op2!=TK_IS ) return 0; + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_NOT: { + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1); + } + } + return 0; +} + +/* ** Return true if we can prove the pE2 will always be true if pE1 is ** true. Return false if we cannot complete the proof or if pE2 might ** be false. Examples: @@ -101573,10 +102242,10 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, i ){ return 1; } - if( pE2->op==TK_NOTNULL && pE1->op!=TK_ISNULL && pE1->op!=TK_IS ){ - Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft); - testcase( pX!=pE1->pLeft ); - if( sqlite3ExprCompare(pParse, pX, pE2->pLeft, iTab)==0 ) return 1; + if( pE2->op==TK_NOTNULL + && exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0) + ){ + return 1; } return 0; } @@ -101670,6 +102339,17 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ */ SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){ Walker w; + p = sqlite3ExprSkipCollate(p); + while( p ){ + if( p->op==TK_NOTNULL ){ + p = p->pLeft; + }else if( p->op==TK_AND ){ + if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1; + p = p->pRight; + }else{ + break; + } + } w.xExprCallback = impliesNotNullRow; w.xSelectCallback = 0; w.xSelectCallback2 = 0; @@ -102139,7 +102819,7 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ sqlite3NestedParse(pParse, "SELECT 1 " "FROM \"%w\".%s " - "WHERE name NOT LIKE 'sqlite_%%'" + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ", zDb, MASTER_NAME, @@ -102150,7 +102830,7 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ sqlite3NestedParse(pParse, "SELECT 1 " "FROM temp.%s " - "WHERE name NOT LIKE 'sqlite_%%'" + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ", MASTER_NAME, zDb @@ -102251,15 +102931,15 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( } #endif - /* Begin a transaction for database iDb. - ** Then modify the schema cookie (since the ALTER TABLE modifies the - ** schema). Open a statement transaction if the table is a virtual - ** table. - */ + /* Begin a transaction for database iDb. Then modify the schema cookie + ** (since the ALTER TABLE modifies the schema). Call sqlite3MayAbort(), + ** as the scalar functions (e.g. sqlite_rename_table()) invoked by the + ** nested SQL may raise an exception. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } + sqlite3MayAbort(pParse); /* figure out how many UTF-8 characters are in zName */ zTabName = pTab->zName; @@ -102271,7 +102951,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( "UPDATE \"%w\".%s SET " "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) " "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)" - "AND name NOT LIKE 'sqlite_%%'" + "AND name NOT LIKE 'sqliteX_%%' ESCAPE 'X'" , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName ); @@ -102282,7 +102962,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( "tbl_name = %Q, " "name = CASE " "WHEN type='table' THEN %Q " - "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " + "WHEN name LIKE 'sqliteX_autoindex%%' ESCAPE 'X' " + " AND type='index' THEN " "'sqlite_autoindex_' || %Q || substr(name,%d+18) " "ELSE name END " "WHERE tbl_name=%Q COLLATE nocase AND " @@ -102328,7 +103009,6 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable( int i = ++pParse->nMem; sqlite3VdbeLoadString(v, i, zName); sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); - sqlite3MayAbort(pParse); } #endif @@ -102649,6 +103329,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn( ** uses the sqlite_rename_column() SQL function to compute the new ** CREATE statement text for the sqlite_master table. */ + sqlite3MayAbort(pParse); zNew = sqlite3NameFromToken(db, pNew); if( !zNew ) goto exit_rename_column; assert( pNew->n>0 ); @@ -102656,7 +103337,8 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn( sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) " - "WHERE name NOT LIKE 'sqlite_%%' AND (type != 'index' OR tbl_name = %Q)" + "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' " + " AND (type != 'index' OR tbl_name = %Q)" " AND sql NOT LIKE 'create virtual%%'", zDb, MASTER_NAME, zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1, @@ -102811,6 +103493,29 @@ static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){ } /* +** Walker callback used by sqlite3RenameExprUnmap(). +*/ +static int renameUnmapSelectCb(Walker *pWalker, Select *p){ + Parse *pParse = pWalker->pParse; + int i; + if( ALWAYS(p->pEList) ){ + ExprList *pList = p->pEList; + for(i=0; i<pList->nExpr; i++){ + if( pList->a[i].zName ){ + sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zName); + } + } + } + if( ALWAYS(p->pSrc) ){ /* Every Select as a SrcList, even if it is empty */ + SrcList *pSrc = p->pSrc; + for(i=0; i<pSrc->nSrc; i++){ + sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName); + } + } + return WRC_Continue; +} + +/* ** Remove all nodes that are part of expression pExpr from the rename list. */ SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){ @@ -102818,6 +103523,7 @@ SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){ memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = pParse; sWalker.xExprCallback = renameUnmapExprCb; + sWalker.xSelectCallback = renameUnmapSelectCb; sqlite3WalkExpr(&sWalker, pExpr); } @@ -105903,12 +106609,14 @@ static void attachFunc( sqlite3BtreeEnterAll(db); db->init.iDb = 0; db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); - rc = sqlite3Init(db, &zErrDyn); + if( !REOPEN_AS_MEMDB(db) ){ + rc = sqlite3Init(db, &zErrDyn); + } sqlite3BtreeLeaveAll(db); assert( zErrDyn==0 || rc!=SQLITE_OK ); } #ifdef SQLITE_USER_AUTHENTICATION - if( rc==SQLITE_OK ){ + if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){ u8 newAuth = 0; rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); if( newAuth<db->auth.authLevel ){ @@ -106837,7 +107545,12 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ zSql = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); if( zSql==0 ){ - return; /* A malloc must have failed */ + /* This can result either from an OOM or because the formatted string + ** exceeds SQLITE_LIMIT_LENGTH. In the latter case, we need to set + ** an error */ + if( !db->mallocFailed ) pParse->rc = SQLITE_TOOBIG; + pParse->nErr++; + return; } pParse->nested++; memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ); @@ -107190,10 +107903,14 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ #ifdef SQLITE_DEBUG /* Record the number of outstanding lookaside allocations in schema Tables - ** prior to doing any free() operations. Since schema Tables do not use - ** lookaside, this number should not change. */ + ** prior to doing any free() operations. Since schema Tables do not use + ** lookaside, this number should not change. + ** + ** If malloc has already failed, it may be that it failed while allocating + ** a Table object that was going to be marked ephemeral. So do not check + ** that no lookaside memory is used in this case either. */ int nLookaside = 0; - if( db && (pTable->tabFlags & TF_Ephemeral)==0 ){ + if( db && !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){ nLookaside = sqlite3LookasideUsed(db, 0); } #endif @@ -107901,7 +108618,7 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue( ** accept it. This routine does the necessary conversion. It converts ** the expression given in its argument from a TK_STRING into a TK_ID ** if the expression is just a TK_STRING with an optional COLLATE clause. -** If the epxression is anything other than TK_STRING, the expression is +** If the expression is anything other than TK_STRING, the expression is ** unchanged. */ static void sqlite3StringToId(Expr *p){ @@ -107977,7 +108694,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey( && sortOrder!=SQLITE_SO_DESC ){ if( IN_RENAME_OBJECT && pList ){ - sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pList->a[0].pExpr); + Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[0].pExpr); + sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr); } pTab->iPKey = iCol; pTab->keyConf = (u8)onError; @@ -108297,10 +109015,51 @@ static void estimateIndexWidth(Index *pIdx){ pIdx->szIdxRow = sqlite3LogEst(wIndex*4); } -/* Return true if value x is found any of the first nCol entries of aiCol[] +/* Return true if column number x is any of the first nCol entries of aiCol[]. +** This is used to determine if the column number x appears in any of the +** first nCol entries of an index. */ static int hasColumn(const i16 *aiCol, int nCol, int x){ - while( nCol-- > 0 ) if( x==*(aiCol++) ) return 1; + while( nCol-- > 0 ){ + assert( aiCol[0]>=0 ); + if( x==*(aiCol++) ){ + return 1; + } + } + return 0; +} + +/* +** Return true if any of the first nKey entries of index pIdx exactly +** match the iCol-th entry of pPk. pPk is always a WITHOUT ROWID +** PRIMARY KEY index. pIdx is an index on the same table. pIdx may +** or may not be the same index as pPk. +** +** The first nKey entries of pIdx are guaranteed to be ordinary columns, +** not a rowid or expression. +** +** This routine differs from hasColumn() in that both the column and the +** collating sequence must match for this routine, but for hasColumn() only +** the column name must match. +*/ +static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){ + int i, j; + assert( nKey<=pIdx->nColumn ); + assert( iCol<MAX(pPk->nColumn,pPk->nKeyCol) ); + assert( pPk->idxType==SQLITE_IDXTYPE_PRIMARYKEY ); + assert( pPk->pTable->tabFlags & TF_WithoutRowid ); + assert( pPk->pTable==pIdx->pTable ); + testcase( pPk==pIdx ); + j = pPk->aiColumn[iCol]; + assert( j!=XN_ROWID && j!=XN_EXPR ); + for(i=0; i<nKey; i++){ + assert( pIdx->aiColumn[i]>=0 || j>=0 ); + if( pIdx->aiColumn[i]==j + && sqlite3StrICmp(pIdx->azColl[i], pPk->azColl[iCol])==0 + ){ + return 1; + } + } return 0; } @@ -108389,15 +109148,19 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ) return; + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey); + } pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); + pTab->iPKey = -1; sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); if( db->mallocFailed || pParse->nErr ) return; pPk = sqlite3PrimaryKeyIndex(pTab); - pTab->iPKey = -1; }else{ pPk = sqlite3PrimaryKeyIndex(pTab); + assert( pPk!=0 ); /* ** Remove all redundant columns from the PRIMARY KEY. For example, change @@ -108405,9 +109168,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ ** code assumes the PRIMARY KEY contains no repeated columns. */ for(i=j=1; i<pPk->nKeyCol; i++){ - if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){ + if( isDupColumn(pPk, j, pPk, i) ){ pPk->nColumn--; }else{ + testcase( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ); pPk->aiColumn[j++] = pPk->aiColumn[i]; } } @@ -108437,7 +109201,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ int n; if( IsPrimaryKeyIndex(pIdx) ) continue; for(i=n=0; i<nPk; i++){ - if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++; + if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){ + testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); + n++; + } } if( n==0 ){ /* This index is a superset of the primary key */ @@ -108446,9 +109213,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ } if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return; for(i=0, j=pIdx->nKeyCol; i<nPk; i++){ - if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ){ + if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){ + testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ); pIdx->aiColumn[j] = pPk->aiColumn[i]; pIdx->azColl[j] = pPk->azColl[i]; + if( pPk->aSortOrder[i] ){ + /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */ + pIdx->bAscKeyBug = 1; + } j++; } } @@ -108567,6 +109339,11 @@ SQLITE_PRIVATE void sqlite3EndTable( if( p->tnum==1 ) p->tabFlags |= TF_Readonly; } + assert( (p->tabFlags & TF_HasPrimaryKey)==0 + || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 ); + assert( (p->tabFlags & TF_HasPrimaryKey)!=0 + || (p->iPKey<0 && sqlite3PrimaryKeyIndex(p)==0) ); + /* Special processing for WITHOUT ROWID Tables */ if( tabOpts & TF_WithoutRowid ){ if( (p->tabFlags & TF_Autoincrement) ){ @@ -109562,10 +110339,27 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3UniqueConstraint(pParse, OE_Abort, pIndex); sqlite3VdbeJumpHere(v, j2); }else{ + /* Most CREATE INDEX and REINDEX statements that are not UNIQUE can not + ** abort. The exception is if one of the indexed expressions contains a + ** user function that throws an exception when it is evaluated. But the + ** overhead of adding a statement journal to a CREATE INDEX statement is + ** very small (since most of the pages written do not contain content that + ** needs to be restored if the statement aborts), so we call + ** sqlite3MayAbort() for all CREATE INDEX statements. */ + sqlite3MayAbort(pParse); addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); - sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); + if( !pIndex->bAscKeyBug ){ + /* This OP_SeekEnd opcode makes index insert for a REINDEX go much + ** faster by avoiding unnecessary seeks. But the optimization does + ** not work for UNIQUE constraint indexes on WITHOUT ROWID tables + ** with DESC primary keys, since those indexes have there keys in + ** a different order from the main table. + ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf + */ + sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx); + } sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); @@ -109720,13 +110514,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex( assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 + && pTblName!=0 #if SQLITE_USER_AUTHENTICATION && sqlite3UserAuthTable(pTab->zName)==0 #endif #ifdef SQLITE_ALLOW_SQLITE_MASTER_INDEX && sqlite3StrICmp(&pTab->zName[7],"master")!=0 #endif - && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; @@ -109830,6 +110624,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex( sqlite3ExprListSetSortOrder(pList, sortOrder); }else{ sqlite3ExprListCheckLength(pParse, pList, "index"); + if( pParse->nErr ) goto exit_create_index; } /* Figure out how many bytes of space are required to store explicitly @@ -109848,6 +110643,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex( */ nName = sqlite3Strlen30(zName); nExtraCol = pPk ? pPk->nKeyCol : 1; + assert( pList->nExpr + nExtraCol <= 32767 /* Fits in i16 */ ); pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol, nName + nExtra + 1, &zExtra); if( db->mallocFailed ){ @@ -109955,9 +110751,10 @@ SQLITE_PRIVATE void sqlite3CreateIndex( for(j=0; j<pPk->nKeyCol; j++){ int x = pPk->aiColumn[j]; assert( x>=0 ); - if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){ + if( isDupColumn(pIndex, pIndex->nKeyCol, pPk, j) ){ pIndex->nColumn--; }else{ + testcase( hasColumn(pIndex->aiColumn,pIndex->nKeyCol,x) ); pIndex->aiColumn[i] = x; pIndex->azColl[i] = pPk->azColl[j]; pIndex->aSortOrder[i] = pPk->aSortOrder[j]; @@ -110331,9 +111128,9 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate( int *pIdx /* Write the index of a new slot here */ ){ char *z; - int n = *pnEntry; + sqlite3_int64 n = *pIdx = *pnEntry; if( (n & (n-1))==0 ){ - int sz = (n==0) ? 1 : 2*n; + sqlite3_int64 sz = (n==0) ? 1 : 2*n; void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry); if( pNew==0 ){ *pIdx = -1; @@ -110343,7 +111140,6 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate( } z = (char*)pArray; memset(&z[n * szEntry], 0, szEntry); - *pIdx = n; ++*pnEntry; return pArray; } @@ -110454,7 +111250,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge( /* Allocate additional space if needed */ if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){ SrcList *pNew; - int nAlloc = pSrc->nSrc*2+nExtra; + sqlite3_int64 nAlloc = 2*(sqlite3_int64)pSrc->nSrc+nExtra; sqlite3 *db = pParse->db; if( pSrc->nSrc+nExtra>=SQLITE_MAX_SRCLIST ){ @@ -110961,7 +111757,8 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint( StrAccum errMsg; Table *pTab = pIdx->pTable; - sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); + sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, + pParse->db->aLimit[SQLITE_LIMIT_LENGTH]); if( pIdx->aColExpr ){ sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName); }else{ @@ -111210,7 +112007,7 @@ SQLITE_PRIVATE With *sqlite3WithAdd( } if( pWith ){ - int nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); + sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte); pNew = sqlite3DbRealloc(db, pWith, nByte); }else{ pNew = sqlite3DbMallocZero(db, sizeof(*pWith)); @@ -112728,6 +113525,7 @@ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){ /* #include "sqliteInt.h" */ /* #include <stdlib.h> */ /* #include <assert.h> */ +/* #include <math.h> */ /* #include "vdbeInt.h" */ /* @@ -113098,10 +113896,10 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ ** handle the rounding directly, ** otherwise use printf. */ - if( n==0 && r>=0 && r<LARGEST_INT64-1 ){ - r = (double)((sqlite_int64)(r+0.5)); - }else if( n==0 && r<0 && (-r)<LARGEST_INT64-1 ){ - r = -(double)((sqlite_int64)((-r)+0.5)); + if( r<-4503599627370496.0 || r>+4503599627370496.0 ){ + /* The value has no fractional part so there is nothing to round */ + }else if( n==0 ){ + r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5))); }else{ zBuf = sqlite3_mprintf("%.*f",n,r); if( zBuf==0 ){ @@ -113555,8 +114353,6 @@ static void likeFunc( return; } #endif - zB = sqlite3_value_text(argv[0]); - zA = sqlite3_value_text(argv[1]); /* Limit the length of the LIKE or GLOB pattern to avoid problems ** of deep recursion and N*N behavior in patternCompare(). @@ -113568,8 +114364,6 @@ static void likeFunc( sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); return; } - assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */ - if( argc==3 ){ /* The escape character string must consist of a single UTF-8 character. ** Otherwise, return an error. @@ -113585,6 +114379,8 @@ static void likeFunc( }else{ escape = pInfo->matchSet; } + zB = sqlite3_value_text(argv[0]); + zA = sqlite3_value_text(argv[1]); if( zA && zB ){ #ifdef SQLITE_TEST sqlite3_like_count++; @@ -114510,35 +115306,24 @@ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){ } /* -** Set the LIKEOPT flag on the 2-argument function with the given name. -*/ -static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){ - FuncDef *pDef; - pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0); - if( ALWAYS(pDef) ){ - pDef->funcFlags |= flagVal; - } -} - -/* -** Register the built-in LIKE and GLOB functions. The caseSensitive +** Re-register the built-in LIKE functions. The caseSensitive ** parameter determines whether or not the LIKE operator is case -** sensitive. GLOB is always case sensitive. +** sensitive. */ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ struct compareInfo *pInfo; + int flags; if( caseSensitive ){ pInfo = (struct compareInfo*)&likeInfoAlt; + flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE; }else{ pInfo = (struct compareInfo*)&likeInfoNorm; + flags = SQLITE_FUNC_LIKE; } sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0); - sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, - (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0, 0, 0); - setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE); - setLikeOptFlag(db, "like", - caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE); + sqlite3FindFunction(db, "like", 2, SQLITE_UTF8, 0)->funcFlags |= flags; + sqlite3FindFunction(db, "like", 3, SQLITE_UTF8, 0)->funcFlags |= flags; } /* @@ -115328,7 +116113,7 @@ static void fkScanChildren( zCol = pFKey->pFrom->aCol[iCol].zName; pRight = sqlite3Expr(db, TK_ID, zCol); pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); - pWhere = sqlite3ExprAnd(db, pWhere, pEq); + pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); } /* If the child table is the same as the parent table, then add terms @@ -115362,11 +116147,11 @@ static void fkScanChildren( pLeft = exprTableRegister(pParse, pTab, regData, iCol); pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zName); pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight); - pAll = sqlite3ExprAnd(db, pAll, pEq); + pAll = sqlite3ExprAnd(pParse, pAll, pEq); } pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0); } - pWhere = sqlite3ExprAnd(db, pWhere, pNe); + pWhere = sqlite3ExprAnd(pParse, pWhere, pNe); } /* Resolve the references in the WHERE clause. */ @@ -115972,7 +116757,7 @@ static Trigger *fkActionTrigger( sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)), sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0) ); - pWhere = sqlite3ExprAnd(db, pWhere, pEq); + pWhere = sqlite3ExprAnd(pParse, pWhere, pEq); /* For ON UPDATE, construct the next term of the WHEN clause. ** The final WHEN clause will be like this: @@ -115988,7 +116773,7 @@ static Trigger *fkActionTrigger( sqlite3ExprAlloc(db, TK_ID, &tNew, 0), sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)) ); - pWhen = sqlite3ExprAnd(db, pWhen, pEq); + pWhen = sqlite3ExprAnd(pParse, pWhen, pEq); } if( action!=OE_Restrict && (action!=OE_Cascade || pChanges) ){ @@ -116985,7 +117770,7 @@ SQLITE_PRIVATE void sqlite3Insert( int nIdx; nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0, &iDataCur, &iIdxCur); - aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1)); + aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+2)); if( aRegIdx==0 ){ goto insert_cleanup; } @@ -116994,6 +117779,7 @@ SQLITE_PRIVATE void sqlite3Insert( aRegIdx[i] = ++pParse->nMem; pParse->nMem += pIdx->nColumn; } + aRegIdx[i] = ++pParse->nMem; /* Register to store the table record */ } #ifndef SQLITE_OMIT_UPSERT if( pUpsert ){ @@ -117397,6 +118183,14 @@ SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn( ** the same as the order of indices on the linked list of indices ** at pTab->pIndex. ** +** (2019-05-07) The generated code also creates a new record for the +** main table, if pTab is a rowid table, and stores that record in the +** register identified by aRegIdx[nIdx] - in other words in the first +** entry of aRegIdx[] past the last index. It is important that the +** record be generated during constraint checks to avoid affinity changes +** to the register content that occur after constraint checks but before +** the new record is inserted. +** ** The caller must have already opened writeable cursors on the main ** table and all applicable indices (that is to say, all indices for which ** aRegIdx[] is not zero). iDataCur is the cursor for the main table when @@ -117587,7 +118381,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( }else{ char *zName = pCheck->a[i].zName; if( zName==0 ) zName = pTab->zName; - if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ + if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, onError, zName, P4_TRANSIENT, P5_ConstraintCheck); @@ -117840,7 +118634,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); VdbeComment((v, "for %s", pIdx->zName)); #ifdef SQLITE_ENABLE_NULL_TRIM - if( pIdx->idxType==2 ) sqlite3SetMakeRecordP5(v, pIdx->pTable); + if( pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ + sqlite3SetMakeRecordP5(v, pIdx->pTable); + } #endif /* In an UPDATE operation, if this index is the PRIMARY KEY index @@ -118014,6 +118810,16 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks( sqlite3VdbeJumpHere(v, ipkBottom); } + /* Generate the table record */ + if( HasRowid(pTab) ){ + int regRec = aRegIdx[ix]; + sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nCol, regRec); + sqlite3SetMakeRecordP5(v, pTab); + if( !bAffinityDone ){ + sqlite3TableAffinity(v, pTab, 0); + } + } + *pbMayReplace = seenReplace; VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace)); } @@ -118063,10 +118869,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( Vdbe *v; /* Prepared statements under construction */ Index *pIdx; /* An index being inserted or updated */ u8 pik_flags; /* flag values passed to the btree insert */ - int regData; /* Content registers (after the rowid) */ - int regRec; /* Register holding assembled record for the table */ int i; /* Loop counter */ - u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */ assert( update_flags==0 || update_flags==OPFLAG_ISUPDATE @@ -118078,7 +118881,6 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( assert( pTab->pSelect==0 ); /* This table is not a VIEW */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( aRegIdx[i]==0 ) continue; - bAffinityDone = 1; if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2); VdbeCoverage(v); @@ -118106,13 +118908,6 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( sqlite3VdbeChangeP5(v, pik_flags); } if( !HasRowid(pTab) ) return; - regData = regNewData + 1; - regRec = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); - sqlite3SetMakeRecordP5(v, pTab); - if( !bAffinityDone ){ - sqlite3TableAffinity(v, pTab, 0); - } if( pParse->nested ){ pik_flags = 0; }else{ @@ -118125,7 +118920,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion( if( useSeekResult ){ pik_flags |= OPFLAG_USESEEKRESULT; } - sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData); + sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, aRegIdx[i], regNewData); if( !pParse->nested ){ sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } @@ -118444,6 +119239,13 @@ static int xferOptimization( if( pSrcIdx==0 ){ return 0; /* pDestIdx has no corresponding index in pSrc */ } + if( pSrcIdx->tnum==pDestIdx->tnum && pSrc->pSchema==pDest->pSchema + && sqlite3FaultSim(411)==SQLITE_OK ){ + /* The sqlite3FaultSim() call allows this corruption test to be + ** bypassed during testing, in order to exercise other corruption tests + ** further downstream. */ + return 0; /* Corrupt schema - two indexes on the same btree */ + } } #ifndef SQLITE_OMIT_CHECK if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){ @@ -118521,7 +119323,7 @@ static int xferOptimization( sqlite3RowidConstraint(pParse, onError, pDest); sqlite3VdbeJumpHere(v, addr2); autoIncStep(pParse, regAutoinc, regRowid); - }else if( pDest->pIndex==0 ){ + }else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); }else{ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); @@ -118584,7 +119386,7 @@ static int xferOptimization( sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); } } - if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){ + if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ idxInsFlags |= OPFLAG_NCHANGE; } sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData); @@ -119096,6 +119898,9 @@ struct sqlite3_api_routines { void(*xDestroy)(void*)); /* Version 3.26.0 and later */ const char *(*normalized_sql)(sqlite3_stmt*); + /* Version 3.28.0 and later */ + int (*stmt_isexplain)(sqlite3_stmt*); + int (*value_frombind)(sqlite3_value*); }; /* @@ -119385,6 +120190,9 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_create_window_function sqlite3_api->create_window_function /* Version 3.26.0 and later */ #define sqlite3_normalized_sql sqlite3_api->normalized_sql +/* Version 3.28.0 and later */ +#define sqlite3_stmt_isexplain sqlite3_api->isexplain +#define sqlite3_value_frombind sqlite3_api->frombind #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -119844,10 +120652,13 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_create_window_function, /* Version 3.26.0 and later */ #ifdef SQLITE_ENABLE_NORMALIZE - sqlite3_normalized_sql + sqlite3_normalized_sql, #else - 0 + 0, #endif + /* Version 3.28.0 and later */ + sqlite3_stmt_isexplain, + sqlite3_value_frombind }; /* @@ -120295,10 +121106,9 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){ #define PragTyp_WAL_AUTOCHECKPOINT 38 #define PragTyp_WAL_CHECKPOINT 39 #define PragTyp_ACTIVATE_EXTENSIONS 40 -#define PragTyp_HEXKEY 41 -#define PragTyp_KEY 42 -#define PragTyp_LOCK_STATUS 43 -#define PragTyp_STATS 44 +#define PragTyp_KEY 41 +#define PragTyp_LOCK_STATUS 42 +#define PragTyp_STATS 43 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ @@ -120427,11 +121237,13 @@ static const PragmaName aPragmaName[] = { /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif +#if !defined(SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA) {/* zName: */ "case_sensitive_like", /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, /* ePragFlg: */ PragFlg_NoColumns, /* ColNames: */ 0, 0, /* iArg: */ 0 }, +#endif {/* zName: */ "cell_size_check", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, @@ -120569,12 +121381,12 @@ static const PragmaName aPragmaName[] = { #endif #if defined(SQLITE_HAS_CODEC) {/* zName: */ "hexkey", - /* ePragTyp: */ PragTyp_HEXKEY, + /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 2 }, {/* zName: */ "hexrekey", - /* ePragTyp: */ PragTyp_HEXKEY, + /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 3 }, @@ -121535,6 +122347,11 @@ SQLITE_PRIVATE void sqlite3Pragma( ** then do a query */ eMode = PAGER_JOURNALMODE_QUERY; } + if( eMode==PAGER_JOURNALMODE_OFF && (db->flags & SQLITE_Defensive)!=0 ){ + /* Do not allow journal-mode "OFF" in defensive since the database + ** can become corrupted using ordinary SQL when the journal is off */ + eMode = PAGER_JOURNALMODE_QUERY; + } } if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){ /* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */ @@ -122312,6 +123129,7 @@ SQLITE_PRIVATE void sqlite3Pragma( #endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ +#ifndef SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA /* Reinstall the LIKE and GLOB functions. The variant of LIKE ** used will be case sensitive or not depending on the RHS. */ @@ -122321,6 +123139,7 @@ SQLITE_PRIVATE void sqlite3Pragma( } } break; +#endif /* SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA */ #ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX # define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 @@ -123014,28 +123833,30 @@ SQLITE_PRIVATE void sqlite3Pragma( */ case PragTyp_KEY: { if( zRight ){ - int n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1; - if( (pPragma->iArg & 1)==0 ){ - sqlite3_key_v2(db, zDb, zRight, n); + char zBuf[40]; + const char *zKey = zRight; + int n; + if( pPragma->iArg==2 || pPragma->iArg==3 ){ + u8 iByte; + int i; + for(i=0, iByte=0; i<sizeof(zBuf)*2 && sqlite3Isxdigit(zRight[i]); i++){ + iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]); + if( (i&1)!=0 ) zBuf[i/2] = iByte; + } + zKey = zBuf; + n = i/2; }else{ - sqlite3_rekey_v2(db, zDb, zRight, n); - } - } - break; - } - case PragTyp_HEXKEY: { - if( zRight ){ - u8 iByte; - int i; - char zKey[40]; - for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zRight[i]); i++){ - iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]); - if( (i&1)!=0 ) zKey[i/2] = iByte; + n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1; } if( (pPragma->iArg & 1)==0 ){ - sqlite3_key_v2(db, zDb, zKey, i/2); + rc = sqlite3_key_v2(db, zDb, zKey, n); }else{ - sqlite3_rekey_v2(db, zDb, zKey, i/2); + rc = sqlite3_rekey_v2(db, zDb, zKey, n); + } + if( rc==SQLITE_OK && n!=0 ){ + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC); + returnSingleText(v, "ok"); } } break; @@ -124676,7 +125497,7 @@ static void addWhereTerm( ExprSetVVAProperty(pEq, EP_NoReduce); pEq->iRightJoinTable = (i16)pE2->iTable; } - *ppWhere = sqlite3ExprAnd(db, *ppWhere, pEq); + *ppWhere = sqlite3ExprAnd(pParse, *ppWhere, pEq); } /* @@ -124810,7 +125631,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ */ if( pRight->pOn ){ if( isOuter ) setJoinExpr(pRight->pOn, pRight->iCursor); - p->pWhere = sqlite3ExprAnd(pParse->db, p->pWhere, pRight->pOn); + p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->pOn); pRight->pOn = 0; } @@ -126417,9 +127238,6 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){ if( pTab==0 ){ return 0; } - /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside - ** is disabled */ - assert( db->lookaside.bDisable ); pTab->nTabRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); @@ -126861,6 +127679,7 @@ static int multiSelect( */ assert( p && p->pPrior ); /* Calling function guarantees this much */ assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION ); + assert( p->selFlags & SF_Compound ); db = pParse->db; pPrior = p->pPrior; dest = *pDest; @@ -128355,7 +129174,7 @@ static int flattenSubquery( if( isLeftJoin>0 ){ setJoinExpr(pWhere, iNewParent); } - pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere); + pParent->pWhere = sqlite3ExprAnd(pParse, pWhere, pParent->pWhere); if( db->mallocFailed==0 ){ SubstContext x; x.pParse = pParse; @@ -128366,10 +129185,10 @@ static int flattenSubquery( substSelect(&x, pParent, 0); } - /* The flattened query is distinct if either the inner or the - ** outer query is distinct. - */ - pParent->selFlags |= pSub->selFlags & SF_Distinct; + /* The flattened query is a compound if either the inner or the + ** outer query is a compound. */ + pParent->selFlags |= pSub->selFlags & SF_Compound; + assert( (pSub->selFlags & SF_Distinct)==0 ); /* restriction (17b) */ /* ** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y; @@ -128690,9 +129509,9 @@ static int pushDownWhereTerms( x.pEList = pSubq->pEList; pNew = substExpr(&x, pNew); if( pSubq->selFlags & SF_Aggregate ){ - pSubq->pHaving = sqlite3ExprAnd(pParse->db, pSubq->pHaving, pNew); + pSubq->pHaving = sqlite3ExprAnd(pParse, pSubq->pHaving, pNew); }else{ - pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew); + pSubq->pWhere = sqlite3ExprAnd(pParse, pSubq->pWhere, pNew); } pSubq = pSubq->pPrior; } @@ -129118,7 +129937,7 @@ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFr pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral; - return SQLITE_OK; + return pParse->nErr ? SQLITE_ERROR : SQLITE_OK; } /* @@ -129164,6 +129983,10 @@ static int selectExpander(Walker *pWalker, Select *p){ if( (selFlags & SF_Expanded)!=0 ){ return WRC_Prune; } + if( pWalker->eCode ){ + /* Renumber selId because it has been copied from a view */ + p->selId = ++pParse->nSelect; + } pTabList = p->pSrc; pEList = p->pEList; sqlite3WithPush(pParse, p->pWith, 0); @@ -129213,12 +130036,15 @@ static int selectExpander(Walker *pWalker, Select *p){ #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) if( IsVirtual(pTab) || pTab->pSelect ){ i16 nCol; + u8 eCodeOrig = pWalker->eCode; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); nCol = pTab->nCol; pTab->nCol = -1; + pWalker->eCode = 1; /* Turn on Select.selId renumbering */ sqlite3WalkSelect(pWalker, pFrom->pSelect); + pWalker->eCode = eCodeOrig; pTab->nCol = nCol; } #endif @@ -129468,6 +130294,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){ } w.xSelectCallback = selectExpander; w.xSelectCallback2 = selectPopWith; + w.eCode = 0; sqlite3WalkSelect(&w, pSelect); } @@ -129627,7 +130454,7 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){ ** ** If regAcc is non-zero and there are no min() or max() aggregates ** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator -** registers i register regAcc contains 0. The caller will take care +** registers if register regAcc contains 0. The caller will take care ** of setting and clearing regAcc. */ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){ @@ -129739,7 +130566,7 @@ static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ if( pNew ){ Expr *pWhere = pS->pWhere; SWAP(Expr, *pNew, *pExpr); - pNew = sqlite3ExprAnd(db, pWhere, pNew); + pNew = sqlite3ExprAnd(pWalker->pParse, pWhere, pNew); pS->pWhere = pNew; pWalker->eCode = 1; } @@ -129794,15 +130621,19 @@ static struct SrcList_item *isSelfJoinView( if( pItem->pSelect==0 ) continue; if( pItem->fg.viaCoroutine ) continue; if( pItem->zName==0 ) continue; - if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue; + assert( pItem->pTab!=0 ); + assert( pThis->pTab!=0 ); + if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue; if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; pS1 = pItem->pSelect; - if( pThis->pSelect->selId!=pS1->selId ){ + if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){ /* The query flattener left two different CTE tables with identical ** names in the same FROM clause. */ continue; } - if( sqlite3ExprCompare(0, pThis->pSelect->pWhere, pS1->pWhere, -1) ){ + if( sqlite3ExprCompare(0, pThis->pSelect->pWhere, pS1->pWhere, -1) + || sqlite3ExprCompare(0, pThis->pSelect->pHaving, pS1->pHaving, -1) + ){ /* The view was modified by some other optimization such as ** pushDownWhereTerms() */ continue; @@ -129827,7 +130658,8 @@ static struct SrcList_item *isSelfJoinView( ** * The subquery is a UNION ALL of two or more terms ** * The subquery does not have a LIMIT clause ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries -** * The outer query is a simple count(*) +** * The outer query is a simple count(*) with no WHERE clause or other +** extraneous syntax. ** ** Return TRUE if the optimization is undertaken. */ @@ -129838,6 +130670,8 @@ static int countOfViewOptimization(Parse *pParse, Select *p){ sqlite3 *db; if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ + if( p->pWhere ) return 0; + if( p->pGroupBy ) return 0; pExpr = p->pEList->a[0].pExpr; if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */ if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */ @@ -132488,11 +133322,12 @@ SQLITE_PRIVATE void sqlite3Update( Index *pIdx; /* For looping over indices */ Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */ int nIdx; /* Number of indices that need updating */ + int nAllIdx; /* Total number of indexes */ int iBaseCur; /* Base cursor number */ int iDataCur; /* Cursor for the canonical data btree */ int iIdxCur; /* Cursor for the first index */ sqlite3 *db; /* The database structure */ - int *aRegIdx = 0; /* First register in array assigned to each index */ + int *aRegIdx = 0; /* Registers for to each index and the main table */ int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the ** an expression for the i-th column of the table. ** aXRef[i]==-1 if the i-th column is not changed. */ @@ -132606,10 +133441,10 @@ SQLITE_PRIVATE void sqlite3Update( /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. ** Initialize aXRef[] and aToOpen[] to their default values. */ - aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 ); + aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx+1) + nIdx+2 ); if( aXRef==0 ) goto update_cleanup; aRegIdx = aXRef+pTab->nCol; - aToOpen = (u8*)(aRegIdx+nIdx); + aToOpen = (u8*)(aRegIdx+nIdx+1); memset(aToOpen, 1, nIdx+1); aToOpen[nIdx+1] = 0; for(i=0; i<pTab->nCol; i++) aXRef[i] = -1; @@ -132688,7 +133523,7 @@ SQLITE_PRIVATE void sqlite3Update( ** the key for accessing each index. */ if( onError==OE_Replace ) bReplace = 1; - for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ + for(nAllIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nAllIdx++){ int reg; if( chngKey || hasFK>1 || pIdx==pPk || indexWhereClauseMightChange(pIdx,aXRef,chngRowid) @@ -132708,9 +133543,10 @@ SQLITE_PRIVATE void sqlite3Update( } } } - if( reg==0 ) aToOpen[j+1] = 0; - aRegIdx[j] = reg; + if( reg==0 ) aToOpen[nAllIdx+1] = 0; + aRegIdx[nAllIdx] = reg; } + aRegIdx[nAllIdx] = ++pParse->nMem; /* Register storing the table record */ if( bReplace ){ /* If REPLACE conflict resolution might be invoked, open cursors on all ** indexes in case they are needed to delete records. */ @@ -132725,7 +133561,13 @@ SQLITE_PRIVATE void sqlite3Update( /* Allocate required registers. */ if( !IsVirtual(pTab) ){ - regRowSet = ++pParse->nMem; + /* For now, regRowSet and aRegIdx[nAllIdx] share the same register. + ** If regRowSet turns out to be needed, then aRegIdx[nAllIdx] will be + ** reallocated. aRegIdx[nAllIdx] is the register in which the main + ** table record is written. regRowSet holds the RowSet for the + ** two-pass update algorithm. */ + assert( aRegIdx[nAllIdx]==pParse->nMem ); + regRowSet = aRegIdx[nAllIdx]; regOldRowid = regNewRowid = ++pParse->nMem; if( chngPk || pTrigger || hasFK ){ regOld = pParse->nMem + 1; @@ -132855,6 +133697,8 @@ SQLITE_PRIVATE void sqlite3Update( ** leave it in register regOldRowid. */ sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); if( eOnePass==ONEPASS_OFF ){ + /* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */ + aRegIdx[nAllIdx] = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid); } }else{ @@ -133686,6 +134530,7 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){ Vdbe *v = sqlite3GetVdbe(pParse); int iDb = 0; if( v==0 ) goto build_vacuum_end; + if( pParse->nErr ) goto build_vacuum_end; if( pNm ){ #ifndef SQLITE_BUG_COMPATIBLE_20160819 /* Default behavior: Report an error if the argument to VACUUM is @@ -133719,11 +134564,11 @@ build_vacuum_end: /* ** This routine implements the OP_Vacuum opcode of the VDBE. */ -SQLITE_PRIVATE int sqlite3RunVacuum( +SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( char **pzErrMsg, /* Write error message here */ sqlite3 *db, /* Database connection */ int iDb, /* Which attached DB to vacuum */ - sqlite3_value *pOut /* Write results here, if not NULL */ + sqlite3_value *pOut /* Write results here, if not NULL. VACUUM INTO */ ){ int rc = SQLITE_OK; /* Return code from service routines */ Btree *pMain; /* The database being vacuumed */ @@ -133732,6 +134577,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum( u64 saved_flags; /* Saved value of db->flags */ int saved_nChange; /* Saved value of db->nChange */ int saved_nTotalChange; /* Saved value of db->nTotalChange */ + u32 saved_openFlags; /* Saved value of db->openFlags */ u8 saved_mTrace; /* Saved trace settings */ Db *pDb = 0; /* Database to detach at end of vacuum */ int isMemDb; /* True if vacuuming a :memory: database */ @@ -133742,18 +134588,21 @@ SQLITE_PRIVATE int sqlite3RunVacuum( if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); - return SQLITE_ERROR; + return SQLITE_ERROR; /* IMP: R-12218-18073 */ } if( db->nVdbeActive>1 ){ sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); - return SQLITE_ERROR; + return SQLITE_ERROR; /* IMP: R-15610-35227 */ } + saved_openFlags = db->openFlags; if( pOut ){ if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){ sqlite3SetString(pzErrMsg, db, "non-text filename"); return SQLITE_ERROR; } zOut = (const char*)sqlite3_value_text(pOut); + db->openFlags &= ~SQLITE_OPEN_READONLY; + db->openFlags |= SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE; }else{ zOut = ""; } @@ -133792,6 +134641,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum( */ nDb = db->nDb; rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut); + db->openFlags = saved_openFlags; if( rc!=SQLITE_OK ) goto end_of_vacuum; assert( (db->nDb-1)==nDb ); pDb = &db->aDb[nDb]; @@ -133805,6 +134655,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum( sqlite3SetString(pzErrMsg, db, "output file already exists"); goto end_of_vacuum; } + db->mDbFlags |= DBFLAG_VacuumInto; } nRes = sqlite3BtreeGetOptimalReserve(pMain); @@ -134293,9 +135144,13 @@ SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){ ** string will be freed automatically when the table is ** deleted. */ -static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){ - int nBytes = sizeof(char *)*(2+pTable->nModuleArg); +static void addModuleArgument(Parse *pParse, Table *pTable, char *zArg){ + sqlite3_int64 nBytes = sizeof(char *)*(2+pTable->nModuleArg); char **azModuleArg; + sqlite3 *db = pParse->db; + if( pTable->nModuleArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){ + sqlite3ErrorMsg(pParse, "too many columns on %s", pTable->zName); + } azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes); if( azModuleArg==0 ){ sqlite3DbFree(db, zArg); @@ -134330,9 +135185,9 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse( db = pParse->db; assert( pTable->nModuleArg==0 ); - addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName)); - addModuleArgument(db, pTable, 0); - addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName)); + addModuleArgument(pParse, pTable, sqlite3NameFromToken(db, pModuleName)); + addModuleArgument(pParse, pTable, 0); + addModuleArgument(pParse, pTable, sqlite3DbStrDup(db, pTable->zName)); assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0) || (pParse->sNameToken.z==pName1->z && pName2->z==0) ); @@ -134365,7 +135220,7 @@ static void addArgumentToVtab(Parse *pParse){ const char *z = (const char*)pParse->sArg.z; int n = pParse->sArg.n; sqlite3 *db = pParse->db; - addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); + addModuleArgument(pParse, pParse->pNewTable, sqlite3DbStrNDup(db, z, n)); } } @@ -134654,7 +135509,8 @@ static int growVTrans(sqlite3 *db){ /* Grow the sqlite3.aVTrans array if required */ if( (db->nVTrans%ARRAY_INCR)==0 ){ VTable **aVTrans; - int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR); + sqlite3_int64 nBytes = sizeof(sqlite3_vtab*)* + ((sqlite3_int64)db->nVTrans + ARRAY_INCR); aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes); if( !aVTrans ){ return SQLITE_NOMEM_BKPT; @@ -134827,6 +135683,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab p = vtabDisconnectAll(db, pTab); xDestroy = p->pMod->pModule->xDestroy; assert( xDestroy!=0 ); /* Checked before the virtual table is created */ + pTab->nTabRef++; rc = xDestroy(p->pVtab); /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ if( rc==SQLITE_OK ){ @@ -134835,6 +135692,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab pTab->pVTable = 0; sqlite3VtabUnlock(p); } + sqlite3DeleteTable(db, pTab); } return rc; @@ -135150,9 +136008,9 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ pTab->pSchema = db->aDb[0].pSchema; assert( pTab->nModuleArg==0 ); pTab->iPKey = -1; - addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); - addModuleArgument(db, pTab, 0); - addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); + addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); + addModuleArgument(pParse, pTab, 0); + addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName)); rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr); if( rc ){ sqlite3ErrorMsg(pParse, "%s", zErr); @@ -135277,6 +136135,8 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){ ** planner logic in "where.c". These definitions are broken out into ** a separate source file for easier editing. */ +#ifndef SQLITE_WHEREINT_H +#define SQLITE_WHEREINT_H /* ** Trace output macros @@ -135848,6 +136708,8 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC #define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */ #define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */ +#endif /* !defined(SQLITE_WHEREINT_H) */ + /************** End of whereInt.h ********************************************/ /************** Continuing where we left off in wherecode.c ******************/ @@ -136830,7 +137692,7 @@ static void codeCursorHint( } /* If we survive all prior tests, that means this term is worth hinting */ - pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); + pExpr = sqlite3ExprAnd(pParse, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); } if( pExpr!=0 ){ sWalker.xExprCallback = codeCursorHintFixExpr; @@ -136991,6 +137853,34 @@ static void whereIndexExprTrans( } /* +** The pTruth expression is always true because it is the WHERE clause +** a partial index that is driving a query loop. Look through all of the +** WHERE clause terms on the query, and if any of those terms must be +** true because pTruth is true, then mark those WHERE clause terms as +** coded. +*/ +static void whereApplyPartialIndexConstraints( + Expr *pTruth, + int iTabCur, + WhereClause *pWC +){ + int i; + WhereTerm *pTerm; + while( pTruth->op==TK_AND ){ + whereApplyPartialIndexConstraints(pTruth->pLeft, iTabCur, pWC); + pTruth = pTruth->pRight; + } + for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ + Expr *pExpr; + if( pTerm->wtFlags & TERM_CODED ) continue; + pExpr = pTerm->pExpr; + if( sqlite3ExprCompare(0, pExpr, pTruth, iTabCur)==0 ){ + pTerm->wtFlags |= TERM_CODED; + } + } +} + +/* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ @@ -137599,6 +138489,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo); } + /* If a partial index is driving the loop, try to eliminate WHERE clause + ** terms from the query that must be true due to the WHERE clause of + ** the partial index + */ + if( pIdx->pPartIdxWhere ){ + whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC); + } + /* Record the instruction used to terminate the loop. */ if( pLoop->wsFlags & WHERE_ONEROW ){ pLevel->op = OP_Noop; @@ -137759,10 +138657,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue; testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO ); pExpr = sqlite3ExprDup(db, pExpr, 0); - pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr); + pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr); } if( pAndExpr ){ - pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr); + /* The extra 0x10000 bit on the opcode is masked off and does not + ** become part of the new Expr.op. However, it does make the + ** op==TK_AND comparison inside of sqlite3PExpr() false, and this + ** prevents sqlite3PExpr() from implementing AND short-circuit + ** optimization, which we do not want here. */ + pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr); } } @@ -137905,7 +138808,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( sqlite3VdbeGoto(v, pLevel->addrBrk); sqlite3VdbeResolveLabel(v, iLoopBody); - if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab); + if( pWInfo->nLevel>1 ){ sqlite3StackFree(db, pOrTab); } if( !untestedTerms ) disableTerm(pLevel, pTerm); }else #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ @@ -137992,8 +138895,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( u32 x = pLevel->iLikeRepCntr; if( x>0 ){ skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If,(int)(x>>1)); + VdbeCoverageIf(v, (x&1)==1); + VdbeCoverageIf(v, (x&1)==0); } - VdbeCoverage(v); #endif } #ifdef WHERETRACE_ENABLED /* 0xffff */ @@ -138337,27 +139241,33 @@ static int isLikeOrGlob( zNew[iTo++] = zNew[iFrom]; } zNew[iTo] = 0; + assert( iTo>0 ); - /* If the RHS begins with a digit or a minus sign, then the LHS must be - ** an ordinary column (not a virtual table column) with TEXT affinity. - ** Otherwise the LHS might be numeric and "lhs >= rhs" would be false - ** even though "lhs LIKE rhs" is true. But if the RHS does not start - ** with a digit or '-', then "lhs LIKE rhs" will always be false if - ** the LHS is numeric and so the optimization still works. + /* If the LHS is not an ordinary column with TEXT affinity, then the + ** pattern prefix boundaries (both the start and end boundaries) must + ** not look like a number. Otherwise the pattern might be treated as + ** a number, which will invalidate the LIKE optimization. ** - ** 2018-09-10 ticket c94369cae9b561b1f996d0054bfab11389f9d033 - ** The RHS pattern must not be '/%' because the termination condition - ** will then become "x<'0'" and if the affinity is numeric, will then - ** be converted into "x<0", which is incorrect. + ** Getting this right has been a persistent source of bugs in the + ** LIKE optimization. See, for example: + ** 2018-09-10 https://sqlite.org/src/info/c94369cae9b561b1 + ** 2019-05-02 https://sqlite.org/src/info/b043a54c3de54b28 + ** 2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07 + ** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975 */ - if( sqlite3Isdigit(zNew[0]) - || zNew[0]=='-' - || (zNew[0]+1=='0' && iTo==1) + if( pLeft->op!=TK_COLUMN + || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT + || IsVirtual(pLeft->y.pTab) /* Value might be numeric */ ){ - if( pLeft->op!=TK_COLUMN - || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT - || IsVirtual(pLeft->y.pTab) /* Value might be numeric */ - ){ + int isNum; + double rDummy; + isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + if( isNum<=0 ){ + zNew[iTo-1]++; + isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + zNew[iTo-1]--; + } + if( isNum>0 ){ sqlite3ExprDelete(db, pPrefix); sqlite3ValueFree(pVal); return 0; @@ -139595,6 +140505,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){ }else if( p->x.pList ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); } +#ifndef SQLITE_OMIT_WINDOWFUNC + if( p->op==TK_FUNCTION && p->y.pWin ){ + mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition); + mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy); + } +#endif return mask; } SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ @@ -140238,17 +141154,17 @@ static LogEst estLog(LogEst N){ ** opcodes into OP_Copy when the table is being accessed via co-routine ** instead of via table lookup. ** -** If the bIncrRowid parameter is 0, then any OP_Rowid instructions on -** cursor iTabCur are transformed into OP_Null. Or, if bIncrRowid is non-zero, -** then each OP_Rowid is transformed into an instruction to increment the -** value stored in its output register. +** If the iAutoidxCur is not zero, then any OP_Rowid instructions on +** cursor iTabCur are transformed into OP_Sequence opcode for the +** iAutoidxCur cursor, in order to generate unique rowids for the +** automatic index being generated. */ static void translateColumnToCopy( Parse *pParse, /* Parsing context */ int iStart, /* Translate from this opcode to the end */ int iTabCur, /* OP_Column/OP_Rowid references to this table */ int iRegister, /* The first column is in this register */ - int bIncrRowid /* If non-zero, transform OP_rowid to OP_AddImm(1) */ + int iAutoidxCur /* If non-zero, cursor of autoindex being generated */ ){ Vdbe *v = pParse->pVdbe; VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart); @@ -140262,11 +141178,9 @@ static void translateColumnToCopy( pOp->p2 = pOp->p3; pOp->p3 = 0; }else if( pOp->opcode==OP_Rowid ){ - if( bIncrRowid ){ - /* Increment the value stored in the P2 operand of the OP_Rowid. */ - pOp->opcode = OP_AddImm; - pOp->p1 = pOp->p2; - pOp->p2 = 1; + if( iAutoidxCur ){ + pOp->opcode = OP_Sequence; + pOp->p1 = iAutoidxCur; }else{ pOp->opcode = OP_Null; pOp->p1 = 0; @@ -140413,7 +141327,7 @@ static void constructAutomaticIndex( && (pTerm->wtFlags & TERM_VIRTUAL)==0 && !ExprHasProperty(pExpr, EP_FromJoin) && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){ - pPartial = sqlite3ExprAnd(pParse->db, pPartial, + pPartial = sqlite3ExprAnd(pParse, pPartial, sqlite3ExprDup(pParse->db, pExpr, 0)); } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ @@ -140540,8 +141454,9 @@ static void constructAutomaticIndex( if( pTabItem->fg.viaCoroutine ){ sqlite3VdbeChangeP2(v, addrCounter, regBase+n); testcase( pParse->db->mallocFailed ); + assert( pLevel->iIdxCur>0 ); translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, - pTabItem->regResult, 1); + pTabItem->regResult, pLevel->iIdxCur); sqlite3VdbeGoto(v, addrTop); pTabItem->fg.viaCoroutine = 0; }else{ @@ -143011,11 +143926,11 @@ static int whereLoopAddVirtual( rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn); /* If the call to xBestIndex() with all terms enabled produced a plan - ** that does not require any source tables (IOW: a plan with mBest==0), - ** then there is no point in making any further calls to xBestIndex() - ** since they will all return the same result (if the xBestIndex() - ** implementation is sane). */ - if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){ + ** that does not require any source tables (IOW: a plan with mBest==0) + ** and does not use an IN(...) operator, then there is no point in making + ** any further calls to xBestIndex() since they will all return the same + ** result (if the xBestIndex() implementation is sane). */ + if( rc==SQLITE_OK && ((mBest = (pNew->prereq & ~mPrereq))!=0 || bIn) ){ int seenZero = 0; /* True if a plan with no prereqs seen */ int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */ Bitmask mPrev = 0; @@ -145249,6 +146164,96 @@ static void dense_rankValueFunc(sqlite3_context *pCtx){ } /* +** Implementation of built-in window function nth_value(). This +** implementation is used in "slow mode" only - when the EXCLUDE clause +** is not set to the default value "NO OTHERS". +*/ +struct NthValueCtx { + i64 nStep; + sqlite3_value *pValue; +}; +static void nth_valueStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p ){ + i64 iVal; + switch( sqlite3_value_numeric_type(apArg[1]) ){ + case SQLITE_INTEGER: + iVal = sqlite3_value_int64(apArg[1]); + break; + case SQLITE_FLOAT: { + double fVal = sqlite3_value_double(apArg[1]); + if( ((i64)fVal)!=fVal ) goto error_out; + iVal = (i64)fVal; + break; + } + default: + goto error_out; + } + if( iVal<=0 ) goto error_out; + + p->nStep++; + if( iVal==p->nStep ){ + p->pValue = sqlite3_value_dup(apArg[0]); + if( !p->pValue ){ + sqlite3_result_error_nomem(pCtx); + } + } + } + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); + return; + + error_out: + sqlite3_result_error( + pCtx, "second argument to nth_value must be a positive integer", -1 + ); +} +static void nth_valueFinalizeFunc(sqlite3_context *pCtx){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, 0); + if( p && p->pValue ){ + sqlite3_result_value(pCtx, p->pValue); + sqlite3_value_free(p->pValue); + p->pValue = 0; + } +} +#define nth_valueInvFunc noopStepFunc +#define nth_valueValueFunc noopValueFunc + +static void first_valueStepFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->pValue==0 ){ + p->pValue = sqlite3_value_dup(apArg[0]); + if( !p->pValue ){ + sqlite3_result_error_nomem(pCtx); + } + } + UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); +} +static void first_valueFinalizeFunc(sqlite3_context *pCtx){ + struct NthValueCtx *p; + p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + if( p && p->pValue ){ + sqlite3_result_value(pCtx, p->pValue); + sqlite3_value_free(p->pValue); + p->pValue = 0; + } +} +#define first_valueInvFunc noopStepFunc +#define first_valueValueFunc noopValueFunc + +/* ** Implementation of built-in window function rank(). Assumes that ** the window frame has been set to: ** @@ -145283,7 +146288,7 @@ static void rankValueFunc(sqlite3_context *pCtx){ ** Implementation of built-in window function percent_rank(). Assumes that ** the window frame has been set to: ** -** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +** GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING */ static void percent_rankStepFunc( sqlite3_context *pCtx, @@ -145291,38 +146296,44 @@ static void percent_rankStepFunc( sqlite3_value **apArg ){ struct CallCount *p; - UNUSED_PARAMETER(nArg); assert( nArg==1 ); - + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ - if( p->nTotal==0 ){ - p->nTotal = sqlite3_value_int64(apArg[0]); - } - p->nStep++; - if( p->nValue==0 ){ - p->nValue = p->nStep; - } + p->nTotal++; } } +static void percent_rankInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct CallCount *p; + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p->nStep++; +} static void percent_rankValueFunc(sqlite3_context *pCtx){ struct CallCount *p; p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ + p->nValue = p->nStep; if( p->nTotal>1 ){ - double r = (double)(p->nValue-1) / (double)(p->nTotal-1); + double r = (double)p->nValue / (double)(p->nTotal-1); sqlite3_result_double(pCtx, r); }else{ sqlite3_result_double(pCtx, 0.0); } - p->nValue = 0; } } +#define percent_rankFinalizeFunc percent_rankValueFunc /* ** Implementation of built-in window function cume_dist(). Assumes that ** the window frame has been set to: ** -** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW +** GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING */ static void cume_distStepFunc( sqlite3_context *pCtx, @@ -145330,24 +146341,33 @@ static void cume_distStepFunc( sqlite3_value **apArg ){ struct CallCount *p; - assert( nArg==1 ); UNUSED_PARAMETER(nArg); - + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ - if( p->nTotal==0 ){ - p->nTotal = sqlite3_value_int64(apArg[0]); - } - p->nStep++; + p->nTotal++; } } -static void cume_distValueFunc(sqlite3_context *pCtx){ +static void cume_distInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ struct CallCount *p; + UNUSED_PARAMETER(nArg); assert( nArg==0 ); + UNUSED_PARAMETER(apArg); p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p)); - if( p && p->nTotal ){ + p->nStep++; +} +static void cume_distValueFunc(sqlite3_context *pCtx){ + struct CallCount *p; + p = (struct CallCount*)sqlite3_aggregate_context(pCtx, 0); + if( p ){ double r = (double)(p->nStep) / (double)(p->nTotal); sqlite3_result_double(pCtx, r); } } +#define cume_distFinalizeFunc cume_distValueFunc /* ** Context object for ntile() window function. @@ -145362,7 +146382,7 @@ struct NtileCtx { ** Implementation of ntile(). This assumes that the window frame has ** been coerced to: ** -** ROWS UNBOUNDED PRECEDING AND CURRENT ROW +** ROWS CURRENT ROW AND UNBOUNDED FOLLOWING */ static void ntileStepFunc( sqlite3_context *pCtx, @@ -145370,32 +146390,42 @@ static void ntileStepFunc( sqlite3_value **apArg ){ struct NtileCtx *p; - assert( nArg==2 ); UNUSED_PARAMETER(nArg); + assert( nArg==1 ); UNUSED_PARAMETER(nArg); p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p ){ if( p->nTotal==0 ){ p->nParam = sqlite3_value_int64(apArg[0]); - p->nTotal = sqlite3_value_int64(apArg[1]); if( p->nParam<=0 ){ sqlite3_result_error( pCtx, "argument of ntile must be a positive integer", -1 ); } } - p->iRow++; + p->nTotal++; } } +static void ntileInvFunc( + sqlite3_context *pCtx, + int nArg, + sqlite3_value **apArg +){ + struct NtileCtx *p; + assert( nArg==1 ); UNUSED_PARAMETER(nArg); + UNUSED_PARAMETER(apArg); + p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p->iRow++; +} static void ntileValueFunc(sqlite3_context *pCtx){ struct NtileCtx *p; p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); if( p && p->nParam>0 ){ int nSize = (p->nTotal / p->nParam); if( nSize==0 ){ - sqlite3_result_int64(pCtx, p->iRow); + sqlite3_result_int64(pCtx, p->iRow+1); }else{ i64 nLarge = p->nTotal - p->nParam*nSize; i64 iSmall = nLarge*(nSize+1); - i64 iRow = p->iRow-1; + i64 iRow = p->iRow; assert( (nLarge*(nSize+1) + (p->nParam-nLarge)*nSize)==p->nTotal ); @@ -145407,6 +146437,7 @@ static void ntileValueFunc(sqlite3_context *pCtx){ } } } +#define ntileFinalizeFunc ntileValueFunc /* ** Context object for last_value() window function. @@ -145456,7 +146487,7 @@ static void last_valueInvFunc( } static void last_valueValueFunc(sqlite3_context *pCtx){ struct LastValueCtx *p; - p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p)); + p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, 0); if( p && p->pVal ){ sqlite3_result_value(pCtx, p->pVal); } @@ -145546,12 +146577,12 @@ SQLITE_PRIVATE void sqlite3WindowFunctions(void){ WINDOWFUNCX(row_number, 0, 0), WINDOWFUNCX(dense_rank, 0, 0), WINDOWFUNCX(rank, 0, 0), - WINDOWFUNCX(percent_rank, 0, SQLITE_FUNC_WINDOW_SIZE), - WINDOWFUNCX(cume_dist, 0, SQLITE_FUNC_WINDOW_SIZE), - WINDOWFUNCX(ntile, 1, SQLITE_FUNC_WINDOW_SIZE), + WINDOWFUNCALL(percent_rank, 0, 0), + WINDOWFUNCALL(cume_dist, 0, 0), + WINDOWFUNCALL(ntile, 1, 0), WINDOWFUNCALL(last_value, 1, 0), - WINDOWFUNCNOOP(nth_value, 2, 0), - WINDOWFUNCNOOP(first_value, 1, 0), + WINDOWFUNCALL(nth_value, 2, 0), + WINDOWFUNCALL(first_value, 1, 0), WINDOWFUNCNOOP(lead, 1, 0), WINDOWFUNCNOOP(lead, 2, 0), WINDOWFUNCNOOP(lead, 3, 0), @@ -145562,6 +146593,17 @@ SQLITE_PRIVATE void sqlite3WindowFunctions(void){ sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs)); } +static Window *windowFind(Parse *pParse, Window *pList, const char *zName){ + Window *p; + for(p=pList; p; p=p->pNextWin){ + if( sqlite3StrICmp(p->zName, zName)==0 ) break; + } + if( p==0 ){ + sqlite3ErrorMsg(pParse, "no such window: %s", zName); + } + return p; +} + /* ** This function is called immediately after resolving the function name ** for a window function within a SELECT statement. Argument pList is a @@ -145585,48 +146627,66 @@ SQLITE_PRIVATE void sqlite3WindowUpdate( Window *pWin, /* Window frame to update */ FuncDef *pFunc /* Window function definition */ ){ - if( pWin->zName && pWin->eType==0 ){ - Window *p; - for(p=pList; p; p=p->pNextWin){ - if( sqlite3StrICmp(p->zName, pWin->zName)==0 ) break; - } - if( p==0 ){ - sqlite3ErrorMsg(pParse, "no such window: %s", pWin->zName); - return; - } + if( pWin->zName && pWin->eFrmType==0 ){ + Window *p = windowFind(pParse, pList, pWin->zName); + if( p==0 ) return; pWin->pPartition = sqlite3ExprListDup(pParse->db, p->pPartition, 0); pWin->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy, 0); pWin->pStart = sqlite3ExprDup(pParse->db, p->pStart, 0); pWin->pEnd = sqlite3ExprDup(pParse->db, p->pEnd, 0); pWin->eStart = p->eStart; pWin->eEnd = p->eEnd; - pWin->eType = p->eType; + pWin->eFrmType = p->eFrmType; + pWin->eExclude = p->eExclude; + }else{ + sqlite3WindowChain(pParse, pWin, pList); } + if( (pWin->eFrmType==TK_RANGE) + && (pWin->pStart || pWin->pEnd) + && (pWin->pOrderBy==0 || pWin->pOrderBy->nExpr!=1) + ){ + sqlite3ErrorMsg(pParse, + "RANGE with offset PRECEDING/FOLLOWING requires one ORDER BY expression" + ); + }else if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){ sqlite3 *db = pParse->db; if( pWin->pFilter ){ sqlite3ErrorMsg(pParse, "FILTER clause may only be used with aggregate window functions" ); - }else - if( pFunc->zName==row_numberName || pFunc->zName==ntileName ){ - sqlite3ExprDelete(db, pWin->pStart); - sqlite3ExprDelete(db, pWin->pEnd); - pWin->pStart = pWin->pEnd = 0; - pWin->eType = TK_ROWS; - pWin->eStart = TK_UNBOUNDED; - pWin->eEnd = TK_CURRENT; - }else - - if( pFunc->zName==dense_rankName || pFunc->zName==rankName - || pFunc->zName==percent_rankName || pFunc->zName==cume_distName - ){ - sqlite3ExprDelete(db, pWin->pStart); - sqlite3ExprDelete(db, pWin->pEnd); - pWin->pStart = pWin->pEnd = 0; - pWin->eType = TK_RANGE; - pWin->eStart = TK_UNBOUNDED; - pWin->eEnd = TK_CURRENT; + }else{ + struct WindowUpdate { + const char *zFunc; + int eFrmType; + int eStart; + int eEnd; + } aUp[] = { + { row_numberName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT }, + { dense_rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT }, + { rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT }, + { percent_rankName, TK_GROUPS, TK_CURRENT, TK_UNBOUNDED }, + { cume_distName, TK_GROUPS, TK_FOLLOWING, TK_UNBOUNDED }, + { ntileName, TK_ROWS, TK_CURRENT, TK_UNBOUNDED }, + { leadName, TK_ROWS, TK_UNBOUNDED, TK_UNBOUNDED }, + { lagName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT }, + }; + int i; + for(i=0; i<ArraySize(aUp); i++){ + if( pFunc->zName==aUp[i].zFunc ){ + sqlite3ExprDelete(db, pWin->pStart); + sqlite3ExprDelete(db, pWin->pEnd); + pWin->pEnd = pWin->pStart = 0; + pWin->eFrmType = aUp[i].eFrmType; + pWin->eStart = aUp[i].eStart; + pWin->eEnd = aUp[i].eEnd; + pWin->eExclude = 0; + if( pWin->eStart==TK_FOLLOWING ){ + pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1"); + } + break; + } + } } } pWin->pFunc = pFunc; @@ -145641,6 +146701,7 @@ struct WindowRewrite { Window *pWin; SrcList *pSrc; ExprList *pSub; + Table *pTab; Select *pSubSelect; /* Current sub-select, if any */ }; @@ -145701,6 +146762,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){ pExpr->op = TK_COLUMN; pExpr->iColumn = p->pSub->nExpr-1; pExpr->iTable = p->pWin->iEphCsr; + pExpr->y.pTab = p->pTab; } break; @@ -145744,6 +146806,7 @@ static void selectWindowRewriteEList( Window *pWin, SrcList *pSrc, ExprList *pEList, /* Rewrite expressions in this list */ + Table *pTab, ExprList **ppSub /* IN/OUT: Sub-select expression-list */ ){ Walker sWalker; @@ -145755,6 +146818,7 @@ static void selectWindowRewriteEList( sRewrite.pSub = *ppSub; sRewrite.pWin = pWin; sRewrite.pSrc = pSrc; + sRewrite.pTab = pTab; sWalker.pParse = pParse; sWalker.xExprCallback = selectWindowRewriteExprCb; @@ -145773,13 +146837,18 @@ static void selectWindowRewriteEList( static ExprList *exprListAppendList( Parse *pParse, /* Parsing context */ ExprList *pList, /* List to which to append. Might be NULL */ - ExprList *pAppend /* List of values to append. Might be NULL */ + ExprList *pAppend, /* List of values to append. Might be NULL */ + int bIntToNull ){ if( pAppend ){ int i; int nInit = pList ? pList->nExpr : 0; for(i=0; i<pAppend->nExpr; i++){ Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0); + if( bIntToNull && pDup && pDup->op==TK_INTEGER ){ + pDup->op = TK_NULL; + pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse); + } pList = sqlite3ExprListAppend(pParse, pList, pDup); if( pList ) pList->a[nInit+i].sortOrder = pAppend->a[i].sortOrder; } @@ -145809,17 +146878,24 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ ExprList *pSublist = 0; /* Expression list for sub-query */ Window *pMWin = p->pWin; /* Master window object */ Window *pWin; /* Window object iterator */ + Table *pTab; + + pTab = sqlite3DbMallocZero(db, sizeof(Table)); + if( pTab==0 ){ + return SQLITE_NOMEM; + } p->pSrc = 0; p->pWhere = 0; p->pGroupBy = 0; p->pHaving = 0; + p->selFlags &= ~SF_Aggregate; /* Create the ORDER BY clause for the sub-select. This is the concatenation ** of the window PARTITION and ORDER BY clauses. Then, if this makes it ** redundant, remove the ORDER BY from the parent SELECT. */ pSort = sqlite3ExprListDup(db, pMWin->pPartition, 0); - pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy); + pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1); if( pSort && p->pOrderBy ){ if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){ sqlite3ExprListDelete(db, p->pOrderBy); @@ -145831,16 +146907,17 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ ** The OpenEphemeral instruction is coded later, after it is known how ** many columns the table will have. */ pMWin->iEphCsr = pParse->nTab++; + pParse->nTab += 3; - selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, &pSublist); - selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, &pSublist); + selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, pTab, &pSublist); + selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, pTab, &pSublist); pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0); /* Append the PARTITION BY and ORDER BY expressions to the to the ** sub-select expression list. They are required to figure out where ** boundaries for partitions and sets of peer rows lie. */ - pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition); - pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy); + pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition, 0); + pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy, 0); /* Append the arguments passed to each window function to the ** sub-select expression list. Also allocate two registers for each @@ -145848,7 +146925,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ ** results. */ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); - pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList); + pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList, 0); if( pWin->pFilter ){ Expr *pFilter = sqlite3ExprDup(db, pWin->pFilter, 0); pSublist = sqlite3ExprListAppend(pParse, pSublist, pFilter); @@ -145875,21 +146952,28 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ ); p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( p->pSrc ){ + Table *pTab2; p->pSrc->a[0].pSelect = pSub; sqlite3SrcListAssignCursors(pParse, p->pSrc); - if( sqlite3ExpandSubquery(pParse, &p->pSrc->a[0]) ){ + pSub->selFlags |= SF_Expanded; + pTab2 = sqlite3ResultSetOfSelect(pParse, pSub); + if( pTab2==0 ){ rc = SQLITE_NOMEM; }else{ - pSub->selFlags |= SF_Expanded; - p->selFlags &= ~SF_Aggregate; - sqlite3SelectPrep(pParse, pSub, 0); + memcpy(pTab, pTab2, sizeof(Table)); + pTab->tabFlags |= TF_Ephemeral; + p->pSrc->a[0].pTab = pTab; + pTab = pTab2; } - sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr); }else{ sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; + sqlite3DbFree(db, pTab); } return rc; @@ -145906,6 +146990,7 @@ SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3 *db, Window *p){ sqlite3ExprDelete(db, p->pEnd); sqlite3ExprDelete(db, p->pStart); sqlite3DbFree(db, p->zName); + sqlite3DbFree(db, p->zBase); sqlite3DbFree(db, p); } } @@ -145942,16 +147027,18 @@ static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){ */ SQLITE_PRIVATE Window *sqlite3WindowAlloc( Parse *pParse, /* Parsing context */ - int eType, /* Frame type. TK_RANGE or TK_ROWS */ + int eType, /* Frame type. TK_RANGE, TK_ROWS, TK_GROUPS, or 0 */ int eStart, /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */ Expr *pStart, /* Start window size if TK_PRECEDING or FOLLOWING */ int eEnd, /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */ - Expr *pEnd /* End window size if TK_FOLLOWING or PRECEDING */ + Expr *pEnd, /* End window size if TK_FOLLOWING or PRECEDING */ + u8 eExclude /* EXCLUDE clause */ ){ Window *pWin = 0; + int bImplicitFrame = 0; /* Parser assures the following: */ - assert( eType==TK_RANGE || eType==TK_ROWS ); + assert( eType==0 || eType==TK_RANGE || eType==TK_ROWS || eType==TK_GROUPS ); assert( eStart==TK_CURRENT || eStart==TK_PRECEDING || eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING ); assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING @@ -145959,13 +147046,9 @@ SQLITE_PRIVATE Window *sqlite3WindowAlloc( assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) ); assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) ); - - /* If a frame is declared "RANGE" (not "ROWS"), then it may not use - ** either "<expr> PRECEDING" or "<expr> FOLLOWING". - */ - if( eType==TK_RANGE && (pStart!=0 || pEnd!=0) ){ - sqlite3ErrorMsg(pParse, "RANGE must use only UNBOUNDED or CURRENT ROW"); - goto windowAllocErr; + if( eType==0 ){ + bImplicitFrame = 1; + eType = TK_RANGE; } /* Additionally, the @@ -145985,15 +147068,20 @@ SQLITE_PRIVATE Window *sqlite3WindowAlloc( if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING) || (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT)) ){ - sqlite3ErrorMsg(pParse, "unsupported frame delimiter for ROWS"); + sqlite3ErrorMsg(pParse, "unsupported frame specification"); goto windowAllocErr; } pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( pWin==0 ) goto windowAllocErr; - pWin->eType = eType; + pWin->eFrmType = eType; pWin->eStart = eStart; pWin->eEnd = eEnd; + if( eExclude==0 && OptimizationDisabled(pParse->db, SQLITE_WindowFunc) ){ + eExclude = TK_NO; + } + pWin->eExclude = eExclude; + pWin->bImplicitFrame = bImplicitFrame; pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd); pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart); return pWin; @@ -146005,6 +147093,69 @@ windowAllocErr: } /* +** Attach PARTITION and ORDER BY clauses pPartition and pOrderBy to window +** pWin. Also, if parameter pBase is not NULL, set pWin->zBase to the +** equivalent nul-terminated string. +*/ +SQLITE_PRIVATE Window *sqlite3WindowAssemble( + Parse *pParse, + Window *pWin, + ExprList *pPartition, + ExprList *pOrderBy, + Token *pBase +){ + if( pWin ){ + pWin->pPartition = pPartition; + pWin->pOrderBy = pOrderBy; + if( pBase ){ + pWin->zBase = sqlite3DbStrNDup(pParse->db, pBase->z, pBase->n); + } + }else{ + sqlite3ExprListDelete(pParse->db, pPartition); + sqlite3ExprListDelete(pParse->db, pOrderBy); + } + return pWin; +} + +/* +** Window *pWin has just been created from a WINDOW clause. Tokne pBase +** is the base window. Earlier windows from the same WINDOW clause are +** stored in the linked list starting at pWin->pNextWin. This function +** either updates *pWin according to the base specification, or else +** leaves an error in pParse. +*/ +SQLITE_PRIVATE void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pList){ + if( pWin->zBase ){ + sqlite3 *db = pParse->db; + Window *pExist = windowFind(pParse, pList, pWin->zBase); + if( pExist ){ + const char *zErr = 0; + /* Check for errors */ + if( pWin->pPartition ){ + zErr = "PARTITION clause"; + }else if( pExist->pOrderBy && pWin->pOrderBy ){ + zErr = "ORDER BY clause"; + }else if( pExist->bImplicitFrame==0 ){ + zErr = "frame specification"; + } + if( zErr ){ + sqlite3ErrorMsg(pParse, + "cannot override %s of window: %s", zErr, pWin->zBase + ); + }else{ + pWin->pPartition = sqlite3ExprListDup(db, pExist->pPartition, 0); + if( pExist->pOrderBy ){ + assert( pWin->pOrderBy==0 ); + pWin->pOrderBy = sqlite3ExprListDup(db, pExist->pOrderBy, 0); + } + sqlite3DbFree(db, pWin->zBase); + pWin->zBase = 0; + } + } + } +} + +/* ** Attach window object pWin to expression p. */ SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ @@ -146032,9 +147183,10 @@ SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ ** Identical window objects can be processed in a single scan. */ SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){ - if( p1->eType!=p2->eType ) return 1; + if( p1->eFrmType!=p2->eFrmType ) return 1; if( p1->eStart!=p2->eStart ) return 1; if( p1->eEnd!=p2->eEnd ) return 1; + if( p1->eExclude!=p2->eExclude ) return 1; if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1; if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1; if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1; @@ -146051,12 +147203,27 @@ SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){ Window *pWin; Vdbe *v = sqlite3GetVdbe(pParse); - int nPart = (pMWin->pPartition ? pMWin->pPartition->nExpr : 0); - nPart += (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); - if( nPart ){ + + /* Allocate registers to use for PARTITION BY values, if any. Initialize + ** said registers to NULL. */ + if( pMWin->pPartition ){ + int nExpr = pMWin->pPartition->nExpr; pMWin->regPart = pParse->nMem+1; - pParse->nMem += nPart; - sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nPart-1); + pParse->nMem += nExpr; + sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nExpr-1); + } + + pMWin->regOne = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regOne); + + if( pMWin->eExclude ){ + pMWin->regStartRowid = ++pParse->nMem; + pMWin->regEndRowid = ++pParse->nMem; + pMWin->csrApp = pParse->nTab++; + sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid); + sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->csrApp, pMWin->iEphCsr); + return; } for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ @@ -146085,20 +147252,24 @@ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){ else if( p->zName==nth_valueName || p->zName==first_valueName ){ /* Allocate two registers at pWin->regApp. These will be used to ** store the start and end index of the current frame. */ - assert( pMWin->iEphCsr ); pWin->regApp = pParse->nMem+1; pWin->csrApp = pParse->nTab++; pParse->nMem += 2; sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); } else if( p->zName==leadName || p->zName==lagName ){ - assert( pMWin->iEphCsr ); pWin->csrApp = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr); } } } +#define WINDOW_STARTING_INT 0 +#define WINDOW_ENDING_INT 1 +#define WINDOW_NTH_VALUE_INT 2 +#define WINDOW_STARTING_NUM 3 +#define WINDOW_ENDING_NUM 4 + /* ** A "PRECEDING <expr>" (eCond==0) or "FOLLOWING <expr>" (eCond==1) or the ** value of the second argument to nth_value() (eCond==2) has just been @@ -146106,25 +147277,42 @@ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){ ** code to check that the value is a non-negative integer and throws an ** exception if it is not. */ -static void windowCheckIntValue(Parse *pParse, int reg, int eCond){ +static void windowCheckValue(Parse *pParse, int reg, int eCond){ static const char *azErr[] = { "frame starting offset must be a non-negative integer", "frame ending offset must be a non-negative integer", - "second argument to nth_value must be a positive integer" + "second argument to nth_value must be a positive integer", + "frame starting offset must be a non-negative number", + "frame ending offset must be a non-negative number", }; - static int aOp[] = { OP_Ge, OP_Ge, OP_Gt }; + static int aOp[] = { OP_Ge, OP_Ge, OP_Gt, OP_Ge, OP_Ge }; Vdbe *v = sqlite3GetVdbe(pParse); int regZero = sqlite3GetTempReg(pParse); - assert( eCond==0 || eCond==1 || eCond==2 ); + assert( eCond>=0 && eCond<ArraySize(azErr) ); sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero); - sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverageIf(v, eCond==0); - VdbeCoverageIf(v, eCond==1); - VdbeCoverageIf(v, eCond==2); + if( eCond>=WINDOW_STARTING_NUM ){ + int regString = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); + sqlite3VdbeAddOp3(v, OP_Ge, regString, sqlite3VdbeCurrentAddr(v)+2, reg); + sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC|SQLITE_JUMPIFNULL); + VdbeCoverage(v); + assert( eCond==3 || eCond==4 ); + VdbeCoverageIf(v, eCond==3); + VdbeCoverageIf(v, eCond==4); + }else{ + sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + assert( eCond==0 || eCond==1 || eCond==2 ); + VdbeCoverageIf(v, eCond==0); + VdbeCoverageIf(v, eCond==1); + VdbeCoverageIf(v, eCond==2); + } sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg); - VdbeCoverageNeverNullIf(v, eCond==0); - VdbeCoverageNeverNullIf(v, eCond==1); + VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */ + VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */ VdbeCoverageNeverNullIf(v, eCond==2); + VdbeCoverageNeverNullIf(v, eCond==3); /* NULL case caught by */ + VdbeCoverageNeverNullIf(v, eCond==4); /* the OP_Ge */ sqlite3MayAbort(pParse); sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort); sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC); @@ -146164,37 +147352,28 @@ static void windowAggStep( Window *pMWin, /* Linked list of window functions */ int csr, /* Read arguments from this cursor */ int bInverse, /* True to invoke xInverse instead of xStep */ - int reg, /* Array of registers */ - int regPartSize /* Register containing size of partition */ + int reg /* Array of registers */ ){ Vdbe *v = sqlite3GetVdbe(pParse); Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ - int flags = pWin->pFunc->funcFlags; + FuncDef *pFunc = pWin->pFunc; int regArg; int nArg = windowArgCount(pWin); + int i; - if( csr>=0 ){ - int i; - for(i=0; i<nArg; i++){ + for(i=0; i<nArg; i++){ + if( i!=1 || pFunc->zName!=nth_valueName ){ sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i); + }else{ + sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i); } - regArg = reg; - if( flags & SQLITE_FUNC_WINDOW_SIZE ){ - if( nArg==0 ){ - regArg = regPartSize; - }else{ - sqlite3VdbeAddOp2(v, OP_SCopy, regPartSize, reg+nArg); - } - nArg++; - } - }else{ - assert( !(flags & SQLITE_FUNC_WINDOW_SIZE) ); - regArg = reg + pWin->iArgCol; } + regArg = reg; - if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) - && pWin->eStart!=TK_UNBOUNDED + if( pMWin->regStartRowid==0 + && (pFunc->funcFlags & SQLITE_FUNC_MINMAX) + && (pWin->eStart!=TK_UNBOUNDED) ){ int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg); VdbeCoverage(v); @@ -146211,34 +147390,24 @@ static void windowAggStep( } sqlite3VdbeJumpHere(v, addrIsNull); }else if( pWin->regApp ){ - assert( pWin->pFunc->zName==nth_valueName - || pWin->pFunc->zName==first_valueName + assert( pFunc->zName==nth_valueName + || pFunc->zName==first_valueName ); assert( bInverse==0 || bInverse==1 ); sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1); - }else if( pWin->pFunc->zName==leadName - || pWin->pFunc->zName==lagName - ){ - /* no-op */ - }else{ + }else if( pFunc->xSFunc!=noopStepFunc ){ int addrIf = 0; if( pWin->pFilter ){ int regTmp; assert( nArg==0 || nArg==pWin->pOwner->x.pList->nExpr ); assert( nArg || pWin->pOwner->x.pList==0 ); - if( csr>0 ){ - regTmp = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); - }else{ - regTmp = regArg + nArg; - } + regTmp = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp); addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1); VdbeCoverage(v); - if( csr>0 ){ - sqlite3ReleaseTempReg(pParse, regTmp); - } + sqlite3ReleaseTempReg(pParse, regTmp); } - if( pWin->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ + if( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl; assert( nArg>0 ); pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr); @@ -146246,45 +147415,96 @@ static void windowAggStep( } sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep, bInverse, regArg, pWin->regAccum); - sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); + sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } } } +typedef struct WindowCodeArg WindowCodeArg; +typedef struct WindowCsrAndReg WindowCsrAndReg; +struct WindowCsrAndReg { + int csr; + int reg; +}; + +struct WindowCodeArg { + Parse *pParse; + Window *pMWin; + Vdbe *pVdbe; + int regGosub; + int addrGosub; + int regArg; + int eDelete; + + WindowCsrAndReg start; + WindowCsrAndReg current; + WindowCsrAndReg end; +}; + +/* +** Values that may be passed as the second argument to windowCodeOp(). +*/ +#define WINDOW_RETURN_ROW 1 +#define WINDOW_AGGINVERSE 2 +#define WINDOW_AGGSTEP 3 + +/* +** Generate VM code to read the window frames peer values from cursor csr into +** an array of registers starting at reg. +*/ +static void windowReadPeerValues( + WindowCodeArg *p, + int csr, + int reg +){ + Window *pMWin = p->pMWin; + ExprList *pOrderBy = pMWin->pOrderBy; + if( pOrderBy ){ + Vdbe *v = sqlite3GetVdbe(p->pParse); + ExprList *pPart = pMWin->pPartition; + int iColOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0); + int i; + for(i=0; i<pOrderBy->nExpr; i++){ + sqlite3VdbeAddOp3(v, OP_Column, csr, iColOff+i, reg+i); + } + } +} + /* -** Generate VM code to invoke either xValue() (bFinal==0) or xFinalize() -** (bFinal==1) for each window function in the linked list starting at +** Generate VM code to invoke either xValue() (bFin==0) or xFinalize() +** (bFin==1) for each window function in the linked list starting at ** pMWin. Or, for built-in window-functions that do not use the standard ** API, generate the equivalent VM code. */ -static void windowAggFinal(Parse *pParse, Window *pMWin, int bFinal){ +static void windowAggFinal(WindowCodeArg *p, int bFin){ + Parse *pParse = p->pParse; + Window *pMWin = p->pMWin; Vdbe *v = sqlite3GetVdbe(pParse); Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ - if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) - && pWin->eStart!=TK_UNBOUNDED + if( pMWin->regStartRowid==0 + && (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) + && (pWin->eStart!=TK_UNBOUNDED) ){ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); sqlite3VdbeAddOp1(v, OP_Last, pWin->csrApp); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, pWin->csrApp, 0, pWin->regResult); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); - if( bFinal ){ - sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); - } }else if( pWin->regApp ){ + assert( pMWin->regStartRowid==0 ); }else{ - if( bFinal ){ - sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin)); + int nArg = windowArgCount(pWin); + if( bFin ){ + sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, nArg); sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); }else{ - sqlite3VdbeAddOp3(v, OP_AggValue, pWin->regAccum, windowArgCount(pWin), - pWin->regResult); + sqlite3VdbeAddOp3(v, OP_AggValue,pWin->regAccum,nArg,pWin->regResult); sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF); } } @@ -146292,66 +147512,97 @@ static void windowAggFinal(Parse *pParse, Window *pMWin, int bFinal){ } /* -** This function generates VM code to invoke the sub-routine at address -** lblFlushPart once for each partition with the entire partition cached in -** the Window.iEphCsr temp table. +** Generate code to calculate the current values of all window functions in the +** p->pMWin list by doing a full scan of the current window frame. Store the +** results in the Window.regResult registers, ready to return the upper +** layer. */ -static void windowPartitionCache( - Parse *pParse, - Select *p, /* The rewritten SELECT statement */ - WhereInfo *pWInfo, /* WhereInfo to call WhereEnd() on */ - int regFlushPart, /* Register to use with Gosub lblFlushPart */ - int lblFlushPart, /* Subroutine to Gosub to */ - int *pRegSize /* OUT: Register containing partition size */ -){ - Window *pMWin = p->pWin; - Vdbe *v = sqlite3GetVdbe(pParse); - int iSubCsr = p->pSrc->a[0].iCursor; - int nSub = p->pSrc->a[0].pTab->nCol; - int k; +static void windowFullScan(WindowCodeArg *p){ + Window *pWin; + Parse *pParse = p->pParse; + Window *pMWin = p->pMWin; + Vdbe *v = p->pVdbe; - int reg = pParse->nMem+1; - int regRecord = reg+nSub; - int regRowid = regRecord+1; + int regCRowid = 0; /* Current rowid value */ + int regCPeer = 0; /* Current peer values */ + int regRowid = 0; /* AggStep rowid value */ + int regPeer = 0; /* AggStep peer values */ - *pRegSize = regRowid; - pParse->nMem += nSub + 2; + int nPeer; + int lblNext; + int lblBrk; + int addrNext; + int csr = pMWin->csrApp; - /* Load the column values for the row returned by the sub-select - ** into an array of registers starting at reg. */ - for(k=0; k<nSub; k++){ - sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k); + nPeer = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); + + lblNext = sqlite3VdbeMakeLabel(pParse); + lblBrk = sqlite3VdbeMakeLabel(pParse); + + regCRowid = sqlite3GetTempReg(pParse); + regRowid = sqlite3GetTempReg(pParse); + if( nPeer ){ + regCPeer = sqlite3GetTempRange(pParse, nPeer); + regPeer = sqlite3GetTempRange(pParse, nPeer); } - sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, nSub, regRecord); - /* Check if this is the start of a new partition. If so, call the - ** flush_partition sub-routine. */ - if( pMWin->pPartition ){ + sqlite3VdbeAddOp2(v, OP_Rowid, pMWin->iEphCsr, regCRowid); + windowReadPeerValues(p, pMWin->iEphCsr, regCPeer); + + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); + } + + sqlite3VdbeAddOp3(v, OP_SeekGE, csr, lblBrk, pMWin->regStartRowid); + VdbeCoverage(v); + addrNext = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_Rowid, csr, regRowid); + sqlite3VdbeAddOp3(v, OP_Gt, pMWin->regEndRowid, lblBrk, regRowid); + VdbeCoverageNeverNull(v); + + if( pMWin->eExclude==TK_CURRENT ){ + sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, lblNext, regRowid); + VdbeCoverageNeverNull(v); + }else if( pMWin->eExclude!=TK_NO ){ int addr; - ExprList *pPart = pMWin->pPartition; - int nPart = pPart->nExpr; - int regNewPart = reg + pMWin->nBufferCol; - KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); + int addrEq = 0; + KeyInfo *pKeyInfo = 0; - addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart); - sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); - sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2); - VdbeCoverageEqNe(v); - sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1); - sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart); - VdbeComment((v, "call flush_partition")); + if( pMWin->pOrderBy ){ + pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pMWin->pOrderBy, 0, 0); + } + if( pMWin->eExclude==TK_TIES ){ + addrEq = sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, 0, regRowid); + VdbeCoverageNeverNull(v); + } + if( pKeyInfo ){ + windowReadPeerValues(p, csr, regPeer); + sqlite3VdbeAddOp3(v, OP_Compare, regPeer, regCPeer, nPeer); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + addr = sqlite3VdbeCurrentAddr(v)+1; + sqlite3VdbeAddOp3(v, OP_Jump, addr, lblNext, addr); + VdbeCoverageEqNe(v); + }else{ + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblNext); + } + if( addrEq ) sqlite3VdbeJumpHere(v, addrEq); } - /* Buffer the current row in the ephemeral table. */ - sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid); + windowAggStep(pParse, pMWin, csr, 0, p->regArg); - /* End of the input loop */ - sqlite3WhereEnd(pWInfo); + sqlite3VdbeResolveLabel(v, lblNext); + sqlite3VdbeAddOp2(v, OP_Next, csr, addrNext); + VdbeCoverage(v); + sqlite3VdbeJumpHere(v, addrNext-1); + sqlite3VdbeJumpHere(v, addrNext+1); + sqlite3ReleaseTempReg(pParse, regRowid); + sqlite3ReleaseTempReg(pParse, regCRowid); + if( nPeer ){ + sqlite3ReleaseTempRange(pParse, regPeer, nPeer); + sqlite3ReleaseTempRange(pParse, regCPeer, nPeer); + } - /* Invoke "flush_partition" to deal with the final (or only) partition */ - sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart); - VdbeComment((v, "call flush_partition")); + windowAggFinal(p, 1); } /* @@ -146367,110 +147618,74 @@ static void windowPartitionCache( ** lag() ** lead() */ -static void windowReturnOneRow( - Parse *pParse, - Window *pMWin, - int regGosub, - int addrGosub -){ - Vdbe *v = sqlite3GetVdbe(pParse); - Window *pWin; - for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ - FuncDef *pFunc = pWin->pFunc; - if( pFunc->zName==nth_valueName - || pFunc->zName==first_valueName - ){ - int csr = pWin->csrApp; - int lbl = sqlite3VdbeMakeLabel(pParse); - int tmpReg = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); +static void windowReturnOneRow(WindowCodeArg *p){ + Window *pMWin = p->pMWin; + Vdbe *v = p->pVdbe; - if( pFunc->zName==nth_valueName ){ - sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+1,tmpReg); - windowCheckIntValue(pParse, tmpReg, 2); - }else{ - sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); - } - sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg); - sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg); - VdbeCoverageNeverNull(v); - sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg); - VdbeCoverageNeverTaken(v); - sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); - sqlite3VdbeResolveLabel(v, lbl); - sqlite3ReleaseTempReg(pParse, tmpReg); - } - else if( pFunc->zName==leadName || pFunc->zName==lagName ){ - int nArg = pWin->pOwner->x.pList->nExpr; - int iEph = pMWin->iEphCsr; - int csr = pWin->csrApp; - int lbl = sqlite3VdbeMakeLabel(pParse); - int tmpReg = sqlite3GetTempReg(pParse); - - if( nArg<3 ){ + if( pMWin->regStartRowid ){ + windowFullScan(p); + }else{ + Parse *pParse = p->pParse; + Window *pWin; + + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + if( pFunc->zName==nth_valueName + || pFunc->zName==first_valueName + ){ + int csr = pWin->csrApp; + int lbl = sqlite3VdbeMakeLabel(pParse); + int tmpReg = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); - }else{ - sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+2, pWin->regResult); - } - sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg); - if( nArg<2 ){ - int val = (pFunc->zName==leadName ? 1 : -1); - sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val); - }else{ - int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract); - int tmpReg2 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2); - sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg); - sqlite3ReleaseTempReg(pParse, tmpReg2); + + if( pFunc->zName==nth_valueName ){ + sqlite3VdbeAddOp3(v, OP_Column,pMWin->iEphCsr,pWin->iArgCol+1,tmpReg); + windowCheckValue(pParse, tmpReg, 2); + }else{ + sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg); + } + sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg); + sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg); + VdbeCoverageNeverNull(v); + sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg); + VdbeCoverageNeverTaken(v); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); + sqlite3VdbeResolveLabel(v, lbl); + sqlite3ReleaseTempReg(pParse, tmpReg); + } + else if( pFunc->zName==leadName || pFunc->zName==lagName ){ + int nArg = pWin->pOwner->x.pList->nExpr; + int csr = pWin->csrApp; + int lbl = sqlite3VdbeMakeLabel(pParse); + int tmpReg = sqlite3GetTempReg(pParse); + int iEph = pMWin->iEphCsr; + + if( nArg<3 ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult); + }else{ + sqlite3VdbeAddOp3(v, OP_Column, iEph,pWin->iArgCol+2,pWin->regResult); + } + sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg); + if( nArg<2 ){ + int val = (pFunc->zName==leadName ? 1 : -1); + sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val); + }else{ + int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract); + int tmpReg2 = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2); + sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg); + sqlite3ReleaseTempReg(pParse, tmpReg2); + } + + sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); + sqlite3VdbeResolveLabel(v, lbl); + sqlite3ReleaseTempReg(pParse, tmpReg); } - - sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult); - sqlite3VdbeResolveLabel(v, lbl); - sqlite3ReleaseTempReg(pParse, tmpReg); } } - sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); -} - -/* -** Invoke the code generated by windowReturnOneRow() and, optionally, the -** xInverse() function for each window function, for one or more rows -** from the Window.iEphCsr temp table. This routine generates VM code -** similar to: -** -** while( regCtr>0 ){ -** regCtr--; -** windowReturnOneRow() -** if( bInverse ){ -** AggInverse -** } -** Next (Window.iEphCsr) -** } -*/ -static void windowReturnRows( - Parse *pParse, - Window *pMWin, /* List of window functions */ - int regCtr, /* Register containing number of rows */ - int regGosub, /* Register for Gosub addrGosub */ - int addrGosub, /* Address of sub-routine for ReturnOneRow */ - int regInvArg, /* Array of registers for xInverse args */ - int regInvSize /* Register containing size of partition */ -){ - int addr; - Vdbe *v = sqlite3GetVdbe(pParse); - windowAggFinal(pParse, pMWin, 0); - addr = sqlite3VdbeAddOp3(v, OP_IfPos, regCtr, sqlite3VdbeCurrentAddr(v)+2 ,1); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, 0); - windowReturnOneRow(pParse, pMWin, regGosub, addrGosub); - if( regInvArg ){ - windowAggStep(pParse, pMWin, pMWin->iEphCsr, 1, regInvArg, regInvSize); - } - sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, addr); - VdbeCoverage(v); - sqlite3VdbeJumpHere(v, addr+1); /* The OP_Goto */ + sqlite3VdbeAddOp2(v, OP_Gosub, p->regGosub, p->addrGosub); } /* @@ -146488,17 +147703,17 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){ FuncDef *pFunc = pWin->pFunc; sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum); nArg = MAX(nArg, windowArgCount(pWin)); - if( pFunc->zName==nth_valueName - || pFunc->zName==first_valueName - ){ - sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp); - sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); - } + if( pMWin->regStartRowid==0 ){ + if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){ + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); + } - if( (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->csrApp ){ - assert( pWin->eStart!=TK_UNBOUNDED ); - sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); - sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); + if( (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->csrApp ){ + assert( pWin->eStart!=TK_UNBOUNDED ); + sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1); + } } } regArg = pParse->nMem+1; @@ -146506,672 +147721,248 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){ return regArg; } +/* +** Return true if the current frame should be cached in the ephemeral table, +** even if there are no xInverse() calls required. +*/ +static int windowCacheFrame(Window *pMWin){ + Window *pWin; + if( pMWin->regStartRowid ) return 1; + for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ + FuncDef *pFunc = pWin->pFunc; + if( (pFunc->zName==nth_valueName) + || (pFunc->zName==first_valueName) + || (pFunc->zName==leadName) + || (pFunc->zName==lagName) + ){ + return 1; + } + } + return 0; +} /* -** This function does the work of sqlite3WindowCodeStep() for all "ROWS" -** window frame types except for "BETWEEN UNBOUNDED PRECEDING AND CURRENT -** ROW". Pseudo-code for each follows. -** -** ROWS BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING -** -** ... -** if( new partition ){ -** Gosub flush_partition -** } -** Insert (record in eph-table) -** sqlite3WhereEnd() -** Gosub flush_partition -** -** flush_partition: -** Once { -** OpenDup (iEphCsr -> csrStart) -** OpenDup (iEphCsr -> csrEnd) -** } -** regStart = <expr1> // PRECEDING expression -** regEnd = <expr2> // FOLLOWING expression -** if( regStart<0 || regEnd<0 ){ error! } -** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done -** Next(csrEnd) // if EOF skip Aggstep -** Aggstep (csrEnd) -** if( (regEnd--)<=0 ){ -** AggFinal (xValue) -** Gosub addrGosub -** Next(csr) // if EOF goto flush_partition_done -** if( (regStart--)<=0 ){ -** AggInverse (csrStart) -** Next(csrStart) -** } -** } -** flush_partition_done: -** ResetSorter (csr) -** Return -** -** ROWS BETWEEN <expr> PRECEDING AND CURRENT ROW -** ROWS BETWEEN CURRENT ROW AND <expr> FOLLOWING -** ROWS BETWEEN UNBOUNDED PRECEDING AND <expr> FOLLOWING -** -** These are similar to the above. For "CURRENT ROW", intialize the -** register to 0. For "UNBOUNDED PRECEDING" to infinity. -** -** ROWS BETWEEN <expr> PRECEDING AND UNBOUNDED FOLLOWING -** ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING -** -** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done -** while( 1 ){ -** Next(csrEnd) // Exit while(1) at EOF -** Aggstep (csrEnd) -** } -** while( 1 ){ -** AggFinal (xValue) -** Gosub addrGosub -** Next(csr) // if EOF goto flush_partition_done -** if( (regStart--)<=0 ){ -** AggInverse (csrStart) -** Next(csrStart) -** } -** } -** -** For the "CURRENT ROW AND UNBOUNDED FOLLOWING" case, the final if() -** condition is always true (as if regStart were initialized to 0). -** -** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING -** -** This is the only RANGE case handled by this routine. It modifies the -** second while( 1 ) loop in "ROWS BETWEEN CURRENT ... UNBOUNDED..." to -** be: -** -** while( 1 ){ -** AggFinal (xValue) -** while( 1 ){ -** regPeer++ -** Gosub addrGosub -** Next(csr) // if EOF goto flush_partition_done -** if( new peer ) break; -** } -** while( (regPeer--)>0 ){ -** AggInverse (csrStart) -** Next(csrStart) -** } -** } -** -** ROWS BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING -** -** regEnd = regEnd - regStart -** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done -** Aggstep (csrEnd) -** Next(csrEnd) // if EOF fall-through -** if( (regEnd--)<=0 ){ -** if( (regStart--)<=0 ){ -** AggFinal (xValue) -** Gosub addrGosub -** Next(csr) // if EOF goto flush_partition_done -** } -** AggInverse (csrStart) -** Next (csrStart) -** } -** -** ROWS BETWEEN <expr> PRECEDING AND <expr> PRECEDING -** -** Replace the bit after "Rewind" in the above with: -** -** if( (regEnd--)<=0 ){ -** AggStep (csrEnd) -** Next (csrEnd) -** } -** AggFinal (xValue) -** Gosub addrGosub -** Next(csr) // if EOF goto flush_partition_done -** if( (regStart--)<=0 ){ -** AggInverse (csr2) -** Next (csr2) -** } +** regOld and regNew are each the first register in an array of size +** pOrderBy->nExpr. This function generates code to compare the two +** arrays of registers using the collation sequences and other comparison +** parameters specified by pOrderBy. ** +** If the two arrays are not equal, the contents of regNew is copied to +** regOld and control falls through. Otherwise, if the contents of the arrays +** are equal, an OP_Goto is executed. The address of the OP_Goto is returned. */ -static void windowCodeRowExprStep( - Parse *pParse, - Select *p, - WhereInfo *pWInfo, - int regGosub, - int addrGosub +static void windowIfNewPeer( + Parse *pParse, + ExprList *pOrderBy, + int regNew, /* First in array of new values */ + int regOld, /* First in array of old values */ + int addr /* Jump here */ ){ - Window *pMWin = p->pWin; Vdbe *v = sqlite3GetVdbe(pParse); - int regFlushPart; /* Register for "Gosub flush_partition" */ - int lblFlushPart; /* Label for "Gosub flush_partition" */ - int lblFlushDone; /* Label for "Gosub flush_partition_done" */ - - int regArg; - int addr; - int csrStart = pParse->nTab++; - int csrEnd = pParse->nTab++; - int regStart; /* Value of <expr> PRECEDING */ - int regEnd; /* Value of <expr> FOLLOWING */ - int addrGoto; - int addrTop; - int addrIfPos1 = 0; - int addrIfPos2 = 0; - int regSize = 0; - - assert( pMWin->eStart==TK_PRECEDING - || pMWin->eStart==TK_CURRENT - || pMWin->eStart==TK_FOLLOWING - || pMWin->eStart==TK_UNBOUNDED - ); - assert( pMWin->eEnd==TK_FOLLOWING - || pMWin->eEnd==TK_CURRENT - || pMWin->eEnd==TK_UNBOUNDED - || pMWin->eEnd==TK_PRECEDING - ); - - /* Allocate register and label for the "flush_partition" sub-routine. */ - regFlushPart = ++pParse->nMem; - lblFlushPart = sqlite3VdbeMakeLabel(pParse); - lblFlushDone = sqlite3VdbeMakeLabel(pParse); - - regStart = ++pParse->nMem; - regEnd = ++pParse->nMem; - - windowPartitionCache(pParse, p, pWInfo, regFlushPart, lblFlushPart, ®Size); - - addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); - - /* Start of "flush_partition" */ - sqlite3VdbeResolveLabel(v, lblFlushPart); - sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3); - VdbeCoverage(v); - VdbeComment((v, "Flush_partition subroutine")); - sqlite3VdbeAddOp2(v, OP_OpenDup, csrStart, pMWin->iEphCsr); - sqlite3VdbeAddOp2(v, OP_OpenDup, csrEnd, pMWin->iEphCsr); - - /* If either regStart or regEnd are not non-negative integers, throw - ** an exception. */ - if( pMWin->pStart ){ - sqlite3ExprCode(pParse, pMWin->pStart, regStart); - windowCheckIntValue(pParse, regStart, 0); - } - if( pMWin->pEnd ){ - sqlite3ExprCode(pParse, pMWin->pEnd, regEnd); - windowCheckIntValue(pParse, regEnd, 1); - } - - /* If this is "ROWS <expr1> FOLLOWING AND ROWS <expr2> FOLLOWING", do: - ** - ** if( regEnd<regStart ){ - ** // The frame always consists of 0 rows - ** regStart = regSize; - ** } - ** regEnd = regEnd - regStart; - */ - if( pMWin->pEnd && pMWin->eStart==TK_FOLLOWING ){ - assert( pMWin->pStart!=0 ); - assert( pMWin->eEnd==TK_FOLLOWING ); - sqlite3VdbeAddOp3(v, OP_Ge, regStart, sqlite3VdbeCurrentAddr(v)+2, regEnd); - VdbeCoverageNeverNull(v); - sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart); - sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regEnd); - } - - if( pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){ - assert( pMWin->pEnd!=0 ); - assert( pMWin->eStart==TK_PRECEDING ); - sqlite3VdbeAddOp3(v, OP_Le, regStart, sqlite3VdbeCurrentAddr(v)+3, regEnd); - VdbeCoverageNeverNull(v); - sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart); - sqlite3VdbeAddOp2(v, OP_Copy, regSize, regEnd); - } - - /* Initialize the accumulator register for each window function to NULL */ - regArg = windowInitAccum(pParse, pMWin); - - sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, lblFlushDone); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, lblFlushDone); - VdbeCoverageNeverTaken(v); - sqlite3VdbeChangeP5(v, 1); - sqlite3VdbeAddOp2(v, OP_Rewind, csrEnd, lblFlushDone); - VdbeCoverageNeverTaken(v); - sqlite3VdbeChangeP5(v, 1); - - /* Invoke AggStep function for each window function using the row that - ** csrEnd currently points to. Or, if csrEnd is already at EOF, - ** do nothing. */ - addrTop = sqlite3VdbeCurrentAddr(v); - if( pMWin->eEnd==TK_PRECEDING ){ - addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1); - VdbeCoverage(v); - } - sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - addr = sqlite3VdbeAddOp0(v, OP_Goto); - windowAggStep(pParse, pMWin, csrEnd, 0, regArg, regSize); - if( pMWin->eEnd==TK_UNBOUNDED ){ - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); - sqlite3VdbeJumpHere(v, addr); - addrTop = sqlite3VdbeCurrentAddr(v); + if( pOrderBy ){ + int nVal = pOrderBy->nExpr; + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); + sqlite3VdbeAddOp3(v, OP_Compare, regOld, regNew, nVal); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + sqlite3VdbeAddOp3(v, OP_Jump, + sqlite3VdbeCurrentAddr(v)+1, addr, sqlite3VdbeCurrentAddr(v)+1 + ); + VdbeCoverageEqNe(v); + sqlite3VdbeAddOp3(v, OP_Copy, regNew, regOld, nVal-1); }else{ - sqlite3VdbeJumpHere(v, addr); - if( pMWin->eEnd==TK_PRECEDING ){ - sqlite3VdbeJumpHere(v, addrIfPos1); - } - } - - if( pMWin->eEnd==TK_FOLLOWING ){ - addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1); - VdbeCoverage(v); - } - if( pMWin->eStart==TK_FOLLOWING ){ - addrIfPos2 = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0 , 1); - VdbeCoverage(v); - } - windowAggFinal(pParse, pMWin, 0); - windowReturnOneRow(pParse, pMWin, regGosub, addrGosub); - sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, lblFlushDone); - if( pMWin->eStart==TK_FOLLOWING ){ - sqlite3VdbeJumpHere(v, addrIfPos2); - } - - if( pMWin->eStart==TK_CURRENT - || pMWin->eStart==TK_PRECEDING - || pMWin->eStart==TK_FOLLOWING - ){ - int lblSkipInverse = sqlite3VdbeMakeLabel(pParse);; - if( pMWin->eStart==TK_PRECEDING ){ - sqlite3VdbeAddOp3(v, OP_IfPos, regStart, lblSkipInverse, 1); - VdbeCoverage(v); - } - if( pMWin->eStart==TK_FOLLOWING ){ - sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Goto, 0, lblSkipInverse); - }else{ - sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1); - VdbeCoverageAlwaysTaken(v); - } - windowAggStep(pParse, pMWin, csrStart, 1, regArg, regSize); - sqlite3VdbeResolveLabel(v, lblSkipInverse); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); } - if( pMWin->eEnd==TK_FOLLOWING ){ - sqlite3VdbeJumpHere(v, addrIfPos1); - } - sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); - - /* flush_partition_done: */ - sqlite3VdbeResolveLabel(v, lblFlushDone); - sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr); - sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); - VdbeComment((v, "end flush_partition subroutine")); - - /* Jump to here to skip over flush_partition */ - sqlite3VdbeJumpHere(v, addrGoto); } /* -** This function does the work of sqlite3WindowCodeStep() for cases that -** would normally be handled by windowCodeDefaultStep() when there are -** one or more built-in window-functions that require the entire partition -** to be cached in a temp table before any rows can be returned. Additionally. -** "RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" is always handled by -** this function. -** -** Pseudo-code corresponding to the VM code generated by this function -** for each type of window follows. -** -** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -** -** flush_partition: -** Once { -** OpenDup (iEphCsr -> csrLead) -** } -** Integer ctr 0 -** foreach row (csrLead){ -** if( new peer ){ -** AggFinal (xValue) -** for(i=0; i<ctr; i++){ -** Gosub addrGosub -** Next iEphCsr -** } -** Integer ctr 0 -** } -** AggStep (csrLead) -** Incr ctr -** } -** -** AggFinal (xFinalize) -** for(i=0; i<ctr; i++){ -** Gosub addrGosub -** Next iEphCsr -** } -** -** ResetSorter (csr) -** Return -** -** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -** -** As above, except that the "if( new peer )" branch is always taken. -** -** RANGE BETWEEN CURRENT ROW AND CURRENT ROW -** -** As above, except that each of the for() loops becomes: -** -** for(i=0; i<ctr; i++){ -** Gosub addrGosub -** AggInverse (iEphCsr) -** Next iEphCsr -** } -** -** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING +** This function is called as part of generating VM programs for RANGE +** offset PRECEDING/FOLLOWING frame boundaries. Assuming "ASC" order for +** the ORDER BY term in the window, it generates code equivalent to: ** -** flush_partition: -** Once { -** OpenDup (iEphCsr -> csrLead) -** } -** foreach row (csrLead) { -** AggStep (csrLead) -** } -** foreach row (iEphCsr) { -** Gosub addrGosub -** } -** -** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING -** -** flush_partition: -** Once { -** OpenDup (iEphCsr -> csrLead) -** } -** foreach row (csrLead){ -** AggStep (csrLead) -** } -** Rewind (csrLead) -** Integer ctr 0 -** foreach row (csrLead){ -** if( new peer ){ -** AggFinal (xValue) -** for(i=0; i<ctr; i++){ -** Gosub addrGosub -** AggInverse (iEphCsr) -** Next iEphCsr -** } -** Integer ctr 0 -** } -** Incr ctr -** } +** if( csr1.peerVal + regVal >= csr2.peerVal ) goto lbl; ** -** AggFinal (xFinalize) -** for(i=0; i<ctr; i++){ -** Gosub addrGosub -** Next iEphCsr -** } -** -** ResetSorter (csr) -** Return +** A special type of arithmetic is used such that if csr.peerVal is not +** a numeric type (real or integer), then the result of the addition is +** a copy of csr1.peerVal. */ -static void windowCodeCacheStep( - Parse *pParse, - Select *p, - WhereInfo *pWInfo, - int regGosub, - int addrGosub +static void windowCodeRangeTest( + WindowCodeArg *p, + int op, /* OP_Ge or OP_Gt */ + int csr1, + int regVal, + int csr2, + int lbl ){ - Window *pMWin = p->pWin; + Parse *pParse = p->pParse; Vdbe *v = sqlite3GetVdbe(pParse); - int k; - int addr; - ExprList *pPart = pMWin->pPartition; - ExprList *pOrderBy = pMWin->pOrderBy; - int nPeer = pOrderBy ? pOrderBy->nExpr : 0; - int regNewPeer; - - int addrGoto; /* Address of Goto used to jump flush_par.. */ - int addrNext; /* Jump here for next iteration of loop */ - int regFlushPart; - int lblFlushPart; - int csrLead; - int regCtr; - int regArg; /* Register array to martial function args */ - int regSize; - int lblEmpty; - int bReverse = pMWin->pOrderBy && pMWin->eStart==TK_CURRENT - && pMWin->eEnd==TK_UNBOUNDED; - - assert( (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT) - || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_UNBOUNDED) - || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_CURRENT) - || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED) - ); - - lblEmpty = sqlite3VdbeMakeLabel(pParse); - regNewPeer = pParse->nMem+1; - pParse->nMem += nPeer; - - /* Allocate register and label for the "flush_partition" sub-routine. */ - regFlushPart = ++pParse->nMem; - lblFlushPart = sqlite3VdbeMakeLabel(pParse); + int reg1 = sqlite3GetTempReg(pParse); + int reg2 = sqlite3GetTempReg(pParse); + int arith = OP_Add; + int addrGe; - csrLead = pParse->nTab++; - regCtr = ++pParse->nMem; - - windowPartitionCache(pParse, p, pWInfo, regFlushPart, lblFlushPart, ®Size); - addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); - - /* Start of "flush_partition" */ - sqlite3VdbeResolveLabel(v, lblFlushPart); - sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_OpenDup, csrLead, pMWin->iEphCsr); - - /* Initialize the accumulator register for each window function to NULL */ - regArg = windowInitAccum(pParse, pMWin); - - sqlite3VdbeAddOp2(v, OP_Integer, 0, regCtr); - sqlite3VdbeAddOp2(v, OP_Rewind, csrLead, lblEmpty); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, lblEmpty); - VdbeCoverageNeverTaken(v); + int regString = ++pParse->nMem; - if( bReverse ){ - int addr2 = sqlite3VdbeCurrentAddr(v); - windowAggStep(pParse, pMWin, csrLead, 0, regArg, regSize); - sqlite3VdbeAddOp2(v, OP_Next, csrLead, addr2); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Rewind, csrLead, lblEmpty); - VdbeCoverageNeverTaken(v); - } - addrNext = sqlite3VdbeCurrentAddr(v); - - if( pOrderBy && (pMWin->eEnd==TK_CURRENT || pMWin->eStart==TK_CURRENT) ){ - int bCurrent = (pMWin->eStart==TK_CURRENT); - int addrJump = 0; /* Address of OP_Jump below */ - if( pMWin->eType==TK_RANGE ){ - int iOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0); - int regPeer = pMWin->regPart + (pPart ? pPart->nExpr : 0); - KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); - for(k=0; k<nPeer; k++){ - sqlite3VdbeAddOp3(v, OP_Column, csrLead, iOff+k, regNewPeer+k); - } - addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer); - sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); - addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, nPeer-1); + assert( op==OP_Ge || op==OP_Gt || op==OP_Le ); + assert( p->pMWin->pOrderBy && p->pMWin->pOrderBy->nExpr==1 ); + if( p->pMWin->pOrderBy->a[0].sortOrder ){ + switch( op ){ + case OP_Ge: op = OP_Le; break; + case OP_Gt: op = OP_Lt; break; + default: assert( op==OP_Le ); op = OP_Ge; break; } - - windowReturnRows(pParse, pMWin, regCtr, regGosub, addrGosub, - (bCurrent ? regArg : 0), (bCurrent ? regSize : 0) - ); - if( addrJump ) sqlite3VdbeJumpHere(v, addrJump); + arith = OP_Subtract; } - if( bReverse==0 ){ - windowAggStep(pParse, pMWin, csrLead, 0, regArg, regSize); - } - sqlite3VdbeAddOp2(v, OP_AddImm, regCtr, 1); - sqlite3VdbeAddOp2(v, OP_Next, csrLead, addrNext); - VdbeCoverage(v); - - windowReturnRows(pParse, pMWin, regCtr, regGosub, addrGosub, 0, 0); + windowReadPeerValues(p, csr1, reg1); + windowReadPeerValues(p, csr2, reg2); - sqlite3VdbeResolveLabel(v, lblEmpty); - sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr); - sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); + /* Check if the peer value for csr1 value is a text or blob by comparing + ** it to the smallest possible string - ''. If it is, jump over the + ** OP_Add or OP_Subtract operation and proceed directly to the comparison. */ + sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); + addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1); + VdbeCoverage(v); + sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1); + sqlite3VdbeJumpHere(v, addrGe); + sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); + sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); + assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le ); + testcase(op==OP_Ge); VdbeCoverageIf(v, op==OP_Ge); + testcase(op==OP_Lt); VdbeCoverageIf(v, op==OP_Lt); + testcase(op==OP_Le); VdbeCoverageIf(v, op==OP_Le); + testcase(op==OP_Gt); VdbeCoverageIf(v, op==OP_Gt); - /* Jump to here to skip over flush_partition */ - sqlite3VdbeJumpHere(v, addrGoto); + sqlite3ReleaseTempReg(pParse, reg1); + sqlite3ReleaseTempReg(pParse, reg2); } - /* -** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -** -** ... -** if( new partition ){ -** AggFinal (xFinalize) -** Gosub addrGosub -** ResetSorter eph-table -** } -** else if( new peer ){ -** AggFinal (xValue) -** Gosub addrGosub -** ResetSorter eph-table -** } -** AggStep -** Insert (record into eph-table) -** sqlite3WhereEnd() -** AggFinal (xFinalize) -** Gosub addrGosub -** -** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING -** -** As above, except take no action for a "new peer". Invoke -** the sub-routine once only for each partition. -** -** RANGE BETWEEN CURRENT ROW AND CURRENT ROW -** -** As above, except that the "new peer" condition is handled in the -** same way as "new partition" (so there is no "else if" block). -** -** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW -** -** As above, except assume every row is a "new peer". +** Helper function for sqlite3WindowCodeStep(). Each call to this function +** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE +** operation. Refer to the header comment for sqlite3WindowCodeStep() for +** details. */ -static void windowCodeDefaultStep( - Parse *pParse, - Select *p, - WhereInfo *pWInfo, - int regGosub, - int addrGosub +static int windowCodeOp( + WindowCodeArg *p, /* Context object */ + int op, /* WINDOW_RETURN_ROW, AGGSTEP or AGGINVERSE */ + int regCountdown, /* Register for OP_IfPos countdown */ + int jumpOnEof /* Jump here if stepped cursor reaches EOF */ ){ - Window *pMWin = p->pWin; - Vdbe *v = sqlite3GetVdbe(pParse); - int k; - int iSubCsr = p->pSrc->a[0].iCursor; - int nSub = p->pSrc->a[0].pTab->nCol; - int reg = pParse->nMem+1; - int regRecord = reg+nSub; - int regRowid = regRecord+1; - int addr; - ExprList *pPart = pMWin->pPartition; - ExprList *pOrderBy = pMWin->pOrderBy; - - assert( pMWin->eType==TK_RANGE - || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT) - ); - - assert( (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT) - || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_UNBOUNDED) - || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_CURRENT) - || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED && !pOrderBy) - ); - - if( pMWin->eEnd==TK_UNBOUNDED ){ - pOrderBy = 0; - } - - pParse->nMem += nSub + 2; - - /* Load the individual column values of the row returned by - ** the sub-select into an array of registers. */ - for(k=0; k<nSub; k++){ - sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k); + int csr, reg; + Parse *pParse = p->pParse; + Window *pMWin = p->pMWin; + int ret = 0; + Vdbe *v = p->pVdbe; + int addrIf = 0; + int addrContinue = 0; + int addrGoto = 0; + int bPeer = (pMWin->eFrmType!=TK_ROWS); + + int lblDone = sqlite3VdbeMakeLabel(pParse); + int addrNextRange = 0; + + /* Special case - WINDOW_AGGINVERSE is always a no-op if the frame + ** starts with UNBOUNDED PRECEDING. */ + if( op==WINDOW_AGGINVERSE && pMWin->eStart==TK_UNBOUNDED ){ + assert( regCountdown==0 && jumpOnEof==0 ); + return 0; } - /* Check if this is the start of a new partition or peer group. */ - if( pPart || pOrderBy ){ - int nPart = (pPart ? pPart->nExpr : 0); - int addrGoto = 0; - int addrJump = 0; - int nPeer = (pOrderBy ? pOrderBy->nExpr : 0); - - if( pPart ){ - int regNewPart = reg + pMWin->nBufferCol; - KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); - addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart); - sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); - addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2); - VdbeCoverageEqNe(v); - windowAggFinal(pParse, pMWin, 1); - if( pOrderBy ){ - addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); + if( regCountdown>0 ){ + if( pMWin->eFrmType==TK_RANGE ){ + addrNextRange = sqlite3VdbeCurrentAddr(v); + assert( op==WINDOW_AGGINVERSE || op==WINDOW_AGGSTEP ); + if( op==WINDOW_AGGINVERSE ){ + if( pMWin->eStart==TK_FOLLOWING ){ + windowCodeRangeTest( + p, OP_Le, p->current.csr, regCountdown, p->start.csr, lblDone + ); + }else{ + windowCodeRangeTest( + p, OP_Ge, p->start.csr, regCountdown, p->current.csr, lblDone + ); + } + }else{ + windowCodeRangeTest( + p, OP_Gt, p->end.csr, regCountdown, p->current.csr, lblDone + ); } + }else{ + addrIf = sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, 0, 1); + VdbeCoverage(v); } + } - if( pOrderBy ){ - int regNewPeer = reg + pMWin->nBufferCol + nPart; - int regPeer = pMWin->regPart + nPart; + if( op==WINDOW_RETURN_ROW && pMWin->regStartRowid==0 ){ + windowAggFinal(p, 0); + } + addrContinue = sqlite3VdbeCurrentAddr(v); + switch( op ){ + case WINDOW_RETURN_ROW: + csr = p->current.csr; + reg = p->current.reg; + windowReturnOneRow(p); + break; - if( addrJump ) sqlite3VdbeJumpHere(v, addrJump); - if( pMWin->eType==TK_RANGE ){ - KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0); - addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer); - sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); - addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2); - VdbeCoverage(v); + case WINDOW_AGGINVERSE: + csr = p->start.csr; + reg = p->start.reg; + if( pMWin->regStartRowid ){ + assert( pMWin->regEndRowid ); + sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regStartRowid, 1); }else{ - addrJump = 0; + windowAggStep(pParse, pMWin, csr, 1, p->regArg); } - windowAggFinal(pParse, pMWin, pMWin->eStart==TK_CURRENT); - if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto); - } - - sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr,sqlite3VdbeCurrentAddr(v)+3); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); - sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1); - VdbeCoverage(v); - - sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr); - sqlite3VdbeAddOp3( - v, OP_Copy, reg+pMWin->nBufferCol, pMWin->regPart, nPart+nPeer-1 - ); + break; - if( addrJump ) sqlite3VdbeJumpHere(v, addrJump); + default: + assert( op==WINDOW_AGGSTEP ); + csr = p->end.csr; + reg = p->end.reg; + if( pMWin->regStartRowid ){ + assert( pMWin->regEndRowid ); + sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regEndRowid, 1); + }else{ + windowAggStep(pParse, pMWin, csr, 0, p->regArg); + } + break; } - /* Invoke step function for window functions */ - windowAggStep(pParse, pMWin, -1, 0, reg, 0); + if( op==p->eDelete ){ + sqlite3VdbeAddOp1(v, OP_Delete, csr); + sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION); + } - /* Buffer the current row in the ephemeral table. */ - if( pMWin->nBufferCol>0 ){ - sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pMWin->nBufferCol, regRecord); + if( jumpOnEof ){ + sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+2); + VdbeCoverage(v); + ret = sqlite3VdbeAddOp0(v, OP_Goto); }else{ - sqlite3VdbeAddOp2(v, OP_Blob, 0, regRecord); - sqlite3VdbeAppendP4(v, (void*)"", 0); + sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+1+bPeer); + VdbeCoverage(v); + if( bPeer ){ + addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); + } } - sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid); - sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid); - /* End the database scan loop. */ - sqlite3WhereEnd(pWInfo); + if( bPeer ){ + int nReg = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); + int regTmp = (nReg ? sqlite3GetTempRange(pParse, nReg) : 0); + windowReadPeerValues(p, csr, regTmp); + windowIfNewPeer(pParse, pMWin->pOrderBy, regTmp, reg, addrContinue); + sqlite3ReleaseTempRange(pParse, regTmp, nReg); + } - windowAggFinal(pParse, pMWin, 1); - sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr,sqlite3VdbeCurrentAddr(v)+3); - VdbeCoverage(v); - sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub); - sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1); - VdbeCoverage(v); + if( addrNextRange ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNextRange); + } + sqlite3VdbeResolveLabel(v, lblDone); + if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto); + if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); + return ret; } + /* ** Allocate and return a duplicate of the Window object indicated by the ** third argument. Set the Window.pOwner field of the new object to @@ -147187,9 +147978,10 @@ SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){ pNew->pFunc = p->pFunc; pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0); pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0); - pNew->eType = p->eType; + pNew->eFrmType = p->eFrmType; pNew->eEnd = p->eEnd; pNew->eStart = p->eStart; + pNew->eExclude = p->eExclude; pNew->pStart = sqlite3ExprDup(db, p->pStart, 0); pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0); pNew->pOwner = pOwner; @@ -147217,11 +148009,359 @@ SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p){ } /* +** Return true if it can be determined at compile time that expression +** pExpr evaluates to a value that, when cast to an integer, is greater +** than zero. False otherwise. +** +** If an OOM error occurs, this function sets the Parse.db.mallocFailed +** flag and returns zero. +*/ +static int windowExprGtZero(Parse *pParse, Expr *pExpr){ + int ret = 0; + sqlite3 *db = pParse->db; + sqlite3_value *pVal = 0; + sqlite3ValueFromExpr(db, pExpr, db->enc, SQLITE_AFF_NUMERIC, &pVal); + if( pVal && sqlite3_value_int(pVal)>0 ){ + ret = 1; + } + sqlite3ValueFree(pVal); + return ret; +} + +/* ** sqlite3WhereBegin() has already been called for the SELECT statement ** passed as the second argument when this function is invoked. It generates -** code to populate the Window.regResult register for each window function and -** invoke the sub-routine at instruction addrGosub once for each row. -** This function calls sqlite3WhereEnd() before returning. +** code to populate the Window.regResult register for each window function +** and invoke the sub-routine at instruction addrGosub once for each row. +** sqlite3WhereEnd() is always called before returning. +** +** This function handles several different types of window frames, which +** require slightly different processing. The following pseudo code is +** used to implement window frames of the form: +** +** ROWS BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING +** +** Other window frame types use variants of the following: +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** +** if( first row of partition ){ +** // Rewind three cursors, all open on the eph table. +** Rewind(csrEnd); +** Rewind(csrStart); +** Rewind(csrCurrent); +** +** regEnd = <expr2> // FOLLOWING expression +** regStart = <expr1> // PRECEDING expression +** }else{ +** // First time this branch is taken, the eph table contains two +** // rows. The first row in the partition, which all three cursors +** // currently point to, and the following row. +** AGGSTEP +** if( (regEnd--)<=0 ){ +** RETURN_ROW +** if( (regStart--)<=0 ){ +** AGGINVERSE +** } +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** RETURN ROW +** if( csrCurrent is EOF ) break; +** if( (regStart--)<=0 ){ +** AggInverse(csrStart) +** Next(csrStart) +** } +** } +** +** The pseudo-code above uses the following shorthand: +** +** AGGSTEP: invoke the aggregate xStep() function for each window function +** with arguments read from the current row of cursor csrEnd, then +** step cursor csrEnd forward one row (i.e. sqlite3BtreeNext()). +** +** RETURN_ROW: return a row to the caller based on the contents of the +** current row of csrCurrent and the current state of all +** aggregates. Then step cursor csrCurrent forward one row. +** +** AGGINVERSE: invoke the aggregate xInverse() function for each window +** functions with arguments read from the current row of cursor +** csrStart. Then step csrStart forward one row. +** +** There are two other ROWS window frames that are handled significantly +** differently from the above - "BETWEEN <expr> PRECEDING AND <expr> PRECEDING" +** and "BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING". These are special +** cases because they change the order in which the three cursors (csrStart, +** csrCurrent and csrEnd) iterate through the ephemeral table. Cases that +** use UNBOUNDED or CURRENT ROW are much simpler variations on one of these +** three. +** +** ROWS BETWEEN <expr1> PRECEDING AND <expr2> PRECEDING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = <expr2> +** regStart = <expr1> +** }else{ +** if( (regEnd--)<=0 ){ +** AGGSTEP +** } +** RETURN_ROW +** if( (regStart--)<=0 ){ +** AGGINVERSE +** } +** } +** } +** flush: +** if( (regEnd--)<=0 ){ +** AGGSTEP +** } +** RETURN_ROW +** +** +** ROWS BETWEEN <expr1> FOLLOWING AND <expr2> FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = <expr2> +** regStart = regEnd - <expr1> +** }else{ +** AGGSTEP +** if( (regEnd--)<=0 ){ +** RETURN_ROW +** } +** if( (regStart--)<=0 ){ +** AGGINVERSE +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** if( (regEnd--)<=0 ){ +** RETURN_ROW +** if( eof ) break; +** } +** if( (regStart--)<=0 ){ +** AGGINVERSE +** if( eof ) break +** } +** } +** while( !eof csrCurrent ){ +** RETURN_ROW +** } +** +** For the most part, the patterns above are adapted to support UNBOUNDED by +** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and +** CURRENT ROW by assuming that it is equivilent to "0 PRECEDING/FOLLOWING". +** This is optimized of course - branches that will never be taken and +** conditions that are always true are omitted from the VM code. The only +** exceptional case is: +** +** ROWS BETWEEN <expr1> FOLLOWING AND UNBOUNDED FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regStart = <expr1> +** }else{ +** AGGSTEP +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** if( (regStart--)<=0 ){ +** AGGINVERSE +** if( eof ) break +** } +** RETURN_ROW +** } +** while( !eof csrCurrent ){ +** RETURN_ROW +** } +** +** Also requiring special handling are the cases: +** +** ROWS BETWEEN <expr1> PRECEDING AND <expr2> PRECEDING +** ROWS BETWEEN <expr1> FOLLOWING AND <expr2> FOLLOWING +** +** when (expr1 < expr2). This is detected at runtime, not by this function. +** To handle this case, the pseudo-code programs depicted above are modified +** slightly to be: +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = <expr2> +** regStart = <expr1> +** if( regEnd < regStart ){ +** RETURN_ROW +** delete eph table contents +** continue +** } +** ... +** +** The new "continue" statement in the above jumps to the next iteration +** of the outer loop - the one started by sqlite3WhereBegin(). +** +** The various GROUPS cases are implemented using the same patterns as +** ROWS. The VM code is modified slightly so that: +** +** 1. The else branch in the main loop is only taken if the row just +** added to the ephemeral table is the start of a new group. In +** other words, it becomes: +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = <expr2> +** regStart = <expr1> +** }else if( new group ){ +** ... +** } +** } +** +** 2. Instead of processing a single row, each RETURN_ROW, AGGSTEP or +** AGGINVERSE step processes the current row of the relevant cursor and +** all subsequent rows belonging to the same group. +** +** RANGE window frames are a little different again. As for GROUPS, the +** main loop runs once per group only. And RETURN_ROW, AGGSTEP and AGGINVERSE +** deal in groups instead of rows. As for ROWS and GROUPS, there are three +** basic cases: +** +** RANGE BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = <expr2> +** regStart = <expr1> +** }else{ +** AGGSTEP +** while( (csrCurrent.key + regEnd) < csrEnd.key ){ +** RETURN_ROW +** while( csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** RETURN ROW +** if( csrCurrent is EOF ) break; +** while( csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** } +** } +** +** In the above notation, "csr.key" means the current value of the ORDER BY +** expression (there is only ever 1 for a RANGE that uses an <expr> FOLLOWING +** or <expr PRECEDING) read from cursor csr. +** +** RANGE BETWEEN <expr1> PRECEDING AND <expr2> PRECEDING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = <expr2> +** regStart = <expr1> +** }else{ +** if( (csrEnd.key + regEnd) <= csrCurrent.key ){ +** AGGSTEP +** } +** while( (csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** RETURN_ROW +** } +** } +** flush: +** while( (csrEnd.key + regEnd) <= csrCurrent.key ){ +** AGGSTEP +** } +** while( (csrStart.key + regStart) < csrCurrent.key ){ +** AGGINVERSE +** } +** RETURN_ROW +** +** RANGE BETWEEN <expr1> FOLLOWING AND <expr2> FOLLOWING +** +** ... loop started by sqlite3WhereBegin() ... +** if( new partition ){ +** Gosub flush +** } +** Insert new row into eph table. +** if( first row of partition ){ +** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) +** regEnd = <expr2> +** regStart = <expr1> +** }else{ +** AGGSTEP +** while( (csrCurrent.key + regEnd) < csrEnd.key ){ +** while( (csrCurrent.key + regStart) > csrStart.key ){ +** AGGINVERSE +** } +** RETURN_ROW +** } +** } +** } +** flush: +** AGGSTEP +** while( 1 ){ +** while( (csrCurrent.key + regStart) > csrStart.key ){ +** AGGINVERSE +** if( eof ) break "while( 1 )" loop. +** } +** RETURN_ROW +** } +** while( !eof csrCurrent ){ +** RETURN_ROW +** } +** +** The text above leaves out many details. Refer to the code and comments +** below for a more complete picture. */ SQLITE_PRIVATE void sqlite3WindowCodeStep( Parse *pParse, /* Parse context */ @@ -147231,75 +148371,321 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep( int addrGosub /* OP_Gosub here to return each row */ ){ Window *pMWin = p->pWin; + ExprList *pOrderBy = pMWin->pOrderBy; + Vdbe *v = sqlite3GetVdbe(pParse); + int csrWrite; /* Cursor used to write to eph. table */ + int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */ + int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */ + int iInput; /* To iterate through sub cols */ + int addrNe; /* Address of OP_Ne */ + int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */ + int addrInteger = 0; /* Address of OP_Integer */ + int addrEmpty; /* Address of OP_Rewind in flush: */ + int regStart = 0; /* Value of <expr> PRECEDING */ + int regEnd = 0; /* Value of <expr> FOLLOWING */ + int regNew; /* Array of registers holding new input row */ + int regRecord; /* regNew array in record form */ + int regRowid; /* Rowid for regRecord in eph table */ + int regNewPeer = 0; /* Peer values for new row (part of regNew) */ + int regPeer = 0; /* Peer values for current row */ + int regFlushPart = 0; /* Register for "Gosub flush_partition" */ + WindowCodeArg s; /* Context object for sub-routines */ + int lblWhereEnd; /* Label just before sqlite3WhereEnd() code */ + + assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT + || pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED + ); + assert( pMWin->eEnd==TK_FOLLOWING || pMWin->eEnd==TK_CURRENT + || pMWin->eEnd==TK_UNBOUNDED || pMWin->eEnd==TK_PRECEDING + ); + assert( pMWin->eExclude==0 || pMWin->eExclude==TK_CURRENT + || pMWin->eExclude==TK_GROUP || pMWin->eExclude==TK_TIES + || pMWin->eExclude==TK_NO + ); - /* There are three different functions that may be used to do the work - ** of this one, depending on the window frame and the specific built-in - ** window functions used (if any). - ** - ** windowCodeRowExprStep() handles all "ROWS" window frames, except for: - ** - ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW - ** - ** The exception is because windowCodeRowExprStep() implements all window - ** frame types by caching the entire partition in a temp table, and - ** "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW" is easy enough to - ** implement without such a cache. - ** - ** windowCodeCacheStep() is used for: - ** - ** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING - ** - ** It is also used for anything not handled by windowCodeRowExprStep() - ** that invokes a built-in window function that requires the entire - ** partition to be cached in a temp table before any rows are returned - ** (e.g. nth_value() or percent_rank()). - ** - ** Finally, assuming there is no built-in window function that requires - ** the partition to be cached, windowCodeDefaultStep() is used for: - ** - ** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW - ** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING - ** RANGE BETWEEN CURRENT ROW AND CURRENT ROW - ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW - ** - ** windowCodeDefaultStep() is the only one of the three functions that - ** does not cache each partition in a temp table before beginning to - ** return rows. - */ - if( pMWin->eType==TK_ROWS - && (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy) - ){ - VdbeModuleComment((pParse->pVdbe, "Begin RowExprStep()")); - windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub); - }else{ - Window *pWin; - int bCache = 0; /* True to use CacheStep() */ - - if( pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED ){ - bCache = 1; - }else{ - for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ - FuncDef *pFunc = pWin->pFunc; - if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE) - || (pFunc->zName==nth_valueName) - || (pFunc->zName==first_valueName) - || (pFunc->zName==leadName) - || (pFunc->zName==lagName) - ){ - bCache = 1; - break; + lblWhereEnd = sqlite3VdbeMakeLabel(pParse); + + /* Fill in the context object */ + memset(&s, 0, sizeof(WindowCodeArg)); + s.pParse = pParse; + s.pMWin = pMWin; + s.pVdbe = v; + s.regGosub = regGosub; + s.addrGosub = addrGosub; + s.current.csr = pMWin->iEphCsr; + csrWrite = s.current.csr+1; + s.start.csr = s.current.csr+2; + s.end.csr = s.current.csr+3; + + /* Figure out when rows may be deleted from the ephemeral table. There + ** are four options - they may never be deleted (eDelete==0), they may + ** be deleted as soon as they are no longer part of the window frame + ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row + ** has been returned to the caller (WINDOW_RETURN_ROW), or they may + ** be deleted after they enter the frame (WINDOW_AGGSTEP). */ + switch( pMWin->eStart ){ + case TK_FOLLOWING: + if( pMWin->eFrmType!=TK_RANGE + && windowExprGtZero(pParse, pMWin->pStart) + ){ + s.eDelete = WINDOW_RETURN_ROW; + } + break; + case TK_UNBOUNDED: + if( windowCacheFrame(pMWin)==0 ){ + if( pMWin->eEnd==TK_PRECEDING ){ + if( pMWin->eFrmType!=TK_RANGE + && windowExprGtZero(pParse, pMWin->pEnd) + ){ + s.eDelete = WINDOW_AGGSTEP; + } + }else{ + s.eDelete = WINDOW_RETURN_ROW; + } + } + break; + default: + s.eDelete = WINDOW_AGGINVERSE; + break; + } + + /* Allocate registers for the array of values from the sub-query, the + ** samve values in record form, and the rowid used to insert said record + ** into the ephemeral table. */ + regNew = pParse->nMem+1; + pParse->nMem += nInput; + regRecord = ++pParse->nMem; + regRowid = ++pParse->nMem; + + /* If the window frame contains an "<expr> PRECEDING" or "<expr> FOLLOWING" + ** clause, allocate registers to store the results of evaluating each + ** <expr>. */ + if( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ){ + regStart = ++pParse->nMem; + } + if( pMWin->eEnd==TK_PRECEDING || pMWin->eEnd==TK_FOLLOWING ){ + regEnd = ++pParse->nMem; + } + + /* If this is not a "ROWS BETWEEN ..." frame, then allocate arrays of + ** registers to store copies of the ORDER BY expressions (peer values) + ** for the main loop, and for each cursor (start, current and end). */ + if( pMWin->eFrmType!=TK_ROWS ){ + int nPeer = (pOrderBy ? pOrderBy->nExpr : 0); + regNewPeer = regNew + pMWin->nBufferCol; + if( pMWin->pPartition ) regNewPeer += pMWin->pPartition->nExpr; + regPeer = pParse->nMem+1; pParse->nMem += nPeer; + s.start.reg = pParse->nMem+1; pParse->nMem += nPeer; + s.current.reg = pParse->nMem+1; pParse->nMem += nPeer; + s.end.reg = pParse->nMem+1; pParse->nMem += nPeer; + } + + /* Load the column values for the row returned by the sub-select + ** into an array of registers starting at regNew. Assemble them into + ** a record in register regRecord. */ + for(iInput=0; iInput<nInput; iInput++){ + sqlite3VdbeAddOp3(v, OP_Column, csrInput, iInput, regNew+iInput); + } + sqlite3VdbeAddOp3(v, OP_MakeRecord, regNew, nInput, regRecord); + + /* An input row has just been read into an array of registers starting + ** at regNew. If the window has a PARTITION clause, this block generates + ** VM code to check if the input row is the start of a new partition. + ** If so, it does an OP_Gosub to an address to be filled in later. The + ** address of the OP_Gosub is stored in local variable addrGosubFlush. */ + if( pMWin->pPartition ){ + int addr; + ExprList *pPart = pMWin->pPartition; + int nPart = pPart->nExpr; + int regNewPart = regNew + pMWin->nBufferCol; + KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0); + + regFlushPart = ++pParse->nMem; + addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart, nPart); + sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO); + sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2); + VdbeCoverageEqNe(v); + addrGosubFlush = sqlite3VdbeAddOp1(v, OP_Gosub, regFlushPart); + VdbeComment((v, "call flush_partition")); + sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1); + } + + /* Insert the new row into the ephemeral table */ + sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, regRowid); + addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, regRowid); + VdbeCoverageNeverNull(v); + + /* This block is run for the first row of each partition */ + s.regArg = windowInitAccum(pParse, pMWin); + + if( regStart ){ + sqlite3ExprCode(pParse, pMWin->pStart, regStart); + windowCheckValue(pParse, regStart, 0 + (pMWin->eFrmType==TK_RANGE ? 3 : 0)); + } + if( regEnd ){ + sqlite3ExprCode(pParse, pMWin->pEnd, regEnd); + windowCheckValue(pParse, regEnd, 1 + (pMWin->eFrmType==TK_RANGE ? 3 : 0)); + } + + if( pMWin->eStart==pMWin->eEnd && regStart ){ + int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le); + int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd); + VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound <expr> */ + VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */ + windowAggFinal(&s, 0); + sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1); + VdbeCoverageNeverTaken(v); + windowReturnOneRow(&s); + sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); + sqlite3VdbeJumpHere(v, addrGe); + } + if( pMWin->eStart==TK_FOLLOWING && pMWin->eFrmType!=TK_RANGE && regEnd ){ + assert( pMWin->eEnd==TK_FOLLOWING ); + sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regStart); + } + + if( pMWin->eStart!=TK_UNBOUNDED ){ + sqlite3VdbeAddOp2(v, OP_Rewind, s.start.csr, 1); + VdbeCoverageNeverTaken(v); + } + sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1); + VdbeCoverageNeverTaken(v); + sqlite3VdbeAddOp2(v, OP_Rewind, s.end.csr, 1); + VdbeCoverageNeverTaken(v); + if( regPeer && pOrderBy ){ + sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, pOrderBy->nExpr-1); + sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.start.reg, pOrderBy->nExpr-1); + sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.current.reg, pOrderBy->nExpr-1); + sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.end.reg, pOrderBy->nExpr-1); + } + + sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd); + + sqlite3VdbeJumpHere(v, addrNe); + + /* Beginning of the block executed for the second and subsequent rows. */ + if( regPeer ){ + windowIfNewPeer(pParse, pOrderBy, regNewPeer, regPeer, lblWhereEnd); + } + if( pMWin->eStart==TK_FOLLOWING ){ + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + if( pMWin->eEnd!=TK_UNBOUNDED ){ + if( pMWin->eFrmType==TK_RANGE ){ + int lbl = sqlite3VdbeMakeLabel(pParse); + int addrNext = sqlite3VdbeCurrentAddr(v); + windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext); + sqlite3VdbeResolveLabel(v, lbl); + }else{ + windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 0); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + } + } + }else + if( pMWin->eEnd==TK_PRECEDING ){ + int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE); + windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0); + if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + if( !bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + }else{ + int addr = 0; + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + if( pMWin->eEnd!=TK_UNBOUNDED ){ + if( pMWin->eFrmType==TK_RANGE ){ + int lbl = 0; + addr = sqlite3VdbeCurrentAddr(v); + if( regEnd ){ + lbl = sqlite3VdbeMakeLabel(pParse); + windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl); + } + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + if( regEnd ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); + sqlite3VdbeResolveLabel(v, lbl); } + }else{ + if( regEnd ){ + addr = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1); + VdbeCoverage(v); + } + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + if( regEnd ) sqlite3VdbeJumpHere(v, addr); } } + } - /* Otherwise, call windowCodeDefaultStep(). */ - if( bCache ){ - VdbeModuleComment((pParse->pVdbe, "Begin CacheStep()")); - windowCodeCacheStep(pParse, p, pWInfo, regGosub, addrGosub); - }else{ - VdbeModuleComment((pParse->pVdbe, "Begin DefaultStep()")); - windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub); + /* End of the main input loop */ + sqlite3VdbeResolveLabel(v, lblWhereEnd); + sqlite3WhereEnd(pWInfo); + + /* Fall through */ + if( pMWin->pPartition ){ + addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart); + sqlite3VdbeJumpHere(v, addrGosubFlush); + } + + addrEmpty = sqlite3VdbeAddOp1(v, OP_Rewind, csrWrite); + VdbeCoverage(v); + if( pMWin->eEnd==TK_PRECEDING ){ + int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE); + windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0); + if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0); + }else if( pMWin->eStart==TK_FOLLOWING ){ + int addrStart; + int addrBreak1; + int addrBreak2; + int addrBreak3; + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + if( pMWin->eFrmType==TK_RANGE ){ + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); + addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); + }else + if( pMWin->eEnd==TK_UNBOUNDED ){ + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regStart, 1); + addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, 0, 1); + }else{ + assert( pMWin->eEnd==TK_FOLLOWING ); + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 1); + addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1); + } + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); + sqlite3VdbeJumpHere(v, addrBreak2); + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak3 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); + sqlite3VdbeJumpHere(v, addrBreak1); + sqlite3VdbeJumpHere(v, addrBreak3); + }else{ + int addrBreak; + int addrStart; + windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0); + addrStart = sqlite3VdbeCurrentAddr(v); + addrBreak = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1); + windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0); + sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); + sqlite3VdbeJumpHere(v, addrBreak); + } + sqlite3VdbeJumpHere(v, addrEmpty); + + sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr); + if( pMWin->pPartition ){ + if( pMWin->regStartRowid ){ + sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid); + sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid); } + sqlite3VdbeChangeP1(v, addrInteger, sqlite3VdbeCurrentAddr(v)); + sqlite3VdbeAddOp1(v, OP_Return, regFlushPart); } } @@ -147488,6 +148874,10 @@ static void disableLookaside(Parse *pParse){ sqlite3ExprListSetName(pParse, p, pIdToken, 1); return p; } + +#if TK_SPAN>255 +# error too many tokens in the grammar +#endif /**************** End of %include directives **********************************/ /* These constants specify the various numeric values for terminal symbols ** in a format understandable to "makeheaders". This section is blank unless @@ -147551,27 +148941,28 @@ static void disableLookaside(Parse *pParse){ #endif /************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned short int -#define YYNOCODE 278 +#define YYNOCODE 302 #define YYACTIONTYPE unsigned short int -#define YYWILDCARD 91 +#define YYWILDCARD 95 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; sqlite3ParserTOKENTYPE yy0; - ExprList* yy42; - int yy96; - TriggerStep* yy119; - Window* yy147; - SrcList* yy167; - Upsert* yy266; - struct FrameBound yy317; - IdList* yy336; - struct TrigEvent yy350; - struct {int value; int mask;} yy367; - Select* yy423; - const char* yy464; - Expr* yy490; - With* yy499; + TriggerStep* yy11; + IdList* yy76; + ExprList* yy94; + Upsert* yy95; + int yy100; + Expr* yy102; + struct {int value; int mask;} yy199; + u8 yy218; + With* yy243; + struct TrigEvent yy298; + Window* yy379; + struct FrameBound yy389; + Select* yy391; + SrcList* yy407; + const char* yy528; } YYMINORTYPE; #ifndef YYSTACKDEPTH #define YYSTACKDEPTH 100 @@ -147587,17 +148978,17 @@ typedef union { #define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse; #define sqlite3ParserCTX_STORE yypParser->pParse=pParse; #define YYFALLBACK 1 -#define YYNSTATE 524 -#define YYNRULE 369 -#define YYNTOKEN 155 -#define YY_MAX_SHIFT 523 -#define YY_MIN_SHIFTREDUCE 760 -#define YY_MAX_SHIFTREDUCE 1128 -#define YY_ERROR_ACTION 1129 -#define YY_ACCEPT_ACTION 1130 -#define YY_NO_ACTION 1131 -#define YY_MIN_REDUCE 1132 -#define YY_MAX_REDUCE 1500 +#define YYNSTATE 540 +#define YYNRULE 376 +#define YYNTOKEN 176 +#define YY_MAX_SHIFT 539 +#define YY_MIN_SHIFTREDUCE 783 +#define YY_MAX_SHIFTREDUCE 1158 +#define YY_ERROR_ACTION 1159 +#define YY_ACCEPT_ACTION 1160 +#define YY_NO_ACTION 1161 +#define YY_MIN_REDUCE 1162 +#define YY_MAX_REDUCE 1537 /************* End control #defines *******************************************/ #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) @@ -147664,569 +149055,601 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (2009) +#define YY_ACTTAB_COUNT (2142) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 377, 518, 371, 107, 104, 200, 1293, 518, 1130, 1, - /* 10 */ 1, 523, 2, 1134, 518, 1203, 1203, 1262, 277, 373, - /* 20 */ 129, 495, 37, 37, 1397, 1201, 1201, 1211, 65, 65, - /* 30 */ 480, 891, 107, 104, 200, 37, 37, 1043, 1494, 892, - /* 40 */ 346, 1494, 342, 114, 115, 105, 1106, 1106, 957, 960, - /* 50 */ 950, 950, 112, 112, 113, 113, 113, 113, 285, 254, - /* 60 */ 254, 518, 254, 254, 500, 518, 495, 518, 107, 104, - /* 70 */ 200, 1085, 515, 481, 386, 515, 1464, 442, 501, 230, - /* 80 */ 197, 439, 37, 37, 1172, 210, 65, 65, 65, 65, - /* 90 */ 254, 254, 111, 111, 111, 111, 110, 110, 109, 109, - /* 100 */ 109, 108, 404, 515, 404, 155, 1041, 431, 401, 400, - /* 110 */ 254, 254, 373, 1431, 1427, 408, 1110, 1085, 1086, 1087, - /* 120 */ 284, 1112, 500, 515, 500, 368, 1433, 1421, 1428, 1111, - /* 130 */ 1261, 499, 373, 502, 108, 404, 114, 115, 105, 1106, - /* 140 */ 1106, 957, 960, 950, 950, 112, 112, 113, 113, 113, - /* 150 */ 113, 276, 509, 1113, 369, 1113, 114, 115, 105, 1106, - /* 160 */ 1106, 957, 960, 950, 950, 112, 112, 113, 113, 113, - /* 170 */ 113, 496, 1420, 1431, 493, 1468, 1065, 260, 1063, 433, - /* 180 */ 74, 107, 104, 200, 498, 111, 111, 111, 111, 110, - /* 190 */ 110, 109, 109, 109, 108, 404, 373, 113, 113, 113, - /* 200 */ 113, 106, 131, 91, 1361, 111, 111, 111, 111, 110, - /* 210 */ 110, 109, 109, 109, 108, 404, 113, 113, 113, 113, - /* 220 */ 114, 115, 105, 1106, 1106, 957, 960, 950, 950, 112, - /* 230 */ 112, 113, 113, 113, 113, 111, 111, 111, 111, 110, - /* 240 */ 110, 109, 109, 109, 108, 404, 116, 110, 110, 109, - /* 250 */ 109, 109, 108, 404, 111, 111, 111, 111, 110, 110, - /* 260 */ 109, 109, 109, 108, 404, 917, 512, 512, 512, 111, - /* 270 */ 111, 111, 111, 110, 110, 109, 109, 109, 108, 404, - /* 280 */ 517, 1198, 1177, 181, 109, 109, 109, 108, 404, 373, - /* 290 */ 1198, 402, 402, 402, 75, 360, 111, 111, 111, 111, - /* 300 */ 110, 110, 109, 109, 109, 108, 404, 382, 299, 419, - /* 310 */ 287, 170, 518, 114, 115, 105, 1106, 1106, 957, 960, - /* 320 */ 950, 950, 112, 112, 113, 113, 113, 113, 1444, 523, - /* 330 */ 2, 1134, 518, 13, 13, 337, 277, 1085, 129, 226, - /* 340 */ 937, 1058, 1000, 471, 917, 1211, 453, 384, 1085, 395, - /* 350 */ 162, 1057, 155, 45, 45, 416, 928, 401, 400, 479, - /* 360 */ 927, 12, 111, 111, 111, 111, 110, 110, 109, 109, - /* 370 */ 109, 108, 404, 226, 286, 254, 254, 254, 254, 518, - /* 380 */ 16, 16, 373, 1085, 1086, 1087, 314, 299, 515, 472, - /* 390 */ 515, 927, 927, 929, 1085, 1086, 1087, 378, 276, 509, - /* 400 */ 65, 65, 1113, 210, 1113, 1085, 114, 115, 105, 1106, - /* 410 */ 1106, 957, 960, 950, 950, 112, 112, 113, 113, 113, - /* 420 */ 113, 1448, 222, 1134, 1089, 461, 458, 457, 277, 180, - /* 430 */ 129, 378, 392, 408, 423, 456, 500, 1211, 240, 257, - /* 440 */ 324, 464, 319, 463, 227, 470, 12, 317, 424, 300, - /* 450 */ 317, 1085, 1086, 1087, 485, 111, 111, 111, 111, 110, - /* 460 */ 110, 109, 109, 109, 108, 404, 181, 118, 1085, 254, - /* 470 */ 254, 1089, 518, 90, 351, 373, 518, 1181, 365, 798, - /* 480 */ 1440, 339, 515, 248, 248, 77, 325, 133, 1085, 249, - /* 490 */ 424, 300, 794, 49, 49, 210, 515, 65, 65, 114, - /* 500 */ 115, 105, 1106, 1106, 957, 960, 950, 950, 112, 112, - /* 510 */ 113, 113, 113, 113, 1085, 1086, 1087, 222, 1085, 438, - /* 520 */ 461, 458, 457, 937, 787, 408, 171, 857, 362, 1021, - /* 530 */ 456, 136, 198, 486, 1085, 1086, 1087, 448, 794, 928, - /* 540 */ 5, 193, 192, 927, 1022, 107, 104, 200, 111, 111, - /* 550 */ 111, 111, 110, 110, 109, 109, 109, 108, 404, 1023, - /* 560 */ 254, 254, 803, 1085, 1085, 1086, 1087, 437, 373, 1085, - /* 570 */ 344, 787, 791, 515, 927, 927, 929, 1085, 1408, 1396, - /* 580 */ 832, 1085, 176, 3, 852, 1085, 518, 1439, 429, 851, - /* 590 */ 833, 518, 114, 115, 105, 1106, 1106, 957, 960, 950, - /* 600 */ 950, 112, 112, 113, 113, 113, 113, 13, 13, 1085, - /* 610 */ 1086, 1087, 13, 13, 518, 1085, 1086, 1087, 1496, 358, - /* 620 */ 1085, 389, 1234, 1085, 1086, 1087, 391, 1085, 1086, 1087, - /* 630 */ 448, 1085, 1086, 1087, 518, 65, 65, 947, 947, 958, - /* 640 */ 961, 111, 111, 111, 111, 110, 110, 109, 109, 109, - /* 650 */ 108, 404, 518, 382, 878, 13, 13, 518, 877, 518, - /* 660 */ 263, 373, 518, 431, 448, 1070, 1085, 1086, 1087, 267, - /* 670 */ 448, 488, 1360, 64, 64, 431, 812, 155, 50, 50, - /* 680 */ 65, 65, 518, 65, 65, 114, 115, 105, 1106, 1106, - /* 690 */ 957, 960, 950, 950, 112, 112, 113, 113, 113, 113, - /* 700 */ 518, 951, 382, 13, 13, 415, 411, 462, 414, 1085, - /* 710 */ 1366, 777, 1210, 292, 297, 813, 399, 497, 181, 403, - /* 720 */ 261, 15, 15, 276, 509, 414, 413, 1366, 1368, 410, - /* 730 */ 372, 345, 1209, 264, 111, 111, 111, 111, 110, 110, - /* 740 */ 109, 109, 109, 108, 404, 265, 254, 254, 229, 1405, - /* 750 */ 268, 1215, 268, 1103, 373, 1085, 1086, 1087, 938, 515, - /* 760 */ 393, 409, 876, 515, 254, 254, 1152, 482, 473, 262, - /* 770 */ 422, 476, 325, 503, 289, 518, 291, 515, 114, 115, - /* 780 */ 105, 1106, 1106, 957, 960, 950, 950, 112, 112, 113, - /* 790 */ 113, 113, 113, 414, 1021, 1366, 39, 39, 254, 254, - /* 800 */ 254, 254, 980, 254, 254, 254, 254, 255, 255, 1022, - /* 810 */ 279, 515, 516, 515, 846, 846, 515, 138, 515, 518, - /* 820 */ 515, 1043, 1495, 251, 1023, 1495, 876, 111, 111, 111, - /* 830 */ 111, 110, 110, 109, 109, 109, 108, 404, 518, 1353, - /* 840 */ 51, 51, 518, 199, 518, 506, 290, 373, 518, 276, - /* 850 */ 509, 922, 9, 483, 233, 1005, 1005, 445, 189, 52, - /* 860 */ 52, 325, 280, 53, 53, 54, 54, 373, 876, 55, - /* 870 */ 55, 114, 115, 105, 1106, 1106, 957, 960, 950, 950, - /* 880 */ 112, 112, 113, 113, 113, 113, 97, 518, 95, 1104, - /* 890 */ 1041, 114, 115, 105, 1106, 1106, 957, 960, 950, 950, - /* 900 */ 112, 112, 113, 113, 113, 113, 135, 199, 56, 56, - /* 910 */ 765, 766, 767, 225, 224, 223, 518, 283, 437, 233, - /* 920 */ 111, 111, 111, 111, 110, 110, 109, 109, 109, 108, - /* 930 */ 404, 1002, 876, 326, 518, 1002, 1104, 40, 40, 518, - /* 940 */ 111, 111, 111, 111, 110, 110, 109, 109, 109, 108, - /* 950 */ 404, 518, 448, 518, 1104, 41, 41, 518, 17, 518, - /* 960 */ 43, 43, 1155, 379, 518, 448, 518, 443, 518, 390, - /* 970 */ 518, 194, 44, 44, 57, 57, 1247, 518, 58, 58, - /* 980 */ 59, 59, 518, 466, 326, 14, 14, 60, 60, 120, - /* 990 */ 120, 61, 61, 449, 1206, 93, 518, 425, 46, 46, - /* 1000 */ 518, 1104, 518, 62, 62, 518, 437, 305, 518, 852, - /* 1010 */ 518, 298, 518, 1246, 851, 373, 518, 63, 63, 1293, - /* 1020 */ 397, 47, 47, 142, 142, 1467, 143, 143, 821, 70, - /* 1030 */ 70, 48, 48, 66, 66, 373, 518, 121, 121, 114, - /* 1040 */ 115, 105, 1106, 1106, 957, 960, 950, 950, 112, 112, - /* 1050 */ 113, 113, 113, 113, 518, 418, 518, 67, 67, 114, - /* 1060 */ 115, 105, 1106, 1106, 957, 960, 950, 950, 112, 112, - /* 1070 */ 113, 113, 113, 113, 312, 122, 122, 123, 123, 1293, - /* 1080 */ 518, 357, 1126, 88, 518, 435, 325, 387, 111, 111, - /* 1090 */ 111, 111, 110, 110, 109, 109, 109, 108, 404, 266, - /* 1100 */ 518, 119, 119, 518, 1293, 141, 141, 518, 111, 111, - /* 1110 */ 111, 111, 110, 110, 109, 109, 109, 108, 404, 518, - /* 1120 */ 801, 140, 140, 518, 127, 127, 511, 379, 126, 126, - /* 1130 */ 518, 137, 518, 1308, 518, 307, 518, 310, 518, 203, - /* 1140 */ 124, 124, 1307, 96, 125, 125, 207, 388, 1441, 468, - /* 1150 */ 1127, 69, 69, 71, 71, 68, 68, 38, 38, 42, - /* 1160 */ 42, 357, 1042, 373, 1293, 276, 509, 801, 185, 469, - /* 1170 */ 494, 436, 444, 6, 380, 156, 253, 197, 469, 134, - /* 1180 */ 426, 33, 1038, 373, 1121, 359, 1411, 114, 115, 105, - /* 1190 */ 1106, 1106, 957, 960, 950, 950, 112, 112, 113, 113, - /* 1200 */ 113, 113, 914, 296, 27, 293, 90, 114, 103, 105, - /* 1210 */ 1106, 1106, 957, 960, 950, 950, 112, 112, 113, 113, - /* 1220 */ 113, 113, 919, 275, 430, 232, 891, 232, 432, 256, - /* 1230 */ 1127, 232, 398, 370, 892, 28, 111, 111, 111, 111, - /* 1240 */ 110, 110, 109, 109, 109, 108, 404, 301, 454, 1385, - /* 1250 */ 90, 228, 209, 987, 811, 810, 111, 111, 111, 111, - /* 1260 */ 110, 110, 109, 109, 109, 108, 404, 315, 818, 819, - /* 1270 */ 90, 323, 983, 931, 885, 228, 373, 232, 999, 849, - /* 1280 */ 999, 322, 102, 998, 1384, 998, 785, 850, 440, 132, - /* 1290 */ 102, 302, 1243, 306, 309, 311, 373, 313, 1194, 1180, - /* 1300 */ 987, 115, 105, 1106, 1106, 957, 960, 950, 950, 112, - /* 1310 */ 112, 113, 113, 113, 113, 1178, 1179, 318, 327, 328, - /* 1320 */ 931, 1255, 105, 1106, 1106, 957, 960, 950, 950, 112, - /* 1330 */ 112, 113, 113, 113, 113, 1292, 1230, 1457, 273, 1241, - /* 1340 */ 504, 505, 1298, 100, 510, 246, 4, 1161, 1154, 111, - /* 1350 */ 111, 111, 111, 110, 110, 109, 109, 109, 108, 404, - /* 1360 */ 513, 1143, 187, 1142, 202, 1144, 1451, 356, 1227, 111, - /* 1370 */ 111, 111, 111, 110, 110, 109, 109, 109, 108, 404, - /* 1380 */ 11, 1277, 330, 405, 332, 334, 191, 1285, 364, 195, - /* 1390 */ 295, 417, 288, 100, 510, 507, 4, 434, 459, 321, - /* 1400 */ 1177, 349, 1357, 1356, 336, 155, 190, 1454, 1121, 158, - /* 1410 */ 513, 508, 235, 1404, 937, 1402, 1118, 381, 77, 428, - /* 1420 */ 98, 98, 8, 1282, 168, 30, 152, 99, 160, 405, - /* 1430 */ 520, 519, 88, 405, 927, 1362, 1274, 420, 163, 73, - /* 1440 */ 164, 76, 165, 166, 421, 507, 452, 212, 361, 363, - /* 1450 */ 427, 276, 509, 31, 1288, 172, 491, 441, 216, 1351, - /* 1460 */ 82, 490, 447, 1373, 937, 927, 927, 929, 930, 24, - /* 1470 */ 98, 98, 304, 247, 218, 177, 308, 99, 219, 405, - /* 1480 */ 520, 519, 450, 1145, 927, 220, 366, 1197, 100, 510, - /* 1490 */ 465, 4, 1188, 1196, 1195, 394, 803, 1169, 1187, 367, - /* 1500 */ 1168, 396, 484, 320, 1167, 513, 1466, 87, 475, 100, - /* 1510 */ 510, 271, 4, 272, 478, 927, 927, 929, 930, 24, - /* 1520 */ 1443, 1074, 407, 1238, 1239, 258, 513, 329, 405, 331, - /* 1530 */ 355, 355, 354, 243, 352, 234, 489, 774, 498, 184, - /* 1540 */ 507, 338, 1422, 339, 117, 1220, 10, 341, 333, 405, - /* 1550 */ 204, 491, 282, 1219, 1237, 1236, 492, 335, 343, 937, - /* 1560 */ 281, 507, 94, 1337, 186, 98, 98, 347, 89, 487, - /* 1570 */ 348, 241, 99, 29, 405, 520, 519, 274, 1151, 927, - /* 1580 */ 937, 521, 1080, 245, 242, 244, 98, 98, 856, 522, - /* 1590 */ 206, 1140, 1135, 99, 144, 405, 520, 519, 147, 375, - /* 1600 */ 927, 149, 376, 157, 1389, 1390, 1388, 1387, 205, 145, - /* 1610 */ 927, 927, 929, 930, 24, 146, 130, 761, 1165, 1164, - /* 1620 */ 72, 100, 510, 1162, 4, 269, 406, 188, 278, 201, - /* 1630 */ 259, 927, 927, 929, 930, 24, 128, 911, 513, 997, - /* 1640 */ 995, 159, 374, 208, 148, 161, 835, 276, 509, 211, - /* 1650 */ 294, 1011, 915, 167, 150, 383, 169, 78, 385, 79, - /* 1660 */ 80, 405, 81, 151, 1014, 213, 214, 1010, 139, 18, - /* 1670 */ 412, 215, 303, 507, 232, 1115, 1003, 446, 173, 217, - /* 1680 */ 174, 32, 776, 451, 491, 322, 221, 175, 814, 490, - /* 1690 */ 83, 455, 937, 19, 460, 316, 20, 84, 98, 98, - /* 1700 */ 270, 182, 85, 467, 153, 99, 154, 405, 520, 519, - /* 1710 */ 1074, 407, 927, 183, 258, 963, 1046, 86, 34, 355, - /* 1720 */ 355, 354, 243, 352, 474, 1047, 774, 35, 477, 196, - /* 1730 */ 250, 100, 510, 252, 4, 884, 178, 231, 1060, 204, - /* 1740 */ 21, 282, 102, 927, 927, 929, 930, 24, 513, 281, - /* 1750 */ 879, 22, 1064, 1062, 1051, 7, 340, 23, 978, 179, - /* 1760 */ 90, 92, 510, 964, 4, 236, 962, 966, 1020, 1019, - /* 1770 */ 237, 405, 967, 25, 36, 514, 932, 786, 513, 206, - /* 1780 */ 101, 26, 845, 507, 238, 239, 1459, 147, 350, 1458, - /* 1790 */ 149, 353, 1075, 1131, 1131, 1131, 1131, 205, 1131, 1131, - /* 1800 */ 1131, 405, 937, 1131, 1131, 1131, 1131, 1131, 98, 98, - /* 1810 */ 1131, 1131, 1131, 507, 1131, 99, 1131, 405, 520, 519, - /* 1820 */ 1131, 1131, 927, 1131, 1131, 1131, 1131, 1131, 1131, 1131, - /* 1830 */ 1131, 374, 937, 1131, 1131, 1131, 276, 509, 98, 98, - /* 1840 */ 1131, 1131, 1131, 1131, 1131, 99, 1131, 405, 520, 519, - /* 1850 */ 1131, 1131, 927, 927, 927, 929, 930, 24, 1131, 412, - /* 1860 */ 1131, 1131, 1131, 258, 1131, 1131, 1131, 1131, 355, 355, - /* 1870 */ 354, 243, 352, 1131, 1131, 774, 1131, 1131, 1131, 1131, - /* 1880 */ 1131, 1131, 1131, 927, 927, 929, 930, 24, 204, 1131, - /* 1890 */ 282, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 281, 1131, - /* 1900 */ 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, - /* 1910 */ 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, - /* 1920 */ 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 206, 1131, - /* 1930 */ 1131, 1131, 1131, 1131, 1131, 1131, 147, 1131, 1131, 149, - /* 1940 */ 1131, 1131, 1131, 1131, 1131, 1131, 205, 1131, 1131, 1131, - /* 1950 */ 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, - /* 1960 */ 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, - /* 1970 */ 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, - /* 1980 */ 374, 1131, 1131, 1131, 1131, 276, 509, 1131, 1131, 1131, - /* 1990 */ 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, - /* 2000 */ 1131, 1131, 1131, 1131, 1131, 1131, 1131, 1131, 412, + /* 0 */ 112, 109, 209, 112, 109, 209, 1160, 1, 1, 539, + /* 10 */ 2, 1164, 490, 1193, 1293, 534, 289, 1196, 134, 383, + /* 20 */ 1485, 1428, 1164, 1229, 1208, 1242, 1195, 289, 491, 134, + /* 30 */ 373, 915, 1229, 443, 16, 16, 1242, 70, 70, 916, + /* 40 */ 242, 1292, 296, 119, 120, 110, 1136, 1136, 981, 984, + /* 50 */ 974, 974, 117, 117, 118, 118, 118, 118, 264, 264, + /* 60 */ 190, 264, 264, 264, 264, 112, 109, 209, 362, 264, + /* 70 */ 264, 531, 376, 497, 531, 1134, 531, 1501, 239, 206, + /* 80 */ 338, 9, 531, 242, 219, 1203, 118, 118, 118, 118, + /* 90 */ 111, 439, 112, 109, 209, 219, 116, 116, 116, 116, + /* 100 */ 115, 115, 114, 114, 114, 113, 414, 115, 115, 114, + /* 110 */ 114, 114, 113, 414, 418, 12, 383, 400, 1134, 114, + /* 120 */ 114, 114, 113, 414, 1115, 418, 1134, 1392, 116, 116, + /* 130 */ 116, 116, 115, 115, 114, 114, 114, 113, 414, 961, + /* 140 */ 119, 120, 110, 1136, 1136, 981, 984, 974, 974, 117, + /* 150 */ 117, 118, 118, 118, 118, 952, 534, 414, 941, 951, + /* 160 */ 1481, 539, 2, 1164, 1505, 534, 160, 175, 289, 1134, + /* 170 */ 134, 434, 312, 297, 1115, 1116, 1117, 1242, 70, 70, + /* 180 */ 1089, 338, 1089, 118, 118, 118, 118, 42, 42, 448, + /* 190 */ 951, 951, 953, 116, 116, 116, 116, 115, 115, 114, + /* 200 */ 114, 114, 113, 414, 1115, 311, 264, 264, 82, 441, + /* 210 */ 264, 264, 190, 383, 284, 12, 288, 525, 407, 531, + /* 220 */ 96, 159, 458, 531, 371, 116, 116, 116, 116, 115, + /* 230 */ 115, 114, 114, 114, 113, 414, 219, 119, 120, 110, + /* 240 */ 1136, 1136, 981, 984, 974, 974, 117, 117, 118, 118, + /* 250 */ 118, 118, 511, 1477, 1115, 1116, 1117, 113, 414, 534, + /* 260 */ 528, 528, 528, 121, 534, 1427, 418, 116, 116, 116, + /* 270 */ 116, 115, 115, 114, 114, 114, 113, 414, 1464, 351, + /* 280 */ 270, 42, 42, 383, 187, 1115, 70, 70, 533, 433, + /* 290 */ 116, 116, 116, 116, 115, 115, 114, 114, 114, 113, + /* 300 */ 414, 534, 1339, 405, 159, 411, 410, 119, 120, 110, + /* 310 */ 1136, 1136, 981, 984, 974, 974, 117, 117, 118, 118, + /* 320 */ 118, 118, 285, 42, 42, 349, 411, 410, 514, 479, + /* 330 */ 1458, 79, 1084, 6, 1140, 1115, 1116, 1117, 480, 1142, + /* 340 */ 501, 1115, 1084, 123, 238, 1084, 136, 1141, 1234, 1234, + /* 350 */ 1143, 383, 1143, 1115, 167, 426, 80, 447, 512, 1451, + /* 360 */ 116, 116, 116, 116, 115, 115, 114, 114, 114, 113, + /* 370 */ 414, 1143, 1466, 1143, 350, 119, 120, 110, 1136, 1136, + /* 380 */ 981, 984, 974, 974, 117, 117, 118, 118, 118, 118, + /* 390 */ 402, 1115, 1116, 1117, 500, 534, 250, 267, 336, 474, + /* 400 */ 331, 473, 236, 1115, 1116, 1117, 231, 1115, 329, 471, + /* 410 */ 468, 467, 509, 1458, 1464, 505, 6, 70, 70, 466, + /* 420 */ 181, 380, 379, 534, 971, 971, 982, 985, 116, 116, + /* 430 */ 116, 116, 115, 115, 114, 114, 114, 113, 414, 1115, + /* 440 */ 412, 412, 412, 496, 1115, 69, 69, 235, 383, 288, + /* 450 */ 525, 273, 326, 516, 337, 458, 1084, 1115, 1116, 1117, + /* 460 */ 1232, 1232, 492, 160, 508, 441, 1084, 1067, 1531, 1084, + /* 470 */ 207, 1531, 119, 120, 110, 1136, 1136, 981, 984, 974, + /* 480 */ 974, 117, 117, 118, 118, 118, 118, 881, 534, 1115, + /* 490 */ 1116, 1117, 975, 534, 1115, 1116, 1117, 534, 421, 534, + /* 500 */ 141, 534, 176, 356, 517, 1119, 32, 511, 482, 388, + /* 510 */ 70, 70, 818, 288, 525, 70, 70, 441, 499, 50, + /* 520 */ 50, 70, 70, 70, 70, 116, 116, 116, 116, 115, + /* 530 */ 115, 114, 114, 114, 113, 414, 274, 264, 264, 1115, + /* 540 */ 1065, 264, 264, 1115, 355, 383, 409, 961, 1439, 822, + /* 550 */ 531, 516, 190, 419, 531, 483, 1119, 516, 337, 516, + /* 560 */ 518, 1115, 818, 952, 382, 458, 515, 951, 481, 119, + /* 570 */ 120, 110, 1136, 1136, 981, 984, 974, 974, 117, 117, + /* 580 */ 118, 118, 118, 118, 1338, 278, 1045, 278, 275, 1115, + /* 590 */ 1116, 1117, 259, 1115, 1116, 1117, 534, 5, 951, 951, + /* 600 */ 953, 1046, 231, 3, 143, 471, 468, 467, 1391, 463, + /* 610 */ 1115, 1115, 1116, 1117, 1452, 466, 1047, 836, 70, 70, + /* 620 */ 480, 534, 116, 116, 116, 116, 115, 115, 114, 114, + /* 630 */ 114, 113, 414, 95, 1115, 287, 235, 856, 902, 420, + /* 640 */ 1115, 534, 383, 13, 13, 381, 815, 857, 472, 112, + /* 650 */ 109, 209, 1115, 337, 413, 309, 837, 394, 1436, 534, + /* 660 */ 1115, 1116, 1117, 54, 54, 291, 119, 120, 110, 1136, + /* 670 */ 1136, 981, 984, 974, 974, 117, 117, 118, 118, 118, + /* 680 */ 118, 13, 13, 1084, 1115, 1116, 1117, 901, 264, 264, + /* 690 */ 1115, 1116, 1117, 1084, 292, 399, 1084, 800, 388, 140, + /* 700 */ 295, 531, 1115, 1116, 1117, 403, 447, 532, 534, 870, + /* 710 */ 870, 534, 1240, 534, 329, 534, 1185, 389, 534, 116, + /* 720 */ 116, 116, 116, 115, 115, 114, 114, 114, 113, 414, + /* 730 */ 13, 13, 1024, 13, 13, 13, 13, 13, 13, 383, + /* 740 */ 13, 13, 424, 1100, 401, 264, 264, 277, 160, 184, + /* 750 */ 1182, 185, 1533, 369, 513, 484, 432, 487, 531, 424, + /* 760 */ 423, 1397, 941, 119, 120, 110, 1136, 1136, 981, 984, + /* 770 */ 974, 974, 117, 117, 118, 118, 118, 118, 1397, 1399, + /* 780 */ 425, 519, 392, 264, 264, 1029, 1029, 455, 264, 264, + /* 790 */ 264, 264, 1004, 304, 261, 1278, 531, 900, 288, 525, + /* 800 */ 310, 531, 493, 531, 1067, 1532, 458, 387, 1532, 311, + /* 810 */ 429, 299, 534, 107, 264, 264, 116, 116, 116, 116, + /* 820 */ 115, 115, 114, 114, 114, 113, 414, 531, 424, 1384, + /* 830 */ 507, 258, 258, 1246, 55, 55, 383, 1277, 265, 265, + /* 840 */ 962, 324, 434, 312, 531, 531, 506, 1397, 1026, 1241, + /* 850 */ 298, 531, 1026, 445, 301, 1095, 303, 534, 368, 1156, + /* 860 */ 119, 120, 110, 1136, 1136, 981, 984, 974, 974, 117, + /* 870 */ 117, 118, 118, 118, 118, 1045, 534, 1065, 534, 15, + /* 880 */ 15, 1084, 208, 1324, 453, 452, 534, 1324, 534, 449, + /* 890 */ 1046, 1084, 494, 458, 1084, 234, 233, 232, 44, 44, + /* 900 */ 56, 56, 319, 1095, 322, 1047, 534, 900, 57, 57, + /* 910 */ 58, 58, 534, 116, 116, 116, 116, 115, 115, 114, + /* 920 */ 114, 114, 113, 414, 534, 514, 522, 534, 59, 59, + /* 930 */ 302, 1157, 534, 383, 60, 60, 1237, 946, 788, 789, + /* 940 */ 790, 1459, 1456, 446, 6, 6, 61, 61, 1212, 45, + /* 950 */ 45, 534, 396, 383, 46, 46, 397, 119, 120, 110, + /* 960 */ 1136, 1136, 981, 984, 974, 974, 117, 117, 118, 118, + /* 970 */ 118, 118, 428, 48, 48, 534, 392, 119, 120, 110, + /* 980 */ 1136, 1136, 981, 984, 974, 974, 117, 117, 118, 118, + /* 990 */ 118, 118, 1324, 368, 1066, 447, 825, 49, 49, 534, + /* 1000 */ 458, 357, 534, 353, 534, 138, 534, 337, 1478, 478, + /* 1010 */ 116, 116, 116, 116, 115, 115, 114, 114, 114, 113, + /* 1020 */ 414, 62, 62, 392, 63, 63, 64, 64, 14, 14, + /* 1030 */ 116, 116, 116, 116, 115, 115, 114, 114, 114, 113, + /* 1040 */ 414, 534, 810, 317, 271, 534, 1457, 825, 534, 6, + /* 1050 */ 534, 1324, 534, 142, 534, 1442, 534, 212, 534, 1324, + /* 1060 */ 534, 398, 305, 65, 65, 534, 1157, 125, 125, 476, + /* 1070 */ 66, 66, 51, 51, 67, 67, 68, 68, 52, 52, + /* 1080 */ 147, 147, 148, 148, 534, 98, 534, 75, 75, 276, + /* 1090 */ 534, 272, 534, 810, 534, 876, 534, 527, 389, 534, + /* 1100 */ 875, 534, 1151, 202, 534, 383, 53, 53, 71, 71, + /* 1110 */ 288, 525, 126, 126, 72, 72, 127, 127, 128, 128, + /* 1120 */ 454, 124, 124, 146, 146, 383, 145, 145, 408, 119, + /* 1130 */ 120, 110, 1136, 1136, 981, 984, 974, 974, 117, 117, + /* 1140 */ 118, 118, 118, 118, 534, 900, 534, 95, 534, 119, + /* 1150 */ 120, 110, 1136, 1136, 981, 984, 974, 974, 117, 117, + /* 1160 */ 118, 118, 118, 118, 390, 161, 132, 132, 131, 131, + /* 1170 */ 129, 129, 534, 915, 534, 1455, 534, 1454, 6, 1416, + /* 1180 */ 6, 916, 116, 116, 116, 116, 115, 115, 114, 114, + /* 1190 */ 114, 113, 414, 1415, 130, 130, 74, 74, 76, 76, + /* 1200 */ 534, 30, 116, 116, 116, 116, 115, 115, 114, 114, + /* 1210 */ 114, 113, 414, 534, 263, 206, 534, 1133, 1504, 93, + /* 1220 */ 876, 845, 73, 73, 102, 875, 100, 139, 17, 38, + /* 1230 */ 208, 1062, 31, 450, 370, 43, 43, 101, 47, 47, + /* 1240 */ 827, 216, 436, 308, 943, 440, 95, 241, 241, 442, + /* 1250 */ 313, 464, 241, 95, 237, 900, 327, 383, 266, 95, + /* 1260 */ 835, 834, 193, 335, 938, 314, 1011, 435, 842, 843, + /* 1270 */ 955, 1007, 909, 334, 237, 241, 873, 383, 1023, 107, + /* 1280 */ 1023, 119, 120, 110, 1136, 1136, 981, 984, 974, 974, + /* 1290 */ 117, 117, 118, 118, 118, 118, 1022, 808, 1022, 1274, + /* 1300 */ 137, 119, 108, 110, 1136, 1136, 981, 984, 974, 974, + /* 1310 */ 117, 117, 118, 118, 118, 118, 874, 1011, 318, 107, + /* 1320 */ 321, 955, 323, 325, 1225, 1211, 197, 1210, 1209, 330, + /* 1330 */ 339, 1265, 340, 283, 116, 116, 116, 116, 115, 115, + /* 1340 */ 114, 114, 114, 113, 414, 1286, 1323, 1261, 1471, 1272, + /* 1350 */ 520, 218, 521, 1329, 116, 116, 116, 116, 115, 115, + /* 1360 */ 114, 114, 114, 113, 414, 1192, 1184, 1173, 1172, 1174, + /* 1370 */ 1494, 1488, 459, 256, 383, 1258, 342, 199, 367, 344, + /* 1380 */ 211, 195, 307, 444, 11, 346, 469, 333, 1308, 1316, + /* 1390 */ 375, 427, 203, 360, 383, 1388, 188, 1387, 189, 120, + /* 1400 */ 110, 1136, 1136, 981, 984, 974, 974, 117, 117, 118, + /* 1410 */ 118, 118, 118, 1208, 1151, 300, 348, 1491, 245, 1148, + /* 1420 */ 110, 1136, 1136, 981, 984, 974, 974, 117, 117, 118, + /* 1430 */ 118, 118, 118, 198, 1435, 1433, 524, 78, 391, 163, + /* 1440 */ 82, 1393, 438, 173, 81, 105, 526, 1313, 4, 35, + /* 1450 */ 157, 116, 116, 116, 116, 115, 115, 114, 114, 114, + /* 1460 */ 113, 414, 529, 165, 93, 430, 1305, 168, 169, 431, + /* 1470 */ 462, 116, 116, 116, 116, 115, 115, 114, 114, 114, + /* 1480 */ 113, 414, 170, 171, 221, 415, 372, 437, 1319, 177, + /* 1490 */ 374, 36, 451, 225, 1382, 87, 457, 523, 257, 1404, + /* 1500 */ 316, 105, 526, 227, 4, 182, 460, 160, 320, 228, + /* 1510 */ 377, 1175, 475, 229, 1228, 404, 1227, 1226, 529, 827, + /* 1520 */ 961, 1219, 378, 1200, 1199, 406, 103, 103, 1218, 332, + /* 1530 */ 8, 281, 1198, 104, 1503, 415, 536, 535, 486, 282, + /* 1540 */ 951, 415, 489, 495, 92, 244, 1269, 341, 243, 122, + /* 1550 */ 1270, 343, 514, 523, 1268, 1462, 10, 288, 525, 345, + /* 1560 */ 1461, 354, 99, 352, 503, 94, 1267, 347, 1251, 502, + /* 1570 */ 498, 951, 951, 953, 954, 27, 961, 1250, 194, 358, + /* 1580 */ 251, 359, 103, 103, 1181, 34, 537, 1110, 252, 104, + /* 1590 */ 254, 415, 536, 535, 255, 1368, 951, 1420, 286, 538, + /* 1600 */ 1170, 1165, 1421, 135, 1419, 1418, 149, 150, 279, 784, + /* 1610 */ 416, 196, 151, 290, 210, 200, 77, 385, 269, 386, + /* 1620 */ 133, 162, 935, 1021, 201, 1019, 153, 951, 951, 953, + /* 1630 */ 954, 27, 1480, 1104, 417, 164, 217, 268, 859, 166, + /* 1640 */ 306, 1035, 366, 366, 365, 253, 363, 220, 172, 797, + /* 1650 */ 939, 155, 105, 526, 393, 4, 395, 174, 156, 83, + /* 1660 */ 1038, 84, 213, 85, 294, 222, 86, 223, 1034, 529, + /* 1670 */ 144, 18, 293, 224, 315, 456, 241, 1027, 1145, 178, + /* 1680 */ 226, 179, 37, 799, 334, 461, 230, 465, 470, 838, + /* 1690 */ 180, 88, 415, 19, 280, 328, 20, 89, 90, 158, + /* 1700 */ 191, 477, 215, 1097, 523, 204, 192, 987, 91, 1070, + /* 1710 */ 152, 39, 485, 154, 1071, 503, 40, 488, 205, 260, + /* 1720 */ 504, 262, 105, 526, 214, 4, 908, 961, 183, 240, + /* 1730 */ 903, 107, 1086, 103, 103, 21, 22, 1088, 23, 529, + /* 1740 */ 104, 24, 415, 536, 535, 1090, 1093, 951, 1094, 25, + /* 1750 */ 1074, 33, 7, 26, 510, 1002, 247, 186, 384, 95, + /* 1760 */ 988, 986, 415, 288, 525, 990, 1044, 246, 1043, 991, + /* 1770 */ 28, 41, 530, 956, 523, 809, 106, 29, 951, 951, + /* 1780 */ 953, 954, 27, 869, 361, 503, 422, 248, 364, 1105, + /* 1790 */ 502, 249, 1161, 1496, 1495, 1161, 1161, 961, 1161, 1161, + /* 1800 */ 1161, 1161, 1161, 103, 103, 1161, 1161, 1161, 1161, 1161, + /* 1810 */ 104, 1161, 415, 536, 535, 1104, 417, 951, 1161, 268, + /* 1820 */ 1161, 1161, 1161, 1161, 366, 366, 365, 253, 363, 1161, + /* 1830 */ 1161, 797, 1161, 1161, 1161, 1161, 105, 526, 1161, 4, + /* 1840 */ 1161, 1161, 1161, 1161, 213, 1161, 294, 1161, 951, 951, + /* 1850 */ 953, 954, 27, 529, 293, 1161, 1161, 1161, 1161, 1161, + /* 1860 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, + /* 1870 */ 1161, 1161, 1161, 1161, 1161, 1161, 415, 1161, 1161, 1161, + /* 1880 */ 1161, 1161, 1161, 1161, 215, 1161, 1161, 1161, 523, 1161, + /* 1890 */ 1161, 1161, 152, 1161, 1161, 154, 105, 526, 1161, 4, + /* 1900 */ 1161, 1161, 1161, 1161, 1161, 1161, 214, 1161, 1161, 1161, + /* 1910 */ 1161, 961, 1161, 529, 1161, 1161, 1161, 103, 103, 880, + /* 1920 */ 1161, 1161, 1161, 1161, 104, 1161, 415, 536, 535, 1161, + /* 1930 */ 1161, 951, 1161, 1161, 1161, 1161, 415, 1161, 1161, 1161, + /* 1940 */ 384, 1161, 1161, 1161, 1161, 288, 525, 1161, 523, 1161, + /* 1950 */ 1161, 1161, 1161, 1161, 1161, 1161, 97, 526, 1161, 4, + /* 1960 */ 1161, 1161, 951, 951, 953, 954, 27, 1161, 422, 1161, + /* 1970 */ 1161, 961, 1161, 529, 1161, 1161, 1161, 103, 103, 1161, + /* 1980 */ 1161, 1161, 1161, 1161, 104, 1161, 415, 536, 535, 1161, + /* 1990 */ 1161, 951, 268, 1161, 1161, 1161, 415, 366, 366, 365, + /* 2000 */ 253, 363, 1161, 1161, 797, 1161, 1161, 1161, 523, 1161, + /* 2010 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 213, 1161, 294, + /* 2020 */ 1161, 1161, 951, 951, 953, 954, 27, 293, 1161, 1161, + /* 2030 */ 1161, 961, 1161, 1161, 1161, 1161, 1161, 103, 103, 1161, + /* 2040 */ 1161, 1161, 1161, 1161, 104, 1161, 415, 536, 535, 1161, + /* 2050 */ 1161, 951, 1161, 1161, 1161, 1161, 1161, 215, 1161, 1161, + /* 2060 */ 1161, 1161, 1161, 1161, 1161, 152, 1161, 1161, 154, 1161, + /* 2070 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 214, + /* 2080 */ 1161, 1161, 951, 951, 953, 954, 27, 1161, 1161, 1161, + /* 2090 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, + /* 2100 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, + /* 2110 */ 1161, 1161, 1161, 384, 1161, 1161, 1161, 1161, 288, 525, + /* 2120 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, + /* 2130 */ 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161, + /* 2140 */ 1161, 422, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 168, 163, 184, 238, 239, 240, 163, 163, 155, 156, - /* 10 */ 157, 158, 159, 160, 163, 202, 203, 187, 165, 19, - /* 20 */ 167, 163, 184, 185, 259, 202, 203, 174, 184, 185, - /* 30 */ 174, 31, 238, 239, 240, 184, 185, 22, 23, 39, - /* 40 */ 216, 26, 218, 43, 44, 45, 46, 47, 48, 49, - /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 174, 206, - /* 60 */ 207, 163, 206, 207, 220, 163, 163, 163, 238, 239, - /* 70 */ 240, 59, 219, 229, 231, 219, 183, 245, 174, 223, - /* 80 */ 224, 249, 184, 185, 191, 232, 184, 185, 184, 185, - /* 90 */ 206, 207, 92, 93, 94, 95, 96, 97, 98, 99, - /* 100 */ 100, 101, 102, 219, 102, 81, 91, 163, 96, 97, - /* 110 */ 206, 207, 19, 275, 276, 262, 104, 105, 106, 107, - /* 120 */ 163, 109, 220, 219, 220, 184, 275, 269, 277, 117, - /* 130 */ 187, 229, 19, 229, 101, 102, 43, 44, 45, 46, - /* 140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 150 */ 57, 127, 128, 141, 184, 143, 43, 44, 45, 46, - /* 160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 170 */ 57, 268, 269, 275, 276, 197, 83, 233, 85, 163, - /* 180 */ 67, 238, 239, 240, 134, 92, 93, 94, 95, 96, - /* 190 */ 97, 98, 99, 100, 101, 102, 19, 54, 55, 56, - /* 200 */ 57, 58, 152, 26, 247, 92, 93, 94, 95, 96, - /* 210 */ 97, 98, 99, 100, 101, 102, 54, 55, 56, 57, - /* 220 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 230 */ 53, 54, 55, 56, 57, 92, 93, 94, 95, 96, - /* 240 */ 97, 98, 99, 100, 101, 102, 69, 96, 97, 98, - /* 250 */ 99, 100, 101, 102, 92, 93, 94, 95, 96, 97, - /* 260 */ 98, 99, 100, 101, 102, 73, 179, 180, 181, 92, - /* 270 */ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - /* 280 */ 163, 191, 192, 163, 98, 99, 100, 101, 102, 19, - /* 290 */ 200, 179, 180, 181, 24, 175, 92, 93, 94, 95, - /* 300 */ 96, 97, 98, 99, 100, 101, 102, 163, 116, 117, - /* 310 */ 118, 22, 163, 43, 44, 45, 46, 47, 48, 49, - /* 320 */ 50, 51, 52, 53, 54, 55, 56, 57, 157, 158, - /* 330 */ 159, 160, 163, 184, 185, 163, 165, 59, 167, 46, - /* 340 */ 90, 76, 11, 174, 73, 174, 19, 198, 59, 19, - /* 350 */ 72, 86, 81, 184, 185, 234, 106, 96, 97, 163, - /* 360 */ 110, 182, 92, 93, 94, 95, 96, 97, 98, 99, - /* 370 */ 100, 101, 102, 46, 230, 206, 207, 206, 207, 163, - /* 380 */ 184, 185, 19, 105, 106, 107, 23, 116, 219, 220, - /* 390 */ 219, 141, 142, 143, 105, 106, 107, 104, 127, 128, - /* 400 */ 184, 185, 141, 232, 143, 59, 43, 44, 45, 46, - /* 410 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 420 */ 57, 158, 108, 160, 59, 111, 112, 113, 165, 250, - /* 430 */ 167, 104, 102, 262, 255, 121, 220, 174, 108, 109, - /* 440 */ 110, 111, 112, 113, 114, 229, 182, 120, 117, 118, - /* 450 */ 120, 105, 106, 107, 163, 92, 93, 94, 95, 96, - /* 460 */ 97, 98, 99, 100, 101, 102, 163, 22, 59, 206, - /* 470 */ 207, 106, 163, 26, 171, 19, 163, 193, 175, 23, - /* 480 */ 163, 22, 219, 206, 207, 139, 163, 22, 59, 182, - /* 490 */ 117, 118, 59, 184, 185, 232, 219, 184, 185, 43, - /* 500 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 510 */ 54, 55, 56, 57, 105, 106, 107, 108, 59, 255, - /* 520 */ 111, 112, 113, 90, 59, 262, 22, 98, 174, 12, - /* 530 */ 121, 208, 163, 220, 105, 106, 107, 163, 105, 106, - /* 540 */ 22, 96, 97, 110, 27, 238, 239, 240, 92, 93, - /* 550 */ 94, 95, 96, 97, 98, 99, 100, 101, 102, 42, - /* 560 */ 206, 207, 115, 59, 105, 106, 107, 163, 19, 59, - /* 570 */ 163, 106, 23, 219, 141, 142, 143, 59, 163, 205, - /* 580 */ 63, 59, 72, 22, 124, 59, 163, 270, 234, 129, - /* 590 */ 73, 163, 43, 44, 45, 46, 47, 48, 49, 50, - /* 600 */ 51, 52, 53, 54, 55, 56, 57, 184, 185, 105, - /* 610 */ 106, 107, 184, 185, 163, 105, 106, 107, 265, 266, - /* 620 */ 59, 198, 225, 105, 106, 107, 198, 105, 106, 107, - /* 630 */ 163, 105, 106, 107, 163, 184, 185, 46, 47, 48, - /* 640 */ 49, 92, 93, 94, 95, 96, 97, 98, 99, 100, - /* 650 */ 101, 102, 163, 163, 132, 184, 185, 163, 132, 163, - /* 660 */ 256, 19, 163, 163, 163, 23, 105, 106, 107, 198, - /* 670 */ 163, 220, 205, 184, 185, 163, 35, 81, 184, 185, - /* 680 */ 184, 185, 163, 184, 185, 43, 44, 45, 46, 47, - /* 690 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 700 */ 163, 110, 163, 184, 185, 109, 205, 66, 163, 59, - /* 710 */ 163, 21, 205, 16, 174, 74, 220, 198, 163, 220, - /* 720 */ 230, 184, 185, 127, 128, 180, 181, 180, 181, 163, - /* 730 */ 175, 242, 174, 233, 92, 93, 94, 95, 96, 97, - /* 740 */ 98, 99, 100, 101, 102, 233, 206, 207, 26, 163, - /* 750 */ 195, 207, 197, 26, 19, 105, 106, 107, 23, 219, - /* 760 */ 119, 260, 26, 219, 206, 207, 174, 19, 174, 230, - /* 770 */ 80, 174, 163, 174, 77, 163, 79, 219, 43, 44, - /* 780 */ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - /* 790 */ 55, 56, 57, 248, 12, 248, 184, 185, 206, 207, - /* 800 */ 206, 207, 112, 206, 207, 206, 207, 206, 207, 27, - /* 810 */ 163, 219, 123, 219, 125, 126, 219, 208, 219, 163, - /* 820 */ 219, 22, 23, 23, 42, 26, 26, 92, 93, 94, - /* 830 */ 95, 96, 97, 98, 99, 100, 101, 102, 163, 149, - /* 840 */ 184, 185, 163, 107, 163, 63, 149, 19, 163, 127, - /* 850 */ 128, 23, 22, 105, 24, 116, 117, 118, 131, 184, - /* 860 */ 185, 163, 163, 184, 185, 184, 185, 19, 132, 184, - /* 870 */ 185, 43, 44, 45, 46, 47, 48, 49, 50, 51, - /* 880 */ 52, 53, 54, 55, 56, 57, 146, 163, 148, 59, - /* 890 */ 91, 43, 44, 45, 46, 47, 48, 49, 50, 51, - /* 900 */ 52, 53, 54, 55, 56, 57, 208, 107, 184, 185, - /* 910 */ 7, 8, 9, 116, 117, 118, 163, 163, 163, 24, - /* 920 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - /* 930 */ 102, 29, 132, 163, 163, 33, 106, 184, 185, 163, - /* 940 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - /* 950 */ 102, 163, 163, 163, 59, 184, 185, 163, 22, 163, - /* 960 */ 184, 185, 177, 178, 163, 163, 163, 65, 163, 199, - /* 970 */ 163, 26, 184, 185, 184, 185, 163, 163, 184, 185, - /* 980 */ 184, 185, 163, 98, 163, 184, 185, 184, 185, 184, - /* 990 */ 185, 184, 185, 252, 205, 147, 163, 61, 184, 185, - /* 1000 */ 163, 106, 163, 184, 185, 163, 163, 205, 163, 124, - /* 1010 */ 163, 256, 163, 163, 129, 19, 163, 184, 185, 163, - /* 1020 */ 199, 184, 185, 184, 185, 23, 184, 185, 26, 184, - /* 1030 */ 185, 184, 185, 184, 185, 19, 163, 184, 185, 43, - /* 1040 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 1050 */ 54, 55, 56, 57, 163, 163, 163, 184, 185, 43, - /* 1060 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - /* 1070 */ 54, 55, 56, 57, 16, 184, 185, 184, 185, 163, - /* 1080 */ 163, 22, 23, 138, 163, 19, 163, 231, 92, 93, - /* 1090 */ 94, 95, 96, 97, 98, 99, 100, 101, 102, 256, - /* 1100 */ 163, 184, 185, 163, 163, 184, 185, 163, 92, 93, - /* 1110 */ 94, 95, 96, 97, 98, 99, 100, 101, 102, 163, - /* 1120 */ 59, 184, 185, 163, 184, 185, 177, 178, 184, 185, - /* 1130 */ 163, 208, 163, 237, 163, 77, 163, 79, 163, 15, - /* 1140 */ 184, 185, 237, 147, 184, 185, 24, 231, 153, 154, - /* 1150 */ 91, 184, 185, 184, 185, 184, 185, 184, 185, 184, - /* 1160 */ 185, 22, 23, 19, 163, 127, 128, 106, 24, 273, - /* 1170 */ 271, 105, 231, 274, 263, 264, 223, 224, 273, 22, - /* 1180 */ 118, 24, 23, 19, 60, 26, 163, 43, 44, 45, - /* 1190 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - /* 1200 */ 56, 57, 140, 23, 22, 163, 26, 43, 44, 45, - /* 1210 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - /* 1220 */ 56, 57, 23, 211, 23, 26, 31, 26, 23, 22, - /* 1230 */ 91, 26, 231, 221, 39, 53, 92, 93, 94, 95, - /* 1240 */ 96, 97, 98, 99, 100, 101, 102, 23, 23, 163, - /* 1250 */ 26, 26, 130, 59, 109, 110, 92, 93, 94, 95, - /* 1260 */ 96, 97, 98, 99, 100, 101, 102, 23, 7, 8, - /* 1270 */ 26, 110, 23, 59, 23, 26, 19, 26, 141, 23, - /* 1280 */ 143, 120, 26, 141, 163, 143, 23, 23, 163, 26, - /* 1290 */ 26, 163, 163, 163, 163, 163, 19, 163, 163, 193, - /* 1300 */ 106, 44, 45, 46, 47, 48, 49, 50, 51, 52, - /* 1310 */ 53, 54, 55, 56, 57, 163, 193, 163, 163, 163, - /* 1320 */ 106, 163, 45, 46, 47, 48, 49, 50, 51, 52, - /* 1330 */ 53, 54, 55, 56, 57, 163, 163, 130, 222, 163, - /* 1340 */ 163, 203, 163, 19, 20, 251, 22, 163, 163, 92, - /* 1350 */ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - /* 1360 */ 36, 163, 209, 163, 261, 163, 163, 161, 222, 92, - /* 1370 */ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - /* 1380 */ 210, 213, 222, 59, 222, 222, 182, 213, 213, 196, - /* 1390 */ 257, 226, 226, 19, 20, 71, 22, 257, 188, 187, - /* 1400 */ 192, 212, 187, 187, 226, 81, 210, 166, 60, 261, - /* 1410 */ 36, 244, 130, 170, 90, 170, 38, 170, 139, 104, - /* 1420 */ 96, 97, 48, 236, 22, 235, 43, 103, 201, 105, - /* 1430 */ 106, 107, 138, 59, 110, 247, 213, 18, 204, 258, - /* 1440 */ 204, 258, 204, 204, 170, 71, 18, 169, 213, 236, - /* 1450 */ 213, 127, 128, 235, 201, 201, 82, 170, 169, 213, - /* 1460 */ 146, 87, 62, 254, 90, 141, 142, 143, 144, 145, - /* 1470 */ 96, 97, 253, 170, 169, 22, 170, 103, 169, 105, - /* 1480 */ 106, 107, 189, 170, 110, 169, 189, 186, 19, 20, - /* 1490 */ 104, 22, 194, 186, 186, 64, 115, 186, 194, 189, - /* 1500 */ 188, 102, 133, 186, 186, 36, 186, 104, 189, 19, - /* 1510 */ 20, 246, 22, 246, 189, 141, 142, 143, 144, 145, - /* 1520 */ 0, 1, 2, 228, 228, 5, 36, 227, 59, 227, - /* 1530 */ 10, 11, 12, 13, 14, 170, 84, 17, 134, 216, - /* 1540 */ 71, 272, 270, 22, 137, 217, 22, 216, 227, 59, - /* 1550 */ 30, 82, 32, 217, 228, 228, 87, 227, 170, 90, - /* 1560 */ 40, 71, 146, 241, 215, 96, 97, 214, 136, 135, - /* 1570 */ 213, 25, 103, 26, 105, 106, 107, 243, 173, 110, - /* 1580 */ 90, 172, 13, 6, 164, 164, 96, 97, 98, 162, - /* 1590 */ 70, 162, 162, 103, 176, 105, 106, 107, 78, 267, - /* 1600 */ 110, 81, 267, 264, 182, 182, 182, 182, 88, 176, - /* 1610 */ 141, 142, 143, 144, 145, 176, 190, 4, 182, 182, - /* 1620 */ 182, 19, 20, 182, 22, 190, 3, 22, 151, 15, - /* 1630 */ 89, 141, 142, 143, 144, 145, 16, 128, 36, 23, - /* 1640 */ 23, 139, 122, 24, 119, 131, 20, 127, 128, 133, - /* 1650 */ 16, 1, 140, 131, 119, 61, 139, 53, 37, 53, - /* 1660 */ 53, 59, 53, 119, 105, 34, 130, 1, 5, 22, - /* 1670 */ 150, 104, 149, 71, 26, 75, 68, 41, 68, 130, - /* 1680 */ 104, 24, 20, 19, 82, 120, 114, 22, 28, 87, - /* 1690 */ 22, 67, 90, 22, 67, 23, 22, 22, 96, 97, - /* 1700 */ 67, 23, 138, 22, 37, 103, 153, 105, 106, 107, - /* 1710 */ 1, 2, 110, 23, 5, 23, 23, 26, 22, 10, - /* 1720 */ 11, 12, 13, 14, 24, 23, 17, 22, 24, 130, - /* 1730 */ 23, 19, 20, 23, 22, 105, 22, 34, 85, 30, - /* 1740 */ 34, 32, 26, 141, 142, 143, 144, 145, 36, 40, - /* 1750 */ 132, 34, 75, 83, 23, 44, 24, 34, 23, 26, - /* 1760 */ 26, 19, 20, 23, 22, 26, 23, 23, 23, 23, - /* 1770 */ 22, 59, 11, 22, 22, 26, 23, 23, 36, 70, - /* 1780 */ 22, 22, 124, 71, 130, 130, 130, 78, 23, 130, - /* 1790 */ 81, 15, 1, 278, 278, 278, 278, 88, 278, 278, - /* 1800 */ 278, 59, 90, 278, 278, 278, 278, 278, 96, 97, - /* 1810 */ 278, 278, 278, 71, 278, 103, 278, 105, 106, 107, - /* 1820 */ 278, 278, 110, 278, 278, 278, 278, 278, 278, 278, - /* 1830 */ 278, 122, 90, 278, 278, 278, 127, 128, 96, 97, - /* 1840 */ 278, 278, 278, 278, 278, 103, 278, 105, 106, 107, - /* 1850 */ 278, 278, 110, 141, 142, 143, 144, 145, 278, 150, - /* 1860 */ 278, 278, 278, 5, 278, 278, 278, 278, 10, 11, - /* 1870 */ 12, 13, 14, 278, 278, 17, 278, 278, 278, 278, - /* 1880 */ 278, 278, 278, 141, 142, 143, 144, 145, 30, 278, - /* 1890 */ 32, 278, 278, 278, 278, 278, 278, 278, 40, 278, - /* 1900 */ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - /* 1910 */ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - /* 1920 */ 278, 278, 278, 278, 278, 278, 278, 278, 70, 278, - /* 1930 */ 278, 278, 278, 278, 278, 278, 78, 278, 278, 81, - /* 1940 */ 278, 278, 278, 278, 278, 278, 88, 278, 278, 278, - /* 1950 */ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - /* 1960 */ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - /* 1970 */ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - /* 1980 */ 122, 278, 278, 278, 278, 127, 128, 278, 278, 278, - /* 1990 */ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - /* 2000 */ 278, 278, 278, 278, 278, 278, 278, 278, 150, 278, - /* 2010 */ 278, 278, 278, 278, 278, 278, 278, 278, 278, + /* 0 */ 260, 261, 262, 260, 261, 262, 176, 177, 178, 179, + /* 10 */ 180, 181, 184, 206, 209, 184, 186, 206, 188, 19, + /* 20 */ 179, 281, 181, 213, 214, 195, 206, 186, 195, 188, + /* 30 */ 195, 31, 222, 184, 206, 207, 195, 206, 207, 39, + /* 40 */ 24, 209, 184, 43, 44, 45, 46, 47, 48, 49, + /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 228, 229, + /* 60 */ 184, 228, 229, 228, 229, 260, 261, 262, 192, 228, + /* 70 */ 229, 241, 196, 242, 241, 59, 241, 205, 245, 246, + /* 80 */ 184, 22, 241, 24, 254, 213, 54, 55, 56, 57, + /* 90 */ 58, 256, 260, 261, 262, 254, 96, 97, 98, 99, + /* 100 */ 100, 101, 102, 103, 104, 105, 106, 100, 101, 102, + /* 110 */ 103, 104, 105, 106, 284, 203, 19, 221, 59, 102, + /* 120 */ 103, 104, 105, 106, 59, 284, 110, 269, 96, 97, + /* 130 */ 98, 99, 100, 101, 102, 103, 104, 105, 106, 94, + /* 140 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 150 */ 53, 54, 55, 56, 57, 110, 184, 106, 73, 114, + /* 160 */ 178, 179, 180, 181, 219, 184, 81, 22, 186, 110, + /* 170 */ 188, 121, 122, 195, 109, 110, 111, 195, 206, 207, + /* 180 */ 83, 184, 85, 54, 55, 56, 57, 206, 207, 277, + /* 190 */ 145, 146, 147, 96, 97, 98, 99, 100, 101, 102, + /* 200 */ 103, 104, 105, 106, 59, 120, 228, 229, 143, 184, + /* 210 */ 228, 229, 184, 19, 242, 203, 131, 132, 221, 241, + /* 220 */ 26, 184, 184, 241, 196, 96, 97, 98, 99, 100, + /* 230 */ 101, 102, 103, 104, 105, 106, 254, 43, 44, 45, + /* 240 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 250 */ 56, 57, 184, 184, 109, 110, 111, 105, 106, 184, + /* 260 */ 200, 201, 202, 69, 184, 227, 284, 96, 97, 98, + /* 270 */ 99, 100, 101, 102, 103, 104, 105, 106, 297, 298, + /* 280 */ 255, 206, 207, 19, 272, 59, 206, 207, 184, 277, + /* 290 */ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + /* 300 */ 106, 184, 259, 19, 184, 100, 101, 43, 44, 45, + /* 310 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 320 */ 56, 57, 242, 206, 207, 184, 100, 101, 138, 292, + /* 330 */ 293, 67, 76, 296, 108, 109, 110, 111, 295, 113, + /* 340 */ 84, 59, 86, 22, 26, 89, 156, 121, 224, 225, + /* 350 */ 145, 19, 147, 59, 72, 256, 24, 184, 290, 291, + /* 360 */ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + /* 370 */ 106, 145, 297, 147, 299, 43, 44, 45, 46, 47, + /* 380 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 390 */ 106, 109, 110, 111, 138, 184, 112, 113, 114, 115, + /* 400 */ 116, 117, 118, 109, 110, 111, 112, 59, 124, 115, + /* 410 */ 116, 117, 292, 293, 297, 298, 296, 206, 207, 125, + /* 420 */ 72, 100, 101, 184, 46, 47, 48, 49, 96, 97, + /* 430 */ 98, 99, 100, 101, 102, 103, 104, 105, 106, 59, + /* 440 */ 200, 201, 202, 184, 59, 206, 207, 46, 19, 131, + /* 450 */ 132, 278, 23, 242, 184, 184, 76, 109, 110, 111, + /* 460 */ 224, 225, 251, 81, 84, 184, 86, 22, 23, 89, + /* 470 */ 184, 26, 43, 44, 45, 46, 47, 48, 49, 50, + /* 480 */ 51, 52, 53, 54, 55, 56, 57, 102, 184, 109, + /* 490 */ 110, 111, 114, 184, 109, 110, 111, 184, 227, 184, + /* 500 */ 230, 184, 22, 264, 195, 59, 22, 184, 195, 108, + /* 510 */ 206, 207, 59, 131, 132, 206, 207, 184, 138, 206, + /* 520 */ 207, 206, 207, 206, 207, 96, 97, 98, 99, 100, + /* 530 */ 101, 102, 103, 104, 105, 106, 255, 228, 229, 59, + /* 540 */ 95, 228, 229, 59, 184, 19, 242, 94, 184, 23, + /* 550 */ 241, 242, 184, 282, 241, 242, 110, 242, 184, 242, + /* 560 */ 251, 59, 109, 110, 196, 184, 251, 114, 251, 43, + /* 570 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 580 */ 54, 55, 56, 57, 259, 217, 12, 219, 255, 109, + /* 590 */ 110, 111, 203, 109, 110, 111, 184, 22, 145, 146, + /* 600 */ 147, 27, 112, 22, 230, 115, 116, 117, 227, 19, + /* 610 */ 59, 109, 110, 111, 291, 125, 42, 35, 206, 207, + /* 620 */ 295, 184, 96, 97, 98, 99, 100, 101, 102, 103, + /* 630 */ 104, 105, 106, 26, 59, 233, 46, 63, 136, 184, + /* 640 */ 59, 184, 19, 206, 207, 243, 23, 73, 66, 260, + /* 650 */ 261, 262, 59, 184, 242, 195, 74, 220, 184, 184, + /* 660 */ 109, 110, 111, 206, 207, 184, 43, 44, 45, 46, + /* 670 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 680 */ 57, 206, 207, 76, 109, 110, 111, 136, 228, 229, + /* 690 */ 109, 110, 111, 86, 184, 220, 89, 21, 108, 230, + /* 700 */ 184, 241, 109, 110, 111, 123, 184, 127, 184, 129, + /* 710 */ 130, 184, 195, 184, 124, 184, 198, 199, 184, 96, + /* 720 */ 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + /* 730 */ 206, 207, 11, 206, 207, 206, 207, 206, 207, 19, + /* 740 */ 206, 207, 184, 23, 220, 228, 229, 220, 81, 220, + /* 750 */ 195, 220, 287, 288, 220, 195, 80, 195, 241, 201, + /* 760 */ 202, 184, 73, 43, 44, 45, 46, 47, 48, 49, + /* 770 */ 50, 51, 52, 53, 54, 55, 56, 57, 201, 202, + /* 780 */ 113, 195, 184, 228, 229, 120, 121, 122, 228, 229, + /* 790 */ 228, 229, 116, 16, 23, 184, 241, 26, 131, 132, + /* 800 */ 278, 241, 19, 241, 22, 23, 184, 189, 26, 120, + /* 810 */ 121, 122, 184, 26, 228, 229, 96, 97, 98, 99, + /* 820 */ 100, 101, 102, 103, 104, 105, 106, 241, 270, 153, + /* 830 */ 66, 228, 229, 229, 206, 207, 19, 184, 228, 229, + /* 840 */ 23, 16, 121, 122, 241, 241, 82, 270, 29, 227, + /* 850 */ 252, 241, 33, 19, 77, 91, 79, 184, 22, 23, + /* 860 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + /* 870 */ 53, 54, 55, 56, 57, 12, 184, 95, 184, 206, + /* 880 */ 207, 76, 111, 184, 65, 267, 184, 184, 184, 271, + /* 890 */ 27, 86, 109, 184, 89, 120, 121, 122, 206, 207, + /* 900 */ 206, 207, 77, 139, 79, 42, 184, 136, 206, 207, + /* 910 */ 206, 207, 184, 96, 97, 98, 99, 100, 101, 102, + /* 920 */ 103, 104, 105, 106, 184, 138, 63, 184, 206, 207, + /* 930 */ 153, 95, 184, 19, 206, 207, 227, 23, 7, 8, + /* 940 */ 9, 293, 293, 109, 296, 296, 206, 207, 215, 206, + /* 950 */ 207, 184, 253, 19, 206, 207, 253, 43, 44, 45, + /* 960 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 970 */ 56, 57, 184, 206, 207, 184, 184, 43, 44, 45, + /* 980 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 990 */ 56, 57, 184, 22, 23, 184, 59, 206, 207, 184, + /* 1000 */ 184, 238, 184, 240, 184, 22, 184, 184, 157, 158, + /* 1010 */ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + /* 1020 */ 106, 206, 207, 184, 206, 207, 206, 207, 206, 207, + /* 1030 */ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + /* 1040 */ 106, 184, 59, 227, 252, 184, 293, 110, 184, 296, + /* 1050 */ 184, 184, 184, 230, 184, 184, 184, 15, 184, 184, + /* 1060 */ 184, 253, 184, 206, 207, 184, 95, 206, 207, 102, + /* 1070 */ 206, 207, 206, 207, 206, 207, 206, 207, 206, 207, + /* 1080 */ 206, 207, 206, 207, 184, 151, 184, 206, 207, 278, + /* 1090 */ 184, 252, 184, 110, 184, 128, 184, 198, 199, 184, + /* 1100 */ 133, 184, 60, 26, 184, 19, 206, 207, 206, 207, + /* 1110 */ 131, 132, 206, 207, 206, 207, 206, 207, 206, 207, + /* 1120 */ 253, 206, 207, 206, 207, 19, 206, 207, 253, 43, + /* 1130 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 1140 */ 54, 55, 56, 57, 184, 26, 184, 26, 184, 43, + /* 1150 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + /* 1160 */ 54, 55, 56, 57, 285, 286, 206, 207, 206, 207, + /* 1170 */ 206, 207, 184, 31, 184, 293, 184, 293, 296, 184, + /* 1180 */ 296, 39, 96, 97, 98, 99, 100, 101, 102, 103, + /* 1190 */ 104, 105, 106, 184, 206, 207, 206, 207, 206, 207, + /* 1200 */ 184, 22, 96, 97, 98, 99, 100, 101, 102, 103, + /* 1210 */ 104, 105, 106, 184, 245, 246, 184, 26, 23, 142, + /* 1220 */ 128, 26, 206, 207, 150, 133, 152, 22, 22, 24, + /* 1230 */ 111, 23, 53, 184, 26, 206, 207, 151, 206, 207, + /* 1240 */ 119, 24, 122, 23, 23, 23, 26, 26, 26, 23, + /* 1250 */ 23, 23, 26, 26, 26, 136, 23, 19, 22, 26, + /* 1260 */ 113, 114, 24, 114, 144, 184, 59, 61, 7, 8, + /* 1270 */ 59, 23, 23, 124, 26, 26, 23, 19, 145, 26, + /* 1280 */ 147, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 1290 */ 52, 53, 54, 55, 56, 57, 145, 23, 147, 184, + /* 1300 */ 26, 43, 44, 45, 46, 47, 48, 49, 50, 51, + /* 1310 */ 52, 53, 54, 55, 56, 57, 23, 110, 184, 26, + /* 1320 */ 184, 110, 184, 184, 184, 215, 135, 215, 184, 184, + /* 1330 */ 184, 247, 184, 244, 96, 97, 98, 99, 100, 101, + /* 1340 */ 102, 103, 104, 105, 106, 184, 184, 184, 301, 184, + /* 1350 */ 184, 134, 225, 184, 96, 97, 98, 99, 100, 101, + /* 1360 */ 102, 103, 104, 105, 106, 184, 184, 184, 184, 184, + /* 1370 */ 134, 184, 274, 273, 19, 244, 244, 204, 182, 244, + /* 1380 */ 283, 231, 279, 279, 232, 244, 210, 209, 235, 235, + /* 1390 */ 235, 248, 218, 234, 19, 209, 238, 209, 238, 44, + /* 1400 */ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + /* 1410 */ 55, 56, 57, 214, 60, 248, 248, 187, 134, 38, + /* 1420 */ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + /* 1430 */ 55, 56, 57, 232, 191, 191, 266, 280, 191, 283, + /* 1440 */ 143, 269, 108, 22, 280, 19, 20, 258, 22, 257, + /* 1450 */ 43, 96, 97, 98, 99, 100, 101, 102, 103, 104, + /* 1460 */ 105, 106, 36, 223, 142, 18, 235, 226, 226, 191, + /* 1470 */ 18, 96, 97, 98, 99, 100, 101, 102, 103, 104, + /* 1480 */ 105, 106, 226, 226, 190, 59, 235, 235, 223, 223, + /* 1490 */ 258, 257, 191, 190, 235, 150, 62, 71, 191, 276, + /* 1500 */ 275, 19, 20, 190, 22, 22, 211, 81, 191, 190, + /* 1510 */ 211, 191, 108, 190, 208, 64, 208, 208, 36, 119, + /* 1520 */ 94, 216, 211, 208, 210, 106, 100, 101, 216, 208, + /* 1530 */ 48, 268, 208, 107, 208, 109, 110, 111, 211, 268, + /* 1540 */ 114, 59, 211, 137, 108, 88, 250, 249, 191, 141, + /* 1550 */ 250, 249, 138, 71, 250, 300, 22, 131, 132, 249, + /* 1560 */ 300, 191, 150, 238, 82, 140, 250, 249, 239, 87, + /* 1570 */ 139, 145, 146, 147, 148, 149, 94, 239, 237, 236, + /* 1580 */ 25, 235, 100, 101, 194, 26, 193, 13, 185, 107, + /* 1590 */ 185, 109, 110, 111, 6, 263, 114, 203, 265, 183, + /* 1600 */ 183, 183, 203, 212, 203, 203, 197, 197, 212, 4, + /* 1610 */ 3, 22, 197, 155, 15, 204, 203, 289, 93, 289, + /* 1620 */ 16, 286, 132, 23, 204, 23, 123, 145, 146, 147, + /* 1630 */ 148, 149, 0, 1, 2, 143, 24, 5, 20, 135, + /* 1640 */ 16, 1, 10, 11, 12, 13, 14, 137, 135, 17, + /* 1650 */ 144, 123, 19, 20, 61, 22, 37, 143, 123, 53, + /* 1660 */ 109, 53, 30, 53, 32, 34, 53, 134, 1, 36, + /* 1670 */ 5, 22, 40, 108, 153, 41, 26, 68, 75, 68, + /* 1680 */ 134, 108, 24, 20, 124, 19, 118, 67, 67, 28, + /* 1690 */ 22, 22, 59, 22, 67, 23, 22, 22, 142, 37, + /* 1700 */ 23, 22, 70, 23, 71, 157, 23, 23, 26, 23, + /* 1710 */ 78, 22, 24, 81, 23, 82, 22, 24, 134, 23, + /* 1720 */ 87, 23, 19, 20, 92, 22, 109, 94, 22, 34, + /* 1730 */ 136, 26, 85, 100, 101, 34, 34, 83, 34, 36, + /* 1740 */ 107, 34, 109, 110, 111, 75, 90, 114, 75, 34, + /* 1750 */ 23, 22, 44, 34, 24, 23, 22, 26, 126, 26, + /* 1760 */ 23, 23, 59, 131, 132, 23, 23, 26, 23, 11, + /* 1770 */ 22, 22, 26, 23, 71, 23, 22, 22, 145, 146, + /* 1780 */ 147, 148, 149, 128, 23, 82, 154, 134, 15, 1, + /* 1790 */ 87, 134, 302, 134, 134, 302, 302, 94, 302, 302, + /* 1800 */ 302, 302, 302, 100, 101, 302, 302, 302, 302, 302, + /* 1810 */ 107, 302, 109, 110, 111, 1, 2, 114, 302, 5, + /* 1820 */ 302, 302, 302, 302, 10, 11, 12, 13, 14, 302, + /* 1830 */ 302, 17, 302, 302, 302, 302, 19, 20, 302, 22, + /* 1840 */ 302, 302, 302, 302, 30, 302, 32, 302, 145, 146, + /* 1850 */ 147, 148, 149, 36, 40, 302, 302, 302, 302, 302, + /* 1860 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 1870 */ 302, 302, 302, 302, 302, 302, 59, 302, 302, 302, + /* 1880 */ 302, 302, 302, 302, 70, 302, 302, 302, 71, 302, + /* 1890 */ 302, 302, 78, 302, 302, 81, 19, 20, 302, 22, + /* 1900 */ 302, 302, 302, 302, 302, 302, 92, 302, 302, 302, + /* 1910 */ 302, 94, 302, 36, 302, 302, 302, 100, 101, 102, + /* 1920 */ 302, 302, 302, 302, 107, 302, 109, 110, 111, 302, + /* 1930 */ 302, 114, 302, 302, 302, 302, 59, 302, 302, 302, + /* 1940 */ 126, 302, 302, 302, 302, 131, 132, 302, 71, 302, + /* 1950 */ 302, 302, 302, 302, 302, 302, 19, 20, 302, 22, + /* 1960 */ 302, 302, 145, 146, 147, 148, 149, 302, 154, 302, + /* 1970 */ 302, 94, 302, 36, 302, 302, 302, 100, 101, 302, + /* 1980 */ 302, 302, 302, 302, 107, 302, 109, 110, 111, 302, + /* 1990 */ 302, 114, 5, 302, 302, 302, 59, 10, 11, 12, + /* 2000 */ 13, 14, 302, 302, 17, 302, 302, 302, 71, 302, + /* 2010 */ 302, 302, 302, 302, 302, 302, 302, 30, 302, 32, + /* 2020 */ 302, 302, 145, 146, 147, 148, 149, 40, 302, 302, + /* 2030 */ 302, 94, 302, 302, 302, 302, 302, 100, 101, 302, + /* 2040 */ 302, 302, 302, 302, 107, 302, 109, 110, 111, 302, + /* 2050 */ 302, 114, 302, 302, 302, 302, 302, 70, 302, 302, + /* 2060 */ 302, 302, 302, 302, 302, 78, 302, 302, 81, 302, + /* 2070 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 92, + /* 2080 */ 302, 302, 145, 146, 147, 148, 149, 302, 302, 302, + /* 2090 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2100 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2110 */ 302, 302, 302, 126, 302, 302, 302, 302, 131, 132, + /* 2120 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2130 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2140 */ 302, 154, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2150 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, + /* 2160 */ 302, 302, 302, 302, 302, 302, 302, 302, 302, }; -#define YY_SHIFT_COUNT (523) +#define YY_SHIFT_COUNT (539) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (1858) +#define YY_SHIFT_MAX (1987) static const unsigned short int yy_shift_ofst[] = { - /* 0 */ 1709, 1520, 1858, 1324, 1324, 24, 1374, 1469, 1602, 1712, - /* 10 */ 1712, 1712, 271, 0, 0, 113, 1016, 1712, 1712, 1712, - /* 20 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 12, 12, 409, - /* 30 */ 596, 24, 24, 24, 24, 24, 24, 93, 177, 270, - /* 40 */ 363, 456, 549, 642, 735, 828, 848, 996, 1144, 1016, - /* 50 */ 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, - /* 60 */ 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1164, 1016, 1257, - /* 70 */ 1277, 1277, 1490, 1712, 1712, 1712, 1712, 1712, 1712, 1712, - /* 80 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, - /* 90 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, - /* 100 */ 1712, 1712, 1712, 1712, 1712, 1742, 1712, 1712, 1712, 1712, - /* 110 */ 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 143, - /* 120 */ 162, 162, 162, 162, 162, 204, 151, 186, 650, 690, - /* 130 */ 327, 650, 261, 261, 650, 722, 722, 722, 722, 373, - /* 140 */ 33, 2, 2009, 2009, 330, 330, 330, 346, 289, 278, - /* 150 */ 289, 289, 517, 517, 459, 510, 15, 799, 650, 650, - /* 160 */ 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, - /* 170 */ 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, - /* 180 */ 331, 365, 995, 995, 265, 365, 50, 1038, 2009, 2009, - /* 190 */ 2009, 433, 250, 250, 504, 314, 429, 518, 522, 526, - /* 200 */ 561, 650, 650, 650, 650, 650, 650, 650, 650, 650, - /* 210 */ 192, 650, 650, 650, 650, 650, 650, 650, 650, 650, - /* 220 */ 650, 650, 650, 641, 641, 641, 650, 650, 650, 650, - /* 230 */ 800, 650, 650, 650, 830, 650, 650, 782, 650, 650, - /* 240 */ 650, 650, 650, 650, 650, 650, 739, 902, 689, 895, - /* 250 */ 895, 895, 895, 736, 689, 689, 885, 445, 903, 1124, - /* 260 */ 945, 748, 748, 1066, 945, 945, 1066, 447, 1002, 293, - /* 270 */ 1195, 1195, 1195, 748, 740, 727, 460, 1157, 1348, 1282, - /* 280 */ 1282, 1378, 1378, 1282, 1279, 1315, 1402, 1383, 1294, 1419, - /* 290 */ 1419, 1419, 1419, 1282, 1428, 1294, 1294, 1315, 1402, 1383, - /* 300 */ 1383, 1294, 1282, 1428, 1314, 1400, 1282, 1428, 1453, 1282, - /* 310 */ 1428, 1282, 1428, 1453, 1386, 1386, 1386, 1431, 1453, 1386, - /* 320 */ 1381, 1386, 1431, 1386, 1386, 1453, 1399, 1399, 1453, 1369, - /* 330 */ 1403, 1369, 1403, 1369, 1403, 1369, 1403, 1282, 1404, 1452, - /* 340 */ 1521, 1407, 1404, 1524, 1282, 1416, 1407, 1432, 1434, 1294, - /* 350 */ 1546, 1547, 1569, 1569, 1577, 1577, 1577, 2009, 2009, 2009, - /* 360 */ 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, - /* 370 */ 2009, 2009, 2009, 591, 697, 1059, 1139, 1058, 797, 465, - /* 380 */ 1159, 1182, 1122, 1062, 1180, 936, 1199, 1201, 1205, 1224, - /* 390 */ 1225, 1244, 1061, 1145, 1261, 1161, 1194, 1249, 1251, 1256, - /* 400 */ 1137, 1142, 1263, 1264, 1214, 1207, 1613, 1623, 1605, 1477, - /* 410 */ 1614, 1541, 1620, 1616, 1617, 1509, 1502, 1525, 1619, 1514, - /* 420 */ 1626, 1516, 1634, 1650, 1522, 1512, 1535, 1594, 1621, 1517, - /* 430 */ 1604, 1606, 1607, 1609, 1544, 1559, 1631, 1536, 1666, 1663, - /* 440 */ 1647, 1567, 1523, 1608, 1648, 1610, 1600, 1636, 1549, 1576, - /* 450 */ 1657, 1662, 1664, 1565, 1572, 1665, 1624, 1668, 1671, 1672, - /* 460 */ 1674, 1627, 1660, 1675, 1633, 1667, 1678, 1564, 1681, 1553, - /* 470 */ 1690, 1692, 1691, 1693, 1696, 1700, 1702, 1705, 1704, 1599, - /* 480 */ 1707, 1710, 1630, 1703, 1714, 1618, 1716, 1706, 1716, 1717, - /* 490 */ 1653, 1677, 1670, 1711, 1731, 1732, 1733, 1734, 1723, 1735, - /* 500 */ 1716, 1740, 1743, 1744, 1745, 1739, 1746, 1748, 1761, 1751, - /* 510 */ 1752, 1753, 1754, 1758, 1759, 1749, 1658, 1654, 1655, 1656, - /* 520 */ 1659, 1765, 1776, 1791, + /* 0 */ 1814, 1632, 1987, 1426, 1426, 382, 1482, 1633, 1703, 1877, + /* 10 */ 1877, 1877, 85, 0, 0, 264, 1106, 1877, 1877, 1877, + /* 20 */ 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + /* 30 */ 226, 226, 380, 380, 294, 667, 382, 382, 382, 382, + /* 40 */ 382, 382, 97, 194, 332, 429, 526, 623, 720, 817, + /* 50 */ 914, 934, 1086, 1238, 1106, 1106, 1106, 1106, 1106, 1106, + /* 60 */ 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, 1106, + /* 70 */ 1106, 1106, 1258, 1106, 1355, 1375, 1375, 1817, 1877, 1877, + /* 80 */ 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + /* 90 */ 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + /* 100 */ 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + /* 110 */ 1937, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877, + /* 120 */ 1877, 1877, 1877, 1877, 32, 129, 129, 129, 129, 129, + /* 130 */ 171, 7, 17, 593, 676, 590, 593, 205, 205, 593, + /* 140 */ 318, 318, 318, 318, 50, 152, 51, 2142, 2142, 284, + /* 150 */ 284, 284, 65, 145, 282, 145, 145, 574, 574, 256, + /* 160 */ 348, 445, 782, 593, 593, 593, 593, 593, 593, 593, + /* 170 */ 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, + /* 180 */ 593, 593, 593, 593, 607, 607, 593, 721, 805, 805, + /* 190 */ 446, 851, 851, 446, 190, 979, 2142, 2142, 2142, 453, + /* 200 */ 45, 45, 480, 490, 484, 385, 575, 502, 551, 581, + /* 210 */ 593, 593, 593, 593, 593, 593, 593, 593, 593, 689, + /* 220 */ 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, + /* 230 */ 593, 593, 582, 582, 582, 593, 593, 593, 593, 771, + /* 240 */ 593, 593, 593, 59, 764, 593, 593, 863, 593, 593, + /* 250 */ 593, 593, 593, 593, 593, 593, 665, 819, 580, 16, + /* 260 */ 16, 16, 16, 1119, 580, 580, 967, 321, 931, 1042, + /* 270 */ 1077, 783, 783, 834, 1077, 1077, 834, 1121, 1195, 401, + /* 280 */ 1142, 1142, 1142, 783, 787, 787, 1074, 1191, 1092, 1205, + /* 290 */ 1354, 1284, 1284, 1381, 1381, 1284, 1297, 1334, 1421, 1407, + /* 300 */ 1322, 1447, 1447, 1447, 1447, 1284, 1452, 1322, 1322, 1334, + /* 310 */ 1421, 1407, 1407, 1322, 1284, 1452, 1345, 1434, 1284, 1452, + /* 320 */ 1483, 1284, 1452, 1284, 1452, 1483, 1404, 1404, 1404, 1451, + /* 330 */ 1483, 1404, 1400, 1404, 1451, 1404, 1404, 1483, 1419, 1419, + /* 340 */ 1483, 1406, 1436, 1406, 1436, 1406, 1436, 1406, 1436, 1284, + /* 350 */ 1457, 1457, 1408, 1414, 1534, 1284, 1412, 1408, 1425, 1431, + /* 360 */ 1322, 1555, 1559, 1574, 1574, 1588, 1588, 1588, 2142, 2142, + /* 370 */ 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, 2142, + /* 380 */ 2142, 2142, 2142, 378, 777, 836, 971, 825, 775, 983, + /* 390 */ 1208, 1179, 1217, 1120, 1220, 1206, 1221, 1222, 1226, 1227, + /* 400 */ 1228, 1233, 937, 1147, 1261, 1149, 1207, 1248, 1249, 1253, + /* 410 */ 1133, 1151, 1274, 1293, 1211, 1236, 1605, 1607, 1589, 1458, + /* 420 */ 1599, 1525, 1604, 1600, 1602, 1490, 1492, 1503, 1612, 1504, + /* 430 */ 1618, 1510, 1624, 1640, 1513, 1506, 1528, 1593, 1619, 1514, + /* 440 */ 1606, 1608, 1610, 1613, 1535, 1551, 1631, 1533, 1667, 1665, + /* 450 */ 1649, 1565, 1521, 1609, 1650, 1611, 1603, 1634, 1546, 1573, + /* 460 */ 1658, 1663, 1666, 1560, 1568, 1668, 1620, 1669, 1671, 1672, + /* 470 */ 1674, 1621, 1661, 1675, 1627, 1662, 1677, 1556, 1679, 1680, + /* 480 */ 1548, 1683, 1684, 1682, 1686, 1689, 1688, 1691, 1694, 1693, + /* 490 */ 1584, 1696, 1698, 1617, 1695, 1706, 1594, 1705, 1701, 1702, + /* 500 */ 1704, 1707, 1647, 1670, 1654, 1708, 1673, 1656, 1715, 1727, + /* 510 */ 1729, 1730, 1731, 1733, 1719, 1732, 1705, 1737, 1738, 1742, + /* 520 */ 1743, 1741, 1745, 1734, 1758, 1748, 1749, 1750, 1752, 1754, + /* 530 */ 1755, 1746, 1655, 1653, 1657, 1659, 1660, 1761, 1773, 1788, }; -#define YY_REDUCE_COUNT (372) -#define YY_REDUCE_MIN (-235) -#define YY_REDUCE_MAX (1441) +#define YY_REDUCE_COUNT (382) +#define YY_REDUCE_MIN (-260) +#define YY_REDUCE_MAX (1420) static const short yy_reduce_ofst[] = { - /* 0 */ -147, 171, 263, -96, 169, -144, -162, -149, -102, -156, - /* 10 */ -98, 216, 354, -170, -57, -235, 307, 149, 423, 428, - /* 20 */ 471, 313, 451, 519, 489, 496, 499, 545, 547, 555, - /* 30 */ -116, 540, 558, 592, 594, 597, 599, -206, -206, -206, - /* 40 */ -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, - /* 50 */ -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, - /* 60 */ -206, -206, -206, -206, -206, -206, -206, -206, -206, -206, - /* 70 */ -206, -206, 196, 309, 494, 537, 612, 656, 675, 679, - /* 80 */ 681, 685, 724, 753, 771, 776, 788, 790, 794, 796, - /* 90 */ 801, 803, 805, 807, 814, 819, 833, 837, 839, 842, - /* 100 */ 845, 847, 849, 853, 873, 891, 893, 917, 921, 937, - /* 110 */ 940, 944, 956, 960, 967, 969, 971, 973, 975, -206, - /* 120 */ -206, -206, -206, -206, -206, -206, -206, -206, 501, -168, - /* 130 */ 90, -97, 87, 112, 303, 277, 601, 277, 601, 179, - /* 140 */ -206, -206, -206, -206, -107, -107, -107, -43, -56, 323, - /* 150 */ 500, 512, -187, -177, 317, 609, 353, 353, 120, 144, - /* 160 */ 490, 539, 698, 374, 467, 507, 789, 404, -157, 755, - /* 170 */ 856, 916, 843, 941, 802, 770, 923, 821, 1001, -142, - /* 180 */ 264, 785, 896, 905, 899, 949, -176, 544, 911, 953, - /* 190 */ 1012, -182, -59, -30, 16, -22, 117, 172, 291, 369, - /* 200 */ 407, 415, 566, 586, 647, 699, 754, 813, 850, 892, - /* 210 */ 121, 1023, 1042, 1086, 1121, 1125, 1128, 1129, 1130, 1131, - /* 220 */ 1132, 1134, 1135, 284, 1106, 1123, 1152, 1154, 1155, 1156, - /* 230 */ 397, 1158, 1172, 1173, 1116, 1176, 1177, 1138, 1179, 117, - /* 240 */ 1184, 1185, 1198, 1200, 1202, 1203, 741, 1094, 1153, 1146, - /* 250 */ 1160, 1162, 1163, 397, 1153, 1153, 1170, 1204, 1206, 1103, - /* 260 */ 1168, 1165, 1166, 1133, 1174, 1175, 1140, 1210, 1193, 1208, - /* 270 */ 1212, 1215, 1216, 1178, 1167, 1189, 1196, 1241, 1148, 1243, - /* 280 */ 1245, 1181, 1183, 1247, 1188, 1187, 1190, 1227, 1223, 1234, - /* 290 */ 1236, 1238, 1239, 1274, 1278, 1235, 1237, 1213, 1218, 1253, - /* 300 */ 1254, 1246, 1287, 1289, 1209, 1219, 1303, 1305, 1293, 1306, - /* 310 */ 1309, 1313, 1316, 1297, 1301, 1307, 1308, 1298, 1310, 1311, - /* 320 */ 1312, 1317, 1304, 1318, 1320, 1319, 1265, 1267, 1325, 1295, - /* 330 */ 1300, 1296, 1302, 1326, 1321, 1327, 1330, 1365, 1323, 1269, - /* 340 */ 1272, 1328, 1331, 1322, 1388, 1334, 1336, 1349, 1353, 1357, - /* 350 */ 1405, 1409, 1420, 1421, 1427, 1429, 1430, 1332, 1335, 1339, - /* 360 */ 1418, 1422, 1423, 1424, 1425, 1433, 1426, 1435, 1436, 1437, - /* 370 */ 1438, 1441, 1439, + /* 0 */ -170, -18, -159, 309, 313, -167, -19, 75, 117, 211, + /* 10 */ 315, 317, -165, -195, -168, -260, 389, 437, 475, 524, + /* 20 */ 527, -169, 529, 531, -28, 80, 534, 239, 304, 412, + /* 30 */ 558, 577, 37, 120, 368, -22, 460, 517, 555, 560, + /* 40 */ 562, 586, -257, -257, -257, -257, -257, -257, -257, -257, + /* 50 */ -257, -257, -257, -257, -257, -257, -257, -257, -257, -257, + /* 60 */ -257, -257, -257, -257, -257, -257, -257, -257, -257, -257, + /* 70 */ -257, -257, -257, -257, -257, -257, -257, -172, 457, 628, + /* 80 */ 673, 692, 694, 702, 704, 722, 728, 740, 743, 748, + /* 90 */ 767, 791, 815, 818, 820, 822, 857, 861, 864, 866, + /* 100 */ 868, 870, 872, 874, 876, 881, 900, 902, 906, 908, + /* 110 */ 910, 912, 915, 917, 920, 960, 962, 964, 988, 990, + /* 120 */ 992, 1016, 1029, 1032, -257, -257, -257, -257, -257, -257, + /* 130 */ -257, -257, -257, 271, 618, -190, 68, 60, 240, -124, + /* 140 */ 603, 610, 603, 610, 12, -257, -257, -257, -257, -128, + /* 150 */ -128, -128, -142, 25, 270, 281, 333, 124, 236, 648, + /* 160 */ 374, 465, 465, 28, 598, 792, 839, 469, 38, 381, + /* 170 */ 622, 709, 173, 699, 522, 703, 808, 811, 867, 816, + /* 180 */ -104, 823, -3, 875, 649, 753, 323, -88, 882, 884, + /* 190 */ 518, 43, 325, 899, 763, 604, 879, 969, 402, -193, + /* 200 */ -189, -180, -151, -55, 69, 104, 141, 259, 286, 360, + /* 210 */ 364, 455, 474, 481, 510, 516, 611, 653, 788, 99, + /* 220 */ 871, 878, 995, 1009, 1049, 1081, 1115, 1134, 1136, 1138, + /* 230 */ 1139, 1140, 733, 1110, 1112, 1144, 1145, 1146, 1148, 1084, + /* 240 */ 1161, 1162, 1163, 1089, 1047, 1165, 1166, 1127, 1169, 104, + /* 250 */ 1181, 1182, 1183, 1184, 1185, 1187, 1098, 1100, 1150, 1131, + /* 260 */ 1132, 1135, 1141, 1084, 1150, 1150, 1152, 1173, 1196, 1097, + /* 270 */ 1153, 1143, 1167, 1103, 1154, 1155, 1104, 1176, 1174, 1199, + /* 280 */ 1178, 1186, 1188, 1168, 1158, 1160, 1170, 1159, 1201, 1230, + /* 290 */ 1156, 1243, 1244, 1157, 1164, 1247, 1172, 1189, 1192, 1240, + /* 300 */ 1231, 1241, 1242, 1256, 1257, 1278, 1294, 1251, 1252, 1232, + /* 310 */ 1234, 1265, 1266, 1259, 1301, 1303, 1223, 1225, 1307, 1313, + /* 320 */ 1295, 1317, 1319, 1320, 1323, 1299, 1306, 1308, 1309, 1305, + /* 330 */ 1311, 1315, 1314, 1321, 1312, 1324, 1326, 1327, 1263, 1271, + /* 340 */ 1331, 1296, 1298, 1300, 1302, 1304, 1310, 1316, 1318, 1357, + /* 350 */ 1255, 1260, 1329, 1325, 1332, 1370, 1333, 1338, 1341, 1343, + /* 360 */ 1346, 1390, 1393, 1403, 1405, 1416, 1417, 1418, 1328, 1330, + /* 370 */ 1335, 1409, 1394, 1399, 1401, 1402, 1410, 1391, 1396, 1411, + /* 380 */ 1420, 1413, 1415, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1500, 1500, 1500, 1346, 1129, 1235, 1129, 1129, 1129, 1346, - /* 10 */ 1346, 1346, 1129, 1265, 1265, 1399, 1160, 1129, 1129, 1129, - /* 20 */ 1129, 1129, 1129, 1129, 1345, 1129, 1129, 1129, 1129, 1129, - /* 30 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1271, 1129, - /* 40 */ 1129, 1129, 1129, 1129, 1347, 1348, 1129, 1129, 1129, 1398, - /* 50 */ 1400, 1363, 1281, 1280, 1279, 1278, 1381, 1252, 1276, 1269, - /* 60 */ 1273, 1341, 1342, 1340, 1344, 1348, 1347, 1129, 1272, 1312, - /* 70 */ 1326, 1311, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 80 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 90 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 100 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 110 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1320, - /* 120 */ 1325, 1331, 1324, 1321, 1314, 1313, 1315, 1316, 1129, 1150, - /* 130 */ 1199, 1129, 1129, 1129, 1129, 1417, 1416, 1129, 1129, 1160, - /* 140 */ 1317, 1318, 1328, 1327, 1406, 1456, 1455, 1364, 1129, 1129, - /* 150 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 160 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 170 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 180 */ 1160, 1156, 1306, 1305, 1426, 1156, 1259, 1129, 1412, 1235, - /* 190 */ 1226, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 200 */ 1129, 1129, 1129, 1129, 1403, 1401, 1129, 1129, 1129, 1129, - /* 210 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 220 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 230 */ 1129, 1129, 1129, 1129, 1231, 1129, 1129, 1129, 1129, 1129, - /* 240 */ 1129, 1129, 1129, 1129, 1129, 1450, 1129, 1376, 1213, 1231, - /* 250 */ 1231, 1231, 1231, 1233, 1214, 1212, 1225, 1160, 1136, 1492, - /* 260 */ 1275, 1254, 1254, 1489, 1275, 1275, 1489, 1174, 1470, 1171, - /* 270 */ 1265, 1265, 1265, 1254, 1343, 1232, 1225, 1129, 1492, 1240, - /* 280 */ 1240, 1491, 1491, 1240, 1364, 1284, 1290, 1202, 1275, 1208, - /* 290 */ 1208, 1208, 1208, 1240, 1147, 1275, 1275, 1284, 1290, 1202, - /* 300 */ 1202, 1275, 1240, 1147, 1380, 1486, 1240, 1147, 1354, 1240, - /* 310 */ 1147, 1240, 1147, 1354, 1200, 1200, 1200, 1189, 1354, 1200, - /* 320 */ 1174, 1200, 1189, 1200, 1200, 1354, 1358, 1358, 1354, 1258, - /* 330 */ 1253, 1258, 1253, 1258, 1253, 1258, 1253, 1240, 1259, 1425, - /* 340 */ 1129, 1270, 1259, 1349, 1240, 1129, 1270, 1268, 1266, 1275, - /* 350 */ 1153, 1192, 1453, 1453, 1449, 1449, 1449, 1497, 1497, 1412, - /* 360 */ 1465, 1160, 1160, 1160, 1160, 1465, 1176, 1176, 1160, 1160, - /* 370 */ 1160, 1160, 1465, 1129, 1129, 1129, 1129, 1129, 1129, 1460, - /* 380 */ 1129, 1365, 1244, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 390 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 400 */ 1129, 1129, 1129, 1129, 1129, 1295, 1129, 1132, 1409, 1129, - /* 410 */ 1129, 1407, 1129, 1129, 1129, 1129, 1129, 1129, 1245, 1129, - /* 420 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 430 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1488, 1129, 1129, - /* 440 */ 1129, 1129, 1129, 1129, 1379, 1378, 1129, 1129, 1242, 1129, - /* 450 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 460 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 470 */ 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 480 */ 1129, 1129, 1129, 1129, 1129, 1129, 1267, 1129, 1424, 1129, - /* 490 */ 1129, 1129, 1129, 1129, 1129, 1129, 1438, 1260, 1129, 1129, - /* 500 */ 1479, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1129, - /* 510 */ 1129, 1129, 1129, 1129, 1129, 1474, 1216, 1297, 1129, 1296, - /* 520 */ 1300, 1129, 1141, 1129, + /* 0 */ 1537, 1537, 1537, 1377, 1159, 1266, 1159, 1159, 1159, 1377, + /* 10 */ 1377, 1377, 1159, 1296, 1296, 1430, 1190, 1159, 1159, 1159, + /* 20 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1376, 1159, 1159, + /* 30 */ 1159, 1159, 1460, 1460, 1159, 1159, 1159, 1159, 1159, 1159, + /* 40 */ 1159, 1159, 1159, 1302, 1159, 1159, 1159, 1159, 1159, 1378, + /* 50 */ 1379, 1159, 1159, 1159, 1429, 1431, 1394, 1312, 1311, 1310, + /* 60 */ 1309, 1412, 1283, 1307, 1300, 1304, 1372, 1373, 1371, 1375, + /* 70 */ 1379, 1378, 1159, 1303, 1343, 1357, 1342, 1159, 1159, 1159, + /* 80 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 90 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 100 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 110 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 120 */ 1159, 1159, 1159, 1159, 1351, 1356, 1362, 1355, 1352, 1345, + /* 130 */ 1344, 1346, 1347, 1159, 1180, 1230, 1159, 1159, 1159, 1159, + /* 140 */ 1448, 1447, 1159, 1159, 1190, 1348, 1349, 1359, 1358, 1437, + /* 150 */ 1493, 1492, 1395, 1159, 1159, 1159, 1159, 1159, 1159, 1460, + /* 160 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 170 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 180 */ 1159, 1159, 1159, 1159, 1460, 1460, 1159, 1190, 1460, 1460, + /* 190 */ 1186, 1337, 1336, 1186, 1290, 1159, 1443, 1266, 1257, 1159, + /* 200 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 210 */ 1159, 1159, 1159, 1434, 1432, 1159, 1159, 1159, 1159, 1159, + /* 220 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 230 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 240 */ 1159, 1159, 1159, 1262, 1159, 1159, 1159, 1159, 1159, 1159, + /* 250 */ 1159, 1159, 1159, 1159, 1159, 1487, 1159, 1407, 1244, 1262, + /* 260 */ 1262, 1262, 1262, 1264, 1245, 1243, 1256, 1191, 1166, 1529, + /* 270 */ 1306, 1285, 1285, 1526, 1306, 1306, 1526, 1205, 1507, 1202, + /* 280 */ 1296, 1296, 1296, 1285, 1290, 1290, 1374, 1263, 1256, 1159, + /* 290 */ 1529, 1271, 1271, 1528, 1528, 1271, 1395, 1315, 1321, 1233, + /* 300 */ 1306, 1239, 1239, 1239, 1239, 1271, 1177, 1306, 1306, 1315, + /* 310 */ 1321, 1233, 1233, 1306, 1271, 1177, 1411, 1523, 1271, 1177, + /* 320 */ 1385, 1271, 1177, 1271, 1177, 1385, 1231, 1231, 1231, 1220, + /* 330 */ 1385, 1231, 1205, 1231, 1220, 1231, 1231, 1385, 1389, 1389, + /* 340 */ 1385, 1289, 1284, 1289, 1284, 1289, 1284, 1289, 1284, 1271, + /* 350 */ 1470, 1470, 1301, 1290, 1380, 1271, 1159, 1301, 1299, 1297, + /* 360 */ 1306, 1183, 1223, 1490, 1490, 1486, 1486, 1486, 1534, 1534, + /* 370 */ 1443, 1502, 1190, 1190, 1190, 1190, 1502, 1207, 1207, 1191, + /* 380 */ 1191, 1190, 1502, 1159, 1159, 1159, 1159, 1159, 1159, 1497, + /* 390 */ 1159, 1396, 1275, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 400 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 410 */ 1159, 1159, 1159, 1159, 1159, 1326, 1159, 1162, 1440, 1159, + /* 420 */ 1159, 1438, 1159, 1159, 1159, 1159, 1159, 1159, 1276, 1159, + /* 430 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 440 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1525, 1159, 1159, + /* 450 */ 1159, 1159, 1159, 1159, 1410, 1409, 1159, 1159, 1273, 1159, + /* 460 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 470 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 480 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 490 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1298, 1159, 1159, + /* 500 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 510 */ 1159, 1159, 1475, 1291, 1159, 1159, 1516, 1159, 1159, 1159, + /* 520 */ 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, 1159, + /* 530 */ 1159, 1511, 1247, 1328, 1159, 1327, 1331, 1159, 1171, 1159, }; /********** End of lemon-generated parsing tables *****************************/ @@ -148334,6 +149757,10 @@ static const YYCODETYPE yyFallback[] = { 59, /* PRECEDING => ID */ 59, /* RANGE => ID */ 59, /* UNBOUNDED => ID */ + 59, /* EXCLUDE => ID */ + 59, /* GROUPS => ID */ + 59, /* OTHERS => ID */ + 59, /* TIES => ID */ 59, /* REINDEX => ID */ 59, /* RENAME => ID */ 59, /* CTIME_KW => ID */ @@ -148512,196 +149939,220 @@ static const char *const yyTokenName[] = { /* 85 */ "PRECEDING", /* 86 */ "RANGE", /* 87 */ "UNBOUNDED", - /* 88 */ "REINDEX", - /* 89 */ "RENAME", - /* 90 */ "CTIME_KW", - /* 91 */ "ANY", - /* 92 */ "BITAND", - /* 93 */ "BITOR", - /* 94 */ "LSHIFT", - /* 95 */ "RSHIFT", - /* 96 */ "PLUS", - /* 97 */ "MINUS", - /* 98 */ "STAR", - /* 99 */ "SLASH", - /* 100 */ "REM", - /* 101 */ "CONCAT", - /* 102 */ "COLLATE", - /* 103 */ "BITNOT", - /* 104 */ "ON", - /* 105 */ "INDEXED", - /* 106 */ "STRING", - /* 107 */ "JOIN_KW", - /* 108 */ "CONSTRAINT", - /* 109 */ "DEFAULT", - /* 110 */ "NULL", - /* 111 */ "PRIMARY", - /* 112 */ "UNIQUE", - /* 113 */ "CHECK", - /* 114 */ "REFERENCES", - /* 115 */ "AUTOINCR", - /* 116 */ "INSERT", - /* 117 */ "DELETE", - /* 118 */ "UPDATE", - /* 119 */ "SET", - /* 120 */ "DEFERRABLE", - /* 121 */ "FOREIGN", - /* 122 */ "DROP", - /* 123 */ "UNION", - /* 124 */ "ALL", - /* 125 */ "EXCEPT", - /* 126 */ "INTERSECT", - /* 127 */ "SELECT", - /* 128 */ "VALUES", - /* 129 */ "DISTINCT", - /* 130 */ "DOT", - /* 131 */ "FROM", - /* 132 */ "JOIN", - /* 133 */ "USING", - /* 134 */ "ORDER", - /* 135 */ "GROUP", - /* 136 */ "HAVING", - /* 137 */ "LIMIT", - /* 138 */ "WHERE", - /* 139 */ "INTO", - /* 140 */ "NOTHING", - /* 141 */ "FLOAT", - /* 142 */ "BLOB", - /* 143 */ "INTEGER", - /* 144 */ "VARIABLE", - /* 145 */ "CASE", - /* 146 */ "WHEN", - /* 147 */ "THEN", - /* 148 */ "ELSE", - /* 149 */ "INDEX", - /* 150 */ "ALTER", - /* 151 */ "ADD", - /* 152 */ "WINDOW", - /* 153 */ "OVER", - /* 154 */ "FILTER", - /* 155 */ "input", - /* 156 */ "cmdlist", - /* 157 */ "ecmd", - /* 158 */ "cmdx", - /* 159 */ "explain", - /* 160 */ "cmd", - /* 161 */ "transtype", - /* 162 */ "trans_opt", - /* 163 */ "nm", - /* 164 */ "savepoint_opt", - /* 165 */ "create_table", - /* 166 */ "create_table_args", - /* 167 */ "createkw", - /* 168 */ "temp", - /* 169 */ "ifnotexists", - /* 170 */ "dbnm", - /* 171 */ "columnlist", - /* 172 */ "conslist_opt", - /* 173 */ "table_options", - /* 174 */ "select", - /* 175 */ "columnname", - /* 176 */ "carglist", - /* 177 */ "typetoken", - /* 178 */ "typename", - /* 179 */ "signed", - /* 180 */ "plus_num", - /* 181 */ "minus_num", - /* 182 */ "scanpt", - /* 183 */ "ccons", - /* 184 */ "term", - /* 185 */ "expr", - /* 186 */ "onconf", - /* 187 */ "sortorder", - /* 188 */ "autoinc", - /* 189 */ "eidlist_opt", - /* 190 */ "refargs", - /* 191 */ "defer_subclause", - /* 192 */ "refarg", - /* 193 */ "refact", - /* 194 */ "init_deferred_pred_opt", - /* 195 */ "conslist", - /* 196 */ "tconscomma", - /* 197 */ "tcons", - /* 198 */ "sortlist", - /* 199 */ "eidlist", - /* 200 */ "defer_subclause_opt", - /* 201 */ "orconf", - /* 202 */ "resolvetype", - /* 203 */ "raisetype", - /* 204 */ "ifexists", - /* 205 */ "fullname", - /* 206 */ "selectnowith", - /* 207 */ "oneselect", - /* 208 */ "wqlist", - /* 209 */ "multiselect_op", - /* 210 */ "distinct", - /* 211 */ "selcollist", - /* 212 */ "from", - /* 213 */ "where_opt", - /* 214 */ "groupby_opt", - /* 215 */ "having_opt", - /* 216 */ "orderby_opt", - /* 217 */ "limit_opt", - /* 218 */ "window_clause", - /* 219 */ "values", - /* 220 */ "nexprlist", - /* 221 */ "sclp", - /* 222 */ "as", - /* 223 */ "seltablist", - /* 224 */ "stl_prefix", - /* 225 */ "joinop", - /* 226 */ "indexed_opt", - /* 227 */ "on_opt", - /* 228 */ "using_opt", - /* 229 */ "exprlist", - /* 230 */ "xfullname", - /* 231 */ "idlist", - /* 232 */ "with", - /* 233 */ "setlist", - /* 234 */ "insert_cmd", - /* 235 */ "idlist_opt", - /* 236 */ "upsert", - /* 237 */ "over_clause", - /* 238 */ "likeop", - /* 239 */ "between_op", - /* 240 */ "in_op", - /* 241 */ "paren_exprlist", - /* 242 */ "case_operand", - /* 243 */ "case_exprlist", - /* 244 */ "case_else", - /* 245 */ "uniqueflag", - /* 246 */ "collate", - /* 247 */ "vinto", - /* 248 */ "nmnum", - /* 249 */ "trigger_decl", - /* 250 */ "trigger_cmd_list", - /* 251 */ "trigger_time", - /* 252 */ "trigger_event", - /* 253 */ "foreach_clause", - /* 254 */ "when_clause", - /* 255 */ "trigger_cmd", - /* 256 */ "trnm", - /* 257 */ "tridxby", - /* 258 */ "database_kw_opt", - /* 259 */ "key_opt", - /* 260 */ "add_column_fullname", - /* 261 */ "kwcolumn_opt", - /* 262 */ "create_vtab", - /* 263 */ "vtabarglist", - /* 264 */ "vtabarg", - /* 265 */ "vtabargtoken", - /* 266 */ "lp", - /* 267 */ "anylist", - /* 268 */ "windowdefn_list", - /* 269 */ "windowdefn", - /* 270 */ "window", - /* 271 */ "frame_opt", - /* 272 */ "part_opt", - /* 273 */ "filter_opt", - /* 274 */ "range_or_rows", - /* 275 */ "frame_bound", - /* 276 */ "frame_bound_s", - /* 277 */ "frame_bound_e", + /* 88 */ "EXCLUDE", + /* 89 */ "GROUPS", + /* 90 */ "OTHERS", + /* 91 */ "TIES", + /* 92 */ "REINDEX", + /* 93 */ "RENAME", + /* 94 */ "CTIME_KW", + /* 95 */ "ANY", + /* 96 */ "BITAND", + /* 97 */ "BITOR", + /* 98 */ "LSHIFT", + /* 99 */ "RSHIFT", + /* 100 */ "PLUS", + /* 101 */ "MINUS", + /* 102 */ "STAR", + /* 103 */ "SLASH", + /* 104 */ "REM", + /* 105 */ "CONCAT", + /* 106 */ "COLLATE", + /* 107 */ "BITNOT", + /* 108 */ "ON", + /* 109 */ "INDEXED", + /* 110 */ "STRING", + /* 111 */ "JOIN_KW", + /* 112 */ "CONSTRAINT", + /* 113 */ "DEFAULT", + /* 114 */ "NULL", + /* 115 */ "PRIMARY", + /* 116 */ "UNIQUE", + /* 117 */ "CHECK", + /* 118 */ "REFERENCES", + /* 119 */ "AUTOINCR", + /* 120 */ "INSERT", + /* 121 */ "DELETE", + /* 122 */ "UPDATE", + /* 123 */ "SET", + /* 124 */ "DEFERRABLE", + /* 125 */ "FOREIGN", + /* 126 */ "DROP", + /* 127 */ "UNION", + /* 128 */ "ALL", + /* 129 */ "EXCEPT", + /* 130 */ "INTERSECT", + /* 131 */ "SELECT", + /* 132 */ "VALUES", + /* 133 */ "DISTINCT", + /* 134 */ "DOT", + /* 135 */ "FROM", + /* 136 */ "JOIN", + /* 137 */ "USING", + /* 138 */ "ORDER", + /* 139 */ "GROUP", + /* 140 */ "HAVING", + /* 141 */ "LIMIT", + /* 142 */ "WHERE", + /* 143 */ "INTO", + /* 144 */ "NOTHING", + /* 145 */ "FLOAT", + /* 146 */ "BLOB", + /* 147 */ "INTEGER", + /* 148 */ "VARIABLE", + /* 149 */ "CASE", + /* 150 */ "WHEN", + /* 151 */ "THEN", + /* 152 */ "ELSE", + /* 153 */ "INDEX", + /* 154 */ "ALTER", + /* 155 */ "ADD", + /* 156 */ "WINDOW", + /* 157 */ "OVER", + /* 158 */ "FILTER", + /* 159 */ "TRUEFALSE", + /* 160 */ "ISNOT", + /* 161 */ "FUNCTION", + /* 162 */ "COLUMN", + /* 163 */ "AGG_FUNCTION", + /* 164 */ "AGG_COLUMN", + /* 165 */ "UMINUS", + /* 166 */ "UPLUS", + /* 167 */ "TRUTH", + /* 168 */ "REGISTER", + /* 169 */ "VECTOR", + /* 170 */ "SELECT_COLUMN", + /* 171 */ "IF_NULL_ROW", + /* 172 */ "ASTERISK", + /* 173 */ "SPAN", + /* 174 */ "SPACE", + /* 175 */ "ILLEGAL", + /* 176 */ "input", + /* 177 */ "cmdlist", + /* 178 */ "ecmd", + /* 179 */ "cmdx", + /* 180 */ "explain", + /* 181 */ "cmd", + /* 182 */ "transtype", + /* 183 */ "trans_opt", + /* 184 */ "nm", + /* 185 */ "savepoint_opt", + /* 186 */ "create_table", + /* 187 */ "create_table_args", + /* 188 */ "createkw", + /* 189 */ "temp", + /* 190 */ "ifnotexists", + /* 191 */ "dbnm", + /* 192 */ "columnlist", + /* 193 */ "conslist_opt", + /* 194 */ "table_options", + /* 195 */ "select", + /* 196 */ "columnname", + /* 197 */ "carglist", + /* 198 */ "typetoken", + /* 199 */ "typename", + /* 200 */ "signed", + /* 201 */ "plus_num", + /* 202 */ "minus_num", + /* 203 */ "scanpt", + /* 204 */ "scantok", + /* 205 */ "ccons", + /* 206 */ "term", + /* 207 */ "expr", + /* 208 */ "onconf", + /* 209 */ "sortorder", + /* 210 */ "autoinc", + /* 211 */ "eidlist_opt", + /* 212 */ "refargs", + /* 213 */ "defer_subclause", + /* 214 */ "refarg", + /* 215 */ "refact", + /* 216 */ "init_deferred_pred_opt", + /* 217 */ "conslist", + /* 218 */ "tconscomma", + /* 219 */ "tcons", + /* 220 */ "sortlist", + /* 221 */ "eidlist", + /* 222 */ "defer_subclause_opt", + /* 223 */ "orconf", + /* 224 */ "resolvetype", + /* 225 */ "raisetype", + /* 226 */ "ifexists", + /* 227 */ "fullname", + /* 228 */ "selectnowith", + /* 229 */ "oneselect", + /* 230 */ "wqlist", + /* 231 */ "multiselect_op", + /* 232 */ "distinct", + /* 233 */ "selcollist", + /* 234 */ "from", + /* 235 */ "where_opt", + /* 236 */ "groupby_opt", + /* 237 */ "having_opt", + /* 238 */ "orderby_opt", + /* 239 */ "limit_opt", + /* 240 */ "window_clause", + /* 241 */ "values", + /* 242 */ "nexprlist", + /* 243 */ "sclp", + /* 244 */ "as", + /* 245 */ "seltablist", + /* 246 */ "stl_prefix", + /* 247 */ "joinop", + /* 248 */ "indexed_opt", + /* 249 */ "on_opt", + /* 250 */ "using_opt", + /* 251 */ "exprlist", + /* 252 */ "xfullname", + /* 253 */ "idlist", + /* 254 */ "with", + /* 255 */ "setlist", + /* 256 */ "insert_cmd", + /* 257 */ "idlist_opt", + /* 258 */ "upsert", + /* 259 */ "over_clause", + /* 260 */ "likeop", + /* 261 */ "between_op", + /* 262 */ "in_op", + /* 263 */ "paren_exprlist", + /* 264 */ "case_operand", + /* 265 */ "case_exprlist", + /* 266 */ "case_else", + /* 267 */ "uniqueflag", + /* 268 */ "collate", + /* 269 */ "vinto", + /* 270 */ "nmnum", + /* 271 */ "trigger_decl", + /* 272 */ "trigger_cmd_list", + /* 273 */ "trigger_time", + /* 274 */ "trigger_event", + /* 275 */ "foreach_clause", + /* 276 */ "when_clause", + /* 277 */ "trigger_cmd", + /* 278 */ "trnm", + /* 279 */ "tridxby", + /* 280 */ "database_kw_opt", + /* 281 */ "key_opt", + /* 282 */ "add_column_fullname", + /* 283 */ "kwcolumn_opt", + /* 284 */ "create_vtab", + /* 285 */ "vtabarglist", + /* 286 */ "vtabarg", + /* 287 */ "vtabargtoken", + /* 288 */ "lp", + /* 289 */ "anylist", + /* 290 */ "windowdefn_list", + /* 291 */ "windowdefn", + /* 292 */ "window", + /* 293 */ "frame_opt", + /* 294 */ "part_opt", + /* 295 */ "filter_opt", + /* 296 */ "range_or_rows", + /* 297 */ "frame_bound", + /* 298 */ "frame_bound_s", + /* 299 */ "frame_bound_e", + /* 300 */ "frame_exclude_opt", + /* 301 */ "frame_exclude", }; #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ @@ -148738,346 +150189,353 @@ static const char *const yyRuleName[] = { /* 26 */ "typetoken ::= typename LP signed COMMA signed RP", /* 27 */ "typename ::= typename ID|STRING", /* 28 */ "scanpt ::=", - /* 29 */ "ccons ::= CONSTRAINT nm", - /* 30 */ "ccons ::= DEFAULT scanpt term scanpt", - /* 31 */ "ccons ::= DEFAULT LP expr RP", - /* 32 */ "ccons ::= DEFAULT PLUS term scanpt", - /* 33 */ "ccons ::= DEFAULT MINUS term scanpt", - /* 34 */ "ccons ::= DEFAULT scanpt ID|INDEXED", - /* 35 */ "ccons ::= NOT NULL onconf", - /* 36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", - /* 37 */ "ccons ::= UNIQUE onconf", - /* 38 */ "ccons ::= CHECK LP expr RP", - /* 39 */ "ccons ::= REFERENCES nm eidlist_opt refargs", - /* 40 */ "ccons ::= defer_subclause", - /* 41 */ "ccons ::= COLLATE ID|STRING", - /* 42 */ "autoinc ::=", - /* 43 */ "autoinc ::= AUTOINCR", - /* 44 */ "refargs ::=", - /* 45 */ "refargs ::= refargs refarg", - /* 46 */ "refarg ::= MATCH nm", - /* 47 */ "refarg ::= ON INSERT refact", - /* 48 */ "refarg ::= ON DELETE refact", - /* 49 */ "refarg ::= ON UPDATE refact", - /* 50 */ "refact ::= SET NULL", - /* 51 */ "refact ::= SET DEFAULT", - /* 52 */ "refact ::= CASCADE", - /* 53 */ "refact ::= RESTRICT", - /* 54 */ "refact ::= NO ACTION", - /* 55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", - /* 56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", - /* 57 */ "init_deferred_pred_opt ::=", - /* 58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", - /* 59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", - /* 60 */ "conslist_opt ::=", - /* 61 */ "tconscomma ::= COMMA", - /* 62 */ "tcons ::= CONSTRAINT nm", - /* 63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", - /* 64 */ "tcons ::= UNIQUE LP sortlist RP onconf", - /* 65 */ "tcons ::= CHECK LP expr RP onconf", - /* 66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", - /* 67 */ "defer_subclause_opt ::=", - /* 68 */ "onconf ::=", - /* 69 */ "onconf ::= ON CONFLICT resolvetype", - /* 70 */ "orconf ::=", - /* 71 */ "orconf ::= OR resolvetype", - /* 72 */ "resolvetype ::= IGNORE", - /* 73 */ "resolvetype ::= REPLACE", - /* 74 */ "cmd ::= DROP TABLE ifexists fullname", - /* 75 */ "ifexists ::= IF EXISTS", - /* 76 */ "ifexists ::=", - /* 77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", - /* 78 */ "cmd ::= DROP VIEW ifexists fullname", - /* 79 */ "cmd ::= select", - /* 80 */ "select ::= WITH wqlist selectnowith", - /* 81 */ "select ::= WITH RECURSIVE wqlist selectnowith", - /* 82 */ "select ::= selectnowith", - /* 83 */ "selectnowith ::= selectnowith multiselect_op oneselect", - /* 84 */ "multiselect_op ::= UNION", - /* 85 */ "multiselect_op ::= UNION ALL", - /* 86 */ "multiselect_op ::= EXCEPT|INTERSECT", - /* 87 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 88 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", - /* 89 */ "values ::= VALUES LP nexprlist RP", - /* 90 */ "values ::= values COMMA LP nexprlist RP", - /* 91 */ "distinct ::= DISTINCT", - /* 92 */ "distinct ::= ALL", - /* 93 */ "distinct ::=", - /* 94 */ "sclp ::=", - /* 95 */ "selcollist ::= sclp scanpt expr scanpt as", - /* 96 */ "selcollist ::= sclp scanpt STAR", - /* 97 */ "selcollist ::= sclp scanpt nm DOT STAR", - /* 98 */ "as ::= AS nm", - /* 99 */ "as ::=", - /* 100 */ "from ::=", - /* 101 */ "from ::= FROM seltablist", - /* 102 */ "stl_prefix ::= seltablist joinop", - /* 103 */ "stl_prefix ::=", - /* 104 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", - /* 105 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", - /* 106 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", - /* 107 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", - /* 108 */ "dbnm ::=", - /* 109 */ "dbnm ::= DOT nm", - /* 110 */ "fullname ::= nm", - /* 111 */ "fullname ::= nm DOT nm", - /* 112 */ "xfullname ::= nm", - /* 113 */ "xfullname ::= nm DOT nm", - /* 114 */ "xfullname ::= nm DOT nm AS nm", - /* 115 */ "xfullname ::= nm AS nm", - /* 116 */ "joinop ::= COMMA|JOIN", - /* 117 */ "joinop ::= JOIN_KW JOIN", - /* 118 */ "joinop ::= JOIN_KW nm JOIN", - /* 119 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 120 */ "on_opt ::= ON expr", - /* 121 */ "on_opt ::=", - /* 122 */ "indexed_opt ::=", - /* 123 */ "indexed_opt ::= INDEXED BY nm", - /* 124 */ "indexed_opt ::= NOT INDEXED", - /* 125 */ "using_opt ::= USING LP idlist RP", - /* 126 */ "using_opt ::=", - /* 127 */ "orderby_opt ::=", - /* 128 */ "orderby_opt ::= ORDER BY sortlist", - /* 129 */ "sortlist ::= sortlist COMMA expr sortorder", - /* 130 */ "sortlist ::= expr sortorder", - /* 131 */ "sortorder ::= ASC", - /* 132 */ "sortorder ::= DESC", - /* 133 */ "sortorder ::=", - /* 134 */ "groupby_opt ::=", - /* 135 */ "groupby_opt ::= GROUP BY nexprlist", - /* 136 */ "having_opt ::=", - /* 137 */ "having_opt ::= HAVING expr", - /* 138 */ "limit_opt ::=", - /* 139 */ "limit_opt ::= LIMIT expr", - /* 140 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 141 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 142 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt", - /* 143 */ "where_opt ::=", - /* 144 */ "where_opt ::= WHERE expr", - /* 145 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt", - /* 146 */ "setlist ::= setlist COMMA nm EQ expr", - /* 147 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", - /* 148 */ "setlist ::= nm EQ expr", - /* 149 */ "setlist ::= LP idlist RP EQ expr", - /* 150 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", - /* 151 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES", - /* 152 */ "upsert ::=", - /* 153 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt", - /* 154 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING", - /* 155 */ "upsert ::= ON CONFLICT DO NOTHING", - /* 156 */ "insert_cmd ::= INSERT orconf", - /* 157 */ "insert_cmd ::= REPLACE", - /* 158 */ "idlist_opt ::=", - /* 159 */ "idlist_opt ::= LP idlist RP", - /* 160 */ "idlist ::= idlist COMMA nm", - /* 161 */ "idlist ::= nm", - /* 162 */ "expr ::= LP expr RP", - /* 163 */ "expr ::= ID|INDEXED", - /* 164 */ "expr ::= JOIN_KW", - /* 165 */ "expr ::= nm DOT nm", - /* 166 */ "expr ::= nm DOT nm DOT nm", - /* 167 */ "term ::= NULL|FLOAT|BLOB", - /* 168 */ "term ::= STRING", - /* 169 */ "term ::= INTEGER", - /* 170 */ "expr ::= VARIABLE", - /* 171 */ "expr ::= expr COLLATE ID|STRING", - /* 172 */ "expr ::= CAST LP expr AS typetoken RP", - /* 173 */ "expr ::= ID|INDEXED LP distinct exprlist RP", - /* 174 */ "expr ::= ID|INDEXED LP STAR RP", - /* 175 */ "expr ::= ID|INDEXED LP distinct exprlist RP over_clause", - /* 176 */ "expr ::= ID|INDEXED LP STAR RP over_clause", - /* 177 */ "term ::= CTIME_KW", - /* 178 */ "expr ::= LP nexprlist COMMA expr RP", - /* 179 */ "expr ::= expr AND expr", - /* 180 */ "expr ::= expr OR expr", - /* 181 */ "expr ::= expr LT|GT|GE|LE expr", - /* 182 */ "expr ::= expr EQ|NE expr", - /* 183 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", - /* 184 */ "expr ::= expr PLUS|MINUS expr", - /* 185 */ "expr ::= expr STAR|SLASH|REM expr", - /* 186 */ "expr ::= expr CONCAT expr", - /* 187 */ "likeop ::= NOT LIKE_KW|MATCH", - /* 188 */ "expr ::= expr likeop expr", - /* 189 */ "expr ::= expr likeop expr ESCAPE expr", - /* 190 */ "expr ::= expr ISNULL|NOTNULL", - /* 191 */ "expr ::= expr NOT NULL", - /* 192 */ "expr ::= expr IS expr", - /* 193 */ "expr ::= expr IS NOT expr", - /* 194 */ "expr ::= NOT expr", - /* 195 */ "expr ::= BITNOT expr", - /* 196 */ "expr ::= PLUS|MINUS expr", - /* 197 */ "between_op ::= BETWEEN", - /* 198 */ "between_op ::= NOT BETWEEN", - /* 199 */ "expr ::= expr between_op expr AND expr", - /* 200 */ "in_op ::= IN", - /* 201 */ "in_op ::= NOT IN", - /* 202 */ "expr ::= expr in_op LP exprlist RP", - /* 203 */ "expr ::= LP select RP", - /* 204 */ "expr ::= expr in_op LP select RP", - /* 205 */ "expr ::= expr in_op nm dbnm paren_exprlist", - /* 206 */ "expr ::= EXISTS LP select RP", - /* 207 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 208 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 209 */ "case_exprlist ::= WHEN expr THEN expr", - /* 210 */ "case_else ::= ELSE expr", - /* 211 */ "case_else ::=", - /* 212 */ "case_operand ::= expr", - /* 213 */ "case_operand ::=", - /* 214 */ "exprlist ::=", - /* 215 */ "nexprlist ::= nexprlist COMMA expr", - /* 216 */ "nexprlist ::= expr", - /* 217 */ "paren_exprlist ::=", - /* 218 */ "paren_exprlist ::= LP exprlist RP", - /* 219 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", - /* 220 */ "uniqueflag ::= UNIQUE", - /* 221 */ "uniqueflag ::=", - /* 222 */ "eidlist_opt ::=", - /* 223 */ "eidlist_opt ::= LP eidlist RP", - /* 224 */ "eidlist ::= eidlist COMMA nm collate sortorder", - /* 225 */ "eidlist ::= nm collate sortorder", - /* 226 */ "collate ::=", - /* 227 */ "collate ::= COLLATE ID|STRING", - /* 228 */ "cmd ::= DROP INDEX ifexists fullname", - /* 229 */ "cmd ::= VACUUM vinto", - /* 230 */ "cmd ::= VACUUM nm vinto", - /* 231 */ "vinto ::= INTO expr", - /* 232 */ "vinto ::=", - /* 233 */ "cmd ::= PRAGMA nm dbnm", - /* 234 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", - /* 235 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", - /* 236 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 237 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", - /* 238 */ "plus_num ::= PLUS INTEGER|FLOAT", - /* 239 */ "minus_num ::= MINUS INTEGER|FLOAT", - /* 240 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", - /* 241 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 242 */ "trigger_time ::= BEFORE|AFTER", - /* 243 */ "trigger_time ::= INSTEAD OF", - /* 244 */ "trigger_time ::=", - /* 245 */ "trigger_event ::= DELETE|INSERT", - /* 246 */ "trigger_event ::= UPDATE", - /* 247 */ "trigger_event ::= UPDATE OF idlist", - /* 248 */ "when_clause ::=", - /* 249 */ "when_clause ::= WHEN expr", - /* 250 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", - /* 251 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 252 */ "trnm ::= nm DOT nm", - /* 253 */ "tridxby ::= INDEXED BY nm", - /* 254 */ "tridxby ::= NOT INDEXED", - /* 255 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt", - /* 256 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", - /* 257 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", - /* 258 */ "trigger_cmd ::= scanpt select scanpt", - /* 259 */ "expr ::= RAISE LP IGNORE RP", - /* 260 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 261 */ "raisetype ::= ROLLBACK", - /* 262 */ "raisetype ::= ABORT", - /* 263 */ "raisetype ::= FAIL", - /* 264 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 265 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 266 */ "cmd ::= DETACH database_kw_opt expr", - /* 267 */ "key_opt ::=", - /* 268 */ "key_opt ::= KEY expr", - /* 269 */ "cmd ::= REINDEX", - /* 270 */ "cmd ::= REINDEX nm dbnm", - /* 271 */ "cmd ::= ANALYZE", - /* 272 */ "cmd ::= ANALYZE nm dbnm", - /* 273 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 274 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", - /* 275 */ "add_column_fullname ::= fullname", - /* 276 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", - /* 277 */ "cmd ::= create_vtab", - /* 278 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 279 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 280 */ "vtabarg ::=", - /* 281 */ "vtabargtoken ::= ANY", - /* 282 */ "vtabargtoken ::= lp anylist RP", - /* 283 */ "lp ::= LP", - /* 284 */ "with ::= WITH wqlist", - /* 285 */ "with ::= WITH RECURSIVE wqlist", - /* 286 */ "wqlist ::= nm eidlist_opt AS LP select RP", - /* 287 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", - /* 288 */ "windowdefn_list ::= windowdefn", - /* 289 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", - /* 290 */ "windowdefn ::= nm AS window", - /* 291 */ "window ::= LP part_opt orderby_opt frame_opt RP", - /* 292 */ "part_opt ::= PARTITION BY nexprlist", - /* 293 */ "part_opt ::=", - /* 294 */ "frame_opt ::=", - /* 295 */ "frame_opt ::= range_or_rows frame_bound_s", - /* 296 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e", - /* 297 */ "range_or_rows ::= RANGE", - /* 298 */ "range_or_rows ::= ROWS", - /* 299 */ "frame_bound_s ::= frame_bound", - /* 300 */ "frame_bound_s ::= UNBOUNDED PRECEDING", - /* 301 */ "frame_bound_e ::= frame_bound", - /* 302 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", - /* 303 */ "frame_bound ::= expr PRECEDING", - /* 304 */ "frame_bound ::= CURRENT ROW", - /* 305 */ "frame_bound ::= expr FOLLOWING", - /* 306 */ "window_clause ::= WINDOW windowdefn_list", - /* 307 */ "over_clause ::= filter_opt OVER window", - /* 308 */ "over_clause ::= filter_opt OVER nm", - /* 309 */ "filter_opt ::=", - /* 310 */ "filter_opt ::= FILTER LP WHERE expr RP", - /* 311 */ "input ::= cmdlist", - /* 312 */ "cmdlist ::= cmdlist ecmd", - /* 313 */ "cmdlist ::= ecmd", - /* 314 */ "ecmd ::= SEMI", - /* 315 */ "ecmd ::= cmdx SEMI", - /* 316 */ "ecmd ::= explain cmdx", - /* 317 */ "trans_opt ::=", - /* 318 */ "trans_opt ::= TRANSACTION", - /* 319 */ "trans_opt ::= TRANSACTION nm", - /* 320 */ "savepoint_opt ::= SAVEPOINT", - /* 321 */ "savepoint_opt ::=", - /* 322 */ "cmd ::= create_table create_table_args", - /* 323 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 324 */ "columnlist ::= columnname carglist", - /* 325 */ "nm ::= ID|INDEXED", - /* 326 */ "nm ::= STRING", - /* 327 */ "nm ::= JOIN_KW", - /* 328 */ "typetoken ::= typename", - /* 329 */ "typename ::= ID|STRING", - /* 330 */ "signed ::= plus_num", - /* 331 */ "signed ::= minus_num", - /* 332 */ "carglist ::= carglist ccons", - /* 333 */ "carglist ::=", - /* 334 */ "ccons ::= NULL onconf", - /* 335 */ "conslist_opt ::= COMMA conslist", - /* 336 */ "conslist ::= conslist tconscomma tcons", - /* 337 */ "conslist ::= tcons", - /* 338 */ "tconscomma ::=", - /* 339 */ "defer_subclause_opt ::= defer_subclause", - /* 340 */ "resolvetype ::= raisetype", - /* 341 */ "selectnowith ::= oneselect", - /* 342 */ "oneselect ::= values", - /* 343 */ "sclp ::= selcollist COMMA", - /* 344 */ "as ::= ID|STRING", - /* 345 */ "expr ::= term", - /* 346 */ "likeop ::= LIKE_KW|MATCH", - /* 347 */ "exprlist ::= nexprlist", - /* 348 */ "nmnum ::= plus_num", - /* 349 */ "nmnum ::= nm", - /* 350 */ "nmnum ::= ON", - /* 351 */ "nmnum ::= DELETE", - /* 352 */ "nmnum ::= DEFAULT", - /* 353 */ "plus_num ::= INTEGER|FLOAT", - /* 354 */ "foreach_clause ::=", - /* 355 */ "foreach_clause ::= FOR EACH ROW", - /* 356 */ "trnm ::= nm", - /* 357 */ "tridxby ::=", - /* 358 */ "database_kw_opt ::= DATABASE", - /* 359 */ "database_kw_opt ::=", - /* 360 */ "kwcolumn_opt ::=", - /* 361 */ "kwcolumn_opt ::= COLUMNKW", - /* 362 */ "vtabarglist ::= vtabarg", - /* 363 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 364 */ "vtabarg ::= vtabarg vtabargtoken", - /* 365 */ "anylist ::=", - /* 366 */ "anylist ::= anylist LP anylist RP", - /* 367 */ "anylist ::= anylist ANY", - /* 368 */ "with ::=", + /* 29 */ "scantok ::=", + /* 30 */ "ccons ::= CONSTRAINT nm", + /* 31 */ "ccons ::= DEFAULT scantok term", + /* 32 */ "ccons ::= DEFAULT LP expr RP", + /* 33 */ "ccons ::= DEFAULT PLUS scantok term", + /* 34 */ "ccons ::= DEFAULT MINUS scantok term", + /* 35 */ "ccons ::= DEFAULT scantok ID|INDEXED", + /* 36 */ "ccons ::= NOT NULL onconf", + /* 37 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 38 */ "ccons ::= UNIQUE onconf", + /* 39 */ "ccons ::= CHECK LP expr RP", + /* 40 */ "ccons ::= REFERENCES nm eidlist_opt refargs", + /* 41 */ "ccons ::= defer_subclause", + /* 42 */ "ccons ::= COLLATE ID|STRING", + /* 43 */ "autoinc ::=", + /* 44 */ "autoinc ::= AUTOINCR", + /* 45 */ "refargs ::=", + /* 46 */ "refargs ::= refargs refarg", + /* 47 */ "refarg ::= MATCH nm", + /* 48 */ "refarg ::= ON INSERT refact", + /* 49 */ "refarg ::= ON DELETE refact", + /* 50 */ "refarg ::= ON UPDATE refact", + /* 51 */ "refact ::= SET NULL", + /* 52 */ "refact ::= SET DEFAULT", + /* 53 */ "refact ::= CASCADE", + /* 54 */ "refact ::= RESTRICT", + /* 55 */ "refact ::= NO ACTION", + /* 56 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 57 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 58 */ "init_deferred_pred_opt ::=", + /* 59 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 60 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 61 */ "conslist_opt ::=", + /* 62 */ "tconscomma ::= COMMA", + /* 63 */ "tcons ::= CONSTRAINT nm", + /* 64 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf", + /* 65 */ "tcons ::= UNIQUE LP sortlist RP onconf", + /* 66 */ "tcons ::= CHECK LP expr RP onconf", + /* 67 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt", + /* 68 */ "defer_subclause_opt ::=", + /* 69 */ "onconf ::=", + /* 70 */ "onconf ::= ON CONFLICT resolvetype", + /* 71 */ "orconf ::=", + /* 72 */ "orconf ::= OR resolvetype", + /* 73 */ "resolvetype ::= IGNORE", + /* 74 */ "resolvetype ::= REPLACE", + /* 75 */ "cmd ::= DROP TABLE ifexists fullname", + /* 76 */ "ifexists ::= IF EXISTS", + /* 77 */ "ifexists ::=", + /* 78 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select", + /* 79 */ "cmd ::= DROP VIEW ifexists fullname", + /* 80 */ "cmd ::= select", + /* 81 */ "select ::= WITH wqlist selectnowith", + /* 82 */ "select ::= WITH RECURSIVE wqlist selectnowith", + /* 83 */ "select ::= selectnowith", + /* 84 */ "selectnowith ::= selectnowith multiselect_op oneselect", + /* 85 */ "multiselect_op ::= UNION", + /* 86 */ "multiselect_op ::= UNION ALL", + /* 87 */ "multiselect_op ::= EXCEPT|INTERSECT", + /* 88 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 89 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt", + /* 90 */ "values ::= VALUES LP nexprlist RP", + /* 91 */ "values ::= values COMMA LP nexprlist RP", + /* 92 */ "distinct ::= DISTINCT", + /* 93 */ "distinct ::= ALL", + /* 94 */ "distinct ::=", + /* 95 */ "sclp ::=", + /* 96 */ "selcollist ::= sclp scanpt expr scanpt as", + /* 97 */ "selcollist ::= sclp scanpt STAR", + /* 98 */ "selcollist ::= sclp scanpt nm DOT STAR", + /* 99 */ "as ::= AS nm", + /* 100 */ "as ::=", + /* 101 */ "from ::=", + /* 102 */ "from ::= FROM seltablist", + /* 103 */ "stl_prefix ::= seltablist joinop", + /* 104 */ "stl_prefix ::=", + /* 105 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt", + /* 106 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt", + /* 107 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt", + /* 108 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt", + /* 109 */ "dbnm ::=", + /* 110 */ "dbnm ::= DOT nm", + /* 111 */ "fullname ::= nm", + /* 112 */ "fullname ::= nm DOT nm", + /* 113 */ "xfullname ::= nm", + /* 114 */ "xfullname ::= nm DOT nm", + /* 115 */ "xfullname ::= nm DOT nm AS nm", + /* 116 */ "xfullname ::= nm AS nm", + /* 117 */ "joinop ::= COMMA|JOIN", + /* 118 */ "joinop ::= JOIN_KW JOIN", + /* 119 */ "joinop ::= JOIN_KW nm JOIN", + /* 120 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 121 */ "on_opt ::= ON expr", + /* 122 */ "on_opt ::=", + /* 123 */ "indexed_opt ::=", + /* 124 */ "indexed_opt ::= INDEXED BY nm", + /* 125 */ "indexed_opt ::= NOT INDEXED", + /* 126 */ "using_opt ::= USING LP idlist RP", + /* 127 */ "using_opt ::=", + /* 128 */ "orderby_opt ::=", + /* 129 */ "orderby_opt ::= ORDER BY sortlist", + /* 130 */ "sortlist ::= sortlist COMMA expr sortorder", + /* 131 */ "sortlist ::= expr sortorder", + /* 132 */ "sortorder ::= ASC", + /* 133 */ "sortorder ::= DESC", + /* 134 */ "sortorder ::=", + /* 135 */ "groupby_opt ::=", + /* 136 */ "groupby_opt ::= GROUP BY nexprlist", + /* 137 */ "having_opt ::=", + /* 138 */ "having_opt ::= HAVING expr", + /* 139 */ "limit_opt ::=", + /* 140 */ "limit_opt ::= LIMIT expr", + /* 141 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 142 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 143 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt", + /* 144 */ "where_opt ::=", + /* 145 */ "where_opt ::= WHERE expr", + /* 146 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt", + /* 147 */ "setlist ::= setlist COMMA nm EQ expr", + /* 148 */ "setlist ::= setlist COMMA LP idlist RP EQ expr", + /* 149 */ "setlist ::= nm EQ expr", + /* 150 */ "setlist ::= LP idlist RP EQ expr", + /* 151 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert", + /* 152 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES", + /* 153 */ "upsert ::=", + /* 154 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt", + /* 155 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING", + /* 156 */ "upsert ::= ON CONFLICT DO NOTHING", + /* 157 */ "insert_cmd ::= INSERT orconf", + /* 158 */ "insert_cmd ::= REPLACE", + /* 159 */ "idlist_opt ::=", + /* 160 */ "idlist_opt ::= LP idlist RP", + /* 161 */ "idlist ::= idlist COMMA nm", + /* 162 */ "idlist ::= nm", + /* 163 */ "expr ::= LP expr RP", + /* 164 */ "expr ::= ID|INDEXED", + /* 165 */ "expr ::= JOIN_KW", + /* 166 */ "expr ::= nm DOT nm", + /* 167 */ "expr ::= nm DOT nm DOT nm", + /* 168 */ "term ::= NULL|FLOAT|BLOB", + /* 169 */ "term ::= STRING", + /* 170 */ "term ::= INTEGER", + /* 171 */ "expr ::= VARIABLE", + /* 172 */ "expr ::= expr COLLATE ID|STRING", + /* 173 */ "expr ::= CAST LP expr AS typetoken RP", + /* 174 */ "expr ::= ID|INDEXED LP distinct exprlist RP", + /* 175 */ "expr ::= ID|INDEXED LP STAR RP", + /* 176 */ "expr ::= ID|INDEXED LP distinct exprlist RP over_clause", + /* 177 */ "expr ::= ID|INDEXED LP STAR RP over_clause", + /* 178 */ "term ::= CTIME_KW", + /* 179 */ "expr ::= LP nexprlist COMMA expr RP", + /* 180 */ "expr ::= expr AND expr", + /* 181 */ "expr ::= expr OR expr", + /* 182 */ "expr ::= expr LT|GT|GE|LE expr", + /* 183 */ "expr ::= expr EQ|NE expr", + /* 184 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 185 */ "expr ::= expr PLUS|MINUS expr", + /* 186 */ "expr ::= expr STAR|SLASH|REM expr", + /* 187 */ "expr ::= expr CONCAT expr", + /* 188 */ "likeop ::= NOT LIKE_KW|MATCH", + /* 189 */ "expr ::= expr likeop expr", + /* 190 */ "expr ::= expr likeop expr ESCAPE expr", + /* 191 */ "expr ::= expr ISNULL|NOTNULL", + /* 192 */ "expr ::= expr NOT NULL", + /* 193 */ "expr ::= expr IS expr", + /* 194 */ "expr ::= expr IS NOT expr", + /* 195 */ "expr ::= NOT expr", + /* 196 */ "expr ::= BITNOT expr", + /* 197 */ "expr ::= PLUS|MINUS expr", + /* 198 */ "between_op ::= BETWEEN", + /* 199 */ "between_op ::= NOT BETWEEN", + /* 200 */ "expr ::= expr between_op expr AND expr", + /* 201 */ "in_op ::= IN", + /* 202 */ "in_op ::= NOT IN", + /* 203 */ "expr ::= expr in_op LP exprlist RP", + /* 204 */ "expr ::= LP select RP", + /* 205 */ "expr ::= expr in_op LP select RP", + /* 206 */ "expr ::= expr in_op nm dbnm paren_exprlist", + /* 207 */ "expr ::= EXISTS LP select RP", + /* 208 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 209 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 210 */ "case_exprlist ::= WHEN expr THEN expr", + /* 211 */ "case_else ::= ELSE expr", + /* 212 */ "case_else ::=", + /* 213 */ "case_operand ::= expr", + /* 214 */ "case_operand ::=", + /* 215 */ "exprlist ::=", + /* 216 */ "nexprlist ::= nexprlist COMMA expr", + /* 217 */ "nexprlist ::= expr", + /* 218 */ "paren_exprlist ::=", + /* 219 */ "paren_exprlist ::= LP exprlist RP", + /* 220 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt", + /* 221 */ "uniqueflag ::= UNIQUE", + /* 222 */ "uniqueflag ::=", + /* 223 */ "eidlist_opt ::=", + /* 224 */ "eidlist_opt ::= LP eidlist RP", + /* 225 */ "eidlist ::= eidlist COMMA nm collate sortorder", + /* 226 */ "eidlist ::= nm collate sortorder", + /* 227 */ "collate ::=", + /* 228 */ "collate ::= COLLATE ID|STRING", + /* 229 */ "cmd ::= DROP INDEX ifexists fullname", + /* 230 */ "cmd ::= VACUUM vinto", + /* 231 */ "cmd ::= VACUUM nm vinto", + /* 232 */ "vinto ::= INTO expr", + /* 233 */ "vinto ::=", + /* 234 */ "cmd ::= PRAGMA nm dbnm", + /* 235 */ "cmd ::= PRAGMA nm dbnm EQ nmnum", + /* 236 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP", + /* 237 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 238 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP", + /* 239 */ "plus_num ::= PLUS INTEGER|FLOAT", + /* 240 */ "minus_num ::= MINUS INTEGER|FLOAT", + /* 241 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END", + /* 242 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 243 */ "trigger_time ::= BEFORE|AFTER", + /* 244 */ "trigger_time ::= INSTEAD OF", + /* 245 */ "trigger_time ::=", + /* 246 */ "trigger_event ::= DELETE|INSERT", + /* 247 */ "trigger_event ::= UPDATE", + /* 248 */ "trigger_event ::= UPDATE OF idlist", + /* 249 */ "when_clause ::=", + /* 250 */ "when_clause ::= WHEN expr", + /* 251 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", + /* 252 */ "trigger_cmd_list ::= trigger_cmd SEMI", + /* 253 */ "trnm ::= nm DOT nm", + /* 254 */ "tridxby ::= INDEXED BY nm", + /* 255 */ "tridxby ::= NOT INDEXED", + /* 256 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt", + /* 257 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", + /* 258 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", + /* 259 */ "trigger_cmd ::= scanpt select scanpt", + /* 260 */ "expr ::= RAISE LP IGNORE RP", + /* 261 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 262 */ "raisetype ::= ROLLBACK", + /* 263 */ "raisetype ::= ABORT", + /* 264 */ "raisetype ::= FAIL", + /* 265 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 266 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 267 */ "cmd ::= DETACH database_kw_opt expr", + /* 268 */ "key_opt ::=", + /* 269 */ "key_opt ::= KEY expr", + /* 270 */ "cmd ::= REINDEX", + /* 271 */ "cmd ::= REINDEX nm dbnm", + /* 272 */ "cmd ::= ANALYZE", + /* 273 */ "cmd ::= ANALYZE nm dbnm", + /* 274 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 275 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 276 */ "add_column_fullname ::= fullname", + /* 277 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", + /* 278 */ "cmd ::= create_vtab", + /* 279 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 280 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 281 */ "vtabarg ::=", + /* 282 */ "vtabargtoken ::= ANY", + /* 283 */ "vtabargtoken ::= lp anylist RP", + /* 284 */ "lp ::= LP", + /* 285 */ "with ::= WITH wqlist", + /* 286 */ "with ::= WITH RECURSIVE wqlist", + /* 287 */ "wqlist ::= nm eidlist_opt AS LP select RP", + /* 288 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP", + /* 289 */ "windowdefn_list ::= windowdefn", + /* 290 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", + /* 291 */ "windowdefn ::= nm AS LP window RP", + /* 292 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", + /* 293 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", + /* 294 */ "window ::= ORDER BY sortlist frame_opt", + /* 295 */ "window ::= nm ORDER BY sortlist frame_opt", + /* 296 */ "window ::= frame_opt", + /* 297 */ "window ::= nm frame_opt", + /* 298 */ "frame_opt ::=", + /* 299 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", + /* 300 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", + /* 301 */ "range_or_rows ::= RANGE|ROWS|GROUPS", + /* 302 */ "frame_bound_s ::= frame_bound", + /* 303 */ "frame_bound_s ::= UNBOUNDED PRECEDING", + /* 304 */ "frame_bound_e ::= frame_bound", + /* 305 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", + /* 306 */ "frame_bound ::= expr PRECEDING|FOLLOWING", + /* 307 */ "frame_bound ::= CURRENT ROW", + /* 308 */ "frame_exclude_opt ::=", + /* 309 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", + /* 310 */ "frame_exclude ::= NO OTHERS", + /* 311 */ "frame_exclude ::= CURRENT ROW", + /* 312 */ "frame_exclude ::= GROUP|TIES", + /* 313 */ "window_clause ::= WINDOW windowdefn_list", + /* 314 */ "over_clause ::= filter_opt OVER LP window RP", + /* 315 */ "over_clause ::= filter_opt OVER nm", + /* 316 */ "filter_opt ::=", + /* 317 */ "filter_opt ::= FILTER LP WHERE expr RP", + /* 318 */ "input ::= cmdlist", + /* 319 */ "cmdlist ::= cmdlist ecmd", + /* 320 */ "cmdlist ::= ecmd", + /* 321 */ "ecmd ::= SEMI", + /* 322 */ "ecmd ::= cmdx SEMI", + /* 323 */ "ecmd ::= explain cmdx", + /* 324 */ "trans_opt ::=", + /* 325 */ "trans_opt ::= TRANSACTION", + /* 326 */ "trans_opt ::= TRANSACTION nm", + /* 327 */ "savepoint_opt ::= SAVEPOINT", + /* 328 */ "savepoint_opt ::=", + /* 329 */ "cmd ::= create_table create_table_args", + /* 330 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 331 */ "columnlist ::= columnname carglist", + /* 332 */ "nm ::= ID|INDEXED", + /* 333 */ "nm ::= STRING", + /* 334 */ "nm ::= JOIN_KW", + /* 335 */ "typetoken ::= typename", + /* 336 */ "typename ::= ID|STRING", + /* 337 */ "signed ::= plus_num", + /* 338 */ "signed ::= minus_num", + /* 339 */ "carglist ::= carglist ccons", + /* 340 */ "carglist ::=", + /* 341 */ "ccons ::= NULL onconf", + /* 342 */ "conslist_opt ::= COMMA conslist", + /* 343 */ "conslist ::= conslist tconscomma tcons", + /* 344 */ "conslist ::= tcons", + /* 345 */ "tconscomma ::=", + /* 346 */ "defer_subclause_opt ::= defer_subclause", + /* 347 */ "resolvetype ::= raisetype", + /* 348 */ "selectnowith ::= oneselect", + /* 349 */ "oneselect ::= values", + /* 350 */ "sclp ::= selcollist COMMA", + /* 351 */ "as ::= ID|STRING", + /* 352 */ "expr ::= term", + /* 353 */ "likeop ::= LIKE_KW|MATCH", + /* 354 */ "exprlist ::= nexprlist", + /* 355 */ "nmnum ::= plus_num", + /* 356 */ "nmnum ::= nm", + /* 357 */ "nmnum ::= ON", + /* 358 */ "nmnum ::= DELETE", + /* 359 */ "nmnum ::= DEFAULT", + /* 360 */ "plus_num ::= INTEGER|FLOAT", + /* 361 */ "foreach_clause ::=", + /* 362 */ "foreach_clause ::= FOR EACH ROW", + /* 363 */ "trnm ::= nm", + /* 364 */ "tridxby ::=", + /* 365 */ "database_kw_opt ::= DATABASE", + /* 366 */ "database_kw_opt ::=", + /* 367 */ "kwcolumn_opt ::=", + /* 368 */ "kwcolumn_opt ::= COLUMNKW", + /* 369 */ "vtabarglist ::= vtabarg", + /* 370 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 371 */ "vtabarg ::= vtabarg vtabargtoken", + /* 372 */ "anylist ::=", + /* 373 */ "anylist ::= anylist LP anylist RP", + /* 374 */ "anylist ::= anylist ANY", + /* 375 */ "with ::=", }; #endif /* NDEBUG */ @@ -149203,97 +150661,97 @@ static void yy_destructor( ** inside the C code. */ /********* Begin destructor definitions ***************************************/ - case 174: /* select */ - case 206: /* selectnowith */ - case 207: /* oneselect */ - case 219: /* values */ + case 195: /* select */ + case 228: /* selectnowith */ + case 229: /* oneselect */ + case 241: /* values */ { -sqlite3SelectDelete(pParse->db, (yypminor->yy423)); +sqlite3SelectDelete(pParse->db, (yypminor->yy391)); } break; - case 184: /* term */ - case 185: /* expr */ - case 213: /* where_opt */ - case 215: /* having_opt */ - case 227: /* on_opt */ - case 242: /* case_operand */ - case 244: /* case_else */ - case 247: /* vinto */ - case 254: /* when_clause */ - case 259: /* key_opt */ - case 273: /* filter_opt */ + case 206: /* term */ + case 207: /* expr */ + case 235: /* where_opt */ + case 237: /* having_opt */ + case 249: /* on_opt */ + case 264: /* case_operand */ + case 266: /* case_else */ + case 269: /* vinto */ + case 276: /* when_clause */ + case 281: /* key_opt */ + case 295: /* filter_opt */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy490)); +sqlite3ExprDelete(pParse->db, (yypminor->yy102)); } break; - case 189: /* eidlist_opt */ - case 198: /* sortlist */ - case 199: /* eidlist */ - case 211: /* selcollist */ - case 214: /* groupby_opt */ - case 216: /* orderby_opt */ - case 220: /* nexprlist */ - case 221: /* sclp */ - case 229: /* exprlist */ - case 233: /* setlist */ - case 241: /* paren_exprlist */ - case 243: /* case_exprlist */ - case 272: /* part_opt */ + case 211: /* eidlist_opt */ + case 220: /* sortlist */ + case 221: /* eidlist */ + case 233: /* selcollist */ + case 236: /* groupby_opt */ + case 238: /* orderby_opt */ + case 242: /* nexprlist */ + case 243: /* sclp */ + case 251: /* exprlist */ + case 255: /* setlist */ + case 263: /* paren_exprlist */ + case 265: /* case_exprlist */ + case 294: /* part_opt */ { -sqlite3ExprListDelete(pParse->db, (yypminor->yy42)); +sqlite3ExprListDelete(pParse->db, (yypminor->yy94)); } break; - case 205: /* fullname */ - case 212: /* from */ - case 223: /* seltablist */ - case 224: /* stl_prefix */ - case 230: /* xfullname */ + case 227: /* fullname */ + case 234: /* from */ + case 245: /* seltablist */ + case 246: /* stl_prefix */ + case 252: /* xfullname */ { -sqlite3SrcListDelete(pParse->db, (yypminor->yy167)); +sqlite3SrcListDelete(pParse->db, (yypminor->yy407)); } break; - case 208: /* wqlist */ + case 230: /* wqlist */ { -sqlite3WithDelete(pParse->db, (yypminor->yy499)); +sqlite3WithDelete(pParse->db, (yypminor->yy243)); } break; - case 218: /* window_clause */ - case 268: /* windowdefn_list */ + case 240: /* window_clause */ + case 290: /* windowdefn_list */ { -sqlite3WindowListDelete(pParse->db, (yypminor->yy147)); +sqlite3WindowListDelete(pParse->db, (yypminor->yy379)); } break; - case 228: /* using_opt */ - case 231: /* idlist */ - case 235: /* idlist_opt */ + case 250: /* using_opt */ + case 253: /* idlist */ + case 257: /* idlist_opt */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy336)); +sqlite3IdListDelete(pParse->db, (yypminor->yy76)); } break; - case 237: /* over_clause */ - case 269: /* windowdefn */ - case 270: /* window */ - case 271: /* frame_opt */ + case 259: /* over_clause */ + case 291: /* windowdefn */ + case 292: /* window */ + case 293: /* frame_opt */ { -sqlite3WindowDelete(pParse->db, (yypminor->yy147)); +sqlite3WindowDelete(pParse->db, (yypminor->yy379)); } break; - case 250: /* trigger_cmd_list */ - case 255: /* trigger_cmd */ + case 272: /* trigger_cmd_list */ + case 277: /* trigger_cmd */ { -sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy119)); +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy11)); } break; - case 252: /* trigger_event */ + case 274: /* trigger_event */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy350).b); +sqlite3IdListDelete(pParse->db, (yypminor->yy298).b); } break; - case 275: /* frame_bound */ - case 276: /* frame_bound_s */ - case 277: /* frame_bound_e */ + case 297: /* frame_bound */ + case 298: /* frame_bound_s */ + case 299: /* frame_bound_e */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy317).pExpr); +sqlite3ExprDelete(pParse->db, (yypminor->yy389).pExpr); } break; /********* End destructor definitions *****************************************/ @@ -149588,375 +151046,382 @@ static void yy_shift( /* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side ** of that rule */ static const YYCODETYPE yyRuleInfoLhs[] = { - 159, /* (0) explain ::= EXPLAIN */ - 159, /* (1) explain ::= EXPLAIN QUERY PLAN */ - 158, /* (2) cmdx ::= cmd */ - 160, /* (3) cmd ::= BEGIN transtype trans_opt */ - 161, /* (4) transtype ::= */ - 161, /* (5) transtype ::= DEFERRED */ - 161, /* (6) transtype ::= IMMEDIATE */ - 161, /* (7) transtype ::= EXCLUSIVE */ - 160, /* (8) cmd ::= COMMIT|END trans_opt */ - 160, /* (9) cmd ::= ROLLBACK trans_opt */ - 160, /* (10) cmd ::= SAVEPOINT nm */ - 160, /* (11) cmd ::= RELEASE savepoint_opt nm */ - 160, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ - 165, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ - 167, /* (14) createkw ::= CREATE */ - 169, /* (15) ifnotexists ::= */ - 169, /* (16) ifnotexists ::= IF NOT EXISTS */ - 168, /* (17) temp ::= TEMP */ - 168, /* (18) temp ::= */ - 166, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */ - 166, /* (20) create_table_args ::= AS select */ - 173, /* (21) table_options ::= */ - 173, /* (22) table_options ::= WITHOUT nm */ - 175, /* (23) columnname ::= nm typetoken */ - 177, /* (24) typetoken ::= */ - 177, /* (25) typetoken ::= typename LP signed RP */ - 177, /* (26) typetoken ::= typename LP signed COMMA signed RP */ - 178, /* (27) typename ::= typename ID|STRING */ - 182, /* (28) scanpt ::= */ - 183, /* (29) ccons ::= CONSTRAINT nm */ - 183, /* (30) ccons ::= DEFAULT scanpt term scanpt */ - 183, /* (31) ccons ::= DEFAULT LP expr RP */ - 183, /* (32) ccons ::= DEFAULT PLUS term scanpt */ - 183, /* (33) ccons ::= DEFAULT MINUS term scanpt */ - 183, /* (34) ccons ::= DEFAULT scanpt ID|INDEXED */ - 183, /* (35) ccons ::= NOT NULL onconf */ - 183, /* (36) ccons ::= PRIMARY KEY sortorder onconf autoinc */ - 183, /* (37) ccons ::= UNIQUE onconf */ - 183, /* (38) ccons ::= CHECK LP expr RP */ - 183, /* (39) ccons ::= REFERENCES nm eidlist_opt refargs */ - 183, /* (40) ccons ::= defer_subclause */ - 183, /* (41) ccons ::= COLLATE ID|STRING */ - 188, /* (42) autoinc ::= */ - 188, /* (43) autoinc ::= AUTOINCR */ - 190, /* (44) refargs ::= */ - 190, /* (45) refargs ::= refargs refarg */ - 192, /* (46) refarg ::= MATCH nm */ - 192, /* (47) refarg ::= ON INSERT refact */ - 192, /* (48) refarg ::= ON DELETE refact */ - 192, /* (49) refarg ::= ON UPDATE refact */ - 193, /* (50) refact ::= SET NULL */ - 193, /* (51) refact ::= SET DEFAULT */ - 193, /* (52) refact ::= CASCADE */ - 193, /* (53) refact ::= RESTRICT */ - 193, /* (54) refact ::= NO ACTION */ - 191, /* (55) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ - 191, /* (56) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - 194, /* (57) init_deferred_pred_opt ::= */ - 194, /* (58) init_deferred_pred_opt ::= INITIALLY DEFERRED */ - 194, /* (59) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ - 172, /* (60) conslist_opt ::= */ - 196, /* (61) tconscomma ::= COMMA */ - 197, /* (62) tcons ::= CONSTRAINT nm */ - 197, /* (63) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ - 197, /* (64) tcons ::= UNIQUE LP sortlist RP onconf */ - 197, /* (65) tcons ::= CHECK LP expr RP onconf */ - 197, /* (66) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ - 200, /* (67) defer_subclause_opt ::= */ - 186, /* (68) onconf ::= */ - 186, /* (69) onconf ::= ON CONFLICT resolvetype */ - 201, /* (70) orconf ::= */ - 201, /* (71) orconf ::= OR resolvetype */ - 202, /* (72) resolvetype ::= IGNORE */ - 202, /* (73) resolvetype ::= REPLACE */ - 160, /* (74) cmd ::= DROP TABLE ifexists fullname */ - 204, /* (75) ifexists ::= IF EXISTS */ - 204, /* (76) ifexists ::= */ - 160, /* (77) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ - 160, /* (78) cmd ::= DROP VIEW ifexists fullname */ - 160, /* (79) cmd ::= select */ - 174, /* (80) select ::= WITH wqlist selectnowith */ - 174, /* (81) select ::= WITH RECURSIVE wqlist selectnowith */ - 174, /* (82) select ::= selectnowith */ - 206, /* (83) selectnowith ::= selectnowith multiselect_op oneselect */ - 209, /* (84) multiselect_op ::= UNION */ - 209, /* (85) multiselect_op ::= UNION ALL */ - 209, /* (86) multiselect_op ::= EXCEPT|INTERSECT */ - 207, /* (87) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ - 207, /* (88) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ - 219, /* (89) values ::= VALUES LP nexprlist RP */ - 219, /* (90) values ::= values COMMA LP nexprlist RP */ - 210, /* (91) distinct ::= DISTINCT */ - 210, /* (92) distinct ::= ALL */ - 210, /* (93) distinct ::= */ - 221, /* (94) sclp ::= */ - 211, /* (95) selcollist ::= sclp scanpt expr scanpt as */ - 211, /* (96) selcollist ::= sclp scanpt STAR */ - 211, /* (97) selcollist ::= sclp scanpt nm DOT STAR */ - 222, /* (98) as ::= AS nm */ - 222, /* (99) as ::= */ - 212, /* (100) from ::= */ - 212, /* (101) from ::= FROM seltablist */ - 224, /* (102) stl_prefix ::= seltablist joinop */ - 224, /* (103) stl_prefix ::= */ - 223, /* (104) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ - 223, /* (105) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ - 223, /* (106) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ - 223, /* (107) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ - 170, /* (108) dbnm ::= */ - 170, /* (109) dbnm ::= DOT nm */ - 205, /* (110) fullname ::= nm */ - 205, /* (111) fullname ::= nm DOT nm */ - 230, /* (112) xfullname ::= nm */ - 230, /* (113) xfullname ::= nm DOT nm */ - 230, /* (114) xfullname ::= nm DOT nm AS nm */ - 230, /* (115) xfullname ::= nm AS nm */ - 225, /* (116) joinop ::= COMMA|JOIN */ - 225, /* (117) joinop ::= JOIN_KW JOIN */ - 225, /* (118) joinop ::= JOIN_KW nm JOIN */ - 225, /* (119) joinop ::= JOIN_KW nm nm JOIN */ - 227, /* (120) on_opt ::= ON expr */ - 227, /* (121) on_opt ::= */ - 226, /* (122) indexed_opt ::= */ - 226, /* (123) indexed_opt ::= INDEXED BY nm */ - 226, /* (124) indexed_opt ::= NOT INDEXED */ - 228, /* (125) using_opt ::= USING LP idlist RP */ - 228, /* (126) using_opt ::= */ - 216, /* (127) orderby_opt ::= */ - 216, /* (128) orderby_opt ::= ORDER BY sortlist */ - 198, /* (129) sortlist ::= sortlist COMMA expr sortorder */ - 198, /* (130) sortlist ::= expr sortorder */ - 187, /* (131) sortorder ::= ASC */ - 187, /* (132) sortorder ::= DESC */ - 187, /* (133) sortorder ::= */ - 214, /* (134) groupby_opt ::= */ - 214, /* (135) groupby_opt ::= GROUP BY nexprlist */ - 215, /* (136) having_opt ::= */ - 215, /* (137) having_opt ::= HAVING expr */ - 217, /* (138) limit_opt ::= */ - 217, /* (139) limit_opt ::= LIMIT expr */ - 217, /* (140) limit_opt ::= LIMIT expr OFFSET expr */ - 217, /* (141) limit_opt ::= LIMIT expr COMMA expr */ - 160, /* (142) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ - 213, /* (143) where_opt ::= */ - 213, /* (144) where_opt ::= WHERE expr */ - 160, /* (145) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ - 233, /* (146) setlist ::= setlist COMMA nm EQ expr */ - 233, /* (147) setlist ::= setlist COMMA LP idlist RP EQ expr */ - 233, /* (148) setlist ::= nm EQ expr */ - 233, /* (149) setlist ::= LP idlist RP EQ expr */ - 160, /* (150) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ - 160, /* (151) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ - 236, /* (152) upsert ::= */ - 236, /* (153) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ - 236, /* (154) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ - 236, /* (155) upsert ::= ON CONFLICT DO NOTHING */ - 234, /* (156) insert_cmd ::= INSERT orconf */ - 234, /* (157) insert_cmd ::= REPLACE */ - 235, /* (158) idlist_opt ::= */ - 235, /* (159) idlist_opt ::= LP idlist RP */ - 231, /* (160) idlist ::= idlist COMMA nm */ - 231, /* (161) idlist ::= nm */ - 185, /* (162) expr ::= LP expr RP */ - 185, /* (163) expr ::= ID|INDEXED */ - 185, /* (164) expr ::= JOIN_KW */ - 185, /* (165) expr ::= nm DOT nm */ - 185, /* (166) expr ::= nm DOT nm DOT nm */ - 184, /* (167) term ::= NULL|FLOAT|BLOB */ - 184, /* (168) term ::= STRING */ - 184, /* (169) term ::= INTEGER */ - 185, /* (170) expr ::= VARIABLE */ - 185, /* (171) expr ::= expr COLLATE ID|STRING */ - 185, /* (172) expr ::= CAST LP expr AS typetoken RP */ - 185, /* (173) expr ::= ID|INDEXED LP distinct exprlist RP */ - 185, /* (174) expr ::= ID|INDEXED LP STAR RP */ - 185, /* (175) expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ - 185, /* (176) expr ::= ID|INDEXED LP STAR RP over_clause */ - 184, /* (177) term ::= CTIME_KW */ - 185, /* (178) expr ::= LP nexprlist COMMA expr RP */ - 185, /* (179) expr ::= expr AND expr */ - 185, /* (180) expr ::= expr OR expr */ - 185, /* (181) expr ::= expr LT|GT|GE|LE expr */ - 185, /* (182) expr ::= expr EQ|NE expr */ - 185, /* (183) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - 185, /* (184) expr ::= expr PLUS|MINUS expr */ - 185, /* (185) expr ::= expr STAR|SLASH|REM expr */ - 185, /* (186) expr ::= expr CONCAT expr */ - 238, /* (187) likeop ::= NOT LIKE_KW|MATCH */ - 185, /* (188) expr ::= expr likeop expr */ - 185, /* (189) expr ::= expr likeop expr ESCAPE expr */ - 185, /* (190) expr ::= expr ISNULL|NOTNULL */ - 185, /* (191) expr ::= expr NOT NULL */ - 185, /* (192) expr ::= expr IS expr */ - 185, /* (193) expr ::= expr IS NOT expr */ - 185, /* (194) expr ::= NOT expr */ - 185, /* (195) expr ::= BITNOT expr */ - 185, /* (196) expr ::= PLUS|MINUS expr */ - 239, /* (197) between_op ::= BETWEEN */ - 239, /* (198) between_op ::= NOT BETWEEN */ - 185, /* (199) expr ::= expr between_op expr AND expr */ - 240, /* (200) in_op ::= IN */ - 240, /* (201) in_op ::= NOT IN */ - 185, /* (202) expr ::= expr in_op LP exprlist RP */ - 185, /* (203) expr ::= LP select RP */ - 185, /* (204) expr ::= expr in_op LP select RP */ - 185, /* (205) expr ::= expr in_op nm dbnm paren_exprlist */ - 185, /* (206) expr ::= EXISTS LP select RP */ - 185, /* (207) expr ::= CASE case_operand case_exprlist case_else END */ - 243, /* (208) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - 243, /* (209) case_exprlist ::= WHEN expr THEN expr */ - 244, /* (210) case_else ::= ELSE expr */ - 244, /* (211) case_else ::= */ - 242, /* (212) case_operand ::= expr */ - 242, /* (213) case_operand ::= */ - 229, /* (214) exprlist ::= */ - 220, /* (215) nexprlist ::= nexprlist COMMA expr */ - 220, /* (216) nexprlist ::= expr */ - 241, /* (217) paren_exprlist ::= */ - 241, /* (218) paren_exprlist ::= LP exprlist RP */ - 160, /* (219) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - 245, /* (220) uniqueflag ::= UNIQUE */ - 245, /* (221) uniqueflag ::= */ - 189, /* (222) eidlist_opt ::= */ - 189, /* (223) eidlist_opt ::= LP eidlist RP */ - 199, /* (224) eidlist ::= eidlist COMMA nm collate sortorder */ - 199, /* (225) eidlist ::= nm collate sortorder */ - 246, /* (226) collate ::= */ - 246, /* (227) collate ::= COLLATE ID|STRING */ - 160, /* (228) cmd ::= DROP INDEX ifexists fullname */ - 160, /* (229) cmd ::= VACUUM vinto */ - 160, /* (230) cmd ::= VACUUM nm vinto */ - 247, /* (231) vinto ::= INTO expr */ - 247, /* (232) vinto ::= */ - 160, /* (233) cmd ::= PRAGMA nm dbnm */ - 160, /* (234) cmd ::= PRAGMA nm dbnm EQ nmnum */ - 160, /* (235) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - 160, /* (236) cmd ::= PRAGMA nm dbnm EQ minus_num */ - 160, /* (237) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - 180, /* (238) plus_num ::= PLUS INTEGER|FLOAT */ - 181, /* (239) minus_num ::= MINUS INTEGER|FLOAT */ - 160, /* (240) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - 249, /* (241) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - 251, /* (242) trigger_time ::= BEFORE|AFTER */ - 251, /* (243) trigger_time ::= INSTEAD OF */ - 251, /* (244) trigger_time ::= */ - 252, /* (245) trigger_event ::= DELETE|INSERT */ - 252, /* (246) trigger_event ::= UPDATE */ - 252, /* (247) trigger_event ::= UPDATE OF idlist */ - 254, /* (248) when_clause ::= */ - 254, /* (249) when_clause ::= WHEN expr */ - 250, /* (250) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - 250, /* (251) trigger_cmd_list ::= trigger_cmd SEMI */ - 256, /* (252) trnm ::= nm DOT nm */ - 257, /* (253) tridxby ::= INDEXED BY nm */ - 257, /* (254) tridxby ::= NOT INDEXED */ - 255, /* (255) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ - 255, /* (256) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - 255, /* (257) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - 255, /* (258) trigger_cmd ::= scanpt select scanpt */ - 185, /* (259) expr ::= RAISE LP IGNORE RP */ - 185, /* (260) expr ::= RAISE LP raisetype COMMA nm RP */ - 203, /* (261) raisetype ::= ROLLBACK */ - 203, /* (262) raisetype ::= ABORT */ - 203, /* (263) raisetype ::= FAIL */ - 160, /* (264) cmd ::= DROP TRIGGER ifexists fullname */ - 160, /* (265) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - 160, /* (266) cmd ::= DETACH database_kw_opt expr */ - 259, /* (267) key_opt ::= */ - 259, /* (268) key_opt ::= KEY expr */ - 160, /* (269) cmd ::= REINDEX */ - 160, /* (270) cmd ::= REINDEX nm dbnm */ - 160, /* (271) cmd ::= ANALYZE */ - 160, /* (272) cmd ::= ANALYZE nm dbnm */ - 160, /* (273) cmd ::= ALTER TABLE fullname RENAME TO nm */ - 160, /* (274) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - 260, /* (275) add_column_fullname ::= fullname */ - 160, /* (276) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - 160, /* (277) cmd ::= create_vtab */ - 160, /* (278) cmd ::= create_vtab LP vtabarglist RP */ - 262, /* (279) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 264, /* (280) vtabarg ::= */ - 265, /* (281) vtabargtoken ::= ANY */ - 265, /* (282) vtabargtoken ::= lp anylist RP */ - 266, /* (283) lp ::= LP */ - 232, /* (284) with ::= WITH wqlist */ - 232, /* (285) with ::= WITH RECURSIVE wqlist */ - 208, /* (286) wqlist ::= nm eidlist_opt AS LP select RP */ - 208, /* (287) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ - 268, /* (288) windowdefn_list ::= windowdefn */ - 268, /* (289) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - 269, /* (290) windowdefn ::= nm AS window */ - 270, /* (291) window ::= LP part_opt orderby_opt frame_opt RP */ - 272, /* (292) part_opt ::= PARTITION BY nexprlist */ - 272, /* (293) part_opt ::= */ - 271, /* (294) frame_opt ::= */ - 271, /* (295) frame_opt ::= range_or_rows frame_bound_s */ - 271, /* (296) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e */ - 274, /* (297) range_or_rows ::= RANGE */ - 274, /* (298) range_or_rows ::= ROWS */ - 276, /* (299) frame_bound_s ::= frame_bound */ - 276, /* (300) frame_bound_s ::= UNBOUNDED PRECEDING */ - 277, /* (301) frame_bound_e ::= frame_bound */ - 277, /* (302) frame_bound_e ::= UNBOUNDED FOLLOWING */ - 275, /* (303) frame_bound ::= expr PRECEDING */ - 275, /* (304) frame_bound ::= CURRENT ROW */ - 275, /* (305) frame_bound ::= expr FOLLOWING */ - 218, /* (306) window_clause ::= WINDOW windowdefn_list */ - 237, /* (307) over_clause ::= filter_opt OVER window */ - 237, /* (308) over_clause ::= filter_opt OVER nm */ - 273, /* (309) filter_opt ::= */ - 273, /* (310) filter_opt ::= FILTER LP WHERE expr RP */ - 155, /* (311) input ::= cmdlist */ - 156, /* (312) cmdlist ::= cmdlist ecmd */ - 156, /* (313) cmdlist ::= ecmd */ - 157, /* (314) ecmd ::= SEMI */ - 157, /* (315) ecmd ::= cmdx SEMI */ - 157, /* (316) ecmd ::= explain cmdx */ - 162, /* (317) trans_opt ::= */ - 162, /* (318) trans_opt ::= TRANSACTION */ - 162, /* (319) trans_opt ::= TRANSACTION nm */ - 164, /* (320) savepoint_opt ::= SAVEPOINT */ - 164, /* (321) savepoint_opt ::= */ - 160, /* (322) cmd ::= create_table create_table_args */ - 171, /* (323) columnlist ::= columnlist COMMA columnname carglist */ - 171, /* (324) columnlist ::= columnname carglist */ - 163, /* (325) nm ::= ID|INDEXED */ - 163, /* (326) nm ::= STRING */ - 163, /* (327) nm ::= JOIN_KW */ - 177, /* (328) typetoken ::= typename */ - 178, /* (329) typename ::= ID|STRING */ - 179, /* (330) signed ::= plus_num */ - 179, /* (331) signed ::= minus_num */ - 176, /* (332) carglist ::= carglist ccons */ - 176, /* (333) carglist ::= */ - 183, /* (334) ccons ::= NULL onconf */ - 172, /* (335) conslist_opt ::= COMMA conslist */ - 195, /* (336) conslist ::= conslist tconscomma tcons */ - 195, /* (337) conslist ::= tcons */ - 196, /* (338) tconscomma ::= */ - 200, /* (339) defer_subclause_opt ::= defer_subclause */ - 202, /* (340) resolvetype ::= raisetype */ - 206, /* (341) selectnowith ::= oneselect */ - 207, /* (342) oneselect ::= values */ - 221, /* (343) sclp ::= selcollist COMMA */ - 222, /* (344) as ::= ID|STRING */ - 185, /* (345) expr ::= term */ - 238, /* (346) likeop ::= LIKE_KW|MATCH */ - 229, /* (347) exprlist ::= nexprlist */ - 248, /* (348) nmnum ::= plus_num */ - 248, /* (349) nmnum ::= nm */ - 248, /* (350) nmnum ::= ON */ - 248, /* (351) nmnum ::= DELETE */ - 248, /* (352) nmnum ::= DEFAULT */ - 180, /* (353) plus_num ::= INTEGER|FLOAT */ - 253, /* (354) foreach_clause ::= */ - 253, /* (355) foreach_clause ::= FOR EACH ROW */ - 256, /* (356) trnm ::= nm */ - 257, /* (357) tridxby ::= */ - 258, /* (358) database_kw_opt ::= DATABASE */ - 258, /* (359) database_kw_opt ::= */ - 261, /* (360) kwcolumn_opt ::= */ - 261, /* (361) kwcolumn_opt ::= COLUMNKW */ - 263, /* (362) vtabarglist ::= vtabarg */ - 263, /* (363) vtabarglist ::= vtabarglist COMMA vtabarg */ - 264, /* (364) vtabarg ::= vtabarg vtabargtoken */ - 267, /* (365) anylist ::= */ - 267, /* (366) anylist ::= anylist LP anylist RP */ - 267, /* (367) anylist ::= anylist ANY */ - 232, /* (368) with ::= */ + 180, /* (0) explain ::= EXPLAIN */ + 180, /* (1) explain ::= EXPLAIN QUERY PLAN */ + 179, /* (2) cmdx ::= cmd */ + 181, /* (3) cmd ::= BEGIN transtype trans_opt */ + 182, /* (4) transtype ::= */ + 182, /* (5) transtype ::= DEFERRED */ + 182, /* (6) transtype ::= IMMEDIATE */ + 182, /* (7) transtype ::= EXCLUSIVE */ + 181, /* (8) cmd ::= COMMIT|END trans_opt */ + 181, /* (9) cmd ::= ROLLBACK trans_opt */ + 181, /* (10) cmd ::= SAVEPOINT nm */ + 181, /* (11) cmd ::= RELEASE savepoint_opt nm */ + 181, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */ + 186, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */ + 188, /* (14) createkw ::= CREATE */ + 190, /* (15) ifnotexists ::= */ + 190, /* (16) ifnotexists ::= IF NOT EXISTS */ + 189, /* (17) temp ::= TEMP */ + 189, /* (18) temp ::= */ + 187, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */ + 187, /* (20) create_table_args ::= AS select */ + 194, /* (21) table_options ::= */ + 194, /* (22) table_options ::= WITHOUT nm */ + 196, /* (23) columnname ::= nm typetoken */ + 198, /* (24) typetoken ::= */ + 198, /* (25) typetoken ::= typename LP signed RP */ + 198, /* (26) typetoken ::= typename LP signed COMMA signed RP */ + 199, /* (27) typename ::= typename ID|STRING */ + 203, /* (28) scanpt ::= */ + 204, /* (29) scantok ::= */ + 205, /* (30) ccons ::= CONSTRAINT nm */ + 205, /* (31) ccons ::= DEFAULT scantok term */ + 205, /* (32) ccons ::= DEFAULT LP expr RP */ + 205, /* (33) ccons ::= DEFAULT PLUS scantok term */ + 205, /* (34) ccons ::= DEFAULT MINUS scantok term */ + 205, /* (35) ccons ::= DEFAULT scantok ID|INDEXED */ + 205, /* (36) ccons ::= NOT NULL onconf */ + 205, /* (37) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + 205, /* (38) ccons ::= UNIQUE onconf */ + 205, /* (39) ccons ::= CHECK LP expr RP */ + 205, /* (40) ccons ::= REFERENCES nm eidlist_opt refargs */ + 205, /* (41) ccons ::= defer_subclause */ + 205, /* (42) ccons ::= COLLATE ID|STRING */ + 210, /* (43) autoinc ::= */ + 210, /* (44) autoinc ::= AUTOINCR */ + 212, /* (45) refargs ::= */ + 212, /* (46) refargs ::= refargs refarg */ + 214, /* (47) refarg ::= MATCH nm */ + 214, /* (48) refarg ::= ON INSERT refact */ + 214, /* (49) refarg ::= ON DELETE refact */ + 214, /* (50) refarg ::= ON UPDATE refact */ + 215, /* (51) refact ::= SET NULL */ + 215, /* (52) refact ::= SET DEFAULT */ + 215, /* (53) refact ::= CASCADE */ + 215, /* (54) refact ::= RESTRICT */ + 215, /* (55) refact ::= NO ACTION */ + 213, /* (56) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + 213, /* (57) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 216, /* (58) init_deferred_pred_opt ::= */ + 216, /* (59) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + 216, /* (60) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 193, /* (61) conslist_opt ::= */ + 218, /* (62) tconscomma ::= COMMA */ + 219, /* (63) tcons ::= CONSTRAINT nm */ + 219, /* (64) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + 219, /* (65) tcons ::= UNIQUE LP sortlist RP onconf */ + 219, /* (66) tcons ::= CHECK LP expr RP onconf */ + 219, /* (67) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 222, /* (68) defer_subclause_opt ::= */ + 208, /* (69) onconf ::= */ + 208, /* (70) onconf ::= ON CONFLICT resolvetype */ + 223, /* (71) orconf ::= */ + 223, /* (72) orconf ::= OR resolvetype */ + 224, /* (73) resolvetype ::= IGNORE */ + 224, /* (74) resolvetype ::= REPLACE */ + 181, /* (75) cmd ::= DROP TABLE ifexists fullname */ + 226, /* (76) ifexists ::= IF EXISTS */ + 226, /* (77) ifexists ::= */ + 181, /* (78) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + 181, /* (79) cmd ::= DROP VIEW ifexists fullname */ + 181, /* (80) cmd ::= select */ + 195, /* (81) select ::= WITH wqlist selectnowith */ + 195, /* (82) select ::= WITH RECURSIVE wqlist selectnowith */ + 195, /* (83) select ::= selectnowith */ + 228, /* (84) selectnowith ::= selectnowith multiselect_op oneselect */ + 231, /* (85) multiselect_op ::= UNION */ + 231, /* (86) multiselect_op ::= UNION ALL */ + 231, /* (87) multiselect_op ::= EXCEPT|INTERSECT */ + 229, /* (88) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + 229, /* (89) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + 241, /* (90) values ::= VALUES LP nexprlist RP */ + 241, /* (91) values ::= values COMMA LP nexprlist RP */ + 232, /* (92) distinct ::= DISTINCT */ + 232, /* (93) distinct ::= ALL */ + 232, /* (94) distinct ::= */ + 243, /* (95) sclp ::= */ + 233, /* (96) selcollist ::= sclp scanpt expr scanpt as */ + 233, /* (97) selcollist ::= sclp scanpt STAR */ + 233, /* (98) selcollist ::= sclp scanpt nm DOT STAR */ + 244, /* (99) as ::= AS nm */ + 244, /* (100) as ::= */ + 234, /* (101) from ::= */ + 234, /* (102) from ::= FROM seltablist */ + 246, /* (103) stl_prefix ::= seltablist joinop */ + 246, /* (104) stl_prefix ::= */ + 245, /* (105) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + 245, /* (106) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + 245, /* (107) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + 245, /* (108) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + 191, /* (109) dbnm ::= */ + 191, /* (110) dbnm ::= DOT nm */ + 227, /* (111) fullname ::= nm */ + 227, /* (112) fullname ::= nm DOT nm */ + 252, /* (113) xfullname ::= nm */ + 252, /* (114) xfullname ::= nm DOT nm */ + 252, /* (115) xfullname ::= nm DOT nm AS nm */ + 252, /* (116) xfullname ::= nm AS nm */ + 247, /* (117) joinop ::= COMMA|JOIN */ + 247, /* (118) joinop ::= JOIN_KW JOIN */ + 247, /* (119) joinop ::= JOIN_KW nm JOIN */ + 247, /* (120) joinop ::= JOIN_KW nm nm JOIN */ + 249, /* (121) on_opt ::= ON expr */ + 249, /* (122) on_opt ::= */ + 248, /* (123) indexed_opt ::= */ + 248, /* (124) indexed_opt ::= INDEXED BY nm */ + 248, /* (125) indexed_opt ::= NOT INDEXED */ + 250, /* (126) using_opt ::= USING LP idlist RP */ + 250, /* (127) using_opt ::= */ + 238, /* (128) orderby_opt ::= */ + 238, /* (129) orderby_opt ::= ORDER BY sortlist */ + 220, /* (130) sortlist ::= sortlist COMMA expr sortorder */ + 220, /* (131) sortlist ::= expr sortorder */ + 209, /* (132) sortorder ::= ASC */ + 209, /* (133) sortorder ::= DESC */ + 209, /* (134) sortorder ::= */ + 236, /* (135) groupby_opt ::= */ + 236, /* (136) groupby_opt ::= GROUP BY nexprlist */ + 237, /* (137) having_opt ::= */ + 237, /* (138) having_opt ::= HAVING expr */ + 239, /* (139) limit_opt ::= */ + 239, /* (140) limit_opt ::= LIMIT expr */ + 239, /* (141) limit_opt ::= LIMIT expr OFFSET expr */ + 239, /* (142) limit_opt ::= LIMIT expr COMMA expr */ + 181, /* (143) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ + 235, /* (144) where_opt ::= */ + 235, /* (145) where_opt ::= WHERE expr */ + 181, /* (146) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ + 255, /* (147) setlist ::= setlist COMMA nm EQ expr */ + 255, /* (148) setlist ::= setlist COMMA LP idlist RP EQ expr */ + 255, /* (149) setlist ::= nm EQ expr */ + 255, /* (150) setlist ::= LP idlist RP EQ expr */ + 181, /* (151) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + 181, /* (152) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ + 258, /* (153) upsert ::= */ + 258, /* (154) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ + 258, /* (155) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ + 258, /* (156) upsert ::= ON CONFLICT DO NOTHING */ + 256, /* (157) insert_cmd ::= INSERT orconf */ + 256, /* (158) insert_cmd ::= REPLACE */ + 257, /* (159) idlist_opt ::= */ + 257, /* (160) idlist_opt ::= LP idlist RP */ + 253, /* (161) idlist ::= idlist COMMA nm */ + 253, /* (162) idlist ::= nm */ + 207, /* (163) expr ::= LP expr RP */ + 207, /* (164) expr ::= ID|INDEXED */ + 207, /* (165) expr ::= JOIN_KW */ + 207, /* (166) expr ::= nm DOT nm */ + 207, /* (167) expr ::= nm DOT nm DOT nm */ + 206, /* (168) term ::= NULL|FLOAT|BLOB */ + 206, /* (169) term ::= STRING */ + 206, /* (170) term ::= INTEGER */ + 207, /* (171) expr ::= VARIABLE */ + 207, /* (172) expr ::= expr COLLATE ID|STRING */ + 207, /* (173) expr ::= CAST LP expr AS typetoken RP */ + 207, /* (174) expr ::= ID|INDEXED LP distinct exprlist RP */ + 207, /* (175) expr ::= ID|INDEXED LP STAR RP */ + 207, /* (176) expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ + 207, /* (177) expr ::= ID|INDEXED LP STAR RP over_clause */ + 206, /* (178) term ::= CTIME_KW */ + 207, /* (179) expr ::= LP nexprlist COMMA expr RP */ + 207, /* (180) expr ::= expr AND expr */ + 207, /* (181) expr ::= expr OR expr */ + 207, /* (182) expr ::= expr LT|GT|GE|LE expr */ + 207, /* (183) expr ::= expr EQ|NE expr */ + 207, /* (184) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + 207, /* (185) expr ::= expr PLUS|MINUS expr */ + 207, /* (186) expr ::= expr STAR|SLASH|REM expr */ + 207, /* (187) expr ::= expr CONCAT expr */ + 260, /* (188) likeop ::= NOT LIKE_KW|MATCH */ + 207, /* (189) expr ::= expr likeop expr */ + 207, /* (190) expr ::= expr likeop expr ESCAPE expr */ + 207, /* (191) expr ::= expr ISNULL|NOTNULL */ + 207, /* (192) expr ::= expr NOT NULL */ + 207, /* (193) expr ::= expr IS expr */ + 207, /* (194) expr ::= expr IS NOT expr */ + 207, /* (195) expr ::= NOT expr */ + 207, /* (196) expr ::= BITNOT expr */ + 207, /* (197) expr ::= PLUS|MINUS expr */ + 261, /* (198) between_op ::= BETWEEN */ + 261, /* (199) between_op ::= NOT BETWEEN */ + 207, /* (200) expr ::= expr between_op expr AND expr */ + 262, /* (201) in_op ::= IN */ + 262, /* (202) in_op ::= NOT IN */ + 207, /* (203) expr ::= expr in_op LP exprlist RP */ + 207, /* (204) expr ::= LP select RP */ + 207, /* (205) expr ::= expr in_op LP select RP */ + 207, /* (206) expr ::= expr in_op nm dbnm paren_exprlist */ + 207, /* (207) expr ::= EXISTS LP select RP */ + 207, /* (208) expr ::= CASE case_operand case_exprlist case_else END */ + 265, /* (209) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + 265, /* (210) case_exprlist ::= WHEN expr THEN expr */ + 266, /* (211) case_else ::= ELSE expr */ + 266, /* (212) case_else ::= */ + 264, /* (213) case_operand ::= expr */ + 264, /* (214) case_operand ::= */ + 251, /* (215) exprlist ::= */ + 242, /* (216) nexprlist ::= nexprlist COMMA expr */ + 242, /* (217) nexprlist ::= expr */ + 263, /* (218) paren_exprlist ::= */ + 263, /* (219) paren_exprlist ::= LP exprlist RP */ + 181, /* (220) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + 267, /* (221) uniqueflag ::= UNIQUE */ + 267, /* (222) uniqueflag ::= */ + 211, /* (223) eidlist_opt ::= */ + 211, /* (224) eidlist_opt ::= LP eidlist RP */ + 221, /* (225) eidlist ::= eidlist COMMA nm collate sortorder */ + 221, /* (226) eidlist ::= nm collate sortorder */ + 268, /* (227) collate ::= */ + 268, /* (228) collate ::= COLLATE ID|STRING */ + 181, /* (229) cmd ::= DROP INDEX ifexists fullname */ + 181, /* (230) cmd ::= VACUUM vinto */ + 181, /* (231) cmd ::= VACUUM nm vinto */ + 269, /* (232) vinto ::= INTO expr */ + 269, /* (233) vinto ::= */ + 181, /* (234) cmd ::= PRAGMA nm dbnm */ + 181, /* (235) cmd ::= PRAGMA nm dbnm EQ nmnum */ + 181, /* (236) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + 181, /* (237) cmd ::= PRAGMA nm dbnm EQ minus_num */ + 181, /* (238) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + 201, /* (239) plus_num ::= PLUS INTEGER|FLOAT */ + 202, /* (240) minus_num ::= MINUS INTEGER|FLOAT */ + 181, /* (241) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + 271, /* (242) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + 273, /* (243) trigger_time ::= BEFORE|AFTER */ + 273, /* (244) trigger_time ::= INSTEAD OF */ + 273, /* (245) trigger_time ::= */ + 274, /* (246) trigger_event ::= DELETE|INSERT */ + 274, /* (247) trigger_event ::= UPDATE */ + 274, /* (248) trigger_event ::= UPDATE OF idlist */ + 276, /* (249) when_clause ::= */ + 276, /* (250) when_clause ::= WHEN expr */ + 272, /* (251) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + 272, /* (252) trigger_cmd_list ::= trigger_cmd SEMI */ + 278, /* (253) trnm ::= nm DOT nm */ + 279, /* (254) tridxby ::= INDEXED BY nm */ + 279, /* (255) tridxby ::= NOT INDEXED */ + 277, /* (256) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ + 277, /* (257) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + 277, /* (258) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + 277, /* (259) trigger_cmd ::= scanpt select scanpt */ + 207, /* (260) expr ::= RAISE LP IGNORE RP */ + 207, /* (261) expr ::= RAISE LP raisetype COMMA nm RP */ + 225, /* (262) raisetype ::= ROLLBACK */ + 225, /* (263) raisetype ::= ABORT */ + 225, /* (264) raisetype ::= FAIL */ + 181, /* (265) cmd ::= DROP TRIGGER ifexists fullname */ + 181, /* (266) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + 181, /* (267) cmd ::= DETACH database_kw_opt expr */ + 281, /* (268) key_opt ::= */ + 281, /* (269) key_opt ::= KEY expr */ + 181, /* (270) cmd ::= REINDEX */ + 181, /* (271) cmd ::= REINDEX nm dbnm */ + 181, /* (272) cmd ::= ANALYZE */ + 181, /* (273) cmd ::= ANALYZE nm dbnm */ + 181, /* (274) cmd ::= ALTER TABLE fullname RENAME TO nm */ + 181, /* (275) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + 282, /* (276) add_column_fullname ::= fullname */ + 181, /* (277) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + 181, /* (278) cmd ::= create_vtab */ + 181, /* (279) cmd ::= create_vtab LP vtabarglist RP */ + 284, /* (280) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 286, /* (281) vtabarg ::= */ + 287, /* (282) vtabargtoken ::= ANY */ + 287, /* (283) vtabargtoken ::= lp anylist RP */ + 288, /* (284) lp ::= LP */ + 254, /* (285) with ::= WITH wqlist */ + 254, /* (286) with ::= WITH RECURSIVE wqlist */ + 230, /* (287) wqlist ::= nm eidlist_opt AS LP select RP */ + 230, /* (288) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ + 290, /* (289) windowdefn_list ::= windowdefn */ + 290, /* (290) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + 291, /* (291) windowdefn ::= nm AS LP window RP */ + 292, /* (292) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + 292, /* (293) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + 292, /* (294) window ::= ORDER BY sortlist frame_opt */ + 292, /* (295) window ::= nm ORDER BY sortlist frame_opt */ + 292, /* (296) window ::= frame_opt */ + 292, /* (297) window ::= nm frame_opt */ + 293, /* (298) frame_opt ::= */ + 293, /* (299) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + 293, /* (300) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + 296, /* (301) range_or_rows ::= RANGE|ROWS|GROUPS */ + 298, /* (302) frame_bound_s ::= frame_bound */ + 298, /* (303) frame_bound_s ::= UNBOUNDED PRECEDING */ + 299, /* (304) frame_bound_e ::= frame_bound */ + 299, /* (305) frame_bound_e ::= UNBOUNDED FOLLOWING */ + 297, /* (306) frame_bound ::= expr PRECEDING|FOLLOWING */ + 297, /* (307) frame_bound ::= CURRENT ROW */ + 300, /* (308) frame_exclude_opt ::= */ + 300, /* (309) frame_exclude_opt ::= EXCLUDE frame_exclude */ + 301, /* (310) frame_exclude ::= NO OTHERS */ + 301, /* (311) frame_exclude ::= CURRENT ROW */ + 301, /* (312) frame_exclude ::= GROUP|TIES */ + 240, /* (313) window_clause ::= WINDOW windowdefn_list */ + 259, /* (314) over_clause ::= filter_opt OVER LP window RP */ + 259, /* (315) over_clause ::= filter_opt OVER nm */ + 295, /* (316) filter_opt ::= */ + 295, /* (317) filter_opt ::= FILTER LP WHERE expr RP */ + 176, /* (318) input ::= cmdlist */ + 177, /* (319) cmdlist ::= cmdlist ecmd */ + 177, /* (320) cmdlist ::= ecmd */ + 178, /* (321) ecmd ::= SEMI */ + 178, /* (322) ecmd ::= cmdx SEMI */ + 178, /* (323) ecmd ::= explain cmdx */ + 183, /* (324) trans_opt ::= */ + 183, /* (325) trans_opt ::= TRANSACTION */ + 183, /* (326) trans_opt ::= TRANSACTION nm */ + 185, /* (327) savepoint_opt ::= SAVEPOINT */ + 185, /* (328) savepoint_opt ::= */ + 181, /* (329) cmd ::= create_table create_table_args */ + 192, /* (330) columnlist ::= columnlist COMMA columnname carglist */ + 192, /* (331) columnlist ::= columnname carglist */ + 184, /* (332) nm ::= ID|INDEXED */ + 184, /* (333) nm ::= STRING */ + 184, /* (334) nm ::= JOIN_KW */ + 198, /* (335) typetoken ::= typename */ + 199, /* (336) typename ::= ID|STRING */ + 200, /* (337) signed ::= plus_num */ + 200, /* (338) signed ::= minus_num */ + 197, /* (339) carglist ::= carglist ccons */ + 197, /* (340) carglist ::= */ + 205, /* (341) ccons ::= NULL onconf */ + 193, /* (342) conslist_opt ::= COMMA conslist */ + 217, /* (343) conslist ::= conslist tconscomma tcons */ + 217, /* (344) conslist ::= tcons */ + 218, /* (345) tconscomma ::= */ + 222, /* (346) defer_subclause_opt ::= defer_subclause */ + 224, /* (347) resolvetype ::= raisetype */ + 228, /* (348) selectnowith ::= oneselect */ + 229, /* (349) oneselect ::= values */ + 243, /* (350) sclp ::= selcollist COMMA */ + 244, /* (351) as ::= ID|STRING */ + 207, /* (352) expr ::= term */ + 260, /* (353) likeop ::= LIKE_KW|MATCH */ + 251, /* (354) exprlist ::= nexprlist */ + 270, /* (355) nmnum ::= plus_num */ + 270, /* (356) nmnum ::= nm */ + 270, /* (357) nmnum ::= ON */ + 270, /* (358) nmnum ::= DELETE */ + 270, /* (359) nmnum ::= DEFAULT */ + 201, /* (360) plus_num ::= INTEGER|FLOAT */ + 275, /* (361) foreach_clause ::= */ + 275, /* (362) foreach_clause ::= FOR EACH ROW */ + 278, /* (363) trnm ::= nm */ + 279, /* (364) tridxby ::= */ + 280, /* (365) database_kw_opt ::= DATABASE */ + 280, /* (366) database_kw_opt ::= */ + 283, /* (367) kwcolumn_opt ::= */ + 283, /* (368) kwcolumn_opt ::= COLUMNKW */ + 285, /* (369) vtabarglist ::= vtabarg */ + 285, /* (370) vtabarglist ::= vtabarglist COMMA vtabarg */ + 286, /* (371) vtabarg ::= vtabarg vtabargtoken */ + 289, /* (372) anylist ::= */ + 289, /* (373) anylist ::= anylist LP anylist RP */ + 289, /* (374) anylist ::= anylist ANY */ + 254, /* (375) with ::= */ }; /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number @@ -149991,346 +151456,353 @@ static const signed char yyRuleInfoNRhs[] = { -6, /* (26) typetoken ::= typename LP signed COMMA signed RP */ -2, /* (27) typename ::= typename ID|STRING */ 0, /* (28) scanpt ::= */ - -2, /* (29) ccons ::= CONSTRAINT nm */ - -4, /* (30) ccons ::= DEFAULT scanpt term scanpt */ - -4, /* (31) ccons ::= DEFAULT LP expr RP */ - -4, /* (32) ccons ::= DEFAULT PLUS term scanpt */ - -4, /* (33) ccons ::= DEFAULT MINUS term scanpt */ - -3, /* (34) ccons ::= DEFAULT scanpt ID|INDEXED */ - -3, /* (35) ccons ::= NOT NULL onconf */ - -5, /* (36) ccons ::= PRIMARY KEY sortorder onconf autoinc */ - -2, /* (37) ccons ::= UNIQUE onconf */ - -4, /* (38) ccons ::= CHECK LP expr RP */ - -4, /* (39) ccons ::= REFERENCES nm eidlist_opt refargs */ - -1, /* (40) ccons ::= defer_subclause */ - -2, /* (41) ccons ::= COLLATE ID|STRING */ - 0, /* (42) autoinc ::= */ - -1, /* (43) autoinc ::= AUTOINCR */ - 0, /* (44) refargs ::= */ - -2, /* (45) refargs ::= refargs refarg */ - -2, /* (46) refarg ::= MATCH nm */ - -3, /* (47) refarg ::= ON INSERT refact */ - -3, /* (48) refarg ::= ON DELETE refact */ - -3, /* (49) refarg ::= ON UPDATE refact */ - -2, /* (50) refact ::= SET NULL */ - -2, /* (51) refact ::= SET DEFAULT */ - -1, /* (52) refact ::= CASCADE */ - -1, /* (53) refact ::= RESTRICT */ - -2, /* (54) refact ::= NO ACTION */ - -3, /* (55) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ - -2, /* (56) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - 0, /* (57) init_deferred_pred_opt ::= */ - -2, /* (58) init_deferred_pred_opt ::= INITIALLY DEFERRED */ - -2, /* (59) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ - 0, /* (60) conslist_opt ::= */ - -1, /* (61) tconscomma ::= COMMA */ - -2, /* (62) tcons ::= CONSTRAINT nm */ - -7, /* (63) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ - -5, /* (64) tcons ::= UNIQUE LP sortlist RP onconf */ - -5, /* (65) tcons ::= CHECK LP expr RP onconf */ - -10, /* (66) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ - 0, /* (67) defer_subclause_opt ::= */ - 0, /* (68) onconf ::= */ - -3, /* (69) onconf ::= ON CONFLICT resolvetype */ - 0, /* (70) orconf ::= */ - -2, /* (71) orconf ::= OR resolvetype */ - -1, /* (72) resolvetype ::= IGNORE */ - -1, /* (73) resolvetype ::= REPLACE */ - -4, /* (74) cmd ::= DROP TABLE ifexists fullname */ - -2, /* (75) ifexists ::= IF EXISTS */ - 0, /* (76) ifexists ::= */ - -9, /* (77) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ - -4, /* (78) cmd ::= DROP VIEW ifexists fullname */ - -1, /* (79) cmd ::= select */ - -3, /* (80) select ::= WITH wqlist selectnowith */ - -4, /* (81) select ::= WITH RECURSIVE wqlist selectnowith */ - -1, /* (82) select ::= selectnowith */ - -3, /* (83) selectnowith ::= selectnowith multiselect_op oneselect */ - -1, /* (84) multiselect_op ::= UNION */ - -2, /* (85) multiselect_op ::= UNION ALL */ - -1, /* (86) multiselect_op ::= EXCEPT|INTERSECT */ - -9, /* (87) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ - -10, /* (88) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ - -4, /* (89) values ::= VALUES LP nexprlist RP */ - -5, /* (90) values ::= values COMMA LP nexprlist RP */ - -1, /* (91) distinct ::= DISTINCT */ - -1, /* (92) distinct ::= ALL */ - 0, /* (93) distinct ::= */ - 0, /* (94) sclp ::= */ - -5, /* (95) selcollist ::= sclp scanpt expr scanpt as */ - -3, /* (96) selcollist ::= sclp scanpt STAR */ - -5, /* (97) selcollist ::= sclp scanpt nm DOT STAR */ - -2, /* (98) as ::= AS nm */ - 0, /* (99) as ::= */ - 0, /* (100) from ::= */ - -2, /* (101) from ::= FROM seltablist */ - -2, /* (102) stl_prefix ::= seltablist joinop */ - 0, /* (103) stl_prefix ::= */ - -7, /* (104) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ - -9, /* (105) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ - -7, /* (106) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ - -7, /* (107) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ - 0, /* (108) dbnm ::= */ - -2, /* (109) dbnm ::= DOT nm */ - -1, /* (110) fullname ::= nm */ - -3, /* (111) fullname ::= nm DOT nm */ - -1, /* (112) xfullname ::= nm */ - -3, /* (113) xfullname ::= nm DOT nm */ - -5, /* (114) xfullname ::= nm DOT nm AS nm */ - -3, /* (115) xfullname ::= nm AS nm */ - -1, /* (116) joinop ::= COMMA|JOIN */ - -2, /* (117) joinop ::= JOIN_KW JOIN */ - -3, /* (118) joinop ::= JOIN_KW nm JOIN */ - -4, /* (119) joinop ::= JOIN_KW nm nm JOIN */ - -2, /* (120) on_opt ::= ON expr */ - 0, /* (121) on_opt ::= */ - 0, /* (122) indexed_opt ::= */ - -3, /* (123) indexed_opt ::= INDEXED BY nm */ - -2, /* (124) indexed_opt ::= NOT INDEXED */ - -4, /* (125) using_opt ::= USING LP idlist RP */ - 0, /* (126) using_opt ::= */ - 0, /* (127) orderby_opt ::= */ - -3, /* (128) orderby_opt ::= ORDER BY sortlist */ - -4, /* (129) sortlist ::= sortlist COMMA expr sortorder */ - -2, /* (130) sortlist ::= expr sortorder */ - -1, /* (131) sortorder ::= ASC */ - -1, /* (132) sortorder ::= DESC */ - 0, /* (133) sortorder ::= */ - 0, /* (134) groupby_opt ::= */ - -3, /* (135) groupby_opt ::= GROUP BY nexprlist */ - 0, /* (136) having_opt ::= */ - -2, /* (137) having_opt ::= HAVING expr */ - 0, /* (138) limit_opt ::= */ - -2, /* (139) limit_opt ::= LIMIT expr */ - -4, /* (140) limit_opt ::= LIMIT expr OFFSET expr */ - -4, /* (141) limit_opt ::= LIMIT expr COMMA expr */ - -6, /* (142) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ - 0, /* (143) where_opt ::= */ - -2, /* (144) where_opt ::= WHERE expr */ - -8, /* (145) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ - -5, /* (146) setlist ::= setlist COMMA nm EQ expr */ - -7, /* (147) setlist ::= setlist COMMA LP idlist RP EQ expr */ - -3, /* (148) setlist ::= nm EQ expr */ - -5, /* (149) setlist ::= LP idlist RP EQ expr */ - -7, /* (150) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ - -7, /* (151) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ - 0, /* (152) upsert ::= */ - -11, /* (153) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ - -8, /* (154) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ - -4, /* (155) upsert ::= ON CONFLICT DO NOTHING */ - -2, /* (156) insert_cmd ::= INSERT orconf */ - -1, /* (157) insert_cmd ::= REPLACE */ - 0, /* (158) idlist_opt ::= */ - -3, /* (159) idlist_opt ::= LP idlist RP */ - -3, /* (160) idlist ::= idlist COMMA nm */ - -1, /* (161) idlist ::= nm */ - -3, /* (162) expr ::= LP expr RP */ - -1, /* (163) expr ::= ID|INDEXED */ - -1, /* (164) expr ::= JOIN_KW */ - -3, /* (165) expr ::= nm DOT nm */ - -5, /* (166) expr ::= nm DOT nm DOT nm */ - -1, /* (167) term ::= NULL|FLOAT|BLOB */ - -1, /* (168) term ::= STRING */ - -1, /* (169) term ::= INTEGER */ - -1, /* (170) expr ::= VARIABLE */ - -3, /* (171) expr ::= expr COLLATE ID|STRING */ - -6, /* (172) expr ::= CAST LP expr AS typetoken RP */ - -5, /* (173) expr ::= ID|INDEXED LP distinct exprlist RP */ - -4, /* (174) expr ::= ID|INDEXED LP STAR RP */ - -6, /* (175) expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ - -5, /* (176) expr ::= ID|INDEXED LP STAR RP over_clause */ - -1, /* (177) term ::= CTIME_KW */ - -5, /* (178) expr ::= LP nexprlist COMMA expr RP */ - -3, /* (179) expr ::= expr AND expr */ - -3, /* (180) expr ::= expr OR expr */ - -3, /* (181) expr ::= expr LT|GT|GE|LE expr */ - -3, /* (182) expr ::= expr EQ|NE expr */ - -3, /* (183) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ - -3, /* (184) expr ::= expr PLUS|MINUS expr */ - -3, /* (185) expr ::= expr STAR|SLASH|REM expr */ - -3, /* (186) expr ::= expr CONCAT expr */ - -2, /* (187) likeop ::= NOT LIKE_KW|MATCH */ - -3, /* (188) expr ::= expr likeop expr */ - -5, /* (189) expr ::= expr likeop expr ESCAPE expr */ - -2, /* (190) expr ::= expr ISNULL|NOTNULL */ - -3, /* (191) expr ::= expr NOT NULL */ - -3, /* (192) expr ::= expr IS expr */ - -4, /* (193) expr ::= expr IS NOT expr */ - -2, /* (194) expr ::= NOT expr */ - -2, /* (195) expr ::= BITNOT expr */ - -2, /* (196) expr ::= PLUS|MINUS expr */ - -1, /* (197) between_op ::= BETWEEN */ - -2, /* (198) between_op ::= NOT BETWEEN */ - -5, /* (199) expr ::= expr between_op expr AND expr */ - -1, /* (200) in_op ::= IN */ - -2, /* (201) in_op ::= NOT IN */ - -5, /* (202) expr ::= expr in_op LP exprlist RP */ - -3, /* (203) expr ::= LP select RP */ - -5, /* (204) expr ::= expr in_op LP select RP */ - -5, /* (205) expr ::= expr in_op nm dbnm paren_exprlist */ - -4, /* (206) expr ::= EXISTS LP select RP */ - -5, /* (207) expr ::= CASE case_operand case_exprlist case_else END */ - -5, /* (208) case_exprlist ::= case_exprlist WHEN expr THEN expr */ - -4, /* (209) case_exprlist ::= WHEN expr THEN expr */ - -2, /* (210) case_else ::= ELSE expr */ - 0, /* (211) case_else ::= */ - -1, /* (212) case_operand ::= expr */ - 0, /* (213) case_operand ::= */ - 0, /* (214) exprlist ::= */ - -3, /* (215) nexprlist ::= nexprlist COMMA expr */ - -1, /* (216) nexprlist ::= expr */ - 0, /* (217) paren_exprlist ::= */ - -3, /* (218) paren_exprlist ::= LP exprlist RP */ - -12, /* (219) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ - -1, /* (220) uniqueflag ::= UNIQUE */ - 0, /* (221) uniqueflag ::= */ - 0, /* (222) eidlist_opt ::= */ - -3, /* (223) eidlist_opt ::= LP eidlist RP */ - -5, /* (224) eidlist ::= eidlist COMMA nm collate sortorder */ - -3, /* (225) eidlist ::= nm collate sortorder */ - 0, /* (226) collate ::= */ - -2, /* (227) collate ::= COLLATE ID|STRING */ - -4, /* (228) cmd ::= DROP INDEX ifexists fullname */ - -2, /* (229) cmd ::= VACUUM vinto */ - -3, /* (230) cmd ::= VACUUM nm vinto */ - -2, /* (231) vinto ::= INTO expr */ - 0, /* (232) vinto ::= */ - -3, /* (233) cmd ::= PRAGMA nm dbnm */ - -5, /* (234) cmd ::= PRAGMA nm dbnm EQ nmnum */ - -6, /* (235) cmd ::= PRAGMA nm dbnm LP nmnum RP */ - -5, /* (236) cmd ::= PRAGMA nm dbnm EQ minus_num */ - -6, /* (237) cmd ::= PRAGMA nm dbnm LP minus_num RP */ - -2, /* (238) plus_num ::= PLUS INTEGER|FLOAT */ - -2, /* (239) minus_num ::= MINUS INTEGER|FLOAT */ - -5, /* (240) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ - -11, /* (241) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ - -1, /* (242) trigger_time ::= BEFORE|AFTER */ - -2, /* (243) trigger_time ::= INSTEAD OF */ - 0, /* (244) trigger_time ::= */ - -1, /* (245) trigger_event ::= DELETE|INSERT */ - -1, /* (246) trigger_event ::= UPDATE */ - -3, /* (247) trigger_event ::= UPDATE OF idlist */ - 0, /* (248) when_clause ::= */ - -2, /* (249) when_clause ::= WHEN expr */ - -3, /* (250) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ - -2, /* (251) trigger_cmd_list ::= trigger_cmd SEMI */ - -3, /* (252) trnm ::= nm DOT nm */ - -3, /* (253) tridxby ::= INDEXED BY nm */ - -2, /* (254) tridxby ::= NOT INDEXED */ - -8, /* (255) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ - -8, /* (256) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - -6, /* (257) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - -3, /* (258) trigger_cmd ::= scanpt select scanpt */ - -4, /* (259) expr ::= RAISE LP IGNORE RP */ - -6, /* (260) expr ::= RAISE LP raisetype COMMA nm RP */ - -1, /* (261) raisetype ::= ROLLBACK */ - -1, /* (262) raisetype ::= ABORT */ - -1, /* (263) raisetype ::= FAIL */ - -4, /* (264) cmd ::= DROP TRIGGER ifexists fullname */ - -6, /* (265) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - -3, /* (266) cmd ::= DETACH database_kw_opt expr */ - 0, /* (267) key_opt ::= */ - -2, /* (268) key_opt ::= KEY expr */ - -1, /* (269) cmd ::= REINDEX */ - -3, /* (270) cmd ::= REINDEX nm dbnm */ - -1, /* (271) cmd ::= ANALYZE */ - -3, /* (272) cmd ::= ANALYZE nm dbnm */ - -6, /* (273) cmd ::= ALTER TABLE fullname RENAME TO nm */ - -7, /* (274) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ - -1, /* (275) add_column_fullname ::= fullname */ - -8, /* (276) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - -1, /* (277) cmd ::= create_vtab */ - -4, /* (278) cmd ::= create_vtab LP vtabarglist RP */ - -8, /* (279) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 0, /* (280) vtabarg ::= */ - -1, /* (281) vtabargtoken ::= ANY */ - -3, /* (282) vtabargtoken ::= lp anylist RP */ - -1, /* (283) lp ::= LP */ - -2, /* (284) with ::= WITH wqlist */ - -3, /* (285) with ::= WITH RECURSIVE wqlist */ - -6, /* (286) wqlist ::= nm eidlist_opt AS LP select RP */ - -8, /* (287) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ - -1, /* (288) windowdefn_list ::= windowdefn */ - -3, /* (289) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - -3, /* (290) windowdefn ::= nm AS window */ - -5, /* (291) window ::= LP part_opt orderby_opt frame_opt RP */ - -3, /* (292) part_opt ::= PARTITION BY nexprlist */ - 0, /* (293) part_opt ::= */ - 0, /* (294) frame_opt ::= */ - -2, /* (295) frame_opt ::= range_or_rows frame_bound_s */ - -5, /* (296) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e */ - -1, /* (297) range_or_rows ::= RANGE */ - -1, /* (298) range_or_rows ::= ROWS */ - -1, /* (299) frame_bound_s ::= frame_bound */ - -2, /* (300) frame_bound_s ::= UNBOUNDED PRECEDING */ - -1, /* (301) frame_bound_e ::= frame_bound */ - -2, /* (302) frame_bound_e ::= UNBOUNDED FOLLOWING */ - -2, /* (303) frame_bound ::= expr PRECEDING */ - -2, /* (304) frame_bound ::= CURRENT ROW */ - -2, /* (305) frame_bound ::= expr FOLLOWING */ - -2, /* (306) window_clause ::= WINDOW windowdefn_list */ - -3, /* (307) over_clause ::= filter_opt OVER window */ - -3, /* (308) over_clause ::= filter_opt OVER nm */ - 0, /* (309) filter_opt ::= */ - -5, /* (310) filter_opt ::= FILTER LP WHERE expr RP */ - -1, /* (311) input ::= cmdlist */ - -2, /* (312) cmdlist ::= cmdlist ecmd */ - -1, /* (313) cmdlist ::= ecmd */ - -1, /* (314) ecmd ::= SEMI */ - -2, /* (315) ecmd ::= cmdx SEMI */ - -2, /* (316) ecmd ::= explain cmdx */ - 0, /* (317) trans_opt ::= */ - -1, /* (318) trans_opt ::= TRANSACTION */ - -2, /* (319) trans_opt ::= TRANSACTION nm */ - -1, /* (320) savepoint_opt ::= SAVEPOINT */ - 0, /* (321) savepoint_opt ::= */ - -2, /* (322) cmd ::= create_table create_table_args */ - -4, /* (323) columnlist ::= columnlist COMMA columnname carglist */ - -2, /* (324) columnlist ::= columnname carglist */ - -1, /* (325) nm ::= ID|INDEXED */ - -1, /* (326) nm ::= STRING */ - -1, /* (327) nm ::= JOIN_KW */ - -1, /* (328) typetoken ::= typename */ - -1, /* (329) typename ::= ID|STRING */ - -1, /* (330) signed ::= plus_num */ - -1, /* (331) signed ::= minus_num */ - -2, /* (332) carglist ::= carglist ccons */ - 0, /* (333) carglist ::= */ - -2, /* (334) ccons ::= NULL onconf */ - -2, /* (335) conslist_opt ::= COMMA conslist */ - -3, /* (336) conslist ::= conslist tconscomma tcons */ - -1, /* (337) conslist ::= tcons */ - 0, /* (338) tconscomma ::= */ - -1, /* (339) defer_subclause_opt ::= defer_subclause */ - -1, /* (340) resolvetype ::= raisetype */ - -1, /* (341) selectnowith ::= oneselect */ - -1, /* (342) oneselect ::= values */ - -2, /* (343) sclp ::= selcollist COMMA */ - -1, /* (344) as ::= ID|STRING */ - -1, /* (345) expr ::= term */ - -1, /* (346) likeop ::= LIKE_KW|MATCH */ - -1, /* (347) exprlist ::= nexprlist */ - -1, /* (348) nmnum ::= plus_num */ - -1, /* (349) nmnum ::= nm */ - -1, /* (350) nmnum ::= ON */ - -1, /* (351) nmnum ::= DELETE */ - -1, /* (352) nmnum ::= DEFAULT */ - -1, /* (353) plus_num ::= INTEGER|FLOAT */ - 0, /* (354) foreach_clause ::= */ - -3, /* (355) foreach_clause ::= FOR EACH ROW */ - -1, /* (356) trnm ::= nm */ - 0, /* (357) tridxby ::= */ - -1, /* (358) database_kw_opt ::= DATABASE */ - 0, /* (359) database_kw_opt ::= */ - 0, /* (360) kwcolumn_opt ::= */ - -1, /* (361) kwcolumn_opt ::= COLUMNKW */ - -1, /* (362) vtabarglist ::= vtabarg */ - -3, /* (363) vtabarglist ::= vtabarglist COMMA vtabarg */ - -2, /* (364) vtabarg ::= vtabarg vtabargtoken */ - 0, /* (365) anylist ::= */ - -4, /* (366) anylist ::= anylist LP anylist RP */ - -2, /* (367) anylist ::= anylist ANY */ - 0, /* (368) with ::= */ + 0, /* (29) scantok ::= */ + -2, /* (30) ccons ::= CONSTRAINT nm */ + -3, /* (31) ccons ::= DEFAULT scantok term */ + -4, /* (32) ccons ::= DEFAULT LP expr RP */ + -4, /* (33) ccons ::= DEFAULT PLUS scantok term */ + -4, /* (34) ccons ::= DEFAULT MINUS scantok term */ + -3, /* (35) ccons ::= DEFAULT scantok ID|INDEXED */ + -3, /* (36) ccons ::= NOT NULL onconf */ + -5, /* (37) ccons ::= PRIMARY KEY sortorder onconf autoinc */ + -2, /* (38) ccons ::= UNIQUE onconf */ + -4, /* (39) ccons ::= CHECK LP expr RP */ + -4, /* (40) ccons ::= REFERENCES nm eidlist_opt refargs */ + -1, /* (41) ccons ::= defer_subclause */ + -2, /* (42) ccons ::= COLLATE ID|STRING */ + 0, /* (43) autoinc ::= */ + -1, /* (44) autoinc ::= AUTOINCR */ + 0, /* (45) refargs ::= */ + -2, /* (46) refargs ::= refargs refarg */ + -2, /* (47) refarg ::= MATCH nm */ + -3, /* (48) refarg ::= ON INSERT refact */ + -3, /* (49) refarg ::= ON DELETE refact */ + -3, /* (50) refarg ::= ON UPDATE refact */ + -2, /* (51) refact ::= SET NULL */ + -2, /* (52) refact ::= SET DEFAULT */ + -1, /* (53) refact ::= CASCADE */ + -1, /* (54) refact ::= RESTRICT */ + -2, /* (55) refact ::= NO ACTION */ + -3, /* (56) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ + -2, /* (57) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + 0, /* (58) init_deferred_pred_opt ::= */ + -2, /* (59) init_deferred_pred_opt ::= INITIALLY DEFERRED */ + -2, /* (60) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ + 0, /* (61) conslist_opt ::= */ + -1, /* (62) tconscomma ::= COMMA */ + -2, /* (63) tcons ::= CONSTRAINT nm */ + -7, /* (64) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ + -5, /* (65) tcons ::= UNIQUE LP sortlist RP onconf */ + -5, /* (66) tcons ::= CHECK LP expr RP onconf */ + -10, /* (67) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + 0, /* (68) defer_subclause_opt ::= */ + 0, /* (69) onconf ::= */ + -3, /* (70) onconf ::= ON CONFLICT resolvetype */ + 0, /* (71) orconf ::= */ + -2, /* (72) orconf ::= OR resolvetype */ + -1, /* (73) resolvetype ::= IGNORE */ + -1, /* (74) resolvetype ::= REPLACE */ + -4, /* (75) cmd ::= DROP TABLE ifexists fullname */ + -2, /* (76) ifexists ::= IF EXISTS */ + 0, /* (77) ifexists ::= */ + -9, /* (78) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + -4, /* (79) cmd ::= DROP VIEW ifexists fullname */ + -1, /* (80) cmd ::= select */ + -3, /* (81) select ::= WITH wqlist selectnowith */ + -4, /* (82) select ::= WITH RECURSIVE wqlist selectnowith */ + -1, /* (83) select ::= selectnowith */ + -3, /* (84) selectnowith ::= selectnowith multiselect_op oneselect */ + -1, /* (85) multiselect_op ::= UNION */ + -2, /* (86) multiselect_op ::= UNION ALL */ + -1, /* (87) multiselect_op ::= EXCEPT|INTERSECT */ + -9, /* (88) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + -10, /* (89) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + -4, /* (90) values ::= VALUES LP nexprlist RP */ + -5, /* (91) values ::= values COMMA LP nexprlist RP */ + -1, /* (92) distinct ::= DISTINCT */ + -1, /* (93) distinct ::= ALL */ + 0, /* (94) distinct ::= */ + 0, /* (95) sclp ::= */ + -5, /* (96) selcollist ::= sclp scanpt expr scanpt as */ + -3, /* (97) selcollist ::= sclp scanpt STAR */ + -5, /* (98) selcollist ::= sclp scanpt nm DOT STAR */ + -2, /* (99) as ::= AS nm */ + 0, /* (100) as ::= */ + 0, /* (101) from ::= */ + -2, /* (102) from ::= FROM seltablist */ + -2, /* (103) stl_prefix ::= seltablist joinop */ + 0, /* (104) stl_prefix ::= */ + -7, /* (105) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + -9, /* (106) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + -7, /* (107) seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + -7, /* (108) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + 0, /* (109) dbnm ::= */ + -2, /* (110) dbnm ::= DOT nm */ + -1, /* (111) fullname ::= nm */ + -3, /* (112) fullname ::= nm DOT nm */ + -1, /* (113) xfullname ::= nm */ + -3, /* (114) xfullname ::= nm DOT nm */ + -5, /* (115) xfullname ::= nm DOT nm AS nm */ + -3, /* (116) xfullname ::= nm AS nm */ + -1, /* (117) joinop ::= COMMA|JOIN */ + -2, /* (118) joinop ::= JOIN_KW JOIN */ + -3, /* (119) joinop ::= JOIN_KW nm JOIN */ + -4, /* (120) joinop ::= JOIN_KW nm nm JOIN */ + -2, /* (121) on_opt ::= ON expr */ + 0, /* (122) on_opt ::= */ + 0, /* (123) indexed_opt ::= */ + -3, /* (124) indexed_opt ::= INDEXED BY nm */ + -2, /* (125) indexed_opt ::= NOT INDEXED */ + -4, /* (126) using_opt ::= USING LP idlist RP */ + 0, /* (127) using_opt ::= */ + 0, /* (128) orderby_opt ::= */ + -3, /* (129) orderby_opt ::= ORDER BY sortlist */ + -4, /* (130) sortlist ::= sortlist COMMA expr sortorder */ + -2, /* (131) sortlist ::= expr sortorder */ + -1, /* (132) sortorder ::= ASC */ + -1, /* (133) sortorder ::= DESC */ + 0, /* (134) sortorder ::= */ + 0, /* (135) groupby_opt ::= */ + -3, /* (136) groupby_opt ::= GROUP BY nexprlist */ + 0, /* (137) having_opt ::= */ + -2, /* (138) having_opt ::= HAVING expr */ + 0, /* (139) limit_opt ::= */ + -2, /* (140) limit_opt ::= LIMIT expr */ + -4, /* (141) limit_opt ::= LIMIT expr OFFSET expr */ + -4, /* (142) limit_opt ::= LIMIT expr COMMA expr */ + -6, /* (143) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ + 0, /* (144) where_opt ::= */ + -2, /* (145) where_opt ::= WHERE expr */ + -8, /* (146) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ + -5, /* (147) setlist ::= setlist COMMA nm EQ expr */ + -7, /* (148) setlist ::= setlist COMMA LP idlist RP EQ expr */ + -3, /* (149) setlist ::= nm EQ expr */ + -5, /* (150) setlist ::= LP idlist RP EQ expr */ + -7, /* (151) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + -7, /* (152) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ + 0, /* (153) upsert ::= */ + -11, /* (154) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ + -8, /* (155) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ + -4, /* (156) upsert ::= ON CONFLICT DO NOTHING */ + -2, /* (157) insert_cmd ::= INSERT orconf */ + -1, /* (158) insert_cmd ::= REPLACE */ + 0, /* (159) idlist_opt ::= */ + -3, /* (160) idlist_opt ::= LP idlist RP */ + -3, /* (161) idlist ::= idlist COMMA nm */ + -1, /* (162) idlist ::= nm */ + -3, /* (163) expr ::= LP expr RP */ + -1, /* (164) expr ::= ID|INDEXED */ + -1, /* (165) expr ::= JOIN_KW */ + -3, /* (166) expr ::= nm DOT nm */ + -5, /* (167) expr ::= nm DOT nm DOT nm */ + -1, /* (168) term ::= NULL|FLOAT|BLOB */ + -1, /* (169) term ::= STRING */ + -1, /* (170) term ::= INTEGER */ + -1, /* (171) expr ::= VARIABLE */ + -3, /* (172) expr ::= expr COLLATE ID|STRING */ + -6, /* (173) expr ::= CAST LP expr AS typetoken RP */ + -5, /* (174) expr ::= ID|INDEXED LP distinct exprlist RP */ + -4, /* (175) expr ::= ID|INDEXED LP STAR RP */ + -6, /* (176) expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ + -5, /* (177) expr ::= ID|INDEXED LP STAR RP over_clause */ + -1, /* (178) term ::= CTIME_KW */ + -5, /* (179) expr ::= LP nexprlist COMMA expr RP */ + -3, /* (180) expr ::= expr AND expr */ + -3, /* (181) expr ::= expr OR expr */ + -3, /* (182) expr ::= expr LT|GT|GE|LE expr */ + -3, /* (183) expr ::= expr EQ|NE expr */ + -3, /* (184) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ + -3, /* (185) expr ::= expr PLUS|MINUS expr */ + -3, /* (186) expr ::= expr STAR|SLASH|REM expr */ + -3, /* (187) expr ::= expr CONCAT expr */ + -2, /* (188) likeop ::= NOT LIKE_KW|MATCH */ + -3, /* (189) expr ::= expr likeop expr */ + -5, /* (190) expr ::= expr likeop expr ESCAPE expr */ + -2, /* (191) expr ::= expr ISNULL|NOTNULL */ + -3, /* (192) expr ::= expr NOT NULL */ + -3, /* (193) expr ::= expr IS expr */ + -4, /* (194) expr ::= expr IS NOT expr */ + -2, /* (195) expr ::= NOT expr */ + -2, /* (196) expr ::= BITNOT expr */ + -2, /* (197) expr ::= PLUS|MINUS expr */ + -1, /* (198) between_op ::= BETWEEN */ + -2, /* (199) between_op ::= NOT BETWEEN */ + -5, /* (200) expr ::= expr between_op expr AND expr */ + -1, /* (201) in_op ::= IN */ + -2, /* (202) in_op ::= NOT IN */ + -5, /* (203) expr ::= expr in_op LP exprlist RP */ + -3, /* (204) expr ::= LP select RP */ + -5, /* (205) expr ::= expr in_op LP select RP */ + -5, /* (206) expr ::= expr in_op nm dbnm paren_exprlist */ + -4, /* (207) expr ::= EXISTS LP select RP */ + -5, /* (208) expr ::= CASE case_operand case_exprlist case_else END */ + -5, /* (209) case_exprlist ::= case_exprlist WHEN expr THEN expr */ + -4, /* (210) case_exprlist ::= WHEN expr THEN expr */ + -2, /* (211) case_else ::= ELSE expr */ + 0, /* (212) case_else ::= */ + -1, /* (213) case_operand ::= expr */ + 0, /* (214) case_operand ::= */ + 0, /* (215) exprlist ::= */ + -3, /* (216) nexprlist ::= nexprlist COMMA expr */ + -1, /* (217) nexprlist ::= expr */ + 0, /* (218) paren_exprlist ::= */ + -3, /* (219) paren_exprlist ::= LP exprlist RP */ + -12, /* (220) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + -1, /* (221) uniqueflag ::= UNIQUE */ + 0, /* (222) uniqueflag ::= */ + 0, /* (223) eidlist_opt ::= */ + -3, /* (224) eidlist_opt ::= LP eidlist RP */ + -5, /* (225) eidlist ::= eidlist COMMA nm collate sortorder */ + -3, /* (226) eidlist ::= nm collate sortorder */ + 0, /* (227) collate ::= */ + -2, /* (228) collate ::= COLLATE ID|STRING */ + -4, /* (229) cmd ::= DROP INDEX ifexists fullname */ + -2, /* (230) cmd ::= VACUUM vinto */ + -3, /* (231) cmd ::= VACUUM nm vinto */ + -2, /* (232) vinto ::= INTO expr */ + 0, /* (233) vinto ::= */ + -3, /* (234) cmd ::= PRAGMA nm dbnm */ + -5, /* (235) cmd ::= PRAGMA nm dbnm EQ nmnum */ + -6, /* (236) cmd ::= PRAGMA nm dbnm LP nmnum RP */ + -5, /* (237) cmd ::= PRAGMA nm dbnm EQ minus_num */ + -6, /* (238) cmd ::= PRAGMA nm dbnm LP minus_num RP */ + -2, /* (239) plus_num ::= PLUS INTEGER|FLOAT */ + -2, /* (240) minus_num ::= MINUS INTEGER|FLOAT */ + -5, /* (241) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + -11, /* (242) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + -1, /* (243) trigger_time ::= BEFORE|AFTER */ + -2, /* (244) trigger_time ::= INSTEAD OF */ + 0, /* (245) trigger_time ::= */ + -1, /* (246) trigger_event ::= DELETE|INSERT */ + -1, /* (247) trigger_event ::= UPDATE */ + -3, /* (248) trigger_event ::= UPDATE OF idlist */ + 0, /* (249) when_clause ::= */ + -2, /* (250) when_clause ::= WHEN expr */ + -3, /* (251) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + -2, /* (252) trigger_cmd_list ::= trigger_cmd SEMI */ + -3, /* (253) trnm ::= nm DOT nm */ + -3, /* (254) tridxby ::= INDEXED BY nm */ + -2, /* (255) tridxby ::= NOT INDEXED */ + -8, /* (256) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ + -8, /* (257) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + -6, /* (258) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ + -3, /* (259) trigger_cmd ::= scanpt select scanpt */ + -4, /* (260) expr ::= RAISE LP IGNORE RP */ + -6, /* (261) expr ::= RAISE LP raisetype COMMA nm RP */ + -1, /* (262) raisetype ::= ROLLBACK */ + -1, /* (263) raisetype ::= ABORT */ + -1, /* (264) raisetype ::= FAIL */ + -4, /* (265) cmd ::= DROP TRIGGER ifexists fullname */ + -6, /* (266) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + -3, /* (267) cmd ::= DETACH database_kw_opt expr */ + 0, /* (268) key_opt ::= */ + -2, /* (269) key_opt ::= KEY expr */ + -1, /* (270) cmd ::= REINDEX */ + -3, /* (271) cmd ::= REINDEX nm dbnm */ + -1, /* (272) cmd ::= ANALYZE */ + -3, /* (273) cmd ::= ANALYZE nm dbnm */ + -6, /* (274) cmd ::= ALTER TABLE fullname RENAME TO nm */ + -7, /* (275) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + -1, /* (276) add_column_fullname ::= fullname */ + -8, /* (277) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + -1, /* (278) cmd ::= create_vtab */ + -4, /* (279) cmd ::= create_vtab LP vtabarglist RP */ + -8, /* (280) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 0, /* (281) vtabarg ::= */ + -1, /* (282) vtabargtoken ::= ANY */ + -3, /* (283) vtabargtoken ::= lp anylist RP */ + -1, /* (284) lp ::= LP */ + -2, /* (285) with ::= WITH wqlist */ + -3, /* (286) with ::= WITH RECURSIVE wqlist */ + -6, /* (287) wqlist ::= nm eidlist_opt AS LP select RP */ + -8, /* (288) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ + -1, /* (289) windowdefn_list ::= windowdefn */ + -3, /* (290) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + -5, /* (291) windowdefn ::= nm AS LP window RP */ + -5, /* (292) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + -6, /* (293) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + -4, /* (294) window ::= ORDER BY sortlist frame_opt */ + -5, /* (295) window ::= nm ORDER BY sortlist frame_opt */ + -1, /* (296) window ::= frame_opt */ + -2, /* (297) window ::= nm frame_opt */ + 0, /* (298) frame_opt ::= */ + -3, /* (299) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + -6, /* (300) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + -1, /* (301) range_or_rows ::= RANGE|ROWS|GROUPS */ + -1, /* (302) frame_bound_s ::= frame_bound */ + -2, /* (303) frame_bound_s ::= UNBOUNDED PRECEDING */ + -1, /* (304) frame_bound_e ::= frame_bound */ + -2, /* (305) frame_bound_e ::= UNBOUNDED FOLLOWING */ + -2, /* (306) frame_bound ::= expr PRECEDING|FOLLOWING */ + -2, /* (307) frame_bound ::= CURRENT ROW */ + 0, /* (308) frame_exclude_opt ::= */ + -2, /* (309) frame_exclude_opt ::= EXCLUDE frame_exclude */ + -2, /* (310) frame_exclude ::= NO OTHERS */ + -2, /* (311) frame_exclude ::= CURRENT ROW */ + -1, /* (312) frame_exclude ::= GROUP|TIES */ + -2, /* (313) window_clause ::= WINDOW windowdefn_list */ + -5, /* (314) over_clause ::= filter_opt OVER LP window RP */ + -3, /* (315) over_clause ::= filter_opt OVER nm */ + 0, /* (316) filter_opt ::= */ + -5, /* (317) filter_opt ::= FILTER LP WHERE expr RP */ + -1, /* (318) input ::= cmdlist */ + -2, /* (319) cmdlist ::= cmdlist ecmd */ + -1, /* (320) cmdlist ::= ecmd */ + -1, /* (321) ecmd ::= SEMI */ + -2, /* (322) ecmd ::= cmdx SEMI */ + -2, /* (323) ecmd ::= explain cmdx */ + 0, /* (324) trans_opt ::= */ + -1, /* (325) trans_opt ::= TRANSACTION */ + -2, /* (326) trans_opt ::= TRANSACTION nm */ + -1, /* (327) savepoint_opt ::= SAVEPOINT */ + 0, /* (328) savepoint_opt ::= */ + -2, /* (329) cmd ::= create_table create_table_args */ + -4, /* (330) columnlist ::= columnlist COMMA columnname carglist */ + -2, /* (331) columnlist ::= columnname carglist */ + -1, /* (332) nm ::= ID|INDEXED */ + -1, /* (333) nm ::= STRING */ + -1, /* (334) nm ::= JOIN_KW */ + -1, /* (335) typetoken ::= typename */ + -1, /* (336) typename ::= ID|STRING */ + -1, /* (337) signed ::= plus_num */ + -1, /* (338) signed ::= minus_num */ + -2, /* (339) carglist ::= carglist ccons */ + 0, /* (340) carglist ::= */ + -2, /* (341) ccons ::= NULL onconf */ + -2, /* (342) conslist_opt ::= COMMA conslist */ + -3, /* (343) conslist ::= conslist tconscomma tcons */ + -1, /* (344) conslist ::= tcons */ + 0, /* (345) tconscomma ::= */ + -1, /* (346) defer_subclause_opt ::= defer_subclause */ + -1, /* (347) resolvetype ::= raisetype */ + -1, /* (348) selectnowith ::= oneselect */ + -1, /* (349) oneselect ::= values */ + -2, /* (350) sclp ::= selcollist COMMA */ + -1, /* (351) as ::= ID|STRING */ + -1, /* (352) expr ::= term */ + -1, /* (353) likeop ::= LIKE_KW|MATCH */ + -1, /* (354) exprlist ::= nexprlist */ + -1, /* (355) nmnum ::= plus_num */ + -1, /* (356) nmnum ::= nm */ + -1, /* (357) nmnum ::= ON */ + -1, /* (358) nmnum ::= DELETE */ + -1, /* (359) nmnum ::= DEFAULT */ + -1, /* (360) plus_num ::= INTEGER|FLOAT */ + 0, /* (361) foreach_clause ::= */ + -3, /* (362) foreach_clause ::= FOR EACH ROW */ + -1, /* (363) trnm ::= nm */ + 0, /* (364) tridxby ::= */ + -1, /* (365) database_kw_opt ::= DATABASE */ + 0, /* (366) database_kw_opt ::= */ + 0, /* (367) kwcolumn_opt ::= */ + -1, /* (368) kwcolumn_opt ::= COLUMNKW */ + -1, /* (369) vtabarglist ::= vtabarg */ + -3, /* (370) vtabarglist ::= vtabarglist COMMA vtabarg */ + -2, /* (371) vtabarg ::= vtabarg vtabargtoken */ + 0, /* (372) anylist ::= */ + -4, /* (373) anylist ::= anylist LP anylist RP */ + -2, /* (374) anylist ::= anylist ANY */ + 0, /* (375) with ::= */ }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -150427,15 +151899,16 @@ static YYACTIONTYPE yy_reduce( { sqlite3FinishCoding(pParse); } break; case 3: /* cmd ::= BEGIN transtype trans_opt */ -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy96);} +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy100);} break; case 4: /* transtype ::= */ -{yymsp[1].minor.yy96 = TK_DEFERRED;} +{yymsp[1].minor.yy100 = TK_DEFERRED;} break; case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); -{yymsp[0].minor.yy96 = yymsp[0].major; /*A-overwrites-X*/} + case 301: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==301); +{yymsp[0].minor.yy100 = yymsp[0].major; /*A-overwrites-X*/} break; case 8: /* cmd ::= COMMIT|END trans_opt */ case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); @@ -150458,7 +151931,7 @@ static YYACTIONTYPE yy_reduce( break; case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { - sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy96,0,0,yymsp[-2].minor.yy96); + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy100,0,0,yymsp[-2].minor.yy100); } break; case 14: /* createkw ::= CREATE */ @@ -150467,38 +151940,38 @@ static YYACTIONTYPE yy_reduce( case 15: /* ifnotexists ::= */ case 18: /* temp ::= */ yytestcase(yyruleno==18); case 21: /* table_options ::= */ yytestcase(yyruleno==21); - case 42: /* autoinc ::= */ yytestcase(yyruleno==42); - case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57); - case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67); - case 76: /* ifexists ::= */ yytestcase(yyruleno==76); - case 93: /* distinct ::= */ yytestcase(yyruleno==93); - case 226: /* collate ::= */ yytestcase(yyruleno==226); -{yymsp[1].minor.yy96 = 0;} + case 43: /* autoinc ::= */ yytestcase(yyruleno==43); + case 58: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==58); + case 68: /* defer_subclause_opt ::= */ yytestcase(yyruleno==68); + case 77: /* ifexists ::= */ yytestcase(yyruleno==77); + case 94: /* distinct ::= */ yytestcase(yyruleno==94); + case 227: /* collate ::= */ yytestcase(yyruleno==227); +{yymsp[1].minor.yy100 = 0;} break; case 16: /* ifnotexists ::= IF NOT EXISTS */ -{yymsp[-2].minor.yy96 = 1;} +{yymsp[-2].minor.yy100 = 1;} break; case 17: /* temp ::= TEMP */ - case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43); -{yymsp[0].minor.yy96 = 1;} + case 44: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==44); +{yymsp[0].minor.yy100 = 1;} break; case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */ { - sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy96,0); + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy100,0); } break; case 20: /* create_table_args ::= AS select */ { - sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy423); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy423); + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy391); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy391); } break; case 22: /* table_options ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ - yymsp[-1].minor.yy96 = TF_WithoutRowid | TF_NoVisibleRowid; + yymsp[-1].minor.yy100 = TF_WithoutRowid | TF_NoVisibleRowid; }else{ - yymsp[-1].minor.yy96 = 0; + yymsp[-1].minor.yy100 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } @@ -150507,8 +151980,8 @@ static YYACTIONTYPE yy_reduce( {sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);} break; case 24: /* typetoken ::= */ - case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60); - case 99: /* as ::= */ yytestcase(yyruleno==99); + case 61: /* conslist_opt ::= */ yytestcase(yyruleno==61); + case 100: /* as ::= */ yytestcase(yyruleno==100); {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;} break; case 25: /* typetoken ::= typename LP signed RP */ @@ -150527,29 +152000,35 @@ static YYACTIONTYPE yy_reduce( case 28: /* scanpt ::= */ { assert( yyLookahead!=YYNOCODE ); - yymsp[1].minor.yy464 = yyLookaheadToken.z; + yymsp[1].minor.yy528 = yyLookaheadToken.z; +} + break; + case 29: /* scantok ::= */ +{ + assert( yyLookahead!=YYNOCODE ); + yymsp[1].minor.yy0 = yyLookaheadToken; } break; - case 29: /* ccons ::= CONSTRAINT nm */ - case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62); + case 30: /* ccons ::= CONSTRAINT nm */ + case 63: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==63); {pParse->constraintName = yymsp[0].minor.yy0;} break; - case 30: /* ccons ::= DEFAULT scanpt term scanpt */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy490,yymsp[-2].minor.yy464,yymsp[0].minor.yy464);} + case 31: /* ccons ::= DEFAULT scantok term */ +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy102,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; - case 31: /* ccons ::= DEFAULT LP expr RP */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy490,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} + case 32: /* ccons ::= DEFAULT LP expr RP */ +{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy102,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} break; - case 32: /* ccons ::= DEFAULT PLUS term scanpt */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy490,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy464);} + case 33: /* ccons ::= DEFAULT PLUS scantok term */ +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy102,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; - case 33: /* ccons ::= DEFAULT MINUS term scanpt */ + case 34: /* ccons ::= DEFAULT MINUS scantok term */ { - Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[-1].minor.yy490, 0); - sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy464); + Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy102, 0); + sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]); } break; - case 34: /* ccons ::= DEFAULT scanpt ID|INDEXED */ + case 35: /* ccons ::= DEFAULT scantok ID|INDEXED */ { Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0); if( p ){ @@ -150559,171 +152038,171 @@ static YYACTIONTYPE yy_reduce( sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n); } break; - case 35: /* ccons ::= NOT NULL onconf */ -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy96);} + case 36: /* ccons ::= NOT NULL onconf */ +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy100);} break; - case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy96,yymsp[0].minor.yy96,yymsp[-2].minor.yy96);} + case 37: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy100,yymsp[0].minor.yy100,yymsp[-2].minor.yy100);} break; - case 37: /* ccons ::= UNIQUE onconf */ -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy96,0,0,0,0, + case 38: /* ccons ::= UNIQUE onconf */ +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy100,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; - case 38: /* ccons ::= CHECK LP expr RP */ -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy490);} + case 39: /* ccons ::= CHECK LP expr RP */ +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy102);} break; - case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */ -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy42,yymsp[0].minor.yy96);} + case 40: /* ccons ::= REFERENCES nm eidlist_opt refargs */ +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy94,yymsp[0].minor.yy100);} break; - case 40: /* ccons ::= defer_subclause */ -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy96);} + case 41: /* ccons ::= defer_subclause */ +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy100);} break; - case 41: /* ccons ::= COLLATE ID|STRING */ + case 42: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; - case 44: /* refargs ::= */ -{ yymsp[1].minor.yy96 = OE_None*0x0101; /* EV: R-19803-45884 */} + case 45: /* refargs ::= */ +{ yymsp[1].minor.yy100 = OE_None*0x0101; /* EV: R-19803-45884 */} break; - case 45: /* refargs ::= refargs refarg */ -{ yymsp[-1].minor.yy96 = (yymsp[-1].minor.yy96 & ~yymsp[0].minor.yy367.mask) | yymsp[0].minor.yy367.value; } + case 46: /* refargs ::= refargs refarg */ +{ yymsp[-1].minor.yy100 = (yymsp[-1].minor.yy100 & ~yymsp[0].minor.yy199.mask) | yymsp[0].minor.yy199.value; } break; - case 46: /* refarg ::= MATCH nm */ -{ yymsp[-1].minor.yy367.value = 0; yymsp[-1].minor.yy367.mask = 0x000000; } + case 47: /* refarg ::= MATCH nm */ +{ yymsp[-1].minor.yy199.value = 0; yymsp[-1].minor.yy199.mask = 0x000000; } break; - case 47: /* refarg ::= ON INSERT refact */ -{ yymsp[-2].minor.yy367.value = 0; yymsp[-2].minor.yy367.mask = 0x000000; } + case 48: /* refarg ::= ON INSERT refact */ +{ yymsp[-2].minor.yy199.value = 0; yymsp[-2].minor.yy199.mask = 0x000000; } break; - case 48: /* refarg ::= ON DELETE refact */ -{ yymsp[-2].minor.yy367.value = yymsp[0].minor.yy96; yymsp[-2].minor.yy367.mask = 0x0000ff; } + case 49: /* refarg ::= ON DELETE refact */ +{ yymsp[-2].minor.yy199.value = yymsp[0].minor.yy100; yymsp[-2].minor.yy199.mask = 0x0000ff; } break; - case 49: /* refarg ::= ON UPDATE refact */ -{ yymsp[-2].minor.yy367.value = yymsp[0].minor.yy96<<8; yymsp[-2].minor.yy367.mask = 0x00ff00; } + case 50: /* refarg ::= ON UPDATE refact */ +{ yymsp[-2].minor.yy199.value = yymsp[0].minor.yy100<<8; yymsp[-2].minor.yy199.mask = 0x00ff00; } break; - case 50: /* refact ::= SET NULL */ -{ yymsp[-1].minor.yy96 = OE_SetNull; /* EV: R-33326-45252 */} + case 51: /* refact ::= SET NULL */ +{ yymsp[-1].minor.yy100 = OE_SetNull; /* EV: R-33326-45252 */} break; - case 51: /* refact ::= SET DEFAULT */ -{ yymsp[-1].minor.yy96 = OE_SetDflt; /* EV: R-33326-45252 */} + case 52: /* refact ::= SET DEFAULT */ +{ yymsp[-1].minor.yy100 = OE_SetDflt; /* EV: R-33326-45252 */} break; - case 52: /* refact ::= CASCADE */ -{ yymsp[0].minor.yy96 = OE_Cascade; /* EV: R-33326-45252 */} + case 53: /* refact ::= CASCADE */ +{ yymsp[0].minor.yy100 = OE_Cascade; /* EV: R-33326-45252 */} break; - case 53: /* refact ::= RESTRICT */ -{ yymsp[0].minor.yy96 = OE_Restrict; /* EV: R-33326-45252 */} + case 54: /* refact ::= RESTRICT */ +{ yymsp[0].minor.yy100 = OE_Restrict; /* EV: R-33326-45252 */} break; - case 54: /* refact ::= NO ACTION */ -{ yymsp[-1].minor.yy96 = OE_None; /* EV: R-33326-45252 */} + case 55: /* refact ::= NO ACTION */ +{ yymsp[-1].minor.yy100 = OE_None; /* EV: R-33326-45252 */} break; - case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ -{yymsp[-2].minor.yy96 = 0;} + case 56: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ +{yymsp[-2].minor.yy100 = 0;} break; - case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ - case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71); - case 156: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==156); -{yymsp[-1].minor.yy96 = yymsp[0].minor.yy96;} + case 57: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ + case 72: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==72); + case 157: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==157); +{yymsp[-1].minor.yy100 = yymsp[0].minor.yy100;} break; - case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ - case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75); - case 198: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==198); - case 201: /* in_op ::= NOT IN */ yytestcase(yyruleno==201); - case 227: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==227); -{yymsp[-1].minor.yy96 = 1;} + case 59: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ + case 76: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==76); + case 199: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==199); + case 202: /* in_op ::= NOT IN */ yytestcase(yyruleno==202); + case 228: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==228); +{yymsp[-1].minor.yy100 = 1;} break; - case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ -{yymsp[-1].minor.yy96 = 0;} + case 60: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ +{yymsp[-1].minor.yy100 = 0;} break; - case 61: /* tconscomma ::= COMMA */ + case 62: /* tconscomma ::= COMMA */ {pParse->constraintName.n = 0;} break; - case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy42,yymsp[0].minor.yy96,yymsp[-2].minor.yy96,0);} + case 64: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy94,yymsp[0].minor.yy100,yymsp[-2].minor.yy100,0);} break; - case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */ -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy42,yymsp[0].minor.yy96,0,0,0,0, + case 65: /* tcons ::= UNIQUE LP sortlist RP onconf */ +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy94,yymsp[0].minor.yy100,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; - case 65: /* tcons ::= CHECK LP expr RP onconf */ -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy490);} + case 66: /* tcons ::= CHECK LP expr RP onconf */ +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy102);} break; - case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ + case 67: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy42, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy42, yymsp[-1].minor.yy96); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy96); + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy94, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy94, yymsp[-1].minor.yy100); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy100); } break; - case 68: /* onconf ::= */ - case 70: /* orconf ::= */ yytestcase(yyruleno==70); -{yymsp[1].minor.yy96 = OE_Default;} + case 69: /* onconf ::= */ + case 71: /* orconf ::= */ yytestcase(yyruleno==71); +{yymsp[1].minor.yy100 = OE_Default;} break; - case 69: /* onconf ::= ON CONFLICT resolvetype */ -{yymsp[-2].minor.yy96 = yymsp[0].minor.yy96;} + case 70: /* onconf ::= ON CONFLICT resolvetype */ +{yymsp[-2].minor.yy100 = yymsp[0].minor.yy100;} break; - case 72: /* resolvetype ::= IGNORE */ -{yymsp[0].minor.yy96 = OE_Ignore;} + case 73: /* resolvetype ::= IGNORE */ +{yymsp[0].minor.yy100 = OE_Ignore;} break; - case 73: /* resolvetype ::= REPLACE */ - case 157: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==157); -{yymsp[0].minor.yy96 = OE_Replace;} + case 74: /* resolvetype ::= REPLACE */ + case 158: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==158); +{yymsp[0].minor.yy100 = OE_Replace;} break; - case 74: /* cmd ::= DROP TABLE ifexists fullname */ + case 75: /* cmd ::= DROP TABLE ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy167, 0, yymsp[-1].minor.yy96); + sqlite3DropTable(pParse, yymsp[0].minor.yy407, 0, yymsp[-1].minor.yy100); } break; - case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ + case 78: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { - sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy42, yymsp[0].minor.yy423, yymsp[-7].minor.yy96, yymsp[-5].minor.yy96); + sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy94, yymsp[0].minor.yy391, yymsp[-7].minor.yy100, yymsp[-5].minor.yy100); } break; - case 78: /* cmd ::= DROP VIEW ifexists fullname */ + case 79: /* cmd ::= DROP VIEW ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy167, 1, yymsp[-1].minor.yy96); + sqlite3DropTable(pParse, yymsp[0].minor.yy407, 1, yymsp[-1].minor.yy100); } break; - case 79: /* cmd ::= select */ + case 80: /* cmd ::= select */ { SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0}; - sqlite3Select(pParse, yymsp[0].minor.yy423, &dest); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy423); + sqlite3Select(pParse, yymsp[0].minor.yy391, &dest); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy391); } break; - case 80: /* select ::= WITH wqlist selectnowith */ + case 81: /* select ::= WITH wqlist selectnowith */ { - Select *p = yymsp[0].minor.yy423; + Select *p = yymsp[0].minor.yy391; if( p ){ - p->pWith = yymsp[-1].minor.yy499; + p->pWith = yymsp[-1].minor.yy243; parserDoubleLinkSelect(pParse, p); }else{ - sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy499); + sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy243); } - yymsp[-2].minor.yy423 = p; + yymsp[-2].minor.yy391 = p; } break; - case 81: /* select ::= WITH RECURSIVE wqlist selectnowith */ + case 82: /* select ::= WITH RECURSIVE wqlist selectnowith */ { - Select *p = yymsp[0].minor.yy423; + Select *p = yymsp[0].minor.yy391; if( p ){ - p->pWith = yymsp[-1].minor.yy499; + p->pWith = yymsp[-1].minor.yy243; parserDoubleLinkSelect(pParse, p); }else{ - sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy499); + sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy243); } - yymsp[-3].minor.yy423 = p; + yymsp[-3].minor.yy391 = p; } break; - case 82: /* select ::= selectnowith */ + case 83: /* select ::= selectnowith */ { - Select *p = yymsp[0].minor.yy423; + Select *p = yymsp[0].minor.yy391; if( p ){ parserDoubleLinkSelect(pParse, p); } - yymsp[0].minor.yy423 = p; /*A-overwrites-X*/ + yymsp[0].minor.yy391 = p; /*A-overwrites-X*/ } break; - case 83: /* selectnowith ::= selectnowith multiselect_op oneselect */ + case 84: /* selectnowith ::= selectnowith multiselect_op oneselect */ { - Select *pRhs = yymsp[0].minor.yy423; - Select *pLhs = yymsp[-2].minor.yy423; + Select *pRhs = yymsp[0].minor.yy391; + Select *pLhs = yymsp[-2].minor.yy391; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; @@ -150733,142 +152212,142 @@ static YYACTIONTYPE yy_reduce( pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); } if( pRhs ){ - pRhs->op = (u8)yymsp[-1].minor.yy96; + pRhs->op = (u8)yymsp[-1].minor.yy100; pRhs->pPrior = pLhs; if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; pRhs->selFlags &= ~SF_MultiValue; - if( yymsp[-1].minor.yy96!=TK_ALL ) pParse->hasCompound = 1; + if( yymsp[-1].minor.yy100!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); } - yymsp[-2].minor.yy423 = pRhs; + yymsp[-2].minor.yy391 = pRhs; } break; - case 84: /* multiselect_op ::= UNION */ - case 86: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==86); -{yymsp[0].minor.yy96 = yymsp[0].major; /*A-overwrites-OP*/} + case 85: /* multiselect_op ::= UNION */ + case 87: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==87); +{yymsp[0].minor.yy100 = yymsp[0].major; /*A-overwrites-OP*/} break; - case 85: /* multiselect_op ::= UNION ALL */ -{yymsp[-1].minor.yy96 = TK_ALL;} + case 86: /* multiselect_op ::= UNION ALL */ +{yymsp[-1].minor.yy100 = TK_ALL;} break; - case 87: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ + case 88: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { - yymsp[-8].minor.yy423 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy42,yymsp[-5].minor.yy167,yymsp[-4].minor.yy490,yymsp[-3].minor.yy42,yymsp[-2].minor.yy490,yymsp[-1].minor.yy42,yymsp[-7].minor.yy96,yymsp[0].minor.yy490); + yymsp[-8].minor.yy391 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy94,yymsp[-5].minor.yy407,yymsp[-4].minor.yy102,yymsp[-3].minor.yy94,yymsp[-2].minor.yy102,yymsp[-1].minor.yy94,yymsp[-7].minor.yy100,yymsp[0].minor.yy102); } break; - case 88: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ + case 89: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ { - yymsp[-9].minor.yy423 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy42,yymsp[-6].minor.yy167,yymsp[-5].minor.yy490,yymsp[-4].minor.yy42,yymsp[-3].minor.yy490,yymsp[-1].minor.yy42,yymsp[-8].minor.yy96,yymsp[0].minor.yy490); - if( yymsp[-9].minor.yy423 ){ - yymsp[-9].minor.yy423->pWinDefn = yymsp[-2].minor.yy147; + yymsp[-9].minor.yy391 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy94,yymsp[-6].minor.yy407,yymsp[-5].minor.yy102,yymsp[-4].minor.yy94,yymsp[-3].minor.yy102,yymsp[-1].minor.yy94,yymsp[-8].minor.yy100,yymsp[0].minor.yy102); + if( yymsp[-9].minor.yy391 ){ + yymsp[-9].minor.yy391->pWinDefn = yymsp[-2].minor.yy379; }else{ - sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy147); + sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy379); } } break; - case 89: /* values ::= VALUES LP nexprlist RP */ + case 90: /* values ::= VALUES LP nexprlist RP */ { - yymsp[-3].minor.yy423 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy42,0,0,0,0,0,SF_Values,0); + yymsp[-3].minor.yy391 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy94,0,0,0,0,0,SF_Values,0); } break; - case 90: /* values ::= values COMMA LP nexprlist RP */ + case 91: /* values ::= values COMMA LP nexprlist RP */ { - Select *pRight, *pLeft = yymsp[-4].minor.yy423; - pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy42,0,0,0,0,0,SF_Values|SF_MultiValue,0); + Select *pRight, *pLeft = yymsp[-4].minor.yy391; + pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy94,0,0,0,0,0,SF_Values|SF_MultiValue,0); if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; if( pRight ){ pRight->op = TK_ALL; pRight->pPrior = pLeft; - yymsp[-4].minor.yy423 = pRight; + yymsp[-4].minor.yy391 = pRight; }else{ - yymsp[-4].minor.yy423 = pLeft; + yymsp[-4].minor.yy391 = pLeft; } } break; - case 91: /* distinct ::= DISTINCT */ -{yymsp[0].minor.yy96 = SF_Distinct;} + case 92: /* distinct ::= DISTINCT */ +{yymsp[0].minor.yy100 = SF_Distinct;} break; - case 92: /* distinct ::= ALL */ -{yymsp[0].minor.yy96 = SF_All;} + case 93: /* distinct ::= ALL */ +{yymsp[0].minor.yy100 = SF_All;} break; - case 94: /* sclp ::= */ - case 127: /* orderby_opt ::= */ yytestcase(yyruleno==127); - case 134: /* groupby_opt ::= */ yytestcase(yyruleno==134); - case 214: /* exprlist ::= */ yytestcase(yyruleno==214); - case 217: /* paren_exprlist ::= */ yytestcase(yyruleno==217); - case 222: /* eidlist_opt ::= */ yytestcase(yyruleno==222); -{yymsp[1].minor.yy42 = 0;} + case 95: /* sclp ::= */ + case 128: /* orderby_opt ::= */ yytestcase(yyruleno==128); + case 135: /* groupby_opt ::= */ yytestcase(yyruleno==135); + case 215: /* exprlist ::= */ yytestcase(yyruleno==215); + case 218: /* paren_exprlist ::= */ yytestcase(yyruleno==218); + case 223: /* eidlist_opt ::= */ yytestcase(yyruleno==223); +{yymsp[1].minor.yy94 = 0;} break; - case 95: /* selcollist ::= sclp scanpt expr scanpt as */ + case 96: /* selcollist ::= sclp scanpt expr scanpt as */ { - yymsp[-4].minor.yy42 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy42, yymsp[-2].minor.yy490); - if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy42, &yymsp[0].minor.yy0, 1); - sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy42,yymsp[-3].minor.yy464,yymsp[-1].minor.yy464); + yymsp[-4].minor.yy94 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy94, yymsp[-2].minor.yy102); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy94, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy94,yymsp[-3].minor.yy528,yymsp[-1].minor.yy528); } break; - case 96: /* selcollist ::= sclp scanpt STAR */ + case 97: /* selcollist ::= sclp scanpt STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); - yymsp[-2].minor.yy42 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy42, p); + yymsp[-2].minor.yy94 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy94, p); } break; - case 97: /* selcollist ::= sclp scanpt nm DOT STAR */ + case 98: /* selcollist ::= sclp scanpt nm DOT STAR */ { Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); - yymsp[-4].minor.yy42 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy42, pDot); + yymsp[-4].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy94, pDot); } break; - case 98: /* as ::= AS nm */ - case 109: /* dbnm ::= DOT nm */ yytestcase(yyruleno==109); - case 238: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==238); - case 239: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==239); + case 99: /* as ::= AS nm */ + case 110: /* dbnm ::= DOT nm */ yytestcase(yyruleno==110); + case 239: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==239); + case 240: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==240); {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;} break; - case 100: /* from ::= */ -{yymsp[1].minor.yy167 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy167));} + case 101: /* from ::= */ +{yymsp[1].minor.yy407 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy407));} break; - case 101: /* from ::= FROM seltablist */ + case 102: /* from ::= FROM seltablist */ { - yymsp[-1].minor.yy167 = yymsp[0].minor.yy167; - sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy167); + yymsp[-1].minor.yy407 = yymsp[0].minor.yy407; + sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy407); } break; - case 102: /* stl_prefix ::= seltablist joinop */ + case 103: /* stl_prefix ::= seltablist joinop */ { - if( ALWAYS(yymsp[-1].minor.yy167 && yymsp[-1].minor.yy167->nSrc>0) ) yymsp[-1].minor.yy167->a[yymsp[-1].minor.yy167->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy96; + if( ALWAYS(yymsp[-1].minor.yy407 && yymsp[-1].minor.yy407->nSrc>0) ) yymsp[-1].minor.yy407->a[yymsp[-1].minor.yy407->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy100; } break; - case 103: /* stl_prefix ::= */ -{yymsp[1].minor.yy167 = 0;} + case 104: /* stl_prefix ::= */ +{yymsp[1].minor.yy407 = 0;} break; - case 104: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ + case 105: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */ { - yymsp[-6].minor.yy167 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy167,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy490,yymsp[0].minor.yy336); - sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy167, &yymsp[-2].minor.yy0); + yymsp[-6].minor.yy407 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy407,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy102,yymsp[0].minor.yy76); + sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy407, &yymsp[-2].minor.yy0); } break; - case 105: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ + case 106: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */ { - yymsp[-8].minor.yy167 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy167,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy490,yymsp[0].minor.yy336); - sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy167, yymsp[-4].minor.yy42); + yymsp[-8].minor.yy407 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy407,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy102,yymsp[0].minor.yy76); + sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy407, yymsp[-4].minor.yy94); } break; - case 106: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ + case 107: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */ { - yymsp[-6].minor.yy167 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy167,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy423,yymsp[-1].minor.yy490,yymsp[0].minor.yy336); + yymsp[-6].minor.yy407 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy407,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy391,yymsp[-1].minor.yy102,yymsp[0].minor.yy76); } break; - case 107: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ + case 108: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */ { - if( yymsp[-6].minor.yy167==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy490==0 && yymsp[0].minor.yy336==0 ){ - yymsp[-6].minor.yy167 = yymsp[-4].minor.yy167; - }else if( yymsp[-4].minor.yy167->nSrc==1 ){ - yymsp[-6].minor.yy167 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy167,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy490,yymsp[0].minor.yy336); - if( yymsp[-6].minor.yy167 ){ - struct SrcList_item *pNew = &yymsp[-6].minor.yy167->a[yymsp[-6].minor.yy167->nSrc-1]; - struct SrcList_item *pOld = yymsp[-4].minor.yy167->a; + if( yymsp[-6].minor.yy407==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy102==0 && yymsp[0].minor.yy76==0 ){ + yymsp[-6].minor.yy407 = yymsp[-4].minor.yy407; + }else if( yymsp[-4].minor.yy407->nSrc==1 ){ + yymsp[-6].minor.yy407 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy407,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy102,yymsp[0].minor.yy76); + if( yymsp[-6].minor.yy407 ){ + struct SrcList_item *pNew = &yymsp[-6].minor.yy407->a[yymsp[-6].minor.yy407->nSrc-1]; + struct SrcList_item *pOld = yymsp[-4].minor.yy407->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; @@ -150881,201 +152360,201 @@ static YYACTIONTYPE yy_reduce( pOld->zName = pOld->zDatabase = 0; pOld->pSelect = 0; } - sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy167); + sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy407); }else{ Select *pSubquery; - sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy167); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy167,0,0,0,0,SF_NestedFrom,0); - yymsp[-6].minor.yy167 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy167,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy490,yymsp[0].minor.yy336); + sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy407); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy407,0,0,0,0,SF_NestedFrom,0); + yymsp[-6].minor.yy407 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy407,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy102,yymsp[0].minor.yy76); } } break; - case 108: /* dbnm ::= */ - case 122: /* indexed_opt ::= */ yytestcase(yyruleno==122); + case 109: /* dbnm ::= */ + case 123: /* indexed_opt ::= */ yytestcase(yyruleno==123); {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; - case 110: /* fullname ::= nm */ + case 111: /* fullname ::= nm */ { - yylhsminor.yy167 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); - if( IN_RENAME_OBJECT && yylhsminor.yy167 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy167->a[0].zName, &yymsp[0].minor.yy0); + yylhsminor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); + if( IN_RENAME_OBJECT && yylhsminor.yy407 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy407->a[0].zName, &yymsp[0].minor.yy0); } - yymsp[0].minor.yy167 = yylhsminor.yy167; + yymsp[0].minor.yy407 = yylhsminor.yy407; break; - case 111: /* fullname ::= nm DOT nm */ + case 112: /* fullname ::= nm DOT nm */ { - yylhsminor.yy167 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); - if( IN_RENAME_OBJECT && yylhsminor.yy167 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy167->a[0].zName, &yymsp[0].minor.yy0); + yylhsminor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); + if( IN_RENAME_OBJECT && yylhsminor.yy407 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy407->a[0].zName, &yymsp[0].minor.yy0); } - yymsp[-2].minor.yy167 = yylhsminor.yy167; + yymsp[-2].minor.yy407 = yylhsminor.yy407; break; - case 112: /* xfullname ::= nm */ -{yymsp[0].minor.yy167 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} + case 113: /* xfullname ::= nm */ +{yymsp[0].minor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} break; - case 113: /* xfullname ::= nm DOT nm */ -{yymsp[-2].minor.yy167 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} + case 114: /* xfullname ::= nm DOT nm */ +{yymsp[-2].minor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 114: /* xfullname ::= nm DOT nm AS nm */ + case 115: /* xfullname ::= nm DOT nm AS nm */ { - yymsp[-4].minor.yy167 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ - if( yymsp[-4].minor.yy167 ) yymsp[-4].minor.yy167->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + yymsp[-4].minor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ + if( yymsp[-4].minor.yy407 ) yymsp[-4].minor.yy407->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; - case 115: /* xfullname ::= nm AS nm */ + case 116: /* xfullname ::= nm AS nm */ { - yymsp[-2].minor.yy167 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ - if( yymsp[-2].minor.yy167 ) yymsp[-2].minor.yy167->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + yymsp[-2].minor.yy407 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ + if( yymsp[-2].minor.yy407 ) yymsp[-2].minor.yy407->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); } break; - case 116: /* joinop ::= COMMA|JOIN */ -{ yymsp[0].minor.yy96 = JT_INNER; } + case 117: /* joinop ::= COMMA|JOIN */ +{ yymsp[0].minor.yy100 = JT_INNER; } break; - case 117: /* joinop ::= JOIN_KW JOIN */ -{yymsp[-1].minor.yy96 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} + case 118: /* joinop ::= JOIN_KW JOIN */ +{yymsp[-1].minor.yy100 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; - case 118: /* joinop ::= JOIN_KW nm JOIN */ -{yymsp[-2].minor.yy96 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} + case 119: /* joinop ::= JOIN_KW nm JOIN */ +{yymsp[-2].minor.yy100 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} break; - case 119: /* joinop ::= JOIN_KW nm nm JOIN */ -{yymsp[-3].minor.yy96 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} + case 120: /* joinop ::= JOIN_KW nm nm JOIN */ +{yymsp[-3].minor.yy100 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} break; - case 120: /* on_opt ::= ON expr */ - case 137: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==137); - case 144: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==144); - case 210: /* case_else ::= ELSE expr */ yytestcase(yyruleno==210); - case 231: /* vinto ::= INTO expr */ yytestcase(yyruleno==231); -{yymsp[-1].minor.yy490 = yymsp[0].minor.yy490;} + case 121: /* on_opt ::= ON expr */ + case 138: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==138); + case 145: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==145); + case 211: /* case_else ::= ELSE expr */ yytestcase(yyruleno==211); + case 232: /* vinto ::= INTO expr */ yytestcase(yyruleno==232); +{yymsp[-1].minor.yy102 = yymsp[0].minor.yy102;} break; - case 121: /* on_opt ::= */ - case 136: /* having_opt ::= */ yytestcase(yyruleno==136); - case 138: /* limit_opt ::= */ yytestcase(yyruleno==138); - case 143: /* where_opt ::= */ yytestcase(yyruleno==143); - case 211: /* case_else ::= */ yytestcase(yyruleno==211); - case 213: /* case_operand ::= */ yytestcase(yyruleno==213); - case 232: /* vinto ::= */ yytestcase(yyruleno==232); -{yymsp[1].minor.yy490 = 0;} + case 122: /* on_opt ::= */ + case 137: /* having_opt ::= */ yytestcase(yyruleno==137); + case 139: /* limit_opt ::= */ yytestcase(yyruleno==139); + case 144: /* where_opt ::= */ yytestcase(yyruleno==144); + case 212: /* case_else ::= */ yytestcase(yyruleno==212); + case 214: /* case_operand ::= */ yytestcase(yyruleno==214); + case 233: /* vinto ::= */ yytestcase(yyruleno==233); +{yymsp[1].minor.yy102 = 0;} break; - case 123: /* indexed_opt ::= INDEXED BY nm */ + case 124: /* indexed_opt ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} break; - case 124: /* indexed_opt ::= NOT INDEXED */ + case 125: /* indexed_opt ::= NOT INDEXED */ {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;} break; - case 125: /* using_opt ::= USING LP idlist RP */ -{yymsp[-3].minor.yy336 = yymsp[-1].minor.yy336;} + case 126: /* using_opt ::= USING LP idlist RP */ +{yymsp[-3].minor.yy76 = yymsp[-1].minor.yy76;} break; - case 126: /* using_opt ::= */ - case 158: /* idlist_opt ::= */ yytestcase(yyruleno==158); -{yymsp[1].minor.yy336 = 0;} + case 127: /* using_opt ::= */ + case 159: /* idlist_opt ::= */ yytestcase(yyruleno==159); +{yymsp[1].minor.yy76 = 0;} break; - case 128: /* orderby_opt ::= ORDER BY sortlist */ - case 135: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==135); -{yymsp[-2].minor.yy42 = yymsp[0].minor.yy42;} + case 129: /* orderby_opt ::= ORDER BY sortlist */ + case 136: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==136); +{yymsp[-2].minor.yy94 = yymsp[0].minor.yy94;} break; - case 129: /* sortlist ::= sortlist COMMA expr sortorder */ + case 130: /* sortlist ::= sortlist COMMA expr sortorder */ { - yymsp[-3].minor.yy42 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy42,yymsp[-1].minor.yy490); - sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy42,yymsp[0].minor.yy96); + yymsp[-3].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy94,yymsp[-1].minor.yy102); + sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy94,yymsp[0].minor.yy100); } break; - case 130: /* sortlist ::= expr sortorder */ + case 131: /* sortlist ::= expr sortorder */ { - yymsp[-1].minor.yy42 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy490); /*A-overwrites-Y*/ - sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy42,yymsp[0].minor.yy96); + yymsp[-1].minor.yy94 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy102); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy94,yymsp[0].minor.yy100); } break; - case 131: /* sortorder ::= ASC */ -{yymsp[0].minor.yy96 = SQLITE_SO_ASC;} + case 132: /* sortorder ::= ASC */ +{yymsp[0].minor.yy100 = SQLITE_SO_ASC;} break; - case 132: /* sortorder ::= DESC */ -{yymsp[0].minor.yy96 = SQLITE_SO_DESC;} + case 133: /* sortorder ::= DESC */ +{yymsp[0].minor.yy100 = SQLITE_SO_DESC;} break; - case 133: /* sortorder ::= */ -{yymsp[1].minor.yy96 = SQLITE_SO_UNDEFINED;} + case 134: /* sortorder ::= */ +{yymsp[1].minor.yy100 = SQLITE_SO_UNDEFINED;} break; - case 139: /* limit_opt ::= LIMIT expr */ -{yymsp[-1].minor.yy490 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy490,0);} + case 140: /* limit_opt ::= LIMIT expr */ +{yymsp[-1].minor.yy102 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy102,0);} break; - case 140: /* limit_opt ::= LIMIT expr OFFSET expr */ -{yymsp[-3].minor.yy490 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy490,yymsp[0].minor.yy490);} + case 141: /* limit_opt ::= LIMIT expr OFFSET expr */ +{yymsp[-3].minor.yy102 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy102,yymsp[0].minor.yy102);} break; - case 141: /* limit_opt ::= LIMIT expr COMMA expr */ -{yymsp[-3].minor.yy490 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy490,yymsp[-2].minor.yy490);} + case 142: /* limit_opt ::= LIMIT expr COMMA expr */ +{yymsp[-3].minor.yy102 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy102,yymsp[-2].minor.yy102);} break; - case 142: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ + case 143: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt */ { - sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy167, &yymsp[-1].minor.yy0); - sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy167,yymsp[0].minor.yy490,0,0); + sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy407, &yymsp[-1].minor.yy0); + sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy407,yymsp[0].minor.yy102,0,0); } break; - case 145: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ + case 146: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */ { - sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy167, &yymsp[-3].minor.yy0); - sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy42,"set list"); - sqlite3Update(pParse,yymsp[-4].minor.yy167,yymsp[-1].minor.yy42,yymsp[0].minor.yy490,yymsp[-5].minor.yy96,0,0,0); + sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy407, &yymsp[-3].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy94,"set list"); + sqlite3Update(pParse,yymsp[-4].minor.yy407,yymsp[-1].minor.yy94,yymsp[0].minor.yy102,yymsp[-5].minor.yy100,0,0,0); } break; - case 146: /* setlist ::= setlist COMMA nm EQ expr */ + case 147: /* setlist ::= setlist COMMA nm EQ expr */ { - yymsp[-4].minor.yy42 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy42, yymsp[0].minor.yy490); - sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy42, &yymsp[-2].minor.yy0, 1); + yymsp[-4].minor.yy94 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy94, yymsp[0].minor.yy102); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy94, &yymsp[-2].minor.yy0, 1); } break; - case 147: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ + case 148: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { - yymsp[-6].minor.yy42 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy42, yymsp[-3].minor.yy336, yymsp[0].minor.yy490); + yymsp[-6].minor.yy94 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy94, yymsp[-3].minor.yy76, yymsp[0].minor.yy102); } break; - case 148: /* setlist ::= nm EQ expr */ + case 149: /* setlist ::= nm EQ expr */ { - yylhsminor.yy42 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy490); - sqlite3ExprListSetName(pParse, yylhsminor.yy42, &yymsp[-2].minor.yy0, 1); + yylhsminor.yy94 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy102); + sqlite3ExprListSetName(pParse, yylhsminor.yy94, &yymsp[-2].minor.yy0, 1); } - yymsp[-2].minor.yy42 = yylhsminor.yy42; + yymsp[-2].minor.yy94 = yylhsminor.yy94; break; - case 149: /* setlist ::= LP idlist RP EQ expr */ + case 150: /* setlist ::= LP idlist RP EQ expr */ { - yymsp[-4].minor.yy42 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy336, yymsp[0].minor.yy490); + yymsp[-4].minor.yy94 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy76, yymsp[0].minor.yy102); } break; - case 150: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ + case 151: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ { - sqlite3Insert(pParse, yymsp[-3].minor.yy167, yymsp[-1].minor.yy423, yymsp[-2].minor.yy336, yymsp[-5].minor.yy96, yymsp[0].minor.yy266); + sqlite3Insert(pParse, yymsp[-3].minor.yy407, yymsp[-1].minor.yy391, yymsp[-2].minor.yy76, yymsp[-5].minor.yy100, yymsp[0].minor.yy95); } break; - case 151: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ + case 152: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */ { - sqlite3Insert(pParse, yymsp[-3].minor.yy167, 0, yymsp[-2].minor.yy336, yymsp[-5].minor.yy96, 0); + sqlite3Insert(pParse, yymsp[-3].minor.yy407, 0, yymsp[-2].minor.yy76, yymsp[-5].minor.yy100, 0); } break; - case 152: /* upsert ::= */ -{ yymsp[1].minor.yy266 = 0; } + case 153: /* upsert ::= */ +{ yymsp[1].minor.yy95 = 0; } break; - case 153: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ -{ yymsp[-10].minor.yy266 = sqlite3UpsertNew(pParse->db,yymsp[-7].minor.yy42,yymsp[-5].minor.yy490,yymsp[-1].minor.yy42,yymsp[0].minor.yy490);} + case 154: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */ +{ yymsp[-10].minor.yy95 = sqlite3UpsertNew(pParse->db,yymsp[-7].minor.yy94,yymsp[-5].minor.yy102,yymsp[-1].minor.yy94,yymsp[0].minor.yy102);} break; - case 154: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ -{ yymsp[-7].minor.yy266 = sqlite3UpsertNew(pParse->db,yymsp[-4].minor.yy42,yymsp[-2].minor.yy490,0,0); } + case 155: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */ +{ yymsp[-7].minor.yy95 = sqlite3UpsertNew(pParse->db,yymsp[-4].minor.yy94,yymsp[-2].minor.yy102,0,0); } break; - case 155: /* upsert ::= ON CONFLICT DO NOTHING */ -{ yymsp[-3].minor.yy266 = sqlite3UpsertNew(pParse->db,0,0,0,0); } + case 156: /* upsert ::= ON CONFLICT DO NOTHING */ +{ yymsp[-3].minor.yy95 = sqlite3UpsertNew(pParse->db,0,0,0,0); } break; - case 159: /* idlist_opt ::= LP idlist RP */ -{yymsp[-2].minor.yy336 = yymsp[-1].minor.yy336;} + case 160: /* idlist_opt ::= LP idlist RP */ +{yymsp[-2].minor.yy76 = yymsp[-1].minor.yy76;} break; - case 160: /* idlist ::= idlist COMMA nm */ -{yymsp[-2].minor.yy336 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy336,&yymsp[0].minor.yy0);} + case 161: /* idlist ::= idlist COMMA nm */ +{yymsp[-2].minor.yy76 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy76,&yymsp[0].minor.yy0);} break; - case 161: /* idlist ::= nm */ -{yymsp[0].minor.yy336 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} + case 162: /* idlist ::= nm */ +{yymsp[0].minor.yy76 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} break; - case 162: /* expr ::= LP expr RP */ -{yymsp[-2].minor.yy490 = yymsp[-1].minor.yy490;} + case 163: /* expr ::= LP expr RP */ +{yymsp[-2].minor.yy102 = yymsp[-1].minor.yy102;} break; - case 163: /* expr ::= ID|INDEXED */ - case 164: /* expr ::= JOIN_KW */ yytestcase(yyruleno==164); -{yymsp[0].minor.yy490=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} + case 164: /* expr ::= ID|INDEXED */ + case 165: /* expr ::= JOIN_KW */ yytestcase(yyruleno==165); +{yymsp[0].minor.yy102=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 165: /* expr ::= nm DOT nm */ + case 166: /* expr ::= nm DOT nm */ { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1); @@ -151083,11 +152562,11 @@ static YYACTIONTYPE yy_reduce( sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[0].minor.yy0); sqlite3RenameTokenMap(pParse, (void*)temp1, &yymsp[-2].minor.yy0); } - yylhsminor.yy490 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); + yylhsminor.yy102 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } - yymsp[-2].minor.yy490 = yylhsminor.yy490; + yymsp[-2].minor.yy102 = yylhsminor.yy102; break; - case 166: /* expr ::= nm DOT nm DOT nm */ + case 167: /* expr ::= nm DOT nm DOT nm */ { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1); @@ -151097,26 +152576,26 @@ static YYACTIONTYPE yy_reduce( sqlite3RenameTokenMap(pParse, (void*)temp3, &yymsp[0].minor.yy0); sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[-2].minor.yy0); } - yylhsminor.yy490 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); + yylhsminor.yy102 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); } - yymsp[-4].minor.yy490 = yylhsminor.yy490; + yymsp[-4].minor.yy102 = yylhsminor.yy102; break; - case 167: /* term ::= NULL|FLOAT|BLOB */ - case 168: /* term ::= STRING */ yytestcase(yyruleno==168); -{yymsp[0].minor.yy490=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} + case 168: /* term ::= NULL|FLOAT|BLOB */ + case 169: /* term ::= STRING */ yytestcase(yyruleno==169); +{yymsp[0].minor.yy102=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; - case 169: /* term ::= INTEGER */ + case 170: /* term ::= INTEGER */ { - yylhsminor.yy490 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); + yylhsminor.yy102 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); } - yymsp[0].minor.yy490 = yylhsminor.yy490; + yymsp[0].minor.yy102 = yylhsminor.yy102; break; - case 170: /* expr ::= VARIABLE */ + case 171: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; - yymsp[0].minor.yy490 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); - sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy490, n); + yymsp[0].minor.yy102 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy102, n); }else{ /* When doing a nested parse, one can include terms in an expression ** that look like this: #1 #2 ... These terms refer to registers @@ -151125,154 +152604,156 @@ static YYACTIONTYPE yy_reduce( assert( t.n>=2 ); if( pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); - yymsp[0].minor.yy490 = 0; + yymsp[0].minor.yy102 = 0; }else{ - yymsp[0].minor.yy490 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); - if( yymsp[0].minor.yy490 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy490->iTable); + yymsp[0].minor.yy102 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); + if( yymsp[0].minor.yy102 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy102->iTable); } } } break; - case 171: /* expr ::= expr COLLATE ID|STRING */ + case 172: /* expr ::= expr COLLATE ID|STRING */ { - yymsp[-2].minor.yy490 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy490, &yymsp[0].minor.yy0, 1); + yymsp[-2].minor.yy102 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy102, &yymsp[0].minor.yy0, 1); } break; - case 172: /* expr ::= CAST LP expr AS typetoken RP */ + case 173: /* expr ::= CAST LP expr AS typetoken RP */ { - yymsp[-5].minor.yy490 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); - sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy490, yymsp[-3].minor.yy490, 0); + yymsp[-5].minor.yy102 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); + sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy102, yymsp[-3].minor.yy102, 0); } break; - case 173: /* expr ::= ID|INDEXED LP distinct exprlist RP */ + case 174: /* expr ::= ID|INDEXED LP distinct exprlist RP */ { - yylhsminor.yy490 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy42, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy96); + yylhsminor.yy102 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy94, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy100); } - yymsp[-4].minor.yy490 = yylhsminor.yy490; + yymsp[-4].minor.yy102 = yylhsminor.yy102; break; - case 174: /* expr ::= ID|INDEXED LP STAR RP */ + case 175: /* expr ::= ID|INDEXED LP STAR RP */ { - yylhsminor.yy490 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); + yylhsminor.yy102 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); } - yymsp[-3].minor.yy490 = yylhsminor.yy490; + yymsp[-3].minor.yy102 = yylhsminor.yy102; break; - case 175: /* expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ + case 176: /* expr ::= ID|INDEXED LP distinct exprlist RP over_clause */ { - yylhsminor.yy490 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy42, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy96); - sqlite3WindowAttach(pParse, yylhsminor.yy490, yymsp[0].minor.yy147); + yylhsminor.yy102 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy94, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy100); + sqlite3WindowAttach(pParse, yylhsminor.yy102, yymsp[0].minor.yy379); } - yymsp[-5].minor.yy490 = yylhsminor.yy490; + yymsp[-5].minor.yy102 = yylhsminor.yy102; break; - case 176: /* expr ::= ID|INDEXED LP STAR RP over_clause */ + case 177: /* expr ::= ID|INDEXED LP STAR RP over_clause */ { - yylhsminor.yy490 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); - sqlite3WindowAttach(pParse, yylhsminor.yy490, yymsp[0].minor.yy147); + yylhsminor.yy102 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); + sqlite3WindowAttach(pParse, yylhsminor.yy102, yymsp[0].minor.yy379); } - yymsp[-4].minor.yy490 = yylhsminor.yy490; + yymsp[-4].minor.yy102 = yylhsminor.yy102; break; - case 177: /* term ::= CTIME_KW */ + case 178: /* term ::= CTIME_KW */ { - yylhsminor.yy490 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); + yylhsminor.yy102 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); } - yymsp[0].minor.yy490 = yylhsminor.yy490; + yymsp[0].minor.yy102 = yylhsminor.yy102; break; - case 178: /* expr ::= LP nexprlist COMMA expr RP */ + case 179: /* expr ::= LP nexprlist COMMA expr RP */ { - ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy42, yymsp[-1].minor.yy490); - yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); - if( yymsp[-4].minor.yy490 ){ - yymsp[-4].minor.yy490->x.pList = pList; + ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy94, yymsp[-1].minor.yy102); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( yymsp[-4].minor.yy102 ){ + yymsp[-4].minor.yy102->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } } break; - case 179: /* expr ::= expr AND expr */ - case 180: /* expr ::= expr OR expr */ yytestcase(yyruleno==180); - case 181: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==181); - case 182: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==182); - case 183: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==183); - case 184: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==184); - case 185: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==185); - case 186: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==186); -{yymsp[-2].minor.yy490=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy490,yymsp[0].minor.yy490);} + case 180: /* expr ::= expr AND expr */ +{yymsp[-2].minor.yy102=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy102,yymsp[0].minor.yy102);} + break; + case 181: /* expr ::= expr OR expr */ + case 182: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==182); + case 183: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==183); + case 184: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==184); + case 185: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==185); + case 186: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==186); + case 187: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==187); +{yymsp[-2].minor.yy102=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy102,yymsp[0].minor.yy102);} break; - case 187: /* likeop ::= NOT LIKE_KW|MATCH */ + case 188: /* likeop ::= NOT LIKE_KW|MATCH */ {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} break; - case 188: /* expr ::= expr likeop expr */ + case 189: /* expr ::= expr likeop expr */ { ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; yymsp[-1].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy490); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy490); - yymsp[-2].minor.yy490 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); - if( bNot ) yymsp[-2].minor.yy490 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy490, 0); - if( yymsp[-2].minor.yy490 ) yymsp[-2].minor.yy490->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy102); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy102); + yymsp[-2].minor.yy102 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); + if( bNot ) yymsp[-2].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy102, 0); + if( yymsp[-2].minor.yy102 ) yymsp[-2].minor.yy102->flags |= EP_InfixFunc; } break; - case 189: /* expr ::= expr likeop expr ESCAPE expr */ + case 190: /* expr ::= expr likeop expr ESCAPE expr */ { ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; yymsp[-3].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy490); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy490); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy490); - yymsp[-4].minor.yy490 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); - if( bNot ) yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy490, 0); - if( yymsp[-4].minor.yy490 ) yymsp[-4].minor.yy490->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy102); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy102); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy102); + yymsp[-4].minor.yy102 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); + if( bNot ) yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy102, 0); + if( yymsp[-4].minor.yy102 ) yymsp[-4].minor.yy102->flags |= EP_InfixFunc; } break; - case 190: /* expr ::= expr ISNULL|NOTNULL */ -{yymsp[-1].minor.yy490 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy490,0);} + case 191: /* expr ::= expr ISNULL|NOTNULL */ +{yymsp[-1].minor.yy102 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy102,0);} break; - case 191: /* expr ::= expr NOT NULL */ -{yymsp[-2].minor.yy490 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy490,0);} + case 192: /* expr ::= expr NOT NULL */ +{yymsp[-2].minor.yy102 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy102,0);} break; - case 192: /* expr ::= expr IS expr */ + case 193: /* expr ::= expr IS expr */ { - yymsp[-2].minor.yy490 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy490,yymsp[0].minor.yy490); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy490, yymsp[-2].minor.yy490, TK_ISNULL); + yymsp[-2].minor.yy102 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy102,yymsp[0].minor.yy102); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy102, yymsp[-2].minor.yy102, TK_ISNULL); } break; - case 193: /* expr ::= expr IS NOT expr */ + case 194: /* expr ::= expr IS NOT expr */ { - yymsp[-3].minor.yy490 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy490,yymsp[0].minor.yy490); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy490, yymsp[-3].minor.yy490, TK_NOTNULL); + yymsp[-3].minor.yy102 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy102,yymsp[0].minor.yy102); + binaryToUnaryIfNull(pParse, yymsp[0].minor.yy102, yymsp[-3].minor.yy102, TK_NOTNULL); } break; - case 194: /* expr ::= NOT expr */ - case 195: /* expr ::= BITNOT expr */ yytestcase(yyruleno==195); -{yymsp[-1].minor.yy490 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy490, 0);/*A-overwrites-B*/} + case 195: /* expr ::= NOT expr */ + case 196: /* expr ::= BITNOT expr */ yytestcase(yyruleno==196); +{yymsp[-1].minor.yy102 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy102, 0);/*A-overwrites-B*/} break; - case 196: /* expr ::= PLUS|MINUS expr */ + case 197: /* expr ::= PLUS|MINUS expr */ { - yymsp[-1].minor.yy490 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy490, 0); + yymsp[-1].minor.yy102 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy102, 0); /*A-overwrites-B*/ } break; - case 197: /* between_op ::= BETWEEN */ - case 200: /* in_op ::= IN */ yytestcase(yyruleno==200); -{yymsp[0].minor.yy96 = 0;} + case 198: /* between_op ::= BETWEEN */ + case 201: /* in_op ::= IN */ yytestcase(yyruleno==201); +{yymsp[0].minor.yy100 = 0;} break; - case 199: /* expr ::= expr between_op expr AND expr */ + case 200: /* expr ::= expr between_op expr AND expr */ { - ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy490); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy490); - yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy490, 0); - if( yymsp[-4].minor.yy490 ){ - yymsp[-4].minor.yy490->x.pList = pList; + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy102); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy102); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy102, 0); + if( yymsp[-4].minor.yy102 ){ + yymsp[-4].minor.yy102->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } - if( yymsp[-3].minor.yy96 ) yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy490, 0); + if( yymsp[-3].minor.yy100 ) yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy102, 0); } break; - case 202: /* expr ::= expr in_op LP exprlist RP */ + case 203: /* expr ::= expr in_op LP exprlist RP */ { - if( yymsp[-1].minor.yy42==0 ){ + if( yymsp[-1].minor.yy94==0 ){ /* Expressions of the form ** ** expr1 IN () @@ -151281,11 +152762,9 @@ static YYACTIONTYPE yy_reduce( ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ - if( IN_RENAME_OBJECT==0 ){ - sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy490); - yymsp[-4].minor.yy490 = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy96],1); - } - }else if( yymsp[-1].minor.yy42->nExpr==1 ){ + sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy102); + yymsp[-4].minor.yy102 = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy100],1); + }else if( yymsp[-1].minor.yy94->nExpr==1 ){ /* Expressions of the form: ** ** expr1 IN (?1) @@ -151302,199 +152781,199 @@ static YYACTIONTYPE yy_reduce( ** affinity or the collating sequence to use for comparison. Otherwise, ** the semantics would be subtly different from IN or NOT IN. */ - Expr *pRHS = yymsp[-1].minor.yy42->a[0].pExpr; - yymsp[-1].minor.yy42->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy42); + Expr *pRHS = yymsp[-1].minor.yy94->a[0].pExpr; + yymsp[-1].minor.yy94->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy94); /* pRHS cannot be NULL because a malloc error would have been detected ** before now and control would have never reached this point */ if( ALWAYS(pRHS) ){ pRHS->flags &= ~EP_Collate; pRHS->flags |= EP_Generic; } - yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, yymsp[-3].minor.yy96 ? TK_NE : TK_EQ, yymsp[-4].minor.yy490, pRHS); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, yymsp[-3].minor.yy100 ? TK_NE : TK_EQ, yymsp[-4].minor.yy102, pRHS); }else{ - yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy490, 0); - if( yymsp[-4].minor.yy490 ){ - yymsp[-4].minor.yy490->x.pList = yymsp[-1].minor.yy42; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy490); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy102, 0); + if( yymsp[-4].minor.yy102 ){ + yymsp[-4].minor.yy102->x.pList = yymsp[-1].minor.yy94; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy102); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy42); + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy94); } - if( yymsp[-3].minor.yy96 ) yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy490, 0); + if( yymsp[-3].minor.yy100 ) yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy102, 0); } } break; - case 203: /* expr ::= LP select RP */ + case 204: /* expr ::= LP select RP */ { - yymsp[-2].minor.yy490 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); - sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy490, yymsp[-1].minor.yy423); + yymsp[-2].minor.yy102 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy102, yymsp[-1].minor.yy391); } break; - case 204: /* expr ::= expr in_op LP select RP */ + case 205: /* expr ::= expr in_op LP select RP */ { - yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy490, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy490, yymsp[-1].minor.yy423); - if( yymsp[-3].minor.yy96 ) yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy490, 0); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy102, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy102, yymsp[-1].minor.yy391); + if( yymsp[-3].minor.yy100 ) yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy102, 0); } break; - case 205: /* expr ::= expr in_op nm dbnm paren_exprlist */ + case 206: /* expr ::= expr in_op nm dbnm paren_exprlist */ { SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); - if( yymsp[0].minor.yy42 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy42); - yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy490, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy490, pSelect); - if( yymsp[-3].minor.yy96 ) yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy490, 0); + if( yymsp[0].minor.yy94 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy94); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy102, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy102, pSelect); + if( yymsp[-3].minor.yy100 ) yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy102, 0); } break; - case 206: /* expr ::= EXISTS LP select RP */ + case 207: /* expr ::= EXISTS LP select RP */ { Expr *p; - p = yymsp[-3].minor.yy490 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); - sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy423); + p = yymsp[-3].minor.yy102 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy391); } break; - case 207: /* expr ::= CASE case_operand case_exprlist case_else END */ + case 208: /* expr ::= CASE case_operand case_exprlist case_else END */ { - yymsp[-4].minor.yy490 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy490, 0); - if( yymsp[-4].minor.yy490 ){ - yymsp[-4].minor.yy490->x.pList = yymsp[-1].minor.yy490 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy42,yymsp[-1].minor.yy490) : yymsp[-2].minor.yy42; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy490); + yymsp[-4].minor.yy102 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy102, 0); + if( yymsp[-4].minor.yy102 ){ + yymsp[-4].minor.yy102->x.pList = yymsp[-1].minor.yy102 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy94,yymsp[-1].minor.yy102) : yymsp[-2].minor.yy94; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy102); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy42); - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy490); + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy94); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy102); } } break; - case 208: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ + case 209: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { - yymsp[-4].minor.yy42 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy42, yymsp[-2].minor.yy490); - yymsp[-4].minor.yy42 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy42, yymsp[0].minor.yy490); + yymsp[-4].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy94, yymsp[-2].minor.yy102); + yymsp[-4].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy94, yymsp[0].minor.yy102); } break; - case 209: /* case_exprlist ::= WHEN expr THEN expr */ + case 210: /* case_exprlist ::= WHEN expr THEN expr */ { - yymsp[-3].minor.yy42 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy490); - yymsp[-3].minor.yy42 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy42, yymsp[0].minor.yy490); + yymsp[-3].minor.yy94 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy102); + yymsp[-3].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy94, yymsp[0].minor.yy102); } break; - case 212: /* case_operand ::= expr */ -{yymsp[0].minor.yy490 = yymsp[0].minor.yy490; /*A-overwrites-X*/} + case 213: /* case_operand ::= expr */ +{yymsp[0].minor.yy102 = yymsp[0].minor.yy102; /*A-overwrites-X*/} break; - case 215: /* nexprlist ::= nexprlist COMMA expr */ -{yymsp[-2].minor.yy42 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy42,yymsp[0].minor.yy490);} + case 216: /* nexprlist ::= nexprlist COMMA expr */ +{yymsp[-2].minor.yy94 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy94,yymsp[0].minor.yy102);} break; - case 216: /* nexprlist ::= expr */ -{yymsp[0].minor.yy42 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy490); /*A-overwrites-Y*/} + case 217: /* nexprlist ::= expr */ +{yymsp[0].minor.yy94 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy102); /*A-overwrites-Y*/} break; - case 218: /* paren_exprlist ::= LP exprlist RP */ - case 223: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==223); -{yymsp[-2].minor.yy42 = yymsp[-1].minor.yy42;} + case 219: /* paren_exprlist ::= LP exprlist RP */ + case 224: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==224); +{yymsp[-2].minor.yy94 = yymsp[-1].minor.yy94;} break; - case 219: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ + case 220: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, - sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy42, yymsp[-10].minor.yy96, - &yymsp[-11].minor.yy0, yymsp[0].minor.yy490, SQLITE_SO_ASC, yymsp[-8].minor.yy96, SQLITE_IDXTYPE_APPDEF); + sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy94, yymsp[-10].minor.yy100, + &yymsp[-11].minor.yy0, yymsp[0].minor.yy102, SQLITE_SO_ASC, yymsp[-8].minor.yy100, SQLITE_IDXTYPE_APPDEF); if( IN_RENAME_OBJECT && pParse->pNewIndex ){ sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0); } } break; - case 220: /* uniqueflag ::= UNIQUE */ - case 262: /* raisetype ::= ABORT */ yytestcase(yyruleno==262); -{yymsp[0].minor.yy96 = OE_Abort;} + case 221: /* uniqueflag ::= UNIQUE */ + case 263: /* raisetype ::= ABORT */ yytestcase(yyruleno==263); +{yymsp[0].minor.yy100 = OE_Abort;} break; - case 221: /* uniqueflag ::= */ -{yymsp[1].minor.yy96 = OE_None;} + case 222: /* uniqueflag ::= */ +{yymsp[1].minor.yy100 = OE_None;} break; - case 224: /* eidlist ::= eidlist COMMA nm collate sortorder */ + case 225: /* eidlist ::= eidlist COMMA nm collate sortorder */ { - yymsp[-4].minor.yy42 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy42, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy96, yymsp[0].minor.yy96); + yymsp[-4].minor.yy94 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy94, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy100, yymsp[0].minor.yy100); } break; - case 225: /* eidlist ::= nm collate sortorder */ + case 226: /* eidlist ::= nm collate sortorder */ { - yymsp[-2].minor.yy42 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy96, yymsp[0].minor.yy96); /*A-overwrites-Y*/ + yymsp[-2].minor.yy94 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy100, yymsp[0].minor.yy100); /*A-overwrites-Y*/ } break; - case 228: /* cmd ::= DROP INDEX ifexists fullname */ -{sqlite3DropIndex(pParse, yymsp[0].minor.yy167, yymsp[-1].minor.yy96);} + case 229: /* cmd ::= DROP INDEX ifexists fullname */ +{sqlite3DropIndex(pParse, yymsp[0].minor.yy407, yymsp[-1].minor.yy100);} break; - case 229: /* cmd ::= VACUUM vinto */ -{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy490);} + case 230: /* cmd ::= VACUUM vinto */ +{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy102);} break; - case 230: /* cmd ::= VACUUM nm vinto */ -{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy490);} + case 231: /* cmd ::= VACUUM nm vinto */ +{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy102);} break; - case 233: /* cmd ::= PRAGMA nm dbnm */ + case 234: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} break; - case 234: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ + case 235: /* cmd ::= PRAGMA nm dbnm EQ nmnum */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);} break; - case 235: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ + case 236: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);} break; - case 236: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ + case 237: /* cmd ::= PRAGMA nm dbnm EQ minus_num */ {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);} break; - case 237: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ + case 238: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */ {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);} break; - case 240: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ + case 241: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */ { Token all; all.z = yymsp[-3].minor.yy0.z; all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; - sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy119, &all); + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy11, &all); } break; - case 241: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ + case 242: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { - sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy96, yymsp[-4].minor.yy350.a, yymsp[-4].minor.yy350.b, yymsp[-2].minor.yy167, yymsp[0].minor.yy490, yymsp[-10].minor.yy96, yymsp[-8].minor.yy96); + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy100, yymsp[-4].minor.yy298.a, yymsp[-4].minor.yy298.b, yymsp[-2].minor.yy407, yymsp[0].minor.yy102, yymsp[-10].minor.yy100, yymsp[-8].minor.yy100); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ } break; - case 242: /* trigger_time ::= BEFORE|AFTER */ -{ yymsp[0].minor.yy96 = yymsp[0].major; /*A-overwrites-X*/ } + case 243: /* trigger_time ::= BEFORE|AFTER */ +{ yymsp[0].minor.yy100 = yymsp[0].major; /*A-overwrites-X*/ } break; - case 243: /* trigger_time ::= INSTEAD OF */ -{ yymsp[-1].minor.yy96 = TK_INSTEAD;} + case 244: /* trigger_time ::= INSTEAD OF */ +{ yymsp[-1].minor.yy100 = TK_INSTEAD;} break; - case 244: /* trigger_time ::= */ -{ yymsp[1].minor.yy96 = TK_BEFORE; } + case 245: /* trigger_time ::= */ +{ yymsp[1].minor.yy100 = TK_BEFORE; } break; - case 245: /* trigger_event ::= DELETE|INSERT */ - case 246: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==246); -{yymsp[0].minor.yy350.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy350.b = 0;} + case 246: /* trigger_event ::= DELETE|INSERT */ + case 247: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==247); +{yymsp[0].minor.yy298.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy298.b = 0;} break; - case 247: /* trigger_event ::= UPDATE OF idlist */ -{yymsp[-2].minor.yy350.a = TK_UPDATE; yymsp[-2].minor.yy350.b = yymsp[0].minor.yy336;} + case 248: /* trigger_event ::= UPDATE OF idlist */ +{yymsp[-2].minor.yy298.a = TK_UPDATE; yymsp[-2].minor.yy298.b = yymsp[0].minor.yy76;} break; - case 248: /* when_clause ::= */ - case 267: /* key_opt ::= */ yytestcase(yyruleno==267); - case 309: /* filter_opt ::= */ yytestcase(yyruleno==309); -{ yymsp[1].minor.yy490 = 0; } + case 249: /* when_clause ::= */ + case 268: /* key_opt ::= */ yytestcase(yyruleno==268); + case 316: /* filter_opt ::= */ yytestcase(yyruleno==316); +{ yymsp[1].minor.yy102 = 0; } break; - case 249: /* when_clause ::= WHEN expr */ - case 268: /* key_opt ::= KEY expr */ yytestcase(yyruleno==268); -{ yymsp[-1].minor.yy490 = yymsp[0].minor.yy490; } + case 250: /* when_clause ::= WHEN expr */ + case 269: /* key_opt ::= KEY expr */ yytestcase(yyruleno==269); +{ yymsp[-1].minor.yy102 = yymsp[0].minor.yy102; } break; - case 250: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ + case 251: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { - assert( yymsp[-2].minor.yy119!=0 ); - yymsp[-2].minor.yy119->pLast->pNext = yymsp[-1].minor.yy119; - yymsp[-2].minor.yy119->pLast = yymsp[-1].minor.yy119; + assert( yymsp[-2].minor.yy11!=0 ); + yymsp[-2].minor.yy11->pLast->pNext = yymsp[-1].minor.yy11; + yymsp[-2].minor.yy11->pLast = yymsp[-1].minor.yy11; } break; - case 251: /* trigger_cmd_list ::= trigger_cmd SEMI */ + case 252: /* trigger_cmd_list ::= trigger_cmd SEMI */ { - assert( yymsp[-1].minor.yy119!=0 ); - yymsp[-1].minor.yy119->pLast = yymsp[-1].minor.yy119; + assert( yymsp[-1].minor.yy11!=0 ); + yymsp[-1].minor.yy11->pLast = yymsp[-1].minor.yy11; } break; - case 252: /* trnm ::= nm DOT nm */ + case 253: /* trnm ::= nm DOT nm */ { yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; sqlite3ErrorMsg(pParse, @@ -151502,306 +152981,328 @@ static YYACTIONTYPE yy_reduce( "statements within triggers"); } break; - case 253: /* tridxby ::= INDEXED BY nm */ + case 254: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 254: /* tridxby ::= NOT INDEXED */ + case 255: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 255: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ -{yylhsminor.yy119 = sqlite3TriggerUpdateStep(pParse, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy42, yymsp[-1].minor.yy490, yymsp[-6].minor.yy96, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy464);} - yymsp[-7].minor.yy119 = yylhsminor.yy119; + case 256: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */ +{yylhsminor.yy11 = sqlite3TriggerUpdateStep(pParse, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy94, yymsp[-1].minor.yy102, yymsp[-6].minor.yy100, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy528);} + yymsp[-7].minor.yy11 = yylhsminor.yy11; break; - case 256: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + case 257: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ { - yylhsminor.yy119 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy336,yymsp[-2].minor.yy423,yymsp[-6].minor.yy96,yymsp[-1].minor.yy266,yymsp[-7].minor.yy464,yymsp[0].minor.yy464);/*yylhsminor.yy119-overwrites-yymsp[-6].minor.yy96*/ + yylhsminor.yy11 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy76,yymsp[-2].minor.yy391,yymsp[-6].minor.yy100,yymsp[-1].minor.yy95,yymsp[-7].minor.yy528,yymsp[0].minor.yy528);/*yylhsminor.yy11-overwrites-yymsp[-6].minor.yy100*/ } - yymsp[-7].minor.yy119 = yylhsminor.yy119; + yymsp[-7].minor.yy11 = yylhsminor.yy11; break; - case 257: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ -{yylhsminor.yy119 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy490, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy464);} - yymsp[-5].minor.yy119 = yylhsminor.yy119; + case 258: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ +{yylhsminor.yy11 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy102, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy528);} + yymsp[-5].minor.yy11 = yylhsminor.yy11; break; - case 258: /* trigger_cmd ::= scanpt select scanpt */ -{yylhsminor.yy119 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy423, yymsp[-2].minor.yy464, yymsp[0].minor.yy464); /*yylhsminor.yy119-overwrites-yymsp[-1].minor.yy423*/} - yymsp[-2].minor.yy119 = yylhsminor.yy119; + case 259: /* trigger_cmd ::= scanpt select scanpt */ +{yylhsminor.yy11 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy391, yymsp[-2].minor.yy528, yymsp[0].minor.yy528); /*yylhsminor.yy11-overwrites-yymsp[-1].minor.yy391*/} + yymsp[-2].minor.yy11 = yylhsminor.yy11; break; - case 259: /* expr ::= RAISE LP IGNORE RP */ + case 260: /* expr ::= RAISE LP IGNORE RP */ { - yymsp[-3].minor.yy490 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); - if( yymsp[-3].minor.yy490 ){ - yymsp[-3].minor.yy490->affinity = OE_Ignore; + yymsp[-3].minor.yy102 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); + if( yymsp[-3].minor.yy102 ){ + yymsp[-3].minor.yy102->affinity = OE_Ignore; } } break; - case 260: /* expr ::= RAISE LP raisetype COMMA nm RP */ + case 261: /* expr ::= RAISE LP raisetype COMMA nm RP */ { - yymsp[-5].minor.yy490 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); - if( yymsp[-5].minor.yy490 ) { - yymsp[-5].minor.yy490->affinity = (char)yymsp[-3].minor.yy96; + yymsp[-5].minor.yy102 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); + if( yymsp[-5].minor.yy102 ) { + yymsp[-5].minor.yy102->affinity = (char)yymsp[-3].minor.yy100; } } break; - case 261: /* raisetype ::= ROLLBACK */ -{yymsp[0].minor.yy96 = OE_Rollback;} + case 262: /* raisetype ::= ROLLBACK */ +{yymsp[0].minor.yy100 = OE_Rollback;} break; - case 263: /* raisetype ::= FAIL */ -{yymsp[0].minor.yy96 = OE_Fail;} + case 264: /* raisetype ::= FAIL */ +{yymsp[0].minor.yy100 = OE_Fail;} break; - case 264: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 265: /* cmd ::= DROP TRIGGER ifexists fullname */ { - sqlite3DropTrigger(pParse,yymsp[0].minor.yy167,yymsp[-1].minor.yy96); + sqlite3DropTrigger(pParse,yymsp[0].minor.yy407,yymsp[-1].minor.yy100); } break; - case 265: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 266: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { - sqlite3Attach(pParse, yymsp[-3].minor.yy490, yymsp[-1].minor.yy490, yymsp[0].minor.yy490); + sqlite3Attach(pParse, yymsp[-3].minor.yy102, yymsp[-1].minor.yy102, yymsp[0].minor.yy102); } break; - case 266: /* cmd ::= DETACH database_kw_opt expr */ + case 267: /* cmd ::= DETACH database_kw_opt expr */ { - sqlite3Detach(pParse, yymsp[0].minor.yy490); + sqlite3Detach(pParse, yymsp[0].minor.yy102); } break; - case 269: /* cmd ::= REINDEX */ + case 270: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 270: /* cmd ::= REINDEX nm dbnm */ + case 271: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 271: /* cmd ::= ANALYZE */ + case 272: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 272: /* cmd ::= ANALYZE nm dbnm */ + case 273: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 273: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 274: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy167,&yymsp[0].minor.yy0); + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy407,&yymsp[0].minor.yy0); } break; - case 274: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 275: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 275: /* add_column_fullname ::= fullname */ + case 276: /* add_column_fullname ::= fullname */ { disableLookaside(pParse); - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy167); + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy407); } break; - case 276: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + case 277: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ { - sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy167, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); + sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy407, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); } break; - case 277: /* cmd ::= create_vtab */ + case 278: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 278: /* cmd ::= create_vtab LP vtabarglist RP */ + case 279: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 279: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 280: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { - sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy96); + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy100); } break; - case 280: /* vtabarg ::= */ + case 281: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 281: /* vtabargtoken ::= ANY */ - case 282: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==282); - case 283: /* lp ::= LP */ yytestcase(yyruleno==283); + case 282: /* vtabargtoken ::= ANY */ + case 283: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==283); + case 284: /* lp ::= LP */ yytestcase(yyruleno==284); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 284: /* with ::= WITH wqlist */ - case 285: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==285); -{ sqlite3WithPush(pParse, yymsp[0].minor.yy499, 1); } + case 285: /* with ::= WITH wqlist */ + case 286: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==286); +{ sqlite3WithPush(pParse, yymsp[0].minor.yy243, 1); } break; - case 286: /* wqlist ::= nm eidlist_opt AS LP select RP */ + case 287: /* wqlist ::= nm eidlist_opt AS LP select RP */ { - yymsp[-5].minor.yy499 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy42, yymsp[-1].minor.yy423); /*A-overwrites-X*/ + yymsp[-5].minor.yy243 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy94, yymsp[-1].minor.yy391); /*A-overwrites-X*/ } break; - case 287: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ + case 288: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */ { - yymsp[-7].minor.yy499 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy499, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy42, yymsp[-1].minor.yy423); + yymsp[-7].minor.yy243 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy243, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy94, yymsp[-1].minor.yy391); } break; - case 288: /* windowdefn_list ::= windowdefn */ -{ yylhsminor.yy147 = yymsp[0].minor.yy147; } - yymsp[0].minor.yy147 = yylhsminor.yy147; + case 289: /* windowdefn_list ::= windowdefn */ +{ yylhsminor.yy379 = yymsp[0].minor.yy379; } + yymsp[0].minor.yy379 = yylhsminor.yy379; break; - case 289: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ + case 290: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ { - assert( yymsp[0].minor.yy147!=0 ); - yymsp[0].minor.yy147->pNextWin = yymsp[-2].minor.yy147; - yylhsminor.yy147 = yymsp[0].minor.yy147; + assert( yymsp[0].minor.yy379!=0 ); + sqlite3WindowChain(pParse, yymsp[0].minor.yy379, yymsp[-2].minor.yy379); + yymsp[0].minor.yy379->pNextWin = yymsp[-2].minor.yy379; + yylhsminor.yy379 = yymsp[0].minor.yy379; } - yymsp[-2].minor.yy147 = yylhsminor.yy147; + yymsp[-2].minor.yy379 = yylhsminor.yy379; break; - case 290: /* windowdefn ::= nm AS window */ + case 291: /* windowdefn ::= nm AS LP window RP */ { - if( ALWAYS(yymsp[0].minor.yy147) ){ - yymsp[0].minor.yy147->zName = sqlite3DbStrNDup(pParse->db, yymsp[-2].minor.yy0.z, yymsp[-2].minor.yy0.n); + if( ALWAYS(yymsp[-1].minor.yy379) ){ + yymsp[-1].minor.yy379->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); } - yylhsminor.yy147 = yymsp[0].minor.yy147; + yylhsminor.yy379 = yymsp[-1].minor.yy379; } - yymsp[-2].minor.yy147 = yylhsminor.yy147; + yymsp[-4].minor.yy379 = yylhsminor.yy379; break; - case 291: /* window ::= LP part_opt orderby_opt frame_opt RP */ + case 292: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ { - yymsp[-4].minor.yy147 = yymsp[-1].minor.yy147; - if( ALWAYS(yymsp[-4].minor.yy147) ){ - yymsp[-4].minor.yy147->pPartition = yymsp[-3].minor.yy42; - yymsp[-4].minor.yy147->pOrderBy = yymsp[-2].minor.yy42; - } + yymsp[-4].minor.yy379 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy379, yymsp[-2].minor.yy94, yymsp[-1].minor.yy94, 0); +} + break; + case 293: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ +{ + yylhsminor.yy379 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy379, yymsp[-2].minor.yy94, yymsp[-1].minor.yy94, &yymsp[-5].minor.yy0); +} + yymsp[-5].minor.yy379 = yylhsminor.yy379; + break; + case 294: /* window ::= ORDER BY sortlist frame_opt */ +{ + yymsp[-3].minor.yy379 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy379, 0, yymsp[-1].minor.yy94, 0); +} + break; + case 295: /* window ::= nm ORDER BY sortlist frame_opt */ +{ + yylhsminor.yy379 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy379, 0, yymsp[-1].minor.yy94, &yymsp[-4].minor.yy0); } + yymsp[-4].minor.yy379 = yylhsminor.yy379; break; - case 292: /* part_opt ::= PARTITION BY nexprlist */ -{ yymsp[-2].minor.yy42 = yymsp[0].minor.yy42; } + case 296: /* window ::= frame_opt */ +{ + yylhsminor.yy379 = yymsp[0].minor.yy379; +} + yymsp[0].minor.yy379 = yylhsminor.yy379; break; - case 293: /* part_opt ::= */ -{ yymsp[1].minor.yy42 = 0; } + case 297: /* window ::= nm frame_opt */ +{ + yylhsminor.yy379 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy379, 0, 0, &yymsp[-1].minor.yy0); +} + yymsp[-1].minor.yy379 = yylhsminor.yy379; break; - case 294: /* frame_opt ::= */ + case 298: /* frame_opt ::= */ { - yymsp[1].minor.yy147 = sqlite3WindowAlloc(pParse, TK_RANGE, TK_UNBOUNDED, 0, TK_CURRENT, 0); + yymsp[1].minor.yy379 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); } break; - case 295: /* frame_opt ::= range_or_rows frame_bound_s */ + case 299: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ { - yylhsminor.yy147 = sqlite3WindowAlloc(pParse, yymsp[-1].minor.yy96, yymsp[0].minor.yy317.eType, yymsp[0].minor.yy317.pExpr, TK_CURRENT, 0); + yylhsminor.yy379 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy100, yymsp[-1].minor.yy389.eType, yymsp[-1].minor.yy389.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy218); } - yymsp[-1].minor.yy147 = yylhsminor.yy147; + yymsp[-2].minor.yy379 = yylhsminor.yy379; break; - case 296: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e */ + case 300: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ { - yylhsminor.yy147 = sqlite3WindowAlloc(pParse, yymsp[-4].minor.yy96, yymsp[-2].minor.yy317.eType, yymsp[-2].minor.yy317.pExpr, yymsp[0].minor.yy317.eType, yymsp[0].minor.yy317.pExpr); + yylhsminor.yy379 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy100, yymsp[-3].minor.yy389.eType, yymsp[-3].minor.yy389.pExpr, yymsp[-1].minor.yy389.eType, yymsp[-1].minor.yy389.pExpr, yymsp[0].minor.yy218); } - yymsp[-4].minor.yy147 = yylhsminor.yy147; + yymsp[-5].minor.yy379 = yylhsminor.yy379; break; - case 297: /* range_or_rows ::= RANGE */ -{ yymsp[0].minor.yy96 = TK_RANGE; } + case 302: /* frame_bound_s ::= frame_bound */ + case 304: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==304); +{yylhsminor.yy389 = yymsp[0].minor.yy389;} + yymsp[0].minor.yy389 = yylhsminor.yy389; break; - case 298: /* range_or_rows ::= ROWS */ -{ yymsp[0].minor.yy96 = TK_ROWS; } + case 303: /* frame_bound_s ::= UNBOUNDED PRECEDING */ + case 305: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==305); + case 307: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==307); +{yylhsminor.yy389.eType = yymsp[-1].major; yylhsminor.yy389.pExpr = 0;} + yymsp[-1].minor.yy389 = yylhsminor.yy389; break; - case 299: /* frame_bound_s ::= frame_bound */ - case 301: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==301); -{ yylhsminor.yy317 = yymsp[0].minor.yy317; } - yymsp[0].minor.yy317 = yylhsminor.yy317; + case 306: /* frame_bound ::= expr PRECEDING|FOLLOWING */ +{yylhsminor.yy389.eType = yymsp[0].major; yylhsminor.yy389.pExpr = yymsp[-1].minor.yy102;} + yymsp[-1].minor.yy389 = yylhsminor.yy389; break; - case 300: /* frame_bound_s ::= UNBOUNDED PRECEDING */ - case 302: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==302); -{yymsp[-1].minor.yy317.eType = TK_UNBOUNDED; yymsp[-1].minor.yy317.pExpr = 0;} + case 308: /* frame_exclude_opt ::= */ +{yymsp[1].minor.yy218 = 0;} break; - case 303: /* frame_bound ::= expr PRECEDING */ -{ yylhsminor.yy317.eType = TK_PRECEDING; yylhsminor.yy317.pExpr = yymsp[-1].minor.yy490; } - yymsp[-1].minor.yy317 = yylhsminor.yy317; + case 309: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ +{yymsp[-1].minor.yy218 = yymsp[0].minor.yy218;} break; - case 304: /* frame_bound ::= CURRENT ROW */ -{ yymsp[-1].minor.yy317.eType = TK_CURRENT ; yymsp[-1].minor.yy317.pExpr = 0; } + case 310: /* frame_exclude ::= NO OTHERS */ + case 311: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==311); +{yymsp[-1].minor.yy218 = yymsp[-1].major; /*A-overwrites-X*/} break; - case 305: /* frame_bound ::= expr FOLLOWING */ -{ yylhsminor.yy317.eType = TK_FOLLOWING; yylhsminor.yy317.pExpr = yymsp[-1].minor.yy490; } - yymsp[-1].minor.yy317 = yylhsminor.yy317; + case 312: /* frame_exclude ::= GROUP|TIES */ +{yymsp[0].minor.yy218 = yymsp[0].major; /*A-overwrites-X*/} break; - case 306: /* window_clause ::= WINDOW windowdefn_list */ -{ yymsp[-1].minor.yy147 = yymsp[0].minor.yy147; } + case 313: /* window_clause ::= WINDOW windowdefn_list */ +{ yymsp[-1].minor.yy379 = yymsp[0].minor.yy379; } break; - case 307: /* over_clause ::= filter_opt OVER window */ + case 314: /* over_clause ::= filter_opt OVER LP window RP */ { - yylhsminor.yy147 = yymsp[0].minor.yy147; - assert( yylhsminor.yy147!=0 ); - yylhsminor.yy147->pFilter = yymsp[-2].minor.yy490; + yylhsminor.yy379 = yymsp[-1].minor.yy379; + assert( yylhsminor.yy379!=0 ); + yylhsminor.yy379->pFilter = yymsp[-4].minor.yy102; } - yymsp[-2].minor.yy147 = yylhsminor.yy147; + yymsp[-4].minor.yy379 = yylhsminor.yy379; break; - case 308: /* over_clause ::= filter_opt OVER nm */ + case 315: /* over_clause ::= filter_opt OVER nm */ { - yylhsminor.yy147 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); - if( yylhsminor.yy147 ){ - yylhsminor.yy147->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); - yylhsminor.yy147->pFilter = yymsp[-2].minor.yy490; + yylhsminor.yy379 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yylhsminor.yy379 ){ + yylhsminor.yy379->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); + yylhsminor.yy379->pFilter = yymsp[-2].minor.yy102; }else{ - sqlite3ExprDelete(pParse->db, yymsp[-2].minor.yy490); + sqlite3ExprDelete(pParse->db, yymsp[-2].minor.yy102); } } - yymsp[-2].minor.yy147 = yylhsminor.yy147; + yymsp[-2].minor.yy379 = yylhsminor.yy379; break; - case 310: /* filter_opt ::= FILTER LP WHERE expr RP */ -{ yymsp[-4].minor.yy490 = yymsp[-1].minor.yy490; } + case 317: /* filter_opt ::= FILTER LP WHERE expr RP */ +{ yymsp[-4].minor.yy102 = yymsp[-1].minor.yy102; } break; default: - /* (311) input ::= cmdlist */ yytestcase(yyruleno==311); - /* (312) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==312); - /* (313) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=313); - /* (314) ecmd ::= SEMI */ yytestcase(yyruleno==314); - /* (315) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==315); - /* (316) ecmd ::= explain cmdx */ yytestcase(yyruleno==316); - /* (317) trans_opt ::= */ yytestcase(yyruleno==317); - /* (318) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==318); - /* (319) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==319); - /* (320) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==320); - /* (321) savepoint_opt ::= */ yytestcase(yyruleno==321); - /* (322) cmd ::= create_table create_table_args */ yytestcase(yyruleno==322); - /* (323) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==323); - /* (324) columnlist ::= columnname carglist */ yytestcase(yyruleno==324); - /* (325) nm ::= ID|INDEXED */ yytestcase(yyruleno==325); - /* (326) nm ::= STRING */ yytestcase(yyruleno==326); - /* (327) nm ::= JOIN_KW */ yytestcase(yyruleno==327); - /* (328) typetoken ::= typename */ yytestcase(yyruleno==328); - /* (329) typename ::= ID|STRING */ yytestcase(yyruleno==329); - /* (330) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=330); - /* (331) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=331); - /* (332) carglist ::= carglist ccons */ yytestcase(yyruleno==332); - /* (333) carglist ::= */ yytestcase(yyruleno==333); - /* (334) ccons ::= NULL onconf */ yytestcase(yyruleno==334); - /* (335) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==335); - /* (336) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==336); - /* (337) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=337); - /* (338) tconscomma ::= */ yytestcase(yyruleno==338); - /* (339) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=339); - /* (340) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=340); - /* (341) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=341); - /* (342) oneselect ::= values */ yytestcase(yyruleno==342); - /* (343) sclp ::= selcollist COMMA */ yytestcase(yyruleno==343); - /* (344) as ::= ID|STRING */ yytestcase(yyruleno==344); - /* (345) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=345); - /* (346) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==346); - /* (347) exprlist ::= nexprlist */ yytestcase(yyruleno==347); - /* (348) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=348); - /* (349) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=349); - /* (350) nmnum ::= ON */ yytestcase(yyruleno==350); - /* (351) nmnum ::= DELETE */ yytestcase(yyruleno==351); - /* (352) nmnum ::= DEFAULT */ yytestcase(yyruleno==352); - /* (353) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==353); - /* (354) foreach_clause ::= */ yytestcase(yyruleno==354); - /* (355) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==355); - /* (356) trnm ::= nm */ yytestcase(yyruleno==356); - /* (357) tridxby ::= */ yytestcase(yyruleno==357); - /* (358) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==358); - /* (359) database_kw_opt ::= */ yytestcase(yyruleno==359); - /* (360) kwcolumn_opt ::= */ yytestcase(yyruleno==360); - /* (361) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==361); - /* (362) vtabarglist ::= vtabarg */ yytestcase(yyruleno==362); - /* (363) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==363); - /* (364) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==364); - /* (365) anylist ::= */ yytestcase(yyruleno==365); - /* (366) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==366); - /* (367) anylist ::= anylist ANY */ yytestcase(yyruleno==367); - /* (368) with ::= */ yytestcase(yyruleno==368); + /* (318) input ::= cmdlist */ yytestcase(yyruleno==318); + /* (319) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==319); + /* (320) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=320); + /* (321) ecmd ::= SEMI */ yytestcase(yyruleno==321); + /* (322) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==322); + /* (323) ecmd ::= explain cmdx */ yytestcase(yyruleno==323); + /* (324) trans_opt ::= */ yytestcase(yyruleno==324); + /* (325) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==325); + /* (326) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==326); + /* (327) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==327); + /* (328) savepoint_opt ::= */ yytestcase(yyruleno==328); + /* (329) cmd ::= create_table create_table_args */ yytestcase(yyruleno==329); + /* (330) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==330); + /* (331) columnlist ::= columnname carglist */ yytestcase(yyruleno==331); + /* (332) nm ::= ID|INDEXED */ yytestcase(yyruleno==332); + /* (333) nm ::= STRING */ yytestcase(yyruleno==333); + /* (334) nm ::= JOIN_KW */ yytestcase(yyruleno==334); + /* (335) typetoken ::= typename */ yytestcase(yyruleno==335); + /* (336) typename ::= ID|STRING */ yytestcase(yyruleno==336); + /* (337) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=337); + /* (338) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=338); + /* (339) carglist ::= carglist ccons */ yytestcase(yyruleno==339); + /* (340) carglist ::= */ yytestcase(yyruleno==340); + /* (341) ccons ::= NULL onconf */ yytestcase(yyruleno==341); + /* (342) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==342); + /* (343) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==343); + /* (344) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=344); + /* (345) tconscomma ::= */ yytestcase(yyruleno==345); + /* (346) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=346); + /* (347) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=347); + /* (348) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=348); + /* (349) oneselect ::= values */ yytestcase(yyruleno==349); + /* (350) sclp ::= selcollist COMMA */ yytestcase(yyruleno==350); + /* (351) as ::= ID|STRING */ yytestcase(yyruleno==351); + /* (352) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=352); + /* (353) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==353); + /* (354) exprlist ::= nexprlist */ yytestcase(yyruleno==354); + /* (355) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=355); + /* (356) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=356); + /* (357) nmnum ::= ON */ yytestcase(yyruleno==357); + /* (358) nmnum ::= DELETE */ yytestcase(yyruleno==358); + /* (359) nmnum ::= DEFAULT */ yytestcase(yyruleno==359); + /* (360) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==360); + /* (361) foreach_clause ::= */ yytestcase(yyruleno==361); + /* (362) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==362); + /* (363) trnm ::= nm */ yytestcase(yyruleno==363); + /* (364) tridxby ::= */ yytestcase(yyruleno==364); + /* (365) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==365); + /* (366) database_kw_opt ::= */ yytestcase(yyruleno==366); + /* (367) kwcolumn_opt ::= */ yytestcase(yyruleno==367); + /* (368) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==368); + /* (369) vtabarglist ::= vtabarg */ yytestcase(yyruleno==369); + /* (370) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==370); + /* (371) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==371); + /* (372) anylist ::= */ yytestcase(yyruleno==372); + /* (373) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==373); + /* (374) anylist ::= anylist ANY */ yytestcase(yyruleno==374); + /* (375) with ::= */ yytestcase(yyruleno==375); break; /********** End reduce actions ************************************************/ }; @@ -152264,144 +153765,144 @@ const unsigned char ebcdicToAscii[] = { ** is substantially reduced. This is important for embedded applications ** on platforms with limited memory. */ -/* Hash score: 208 */ -/* zKWText[] encodes 923 bytes of keyword text in 614 bytes */ +/* Hash score: 214 */ +/* zKWText[] encodes 950 bytes of keyword text in 629 bytes */ /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */ -/* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */ -/* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */ -/* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERANGEBETWEEN */ -/* OTHINGLOBYCASCADELETECASECOLLATECREATECURRENT_DATEDETACH */ -/* IMMEDIATEJOINSERTLIKEMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMIT */ -/* WHENOTNULLWHERECURSIVEAFTERENAMEANDEFAULTAUTOINCREMENTCAST */ -/* COLUMNCOMMITCONFLICTCROSSCURRENT_TIMESTAMPARTITIONDEFERRED */ -/* ISTINCTDROPRECEDINGFAILFILTEREPLACEFOLLOWINGFROMFULLIFISNULL */ -/* ORDERESTRICTOVERIGHTROLLBACKROWSUNBOUNDEDUNIONUSINGVACUUMVIEW */ -/* INDOWINITIALLYPRIMARY */ -static const char zKWText[613] = { +/* ABLEFTHENDEFERRABLELSEXCLUDELETEMPORARYCONSTRAINTERSECTIES */ +/* AVEPOINTOFFSETRANSACTIONATURALTERAISEXCEPTRIGGEREFERENCES */ +/* UNIQUERYWITHOUTERELEASEXCLUSIVEXISTSATTACHAVINGLOBEGINNERANGE */ +/* BETWEENOTHINGROUPSCASCADETACHCASECOLLATECREATECURRENT_DATE */ +/* IMMEDIATEJOINSERTLIKEMATCHPLANALYZEPRAGMABORTUPDATEVALUES */ +/* VIRTUALIMITWHENOTNULLWHERECURSIVEAFTERENAMEANDEFAULT */ +/* AUTOINCREMENTCASTCOLUMNCOMMITCONFLICTCROSSCURRENT_TIMESTAMP */ +/* ARTITIONDEFERREDISTINCTDROPRECEDINGFAILFILTEREPLACEFOLLOWING */ +/* FROMFULLIFISNULLORDERESTRICTOTHERSOVERIGHTROLLBACKROWS */ +/* UNBOUNDEDUNIONUSINGVACUUMVIEWINDOWBYINITIALLYPRIMARY */ +static const char zKWText[628] = { 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H', 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G', 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A', 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F', - 'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N', - 'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I', - 'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E', - 'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E', - 'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T', - 'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q', - 'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S', - 'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A', - 'T','E','B','E','G','I','N','N','E','R','A','N','G','E','B','E','T','W', - 'E','E','N','O','T','H','I','N','G','L','O','B','Y','C','A','S','C','A', - 'D','E','L','E','T','E','C','A','S','E','C','O','L','L','A','T','E','C', - 'R','E','A','T','E','C','U','R','R','E','N','T','_','D','A','T','E','D', - 'E','T','A','C','H','I','M','M','E','D','I','A','T','E','J','O','I','N', - 'S','E','R','T','L','I','K','E','M','A','T','C','H','P','L','A','N','A', - 'L','Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U', - 'E','S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','O', - 'T','N','U','L','L','W','H','E','R','E','C','U','R','S','I','V','E','A', - 'F','T','E','R','E','N','A','M','E','A','N','D','E','F','A','U','L','T', - 'A','U','T','O','I','N','C','R','E','M','E','N','T','C','A','S','T','C', - 'O','L','U','M','N','C','O','M','M','I','T','C','O','N','F','L','I','C', - 'T','C','R','O','S','S','C','U','R','R','E','N','T','_','T','I','M','E', - 'S','T','A','M','P','A','R','T','I','T','I','O','N','D','E','F','E','R', - 'R','E','D','I','S','T','I','N','C','T','D','R','O','P','R','E','C','E', - 'D','I','N','G','F','A','I','L','F','I','L','T','E','R','E','P','L','A', - 'C','E','F','O','L','L','O','W','I','N','G','F','R','O','M','F','U','L', - 'L','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T','R', - 'I','C','T','O','V','E','R','I','G','H','T','R','O','L','L','B','A','C', - 'K','R','O','W','S','U','N','B','O','U','N','D','E','D','U','N','I','O', - 'N','U','S','I','N','G','V','A','C','U','U','M','V','I','E','W','I','N', - 'D','O','W','I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R', - 'Y', + 'E','R','R','A','B','L','E','L','S','E','X','C','L','U','D','E','L','E', + 'T','E','M','P','O','R','A','R','Y','C','O','N','S','T','R','A','I','N', + 'T','E','R','S','E','C','T','I','E','S','A','V','E','P','O','I','N','T', + 'O','F','F','S','E','T','R','A','N','S','A','C','T','I','O','N','A','T', + 'U','R','A','L','T','E','R','A','I','S','E','X','C','E','P','T','R','I', + 'G','G','E','R','E','F','E','R','E','N','C','E','S','U','N','I','Q','U', + 'E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S','E', + 'X','C','L','U','S','I','V','E','X','I','S','T','S','A','T','T','A','C', + 'H','A','V','I','N','G','L','O','B','E','G','I','N','N','E','R','A','N', + 'G','E','B','E','T','W','E','E','N','O','T','H','I','N','G','R','O','U', + 'P','S','C','A','S','C','A','D','E','T','A','C','H','C','A','S','E','C', + 'O','L','L','A','T','E','C','R','E','A','T','E','C','U','R','R','E','N', + 'T','_','D','A','T','E','I','M','M','E','D','I','A','T','E','J','O','I', + 'N','S','E','R','T','L','I','K','E','M','A','T','C','H','P','L','A','N', + 'A','L','Y','Z','E','P','R','A','G','M','A','B','O','R','T','U','P','D', + 'A','T','E','V','A','L','U','E','S','V','I','R','T','U','A','L','I','M', + 'I','T','W','H','E','N','O','T','N','U','L','L','W','H','E','R','E','C', + 'U','R','S','I','V','E','A','F','T','E','R','E','N','A','M','E','A','N', + 'D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E','M','E', + 'N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M','I','T', + 'C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R','R','E', + 'N','T','_','T','I','M','E','S','T','A','M','P','A','R','T','I','T','I', + 'O','N','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D', + 'R','O','P','R','E','C','E','D','I','N','G','F','A','I','L','F','I','L', + 'T','E','R','E','P','L','A','C','E','F','O','L','L','O','W','I','N','G', + 'F','R','O','M','F','U','L','L','I','F','I','S','N','U','L','L','O','R', + 'D','E','R','E','S','T','R','I','C','T','O','T','H','E','R','S','O','V', + 'E','R','I','G','H','T','R','O','L','L','B','A','C','K','R','O','W','S', + 'U','N','B','O','U','N','D','E','D','U','N','I','O','N','U','S','I','N', + 'G','V','A','C','U','U','M','V','I','E','W','I','N','D','O','W','B','Y', + 'I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R','Y', }; /* aKWHash[i] is the hash value for the i-th keyword */ static const unsigned char aKWHash[127] = { - 74, 109, 124, 72, 106, 45, 0, 0, 81, 0, 76, 61, 0, - 42, 12, 77, 15, 0, 123, 84, 54, 118, 125, 19, 0, 0, - 130, 0, 128, 121, 0, 22, 96, 0, 9, 0, 0, 115, 69, - 0, 67, 6, 0, 48, 93, 136, 0, 126, 104, 0, 0, 44, - 0, 107, 24, 0, 17, 0, 131, 53, 23, 0, 5, 62, 132, - 99, 0, 0, 135, 110, 60, 134, 57, 113, 55, 0, 94, 0, - 103, 26, 0, 102, 0, 0, 0, 98, 95, 100, 105, 117, 14, - 39, 116, 0, 80, 0, 133, 114, 92, 59, 0, 129, 79, 119, - 86, 46, 83, 0, 0, 97, 40, 122, 120, 0, 127, 0, 0, - 29, 0, 89, 87, 88, 0, 20, 85, 111, 56, + 75, 111, 127, 73, 108, 29, 0, 0, 83, 0, 77, 63, 0, + 37, 33, 78, 15, 0, 126, 86, 57, 120, 128, 19, 0, 0, + 133, 0, 131, 123, 0, 22, 98, 0, 9, 0, 0, 117, 71, + 0, 69, 6, 0, 49, 95, 140, 0, 129, 106, 0, 0, 54, + 0, 109, 24, 0, 17, 0, 134, 56, 23, 26, 5, 58, 135, + 101, 0, 0, 139, 112, 62, 138, 59, 115, 65, 0, 96, 0, + 105, 45, 0, 104, 0, 0, 0, 100, 97, 102, 107, 119, 14, + 31, 118, 0, 81, 0, 136, 116, 137, 61, 124, 132, 80, 121, + 88, 30, 85, 0, 0, 99, 35, 125, 122, 0, 130, 0, 0, + 41, 0, 91, 89, 90, 0, 20, 87, 113, 82, }; /* aKWNext[] forms the hash collision chain. If aKWHash[i]==0 ** then the i-th keyword has no more hash collisions. Otherwise, ** the next keyword with the same hash is aKWHash[i]-1. */ -static const unsigned char aKWNext[136] = { +static const unsigned char aKWNext[140] = { 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, - 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 33, 0, 21, 0, 0, 0, 0, 0, 50, - 0, 43, 3, 47, 0, 0, 32, 0, 0, 0, 0, 0, 0, - 0, 1, 64, 0, 0, 65, 0, 41, 0, 38, 0, 0, 0, - 0, 0, 49, 75, 0, 0, 30, 0, 58, 0, 0, 0, 31, - 63, 16, 34, 10, 0, 0, 0, 0, 0, 0, 0, 11, 70, - 91, 0, 0, 8, 0, 108, 0, 101, 28, 52, 68, 0, 112, - 0, 73, 51, 0, 90, 27, 37, 0, 71, 36, 82, 0, 35, - 66, 25, 18, 0, 0, 78, + 0, 0, 0, 21, 0, 0, 12, 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 51, 28, 0, 0, 38, 0, 0, 0, 44, 0, 0, 0, 3, + 0, 0, 67, 1, 66, 0, 0, 0, 36, 0, 47, 0, 0, + 0, 0, 0, 48, 50, 76, 0, 0, 42, 0, 60, 0, 0, + 0, 43, 0, 16, 55, 10, 0, 0, 0, 0, 0, 0, 0, + 11, 72, 93, 0, 0, 8, 0, 110, 0, 103, 40, 53, 70, + 0, 114, 0, 74, 52, 0, 0, 92, 39, 46, 0, 68, 32, + 84, 0, 34, 27, 25, 18, 94, 0, 64, 79, }; /* aKWLen[i] is the length (in bytes) of the i-th keyword */ -static const unsigned char aKWLen[136] = { +static const unsigned char aKWLen[140] = { 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6, - 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6, - 11, 6, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10, - 4, 6, 2, 3, 9, 4, 2, 6, 5, 7, 4, 5, 7, - 6, 6, 5, 6, 5, 5, 5, 7, 7, 4, 2, 7, 3, - 6, 4, 7, 6, 12, 6, 9, 4, 6, 4, 5, 4, 7, - 6, 5, 6, 7, 5, 4, 7, 3, 2, 4, 5, 9, 5, - 6, 3, 7, 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, - 7, 9, 8, 8, 2, 4, 9, 4, 6, 7, 9, 4, 4, - 2, 6, 5, 8, 4, 5, 8, 4, 3, 9, 5, 5, 6, - 4, 6, 2, 9, 3, 7, + 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7, + 6, 9, 4, 2, 10, 9, 4, 9, 4, 6, 2, 3, 11, + 6, 2, 7, 5, 5, 6, 7, 10, 6, 5, 7, 4, 5, + 7, 9, 6, 6, 6, 4, 5, 5, 5, 7, 7, 6, 5, + 7, 3, 6, 4, 7, 6, 12, 9, 4, 6, 4, 5, 4, + 7, 6, 5, 6, 6, 7, 5, 4, 7, 3, 2, 4, 5, + 9, 5, 6, 3, 7, 13, 2, 2, 4, 6, 6, 8, 5, + 17, 12, 7, 9, 8, 8, 2, 4, 9, 4, 6, 7, 9, + 4, 4, 2, 6, 5, 8, 6, 4, 5, 8, 4, 3, 9, + 5, 5, 6, 4, 6, 2, 2, 9, 3, 7, }; /* aKWOffset[i] is the index into zKWText[] of the start of ** the text for the i-th keyword. */ -static const unsigned short int aKWOffset[136] = { +static const unsigned short int aKWOffset[140] = { 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33, 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81, - 86, 91, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152, - 159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192, - 199, 204, 209, 212, 218, 221, 225, 230, 236, 242, 245, 247, 248, - 252, 258, 262, 269, 275, 287, 293, 302, 304, 310, 314, 319, 321, - 328, 333, 338, 344, 350, 355, 358, 358, 358, 361, 365, 368, 377, - 381, 387, 389, 396, 398, 400, 409, 413, 419, 425, 433, 438, 438, - 438, 454, 463, 470, 471, 478, 481, 490, 494, 499, 506, 515, 519, - 523, 525, 531, 535, 543, 546, 551, 559, 559, 563, 572, 577, 582, - 588, 591, 594, 597, 602, 606, + 86, 90, 90, 94, 99, 106, 114, 117, 123, 126, 126, 129, 131, + 136, 140, 141, 146, 150, 154, 159, 165, 175, 178, 183, 183, 187, + 191, 197, 205, 211, 216, 221, 224, 227, 231, 236, 242, 248, 248, + 254, 255, 259, 265, 269, 276, 282, 294, 303, 305, 311, 315, 320, + 322, 329, 334, 339, 345, 351, 357, 362, 365, 365, 365, 368, 372, + 375, 384, 388, 394, 396, 403, 405, 407, 416, 420, 426, 432, 440, + 445, 445, 445, 461, 470, 477, 478, 485, 488, 497, 501, 506, 513, + 522, 526, 530, 532, 538, 542, 550, 556, 559, 564, 572, 572, 576, + 585, 590, 595, 601, 604, 607, 610, 612, 617, 621, }; /* aKWCode[i] is the parser symbol code for the i-th keyword */ -static const unsigned char aKWCode[136] = { +static const unsigned char aKWCode[140] = { TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE, TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE, TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE, - TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW, - TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_SAVEPOINT, - TK_INTERSECT, TK_TRIGGER, TK_REFERENCES, TK_CONSTRAINT, TK_INTO, - TK_OFFSET, TK_OF, TK_SET, TK_TEMP, TK_TEMP, - TK_OR, TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH, - TK_JOIN_KW, TK_RELEASE, TK_ATTACH, TK_HAVING, TK_GROUP, - TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RANGE, TK_BETWEEN, - TK_NOTHING, TK_LIKE_KW, TK_BY, TK_CASCADE, TK_ASC, - TK_DELETE, TK_CASE, TK_COLLATE, TK_CREATE, TK_CTIME_KW, - TK_DETACH, TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_LIKE_KW, - TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_ABORT, - TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN, TK_NOTNULL, - TK_NOT, TK_NO, TK_NULL, TK_WHERE, TK_RECURSIVE, - TK_AFTER, TK_RENAME, TK_AND, TK_DEFAULT, TK_AUTOINCR, - TK_TO, TK_IN, TK_CAST, TK_COLUMNKW, TK_COMMIT, - TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_CURRENT, - TK_PARTITION, TK_DEFERRED, TK_DISTINCT, TK_IS, TK_DROP, - TK_PRECEDING, TK_FAIL, TK_FILTER, TK_REPLACE, TK_FOLLOWING, - TK_FROM, TK_JOIN_KW, TK_IF, TK_ISNULL, TK_ORDER, - TK_RESTRICT, TK_OVER, TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, - TK_ROW, TK_UNBOUNDED, TK_UNION, TK_USING, TK_VACUUM, - TK_VIEW, TK_WINDOW, TK_DO, TK_INITIALLY, TK_ALL, - TK_PRIMARY, + TK_EXCLUDE, TK_DELETE, TK_TEMP, TK_TEMP, TK_OR, + TK_CONSTRAINT, TK_INTERSECT, TK_TIES, TK_SAVEPOINT, TK_INTO, + TK_OFFSET, TK_OF, TK_SET, TK_TRANSACTION,TK_ACTION, + TK_ON, TK_JOIN_KW, TK_ALTER, TK_RAISE, TK_EXCEPT, + TK_TRIGGER, TK_REFERENCES, TK_UNIQUE, TK_QUERY, TK_WITHOUT, + TK_WITH, TK_JOIN_KW, TK_RELEASE, TK_EXCLUSIVE, TK_EXISTS, + TK_ATTACH, TK_HAVING, TK_LIKE_KW, TK_BEGIN, TK_JOIN_KW, + TK_RANGE, TK_BETWEEN, TK_NOTHING, TK_GROUPS, TK_GROUP, + TK_CASCADE, TK_ASC, TK_DETACH, TK_CASE, TK_COLLATE, + TK_CREATE, TK_CTIME_KW, TK_IMMEDIATE, TK_JOIN, TK_INSERT, + TK_LIKE_KW, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA, + TK_ABORT, TK_UPDATE, TK_VALUES, TK_VIRTUAL, TK_LIMIT, + TK_WHEN, TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, + TK_WHERE, TK_RECURSIVE, TK_AFTER, TK_RENAME, TK_AND, + TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, + TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, + TK_CTIME_KW, TK_CURRENT, TK_PARTITION, TK_DEFERRED, TK_DISTINCT, + TK_IS, TK_DROP, TK_PRECEDING, TK_FAIL, TK_FILTER, + TK_REPLACE, TK_FOLLOWING, TK_FROM, TK_JOIN_KW, TK_IF, + TK_ISNULL, TK_ORDER, TK_RESTRICT, TK_OTHERS, TK_OVER, + TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, TK_ROW, TK_UNBOUNDED, + TK_UNION, TK_USING, TK_VACUUM, TK_VIEW, TK_WINDOW, + TK_DO, TK_BY, TK_INITIALLY, TK_ALL, TK_PRIMARY, }; /* Check to see if z[0..n-1] is a keyword. If it is, write the ** parser symbol code for that keyword into *pType. Always @@ -152447,117 +153948,121 @@ static int keywordCode(const char *z, int n, int *pType){ testcase( i==22 ); /* END */ testcase( i==23 ); /* DEFERRABLE */ testcase( i==24 ); /* ELSE */ - testcase( i==25 ); /* EXCEPT */ - testcase( i==26 ); /* TRANSACTION */ - testcase( i==27 ); /* ACTION */ - testcase( i==28 ); /* ON */ - testcase( i==29 ); /* NATURAL */ - testcase( i==30 ); /* ALTER */ - testcase( i==31 ); /* RAISE */ - testcase( i==32 ); /* EXCLUSIVE */ - testcase( i==33 ); /* EXISTS */ - testcase( i==34 ); /* SAVEPOINT */ - testcase( i==35 ); /* INTERSECT */ - testcase( i==36 ); /* TRIGGER */ - testcase( i==37 ); /* REFERENCES */ - testcase( i==38 ); /* CONSTRAINT */ - testcase( i==39 ); /* INTO */ - testcase( i==40 ); /* OFFSET */ - testcase( i==41 ); /* OF */ - testcase( i==42 ); /* SET */ - testcase( i==43 ); /* TEMPORARY */ - testcase( i==44 ); /* TEMP */ - testcase( i==45 ); /* OR */ - testcase( i==46 ); /* UNIQUE */ - testcase( i==47 ); /* QUERY */ - testcase( i==48 ); /* WITHOUT */ - testcase( i==49 ); /* WITH */ - testcase( i==50 ); /* OUTER */ - testcase( i==51 ); /* RELEASE */ - testcase( i==52 ); /* ATTACH */ - testcase( i==53 ); /* HAVING */ - testcase( i==54 ); /* GROUP */ - testcase( i==55 ); /* UPDATE */ - testcase( i==56 ); /* BEGIN */ - testcase( i==57 ); /* INNER */ - testcase( i==58 ); /* RANGE */ - testcase( i==59 ); /* BETWEEN */ - testcase( i==60 ); /* NOTHING */ - testcase( i==61 ); /* GLOB */ - testcase( i==62 ); /* BY */ - testcase( i==63 ); /* CASCADE */ - testcase( i==64 ); /* ASC */ - testcase( i==65 ); /* DELETE */ - testcase( i==66 ); /* CASE */ - testcase( i==67 ); /* COLLATE */ - testcase( i==68 ); /* CREATE */ - testcase( i==69 ); /* CURRENT_DATE */ - testcase( i==70 ); /* DETACH */ - testcase( i==71 ); /* IMMEDIATE */ - testcase( i==72 ); /* JOIN */ - testcase( i==73 ); /* INSERT */ - testcase( i==74 ); /* LIKE */ - testcase( i==75 ); /* MATCH */ - testcase( i==76 ); /* PLAN */ - testcase( i==77 ); /* ANALYZE */ - testcase( i==78 ); /* PRAGMA */ - testcase( i==79 ); /* ABORT */ - testcase( i==80 ); /* VALUES */ - testcase( i==81 ); /* VIRTUAL */ - testcase( i==82 ); /* LIMIT */ - testcase( i==83 ); /* WHEN */ - testcase( i==84 ); /* NOTNULL */ - testcase( i==85 ); /* NOT */ - testcase( i==86 ); /* NO */ - testcase( i==87 ); /* NULL */ - testcase( i==88 ); /* WHERE */ - testcase( i==89 ); /* RECURSIVE */ - testcase( i==90 ); /* AFTER */ - testcase( i==91 ); /* RENAME */ - testcase( i==92 ); /* AND */ - testcase( i==93 ); /* DEFAULT */ - testcase( i==94 ); /* AUTOINCREMENT */ - testcase( i==95 ); /* TO */ - testcase( i==96 ); /* IN */ - testcase( i==97 ); /* CAST */ - testcase( i==98 ); /* COLUMN */ - testcase( i==99 ); /* COMMIT */ - testcase( i==100 ); /* CONFLICT */ - testcase( i==101 ); /* CROSS */ - testcase( i==102 ); /* CURRENT_TIMESTAMP */ - testcase( i==103 ); /* CURRENT_TIME */ - testcase( i==104 ); /* CURRENT */ - testcase( i==105 ); /* PARTITION */ - testcase( i==106 ); /* DEFERRED */ - testcase( i==107 ); /* DISTINCT */ - testcase( i==108 ); /* IS */ - testcase( i==109 ); /* DROP */ - testcase( i==110 ); /* PRECEDING */ - testcase( i==111 ); /* FAIL */ - testcase( i==112 ); /* FILTER */ - testcase( i==113 ); /* REPLACE */ - testcase( i==114 ); /* FOLLOWING */ - testcase( i==115 ); /* FROM */ - testcase( i==116 ); /* FULL */ - testcase( i==117 ); /* IF */ - testcase( i==118 ); /* ISNULL */ - testcase( i==119 ); /* ORDER */ - testcase( i==120 ); /* RESTRICT */ - testcase( i==121 ); /* OVER */ - testcase( i==122 ); /* RIGHT */ - testcase( i==123 ); /* ROLLBACK */ - testcase( i==124 ); /* ROWS */ - testcase( i==125 ); /* ROW */ - testcase( i==126 ); /* UNBOUNDED */ - testcase( i==127 ); /* UNION */ - testcase( i==128 ); /* USING */ - testcase( i==129 ); /* VACUUM */ - testcase( i==130 ); /* VIEW */ - testcase( i==131 ); /* WINDOW */ - testcase( i==132 ); /* DO */ - testcase( i==133 ); /* INITIALLY */ - testcase( i==134 ); /* ALL */ - testcase( i==135 ); /* PRIMARY */ + testcase( i==25 ); /* EXCLUDE */ + testcase( i==26 ); /* DELETE */ + testcase( i==27 ); /* TEMPORARY */ + testcase( i==28 ); /* TEMP */ + testcase( i==29 ); /* OR */ + testcase( i==30 ); /* CONSTRAINT */ + testcase( i==31 ); /* INTERSECT */ + testcase( i==32 ); /* TIES */ + testcase( i==33 ); /* SAVEPOINT */ + testcase( i==34 ); /* INTO */ + testcase( i==35 ); /* OFFSET */ + testcase( i==36 ); /* OF */ + testcase( i==37 ); /* SET */ + testcase( i==38 ); /* TRANSACTION */ + testcase( i==39 ); /* ACTION */ + testcase( i==40 ); /* ON */ + testcase( i==41 ); /* NATURAL */ + testcase( i==42 ); /* ALTER */ + testcase( i==43 ); /* RAISE */ + testcase( i==44 ); /* EXCEPT */ + testcase( i==45 ); /* TRIGGER */ + testcase( i==46 ); /* REFERENCES */ + testcase( i==47 ); /* UNIQUE */ + testcase( i==48 ); /* QUERY */ + testcase( i==49 ); /* WITHOUT */ + testcase( i==50 ); /* WITH */ + testcase( i==51 ); /* OUTER */ + testcase( i==52 ); /* RELEASE */ + testcase( i==53 ); /* EXCLUSIVE */ + testcase( i==54 ); /* EXISTS */ + testcase( i==55 ); /* ATTACH */ + testcase( i==56 ); /* HAVING */ + testcase( i==57 ); /* GLOB */ + testcase( i==58 ); /* BEGIN */ + testcase( i==59 ); /* INNER */ + testcase( i==60 ); /* RANGE */ + testcase( i==61 ); /* BETWEEN */ + testcase( i==62 ); /* NOTHING */ + testcase( i==63 ); /* GROUPS */ + testcase( i==64 ); /* GROUP */ + testcase( i==65 ); /* CASCADE */ + testcase( i==66 ); /* ASC */ + testcase( i==67 ); /* DETACH */ + testcase( i==68 ); /* CASE */ + testcase( i==69 ); /* COLLATE */ + testcase( i==70 ); /* CREATE */ + testcase( i==71 ); /* CURRENT_DATE */ + testcase( i==72 ); /* IMMEDIATE */ + testcase( i==73 ); /* JOIN */ + testcase( i==74 ); /* INSERT */ + testcase( i==75 ); /* LIKE */ + testcase( i==76 ); /* MATCH */ + testcase( i==77 ); /* PLAN */ + testcase( i==78 ); /* ANALYZE */ + testcase( i==79 ); /* PRAGMA */ + testcase( i==80 ); /* ABORT */ + testcase( i==81 ); /* UPDATE */ + testcase( i==82 ); /* VALUES */ + testcase( i==83 ); /* VIRTUAL */ + testcase( i==84 ); /* LIMIT */ + testcase( i==85 ); /* WHEN */ + testcase( i==86 ); /* NOTNULL */ + testcase( i==87 ); /* NOT */ + testcase( i==88 ); /* NO */ + testcase( i==89 ); /* NULL */ + testcase( i==90 ); /* WHERE */ + testcase( i==91 ); /* RECURSIVE */ + testcase( i==92 ); /* AFTER */ + testcase( i==93 ); /* RENAME */ + testcase( i==94 ); /* AND */ + testcase( i==95 ); /* DEFAULT */ + testcase( i==96 ); /* AUTOINCREMENT */ + testcase( i==97 ); /* TO */ + testcase( i==98 ); /* IN */ + testcase( i==99 ); /* CAST */ + testcase( i==100 ); /* COLUMN */ + testcase( i==101 ); /* COMMIT */ + testcase( i==102 ); /* CONFLICT */ + testcase( i==103 ); /* CROSS */ + testcase( i==104 ); /* CURRENT_TIMESTAMP */ + testcase( i==105 ); /* CURRENT_TIME */ + testcase( i==106 ); /* CURRENT */ + testcase( i==107 ); /* PARTITION */ + testcase( i==108 ); /* DEFERRED */ + testcase( i==109 ); /* DISTINCT */ + testcase( i==110 ); /* IS */ + testcase( i==111 ); /* DROP */ + testcase( i==112 ); /* PRECEDING */ + testcase( i==113 ); /* FAIL */ + testcase( i==114 ); /* FILTER */ + testcase( i==115 ); /* REPLACE */ + testcase( i==116 ); /* FOLLOWING */ + testcase( i==117 ); /* FROM */ + testcase( i==118 ); /* FULL */ + testcase( i==119 ); /* IF */ + testcase( i==120 ); /* ISNULL */ + testcase( i==121 ); /* ORDER */ + testcase( i==122 ); /* RESTRICT */ + testcase( i==123 ); /* OTHERS */ + testcase( i==124 ); /* OVER */ + testcase( i==125 ); /* RIGHT */ + testcase( i==126 ); /* ROLLBACK */ + testcase( i==127 ); /* ROWS */ + testcase( i==128 ); /* ROW */ + testcase( i==129 ); /* UNBOUNDED */ + testcase( i==130 ); /* UNION */ + testcase( i==131 ); /* USING */ + testcase( i==132 ); /* VACUUM */ + testcase( i==133 ); /* VIEW */ + testcase( i==134 ); /* WINDOW */ + testcase( i==135 ); /* DO */ + testcase( i==136 ); /* BY */ + testcase( i==137 ); /* INITIALLY */ + testcase( i==138 ); /* ALL */ + testcase( i==139 ); /* PRIMARY */ *pType = aKWCode[i]; break; } @@ -152569,7 +154074,7 @@ SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){ keywordCode((char*)z, n, &id); return id; } -#define SQLITE_N_KEYWORD 136 +#define SQLITE_N_KEYWORD 140 SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){ if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR; *pzName = zKWText + aKWOffset[i]; @@ -153002,6 +154507,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr #ifdef sqlite3Parser_ENGINEALWAYSONSTACK yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ #endif + VVA_ONLY( u8 startedWithOom = db->mallocFailed ); assert( zSql!=0 ); mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; @@ -153033,6 +154539,8 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->pVList==0 ); + pParse->pParentParse = db->pParse; + db->pParse = pParse; while( 1 ){ n = sqlite3GetToken((u8*)zSql, &tokenType); mxSqlLen -= n; @@ -153089,7 +154597,8 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr sqlite3Parser(pEngine, tokenType, pParse->sLastToken); lastTokenParsed = tokenType; zSql += n; - if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; + assert( db->mallocFailed==0 || pParse->rc!=SQLITE_OK || startedWithOom ); + if( pParse->rc!=SQLITE_OK ) break; } assert( nErr==0 ); #ifdef YYTRACKMAXSTACKDEPTH @@ -153157,6 +154666,8 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr pParse->pZombieTab = p->pNextZombie; sqlite3DeleteTable(db, p); } + db->pParse = pParse->pParentParse; + pParse->pParentParse = 0; assert( nErr==0 || pParse->rc!=SQLITE_OK ); return nErr; } @@ -154393,7 +155904,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){ pStart = 0; }else if( pBuf==0 ){ sqlite3BeginBenignMalloc(); - pStart = sqlite3Malloc( sz*cnt ); /* IMP: R-61949-35727 */ + pStart = sqlite3Malloc( sz*(sqlite3_int64)cnt ); /* IMP: R-61949-35727 */ sqlite3EndBenignMalloc(); if( pStart ) cnt = sqlite3MallocSize(pStart)/sz; }else{ @@ -154531,6 +156042,11 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ { SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP }, { SQLITE_DBCONFIG_RESET_DATABASE, SQLITE_ResetDatabase }, { SQLITE_DBCONFIG_DEFENSIVE, SQLITE_Defensive }, + { SQLITE_DBCONFIG_WRITABLE_SCHEMA, SQLITE_WriteSchema| + SQLITE_NoSchemaError }, + { SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, SQLITE_LegacyAlter }, + { SQLITE_DBCONFIG_DQS_DDL, SQLITE_DqsDDL }, + { SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML }, }; unsigned int i; rc = SQLITE_ERROR; /* IMP: R-42790-23372 */ @@ -154561,28 +156077,17 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ return rc; } - -/* -** Return true if the buffer z[0..n-1] contains all spaces. -*/ -static int allSpaces(const char *z, int n){ - while( n>0 && z[n-1]==' ' ){ n--; } - return n==0; -} - /* ** This is the default collating function named "BINARY" which is always ** available. -** -** If the padFlag argument is not NULL then space padding at the end -** of strings is ignored. This implements the RTRIM collation. */ static int binCollFunc( - void *padFlag, + void *NotUsed, int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ int rc, n; + UNUSED_PARAMETER(NotUsed); n = nKey1<nKey2 ? nKey1 : nKey2; /* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares ** strings byte by byte using the memcmp() function from the standard C @@ -154590,29 +156095,33 @@ static int binCollFunc( assert( pKey1 && pKey2 ); rc = memcmp(pKey1, pKey2, n); if( rc==0 ){ - if( padFlag - && allSpaces(((char*)pKey1)+n, nKey1-n) - && allSpaces(((char*)pKey2)+n, nKey2-n) - ){ - /* EVIDENCE-OF: R-31624-24737 RTRIM is like BINARY except that extra - ** spaces at the end of either string do not change the result. In other - ** words, strings will compare equal to one another as long as they - ** differ only in the number of spaces at the end. - */ - }else{ - rc = nKey1 - nKey2; - } + rc = nKey1 - nKey2; } return rc; } /* +** This is the collating function named "RTRIM" which is always +** available. Ignore trailing spaces. +*/ +static int rtrimCollFunc( + void *pUser, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2 +){ + const u8 *pK1 = (const u8*)pKey1; + const u8 *pK2 = (const u8*)pKey2; + while( nKey1 && pK1[nKey1-1]==' ' ) nKey1--; + while( nKey2 && pK2[nKey2-1]==' ' ) nKey2--; + return binCollFunc(pUser, nKey1, pKey1, nKey2, pKey2); +} + +/* ** Return true if CollSeq is the default built-in BINARY. */ SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq *p){ - assert( p==0 || p->xCmp!=binCollFunc || p->pUser!=0 - || strcmp(p->zName,"BINARY")==0 ); - return p==0 || (p->xCmp==binCollFunc && p->pUser==0); + assert( p==0 || p->xCmp!=binCollFunc || strcmp(p->zName,"BINARY")==0 ); + return p==0 || p->xCmp==binCollFunc; } /* @@ -156763,7 +158272,35 @@ static int openDatabase( db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; db->nMaxSorterMmap = 0x7FFFFFFF; - db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill + db->flags |= SQLITE_ShortColNames + | SQLITE_EnableTrigger + | SQLITE_CacheSpill + +/* The SQLITE_DQS compile-time option determines the default settings +** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML. +** +** SQLITE_DQS SQLITE_DBCONFIG_DQS_DDL SQLITE_DBCONFIG_DQS_DML +** ---------- ----------------------- ----------------------- +** undefined on on +** 3 on on +** 2 on off +** 1 off on +** 0 off off +** +** Legacy behavior is 3 (double-quoted string literals are allowed anywhere) +** and so that is the default. But developers are encouranged to use +** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible. +*/ +#if !defined(SQLITE_DQS) +# define SQLITE_DQS 3 +#endif +#if (SQLITE_DQS&1)==1 + | SQLITE_DqsDML +#endif +#if (SQLITE_DQS&2)==2 + | SQLITE_DqsDDL +#endif + #if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX | SQLITE_AutoIndex #endif @@ -156814,7 +158351,7 @@ static int openDatabase( createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0); createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0); createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0); - createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0); + createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0); if( db->mallocFailed ){ goto opendb_out; } @@ -157790,6 +159327,22 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } #endif /* defined(YYCOVERAGE) */ + + /* sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, sqlite3_context*); + ** + ** This test-control causes the most recent sqlite3_result_int64() value + ** to be interpreted as a MEM_IntReal instead of as an MEM_Int. Normally, + ** MEM_IntReal values only arise during an INSERT operation of integer + ** values into a REAL column, so they can be challenging to test. This + ** test-control enables us to write an intreal() SQL function that can + ** inject an intreal() value at arbitrary places in an SQL statement, + ** for testing purposes. + */ + case SQLITE_TESTCTRL_RESULT_INTREAL: { + sqlite3_context *pCtx = va_arg(ap, sqlite3_context*); + sqlite3ResultIntReal(pCtx); + break; + } } va_end(ap); #endif /* SQLITE_UNTESTABLE */ @@ -161199,7 +162752,7 @@ static int fts3ScanInteriorNode( zCsr += fts3GetVarint32(zCsr, &nSuffix); assert( nPrefix>=0 && nSuffix>=0 ); - if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr ){ + if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){ rc = FTS_CORRUPT_VTAB; goto finish_scan; } @@ -168312,7 +169865,7 @@ static void fts3TokenizerFunc( nName = sqlite3_value_bytes(argv[0])+1; if( argc==2 ){ - if( fts3TokenizerEnabled(context) ){ + if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[1]) ){ void *pOld; int n = sqlite3_value_bytes(argv[1]); if( zName==0 || n!=sizeof(pPtr) ){ @@ -168339,7 +169892,9 @@ static void fts3TokenizerFunc( return; } } - sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); + if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[0]) ){ + sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); + } } SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char c){ @@ -168427,8 +169982,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer( int iArg = 0; z = &z[n+1]; while( z<zEnd && (NULL!=(z = (char *)sqlite3Fts3NextToken(z, &n))) ){ - int nNew = sizeof(char *)*(iArg+1); - char const **aNew = (const char **)sqlite3_realloc((void *)aArg, nNew); + sqlite3_int64 nNew = sizeof(char *)*(iArg+1); + char const **aNew = (const char **)sqlite3_realloc64((void *)aArg, nNew); if( !aNew ){ sqlite3_free(zCopy); sqlite3_free((void *)aArg); @@ -169335,7 +170890,7 @@ static int fts3tokFilterMethod( if( idxNum==1 ){ const char *zByte = (const char *)sqlite3_value_text(apVal[0]); int nByte = sqlite3_value_bytes(apVal[0]); - pCsr->zInput = sqlite3_malloc(nByte+1); + pCsr->zInput = sqlite3_malloc64(nByte+1); if( pCsr->zInput==0 ){ rc = SQLITE_NOMEM; }else{ @@ -170795,7 +172350,9 @@ static int fts3SegReaderNext( /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf ** blocks have already been traversed. */ - assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock ); +#ifdef CORRUPT_DB + assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock || CORRUPT_DB ); +#endif if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){ return SQLITE_OK; } @@ -171197,8 +172754,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending( } if( nElem>0 ){ - int nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *); - pReader = (Fts3SegReader *)sqlite3_malloc(nByte); + sqlite3_int64 nByte; + nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *); + pReader = (Fts3SegReader *)sqlite3_malloc64(nByte); if( !pReader ){ rc = SQLITE_NOMEM; }else{ @@ -172063,14 +173621,14 @@ static void fts3ColumnFilter( nList -= (int)(p - pList); pList = p; - if( nList==0 ){ + if( nList<=0 ){ break; } p = &pList[1]; p += fts3GetVarint32(p, &iCurrent); } - if( bZero && &pList[nList]!=pEnd ){ + if( bZero && (pEnd - &pList[nList])>0){ memset(&pList[nList], 0, pEnd - &pList[nList]); } *ppList = pList; @@ -172682,8 +174240,10 @@ static int fts3SegmentMerge( if( rc!=SQLITE_OK ) goto finished; assert( csr.nSegment>0 ); - assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); - assert( iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL) ); + assert_fts3_nc( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) ); + assert_fts3_nc( + iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL) + ); memset(&filter, 0, sizeof(Fts3SegFilter)); filter.flags = FTS3_SEGMENT_REQUIRE_POS; @@ -172810,7 +174370,7 @@ static void fts3InsertDocsize( int rc; /* Result code from subfunctions */ if( *pRC ) return; - pBlob = sqlite3_malloc( 10*p->nColumn ); + pBlob = sqlite3_malloc64( 10*(sqlite3_int64)p->nColumn ); if( pBlob==0 ){ *pRC = SQLITE_NOMEM; return; @@ -172860,7 +174420,7 @@ static void fts3UpdateDocTotals( const int nStat = p->nColumn+2; if( *pRC ) return; - a = sqlite3_malloc( (sizeof(u32)+10)*nStat ); + a = sqlite3_malloc64( (sizeof(u32)+10)*(sqlite3_int64)nStat ); if( a==0 ){ *pRC = SQLITE_NOMEM; return; @@ -172981,8 +174541,8 @@ static int fts3DoRebuild(Fts3Table *p){ } if( rc==SQLITE_OK ){ - int nByte = sizeof(u32) * (p->nColumn+1)*3; - aSz = (u32 *)sqlite3_malloc(nByte); + sqlite3_int64 nByte = sizeof(u32) * ((sqlite3_int64)p->nColumn+1)*3; + aSz = (u32 *)sqlite3_malloc64(nByte); if( aSz==0 ){ rc = SQLITE_NOMEM; }else{ @@ -173048,12 +174608,12 @@ static int fts3IncrmergeCsr( ){ int rc; /* Return Code */ sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */ - int nByte; /* Bytes allocated at pCsr->apSegment[] */ + sqlite3_int64 nByte; /* Bytes allocated at pCsr->apSegment[] */ /* Allocate space for the Fts3MultiSegReader.aCsr[] array */ memset(pCsr, 0, sizeof(*pCsr)); nByte = sizeof(Fts3SegReader *) * nSeg; - pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc(nByte); + pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc64(nByte); if( pCsr->apSegment==0 ){ rc = SQLITE_NOMEM; @@ -173196,7 +174756,7 @@ static int nodeReaderNext(NodeReader *p){ } p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix); - if( nPrefix>p->iOff || nSuffix>p->nNode-p->iOff ){ + if( nPrefix>p->term.n || nSuffix>p->nNode-p->iOff || nSuffix==0 ){ return FTS_CORRUPT_VTAB; } blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc); @@ -173215,7 +174775,7 @@ static int nodeReaderNext(NodeReader *p){ } } - assert( p->iOff<=p->nNode ); + assert_fts3_nc( p->iOff<=p->nNode ); return rc; } @@ -173376,7 +174936,7 @@ static int fts3AppendToNode( /* Node must have already been started. There must be a doclist for a ** leaf node, and there must not be a doclist for an internal node. */ assert( pNode->n>0 ); - assert( (pNode->a[0]=='\0')==(aDoclist!=0) ); + assert_fts3_nc( (pNode->a[0]=='\0')==(aDoclist!=0) ); blobGrowBuffer(pPrev, nTerm, &rc); if( rc!=SQLITE_OK ) return rc; @@ -173592,7 +175152,7 @@ static int fts3TermCmp( int nCmp = MIN(nLhs, nRhs); int res; - res = memcmp(zLhs, zRhs, nCmp); + res = (nCmp ? memcmp(zLhs, zRhs, nCmp) : 0); if( res==0 ) res = nLhs - nRhs; return res; @@ -173724,10 +175284,13 @@ static int fts3IncrmergeLoad( pNode = &pWriter->aNodeWriter[nHeight]; pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight; - blobGrowBuffer(&pNode->block, MAX(nRoot, p->nNodeSize), &rc); + blobGrowBuffer(&pNode->block, + MAX(nRoot, p->nNodeSize)+FTS3_NODE_PADDING, &rc + ); if( rc==SQLITE_OK ){ memcpy(pNode->block.a, aRoot, nRoot); pNode->block.n = nRoot; + memset(&pNode->block.a[nRoot], 0, FTS3_NODE_PADDING); } for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){ @@ -173735,23 +175298,28 @@ static int fts3IncrmergeLoad( pNode = &pWriter->aNodeWriter[i]; rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n); - while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader); - blobGrowBuffer(&pNode->key, reader.term.n, &rc); - if( rc==SQLITE_OK ){ - memcpy(pNode->key.a, reader.term.a, reader.term.n); - pNode->key.n = reader.term.n; - if( i>0 ){ - char *aBlock = 0; - int nBlock = 0; - pNode = &pWriter->aNodeWriter[i-1]; - pNode->iBlock = reader.iChild; - rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0); - blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize), &rc); - if( rc==SQLITE_OK ){ - memcpy(pNode->block.a, aBlock, nBlock); - pNode->block.n = nBlock; + if( reader.aNode ){ + while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader); + blobGrowBuffer(&pNode->key, reader.term.n, &rc); + if( rc==SQLITE_OK ){ + memcpy(pNode->key.a, reader.term.a, reader.term.n); + pNode->key.n = reader.term.n; + if( i>0 ){ + char *aBlock = 0; + int nBlock = 0; + pNode = &pWriter->aNodeWriter[i-1]; + pNode->iBlock = reader.iChild; + rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0); + blobGrowBuffer(&pNode->block, + MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc + ); + if( rc==SQLITE_OK ){ + memcpy(pNode->block.a, aBlock, nBlock); + pNode->block.n = nBlock; + memset(&pNode->block.a[nBlock], 0, FTS3_NODE_PADDING); + } + sqlite3_free(aBlock); } - sqlite3_free(aBlock); } } nodeReaderRelease(&reader); @@ -173994,7 +175562,10 @@ static int fts3TruncateNode( NodeReader reader; /* Reader object */ Blob prev = {0, 0, 0}; /* Previous term written to new node */ int rc = SQLITE_OK; /* Return code */ - int bLeaf = aNode[0]=='\0'; /* True for a leaf node */ + int bLeaf; /* True for a leaf node */ + + if( nNode<1 ) return FTS_CORRUPT_VTAB; + bLeaf = aNode[0]=='\0'; /* Allocate required output space */ blobGrowBuffer(pNew, nNode, &rc); @@ -175033,7 +176604,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod( } /* Allocate space to hold the change in document sizes */ - aSzDel = sqlite3_malloc( sizeof(aSzDel[0])*(p->nColumn+1)*2 ); + aSzDel = sqlite3_malloc64(sizeof(aSzDel[0])*((sqlite3_int64)p->nColumn+1)*2); if( aSzDel==0 ){ rc = SQLITE_NOMEM; goto update_out; @@ -175287,17 +176858,19 @@ struct StrBuffer { /* ** Allocate a two-slot MatchinfoBuffer object. */ -static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){ +static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){ MatchinfoBuffer *pRet; - int nByte = sizeof(u32) * (2*nElem + 1) + sizeof(MatchinfoBuffer); - int nStr = (int)strlen(zMatchinfo); + sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1) + + sizeof(MatchinfoBuffer); + sqlite3_int64 nStr = strlen(zMatchinfo); - pRet = sqlite3_malloc(nByte + nStr+1); + pRet = sqlite3_malloc64(nByte + nStr+1); if( pRet ){ memset(pRet, 0, nByte); pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet; - pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*(nElem+1); - pRet->nElem = nElem; + pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + + sizeof(u32)*((int)nElem+1); + pRet->nElem = (int)nElem; pRet->zMatchinfo = ((char*)pRet) + nByte; memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1); pRet->aRef[0] = 1; @@ -175588,7 +177161,7 @@ static void fts3SnippetDetails( char *pCsr = pPhrase->pTail; int iCsr = pPhrase->iTail; - while( iCsr<(iStart+pIter->nSnippet) ){ + while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){ int j; u64 mPhrase = (u64)1 << i; u64 mPos = (u64)1 << (iCsr - iStart); @@ -176158,8 +177731,8 @@ static int fts3MatchinfoCheck( return SQLITE_ERROR; } -static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ - int nVal; /* Number of integers output by cArg */ +static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){ + size_t nVal; /* Number of integers output by cArg */ switch( cArg ){ case FTS3_MATCHINFO_NDOC: @@ -176443,7 +178016,7 @@ static int fts3MatchinfoValues( case FTS3_MATCHINFO_LHITS_BM: case FTS3_MATCHINFO_LHITS: { - int nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); + size_t nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32); memset(pInfo->aMatchinfo, 0, nZero); rc = fts3ExprLHitGather(pCsr->pExpr, pInfo); break; @@ -176512,7 +178085,7 @@ static void fts3GetMatchinfo( ** initialize those elements that are constant for every row. */ if( pCsr->pMIBuffer==0 ){ - int nMatchinfo = 0; /* Number of u32 elements in match-info */ + size_t nMatchinfo = 0; /* Number of u32 elements in match-info */ int i; /* Used to iterate through zArg */ /* Determine the number of phrases in the query */ @@ -176702,7 +178275,7 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){ nTerm = pExpr->pPhrase->nToken; if( pList ){ fts3GetDeltaPosition(&pList, &iPos); - assert( iPos>=0 ); + assert_fts3_nc( iPos>=0 ); } for(iTerm=0; iTerm<nTerm; iTerm++){ @@ -176812,7 +178385,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets( /* All offsets for this column have been gathered. */ rc = SQLITE_DONE; }else{ - assert( iCurrent<=iMinPos ); + assert_fts3_nc( iCurrent<=iMinPos ); if( 0==(0xFE&*pTerm->pList) ){ pTerm->pList = 0; }else{ @@ -178794,7 +180367,7 @@ static JsonNode *jsonLookupStep( u32 iStart, iLabel; JsonNode *pNode; iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); - iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath); + iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey); zPath += i; pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); if( pParse->oom ) return 0; @@ -180278,10 +181851,6 @@ SQLITE_API int sqlite3_json_init( /* #include "sqlite3.h" */ #endif -/* #include <string.h> */ -/* #include <assert.h> */ -/* #include <stdio.h> */ - #ifndef SQLITE_AMALGAMATION #include "sqlite3rtree.h" typedef sqlite3_int64 i64; @@ -180289,7 +181858,17 @@ typedef sqlite3_uint64 u64; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; +#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) +# define NDEBUG 1 #endif +#if defined(NDEBUG) && defined(SQLITE_DEBUG) +# undef NDEBUG +#endif +#endif + +/* #include <string.h> */ +/* #include <stdio.h> */ +/* #include <assert.h> */ /* The following macro is used to suppress compiler warnings. */ @@ -183970,49 +185549,45 @@ rtreeInit_fail: ** <num-dimension>*2 coordinates. */ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){ - char *zText = 0; RtreeNode node; Rtree tree; int ii; + int nData; + int errCode; + sqlite3_str *pOut; UNUSED_PARAMETER(nArg); memset(&node, 0, sizeof(RtreeNode)); memset(&tree, 0, sizeof(Rtree)); tree.nDim = (u8)sqlite3_value_int(apArg[0]); + if( tree.nDim<1 || tree.nDim>5 ) return; tree.nDim2 = tree.nDim*2; tree.nBytesPerCell = 8 + 8 * tree.nDim; node.zData = (u8 *)sqlite3_value_blob(apArg[1]); + nData = sqlite3_value_bytes(apArg[1]); + if( nData<4 ) return; + if( nData<NCELL(&node)*tree.nBytesPerCell ) return; + pOut = sqlite3_str_new(0); for(ii=0; ii<NCELL(&node); ii++){ - char zCell[512]; - int nCell = 0; RtreeCell cell; int jj; nodeGetCell(&tree, &node, ii, &cell); - sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid); - nCell = (int)strlen(zCell); + if( ii>0 ) sqlite3_str_append(pOut, " ", 1); + sqlite3_str_appendf(pOut, "{%lld", cell.iRowid); for(jj=0; jj<tree.nDim2; jj++){ #ifndef SQLITE_RTREE_INT_ONLY - sqlite3_snprintf(512-nCell,&zCell[nCell], " %g", - (double)cell.aCoord[jj].f); + sqlite3_str_appendf(pOut, " %g", (double)cell.aCoord[jj].f); #else - sqlite3_snprintf(512-nCell,&zCell[nCell], " %d", - cell.aCoord[jj].i); + sqlite3_str_appendf(pOut, " %d", cell.aCoord[jj].i); #endif - nCell = (int)strlen(zCell); - } - - if( zText ){ - char *zTextNew = sqlite3_mprintf("%s {%s}", zText, zCell); - sqlite3_free(zText); - zText = zTextNew; - }else{ - zText = sqlite3_mprintf("{%s}", zCell); } + sqlite3_str_append(pOut, "}", 1); } - - sqlite3_result_text(ctx, zText, -1, sqlite3_free); + errCode = sqlite3_str_errcode(pOut); + sqlite3_result_text(ctx, sqlite3_str_finish(pOut), -1, sqlite3_free); + sqlite3_result_error_code(ctx, errCode); } /* This routine implements an SQL function that returns the "depth" parameter @@ -184777,7 +186352,7 @@ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){ GeoPoly *pOut; int x = 1; s.nVertex--; /* Remove the redundant vertex at the end */ - pOut = sqlite3_malloc64( GEOPOLY_SZ(s.nVertex) ); + pOut = sqlite3_malloc64( GEOPOLY_SZ((sqlite3_int64)s.nVertex) ); x = 1; if( pOut==0 ) goto parse_json_err; pOut->nVertex = s.nVertex; @@ -185163,7 +186738,7 @@ static GeoPoly *geopolyBBox( if( pRc ) *pRc = SQLITE_OK; if( aCoord==0 ){ geopolyBboxFill: - pOut = sqlite3_realloc(p, GEOPOLY_SZ(4)); + pOut = sqlite3_realloc64(p, GEOPOLY_SZ(4)); if( pOut==0 ){ sqlite3_free(p); if( context ) sqlite3_result_error_nomem(context); @@ -185559,9 +187134,9 @@ static GeoSegment *geopolySortSegmentsByYAndC(GeoSegment *pList){ ** Determine the overlap between two polygons */ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){ - int nVertex = p1->nVertex + p2->nVertex + 2; + sqlite3_int64 nVertex = p1->nVertex + p2->nVertex + 2; GeoOverlap *p; - int nByte; + sqlite3_int64 nByte; GeoEvent *pThisEvent; double rX; int rc = 0; @@ -185573,7 +187148,7 @@ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){ nByte = sizeof(GeoEvent)*nVertex*2 + sizeof(GeoSegment)*nVertex + sizeof(GeoOverlap); - p = sqlite3_malloc( nByte ); + p = sqlite3_malloc64( nByte ); if( p==0 ) return -1; p->aEvent = (GeoEvent*)&p[1]; p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2]; @@ -185732,8 +187307,8 @@ static int geopolyInit( ){ int rc = SQLITE_OK; Rtree *pRtree; - int nDb; /* Length of string argv[1] */ - int nName; /* Length of string argv[2] */ + sqlite3_int64 nDb; /* Length of string argv[1] */ + sqlite3_int64 nName; /* Length of string argv[2] */ sqlite3_str *pSql; char *zSql; int ii; @@ -185741,9 +187316,9 @@ static int geopolyInit( sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); /* Allocate the sqlite3_vtab structure */ - nDb = (int)strlen(argv[1]); - nName = (int)strlen(argv[2]); - pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); + nDb = strlen(argv[1]); + nName = strlen(argv[2]); + pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2); if( !pRtree ){ return SQLITE_NOMEM; } @@ -188168,6 +189743,11 @@ struct RbuUpdateStmt { ** it points to an array of flags nTblCol elements in size. The flag is ** set for each column that is either a part of the PK or a part of an ** index. Or clear otherwise. +** +** If there are one or more partial indexes on the table, all fields of +** this array set set to 1. This is because in that case, the module has +** no way to tell which fields will be required to add and remove entries +** from the partial indexes. ** */ struct RbuObjIter { @@ -188612,6 +190192,7 @@ static void rbuFossilDeltaFunc( }else{ nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut); if( nOut2!=nOut ){ + sqlite3_free(aOut); sqlite3_result_error(context, "corrupt fossil delta", -1); }else{ sqlite3_result_blob(context, aOut, nOut, sqlite3_free); @@ -188852,7 +190433,8 @@ static void rbuTargetNameFunc( zIn = (const char*)sqlite3_value_text(argv[0]); if( zIn ){ if( rbuIsVacuum(p) ){ - if( argc==1 || 0==sqlite3_value_int(argv[1]) ){ + assert( argc==2 ); + if( 0==sqlite3_value_int(argv[1]) ){ sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC); } }else{ @@ -188962,7 +190544,7 @@ static int rbuMPrintfExec(sqlite3rbu *p, sqlite3 *db, const char *zFmt, ...){ ** immediately without attempting the allocation or modifying the stored ** error code. */ -static void *rbuMalloc(sqlite3rbu *p, int nByte){ +static void *rbuMalloc(sqlite3rbu *p, sqlite3_int64 nByte){ void *pRet = 0; if( p->rc==SQLITE_OK ){ assert( nByte>0 ); @@ -188983,7 +190565,7 @@ static void *rbuMalloc(sqlite3rbu *p, int nByte){ ** error code in the RBU handle passed as the first argument. */ static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){ - int nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol; + sqlite3_int64 nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol; char **azNew; azNew = (char**)rbuMalloc(p, nByte); @@ -189177,8 +190759,12 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){ pIter->nIndex = 0; while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){ const char *zIdx = (const char*)sqlite3_column_text(pList, 1); + int bPartial = sqlite3_column_int(pList, 4); sqlite3_stmt *pXInfo = 0; if( zIdx==0 ) break; + if( bPartial ){ + memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol); + } p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) ); @@ -189299,7 +190885,8 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){ } pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc); - pIter->abTblPk[iOrder] = (iPk!=0); + assert( iPk>=0 ); + pIter->abTblPk[iOrder] = (u8)iPk; pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0); iOrder++; } @@ -189335,6 +190922,213 @@ static char *rbuObjIterGetCollist( } /* +** Return a comma separated list of the quoted PRIMARY KEY column names, +** in order, for the current table. Before each column name, add the text +** zPre. After each column name, add the zPost text. Use zSeparator as +** the separator text (usually ", "). +*/ +static char *rbuObjIterGetPkList( + sqlite3rbu *p, /* RBU object */ + RbuObjIter *pIter, /* Object iterator for column names */ + const char *zPre, /* Before each quoted column name */ + const char *zSeparator, /* Separator to use between columns */ + const char *zPost /* After each quoted column name */ +){ + int iPk = 1; + char *zRet = 0; + const char *zSep = ""; + while( 1 ){ + int i; + for(i=0; i<pIter->nTblCol; i++){ + if( (int)pIter->abTblPk[i]==iPk ){ + const char *zCol = pIter->azTblCol[i]; + zRet = rbuMPrintf(p, "%z%s%s\"%w\"%s", zRet, zSep, zPre, zCol, zPost); + zSep = zSeparator; + break; + } + } + if( i==pIter->nTblCol ) break; + iPk++; + } + return zRet; +} + +/* +** This function is called as part of restarting an RBU vacuum within +** stage 1 of the process (while the *-oal file is being built) while +** updating a table (not an index). The table may be a rowid table or +** a WITHOUT ROWID table. It queries the target database to find the +** largest key that has already been written to the target table and +** constructs a WHERE clause that can be used to extract the remaining +** rows from the source table. For a rowid table, the WHERE clause +** is of the form: +** +** "WHERE _rowid_ > ?" +** +** and for WITHOUT ROWID tables: +** +** "WHERE (key1, key2) > (?, ?)" +** +** Instead of "?" placeholders, the actual WHERE clauses created by +** this function contain literal SQL values. +*/ +static char *rbuVacuumTableStart( + sqlite3rbu *p, /* RBU handle */ + RbuObjIter *pIter, /* RBU iterator object */ + int bRowid, /* True for a rowid table */ + const char *zWrite /* Target table name prefix */ +){ + sqlite3_stmt *pMax = 0; + char *zRet = 0; + if( bRowid ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, + sqlite3_mprintf( + "SELECT max(_rowid_) FROM \"%s%w\"", zWrite, pIter->zTbl + ) + ); + if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ + sqlite3_int64 iMax = sqlite3_column_int64(pMax, 0); + zRet = rbuMPrintf(p, " WHERE _rowid_ > %lld ", iMax); + } + rbuFinalize(p, pMax); + }else{ + char *zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", " DESC"); + char *zSelect = rbuObjIterGetPkList(p, pIter, "quote(", "||','||", ")"); + char *zList = rbuObjIterGetPkList(p, pIter, "", ", ", ""); + + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg, + sqlite3_mprintf( + "SELECT %s FROM \"%s%w\" ORDER BY %s LIMIT 1", + zSelect, zWrite, pIter->zTbl, zOrder + ) + ); + if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ + const char *zVal = (const char*)sqlite3_column_text(pMax, 0); + zRet = rbuMPrintf(p, " WHERE (%s) > (%s) ", zList, zVal); + } + rbuFinalize(p, pMax); + } + + sqlite3_free(zOrder); + sqlite3_free(zSelect); + sqlite3_free(zList); + } + return zRet; +} + +/* +** This function is called as part of restating an RBU vacuum when the +** current operation is writing content to an index. If possible, it +** queries the target index b-tree for the largest key already written to +** it, then composes and returns an expression that can be used in a WHERE +** clause to select the remaining required rows from the source table. +** It is only possible to return such an expression if: +** +** * The index contains no DESC columns, and +** * The last key written to the index before the operation was +** suspended does not contain any NULL values. +** +** The expression is of the form: +** +** (index-field1, index-field2, ...) > (?, ?, ...) +** +** except that the "?" placeholders are replaced with literal values. +** +** If the expression cannot be created, NULL is returned. In this case, +** the caller has to use an OFFSET clause to extract only the required +** rows from the sourct table, just as it does for an RBU update operation. +*/ +char *rbuVacuumIndexStart( + sqlite3rbu *p, /* RBU handle */ + RbuObjIter *pIter /* RBU iterator object */ +){ + char *zOrder = 0; + char *zLhs = 0; + char *zSelect = 0; + char *zVector = 0; + char *zRet = 0; + int bFailed = 0; + const char *zSep = ""; + int iCol = 0; + sqlite3_stmt *pXInfo = 0; + + p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg, + sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx) + ); + while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ + int iCid = sqlite3_column_int(pXInfo, 1); + const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); + const char *zCol; + if( sqlite3_column_int(pXInfo, 3) ){ + bFailed = 1; + break; + } + + if( iCid<0 ){ + if( pIter->eType==RBU_PK_IPK ){ + int i; + for(i=0; pIter->abTblPk[i]==0; i++); + assert( i<pIter->nTblCol ); + zCol = pIter->azTblCol[i]; + }else{ + zCol = "_rowid_"; + } + }else{ + zCol = pIter->azTblCol[iCid]; + } + + zLhs = rbuMPrintf(p, "%z%s \"%w\" COLLATE %Q", + zLhs, zSep, zCol, zCollate + ); + zOrder = rbuMPrintf(p, "%z%s \"rbu_imp_%d%w\" COLLATE %Q DESC", + zOrder, zSep, iCol, zCol, zCollate + ); + zSelect = rbuMPrintf(p, "%z%s quote(\"rbu_imp_%d%w\")", + zSelect, zSep, iCol, zCol + ); + zSep = ", "; + iCol++; + } + rbuFinalize(p, pXInfo); + if( bFailed ) goto index_start_out; + + if( p->rc==SQLITE_OK ){ + sqlite3_stmt *pSel = 0; + + p->rc = prepareFreeAndCollectError(p->dbMain, &pSel, &p->zErrmsg, + sqlite3_mprintf("SELECT %s FROM \"rbu_imp_%w\" ORDER BY %s LIMIT 1", + zSelect, pIter->zTbl, zOrder + ) + ); + if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSel) ){ + zSep = ""; + for(iCol=0; iCol<pIter->nCol; iCol++){ + const char *zQuoted = (const char*)sqlite3_column_text(pSel, iCol); + if( zQuoted[0]=='N' ){ + bFailed = 1; + break; + } + zVector = rbuMPrintf(p, "%z%s%s", zVector, zSep, zQuoted); + zSep = ", "; + } + + if( !bFailed ){ + zRet = rbuMPrintf(p, "(%s) > (%s)", zLhs, zVector); + } + } + rbuFinalize(p, pSel); + } + + index_start_out: + sqlite3_free(zOrder); + sqlite3_free(zSelect); + sqlite3_free(zVector); + sqlite3_free(zLhs); + return zRet; +} + +/* ** This function is used to create a SELECT list (the list of SQL ** expressions that follows a SELECT keyword) for a SELECT statement ** used to read from an data_xxx or rbu_tmp_xxx table while updating the @@ -189623,7 +191417,7 @@ static char *rbuObjIterGetSetlist( */ static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){ char *zRet = 0; - int nByte = nBind*2 + 1; + sqlite3_int64 nByte = 2*(sqlite3_int64)nBind + 1; zRet = (char*)rbuMalloc(p, nByte); if( zRet ){ @@ -189885,6 +191679,62 @@ static void rbuTmpInsertFunc( } } +static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ + sqlite3_stmt *pStmt = 0; + int rc = p->rc; + char *zRet = 0; + + if( rc==SQLITE_OK ){ + rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, + "SELECT trim(sql) FROM sqlite_master WHERE type='index' AND name=?" + ); + } + if( rc==SQLITE_OK ){ + int rc2; + rc = sqlite3_bind_text(pStmt, 1, pIter->zIdx, -1, SQLITE_STATIC); + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + const char *zSql = (const char*)sqlite3_column_text(pStmt, 0); + if( zSql ){ + int nParen = 0; /* Number of open parenthesis */ + int i; + for(i=0; zSql[i]; i++){ + char c = zSql[i]; + if( c=='(' ){ + nParen++; + } + else if( c==')' ){ + nParen--; + if( nParen==0 ){ + i++; + break; + } + }else if( c=='"' || c=='\'' || c=='`' ){ + for(i++; 1; i++){ + if( zSql[i]==c ){ + if( zSql[i+1]!=c ) break; + i++; + } + } + }else if( c=='[' ){ + for(i++; 1; i++){ + if( zSql[i]==']' ) break; + } + } + } + if( zSql[i] ){ + zRet = rbuStrndup(&zSql[i], &rc); + } + } + } + + rc2 = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) rc = rc2; + } + + p->rc = rc; + return zRet; +} + /* ** Ensure that the SQLite statement handles required to update the ** target database object currently indicated by the iterator passed @@ -189914,6 +191764,7 @@ static int rbuObjIterPrepareAll( char *zImposterPK = 0; /* Primary key declaration for imposter */ char *zWhere = 0; /* WHERE clause on PK columns */ char *zBind = 0; + char *zPart = 0; int nBind = 0; assert( pIter->eType!=RBU_PK_VTAB ); @@ -189921,6 +191772,7 @@ static int rbuObjIterPrepareAll( p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind ); zBind = rbuObjIterGetBindlist(p, nBind); + zPart = rbuObjIterGetIndexWhere(p, pIter); /* Create the imposter table used to write to this index. */ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1); @@ -189952,39 +191804,58 @@ static int rbuObjIterPrepareAll( if( p->rc==SQLITE_OK ){ char *zSql; if( rbuIsVacuum(p) ){ + char *zStart = 0; + if( nOffset ){ + zStart = rbuVacuumIndexStart(p, pIter); + if( zStart ){ + sqlite3_free(zLimit); + zLimit = 0; + } + } + zSql = sqlite3_mprintf( - "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s", + "SELECT %s, 0 AS rbu_control FROM '%q' %s %s %s ORDER BY %s%s", zCollist, pIter->zDataTbl, + zPart, + (zStart ? (zPart ? "AND" : "WHERE") : ""), zStart, zCollist, zLimit ); + sqlite3_free(zStart); }else if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){ zSql = sqlite3_mprintf( - "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s", + "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s ORDER BY %s%s", zCollist, p->zStateDb, pIter->zDataTbl, - zCollist, zLimit + zPart, zCollist, zLimit ); }else{ zSql = sqlite3_mprintf( - "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' " + "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s " "UNION ALL " "SELECT %s, rbu_control FROM '%q' " - "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 " + "%s %s typeof(rbu_control)='integer' AND rbu_control!=1 " "ORDER BY %s%s", - zCollist, p->zStateDb, pIter->zDataTbl, + zCollist, p->zStateDb, pIter->zDataTbl, zPart, zCollist, pIter->zDataTbl, + zPart, + (zPart ? "AND" : "WHERE"), zCollist, zLimit ); } - p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, zSql); + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbRbu,&pIter->pSelect,pz,zSql); + }else{ + sqlite3_free(zSql); + } } sqlite3_free(zImposterCols); sqlite3_free(zImposterPK); sqlite3_free(zWhere); sqlite3_free(zBind); + sqlite3_free(zPart); }else{ int bRbuRowid = (pIter->eType==RBU_PK_VTAB) ||(pIter->eType==RBU_PK_NONE) @@ -190077,18 +191948,42 @@ static int rbuObjIterPrepareAll( /* Create the SELECT statement to read keys from data_xxx */ if( p->rc==SQLITE_OK ){ const char *zRbuRowid = ""; + char *zStart = 0; + char *zOrder = 0; if( bRbuRowid ){ zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid"; } - p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, - sqlite3_mprintf( - "SELECT %s,%s rbu_control%s FROM '%q'%s", - zCollist, - (rbuIsVacuum(p) ? "0 AS " : ""), - zRbuRowid, - pIter->zDataTbl, zLimit - ) - ); + + if( rbuIsVacuum(p) ){ + if( nOffset ){ + zStart = rbuVacuumTableStart(p, pIter, bRbuRowid, zWrite); + if( zStart ){ + sqlite3_free(zLimit); + zLimit = 0; + } + } + if( bRbuRowid ){ + zOrder = rbuMPrintf(p, "_rowid_"); + }else{ + zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", ""); + } + } + + if( p->rc==SQLITE_OK ){ + p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, + sqlite3_mprintf( + "SELECT %s,%s rbu_control%s FROM '%q'%s %s %s %s", + zCollist, + (rbuIsVacuum(p) ? "0 AS " : ""), + zRbuRowid, + pIter->zDataTbl, (zStart ? zStart : ""), + (zOrder ? "ORDER BY" : ""), zOrder, + zLimit + ) + ); + } + sqlite3_free(zStart); + sqlite3_free(zOrder); } sqlite3_free(zWhere); @@ -192315,9 +194210,7 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){ }else if( rc==SQLITE_NOTFOUND ){ pRbu->pTargetFd = p; p->pRbu = pRbu; - if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ - rbuMainlistAdd(p); - } + rbuMainlistAdd(p); if( p->pWalFd ) p->pWalFd->pRbu = pRbu; rc = SQLITE_OK; } @@ -192380,10 +194273,7 @@ static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY; }else{ int bCapture = 0; - if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE) - && pRbu && pRbu->eStage==RBU_STAGE_CAPTURE - && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0) - ){ + if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){ bCapture = 1; } @@ -192416,20 +194306,24 @@ static int rbuVfsShmMap( ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space ** instead of a file on disk. */ assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); - if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){ - if( iRegion<=p->nShm ){ - int nByte = (iRegion+1) * sizeof(char*); - char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte); - if( apNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm)); - p->apShm = apNew; - p->nShm = iRegion+1; - } + if( eStage==RBU_STAGE_OAL ){ + sqlite3_int64 nByte = (iRegion+1) * sizeof(char*); + char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte); + + /* This is an RBU connection that uses its own heap memory for the + ** pages of the *-shm file. Since no other process can have run + ** recovery, the connection must request *-shm pages in order + ** from start to finish. */ + assert( iRegion==p->nShm ); + if( apNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm)); + p->apShm = apNew; + p->nShm = iRegion+1; } - if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){ + if( rc==SQLITE_OK ){ char *pNew = (char*)sqlite3_malloc64(szRegion); if( pNew==0 ){ rc = SQLITE_NOMEM; @@ -192658,7 +194552,8 @@ static int rbuVfsAccess( */ if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1); - if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ + if( pDb && pDb->pRbu->eStage==RBU_STAGE_OAL ){ + assert( pDb->pRbu ); if( *pResOut ){ rc = SQLITE_CANTOPEN; }else{ @@ -194929,7 +196824,7 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){ if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){ int i; SessionChange **apNew; - int nNew = (pTab->nChange ? pTab->nChange : 128) * 2; + sqlite3_int64 nNew = 2*(sqlite3_int64)(pTab->nChange ? pTab->nChange : 128); apNew = (SessionChange **)sqlite3_malloc64(sizeof(SessionChange *) * nNew); if( apNew==0 ){ @@ -195651,7 +197546,9 @@ SQLITE_API int sqlite3session_diff( } sqlite3_free((char*)azCol); if( bMismatch ){ - *pzErrMsg = sqlite3_mprintf("table schemas do not match"); + if( pzErrMsg ){ + *pzErrMsg = sqlite3_mprintf("table schemas do not match"); + } rc = SQLITE_SCHEMA; } if( bHasPk==0 ){ @@ -195856,8 +197753,8 @@ SQLITE_API int sqlite3session_attach( ** If successful, return zero. Otherwise, if an OOM condition is encountered, ** set *pRc to SQLITE_NOMEM and return non-zero. */ -static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){ - if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){ +static int sessionBufferGrow(SessionBuffer *p, size_t nByte, int *pRc){ + if( *pRc==SQLITE_OK && (size_t)(p->nAlloc-p->nBuf)<nByte ){ u8 *aNew; i64 nNew = p->nAlloc ? p->nAlloc : 128; do { @@ -196974,7 +198871,7 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){ } if( rc==SQLITE_OK ){ - int iPK = sizeof(sqlite3_value*)*p->nCol*2; + size_t iPK = sizeof(sqlite3_value*)*p->nCol*2; memset(p->tblhdr.aBuf, 0, iPK); memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy); p->in.iNext += nCopy; @@ -197889,7 +199786,7 @@ static int sessionSeekToRow( } /* -** This function is called from within sqlite3changset_apply_v2() when +** This function is called from within sqlite3changeset_apply_v2() when ** a conflict is encountered and resolved using conflict resolution ** mode eType (either SQLITE_CHANGESET_OMIT or SQLITE_CHANGESET_REPLACE).. ** It adds a conflict resolution record to the buffer in @@ -198278,7 +200175,7 @@ static int sessionRetryConstraints( rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0); if( rc==SQLITE_OK ){ - int nByte = 2*pApply->nCol*sizeof(sqlite3_value*); + size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*); int rc2; pIter2->bPatchset = bPatchset; pIter2->zTab = (char*)zTab; @@ -199671,7 +201568,7 @@ struct Fts5PhraseIter { ** Save the pointer passed as the second argument as the extension functions ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of -** of the same MATCH query using the xGetAuxdata() API. +** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for ** each FTS query (MATCH expression). If the extension function is invoked @@ -199686,7 +201583,7 @@ struct Fts5PhraseIter { ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** -** If an error (e.g. an OOM condition) occurs within this function, an +** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. @@ -200668,8 +202565,9 @@ static void sqlite3Fts5HashClear(Fts5Hash*); static int sqlite3Fts5HashQuery( Fts5Hash*, /* Hash table to query */ + int nPre, const char *pTerm, int nTerm, /* Query term */ - const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + void **ppObj, /* OUT: Pointer to doclist for pTerm */ int *pnDoclist /* OUT: Size of doclist in bytes */ ); @@ -202739,7 +204637,7 @@ static int fts5SnippetScore( sqlite3_int64 iAdj = iFirst - (nToken - (iLast-iFirst)) / 2; if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken; if( iAdj<0 ) iAdj = 0; - *piPos = iAdj; + *piPos = (int)iAdj; } return rc; @@ -202967,7 +204865,7 @@ static int fts5Bm25GetData( if( p==0 ){ rc = SQLITE_NOMEM; }else{ - memset(p, 0, nByte); + memset(p, 0, (size_t)nByte); p->nPhrase = nPhrase; p->aIDF = (double*)&p[1]; p->aFreq = &p->aIDF[nPhrase]; @@ -203130,7 +205028,7 @@ static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){ *pRc = SQLITE_NOMEM; return 1; }else{ - pBuf->nSpace = nNew; + pBuf->nSpace = (int)nNew; pBuf->p = pNew; } } @@ -203281,10 +205179,19 @@ static int sqlite3Fts5PoslistNext64( i64 iOff = *piOff; int iVal; fts5FastGetVarint32(a, i, iVal); - if( iVal==1 ){ + if( iVal<=1 ){ + if( iVal==0 ){ + *pi = i; + return 0; + } fts5FastGetVarint32(a, i, iVal); iOff = ((i64)iVal) << 32; fts5FastGetVarint32(a, i, iVal); + if( iVal<2 ){ + /* This is a corrupt record. So stop parsing it here. */ + *piOff = -1; + return 1; + } } *piOff = iOff + ((iVal-2) & 0x7FFFFFFF); *pi = i; @@ -203354,7 +205261,7 @@ static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte){ if( pRet==0 ){ if( nByte>0 ) *pRc = SQLITE_NOMEM; }else{ - memset(pRet, 0, nByte); + memset(pRet, 0, (size_t)nByte); } } return pRet; @@ -203823,7 +205730,7 @@ static int fts5ConfigParseSpecial( rc = SQLITE_ERROR; }else{ rc = sqlite3Fts5GetTokenizer(pGlobal, - (const char**)azArg, nArg, &pConfig->pTok, &pConfig->pTokApi, + (const char**)azArg, (int)nArg, &pConfig->pTok, &pConfig->pTokApi, pzErr ); } @@ -203933,7 +205840,7 @@ static const char *fts5ConfigGobbleWord( if( zOut==0 ){ *pRc = SQLITE_NOMEM; }else{ - memcpy(zOut, zIn, nIn+1); + memcpy(zOut, zIn, (size_t)(nIn+1)); if( fts5_isopenquote(zOut[0]) ){ int ii = fts5Dequote(zOut); zRet = &zIn[ii]; @@ -205947,7 +207854,7 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset( if( pRet==0 ){ pParse->rc = SQLITE_NOMEM; }else{ - memset(pRet, 0, nByte); + memset(pRet, 0, (size_t)nByte); } }else if( (pNear->nPhrase % SZALLOC)==0 ){ int nNew = pNear->nPhrase + SZALLOC; @@ -206023,7 +207930,7 @@ static int fts5ParseTokenize( if( pSyn==0 ){ rc = SQLITE_NOMEM; }else{ - memset(pSyn, 0, nByte); + memset(pSyn, 0, (size_t)nByte); pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); memcpy(pSyn->zTerm, pToken, nToken); pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; @@ -206183,7 +208090,7 @@ static int sqlite3Fts5ExprClonePhrase( nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int); pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte); if( pColset ){ - memcpy(pColset, pColsetOrig, nByte); + memcpy(pColset, pColsetOrig, (size_t)nByte); } pNew->pRoot->pNear->pColset = pColset; } @@ -206400,7 +208307,7 @@ static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){ sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int); pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte); if( pRet ){ - memcpy(pRet, pOrig, nByte); + memcpy(pRet, pOrig, (size_t)nByte); } }else{ pRet = 0; @@ -207417,7 +209324,7 @@ static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte *ppNew = 0; rc = SQLITE_NOMEM; }else{ - memset(pNew->aSlot, 0, nByte); + memset(pNew->aSlot, 0, (size_t)nByte); } } return rc; @@ -207501,19 +209408,25 @@ static int fts5HashResize(Fts5Hash *pHash){ return SQLITE_OK; } -static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ +static int fts5HashAddPoslistSize( + Fts5Hash *pHash, + Fts5HashEntry *p, + Fts5HashEntry *p2 +){ + int nRet = 0; if( p->iSzPoslist ){ - u8 *pPtr = (u8*)p; + u8 *pPtr = p2 ? (u8*)p2 : (u8*)p; + int nData = p->nData; if( pHash->eDetail==FTS5_DETAIL_NONE ){ - assert( p->nData==p->iSzPoslist ); + assert( nData==p->iSzPoslist ); if( p->bDel ){ - pPtr[p->nData++] = 0x00; + pPtr[nData++] = 0x00; if( p->bContent ){ - pPtr[p->nData++] = 0x00; + pPtr[nData++] = 0x00; } } }else{ - int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */ + int nSz = (nData - p->iSzPoslist - 1); /* Size in bytes */ int nPos = nSz*2 + p->bDel; /* Value of nPos field */ assert( p->bDel==0 || p->bDel==1 ); @@ -207523,14 +209436,19 @@ static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){ int nByte = sqlite3Fts5GetVarintLen((u32)nPos); memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz); sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos); - p->nData += (nByte-1); + nData += (nByte-1); } } - p->iSzPoslist = 0; - p->bDel = 0; - p->bContent = 0; + nRet = nData - p->nData; + if( p2==0 ){ + p->iSzPoslist = 0; + p->bDel = 0; + p->bContent = 0; + p->nData = nData; + } } + return nRet; } /* @@ -207587,7 +209505,7 @@ static int sqlite3Fts5HashWrite( p = (Fts5HashEntry*)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, sizeof(Fts5HashEntry)); - p->nAlloc = nByte; + p->nAlloc = (int)nByte; zKey = fts5EntryKey(p); zKey[0] = bByte; memcpy(&zKey[1], pToken, nToken); @@ -207642,7 +209560,7 @@ static int sqlite3Fts5HashWrite( /* If this is a new rowid, append the 4-byte size field for the previous ** entry, and the new rowid for this entry. */ if( iRowid!=p->iRowid ){ - fts5HashAddPoslistSize(pHash, p); + fts5HashAddPoslistSize(pHash, p, 0); p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); p->iRowid = iRowid; bNew = 1; @@ -207759,7 +209677,9 @@ static int fts5HashEntrySort( for(iSlot=0; iSlot<pHash->nSlot; iSlot++){ Fts5HashEntry *pIter; for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){ - if( pTerm==0 || 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm) ){ + if( pTerm==0 + || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm)) + ){ Fts5HashEntry *pEntry = pIter; pEntry->pScanNext = 0; for(i=0; ap[i]; i++){ @@ -207787,8 +209707,9 @@ static int fts5HashEntrySort( */ static int sqlite3Fts5HashQuery( Fts5Hash *pHash, /* Hash table to query */ + int nPre, const char *pTerm, int nTerm, /* Query term */ - const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */ + void **ppOut, /* OUT: Pointer to new object */ int *pnDoclist /* OUT: Size of doclist in bytes */ ){ unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm); @@ -207802,11 +209723,20 @@ static int sqlite3Fts5HashQuery( } if( p ){ - fts5HashAddPoslistSize(pHash, p); - *ppDoclist = (const u8*)&zKey[nTerm+1]; - *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); + int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1; + int nList = p->nData - nHashPre; + u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10)); + if( pRet ){ + Fts5HashEntry *pFaux = (Fts5HashEntry*)&pRet[nPre-nHashPre]; + memcpy(&pRet[nPre], &((u8*)p)[nHashPre], nList); + nList += fts5HashAddPoslistSize(pHash, p, pFaux); + *pnDoclist = nList; + }else{ + *pnDoclist = 0; + return SQLITE_NOMEM; + } }else{ - *ppDoclist = 0; + *ppOut = 0; *pnDoclist = 0; } @@ -207839,7 +209769,7 @@ static void sqlite3Fts5HashScanEntry( if( (p = pHash->pScan) ){ char *zKey = fts5EntryKey(p); int nTerm = (int)strlen(zKey); - fts5HashAddPoslistSize(pHash, p); + fts5HashAddPoslistSize(pHash, p, 0); *pzTerm = zKey; *ppDoclist = (const u8*)&zKey[nTerm+1]; *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1); @@ -208844,7 +210774,7 @@ static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){ /* TODO: Do we need this if the leaf-index is appended? Probably... */ memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING); p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet); - if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){ + if( p->rc==SQLITE_OK && (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){ p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); } fts5DataRelease(pData); @@ -210309,31 +212239,40 @@ static void fts5SegIterHashInit( int flags, /* Mask of FTS5INDEX_XXX flags */ Fts5SegIter *pIter /* Object to populate */ ){ - const u8 *pList = 0; int nList = 0; const u8 *z = 0; int n = 0; + Fts5Data *pLeaf = 0; assert( p->pHash ); assert( p->rc==SQLITE_OK ); if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){ + const u8 *pList = 0; + p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm); sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList); n = (z ? (int)strlen((const char*)z) : 0); + if( pList ){ + pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); + if( pLeaf ){ + pLeaf->p = (u8*)pList; + } + } }else{ - pIter->flags |= FTS5_SEGITER_ONETERM; - sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList); + p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data), + (const char*)pTerm, nTerm, (void**)&pLeaf, &nList + ); + if( pLeaf ){ + pLeaf->p = (u8*)&pLeaf[1]; + } z = pTerm; n = nTerm; + pIter->flags |= FTS5_SEGITER_ONETERM; } - if( pList ){ - Fts5Data *pLeaf; + if( pLeaf ){ sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z); - pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data)); - if( pLeaf==0 ) return; - pLeaf->p = (u8*)pList; pLeaf->nn = pLeaf->szLeaf = nList; pIter->pLeaf = pLeaf; pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid); @@ -210486,8 +212425,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){ }else{ int res = fts5BufferCompare(&p1->term, &p2->term); if( res==0 ){ - assert( i2>i1 ); - assert( i2!=0 ); + assert_nc( i2>i1 ); + assert_nc( i2!=0 ); pRes->bTermEq = 1; if( p1->iRowid==p2->iRowid ){ p1->bDel = p2->bDel; @@ -211534,7 +213473,7 @@ static int fts5WriteDlidxGrow( if( aDlidx==0 ){ p->rc = SQLITE_NOMEM; }else{ - int nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx); + size_t nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx); memset(&aDlidx[pWriter->nDlidx], 0, nByte); pWriter->aDlidx = aDlidx; pWriter->nDlidx = nLvl; @@ -212021,13 +213960,14 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){ /* Set up the new page-index array */ fts5BufferAppendVarint(&p->rc, &buf, 4); if( pSeg->iLeafPgno==pSeg->iTermLeafPgno - && pSeg->iEndofDoclist<pData->szLeaf - ){ + && pSeg->iEndofDoclist<pData->szLeaf + && pSeg->iPgidxOff<=pData->nn + ){ int nDiff = pData->szLeaf - pSeg->iEndofDoclist; fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4); fts5BufferAppendBlob(&p->rc, &buf, pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff] - ); + ); } pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno; @@ -212795,8 +214735,14 @@ static void fts5MergePrefixLists( ** first rowid in one input is a large negative number, and the first in ** the other a non-negative number, the delta for the non-negative ** number will be larger on disk than the literal integer value - ** was. */ - if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9) ) return; + ** was. + ** + ** Or, if the input position-lists are corrupt, then the output might + ** include up to 2 extra 10-byte positions created by interpreting -1 + ** (the value PoslistNext64() uses for EOF) as a position and appending + ** it to the output. This can happen at most once for each input + ** position-list, hence two 10 byte paddings. */ + if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9+10+10) ) return; fts5DoclistIterInit(p1, &i1); fts5DoclistIterInit(p2, &i2); @@ -212807,6 +214753,7 @@ static void fts5MergePrefixLists( fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize); fts5DoclistIterNext(&i1); if( i1.aPoslist==0 ) break; + assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) ); } else if( i2.iRowid!=i1.iRowid ){ /* Copy entry from i2 */ @@ -212814,6 +214761,7 @@ static void fts5MergePrefixLists( fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize); fts5DoclistIterNext(&i2); if( i2.aPoslist==0 ) break; + assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) ); } else{ /* Merge the two position lists. */ @@ -212837,7 +214785,7 @@ static void fts5MergePrefixLists( sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); - assert( iPos1>=0 && iPos2>=0 ); + assert_nc( iPos1>=0 && iPos2>=0 ); if( iPos1<iPos2 ){ sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1); @@ -212846,7 +214794,6 @@ static void fts5MergePrefixLists( sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2); sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); } - if( iPos1>=0 && iPos2>=0 ){ while( 1 ){ if( iPos1<iPos2 ){ @@ -212871,7 +214818,7 @@ static void fts5MergePrefixLists( aCopy = &a1[iOff1]; nCopy = i1.nPoslist - iOff1; }else{ - assert( iPos2>=0 && iPos2!=iPrev ); + assert_nc( iPos2>=0 && iPos2!=iPrev ); sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2); aCopy = &a2[iOff2]; nCopy = i2.nPoslist - iOff2; @@ -212885,8 +214832,9 @@ static void fts5MergePrefixLists( fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); fts5DoclistIterNext(&i1); fts5DoclistIterNext(&i2); - assert( out.n<=(p1->n+p2->n+9) ); + assert_nc( out.n<=(p1->n+p2->n+9) ); if( i1.aPoslist==0 || i2.aPoslist==0 ) break; + assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) ); } } @@ -212898,7 +214846,7 @@ static void fts5MergePrefixLists( fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist); } - assert( out.n<=(p1->n+p2->n+9) ); + assert_nc( out.n<=(p1->n+p2->n+9) ); fts5BufferSet(&p->rc, p1, out.n, out.p); fts5BufferFree(&tmp); @@ -215049,7 +216997,7 @@ static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ pCsr = (Fts5Cursor*)sqlite3_malloc64(nByte); if( pCsr ){ Fts5Global *pGlobal = pTab->pGlobal; - memset(pCsr, 0, nByte); + memset(pCsr, 0, (size_t)nByte); pCsr->aColumnSize = (int*)&pCsr[1]; pCsr->pNext = pGlobal->pCsr; pGlobal->pCsr = pCsr; @@ -215330,7 +217278,7 @@ static int fts5CursorFirstSorted( nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1); pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte); if( pSorter==0 ) return SQLITE_NOMEM; - memset(pSorter, 0, nByte); + memset(pSorter, 0, (size_t)nByte); pSorter->nIdx = nPhrase; /* TODO: It would be better to have some system for reusing statement @@ -216884,14 +218832,14 @@ static int fts5CreateAux( int rc = sqlite3_overload_function(pGlobal->db, zName, -1); if( rc==SQLITE_OK ){ Fts5Auxiliary *pAux; - int nName; /* Size of zName in bytes, including \0 */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nName; /* Size of zName in bytes, including \0 */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ - nName = (int)strlen(zName) + 1; + nName = strlen(zName) + 1; nByte = sizeof(Fts5Auxiliary) + nName; - pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte); + pAux = (Fts5Auxiliary*)sqlite3_malloc64(nByte); if( pAux ){ - memset(pAux, 0, nByte); + memset(pAux, 0, (size_t)nByte); pAux->zFunc = (char*)&pAux[1]; memcpy(pAux->zFunc, zName, nName); pAux->pGlobal = pGlobal; @@ -216921,15 +218869,15 @@ static int fts5CreateTokenizer( ){ Fts5Global *pGlobal = (Fts5Global*)pApi; Fts5TokenizerModule *pNew; - int nName; /* Size of zName and its \0 terminator */ - int nByte; /* Bytes of space to allocate */ + sqlite3_int64 nName; /* Size of zName and its \0 terminator */ + sqlite3_int64 nByte; /* Bytes of space to allocate */ int rc = SQLITE_OK; - nName = (int)strlen(zName) + 1; + nName = strlen(zName) + 1; nByte = sizeof(Fts5TokenizerModule) + nName; - pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte); + pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte); if( pNew ){ - memset(pNew, 0, nByte); + memset(pNew, 0, (size_t)nByte); pNew->zName = (char*)&pNew[1]; memcpy(pNew->zName, zName, nName); pNew->pUserData = pUserData; @@ -217064,7 +219012,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2019-02-25 16:06:06 bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0f6d7", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6", -1, SQLITE_TRANSIENT); } /* @@ -217487,7 +219435,7 @@ static int sqlite3Fts5StorageOpen( *pp = p = (Fts5Storage*)sqlite3_malloc64(nByte); if( !p ) return SQLITE_NOMEM; - memset(p, 0, nByte); + memset(p, 0, (size_t)nByte); p->aTotalSize = (i64*)&p[1]; p->pConfig = pConfig; p->pIndex = pIndex; @@ -218709,7 +220657,7 @@ static int fts5UnicodeCreate( p->eRemoveDiacritic = FTS5_REMOVE_DIACRITICS_SIMPLE; p->nFold = 64; - p->aFold = sqlite3_malloc(p->nFold * sizeof(char)); + p->aFold = sqlite3_malloc64(p->nFold * sizeof(char)); if( p->aFold==0 ){ rc = SQLITE_NOMEM; } @@ -220397,7 +222345,7 @@ static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){ int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ - aAscii[i] = bToken; + aAscii[i] = (u8)bToken; } iTbl++; } @@ -221323,8 +223271,10 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){ } if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ - while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++; - assert( pCsr->iCol<pCsr->pFts5->pConfig->nCol ); + for(/* noop */; pCsr->iCol<nCol && pCsr->aDoc[pCsr->iCol]==0; pCsr->iCol++); + if( pCsr->iCol==nCol ){ + rc = FTS5_CORRUPT; + } } return rc; } @@ -221828,9 +223778,9 @@ SQLITE_API int sqlite3_stmt_init( #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ /************** End of stmt.c ************************************************/ -#if __LINE__!=221831 +#if __LINE__!=223781 #undef SQLITE_SOURCE_ID -#define SQLITE_SOURCE_ID "2019-02-25 16:06:06 bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0alt2" +#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88alt2" #endif /* Return the source-id for this library */ SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } diff --git a/db/sqlite3/src/sqlite3.h b/db/sqlite3/src/sqlite3.h index 348db7466..a4bab0ad6 100644 --- a/db/sqlite3/src/sqlite3.h +++ b/db/sqlite3/src/sqlite3.h @@ -123,9 +123,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.27.2" -#define SQLITE_VERSION_NUMBER 3027002 -#define SQLITE_SOURCE_ID "2019-02-25 16:06:06 bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0f6d7" +#define SQLITE_VERSION "3.29.0" +#define SQLITE_VERSION_NUMBER 3029000 +#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -189,6 +189,9 @@ SQLITE_API int sqlite3_libversion_number(void); #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_API int sqlite3_compileoption_used(const char *zOptName); SQLITE_API const char *sqlite3_compileoption_get(int N); +#else +# define sqlite3_compileoption_used(X) 0 +# define sqlite3_compileoption_get(X) ((void*)0) #endif /* @@ -1293,8 +1296,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] -** to test whether a file is at least readable. The file can be a -** directory. +** to test whether a file is at least readable. The SQLITE_ACCESS_READ +** flag is never actually used and is not implemented in the built-in +** VFSes of SQLite. The file is named by the second argument and can be a +** directory. The xAccess method returns [SQLITE_OK] on success or some +** non-zero error code if there is an I/O error or if the name of +** the file given in the second argument is illegal. If SQLITE_OK +** is returned, then non-zero or zero is written into *pResOut to indicate +** whether or not the file is accessible. ** ** ^SQLite will always allocate at least mxPathname+1 bytes for the ** output buffer xFullPathname. The exact size of the output buffer @@ -2086,8 +2095,8 @@ struct sqlite3_mem_methods { ** ** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]] ** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt> -** <dd> ^This option is used to enable or disable the two-argument -** version of the [fts3_tokenizer()] function which is part of the +** <dd> ^This option is used to enable or disable the +** [fts3_tokenizer()] function which is part of the ** [FTS3] full-text search engine extension. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable fts3_tokenizer() or @@ -2195,10 +2204,50 @@ struct sqlite3_mem_methods { ** features include but are not limited to the following: ** <ul> ** <li> The [PRAGMA writable_schema=ON] statement. +** <li> The [PRAGMA journal_mode=OFF] statement. ** <li> Writes to the [sqlite_dbpage] virtual table. ** <li> Direct writes to [shadow tables]. ** </ul> ** </dd> +** +** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]] <dt>SQLITE_DBCONFIG_WRITABLE_SCHEMA</dt> +** <dd>The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the +** "writable_schema" flag. This has the same effect and is logically equivalent +** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF]. +** The first argument to this setting is an integer which is 0 to disable +** the writable_schema, positive to enable writable_schema, or negative to +** leave the setting unchanged. The second parameter is a pointer to an +** integer into which is written 0 or 1 to indicate whether the writable_schema +** is enabled or disabled following this call. +** </dd> +** +** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]] +** <dt>SQLITE_DBCONFIG_LEGACY_ALTER_TABLE</dt> +** <dd>The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates +** the legacy behavior of the [ALTER TABLE RENAME] command such it +** behaves as it did prior to [version 3.24.0] (2018-06-04). See the +** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for +** additional information. This feature can also be turned on and off +** using the [PRAGMA legacy_alter_table] statement. +** </dd> +** +** [[SQLITE_DBCONFIG_DQS_DML]] +** <dt>SQLITE_DBCONFIG_DQS_DML</td> +** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DML statement +** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. +** </dd> +** +** [[SQLITE_DBCONFIG_DQS_DDL]] +** <dt>SQLITE_DBCONFIG_DQS_DDL</td> +** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates +** the legacy [double-quoted string literal] misfeature for DDL statements, +** such as CREATE TABLE and CREATE INDEX. The +** default value of this setting is determined by the [-DSQLITE_DQS] +** compile-time option. +** </dd> ** </dl> */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ @@ -2212,7 +2261,11 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */ #define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */ #define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1010 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */ +#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */ +#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -3895,6 +3948,18 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); /* +** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement +** METHOD: sqlite3_stmt +** +** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the +** prepared statement S is an EXPLAIN statement, or 2 if the +** statement S is an EXPLAIN QUERY PLAN. +** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is +** an ordinary statement or a NULL pointer. +*/ +SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt); + +/* ** CAPI3REF: Determine If A Prepared Statement Has Been Reset ** METHOD: sqlite3_stmt ** @@ -4033,7 +4098,9 @@ typedef struct sqlite3_context sqlite3_context; ** ^The fifth argument to the BLOB and string binding interfaces ** is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor is called -** to dispose of the BLOB or string even if the call to bind API fails. +** to dispose of the BLOB or string even if the call to the bind API fails, +** except the destructor is not called if the third parameter is a NULL +** pointer or the fourth parameter is negative. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. @@ -4950,6 +5017,8 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** <tr><td><b>sqlite3_value_nochange </b> ** <td>→ <td>True if the column is unchanged in an UPDATE ** against a virtual table. +** <tr><td><b>sqlite3_value_frombind </b> +** <td>→ <td>True if value originated from a [bound parameter] ** </table></blockquote> ** ** <b>Details:</b> @@ -5011,6 +5080,11 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** than within an [xUpdate] method call for an UPDATE statement, then ** the return value is arbitrary and meaningless. ** +** ^The sqlite3_value_frombind(X) interface returns non-zero if the +** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] +** interfaces. ^If X comes from an SQL literal value, or a table column, +** and expression, then sqlite3_value_frombind(X) returns zero. +** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to @@ -5056,6 +5130,7 @@ SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); SQLITE_API int sqlite3_value_nochange(sqlite3_value*); +SQLITE_API int sqlite3_value_frombind(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values @@ -5791,7 +5866,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); ** associated with database N of connection D. ^The main database file ** has the name "main". If there is no attached database N on the database ** connection D, or if database N is a temporary or in-memory database, then -** a NULL pointer is returned. +** this function will return either a NULL pointer or an empty string. ** ** ^The filename returned by this function is the output of the ** xFullPathname method of the [VFS]. ^In other words, the filename @@ -7282,7 +7357,8 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_SORTER_MMAP 24 #define SQLITE_TESTCTRL_IMPOSTER 25 #define SQLITE_TESTCTRL_PARSER_COVERAGE 26 -#define SQLITE_TESTCTRL_LAST 26 /* Largest TESTCTRL */ +#define SQLITE_TESTCTRL_RESULT_INTREAL 27 +#define SQLITE_TESTCTRL_LAST 27 /* Largest TESTCTRL */ /* ** CAPI3REF: SQL Keyword Checking @@ -10892,7 +10968,7 @@ SQLITE_API int sqlite3rebaser_configure( ** in size. This function allocates and populates a buffer with a copy ** of the changeset rebased rebased according to the configuration of the ** rebaser object passed as the first argument. If successful, (*ppOut) -** is set to point to the new buffer containing the rebased changset and +** is set to point to the new buffer containing the rebased changeset and ** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the ** responsibility of the caller to eventually free the new buffer using ** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut) @@ -11301,7 +11377,7 @@ struct Fts5PhraseIter { ** Save the pointer passed as the second argument as the extension functions ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of -** of the same MATCH query using the xGetAuxdata() API. +** the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for ** each FTS query (MATCH expression). If the extension function is invoked @@ -11316,7 +11392,7 @@ struct Fts5PhraseIter { ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** -** If an error (e.g. an OOM condition) occurs within this function, an +** If an error (e.g. an OOM condition) occurs within this function, ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. diff --git a/devtools/client/framework/devtools-browser.js b/devtools/client/framework/devtools-browser.js index 4d7176b4c..83a888ab9 100644 --- a/devtools/client/framework/devtools-browser.js +++ b/devtools/client/framework/devtools-browser.js @@ -123,23 +123,6 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { win.DeveloperToolbar.show(false).catch(console.error); } - // Enable WebIDE? - let webIDEEnabled = Services.prefs.getBoolPref("devtools.webide.enabled"); - idEls = [ - "appmenu_webide", - "menu_webide" - ]; - idEls.forEach(function (idEl) { - toggleMenuItem(idEl, webIDEEnabled); - }); - - let showWebIDEWidget = Services.prefs.getBoolPref("devtools.webide.widget.enabled"); - if (webIDEEnabled && showWebIDEWidget) { - gDevToolsBrowser.installWebIDEWidget(); - } else { - gDevToolsBrowser.uninstallWebIDEWidget(); - } - // Enable Browser Toolbox? let chromeEnabled = Services.prefs.getBoolPref("devtools.chrome.enabled"); let devtoolsRemoteEnabled = Services.prefs.getBoolPref("devtools.debugger.remote-enabled"); @@ -347,9 +330,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = { viewId: "PanelUI-developer", shortcutId: "key_devToolboxMenuItem", tooltiptext: "developer-button.tooltiptext2", - defaultArea: AppConstants.MOZ_DEV_EDITION ? - CustomizableUI.AREA_NAVBAR : - CustomizableUI.AREA_PANEL, + defaultArea: CustomizableUI.AREA_PANEL, onViewShowing: function (aEvent) { // Populate the subview with whatever menuitems are in the developer // menu. We skip menu elements, because the menu panel has no way diff --git a/devtools/client/framework/gDevTools.jsm b/devtools/client/framework/gDevTools.jsm index d825c0eaa..6e0dc5e83 100644 --- a/devtools/client/framework/gDevTools.jsm +++ b/devtools/client/framework/gDevTools.jsm @@ -127,15 +127,8 @@ let gDevToolsBrowserMethods = [ "openConnectScreen", // Used by browser-sets.inc, command - // itself, webide widget - "openWebIDE", - - // Used by browser-sets.inc, command "openContentProcessToolbox", - // Used by webide.js - "moveWebIDEWidgetInNavbar", - // Used by browser.js "registerBrowserWindow", @@ -146,10 +139,6 @@ let gDevToolsBrowserMethods = [ "forgetBrowserWindow" ]; this.gDevToolsBrowser = { - // Used by webide.js - get isWebIDEInitialized() { - return browser.isWebIDEInitialized; - }, // Used by a test (should be removed) get _trackedBrowserWindows() { return browser._trackedBrowserWindows; diff --git a/devtools/client/jsonview/converter-child.js b/devtools/client/jsonview/converter-child.js index 61aa0c9a3..65327c395 100644 --- a/devtools/client/jsonview/converter-child.js +++ b/devtools/client/jsonview/converter-child.js @@ -23,10 +23,6 @@ const childProcessMessageManager = Cc["@mozilla.org/childprocessmessagemanager;1"] .getService(Ci.nsISyncMessageSender); -// Amount of space that will be allocated for the stream's backing-store. -// Must be power of 2. Used to copy the data stream in onStopRequest. -const SEGMENT_SIZE = Math.pow(2, 17); - const JSON_VIEW_MIME_TYPE = "application/vnd.mozilla.json.view"; const CONTRACT_ID = "@mozilla.org/streamconv;1?from=" + JSON_VIEW_MIME_TYPE + "&to=*/*"; @@ -61,9 +57,8 @@ let Converter = Class({ * 1. asyncConvertData captures the listener * 2. onStartRequest fires, initializes stuff, modifies the listener * to match our output type - * 3. onDataAvailable transcodes the data into a UTF-8 string - * 4. onStopRequest gets the collected data and converts it, - * spits it to the listener + * 3. onDataAvailable spits it back to the listener + * 4. onStopRequest spits it back to the listener * 5. convert does nothing, it's just the synchronous version * of asyncConvertData */ @@ -76,243 +71,221 @@ let Converter = Class({ }, onDataAvailable: function (request, context, inputStream, offset, count) { - // From https://developer.mozilla.org/en/Reading_textual_data - let is = Cc["@mozilla.org/intl/converter-input-stream;1"] - .createInstance(Ci.nsIConverterInputStream); - is.init(inputStream, this.charset, -1, - Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); - - // Seed it with something positive - while (count) { - let str = {}; - let bytesRead = is.readString(count, str); - if (!bytesRead) { - break; - } - count -= bytesRead; - this.data += str.value; - } + this.listener.onDataAvailable(...arguments); }, onStartRequest: function (request, context) { - this.data = ""; - this.uri = request.QueryInterface(Ci.nsIChannel).URI.spec; + // Set the content type to HTML in order to parse the doctype, styles + // and scripts, but later a <plaintext> element will switch the tokenizer + // to the plaintext state in order to parse the JSON. + request.QueryInterface(Ci.nsIChannel); + request.contentType = "text/html"; - // Sets the charset if it is available. (For documents loaded from the - // filesystem, this is not set.) - this.charset = - request.QueryInterface(Ci.nsIChannel).contentCharset || "UTF-8"; + // JSON enforces UTF-8 charset (see bug 741776). + request.contentCharset = "UTF-8"; + + // Changing the content type breaks saving functionality. Fix it. + fixSave(request); - this.channel = request; - this.channel.contentType = "text/html"; - this.channel.contentCharset = "UTF-8"; // Because content might still have a reference to this window, // force setting it to a null principal to avoid it being same- // origin with (other) content. - this.channel.loadInfo.resetPrincipalsToNullPrincipal(); + request.loadInfo.resetPrincipalsToNullPrincipal(); - this.listener.onStartRequest(this.channel, context); - }, - - /** - * This should go something like this: - * 1. Make sure we have a unicode string. - * 2. Convert it to a Javascript object. - * 2.1 Removes the callback - * 3. Convert that to HTML? Or XUL? - * 4. Spit it back out at the listener - */ - onStopRequest: function (request, context, statusCode) { - let headers = { - response: [], - request: [] - }; + // Start the request. + this.listener.onStartRequest(request, context); + // Initialize stuff. let win = NetworkHelper.getWindowForRequest(request); + exportData(win, request); + win.addEventListener("DOMContentLoaded", event => { + win.addEventListener("contentMessage", onContentMessage, false, true); + }, {once: true}); + + // Insert the initial HTML code. + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + let stream = converter.convertToInputStream(initialHTML(win.document)); + this.listener.onDataAvailable(request, context, stream, 0, stream.available()); + }, - let Locale = { - $STR: key => { - try { - return jsonViewStrings.GetStringFromName(key); - } catch (err) { - console.error(err); - return undefined; - } - } - }; - - JsonViewUtils.exportIntoContentScope(win, Locale, "Locale"); - - Events.once(win, "DOMContentLoaded", event => { - win.addEventListener("contentMessage", - this.onContentMessage.bind(this), false, true); - }); - - // The request doesn't have to be always nsIHttpChannel - // (e.g. in case of data: URLs) - if (request instanceof Ci.nsIHttpChannel) { - request.visitResponseHeaders({ - visitHeader: function (name, value) { - headers.response.push({name: name, value: value}); - } - }); - - request.visitRequestHeaders({ - visitHeader: function (name, value) { - headers.request.push({name: name, value: value}); - } - }); - } - - let outputDoc = ""; + onStopRequest: function (request, context, statusCode) { + this.listener.onStopRequest(request, context, statusCode); + this.listener = null; + } +}); +// Lets "save as" save the original JSON, not the viewer. +// To save with the proper extension we need the original content type, +// which has been replaced by application/vnd.mozilla.json.view +function fixSave(request) { + let originalType; + if (request instanceof Ci.nsIHttpChannel) { try { - headers = JSON.stringify(headers); - outputDoc = this.toHTML(this.data, headers, this.uri); - } catch (e) { - console.error("JSON Viewer ERROR " + e); - outputDoc = this.toErrorPage(e, this.data, this.uri); + let header = request.getResponseHeader("Content-Type"); + originalType = header.split(";")[0]; + } catch (err) { + // Handled below } - - let storage = Cc["@mozilla.org/storagestream;1"] - .createInstance(Ci.nsIStorageStream); - - storage.init(SEGMENT_SIZE, 0xffffffff, null); - let out = storage.getOutputStream(0); - - let binout = Cc["@mozilla.org/binaryoutputstream;1"] - .createInstance(Ci.nsIBinaryOutputStream); - - binout.setOutputStream(out); - binout.writeUtf8Z(outputDoc); - binout.close(); - - // We need to trim 4 bytes off the front (this could be underlying bug). - let trunc = 4; - let instream = storage.newInputStream(trunc); - - // Pass the data to the main content listener - this.listener.onDataAvailable(this.channel, context, instream, 0, - instream.available()); - - this.listener.onStopRequest(this.channel, context, statusCode); - - this.listener = null; - }, - - htmlEncode: function (t) { - return t !== null ? t.toString() - .replace(/&/g, "&") - .replace(/"/g, """) - .replace(/</g, "<") - .replace(/>/g, ">") : ""; - }, - - toHTML: function (json, headers, title) { - let themeClassName = "theme-" + JsonViewUtils.getCurrentTheme(); - let clientBaseUrl = "resource://devtools/client/"; - let baseUrl = clientBaseUrl + "jsonview/"; - let themeVarsUrl = clientBaseUrl + "themes/variables.css"; - let commonUrl = clientBaseUrl + "themes/common.css"; - let toolbarsUrl = clientBaseUrl + "themes/toolbars.css"; - - let os; - let platform = Services.appinfo.OS; - if (platform.startsWith("WINNT")) { - os = "win"; - } else if (platform.startsWith("Darwin")) { - os = "mac"; - } else { - os = "linux"; + } else { + let uri = request.QueryInterface(Ci.nsIChannel).URI.spec; + let match = uri.match(/^data:(.*?)[,;]/); + if (match) { + originalType = match[1]; } + } + const JSON_TYPES = ["application/json", "application/manifest+json"]; + if (!JSON_TYPES.includes(originalType)) { + originalType = JSON_TYPES[0]; + } + request.QueryInterface(Ci.nsIWritablePropertyBag); + request.setProperty("contentType", originalType); +} - return "<!DOCTYPE html>\n" + - "<html platform=\"" + os + "\" class=\"" + themeClassName + "\">" + - "<head><title>" + this.htmlEncode(title) + "</title>" + - "<base href=\"" + this.htmlEncode(baseUrl) + "\">" + - "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + - themeVarsUrl + "\">" + - "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + - commonUrl + "\">" + - "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + - toolbarsUrl + "\">" + - "<link rel=\"stylesheet\" type=\"text/css\" href=\"css/main.css\">" + - "<script data-main=\"viewer-config\" src=\"lib/require.js\"></script>" + - "</head><body>" + - "<div id=\"content\"></div>" + - "<div id=\"json\">" + this.htmlEncode(json) + "</div>" + - "<div id=\"headers\">" + this.htmlEncode(headers) + "</div>" + - "</body></html>"; - }, - - toErrorPage: function (error, data, uri) { - // Escape unicode nulls - data = data.replace("\u0000", "\uFFFD"); +// Exports variables that will be accessed by the non-privileged scripts. +function exportData(win, request) { + let Locale = { + $STR: key => { + try { + return jsonViewStrings.GetStringFromName(key); + } catch (err) { + console.error(err); + return undefined; + } + } + }; + JsonViewUtils.exportIntoContentScope(win, Locale, "Locale"); + + let headers = { + response: [], + request: [] + }; + // The request doesn't have to be always nsIHttpChannel + // (e.g. in case of data: URLs) + if (request instanceof Ci.nsIHttpChannel) { + request.visitResponseHeaders({ + visitHeader: function (name, value) { + headers.response.push({name: name, value: value}); + } + }); + request.visitRequestHeaders({ + visitHeader: function (name, value) { + headers.request.push({name: name, value: value}); + } + }); + } + JsonViewUtils.exportIntoContentScope(win, headers, "headers"); +} - let errorInfo = error + ""; +// Serializes a qualifiedName and an optional set of attributes into an HTML +// start tag. Be aware qualifiedName and attribute names are not validated. +// Attribute values are escaped with escapingString algorithm in attribute mode +// (https://html.spec.whatwg.org/multipage/syntax.html#escapingString). +function startTag(qualifiedName, attributes = {}) { + return Object.entries(attributes).reduce(function (prev, [attr, value]) { + return prev + " " + attr + "=\"" + + value.replace(/&/g, "&") + .replace(/\u00a0/g, " ") + .replace(/"/g, """) + + "\""; + }, "<" + qualifiedName) + ">"; +} - let output = "<div id=\"error\">" + "error parsing"; - if (errorInfo.message) { - output += "<div class=\"errormessage\">" + errorInfo.message + "</div>"; - } +// Builds an HTML string that will be used to load stylesheets and scripts, +// and switch the parser to plaintext state. +function initialHTML(doc) { + let os; + let platform = Services.appinfo.OS; + if (platform.startsWith("WINNT")) { + os = "win"; + } else if (platform.startsWith("Darwin")) { + os = "mac"; + } else { + os = "linux"; + } - output += "</div><div id=\"json\">" + this.highlightError(data, - errorInfo.line, errorInfo.column) + "</div>"; + let base = doc.createElement("base"); + base.href = "resource://devtools/client/jsonview/"; + + let style = doc.createElement("link"); + style.rel = "stylesheet"; + style.type = "text/css"; + style.href = "css/main.css"; + + let script = doc.createElement("script"); + script.src = "lib/require.js"; + script.dataset.main = "viewer-config"; + script.defer = true; + + let head = doc.createElement("head"); + head.append(base, style, script); + + return "<!DOCTYPE html>\n" + + startTag("html", { + "platform": os, + "class": "theme-" + JsonViewUtils.getCurrentTheme(), + "dir": Services.locale.isAppLocaleRTL ? "rtl" : "ltr" + }) + + head.outerHTML + + startTag("body") + + startTag("div", {"id": "content"}) + + startTag("plaintext", {"id": "json"}); +} - return "<!DOCTYPE html>\n" + - "<html><head><title>" + this.htmlEncode(uri + " - Error") + "</title>" + - "<base href=\"" + this.htmlEncode(this.data.url()) + "\">" + - "</head><body>" + - output + - "</body></html>"; - }, +// Chrome <-> Content communication +function onContentMessage(e) { + // Do not handle events from different documents. + let win = this; + if (win != e.target) { + return; + } - // Chrome <-> Content communication + let value = e.detail.value; + switch (e.detail.type) { + case "copy": + copyString(win, value); + break; - onContentMessage: function (e) { - // Do not handle events from different documents. - let win = NetworkHelper.getWindowForRequest(this.channel); - if (win != e.target) { - return; - } + case "copy-headers": + copyHeaders(win, value); + break; - let value = e.detail.value; - switch (e.detail.type) { - case "copy": - Clipboard.set(value, "text"); - break; + case "save": + childProcessMessageManager.sendAsyncMessage( + "devtools:jsonview:save", value); + } +} - case "copy-headers": - this.copyHeaders(value); - break; +function copyHeaders(win, headers) { + let value = ""; + let eol = (Services.appinfo.OS !== "WINNT") ? "\n" : "\r\n"; - case "save": - childProcessMessageManager.sendAsyncMessage( - "devtools:jsonview:save", value); - } - }, + let responseHeaders = headers.response; + for (let i = 0; i < responseHeaders.length; i++) { + let header = responseHeaders[i]; + value += header.name + ": " + header.value + eol; + } - copyHeaders: function (headers) { - let value = ""; - let eol = (Services.appinfo.OS !== "WINNT") ? "\n" : "\r\n"; + value += eol; - let responseHeaders = headers.response; - for (let i = 0; i < responseHeaders.length; i++) { - let header = responseHeaders[i]; - value += header.name + ": " + header.value + eol; - } + let requestHeaders = headers.request; + for (let i = 0; i < requestHeaders.length; i++) { + let header = requestHeaders[i]; + value += header.name + ": " + header.value + eol; + } - value += eol; + copyString(win, value); +} - let requestHeaders = headers.request; - for (let i = 0; i < requestHeaders.length; i++) { - let header = requestHeaders[i]; - value += header.name + ": " + header.value + eol; - } +function copyString(win, string) { + win.document.addEventListener("copy", event => { + event.clipboardData.setData("text/plain", string); + event.preventDefault(); + }, {once: true}); - Clipboard.set(value, "text"); - } -}); + win.document.execCommand("copy", false, null); +} // Stream converter component definition let service = xpcom.Service({ diff --git a/devtools/client/jsonview/css/general.css b/devtools/client/jsonview/css/general.css index 0c68d65e7..d80720f4f 100644 --- a/devtools/client/jsonview/css/general.css +++ b/devtools/client/jsonview/css/general.css @@ -28,9 +28,9 @@ pre { font-family: var(--monospace-font-family); } -#json, -#headers { +#json { display: none; + white-space: pre-wrap; } /******************************************************************************/ diff --git a/devtools/client/jsonview/css/main.css b/devtools/client/jsonview/css/main.css index 04f3cb87c..c75d7cea0 100644 --- a/devtools/client/jsonview/css/main.css +++ b/devtools/client/jsonview/css/main.css @@ -3,7 +3,9 @@ * 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/. */ -@import "resource://devtools/client/shared/components/reps/reps.css"; +@import "resource://devtools/client/themes/variables.css"; +@import "resource://devtools/client/themes/common.css"; +@import "resource://devtools/client/themes/toolbars.css"; @import "resource://devtools/client/shared/components/tree/tree-view.css"; @import "resource://devtools/client/shared/components/tabs/tabs.css"; diff --git a/devtools/client/jsonview/json-viewer.js b/devtools/client/jsonview/json-viewer.js index d96081da2..38cb6d7ec 100644 --- a/devtools/client/jsonview/json-viewer.js +++ b/devtools/client/jsonview/json-viewer.js @@ -12,28 +12,28 @@ define(function (require, exports, module) { const { MainTabbedArea } = createFactories(require("./components/main-tabbed-area")); const json = document.getElementById("json"); - const headers = document.getElementById("headers"); - - let jsonData; - - try { - jsonData = JSON.parse(json.textContent); - } catch (err) { - jsonData = err + ""; - } // Application state object. let input = { jsonText: json.textContent, jsonPretty: null, - json: jsonData, - headers: JSON.parse(headers.textContent), + headers: window.headers, tabActive: 0, prettified: false }; + // Remove BOM, if present. + if (input.jsonText.startsWith("\ufeff")) { + input.jsonText = input.jsonText.slice(1); + } + + try { + input.json = JSON.parse(input.jsonText); + } catch (err) { + input.json = err; + } + json.remove(); - headers.remove(); /** * Application actions/commands. This list implements all commands @@ -61,7 +61,7 @@ define(function (require, exports, module) { theApp.setState({jsonText: input.jsonText}); } else { if (!input.jsonPretty) { - input.jsonPretty = JSON.stringify(jsonData, null, " "); + input.jsonPretty = JSON.stringify(input.json, null, " "); } theApp.setState({jsonText: input.jsonPretty}); } diff --git a/devtools/client/jsonview/utils.js b/devtools/client/jsonview/utils.js index a70afdc68..6ab697c89 100644 --- a/devtools/client/jsonview/utils.js +++ b/devtools/client/jsonview/utils.js @@ -96,6 +96,8 @@ exports.exportIntoContentScope = function (win, obj, defineAs) { Cu.exportFunction(propValue, clone, { defineAs: propName }); + } else { + clone[propName] = Cu.cloneInto(propValue, win); } } }; diff --git a/devtools/client/locales/en-US/menus.properties b/devtools/client/locales/en-US/menus.properties index 66e158cbd..7030fe17d 100644 --- a/devtools/client/locales/en-US/menus.properties +++ b/devtools/client/locales/en-US/menus.properties @@ -54,11 +54,6 @@ devToolbarMenu.accesskey = v devToolbarMenu.key = VK_F2 devToolbarMenu.keytext = F2 -webide.label = WebIDE -webide.accesskey = W -webide.key = VK_F8 -webide.keytext = F8 - devToolboxMenuItem.label = Toggle Tools devToolboxMenuItem.accesskey = T devToolboxMenuItem.key = I diff --git a/devtools/client/locales/en-US/webide.dtd b/devtools/client/locales/en-US/webide.dtd deleted file mode 100644 index 554488f6d..000000000 --- a/devtools/client/locales/en-US/webide.dtd +++ /dev/null @@ -1,222 +0,0 @@ -<!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - -<!ENTITY % brandDTD - SYSTEM "chrome://branding/locale/brand.dtd"> - %brandDTD; - -<!ENTITY windowTitle "&brandShortName; WebIDE"> - -<!ENTITY projectMenu_label "Project"> -<!ENTITY projectMenu_accesskey "P"> -<!ENTITY projectMenu_newApp_label "New App…"> -<!ENTITY projectMenu_newApp_accesskey "N"> -<!ENTITY projectMenu_importPackagedApp_label "Open Packaged App…"> -<!ENTITY projectMenu_importPackagedApp_accesskey "P"> -<!ENTITY projectMenu_importHostedApp_label "Open Hosted App…"> -<!ENTITY projectMenu_importHostedApp_accesskey "H"> -<!ENTITY projectMenu_selectApp_label "Open App…"> -<!ENTITY projectMenu_selectApp_accesskey "O"> -<!ENTITY projectMenu_play_label "Install and Run"> -<!ENTITY projectMenu_play_accesskey "I"> -<!ENTITY projectMenu_stop_label "Stop App"> -<!ENTITY projectMenu_stop_accesskey "S"> -<!ENTITY projectMenu_debug_label "Debug App"> -<!ENTITY projectMenu_debug_accesskey "D"> -<!ENTITY projectMenu_remove_label "Remove Project"> -<!ENTITY projectMenu_remove_accesskey "R"> -<!ENTITY projectMenu_showPrefs_label "Preferences"> -<!ENTITY projectMenu_showPrefs_accesskey "e"> -<!ENTITY projectMenu_manageComponents_label "Manage Extra Components"> -<!ENTITY projectMenu_manageComponents_accesskey "M"> -<!ENTITY projectMenu_refreshTabs_label "Refresh Tabs"> - -<!ENTITY runtimeMenu_label "Runtime"> -<!ENTITY runtimeMenu_accesskey "R"> -<!ENTITY runtimeMenu_disconnect_label "Disconnect"> -<!ENTITY runtimeMenu_disconnect_accesskey "D"> -<!ENTITY runtimeMenu_showPermissionTable_label "Permissions Table"> -<!ENTITY runtimeMenu_showPermissionTable_accesskey "P"> -<!ENTITY runtimeMenu_takeScreenshot_label "Screenshot"> -<!ENTITY runtimeMenu_takeScreenshot_accesskey "S"> -<!ENTITY runtimeMenu_showDetails_label "Runtime Info"> -<!ENTITY runtimeMenu_showDetails_accesskey "E"> -<!ENTITY runtimeMenu_showMonitor_label "Monitor"> -<!ENTITY runtimeMenu_showMonitor_accesskey "M"> -<!ENTITY runtimeMenu_showDevicePrefs_label "Device Preferences"> -<!ENTITY runtimeMenu_showDevicePrefs_accesskey "D"> -<!ENTITY runtimeMenu_showSettings_label "Device Settings"> -<!ENTITY runtimeMenu_showSettings_accesskey "s"> - -<!ENTITY viewMenu_label "View"> -<!ENTITY viewMenu_accesskey "V"> -<!ENTITY viewMenu_toggleEditor_label "Toggle Editor"> -<!ENTITY viewMenu_toggleEditor_accesskey "E"> -<!ENTITY viewMenu_zoomin_label "Zoom In"> -<!ENTITY viewMenu_zoomin_accesskey "I"> -<!ENTITY viewMenu_zoomout_label "Zoom Out"> -<!ENTITY viewMenu_zoomout_accesskey "O"> -<!ENTITY viewMenu_resetzoom_label "Reset Zoom"> -<!ENTITY viewMenu_resetzoom_accesskey "R"> - -<!ENTITY projectButton_label "Open App"> -<!ENTITY runtimeButton_label "Select Runtime"> - -<!-- We try to repicate browser' bindings: --> -<!-- quit app --> -<!ENTITY key_quit "W"> -<!-- open menu --> -<!ENTITY key_showProjectPanel "O"> -<!-- reload app --> -<!ENTITY key_play "R"> -<!-- show toolbox --> -<!ENTITY key_toggleToolbox "VK_F12"> -<!-- toggle sidebar --> -<!ENTITY key_toggleEditor "B"> -<!-- zoom --> -<!ENTITY key_zoomin "+"> -<!ENTITY key_zoomin2 "="> -<!ENTITY key_zoomout "-"> -<!ENTITY key_resetzoom "0"> - -<!ENTITY projectPanel_myProjects "My Projects"> -<!ENTITY projectPanel_runtimeApps "Runtime Apps"> -<!ENTITY projectPanel_tabs "Tabs"> -<!ENTITY runtimePanel_usb "USB Devices"> -<!ENTITY runtimePanel_wifi "Wi-Fi Devices"> -<!ENTITY runtimePanel_simulator "Simulators"> -<!ENTITY runtimePanel_other "Other"> -<!ENTITY runtimePanel_installsimulator "Install Simulator"> -<!ENTITY runtimePanel_noadbhelper "Install ADB Helper"> -<!ENTITY runtimePanel_nousbdevice "Can’t see your device?"> -<!ENTITY runtimePanel_refreshDevices_label "Refresh Devices"> - -<!-- Lense --> -<!ENTITY details_valid_header "valid"> -<!ENTITY details_warning_header "warnings"> -<!ENTITY details_error_header "errors"> -<!ENTITY details_description "Description"> -<!ENTITY details_location "Location"> -<!ENTITY details_manifestURL "App ID"> -<!ENTITY details_removeProject_button "Remove Project"> -<!ENTITY details_showPrepackageLog_button "Show Pre-package Log"> - -<!-- New App --> -<!ENTITY newAppWindowTitle "New App"> -<!ENTITY newAppHeader "Select template"> -<!ENTITY newAppLoadingTemplate "Loading templates…"> -<!ENTITY newAppProjectName "Project Name:"> - - -<!-- Decks --> - -<!ENTITY deck_close "Close"> - -<!-- Addons --> -<!ENTITY addons_title "Extra Components"> -<!ENTITY addons_aboutaddons "Open Add-ons Manager"> - -<!-- Prefs --> -<!ENTITY prefs_title "Preferences"> -<!ENTITY prefs_editor_title "Editor"> -<!ENTITY prefs_general_title "General"> -<!ENTITY prefs_restore "Restore Defaults"> -<!ENTITY prefs_manage_components "Manage Extra Components"> -<!ENTITY prefs_options_autoconnectruntime "Reconnect to previous runtime"> -<!ENTITY prefs_options_autoconnectruntime_tooltip "Reconnect to previous runtime when WebIDE starts"> -<!ENTITY prefs_options_rememberlastproject "Remember last project"> -<!ENTITY prefs_options_rememberlastproject_tooltip "Restore previous project when WebIDE starts"> -<!ENTITY prefs_options_templatesurl "Templates URL"> -<!ENTITY prefs_options_templatesurl_tooltip "Index of available templates"> -<!ENTITY prefs_options_showeditor "Show editor"> -<!ENTITY prefs_options_showeditor_tooltip "Show internal editor"> -<!ENTITY prefs_options_tabsize "Tab size"> -<!ENTITY prefs_options_expandtab "Soft tabs"> -<!ENTITY prefs_options_expandtab_tooltip "Use spaces instead of the tab character"> -<!ENTITY prefs_options_detectindentation "Autoindent"> -<!ENTITY prefs_options_detectindentation_tooltip "Guess indentation based on source content"> -<!ENTITY prefs_options_autocomplete "Autocomplete"> -<!ENTITY prefs_options_autocomplete_tooltip "Enable code autocompletion"> -<!ENTITY prefs_options_autoclosebrackets "Autoclose brackets"> -<!ENTITY prefs_options_autoclosebrackets_tooltip "Automatically insert closing brackets"> -<!ENTITY prefs_options_keybindings "Keybindings"> -<!ENTITY prefs_options_keybindings_default "Default"> -<!ENTITY prefs_options_autosavefiles "Autosave files"> -<!ENTITY prefs_options_autosavefiles_tooltip "Automatically save edited files before running project"> - -<!-- Permissions Table --> -<!ENTITY permissionstable_title "Permissions Table"> -<!ENTITY permissionstable_name_header "Name"> - -<!-- Runtime Details --> -<!ENTITY runtimedetails_title "Runtime Info"> -<!ENTITY runtimedetails_adbIsRoot "ADB is root: "> -<!ENTITY runtimedetails_summonADBRoot "root device"> -<!ENTITY runtimedetails_ADBRootWarning "(requires unlocked bootloader)"> -<!ENTITY runtimedetails_unrestrictedPrivileges "Unrestricted DevTools privileges: "> -<!ENTITY runtimedetails_requestPrivileges "request higher privileges"> -<!ENTITY runtimedetails_privilegesWarning "(Will reboot device. Requires root access.)"> - -<!-- Device Preferences and Settings --> -<!ENTITY device_typeboolean "Boolean"> -<!ENTITY device_typenumber "Integer"> -<!ENTITY device_typestring "String"> -<!ENTITY device_typeobject "Object"> -<!ENTITY device_typenone "Select a type"> - -<!-- Device Preferences --> -<!ENTITY devicepreference_title "Device Preferences"> -<!ENTITY devicepreference_search "Search preferences"> -<!ENTITY devicepreference_newname "New preference name"> -<!ENTITY devicepreference_newtext "Preference value"> -<!ENTITY devicepreference_addnew "Add new preference"> - -<!-- Device Settings --> -<!ENTITY devicesetting_title "Device Settings"> -<!ENTITY devicesetting_search "Search settings"> -<!ENTITY devicesetting_newname "New setting name"> -<!ENTITY devicesetting_newtext "Setting value"> -<!ENTITY devicesetting_addnew "Add new setting"> - -<!-- Monitor --> -<!ENTITY monitor_title "Monitor"> -<!ENTITY monitor_help "Help"> - -<!-- WiFi Authentication --> -<!-- LOCALIZATION NOTE (wifi_auth_header): The header displayed on the dialog - that instructs the user to transfer an authentication token to the - server. --> -<!ENTITY wifi_auth_header "Client Identification"> -<!-- LOCALIZATION NOTE (wifi_auth_scan_request): Instructions requesting the - user to transfer authentication info by scanning a QR code. --> -<!ENTITY wifi_auth_scan_request "The endpoint you are connecting to needs more information to authenticate this connection. Please scan the QR code below via the prompt on your other device."> -<!-- LOCALIZATION NOTE (wifi_auth_no_scanner): Link text to assist users with - devices that can't scan a QR code. --> -<!ENTITY wifi_auth_no_scanner "No QR scanner prompt?"> -<!-- LOCALIZATION NOTE (wifi_auth_yes_scanner): Link text to assist users with - devices that can scan a QR code. --> -<!ENTITY wifi_auth_yes_scanner "Have a QR scanner prompt?"> -<!-- LOCALIZATION NOTE (wifi_auth_token_request): Instructions requesting the - user to transfer authentication info by transferring a token. --> -<!ENTITY wifi_auth_token_request "If your other device asks for a token instead of scanning a QR code, please copy the value below to the other device:"> -<!ENTITY wifi_auth_qr_size_note "If the QR code appears too small for the connection to be successfully established, try zooming or enlarging the window."> - -<!-- Logs panel --> -<!ENTITY logs_title "Pre-packaging Command Logs"> - -<!-- Simulator Options --> -<!ENTITY simulator_title "Simulator Options"> -<!ENTITY simulator_remove "Delete Simulator"> -<!ENTITY simulator_reset "Restore Defaults"> -<!ENTITY simulator_name "Name"> -<!ENTITY simulator_software "Software"> -<!ENTITY simulator_version "Version"> -<!ENTITY simulator_profile "Profile"> -<!ENTITY simulator_hardware "Hardware"> -<!ENTITY simulator_device "Device"> -<!ENTITY simulator_screenSize "Screen"> -<!ENTITY simulator_pixelRatio "Pixel Ratio"> -<!ENTITY simulator_tv_data "TV Simulation"> -<!ENTITY simulator_tv_data_open "Config Data"> -<!ENTITY simulator_tv_data_open_button "Open Config Directory…"> diff --git a/devtools/client/locales/en-US/webide.properties b/devtools/client/locales/en-US/webide.properties deleted file mode 100644 index 154094906..000000000 --- a/devtools/client/locales/en-US/webide.properties +++ /dev/null @@ -1,92 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -title_noApp=WebIDE -title_app=WebIDE: %S - -runtimeButton_label=Select Runtime -projectButton_label=Open App - -mainProcess_label=Main Process - -local_runtime=Local Runtime -remote_runtime=Remote Runtime -remote_runtime_promptTitle=Remote Runtime -remote_runtime_promptMessage=hostname:port - -importPackagedApp_title=Select Directory -importHostedApp_title=Open Hosted App -importHostedApp_header=Enter Manifest URL - -selectCustomBinary_title=Select custom B2G binary -selectCustomProfile_title=Select custom Gaia profile - -notification_showTroubleShooting_label=Troubleshooting -notification_showTroubleShooting_accesskey=T - -# LOCALIZATION NOTE (project_tab_loading): This is shown as a temporary tab -# title for browser tab projects when the tab is still loading. -project_tab_loading=Loading… - -# These messages appear in a notification box when an error occur. - -error_cantInstallNotFullyConnected=Can’t install project. Not fully connected. -error_cantInstallValidationErrors=Can’t install project. Validation errors. -error_listRunningApps=Can’t get app list from device - -# Variable: name of the operation (in english) -error_operationTimeout=Operation timed out: %1$S -error_operationFail=Operation failed: %1$S - -# Variable: app name -error_cantConnectToApp=Can’t connect to app: %1$S - -# Variable: error message (in english) -error_cantFetchAddonsJSON=Can’t fetch the add-on list: %S - -error_appProjectsLoadFailed=Unable to load project list. This can occur if you’ve used this profile with a newer version of the browser. -error_folderCreationFailed=Unable to create project folder in the selected directory. - -# Variable: runtime app build ID (looks like this %Y%M%D format) and firefox build ID (same format) -error_runtimeVersionTooRecent=The connected runtime has a more recent build date (%1$S) than your desktop browser (%2$S) does. This is an unsupported setup and may cause DevTools to fail. Please update the browser. - -addons_stable=stable -addons_unstable=unstable -# LOCALIZATION NOTE (addons_simulator_label): This label is shown as the name of -# a given simulator version in the "Manage Simulators" pane. %1$S: Firefox OS -# version in the simulator, ex. 1.3. %2$S: Simulator stability label, ex. -# "stable" or "unstable". -addons_simulator_label=Firefox OS %1$S Simulator (%2$S) -addons_install_button=install -addons_uninstall_button=uninstall -addons_adb_label=ADB Helper Add-on -addons_adapters_label=Tools Adapters Add-on -addons_adb_warning=USB devices won’t be detected without this add-on -addons_status_unknown=? -addons_status_installed=Installed -addons_status_uninstalled=Not Installed -addons_status_preparing=preparing -addons_status_downloading=downloading -addons_status_installing=installing - -runtimedetails_checkno=no -runtimedetails_checkyes=yes -runtimedetails_checkunknown=unknown (requires ADB Helper 0.4.0 or later) -runtimedetails_notUSBDevice=Not a USB device - -# Validation status -status_tooltip=Validation status: %1$S -status_valid=VALID -status_warning=WARNINGS -status_error=ERRORS -status_unknown=UNKNOWN - -# Device preferences and settings -device_reset_default=Reset to default - -# Simulator options -simulator_custom_device=Custom -simulator_custom_binary=Custom B2G binary… -simulator_custom_profile=Custom Gaia profile… -simulator_default_profile=Use default diff --git a/devtools/client/menus.js b/devtools/client/menus.js index dbacb367d..23f024f04 100644 --- a/devtools/client/menus.js +++ b/devtools/client/menus.js @@ -86,17 +86,6 @@ exports.menuitems = [ }, checkbox: true }, - { id: "menu_webide", - l10nKey: "webide", - disabled: true, - oncommand() { - gDevToolsBrowser.openWebIDE(); - }, - key: { - id: "webide", - modifiers: "shift" - } - }, { id: "menu_browserToolbox", l10nKey: "browserToolboxMenu", disabled: true, diff --git a/devtools/client/moz.build b/devtools/client/moz.build index b55aa5380..9699ec726 100644 --- a/devtools/client/moz.build +++ b/devtools/client/moz.build @@ -34,7 +34,6 @@ DIRS += [ 'themes', 'webaudioeditor', 'webconsole', - 'webide', ] # Shim old theme paths used by DevTools add-ons diff --git a/devtools/client/preferences/devtools.js b/devtools/client/preferences/devtools.js index 2f6ca2104..e817b3a18 100644 --- a/devtools/client/preferences/devtools.js +++ b/devtools/client/preferences/devtools.js @@ -21,9 +21,6 @@ pref("devtools.loader.hotreload", false); pref("devtools.toolbar.enabled", true); pref("devtools.toolbar.visible", false); -// Enable DevTools WebIDE by default -pref("devtools.webide.enabled", true); - // Toolbox preferences pref("devtools.toolbox.footer.height", 250); pref("devtools.toolbox.sidebar.width", 500); @@ -234,11 +231,7 @@ pref("devtools.dom.enabled", false); pref("devtools.webaudioeditor.inspectorWidth", 300); // Default theme ("dark" or "light") -#ifdef MOZ_DEV_EDITION -sticky_pref("devtools.theme", "dark"); -#else sticky_pref("devtools.theme", "light"); -#endif // Web console filters pref("devtools.webconsole.filter.error", true); @@ -356,13 +349,8 @@ pref("devtools.editor.autocomplete", true); // version for each user. pref("devtools.telemetry.tools.opened.version", "{}"); -// Enable the JSON View tool (an inspector for application/json documents) on -// Nightly and Dev. Edition. -#ifdef RELEASE_OR_BETA -pref("devtools.jsonview.enabled", false); -#else +// Enable the JSON View tool (an inspector for application/json documents) pref("devtools.jsonview.enabled", true); -#endif // Enable the HTML responsive design mode for all channels. pref("devtools.responsive.html.enabled", true); diff --git a/devtools/client/projecteditor/lib/plugins/app-manager/app-project-editor.js b/devtools/client/projecteditor/lib/plugins/app-manager/app-project-editor.js deleted file mode 100644 index 9a66770b0..000000000 --- a/devtools/client/projecteditor/lib/plugins/app-manager/app-project-editor.js +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ -/* 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 { Cu } = require("chrome"); -const { Class } = require("sdk/core/heritage"); -const promise = require("promise"); -const { ItchEditor } = require("devtools/client/projecteditor/lib/editors"); - -var AppProjectEditor = Class({ - extends: ItchEditor, - - hidesToolbar: true, - - initialize: function (host) { - ItchEditor.prototype.initialize.apply(this, arguments); - this.appended = promise.resolve(); - this.host = host; - this.label = "app-manager"; - }, - - destroy: function () { - this.elt.remove(); - this.elt = null; - }, - - load: function (resource) { - let {appManagerOpts} = this.host.project; - - // Only load the frame the first time it is selected - if (!this.iframe || this.iframe.getAttribute("src") !== appManagerOpts.projectOverviewURL) { - - this.elt.textContent = ""; - let iframe = this.iframe = this.elt.ownerDocument.createElement("iframe"); - let iframeLoaded = this.iframeLoaded = promise.defer(); - - iframe.addEventListener("load", function onLoad() { - iframe.removeEventListener("load", onLoad); - iframeLoaded.resolve(); - }); - - iframe.setAttribute("flex", "1"); - iframe.setAttribute("src", appManagerOpts.projectOverviewURL); - this.elt.appendChild(iframe); - - } - - promise.all([this.iframeLoaded.promise, this.appended]).then(() => { - this.emit("load"); - }); - } -}); - -exports.AppProjectEditor = AppProjectEditor; diff --git a/devtools/client/projecteditor/lib/plugins/app-manager/moz.build b/devtools/client/projecteditor/lib/plugins/app-manager/moz.build deleted file mode 100644 index 8aae52725..000000000 --- a/devtools/client/projecteditor/lib/plugins/app-manager/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -DevToolsModules( - 'app-project-editor.js', - 'plugin.js', -) diff --git a/devtools/client/projecteditor/lib/plugins/app-manager/plugin.js b/devtools/client/projecteditor/lib/plugins/app-manager/plugin.js deleted file mode 100644 index 82bbab34b..000000000 --- a/devtools/client/projecteditor/lib/plugins/app-manager/plugin.js +++ /dev/null @@ -1,77 +0,0 @@ -const { Cu } = require("chrome"); -const { Class } = require("sdk/core/heritage"); -const { EventTarget } = require("sdk/event/target"); -const { emit } = require("sdk/event/core"); -const promise = require("promise"); -var { registerPlugin, Plugin } = require("devtools/client/projecteditor/lib/plugins/core"); -const { AppProjectEditor } = require("./app-project-editor"); -const OPTION_URL = "chrome://devtools/skin/images/tool-options.svg"; -const Services = require("Services"); -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -var AppManagerRenderer = Class({ - extends: Plugin, - - isAppManagerProject: function () { - return !!this.host.project.appManagerOpts; - }, - editorForResource: function (resource) { - if (!resource.parent && this.isAppManagerProject()) { - return AppProjectEditor; - } - }, - getUI: function (parent) { - let doc = parent.ownerDocument; - if (parent.childElementCount == 0) { - let image = doc.createElement("image"); - let optionImage = doc.createElement("image"); - let flexElement = doc.createElement("div"); - let nameLabel = doc.createElement("span"); - let statusElement = doc.createElement("div"); - - image.className = "project-image"; - optionImage.className = "project-options"; - optionImage.setAttribute("src", OPTION_URL); - nameLabel.className = "project-name-label"; - statusElement.className = "project-status"; - flexElement.className = "project-flex"; - - parent.appendChild(image); - parent.appendChild(nameLabel); - parent.appendChild(flexElement); - parent.appendChild(statusElement); - parent.appendChild(optionImage); - } - - return { - image: parent.querySelector(".project-image"), - nameLabel: parent.querySelector(".project-name-label"), - statusElement: parent.querySelector(".project-status") - }; - }, - onAnnotate: function (resource, editor, elt) { - if (resource.parent || !this.isAppManagerProject()) { - return; - } - - let {appManagerOpts} = this.host.project; - let doc = elt.ownerDocument; - - let {image, nameLabel, statusElement} = this.getUI(elt); - let name = appManagerOpts.name || resource.basename; - let url = appManagerOpts.iconUrl || "icon-sample.png"; - let status = appManagerOpts.validationStatus || "unknown"; - let tooltip = Strings.formatStringFromName("status_tooltip", - [Strings.GetStringFromName("status_" + status)], 1); - - nameLabel.textContent = name; - image.setAttribute("src", url); - statusElement.setAttribute("status", status); - statusElement.setAttribute("tooltiptext", tooltip); - - return true; - } -}); - -exports.AppManagerRenderer = AppManagerRenderer; -registerPlugin(AppManagerRenderer); diff --git a/devtools/client/projecteditor/lib/plugins/moz.build b/devtools/client/projecteditor/lib/plugins/moz.build index 17bff7ce0..99d864e13 100644 --- a/devtools/client/projecteditor/lib/plugins/moz.build +++ b/devtools/client/projecteditor/lib/plugins/moz.build @@ -5,7 +5,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. DIRS += [ - 'app-manager', 'delete', 'dirty', 'image-view', diff --git a/devtools/client/projecteditor/lib/projecteditor.js b/devtools/client/projecteditor/lib/projecteditor.js index a3ef06249..27127b0a0 100644 --- a/devtools/client/projecteditor/lib/projecteditor.js +++ b/devtools/client/projecteditor/lib/projecteditor.js @@ -31,7 +31,6 @@ require("devtools/client/projecteditor/lib/plugins/new/new"); require("devtools/client/projecteditor/lib/plugins/rename/rename"); require("devtools/client/projecteditor/lib/plugins/save/save"); require("devtools/client/projecteditor/lib/plugins/image-view/plugin"); -require("devtools/client/projecteditor/lib/plugins/app-manager/plugin"); require("devtools/client/projecteditor/lib/plugins/status-bar/plugin"); // Uncomment to enable logging. diff --git a/devtools/client/shared/telemetry.js b/devtools/client/shared/telemetry.js index 38a21cef6..547b1c07f 100644 --- a/devtools/client/shared/telemetry.js +++ b/devtools/client/shared/telemetry.js @@ -177,23 +177,6 @@ Telemetry.prototype = { histogram: "DEVTOOLS_ABOUTDEBUGGING_OPENED_COUNT", timerHistogram: "DEVTOOLS_ABOUTDEBUGGING_TIME_ACTIVE_SECONDS" }, - webide: { - histogram: "DEVTOOLS_WEBIDE_OPENED_COUNT", - timerHistogram: "DEVTOOLS_WEBIDE_TIME_ACTIVE_SECONDS" - }, - webideProjectEditor: { - histogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_COUNT", - timerHistogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_TIME_ACTIVE_SECONDS" - }, - webideProjectEditorSave: { - histogram: "DEVTOOLS_WEBIDE_PROJECT_EDITOR_SAVE_COUNT", - }, - webideNewProject: { - histogram: "DEVTOOLS_WEBIDE_NEW_PROJECT_COUNT", - }, - webideImportProject: { - histogram: "DEVTOOLS_WEBIDE_IMPORT_PROJECT_COUNT", - }, custom: { histogram: "DEVTOOLS_CUSTOM_OPENED_COUNT", timerHistogram: "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS" diff --git a/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js b/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js index 992dc62cf..824bdb3fb 100644 --- a/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js +++ b/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js @@ -34,6 +34,7 @@ function EvaluationResult(props) { id: messageId, exceptionDocURL, frame, + notes, } = message; let messageBody; @@ -57,6 +58,7 @@ function EvaluationResult(props) { serviceContainer, exceptionDocURL, frame, + notes, }; return Message(childProps); } diff --git a/devtools/client/webconsole/new-console-output/components/message-types/page-error.js b/devtools/client/webconsole/new-console-output/components/message-types/page-error.js index 77ea75ff7..c68b850bd 100644 --- a/devtools/client/webconsole/new-console-output/components/message-types/page-error.js +++ b/devtools/client/webconsole/new-console-output/components/message-types/page-error.js @@ -44,6 +44,7 @@ function PageError(props) { stacktrace, frame, exceptionDocURL, + notes, } = message; const childProps = { @@ -62,6 +63,7 @@ function PageError(props) { stacktrace, serviceContainer, exceptionDocURL, + notes, }; return Message(childProps); } diff --git a/devtools/client/webconsole/new-console-output/components/message.js b/devtools/client/webconsole/new-console-output/components/message.js index f36bff7e4..1ffa4e12d 100644 --- a/devtools/client/webconsole/new-console-output/components/message.js +++ b/devtools/client/webconsole/new-console-output/components/message.js @@ -47,6 +47,10 @@ const Message = createClass({ onViewSourceInDebugger: PropTypes.func.isRequired, sourceMapService: PropTypes.any, }), + notes: PropTypes.arrayOf(PropTypes.shape({ + messageBody: PropTypes.string.isRequired, + frame: PropTypes.any, + })), }, getDefaultProps: function () { @@ -90,6 +94,7 @@ const Message = createClass({ serviceContainer, dispatch, exceptionDocURL, + notes, } = this.props; topLevelClasses.push("message", source, type, level); @@ -127,6 +132,29 @@ const Message = createClass({ }); } + let notesNodes; + if (notes) { + notesNodes = notes.map(note => dom.span( + { className: "message-flex-body error-note" }, + dom.span({ className: "message-body devtools-monospace" }, + "note: " + note.messageBody + ), + dom.span({ className: "message-location devtools-monospace" }, + note.frame ? FrameView({ + frame: note.frame, + onClick: serviceContainer + ? serviceContainer.onViewSourceInDebugger + : undefined, + showEmptyPathAsHost: true, + sourceMapService: serviceContainer + ? serviceContainer.sourceMapService + : undefined + }) : null + ))); + } else { + notesNodes = []; + } + const repeat = this.props.repeat ? MessageRepeat({repeat: this.props.repeat}) : null; // Configure the location. @@ -167,7 +195,8 @@ const Message = createClass({ repeat, location ), - attachment + attachment, + ...notesNodes ) ); } diff --git a/devtools/client/webconsole/new-console-output/selectors/messages.js b/devtools/client/webconsole/new-console-output/selectors/messages.js index c4b1aee28..e405be2f8 100644 --- a/devtools/client/webconsole/new-console-output/selectors/messages.js +++ b/devtools/client/webconsole/new-console-output/selectors/messages.js @@ -126,6 +126,15 @@ function matchSearchFilters(message, filters) { || (message.parameters !== null && message.parameters.join("").toLocaleLowerCase() .includes(text.toLocaleLowerCase())) + // Look for a match in notes. + || (Array.isArray(message.notes) && message.notes.some(note => + // Look for a match in location. + isTextInFrame(text, note.frame) + // Look for a match in messageBody. + || (note.messageBody !== null + && note.messageBody.toLocaleLowerCase() + .includes(text.toLocaleLowerCase())) + )) ); } diff --git a/devtools/client/webconsole/new-console-output/test/components/page-error.test.js b/devtools/client/webconsole/new-console-output/test/components/page-error.test.js index 93f3a9ea5..5bc5fe0f0 100644 --- a/devtools/client/webconsole/new-console-output/test/components/page-error.test.js +++ b/devtools/client/webconsole/new-console-output/test/components/page-error.test.js @@ -123,4 +123,118 @@ describe("PageError component:", () => { wrapper = render(PageError({ message, serviceContainer})); expect(wrapper.find(".indent").prop("style").width).toBe(`0`); }); + + it("has empty error notes", () => { + const message = stubPreparedMessages.get("ReferenceError: asdf is not defined"); + let wrapper = render(PageError({ message, serviceContainer })); + + const notes = wrapper.find(".error-note"); + + expect(notes.length).toBe(0); + }); + + it("can show an error note", () => { + const origMessage = stubPreparedMessages.get("ReferenceError: asdf is not defined"); + const message = origMessage.set("notes", [ + { + "messageBody": "test note", + "frame": { + "source": "http://example.com/test.js", + "line": 2, + "column": 6 + } + } + ]); + + let wrapper = render(PageError({ message, serviceContainer })); + + const notes = wrapper.find(".error-note"); + expect(notes.length).toBe(1); + + const note = notes.eq(0); + expect(note.find(".message-body").text()) + .toBe("note: test note"); + + // There should be the location. + const locationLink = note.find(`.message-location`); + expect(locationLink.length).toBe(1); + expect(locationLink.text()).toBe("test.js:2:6"); + }); + + it("can show multiple error notes", () => { + const origMessage = stubPreparedMessages.get("ReferenceError: asdf is not defined"); + const message = origMessage.set("notes", [ + { + "messageBody": "test note 1", + "frame": { + "source": "http://example.com/test1.js", + "line": 2, + "column": 6 + } + }, + { + "messageBody": "test note 2", + "frame": { + "source": "http://example.com/test2.js", + "line": 10, + "column": 18 + } + }, + { + "messageBody": "test note 3", + "frame": { + "source": "http://example.com/test3.js", + "line": 9, + "column": 4 + } + } + ]); + + let wrapper = render(PageError({ message, serviceContainer })); + + const notes = wrapper.find(".error-note"); + expect(notes.length).toBe(3); + + const note1 = notes.eq(0); + expect(note1.find(".message-body").text()) + .toBe("note: test note 1"); + + const locationLink1 = note1.find(`.message-location`); + expect(locationLink1.length).toBe(1); + expect(locationLink1.text()).toBe("test1.js:2:6"); + + const note2 = notes.eq(1); + expect(note2.find(".message-body").text()) + .toBe("note: test note 2"); + + const locationLink2 = note2.find(`.message-location`); + expect(locationLink2.length).toBe(1); + expect(locationLink2.text()).toBe("test2.js:10:18"); + + const note3 = notes.eq(2); + expect(note3.find(".message-body").text()) + .toBe("note: test note 3"); + + const locationLink3 = note3.find(`.message-location`); + expect(locationLink3.length).toBe(1); + expect(locationLink3.text()).toBe("test3.js:9:4"); + }); + + it("displays error notes", () => { + const message = stubPreparedMessages.get("SyntaxError: redeclaration of let a"); + + let wrapper = render(PageError({ message, serviceContainer })); + + const notes = wrapper.find(".error-note"); + expect(notes.length).toBe(1); + + const note = notes.eq(0); + expect(note.find(".message-body").text()) + .toBe("note: Previously declared at line 2, column 6"); + + // There should be the location. + const locationLink = note.find(`.message-location`); + expect(locationLink.length).toBe(1); + expect(locationLink.text()).toBe("test-console-api.html:2:6"); + }); }); diff --git a/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js index f79548e7b..f0f01a561 100644 --- a/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js +++ b/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/stub-snippets.js @@ -140,6 +140,10 @@ pageError.set("Reference Error", ` foo() `); +pageError.set("Redeclaration Error", ` + let a, a; +`); + module.exports = { consoleApi, evaluationResult, diff --git a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js index d9662c4fd..bec3abd70 100644 --- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js +++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/consoleApi.js @@ -11,8 +11,6 @@ const { ConsoleMessage, NetworkEventMessage } = require("devtools/client/webcons let stubPreparedMessages = new Map(); let stubPackets = new Map(); - - stubPreparedMessages.set("console.log('foobar', 'test')", new ConsoleMessage({ "id": "1", "allowRepeating": true, @@ -34,7 +32,8 @@ stubPreparedMessages.set("console.log('foobar', 'test')", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.log(undefined)", new ConsoleMessage({ @@ -50,7 +49,7 @@ stubPreparedMessages.set("console.log(undefined)", new ConsoleMessage({ } ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"undefined\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(undefined)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"undefined\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(undefined)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(undefined)", @@ -59,7 +58,8 @@ stubPreparedMessages.set("console.log(undefined)", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.warn('danger, will robinson!')", new ConsoleMessage({ @@ -73,7 +73,7 @@ stubPreparedMessages.set("console.warn('danger, will robinson!')", new ConsoleMe "danger, will robinson!" ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"warn\",\"level\":\"warn\",\"messageText\":null,\"parameters\":[\"danger, will robinson!\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.warn(%27danger%2C%20will%20robinson!%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"warn\",\"level\":\"warn\",\"messageText\":null,\"parameters\":[\"danger, will robinson!\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.warn(%27danger%2C%20will%20robinson!%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.warn(%27danger%2C%20will%20robinson!%27)", @@ -82,7 +82,8 @@ stubPreparedMessages.set("console.warn('danger, will robinson!')", new ConsoleMe }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.log(NaN)", new ConsoleMessage({ @@ -98,7 +99,7 @@ stubPreparedMessages.set("console.log(NaN)", new ConsoleMessage({ } ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"NaN\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(NaN)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"NaN\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(NaN)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(NaN)", @@ -107,7 +108,8 @@ stubPreparedMessages.set("console.log(NaN)", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.log(null)", new ConsoleMessage({ @@ -123,7 +125,7 @@ stubPreparedMessages.set("console.log(null)", new ConsoleMessage({ } ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"null\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(null)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"null\"}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(null)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(null)", @@ -132,7 +134,8 @@ stubPreparedMessages.set("console.log(null)", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.log('鼬')", new ConsoleMessage({ @@ -146,7 +149,7 @@ stubPreparedMessages.set("console.log('鼬')", new ConsoleMessage({ "鼬" ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"鼬\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%E9%BC%AC%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"鼬\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%E9%BC%AC%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%E9%BC%AC%27)", @@ -155,7 +158,8 @@ stubPreparedMessages.set("console.log('鼬')", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.clear()", new ConsoleMessage({ @@ -169,8 +173,7 @@ stubPreparedMessages.set("console.clear()", new ConsoleMessage({ "Console was cleared." ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"clear\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"Console was cleared.\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.clear()\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", - "stacktrace": null, + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"clear\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"Console was cleared.\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.clear()\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.clear()", "line": 1, @@ -178,7 +181,8 @@ stubPreparedMessages.set("console.clear()", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.count('bar')", new ConsoleMessage({ @@ -190,7 +194,7 @@ stubPreparedMessages.set("console.count('bar')", new ConsoleMessage({ "messageText": "bar: 1", "parameters": null, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"debug\",\"messageText\":\"bar: 1\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.count(%27bar%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"debug\",\"messageText\":\"bar: 1\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.count(%27bar%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.count(%27bar%27)", @@ -199,7 +203,8 @@ stubPreparedMessages.set("console.count('bar')", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.assert(false, {message: 'foobar'})", new ConsoleMessage({ @@ -234,7 +239,7 @@ stubPreparedMessages.set("console.assert(false, {message: 'foobar'})", new Conso } ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"assert\",\"level\":\"error\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn8.child1/obj31\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"message\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"foobar\"}},\"ownPropertiesLength\":1,\"safeGetterValues\":{}}}],\"repeatId\":null,\"stacktrace\":[{\"columnNumber\":27,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.assert(false%2C%20%7Bmessage%3A%20%27foobar%27%7D)\",\"functionName\":\"triggerPacket\",\"language\":2,\"lineNumber\":1}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.assert(false%2C%20%7Bmessage%3A%20%27foobar%27%7D)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"assert\",\"level\":\"error\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn8.child1/obj31\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"message\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":\"foobar\"}},\"ownPropertiesLength\":1,\"safeGetterValues\":{}}}],\"repeatId\":null,\"stacktrace\":[{\"columnNumber\":27,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.assert(false%2C%20%7Bmessage%3A%20%27foobar%27%7D)\",\"functionName\":\"triggerPacket\",\"language\":2,\"lineNumber\":1}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.assert(false%2C%20%7Bmessage%3A%20%27foobar%27%7D)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": [ { "columnNumber": 27, @@ -251,7 +256,8 @@ stubPreparedMessages.set("console.assert(false, {message: 'foobar'})", new Conso }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.log('hello \nfrom \rthe \"string world!')", new ConsoleMessage({ @@ -265,7 +271,7 @@ stubPreparedMessages.set("console.log('hello \nfrom \rthe \"string world!')", ne "hello \nfrom \rthe \"string world!" ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"hello \\nfrom \\rthe \\\"string world!\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27hello%20%5Cnfrom%20%5Crthe%20%5C%22string%20world!%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"hello \\nfrom \\rthe \\\"string world!\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27hello%20%5Cnfrom%20%5Crthe%20%5C%22string%20world!%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27hello%20%5Cnfrom%20%5Crthe%20%5C%22string%20world!%27)", @@ -274,7 +280,8 @@ stubPreparedMessages.set("console.log('hello \nfrom \rthe \"string world!')", ne }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.log('úṇĩçödê țĕșť')", new ConsoleMessage({ @@ -288,7 +295,7 @@ stubPreparedMessages.set("console.log('úṇĩçödê țĕșť')", new ConsoleMe "úṇĩçödê țĕșť" ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"úṇĩçödê țĕșť\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%C3%BA%E1%B9%87%C4%A9%C3%A7%C3%B6d%C3%AA%20%C8%9B%C4%95%C8%99%C5%A5%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"úṇĩçödê țĕșť\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%C3%BA%E1%B9%87%C4%A9%C3%A7%C3%B6d%C3%AA%20%C8%9B%C4%95%C8%99%C5%A5%27)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%27%C3%BA%E1%B9%87%C4%A9%C3%A7%C3%B6d%C3%AA%20%C8%9B%C4%95%C8%99%C5%A5%27)", @@ -297,7 +304,8 @@ stubPreparedMessages.set("console.log('úṇĩçödê țĕșť')", new ConsoleMe }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.dirxml(window)", new ConsoleMessage({ @@ -315,7 +323,7 @@ stubPreparedMessages.set("console.dirxml(window)", new ConsoleMessage({ "extensible": true, "frozen": false, "sealed": false, - "ownPropertyLength": 804, + "ownPropertyLength": 815, "preview": { "kind": "ObjectWithURL", "url": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html" @@ -323,7 +331,7 @@ stubPreparedMessages.set("console.dirxml(window)", new ConsoleMessage({ } ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn11.child1/obj31\",\"class\":\"Window\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":804,\"preview\":{\"kind\":\"ObjectWithURL\",\"url\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\"}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.dirxml(window)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn11.child1/obj31\",\"class\":\"Window\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":804,\"preview\":{\"kind\":\"ObjectWithURL\",\"url\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\"}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.dirxml(window)\",\"line\":1,\"column\":27},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.dirxml(window)", @@ -332,7 +340,8 @@ stubPreparedMessages.set("console.dirxml(window)", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.trace()", new ConsoleMessage({ @@ -344,7 +353,7 @@ stubPreparedMessages.set("console.trace()", new ConsoleMessage({ "messageText": null, "parameters": [], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"trace\",\"level\":\"log\",\"messageText\":null,\"parameters\":[],\"repeatId\":null,\"stacktrace\":[{\"columnNumber\":3,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"testStacktraceFiltering\",\"language\":2,\"lineNumber\":3},{\"columnNumber\":3,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"foo\",\"language\":2,\"lineNumber\":6},{\"columnNumber\":1,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"triggerPacket\",\"language\":2,\"lineNumber\":9}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"line\":3,\"column\":3},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"trace\",\"level\":\"log\",\"messageText\":null,\"parameters\":[],\"repeatId\":null,\"stacktrace\":[{\"columnNumber\":3,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"testStacktraceFiltering\",\"language\":2,\"lineNumber\":3},{\"columnNumber\":3,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"foo\",\"language\":2,\"lineNumber\":6},{\"columnNumber\":1,\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"functionName\":\"triggerPacket\",\"language\":2,\"lineNumber\":9}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.trace()\",\"line\":3,\"column\":3},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": [ { "columnNumber": 3, @@ -375,7 +384,8 @@ stubPreparedMessages.set("console.trace()", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.time('bar')", new ConsoleMessage({ @@ -387,7 +397,7 @@ stubPreparedMessages.set("console.time('bar')", new ConsoleMessage({ "messageText": null, "parameters": null, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"nullMessage\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"nullMessage\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)", @@ -396,7 +406,8 @@ stubPreparedMessages.set("console.time('bar')", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.timeEnd('bar')", new ConsoleMessage({ @@ -408,7 +419,7 @@ stubPreparedMessages.set("console.timeEnd('bar')", new ConsoleMessage({ "messageText": "bar: 1.36ms", "parameters": null, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"timeEnd\",\"level\":\"log\",\"messageText\":\"bar: 1.36ms\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"timeEnd\",\"level\":\"log\",\"messageText\":\"bar: 1.36ms\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.time(%27bar%27)", @@ -417,7 +428,8 @@ stubPreparedMessages.set("console.timeEnd('bar')", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.table('bar')", new ConsoleMessage({ @@ -431,7 +443,7 @@ stubPreparedMessages.set("console.table('bar')", new ConsoleMessage({ "bar" ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%27bar%27)", @@ -440,7 +452,8 @@ stubPreparedMessages.set("console.table('bar')", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.table(['a', 'b', 'c'])", new ConsoleMessage({ @@ -471,7 +484,7 @@ stubPreparedMessages.set("console.table(['a', 'b', 'c'])", new ConsoleMessage({ } ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"table\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn15.child1/obj31\",\"class\":\"Array\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":4,\"preview\":{\"kind\":\"ArrayLike\",\"length\":3,\"items\":[\"a\",\"b\",\"c\"]}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%5B%27a%27%2C%20%27b%27%2C%20%27c%27%5D)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"table\",\"level\":\"log\",\"messageText\":null,\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn15.child1/obj31\",\"class\":\"Array\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":4,\"preview\":{\"kind\":\"ArrayLike\",\"length\":3,\"items\":[\"a\",\"b\",\"c\"]}}],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%5B%27a%27%2C%20%27b%27%2C%20%27c%27%5D)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.table(%5B%27a%27%2C%20%27b%27%2C%20%27c%27%5D)", @@ -480,7 +493,8 @@ stubPreparedMessages.set("console.table(['a', 'b', 'c'])", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.group('bar')", new ConsoleMessage({ @@ -492,7 +506,7 @@ stubPreparedMessages.set("console.group('bar')", new ConsoleMessage({ "messageText": "bar", "parameters": null, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":\"bar\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":\"bar\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)", @@ -501,7 +515,8 @@ stubPreparedMessages.set("console.group('bar')", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.groupEnd('bar')", new ConsoleMessage({ @@ -513,7 +528,7 @@ stubPreparedMessages.set("console.groupEnd('bar')", new ConsoleMessage({ "messageText": null, "parameters": null, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group(%27bar%27)", @@ -522,7 +537,8 @@ stubPreparedMessages.set("console.groupEnd('bar')", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.groupCollapsed('foo')", new ConsoleMessage({ @@ -534,7 +550,7 @@ stubPreparedMessages.set("console.groupCollapsed('foo')", new ConsoleMessage({ "messageText": "foo", "parameters": null, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroupCollapsed\",\"level\":\"log\",\"messageText\":\"foo\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroupCollapsed\",\"level\":\"log\",\"messageText\":\"foo\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)", @@ -543,7 +559,8 @@ stubPreparedMessages.set("console.groupCollapsed('foo')", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.groupEnd('foo')", new ConsoleMessage({ @@ -555,7 +572,7 @@ stubPreparedMessages.set("console.groupEnd('foo')", new ConsoleMessage({ "messageText": null, "parameters": null, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.groupCollapsed(%27foo%27)", @@ -564,7 +581,8 @@ stubPreparedMessages.set("console.groupEnd('foo')", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.group()", new ConsoleMessage({ @@ -576,7 +594,7 @@ stubPreparedMessages.set("console.group()", new ConsoleMessage({ "messageText": "<no group label>", "parameters": null, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":\"<no group label>\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"startGroup\",\"level\":\"log\",\"messageText\":\"<no group label>\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()", @@ -585,7 +603,8 @@ stubPreparedMessages.set("console.group()", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.groupEnd()", new ConsoleMessage({ @@ -597,7 +616,7 @@ stubPreparedMessages.set("console.groupEnd()", new ConsoleMessage({ "messageText": null, "parameters": null, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"endGroup\",\"level\":\"log\",\"messageText\":null,\"parameters\":null,\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()\",\"line\":3,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.group()", @@ -606,7 +625,8 @@ stubPreparedMessages.set("console.groupEnd()", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": null, - "userProvidedStyles": [] + "userProvidedStyles": [], + "notes": null })); stubPreparedMessages.set("console.log(%cfoobar)", new ConsoleMessage({ @@ -621,7 +641,7 @@ stubPreparedMessages.set("console.log(%cfoobar)", new ConsoleMessage({ "bar" ], "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%25cfoobar)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"]}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"console-api\",\"type\":\"log\",\"level\":\"log\",\"messageText\":null,\"parameters\":[\"foo\",\"bar\"],\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%25cfoobar)\",\"line\":2,\"column\":1},\"groupId\":null,\"exceptionDocURL\":null,\"userProvidedStyles\":[\"color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px\",\"color:red;background:url('http://example.com/test')\"],\"notes\":null}", "stacktrace": null, "frame": { "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=console.log(%25cfoobar)", @@ -633,10 +653,10 @@ stubPreparedMessages.set("console.log(%cfoobar)", new ConsoleMessage({ "userProvidedStyles": [ "color:blue;font-size:1.3em;background:url('http://example.com/test');position:absolute;top:10px", "color:red;background:url('http://example.com/test')" - ] + ], + "notes": null })); - stubPackets.set("console.log('foobar', 'test')", { "from": "server1.conn0.child1/consoleActor2", "type": "consoleAPICall", @@ -1017,7 +1037,7 @@ stubPackets.set("console.dirxml(window)", { "extensible": true, "frozen": false, "sealed": false, - "ownPropertyLength": 804, + "ownPropertyLength": 815, "preview": { "kind": "ObjectWithURL", "url": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html" @@ -1451,8 +1471,7 @@ stubPackets.set("console.log(%cfoobar)", { } }); - module.exports = { stubPreparedMessages, stubPackets, -}
\ No newline at end of file +}; diff --git a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/evaluationResult.js b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/evaluationResult.js index 098086044..0682d9134 100644 --- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/evaluationResult.js +++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/evaluationResult.js @@ -11,8 +11,6 @@ const { ConsoleMessage, NetworkEventMessage } = require("devtools/client/webcons let stubPreparedMessages = new Map(); let stubPackets = new Map(); - - stubPreparedMessages.set("new Date(0)", new ConsoleMessage({ "id": "1", "allowRepeating": true, @@ -32,11 +30,12 @@ stubPreparedMessages.set("new Date(0)", new ConsoleMessage({ } }, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"log\",\"parameters\":{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj30\",\"class\":\"Date\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"timestamp\":0}},\"repeatId\":null,\"stacktrace\":null,\"frame\":null,\"groupId\":null,\"userProvidedStyles\":null}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"log\",\"parameters\":{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj30\",\"class\":\"Date\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"timestamp\":0}},\"repeatId\":null,\"stacktrace\":null,\"frame\":null,\"groupId\":null,\"userProvidedStyles\":null,\"notes\":null}", "stacktrace": null, "frame": null, "groupId": null, - "userProvidedStyles": null + "userProvidedStyles": null, + "notes": null })); stubPreparedMessages.set("asdf()", new ConsoleMessage({ @@ -50,7 +49,7 @@ stubPreparedMessages.set("asdf()", new ConsoleMessage({ "type": "undefined" }, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":1},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\",\"userProvidedStyles\":null}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":1},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\",\"userProvidedStyles\":null,\"notes\":null}", "stacktrace": null, "frame": { "source": "debugger eval code", @@ -59,7 +58,8 @@ stubPreparedMessages.set("asdf()", new ConsoleMessage({ }, "groupId": null, "exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default", - "userProvidedStyles": null + "userProvidedStyles": null, + "notes": null })); stubPreparedMessages.set("1 + @", new ConsoleMessage({ @@ -73,7 +73,7 @@ stubPreparedMessages.set("1 + @", new ConsoleMessage({ "type": "undefined" }, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"error\",\"messageText\":\"SyntaxError: illegal character\",\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":4},\"groupId\":null,\"userProvidedStyles\":null}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"result\",\"level\":\"error\",\"messageText\":\"SyntaxError: illegal character\",\"parameters\":{\"type\":\"undefined\"},\"repeatId\":null,\"stacktrace\":null,\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":4},\"groupId\":null,\"userProvidedStyles\":null,\"notes\":null}", "stacktrace": null, "frame": { "source": "debugger eval code", @@ -81,10 +81,10 @@ stubPreparedMessages.set("1 + @", new ConsoleMessage({ "column": 4 }, "groupId": null, - "userProvidedStyles": null + "userProvidedStyles": null, + "notes": null })); - stubPackets.set("new Date(0)", { "from": "server1.conn0.child1/consoleActor2", "input": "new Date(0)", @@ -103,7 +103,8 @@ stubPackets.set("new Date(0)", { "timestamp": 1476573073424, "exception": null, "frame": null, - "helperResult": null + "helperResult": null, + "notes": null }); stubPackets.set("asdf()", { @@ -138,7 +139,8 @@ stubPackets.set("asdf()", { "line": 1, "column": 1 }, - "helperResult": null + "helperResult": null, + "notes": null }); stubPackets.set("1 + @", { @@ -172,11 +174,11 @@ stubPackets.set("1 + @", { "line": 1, "column": 4 }, - "helperResult": null + "helperResult": null, + "notes": null }); - module.exports = { stubPreparedMessages, stubPackets, -}
\ No newline at end of file +}; diff --git a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js index eda8e8b83..80147e7dd 100644 --- a/devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js +++ b/devtools/client/webconsole/new-console-output/test/fixtures/stubs/pageError.js @@ -11,8 +11,6 @@ const { ConsoleMessage, NetworkEventMessage } = require("devtools/client/webcons let stubPreparedMessages = new Map(); let stubPackets = new Map(); - - stubPreparedMessages.set("ReferenceError: asdf is not defined", new ConsoleMessage({ "id": "1", "allowRepeating": true, @@ -22,7 +20,7 @@ stubPreparedMessages.set("ReferenceError: asdf is not defined", new ConsoleMessa "messageText": "ReferenceError: asdf is not defined", "parameters": null, "repeat": 1, - "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"log\",\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":[{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":3,\"columnNumber\":5,\"functionName\":\"bar\"},{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":6,\"columnNumber\":5,\"functionName\":\"foo\"},{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":9,\"columnNumber\":3,\"functionName\":null}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"line\":3,\"column\":5},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\"}", + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"log\",\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":[{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":3,\"columnNumber\":5,\"functionName\":\"bar\"},{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":6,\"columnNumber\":5,\"functionName\":\"foo\"},{\"filename\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"lineNumber\":9,\"columnNumber\":3,\"functionName\":null}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error\",\"line\":3,\"column\":5},\"groupId\":null,\"exceptionDocURL\":\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default\",\"userProvidedStyles\":null,\"notes\":null}", "stacktrace": [ { "filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-tempfile.js?key=Reference%20Error", @@ -49,9 +47,53 @@ stubPreparedMessages.set("ReferenceError: asdf is not defined", new ConsoleMessa "column": 5 }, "groupId": null, - "exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default" + "exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default", + "userProvidedStyles": null, + "notes": null })); +stubPreparedMessages.set("SyntaxError: redeclaration of let a", new ConsoleMessage({ + "id": "1", + "allowRepeating": true, + "source": "javascript", + "type": "log", + "level": "error", + "messageText": "SyntaxError: redeclaration of let a", + "parameters": null, + "repeat": 1, + "repeatId": "{\"id\":null,\"allowRepeating\":true,\"source\":\"javascript\",\"type\":\"log\",\"level\":\"error\",\"messageText\":\"SyntaxError: redeclaration of let a\",\"parameters\":null,\"repeatId\":null,\"stacktrace\":[{\"filename\":\"chrome://mochikit/content/tests/BrowserTestUtils/content-task.js line 52 > eval\",\"lineNumber\":6,\"columnNumber\":9,\"functionName\":null},{\"filename\":\"chrome://mochikit/content/tests/BrowserTestUtils/content-task.js\",\"lineNumber\":53,\"columnNumber\":20,\"functionName\":null}],\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":9},\"groupId\":null,\"userProvidedStyles\":null,\"notes\":[{\"messageBody\":\"Previously declared at line 2, column 6\",\"frame\":{\"source\":\"http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html\",\"line\":2,\"column\":6}}]}", + "stacktrace": [ + { + "filename": "chrome://mochikit/content/tests/BrowserTestUtils/content-task.js line 52 > eval", + "lineNumber": 6, + "columnNumber": 9, + "functionName": null + }, + { + "filename": "chrome://mochikit/content/tests/BrowserTestUtils/content-task.js", + "lineNumber": 53, + "columnNumber": 20, + "functionName": null + } + ], + "frame": { + "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html", + "line": 2, + "column": 9 + }, + "groupId": null, + "userProvidedStyles": null, + "notes": [ + { + "messageBody": "Previously declared at line 2, column 6", + "frame": { + "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html", + "line": 2, + "column": 6 + } + } + ] +})); stubPackets.set("ReferenceError: asdf is not defined", { "from": "server1.conn0.child1/consoleActor2", @@ -91,12 +133,56 @@ stubPackets.set("ReferenceError: asdf is not defined", { "columnNumber": 3, "functionName": null } - ] + ], + "notes": null } }); +stubPackets.set("SyntaxError: redeclaration of let a", { + "from": "server1.conn0.child1/consoleActor2", + "type": "pageError", + "pageError": { + "errorMessage": "SyntaxError: redeclaration of let a", + "errorMessageName": "JSMSG_REDECLARED_VAR", + "sourceName": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html", + "lineText": " let a, a;\n", + "lineNumber": 2, + "columnNumber": 9, + "category": "content javascript", + "warning": false, + "error": false, + "exception": true, + "strict": false, + "info": false, + "private": false, + "stacktrace": [ + { + "filename": "chrome://mochikit/content/tests/BrowserTestUtils/content-task.js line 52 > eval", + "lineNumber": 6, + "columnNumber": 9, + "functionName": null + }, + { + "filename": "chrome://mochikit/content/tests/BrowserTestUtils/content-task.js", + "lineNumber": 53, + "columnNumber": 20, + "functionName": null + } + ], + "notes": [ + { + "messageBody": "Previously declared at line 2, column 6", + "frame": { + "source": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html", + "line": 2, + "column": 6 + } + } + ] + } +}); module.exports = { stubPreparedMessages, stubPackets, -}
\ No newline at end of file +}; diff --git a/devtools/client/webconsole/new-console-output/types.js b/devtools/client/webconsole/new-console-output/types.js index 897ae5d3a..cb27aedab 100644 --- a/devtools/client/webconsole/new-console-output/types.js +++ b/devtools/client/webconsole/new-console-output/types.js @@ -38,6 +38,7 @@ exports.ConsoleMessage = Immutable.Record({ groupId: null, exceptionDocURL: null, userProvidedStyles: null, + notes: null, }); exports.NetworkEventMessage = Immutable.Record({ diff --git a/devtools/client/webconsole/new-console-output/utils/messages.js b/devtools/client/webconsole/new-console-output/utils/messages.js index f91209e9d..119bc7fba 100644 --- a/devtools/client/webconsole/new-console-output/utils/messages.js +++ b/devtools/client/webconsole/new-console-output/utils/messages.js @@ -165,6 +165,7 @@ function transformPacket(packet) { stacktrace: pageError.stacktrace ? pageError.stacktrace : null, frame, exceptionDocURL: pageError.exceptionDocURL, + notes: pageError.notes, }); } @@ -185,7 +186,8 @@ function transformPacket(packet) { exceptionMessage: messageText, exceptionDocURL, frame, - result: parameters + result: parameters, + notes, } = packet; const level = messageText ? MESSAGE_LEVEL.ERROR : MESSAGE_LEVEL.LOG; @@ -197,6 +199,7 @@ function transformPacket(packet) { parameters, exceptionDocURL, frame, + notes, }); } } diff --git a/devtools/client/webide/components/moz.build b/devtools/client/webide/components/moz.build deleted file mode 100644 index d4047c295..000000000 --- a/devtools/client/webide/components/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -EXTRA_COMPONENTS += [ - 'webideCli.js', - 'webideComponents.manifest', -] diff --git a/devtools/client/webide/components/webideCli.js b/devtools/client/webide/components/webideCli.js deleted file mode 100644 index 0f75da2c4..000000000 --- a/devtools/client/webide/components/webideCli.js +++ /dev/null @@ -1,58 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Ci = Components.interfaces; -const Cu = Components.utils; - -const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); - -XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); - -/** - * Handles --webide command line option. - */ - -function webideCli() { } - -webideCli.prototype = { - handle: function (cmdLine) { - if (!cmdLine.handleFlag("webide", false)) { - return; - } - - // If --webide is used remotely, we don't want to open - // a new tab. - // - // If --webide is used for a new Firefox instance, we - // want to open webide only. - cmdLine.preventDefault = true; - - let win = Services.wm.getMostRecentWindow("devtools:webide"); - if (win) { - win.focus(); - } else { - win = Services.ww.openWindow(null, - "chrome://webide/content/", - "webide", - "chrome,centerscreen,resizable,dialog=no", - null); - } - - if (cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH) { - // If this is a new Firefox instance, and because we will only start - // webide, we need to notify "sessionstore-windows-restored" to trigger - // addons registration (for simulators and adb helper). - Services.obs.notifyObservers(null, "sessionstore-windows-restored", ""); - } - }, - - helpInfo: "", - - classID: Components.ID("{79b7b44e-de5e-4e4c-b7a2-044003c615d9}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]), -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([webideCli]); diff --git a/devtools/client/webide/components/webideComponents.manifest b/devtools/client/webide/components/webideComponents.manifest deleted file mode 100644 index 03af9758c..000000000 --- a/devtools/client/webide/components/webideComponents.manifest +++ /dev/null @@ -1,4 +0,0 @@ -# webide components -component {79b7b44e-de5e-4e4c-b7a2-044003c615d9} webideCli.js -contract @mozilla.org/browser/webide-clh;1 {79b7b44e-de5e-4e4c-b7a2-044003c615d9} -category command-line-handler a-webide @mozilla.org/browser/webide-clh;1 diff --git a/devtools/client/webide/content/addons.js b/devtools/client/webide/content/addons.js deleted file mode 100644 index 3948b040f..000000000 --- a/devtools/client/webide/content/addons.js +++ /dev/null @@ -1,135 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cu = Components.utils; -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const Services = require("Services"); -const {gDevTools} = require("devtools/client/framework/devtools"); -const {GetAvailableAddons, ForgetAddonsList} = require("devtools/client/webide/modules/addons"); -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - document.querySelector("#aboutaddons").onclick = function () { - let browserWin = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType); - if (browserWin && browserWin.BrowserOpenAddonsMgr) { - browserWin.BrowserOpenAddonsMgr("addons://list/extension"); - } - }; - document.querySelector("#close").onclick = CloseUI; - GetAvailableAddons().then(BuildUI, (e) => { - console.error(e); - window.alert(Strings.formatStringFromName("error_cantFetchAddonsJSON", [e], 1)); - }); -}, true); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - ForgetAddonsList(); -}, true); - -function CloseUI() { - window.parent.UI.openProject(); -} - -function BuildUI(addons) { - BuildItem(addons.adb, "adb"); - BuildItem(addons.adapters, "adapters"); - for (let addon of addons.simulators) { - BuildItem(addon, "simulator"); - } -} - -function BuildItem(addon, type) { - - function onAddonUpdate(event, arg) { - switch (event) { - case "update": - progress.removeAttribute("value"); - li.setAttribute("status", addon.status); - status.textContent = Strings.GetStringFromName("addons_status_" + addon.status); - break; - case "failure": - window.parent.UI.reportError("error_operationFail", arg); - break; - case "progress": - if (arg == -1) { - progress.removeAttribute("value"); - } else { - progress.value = arg; - } - break; - } - } - - let events = ["update", "failure", "progress"]; - for (let e of events) { - addon.on(e, onAddonUpdate); - } - window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - for (let e of events) { - addon.off(e, onAddonUpdate); - } - }); - - let li = document.createElement("li"); - li.setAttribute("status", addon.status); - - let name = document.createElement("span"); - name.className = "name"; - - switch (type) { - case "adb": - li.setAttribute("addon", type); - name.textContent = Strings.GetStringFromName("addons_adb_label"); - break; - case "adapters": - li.setAttribute("addon", type); - try { - name.textContent = Strings.GetStringFromName("addons_adapters_label"); - } catch (e) { - // This code (bug 1081093) will be backported to Aurora, which doesn't - // contain this string. - name.textContent = "Tools Adapters Add-on"; - } - break; - case "simulator": - li.setAttribute("addon", "simulator-" + addon.version); - let stability = Strings.GetStringFromName("addons_" + addon.stability); - name.textContent = Strings.formatStringFromName("addons_simulator_label", [addon.version, stability], 2); - break; - } - - li.appendChild(name); - - let status = document.createElement("span"); - status.className = "status"; - status.textContent = Strings.GetStringFromName("addons_status_" + addon.status); - li.appendChild(status); - - let installButton = document.createElement("button"); - installButton.className = "install-button"; - installButton.onclick = () => addon.install(); - installButton.textContent = Strings.GetStringFromName("addons_install_button"); - li.appendChild(installButton); - - let uninstallButton = document.createElement("button"); - uninstallButton.className = "uninstall-button"; - uninstallButton.onclick = () => addon.uninstall(); - uninstallButton.textContent = Strings.GetStringFromName("addons_uninstall_button"); - li.appendChild(uninstallButton); - - let progress = document.createElement("progress"); - li.appendChild(progress); - - if (type == "adb") { - let warning = document.createElement("p"); - warning.textContent = Strings.GetStringFromName("addons_adb_warning"); - warning.className = "warning"; - li.appendChild(warning); - } - - document.querySelector("ul").appendChild(li); -} diff --git a/devtools/client/webide/content/addons.xhtml b/devtools/client/webide/content/addons.xhtml deleted file mode 100644 index 6f3bc1e7c..000000000 --- a/devtools/client/webide/content/addons.xhtml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/> - <link rel="stylesheet" href="chrome://webide/skin/addons.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/addons.js"></script> - </head> - <body> - - <div id="controls"> - <a id="aboutaddons">&addons_aboutaddons;</a> - <a id="close">&deck_close;</a> - </div> - - <h1>&addons_title;</h1> - - <ul></ul> - - </body> -</html> diff --git a/devtools/client/webide/content/details.js b/devtools/client/webide/content/details.js deleted file mode 100644 index 9097cd8c5..000000000 --- a/devtools/client/webide/content/details.js +++ /dev/null @@ -1,139 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cu = Components.utils; -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const Services = require("Services"); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); -const {ProjectBuilding} = require("devtools/client/webide/modules/build"); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - document.addEventListener("visibilitychange", updateUI, true); - AppManager.on("app-manager-update", onAppManagerUpdate); - updateUI(); -}, true); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - AppManager.off("app-manager-update", onAppManagerUpdate); -}, true); - -function onAppManagerUpdate(event, what, details) { - if (what == "project" || - what == "project-validated") { - updateUI(); - } -} - -function resetUI() { - document.querySelector("#toolbar").classList.add("hidden"); - document.querySelector("#type").classList.add("hidden"); - document.querySelector("#descriptionHeader").classList.add("hidden"); - document.querySelector("#manifestURLHeader").classList.add("hidden"); - document.querySelector("#locationHeader").classList.add("hidden"); - - document.body.className = ""; - document.querySelector("#icon").src = ""; - document.querySelector("h1").textContent = ""; - document.querySelector("#description").textContent = ""; - document.querySelector("#type").textContent = ""; - document.querySelector("#manifestURL").textContent = ""; - document.querySelector("#location").textContent = ""; - - document.querySelector("#prePackageLog").hidden = true; - - document.querySelector("#errorslist").innerHTML = ""; - document.querySelector("#warningslist").innerHTML = ""; - -} - -function updateUI() { - resetUI(); - - let project = AppManager.selectedProject; - if (!project) { - return; - } - - if (project.type != "runtimeApp" && project.type != "mainProcess") { - document.querySelector("#toolbar").classList.remove("hidden"); - document.querySelector("#locationHeader").classList.remove("hidden"); - document.querySelector("#location").textContent = project.location; - } - - document.body.className = project.validationStatus; - document.querySelector("#icon").src = project.icon; - document.querySelector("h1").textContent = project.name; - - let manifest; - if (project.type == "runtimeApp") { - manifest = project.app.manifest; - } else { - manifest = project.manifest; - } - - if (manifest) { - if (manifest.description) { - document.querySelector("#descriptionHeader").classList.remove("hidden"); - document.querySelector("#description").textContent = manifest.description; - } - - document.querySelector("#type").classList.remove("hidden"); - - if (project.type == "runtimeApp") { - let manifestURL = AppManager.getProjectManifestURL(project); - document.querySelector("#type").textContent = manifest.type || "web"; - document.querySelector("#manifestURLHeader").classList.remove("hidden"); - document.querySelector("#manifestURL").textContent = manifestURL; - } else if (project.type == "mainProcess") { - document.querySelector("#type").textContent = project.name; - } else { - document.querySelector("#type").textContent = project.type + " " + (manifest.type || "web"); - } - - if (project.type == "packaged") { - let manifestURL = AppManager.getProjectManifestURL(project); - if (manifestURL) { - document.querySelector("#manifestURLHeader").classList.remove("hidden"); - document.querySelector("#manifestURL").textContent = manifestURL; - } - } - } - - if (project.type != "runtimeApp" && project.type != "mainProcess") { - ProjectBuilding.hasPrepackage(project).then(hasPrepackage => { - document.querySelector("#prePackageLog").hidden = !hasPrepackage; - }); - } - - let errorsNode = document.querySelector("#errorslist"); - let warningsNode = document.querySelector("#warningslist"); - - if (project.errors) { - for (let e of project.errors) { - let li = document.createElement("li"); - li.textContent = e; - errorsNode.appendChild(li); - } - } - - if (project.warnings) { - for (let w of project.warnings) { - let li = document.createElement("li"); - li.textContent = w; - warningsNode.appendChild(li); - } - } - - AppManager.update("details"); -} - -function showPrepackageLog() { - window.top.UI.selectDeckPanel("logs"); -} - -function removeProject() { - AppManager.removeSelectedProject(); -} diff --git a/devtools/client/webide/content/details.xhtml b/devtools/client/webide/content/details.xhtml deleted file mode 100644 index a04c37b0c..000000000 --- a/devtools/client/webide/content/details.xhtml +++ /dev/null @@ -1,54 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/details.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/details.js"></script> - </head> - <body> - - <div id="toolbar"> - <button onclick="removeProject()">&details_removeProject_button;</button> - <p id="validation_status"> - <span class="valid">&details_valid_header;</span> - <span class="warning">&details_warning_header;</span> - <span class="error">&details_error_header;</span> - </p> - </div> - - <header> - <img id="icon"></img> - <div> - <h1></h1> - <p id="type"></p> - </div> - </header> - - <main> - <h3 id="descriptionHeader">&details_description;</h3> - <p id="description"></p> - - <h3 id="locationHeader">&details_location;</h3> - <p id="location"></p> - - <h3 id="manifestURLHeader">&details_manifestURL;</h3> - <p id="manifestURL"></p> - - <button id="prePackageLog" onclick="showPrepackageLog()" hidden="true">&details_showPrepackageLog_button;</button> - </main> - - <ul class="validation_messages" id="errorslist"></ul> - <ul class="validation_messages" id="warningslist"></ul> - - </body> -</html> diff --git a/devtools/client/webide/content/devicepreferences.js b/devtools/client/webide/content/devicepreferences.js deleted file mode 100644 index 14c020f12..000000000 --- a/devtools/client/webide/content/devicepreferences.js +++ /dev/null @@ -1,81 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cu = Components.utils; -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); -const {Connection} = require("devtools/shared/client/connection-manager"); -const ConfigView = require("devtools/client/webide/modules/config-view"); - -var configView = new ConfigView(window); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - AppManager.on("app-manager-update", OnAppManagerUpdate); - document.getElementById("close").onclick = CloseUI; - document.getElementById("device-fields").onchange = UpdateField; - document.getElementById("device-fields").onclick = CheckReset; - document.getElementById("search-bar").onkeyup = document.getElementById("search-bar").onclick = SearchField; - document.getElementById("custom-value").onclick = UpdateNewField; - document.getElementById("custom-value-type").onchange = ClearNewFields; - document.getElementById("add-custom-field").onkeyup = CheckNewFieldSubmit; - BuildUI(); -}, true); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - AppManager.off("app-manager-update", OnAppManagerUpdate); -}); - -function CloseUI() { - window.parent.UI.openProject(); -} - -function OnAppManagerUpdate(event, what) { - if (what == "connection" || what == "runtime-global-actors") { - BuildUI(); - } -} - -function CheckNewFieldSubmit(event) { - configView.checkNewFieldSubmit(event); -} - -function UpdateNewField() { - configView.updateNewField(); -} - -function ClearNewFields() { - configView.clearNewFields(); -} - -function CheckReset(event) { - configView.checkReset(event); -} - -function UpdateField(event) { - configView.updateField(event); -} - -function SearchField(event) { - configView.search(event); -} - -var getAllPrefs; // Used by tests -function BuildUI() { - configView.resetTable(); - - if (AppManager.connection && - AppManager.connection.status == Connection.Status.CONNECTED && - AppManager.preferenceFront) { - configView.front = AppManager.preferenceFront; - configView.kind = "Pref"; - configView.includeTypeName = true; - - getAllPrefs = AppManager.preferenceFront.getAllPrefs() - .then(json => configView.generateDisplay(json)); - } else { - CloseUI(); - } -} diff --git a/devtools/client/webide/content/devicepreferences.xhtml b/devtools/client/webide/content/devicepreferences.xhtml deleted file mode 100644 index dafb6f15f..000000000 --- a/devtools/client/webide/content/devicepreferences.xhtml +++ /dev/null @@ -1,49 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/> - <link rel="stylesheet" href="chrome://webide/skin/config-view.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/devicepreferences.js"></script> - </head> - <body> - <header> - <div id="controls"> - <a id="close">&deck_close;</a> - </div> - <h1>&devicepreference_title;</h1> - <div id="search"> - <input type="text" id="search-bar" placeholder="&devicepreference_search;"/> - </div> - </header> - <table id="device-fields"> - <tr id="add-custom-field"> - <td> - <select id="custom-value-type"> - <option value="" selected="selected">&device_typenone;</option> - <option value="boolean">&device_typeboolean;</option> - <option value="number">&device_typenumber;</option> - <option value="string">&device_typestring;</option> - </select> - <input type="text" id="custom-value-name" placeholder="&devicepreference_newname;"/> - </td> - <td class="custom-input"> - <input type="text" id="custom-value-text" placeholder="&devicepreference_newtext;"/> - </td> - <td> - <button id="custom-value" class="new-editable">&devicepreference_addnew;</button> - </td> - </tr> - </table> - </body> -</html> diff --git a/devtools/client/webide/content/devicesettings.js b/devtools/client/webide/content/devicesettings.js deleted file mode 100644 index 987df5995..000000000 --- a/devtools/client/webide/content/devicesettings.js +++ /dev/null @@ -1,81 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cu = Components.utils; -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); -const {Connection} = require("devtools/shared/client/connection-manager"); -const ConfigView = require("devtools/client/webide/modules/config-view"); - -var configView = new ConfigView(window); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - AppManager.on("app-manager-update", OnAppManagerUpdate); - document.getElementById("close").onclick = CloseUI; - document.getElementById("device-fields").onchange = UpdateField; - document.getElementById("device-fields").onclick = CheckReset; - document.getElementById("search-bar").onkeyup = document.getElementById("search-bar").onclick = SearchField; - document.getElementById("custom-value").onclick = UpdateNewField; - document.getElementById("custom-value-type").onchange = ClearNewFields; - document.getElementById("add-custom-field").onkeyup = CheckNewFieldSubmit; - BuildUI(); -}, true); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - AppManager.off("app-manager-update", OnAppManagerUpdate); -}); - -function CloseUI() { - window.parent.UI.openProject(); -} - -function OnAppManagerUpdate(event, what) { - if (what == "connection" || what == "runtime-global-actors") { - BuildUI(); - } -} - -function CheckNewFieldSubmit(event) { - configView.checkNewFieldSubmit(event); -} - -function UpdateNewField() { - configView.updateNewField(); -} - -function ClearNewFields() { - configView.clearNewFields(); -} - -function CheckReset(event) { - configView.checkReset(event); -} - -function UpdateField(event) { - configView.updateField(event); -} - -function SearchField(event) { - configView.search(event); -} - -var getAllSettings; // Used by tests -function BuildUI() { - configView.resetTable(); - - if (AppManager.connection && - AppManager.connection.status == Connection.Status.CONNECTED && - AppManager.settingsFront) { - configView.front = AppManager.settingsFront; - configView.kind = "Setting"; - configView.includeTypeName = false; - - getAllSettings = AppManager.settingsFront.getAllSettings() - .then(json => configView.generateDisplay(json)); - } else { - CloseUI(); - } -} diff --git a/devtools/client/webide/content/devicesettings.xhtml b/devtools/client/webide/content/devicesettings.xhtml deleted file mode 100644 index 0406c6f07..000000000 --- a/devtools/client/webide/content/devicesettings.xhtml +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/> - <link rel="stylesheet" href="chrome://webide/skin/config-view.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/devicesettings.js"></script> - </head> - <body> - <header> - <div id="controls"> - <a id="close">&deck_close;</a> - </div> - <h1>&devicesetting_title;</h1> - <div id="search"> - <input type="text" id="search-bar" placeholder="&devicesetting_search;"/> - </div> - </header> - <table id="device-fields"> - <tr id="add-custom-field"> - <td> - <select id="custom-value-type"> - <option value="" selected="selected">&device_typenone;</option> - <option value="boolean">&device_typeboolean;</option> - <option value="number">&device_typenumber;</option> - <option value="string">&device_typestring;</option> - <option value="object">&device_typeobject;</option> - </select> - <input type="text" id="custom-value-name" placeholder="&devicesetting_newname;"/> - </td> - <td class="custom-input"> - <input type="text" id="custom-value-text" placeholder="&devicesetting_newtext;"/> - </td> - <td> - <button id="custom-value" class="new-editable">&devicesetting_addnew;</button> - </td> - </tr> - </table> - </body> -</html> diff --git a/devtools/client/webide/content/jar.mn b/devtools/client/webide/content/jar.mn deleted file mode 100644 index db79fdb51..000000000 --- a/devtools/client/webide/content/jar.mn +++ /dev/null @@ -1,38 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -webide.jar: -% content webide %content/ - content/webide.xul (webide.xul) - content/webide.js (webide.js) - content/newapp.xul (newapp.xul) - content/newapp.js (newapp.js) - content/details.xhtml (details.xhtml) - content/details.js (details.js) - content/addons.js (addons.js) - content/addons.xhtml (addons.xhtml) - content/permissionstable.js (permissionstable.js) - content/permissionstable.xhtml (permissionstable.xhtml) - content/runtimedetails.js (runtimedetails.js) - content/runtimedetails.xhtml (runtimedetails.xhtml) - content/prefs.js (prefs.js) - content/prefs.xhtml (prefs.xhtml) - content/monitor.xhtml (monitor.xhtml) - content/monitor.js (monitor.js) - content/devicepreferences.js (devicepreferences.js) - content/devicepreferences.xhtml (devicepreferences.xhtml) - content/devicesettings.js (devicesettings.js) - content/devicesettings.xhtml (devicesettings.xhtml) - content/wifi-auth.js (wifi-auth.js) - content/wifi-auth.xhtml (wifi-auth.xhtml) - content/logs.xhtml (logs.xhtml) - content/logs.js (logs.js) - content/project-listing.xhtml (project-listing.xhtml) - content/project-listing.js (project-listing.js) - content/project-panel.js (project-panel.js) - content/runtime-panel.js (runtime-panel.js) - content/runtime-listing.xhtml (runtime-listing.xhtml) - content/runtime-listing.js (runtime-listing.js) - content/simulator.js (simulator.js) - content/simulator.xhtml (simulator.xhtml) diff --git a/devtools/client/webide/content/logs.js b/devtools/client/webide/content/logs.js deleted file mode 100644 index 157d83b67..000000000 --- a/devtools/client/webide/content/logs.js +++ /dev/null @@ -1,70 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cu = Components.utils; -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - - Logs.init(); -}); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - - Logs.uninit(); -}); - -const Logs = { - init: function () { - this.list = document.getElementById("logs"); - - Logs.onAppManagerUpdate = Logs.onAppManagerUpdate.bind(this); - AppManager.on("app-manager-update", Logs.onAppManagerUpdate); - - document.getElementById("close").onclick = Logs.close.bind(this); - }, - - uninit: function () { - AppManager.off("app-manager-update", Logs.onAppManagerUpdate); - }, - - onAppManagerUpdate: function (event, what, details) { - switch (what) { - case "pre-package": - this.prePackageLog(details); - break; - } - }, - - close: function () { - window.parent.UI.openProject(); - }, - - prePackageLog: function (msg, details) { - if (msg == "start") { - this.clear(); - } else if (msg == "succeed") { - setTimeout(function () { - Logs.close(); - }, 1000); - } else if (msg == "failed") { - this.log(details); - } else { - this.log(msg); - } - }, - - clear: function () { - this.list.innerHTML = ""; - }, - - log: function (msg) { - let line = document.createElement("li"); - line.textContent = msg; - this.list.appendChild(line); - } -}; diff --git a/devtools/client/webide/content/logs.xhtml b/devtools/client/webide/content/logs.xhtml deleted file mode 100644 index 8d003e509..000000000 --- a/devtools/client/webide/content/logs.xhtml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/> - <link rel="stylesheet" href="resource://devtools/client/themes/common.css" type="text/css"/> - <link rel="stylesheet" href="chrome://webide/skin/logs.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://devtools/content/shared/theme-switching.js"></script> - <script type="application/javascript;version=1.8" src="logs.js"></script> - </head> - <body> - - <div id="controls"> - <a id="close">&deck_close;</a> - </div> - - <h1>&logs_title;</h1> - - <ul id="logs" class="devtools-monospace"> - </ul> - - </body> -</html> diff --git a/devtools/client/webide/content/monitor.js b/devtools/client/webide/content/monitor.js deleted file mode 100644 index a5d80d460..000000000 --- a/devtools/client/webide/content/monitor.js +++ /dev/null @@ -1,741 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cu = Components.utils; -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const Services = require("Services"); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); -const {AppActorFront} = require("devtools/shared/apps/app-actor-front"); -const {Connection} = require("devtools/shared/client/connection-manager"); -const EventEmitter = require("devtools/shared/event-emitter"); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - window.addEventListener("resize", Monitor.resize); - window.addEventListener("unload", Monitor.unload); - - document.querySelector("#close").onclick = () => { - window.parent.UI.openProject(); - }; - - Monitor.load(); -}); - - -/** - * The Monitor is a WebIDE tool used to display any kind of time-based data in - * the form of graphs. - * - * The data can come from a Firefox OS device, simulator, or from a WebSockets - * server running locally. - * - * The format of a data update is typically an object like: - * - * { graph: 'mygraph', curve: 'mycurve', value: 42, time: 1234 } - * - * or an array of such objects. For more details on the data format, see the - * `Graph.update(data)` method. - */ -var Monitor = { - - apps: new Map(), - graphs: new Map(), - front: null, - socket: null, - wstimeout: null, - b2ginfo: false, - b2gtimeout: null, - - /** - * Add new data to the graphs, create a new graph if necessary. - */ - update: function (data, fallback) { - if (Array.isArray(data)) { - data.forEach(d => Monitor.update(d, fallback)); - return; - } - - if (Monitor.b2ginfo && data.graph === "USS") { - // If we're polling b2g-info, ignore USS updates from the device's - // USSAgents (see Monitor.pollB2GInfo()). - return; - } - - if (fallback) { - for (let key in fallback) { - if (!data[key]) { - data[key] = fallback[key]; - } - } - } - - let graph = Monitor.graphs.get(data.graph); - if (!graph) { - let element = document.createElement("div"); - element.classList.add("graph"); - document.body.appendChild(element); - - graph = new Graph(data.graph, element); - Monitor.resize(); // a scrollbar might have dis/reappeared - Monitor.graphs.set(data.graph, graph); - } - graph.update(data); - }, - - /** - * Initialize the Monitor. - */ - load: function () { - AppManager.on("app-manager-update", Monitor.onAppManagerUpdate); - Monitor.connectToRuntime(); - Monitor.connectToWebSocket(); - }, - - /** - * Clean up the Monitor. - */ - unload: function () { - AppManager.off("app-manager-update", Monitor.onAppManagerUpdate); - Monitor.disconnectFromRuntime(); - Monitor.disconnectFromWebSocket(); - }, - - /** - * Resize all the graphs. - */ - resize: function () { - for (let graph of Monitor.graphs.values()) { - graph.resize(); - } - }, - - /** - * When WebIDE connects to a new runtime, start its data forwarders. - */ - onAppManagerUpdate: function (event, what, details) { - switch (what) { - case "runtime-global-actors": - Monitor.connectToRuntime(); - break; - case "connection": - if (AppManager.connection.status == Connection.Status.DISCONNECTED) { - Monitor.disconnectFromRuntime(); - } - break; - } - }, - - /** - * Use an AppActorFront on a runtime to watch track its apps. - */ - connectToRuntime: function () { - Monitor.pollB2GInfo(); - let client = AppManager.connection && AppManager.connection.client; - let resp = AppManager._listTabsResponse; - if (client && resp && !Monitor.front) { - Monitor.front = new AppActorFront(client, resp); - Monitor.front.watchApps(Monitor.onRuntimeAppEvent); - } - }, - - /** - * Destroy our AppActorFront. - */ - disconnectFromRuntime: function () { - Monitor.unpollB2GInfo(); - if (Monitor.front) { - Monitor.front.unwatchApps(Monitor.onRuntimeAppEvent); - Monitor.front = null; - } - }, - - /** - * Try connecting to a local websockets server and accept updates from it. - */ - connectToWebSocket: function () { - let webSocketURL = Services.prefs.getCharPref("devtools.webide.monitorWebSocketURL"); - try { - Monitor.socket = new WebSocket(webSocketURL); - Monitor.socket.onmessage = function (event) { - Monitor.update(JSON.parse(event.data)); - }; - Monitor.socket.onclose = function () { - Monitor.wstimeout = setTimeout(Monitor.connectToWebsocket, 1000); - }; - } catch (e) { - Monitor.wstimeout = setTimeout(Monitor.connectToWebsocket, 1000); - } - }, - - /** - * Used when cleaning up. - */ - disconnectFromWebSocket: function () { - clearTimeout(Monitor.wstimeout); - if (Monitor.socket) { - Monitor.socket.onclose = () => {}; - Monitor.socket.close(); - } - }, - - /** - * When an app starts on the runtime, start a monitor actor for its process. - */ - onRuntimeAppEvent: function (type, app) { - if (type !== "appOpen" && type !== "appClose") { - return; - } - - let client = AppManager.connection.client; - app.getForm().then(form => { - if (type === "appOpen") { - app.monitorClient = new MonitorClient(client, form); - app.monitorClient.start(); - app.monitorClient.on("update", Monitor.onRuntimeUpdate); - Monitor.apps.set(form.monitorActor, app); - } else { - let app = Monitor.apps.get(form.monitorActor); - if (app) { - app.monitorClient.stop(() => app.monitorClient.destroy()); - Monitor.apps.delete(form.monitorActor); - } - } - }); - }, - - /** - * Accept data updates from the monitor actors of a runtime. - */ - onRuntimeUpdate: function (type, packet) { - let fallback = {}, app = Monitor.apps.get(packet.from); - if (app) { - fallback.curve = app.manifest.name; - } - Monitor.update(packet.data, fallback); - }, - - /** - * Bug 1047355: If possible, parsing the output of `b2g-info` has several - * benefits over bug 1037465's multi-process USSAgent approach, notably: - * - Works for older Firefox OS devices (pre-2.1), - * - Doesn't need certified-apps debugging, - * - Polling time is synchronized for all processes. - * TODO: After bug 1043324 lands, consider removing this hack. - */ - pollB2GInfo: function () { - if (AppManager.selectedRuntime) { - let device = AppManager.selectedRuntime.device; - if (device && device.shell) { - device.shell("b2g-info").then(s => { - let lines = s.split("\n"); - let line = ""; - - // Find the header row to locate NAME and USS, looks like: - // ' NAME PID NICE USS PSS RSS VSIZE OOM_ADJ USER '. - while (line.indexOf("NAME") < 0) { - if (lines.length < 1) { - // Something is wrong with this output, don't trust b2g-info. - Monitor.unpollB2GInfo(); - return; - } - line = lines.shift(); - } - let namelength = line.indexOf("NAME") + "NAME".length; - let ussindex = line.slice(namelength).split(/\s+/).indexOf("USS"); - - // Get the NAME and USS in each following line, looks like: - // 'Homescreen 375 18 12.6 16.3 27.1 67.8 4 app_375'. - while (lines.length > 0 && lines[0].length > namelength) { - line = lines.shift(); - let name = line.slice(0, namelength); - let uss = line.slice(namelength).split(/\s+/)[ussindex]; - Monitor.update({ - curve: name.trim(), - value: 1024 * 1024 * parseFloat(uss) // Convert MB to bytes. - }, { - // Note: We use the fallback object to set the graph name to 'USS' - // so that Monitor.update() can ignore USSAgent updates. - graph: "USS" - }); - } - }); - } - } - Monitor.b2ginfo = true; - Monitor.b2gtimeout = setTimeout(Monitor.pollB2GInfo, 350); - }, - - /** - * Polling b2g-info doesn't work or is no longer needed. - */ - unpollB2GInfo: function () { - clearTimeout(Monitor.b2gtimeout); - Monitor.b2ginfo = false; - } - -}; - - -/** - * A MonitorClient is used as an actor client of a runtime's monitor actors, - * receiving its updates. - */ -function MonitorClient(client, form) { - this.client = client; - this.actor = form.monitorActor; - this.events = ["update"]; - - EventEmitter.decorate(this); - this.client.registerClient(this); -} -MonitorClient.prototype.destroy = function () { - this.client.unregisterClient(this); -}; -MonitorClient.prototype.start = function () { - this.client.request({ - to: this.actor, - type: "start" - }); -}; -MonitorClient.prototype.stop = function (callback) { - this.client.request({ - to: this.actor, - type: "stop" - }, callback); -}; - - -/** - * A Graph populates a container DOM element with an SVG graph and a legend. - */ -function Graph(name, element) { - this.name = name; - this.element = element; - this.curves = new Map(); - this.events = new Map(); - this.ignored = new Set(); - this.enabled = true; - this.request = null; - - this.x = d3.time.scale(); - this.y = d3.scale.linear(); - - this.xaxis = d3.svg.axis().scale(this.x).orient("bottom"); - this.yaxis = d3.svg.axis().scale(this.y).orient("left"); - - this.xformat = d3.time.format("%I:%M:%S"); - this.yformat = this.formatter(1); - this.yaxis.tickFormat(this.formatter(0)); - - this.line = d3.svg.line().interpolate("linear") - .x(function (d) { return this.x(d.time); }) - .y(function (d) { return this.y(d.value); }); - - this.color = d3.scale.category10(); - - this.svg = d3.select(element).append("svg").append("g") - .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")"); - - this.xelement = this.svg.append("g").attr("class", "x axis").call(this.xaxis); - this.yelement = this.svg.append("g").attr("class", "y axis").call(this.yaxis); - - // RULERS on axes - let xruler = this.xruler = this.svg.select(".x.axis").append("g").attr("class", "x ruler"); - xruler.append("line").attr("y2", 6); - xruler.append("line").attr("stroke-dasharray", "1,1"); - xruler.append("text").attr("y", 9).attr("dy", ".71em"); - - let yruler = this.yruler = this.svg.select(".y.axis").append("g").attr("class", "y ruler"); - yruler.append("line").attr("x2", -6); - yruler.append("line").attr("stroke-dasharray", "1,1"); - yruler.append("text").attr("x", -9).attr("dy", ".32em"); - - let self = this; - - d3.select(element).select("svg") - .on("mousemove", function () { - let mouse = d3.mouse(this); - self.mousex = mouse[0] - self.margin.left, - self.mousey = mouse[1] - self.margin.top; - - xruler.attr("transform", "translate(" + self.mousex + ",0)"); - yruler.attr("transform", "translate(0," + self.mousey + ")"); - }); - /* .on('mouseout', function() { - self.xruler.attr('transform', 'translate(-500,0)'); - self.yruler.attr('transform', 'translate(0,-500)'); - });*/ - this.mousex = this.mousey = -500; - - let sidebar = d3.select(this.element).append("div").attr("class", "sidebar"); - let title = sidebar.append("label").attr("class", "graph-title"); - - title.append("input") - .attr("type", "checkbox") - .attr("checked", "true") - .on("click", function () { self.toggle(); }); - title.append("span").text(this.name); - - this.legend = sidebar.append("div").attr("class", "legend"); - - this.resize = this.resize.bind(this); - this.render = this.render.bind(this); - this.averages = this.averages.bind(this); - - setInterval(this.averages, 1000); - - this.resize(); -} - -Graph.prototype = { - - /** - * These margin are used to properly position the SVG graph items inside the - * container element. - */ - margin: { - top: 10, - right: 150, - bottom: 20, - left: 50 - }, - - /** - * A Graph can be collapsed by the user. - */ - toggle: function () { - if (this.enabled) { - this.element.classList.add("disabled"); - this.enabled = false; - } else { - this.element.classList.remove("disabled"); - this.enabled = true; - } - Monitor.resize(); - }, - - /** - * If the container element is resized (e.g. because the window was resized or - * a scrollbar dis/appeared), the graph needs to be resized as well. - */ - resize: function () { - let style = getComputedStyle(this.element), - height = parseFloat(style.height) - this.margin.top - this.margin.bottom, - width = parseFloat(style.width) - this.margin.left - this.margin.right; - - d3.select(this.element).select("svg") - .attr("width", width + this.margin.left) - .attr("height", height + this.margin.top + this.margin.bottom); - - this.x.range([0, width]); - this.y.range([height, 0]); - - this.xelement.attr("transform", "translate(0," + height + ")"); - this.xruler.select("line[stroke-dasharray]").attr("y2", -height); - this.yruler.select("line[stroke-dasharray]").attr("x2", width); - }, - - /** - * If the domain of the Graph's data changes (on the time axis and/or on the - * value axis), the axes' domains need to be updated and the graph items need - * to be rescaled in order to represent all the data. - */ - rescale: function () { - let gettime = v => { return v.time; }, - getvalue = v => { return v.value; }, - ignored = c => { return this.ignored.has(c.id); }; - - let xmin = null, xmax = null, ymin = null, ymax = null; - for (let curve of this.curves.values()) { - if (ignored(curve)) { - continue; - } - if (xmax == null || curve.xmax > xmax) { - xmax = curve.xmax; - } - if (xmin == null || curve.xmin < xmin) { - xmin = curve.xmin; - } - if (ymax == null || curve.ymax > ymax) { - ymax = curve.ymax; - } - if (ymin == null || curve.ymin < ymin) { - ymin = curve.ymin; - } - } - for (let event of this.events.values()) { - if (ignored(event)) { - continue; - } - if (xmax == null || event.xmax > xmax) { - xmax = event.xmax; - } - if (xmin == null || event.xmin < xmin) { - xmin = event.xmin; - } - } - - let oldxdomain = this.x.domain(); - if (xmin != null && xmax != null) { - this.x.domain([xmin, xmax]); - let newxdomain = this.x.domain(); - if (newxdomain[0] !== oldxdomain[0] || newxdomain[1] !== oldxdomain[1]) { - this.xelement.call(this.xaxis); - } - } - - let oldydomain = this.y.domain(); - if (ymin != null && ymax != null) { - this.y.domain([ymin, ymax]).nice(); - let newydomain = this.y.domain(); - if (newydomain[0] !== oldydomain[0] || newydomain[1] !== oldydomain[1]) { - this.yelement.call(this.yaxis); - } - } - }, - - /** - * Add new values to the graph. - */ - update: function (data) { - delete data.graph; - - let time = data.time || Date.now(); - delete data.time; - - let curve = data.curve; - delete data.curve; - - // Single curve value, e.g. { curve: 'memory', value: 42, time: 1234 }. - if ("value" in data) { - this.push(this.curves, curve, [{time: time, value: data.value}]); - delete data.value; - } - - // Several curve values, e.g. { curve: 'memory', values: [{value: 42, time: 1234}] }. - if ("values" in data) { - this.push(this.curves, curve, data.values); - delete data.values; - } - - // Punctual event, e.g. { event: 'gc', time: 1234 }, - // event with duration, e.g. { event: 'jank', duration: 425, time: 1234 }. - if ("event" in data) { - this.push(this.events, data.event, [{time: time, value: data.duration}]); - delete data.event; - delete data.duration; - } - - // Remaining keys are curves, e.g. { time: 1234, memory: 42, battery: 13, temperature: 45 }. - for (let key in data) { - this.push(this.curves, key, [{time: time, value: data[key]}]); - } - - // If no render is currently pending, request one. - if (this.enabled && !this.request) { - this.request = requestAnimationFrame(this.render); - } - }, - - /** - * Insert new data into the graph's data structures. - */ - push: function (collection, id, values) { - - // Note: collection is either `this.curves` or `this.events`. - let item = collection.get(id); - if (!item) { - item = { id: id, values: [], xmin: null, xmax: null, ymin: 0, ymax: null, average: 0 }; - collection.set(id, item); - } - - for (let v of values) { - let time = new Date(v.time), value = +v.value; - // Update the curve/event's domain values. - if (item.xmax == null || time > item.xmax) { - item.xmax = time; - } - if (item.xmin == null || time < item.xmin) { - item.xmin = time; - } - if (item.ymax == null || value > item.ymax) { - item.ymax = value; - } - if (item.ymin == null || value < item.ymin) { - item.ymin = value; - } - // Note: A curve's average is not computed here. Call `graph.averages()`. - item.values.push({ time: time, value: value }); - } - }, - - /** - * Render the SVG graph with curves, events, crosshair and legend. - */ - render: function () { - this.request = null; - this.rescale(); - - - // DATA - - let self = this, - getid = d => { return d.id; }, - gettime = d => { return d.time.getTime(); }, - getline = d => { return self.line(d.values); }, - getcolor = d => { return self.color(d.id); }, - getvalues = d => { return d.values; }, - ignored = d => { return self.ignored.has(d.id); }; - - // Convert our maps to arrays for d3. - let curvedata = [...this.curves.values()], - eventdata = [...this.events.values()], - data = curvedata.concat(eventdata); - - - // CURVES - - // Map curve data to curve elements. - let curves = this.svg.selectAll(".curve").data(curvedata, getid); - - // Create new curves (no element corresponding to the data). - curves.enter().append("g").attr("class", "curve").append("path") - .style("stroke", getcolor); - - // Delete old curves (elements corresponding to data not present anymore). - curves.exit().remove(); - - // Update all curves from data. - this.svg.selectAll(".curve").select("path") - .attr("d", d => { return ignored(d) ? "" : getline(d); }); - - let height = parseFloat(getComputedStyle(this.element).height) - this.margin.top - this.margin.bottom; - - - // EVENTS - - // Map event data to event elements. - let events = this.svg.selectAll(".event-slot").data(eventdata, getid); - - // Create new events. - events.enter().append("g").attr("class", "event-slot"); - - // Remove old events. - events.exit().remove(); - - // Get all occurences of an event, and map its data to them. - let lines = this.svg.selectAll(".event-slot") - .style("stroke", d => { return ignored(d) ? "none" : getcolor(d); }) - .selectAll(".event") - .data(getvalues, gettime); - - // Create new event occurrence. - lines.enter().append("line").attr("class", "event").attr("y2", height); - - // Delete old event occurrence. - lines.exit().remove(); - - // Update all event occurrences from data. - this.svg.selectAll(".event") - .attr("transform", d => { return "translate(" + self.x(d.time) + ",0)"; }); - - - // CROSSHAIR - - // TODO select curves and events, intersect with curves and show values/hovers - // e.g. look like http://code.shutterstock.com/rickshaw/examples/lines.html - - // Update crosshair labels on each axis. - this.xruler.select("text").text(self.xformat(self.x.invert(self.mousex))); - this.yruler.select("text").text(self.yformat(self.y.invert(self.mousey))); - - - // LEGEND - - // Map data to legend elements. - let legends = this.legend.selectAll("label").data(data, getid); - - // Update averages. - legends.attr("title", c => { return "Average: " + self.yformat(c.average); }); - - // Create new legends. - let newlegend = legends.enter().append("label"); - newlegend.append("input").attr("type", "checkbox").attr("checked", "true").on("click", function (c) { - if (ignored(c)) { - this.parentElement.classList.remove("disabled"); - self.ignored.delete(c.id); - } else { - this.parentElement.classList.add("disabled"); - self.ignored.add(c.id); - } - self.update({}); // if no re-render is pending, request one. - }); - newlegend.append("span").attr("class", "legend-color").style("background-color", getcolor); - newlegend.append("span").attr("class", "legend-id").text(getid); - - // Delete old legends. - legends.exit().remove(); - }, - - /** - * Returns a SI value formatter with a given precision. - */ - formatter: function (decimals) { - return value => { - // Don't use sub-unit SI prefixes (milli, micro, etc.). - if (Math.abs(value) < 1) return value.toFixed(decimals); - // SI prefix, e.g. 1234567 will give '1.2M' at precision 1. - let prefix = d3.formatPrefix(value); - return prefix.scale(value).toFixed(decimals) + prefix.symbol; - }; - }, - - /** - * Compute the average of each time series. - */ - averages: function () { - for (let c of this.curves.values()) { - let length = c.values.length; - if (length > 0) { - let total = 0; - c.values.forEach(v => total += v.value); - c.average = (total / length); - } - } - }, - - /** - * Bisect a time serie to find the data point immediately left of `time`. - */ - bisectTime: d3.bisector(d => d.time).left, - - /** - * Get all curve values at a given time. - */ - valuesAt: function (time) { - let values = { time: time }; - - for (let id of this.curves.keys()) { - let curve = this.curves.get(id); - - // Find the closest value just before `time`. - let i = this.bisectTime(curve.values, time); - if (i < 0) { - // Curve starts after `time`, use first value. - values[id] = curve.values[0].value; - } else if (i > curve.values.length - 2) { - // Curve ends before `time`, use last value. - values[id] = curve.values[curve.values.length - 1].value; - } else { - // Curve has two values around `time`, interpolate. - let v1 = curve.values[i], - v2 = curve.values[i + 1], - delta = (time - v1.time) / (v2.time - v1.time); - values[id] = v1.value + (v2.value - v1.time) * delta; - } - } - return values; - } - -}; diff --git a/devtools/client/webide/content/monitor.xhtml b/devtools/client/webide/content/monitor.xhtml deleted file mode 100644 index 552f3826c..000000000 --- a/devtools/client/webide/content/monitor.xhtml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/> - <link rel="stylesheet" href="chrome://webide/skin/monitor.css" type="text/css"/> - <script src="chrome://devtools/content/shared/vendor/d3.js"></script> - <script type="application/javascript;version=1.8" src="monitor.js"></script> - </head> - <body> - - <div id="controls"> - <a href="https://developer.mozilla.org/docs/Tools/WebIDE/Monitor" target="_blank">&monitor_help;</a> - <a id="close">&deck_close;</a> - </div> - - <h1>&monitor_title;</h1> - - </body> -</html> diff --git a/devtools/client/webide/content/moz.build b/devtools/client/webide/content/moz.build deleted file mode 100644 index aac3a838c..000000000 --- a/devtools/client/webide/content/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -JAR_MANIFESTS += ['jar.mn'] diff --git a/devtools/client/webide/content/newapp.js b/devtools/client/webide/content/newapp.js deleted file mode 100644 index d47bfabec..000000000 --- a/devtools/client/webide/content/newapp.js +++ /dev/null @@ -1,175 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -var Cc = Components.classes; -var Cu = Components.utils; -var Ci = Components.interfaces; - -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm"); -const Services = require("Services"); -const {FileUtils} = require("resource://gre/modules/FileUtils.jsm"); -const {AppProjects} = require("devtools/client/webide/modules/app-projects"); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); -const {getJSON} = require("devtools/client/shared/getjson"); - -XPCOMUtils.defineLazyModuleGetter(this, "ZipUtils", "resource://gre/modules/ZipUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Downloads", "resource://gre/modules/Downloads.jsm"); - -const TEMPLATES_URL = "devtools.webide.templatesURL"; - -var gTemplateList = null; - -// See bug 989619 -console.log = console.log.bind(console); -console.warn = console.warn.bind(console); -console.error = console.error.bind(console); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - let projectNameNode = document.querySelector("#project-name"); - projectNameNode.addEventListener("input", canValidate, true); - getTemplatesJSON(); -}, true); - -function getTemplatesJSON() { - getJSON(TEMPLATES_URL).then(list => { - if (!Array.isArray(list)) { - throw new Error("JSON response not an array"); - } - if (list.length == 0) { - throw new Error("JSON response is an empty array"); - } - gTemplateList = list; - let templatelistNode = document.querySelector("#templatelist"); - templatelistNode.innerHTML = ""; - for (let template of list) { - let richlistitemNode = document.createElement("richlistitem"); - let imageNode = document.createElement("image"); - imageNode.setAttribute("src", template.icon); - let labelNode = document.createElement("label"); - labelNode.setAttribute("value", template.name); - let descriptionNode = document.createElement("description"); - descriptionNode.textContent = template.description; - let vboxNode = document.createElement("vbox"); - vboxNode.setAttribute("flex", "1"); - richlistitemNode.appendChild(imageNode); - vboxNode.appendChild(labelNode); - vboxNode.appendChild(descriptionNode); - richlistitemNode.appendChild(vboxNode); - templatelistNode.appendChild(richlistitemNode); - } - templatelistNode.selectedIndex = 0; - - /* Chrome mochitest support */ - let testOptions = window.arguments[0].testOptions; - if (testOptions) { - templatelistNode.selectedIndex = testOptions.index; - document.querySelector("#project-name").value = testOptions.name; - doOK(); - } - }, (e) => { - failAndBail("Can't download app templates: " + e); - }); -} - -function failAndBail(msg) { - let promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService); - promptService.alert(window, "error", msg); - window.close(); -} - -function canValidate() { - let projectNameNode = document.querySelector("#project-name"); - let dialogNode = document.querySelector("dialog"); - if (projectNameNode.value.length > 0) { - dialogNode.removeAttribute("buttondisabledaccept"); - } else { - dialogNode.setAttribute("buttondisabledaccept", "true"); - } -} - -function doOK() { - let projectName = document.querySelector("#project-name").value; - - if (!projectName) { - console.error("No project name"); - return false; - } - - if (!gTemplateList) { - console.error("No template index"); - return false; - } - - let templatelistNode = document.querySelector("#templatelist"); - if (templatelistNode.selectedIndex < 0) { - console.error("No template selected"); - return false; - } - - let folder; - - /* Chrome mochitest support */ - let testOptions = window.arguments[0].testOptions; - if (testOptions) { - folder = testOptions.folder; - } else { - let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); - fp.init(window, "Select directory where to create app directory", Ci.nsIFilePicker.modeGetFolder); - let res = fp.show(); - if (res == Ci.nsIFilePicker.returnCancel) { - console.error("No directory selected"); - return false; - } - folder = fp.file; - } - - // Create subfolder with fs-friendly name of project - let subfolder = projectName.replace(/[\\/:*?"<>|]/g, "").toLowerCase(); - let win = Services.wm.getMostRecentWindow("devtools:webide"); - folder.append(subfolder); - - try { - folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); - } catch (e) { - win.UI.reportError("error_folderCreationFailed"); - window.close(); - return false; - } - - // Download boilerplate zip - let template = gTemplateList[templatelistNode.selectedIndex]; - let source = template.file; - let target = folder.clone(); - target.append(subfolder + ".zip"); - - let bail = (e) => { - console.error(e); - window.close(); - }; - - Downloads.fetch(source, target).then(() => { - ZipUtils.extractFiles(target, folder); - target.remove(false); - AppProjects.addPackaged(folder).then((project) => { - window.arguments[0].location = project.location; - AppManager.validateAndUpdateProject(project).then(() => { - if (project.manifest) { - project.manifest.name = projectName; - AppManager.writeManifest(project).then(() => { - AppManager.validateAndUpdateProject(project).then( - () => {window.close();}, bail); - }, bail); - } else { - bail("Manifest not found"); - } - }, bail); - }, bail); - }, bail); - - return false; -} diff --git a/devtools/client/webide/content/newapp.xul b/devtools/client/webide/content/newapp.xul deleted file mode 100644 index 7ff083519..000000000 --- a/devtools/client/webide/content/newapp.xul +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0"?> - -<!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - -<!DOCTYPE window [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<?xml-stylesheet href="chrome://global/skin/global.css"?> -<?xml-stylesheet href="chrome://webide/skin/newapp.css"?> - -<dialog id="webide:newapp" title="&newAppWindowTitle;" - width="600" height="400" - buttons="accept,cancel" - ondialogaccept="return doOK();" - buttondisabledaccept="true" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - - <script type="application/javascript" src="newapp.js"></script> - <label class="header-name" value="&newAppHeader;"/> - - <richlistbox id="templatelist" flex="1"> - <description>&newAppLoadingTemplate;</description> - </richlistbox> - <vbox> - <label class="header-name" control="project-name" value="&newAppProjectName;"/> - <textbox id="project-name"/> - </vbox> - -</dialog> diff --git a/devtools/client/webide/content/permissionstable.js b/devtools/client/webide/content/permissionstable.js deleted file mode 100644 index 22c74bd0d..000000000 --- a/devtools/client/webide/content/permissionstable.js +++ /dev/null @@ -1,78 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cu = Components.utils; -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const Services = require("Services"); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); -const {Connection} = require("devtools/shared/client/connection-manager"); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - document.querySelector("#close").onclick = CloseUI; - AppManager.on("app-manager-update", OnAppManagerUpdate); - BuildUI(); -}, true); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - AppManager.off("app-manager-update", OnAppManagerUpdate); -}); - -function CloseUI() { - window.parent.UI.openProject(); -} - -function OnAppManagerUpdate(event, what) { - if (what == "connection" || what == "runtime-global-actors") { - BuildUI(); - } -} - -function generateFields(json) { - let table = document.querySelector("table"); - let permissionsTable = json.rawPermissionsTable; - for (let name in permissionsTable) { - let tr = document.createElement("tr"); - tr.className = "line"; - let td = document.createElement("td"); - td.textContent = name; - tr.appendChild(td); - for (let type of ["app", "privileged", "certified"]) { - let td = document.createElement("td"); - if (permissionsTable[name][type] == json.ALLOW_ACTION) { - td.textContent = "✓"; - td.className = "permallow"; - } - if (permissionsTable[name][type] == json.PROMPT_ACTION) { - td.textContent = "!"; - td.className = "permprompt"; - } - if (permissionsTable[name][type] == json.DENY_ACTION) { - td.textContent = "✕"; - td.className = "permdeny"; - } - tr.appendChild(td); - } - table.appendChild(tr); - } -} - -var getRawPermissionsTablePromise; // Used by tests -function BuildUI() { - let table = document.querySelector("table"); - let lines = table.querySelectorAll(".line"); - for (let line of lines) { - line.remove(); - } - - if (AppManager.connection && - AppManager.connection.status == Connection.Status.CONNECTED && - AppManager.deviceFront) { - getRawPermissionsTablePromise = AppManager.deviceFront.getRawPermissionsTable() - .then(json => generateFields(json)); - } else { - CloseUI(); - } -} diff --git a/devtools/client/webide/content/permissionstable.xhtml b/devtools/client/webide/content/permissionstable.xhtml deleted file mode 100644 index 361cfece8..000000000 --- a/devtools/client/webide/content/permissionstable.xhtml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/> - <link rel="stylesheet" href="chrome://webide/skin/permissionstable.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/permissionstable.js"></script> - </head> - <body> - - <div id="controls"> - <a id="close">&deck_close;</a> - </div> - - <h1>&permissionstable_title;</h1> - - <table class="permissionstable"> - <tr> - <th>&permissionstable_name_header;</th> - <th>type:web</th> - <th>type:privileged</th> - <th>type:certified</th> - </tr> - </table> - </body> -</html> diff --git a/devtools/client/webide/content/prefs.js b/devtools/client/webide/content/prefs.js deleted file mode 100644 index 75f6233ba..000000000 --- a/devtools/client/webide/content/prefs.js +++ /dev/null @@ -1,108 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Cu = Components.utils; -const {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - - // Listen to preference changes - let inputs = document.querySelectorAll("[data-pref]"); - for (let i of inputs) { - let pref = i.dataset.pref; - Services.prefs.addObserver(pref, FillForm, false); - i.addEventListener("change", SaveForm, false); - } - - // Buttons - document.querySelector("#close").onclick = CloseUI; - document.querySelector("#restore").onclick = RestoreDefaults; - document.querySelector("#manageComponents").onclick = ShowAddons; - - // Initialize the controls - FillForm(); - -}, true); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - let inputs = document.querySelectorAll("[data-pref]"); - for (let i of inputs) { - let pref = i.dataset.pref; - i.removeEventListener("change", SaveForm, false); - Services.prefs.removeObserver(pref, FillForm, false); - } -}, true); - -function CloseUI() { - window.parent.UI.openProject(); -} - -function ShowAddons() { - window.parent.Cmds.showAddons(); -} - -function FillForm() { - let inputs = document.querySelectorAll("[data-pref]"); - for (let i of inputs) { - let pref = i.dataset.pref; - let val = GetPref(pref); - if (i.type == "checkbox") { - i.checked = val; - } else { - i.value = val; - } - } -} - -function SaveForm(e) { - let inputs = document.querySelectorAll("[data-pref]"); - for (let i of inputs) { - let pref = i.dataset.pref; - if (i.type == "checkbox") { - SetPref(pref, i.checked); - } else { - SetPref(pref, i.value); - } - } -} - -function GetPref(name) { - let type = Services.prefs.getPrefType(name); - switch (type) { - case Services.prefs.PREF_STRING: - return Services.prefs.getCharPref(name); - case Services.prefs.PREF_INT: - return Services.prefs.getIntPref(name); - case Services.prefs.PREF_BOOL: - return Services.prefs.getBoolPref(name); - default: - throw new Error("Unknown type"); - } -} - -function SetPref(name, value) { - let type = Services.prefs.getPrefType(name); - switch (type) { - case Services.prefs.PREF_STRING: - return Services.prefs.setCharPref(name, value); - case Services.prefs.PREF_INT: - return Services.prefs.setIntPref(name, value); - case Services.prefs.PREF_BOOL: - return Services.prefs.setBoolPref(name, value); - default: - throw new Error("Unknown type"); - } -} - -function RestoreDefaults() { - let inputs = document.querySelectorAll("[data-pref]"); - for (let i of inputs) { - let pref = i.dataset.pref; - Services.prefs.clearUserPref(pref); - } -} diff --git a/devtools/client/webide/content/prefs.xhtml b/devtools/client/webide/content/prefs.xhtml deleted file mode 100644 index 726ca772c..000000000 --- a/devtools/client/webide/content/prefs.xhtml +++ /dev/null @@ -1,112 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/prefs.js"></script> - </head> - <body> - - <div id="controls"> - <a id="restore">&prefs_restore;</a> - <a id="manageComponents">&prefs_manage_components;</a> - <a id="close">&deck_close;</a> - </div> - - <h1>&prefs_title;</h1> - - <h2>&prefs_general_title;</h2> - - <ul> - <li> - <label title="&prefs_options_showeditor_tooltip;"> - <input type="checkbox" data-pref="devtools.webide.showProjectEditor"/> - <span>&prefs_options_showeditor;</span> - </label> - </li> - <li> - <label title="&prefs_options_rememberlastproject_tooltip;"> - <input type="checkbox" data-pref="devtools.webide.restoreLastProject"/> - <span>&prefs_options_rememberlastproject;</span> - </label> - </li> - <li> - <label title="&prefs_options_autoconnectruntime_tooltip;"> - <input type="checkbox" data-pref="devtools.webide.autoConnectRuntime"/> - <span>&prefs_options_autoconnectruntime;</span> - </label> - </li> - <li> - <label class="text-input" title="&prefs_options_templatesurl_tooltip;"> - <span>&prefs_options_templatesurl;</span> - <input data-pref="devtools.webide.templatesURL"/> - </label> - </li> - </ul> - - <h2>&prefs_editor_title;</h2> - - <ul> - <li> - <label><span>&prefs_options_tabsize;</span> - <select data-pref="devtools.editor.tabsize"> - <option value="2">2</option> - <option value="4">4</option> - <option value="8">8</option> - </select> - </label> - </li> - <li> - <label title="&prefs_options_expandtab_tooltip;"> - <input type="checkbox" data-pref="devtools.editor.expandtab"/> - <span>&prefs_options_expandtab;</span> - </label> - </li> - <li> - <label title="&prefs_options_detectindentation_tooltip;"> - <input type="checkbox" data-pref="devtools.editor.detectindentation"/> - <span>&prefs_options_detectindentation;</span> - </label> - </li> - <li> - <label title="&prefs_options_autocomplete_tooltip;"> - <input type="checkbox" data-pref="devtools.editor.autocomplete"/> - <span>&prefs_options_autocomplete;</span> - </label> - </li> - <li> - <label title="&prefs_options_autoclosebrackets_tooltip;"> - <input type="checkbox" data-pref="devtools.editor.autoclosebrackets"/> - <span>&prefs_options_autoclosebrackets;</span> - </label> - </li> - <li> - <label title="&prefs_options_autosavefiles_tooltip;"> - <input type="checkbox" data-pref="devtools.webide.autosaveFiles"/> - <span>&prefs_options_autosavefiles;</span> - </label> - </li> - <li> - <label><span>&prefs_options_keybindings;</span> - <select data-pref="devtools.editor.keymap"> - <option value="default">&prefs_options_keybindings_default;</option> - <option value="vim">Vim</option> - <option value="emacs">Emacs</option> - <option value="sublime">Sublime</option> - </select> - </label> - </li> - </ul> - - </body> -</html> diff --git a/devtools/client/webide/content/project-listing.js b/devtools/client/webide/content/project-listing.js deleted file mode 100644 index 5641f6c0c..000000000 --- a/devtools/client/webide/content/project-listing.js +++ /dev/null @@ -1,42 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* eslint-env browser */ - -var Cu = Components.utils; -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const ProjectList = require("devtools/client/webide/modules/project-list"); - -var projectList = new ProjectList(window, window.parent); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad, true); - document.getElementById("new-app").onclick = CreateNewApp; - document.getElementById("hosted-app").onclick = ImportHostedApp; - document.getElementById("packaged-app").onclick = ImportPackagedApp; - document.getElementById("refresh-tabs").onclick = RefreshTabs; - projectList.update(); - projectList.updateCommands(); -}, true); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - projectList.destroy(); -}); - -function RefreshTabs() { - projectList.refreshTabs(); -} - -function CreateNewApp() { - projectList.newApp(); -} - -function ImportHostedApp() { - projectList.importHostedApp(); -} - -function ImportPackagedApp() { - projectList.importPackagedApp(); -} diff --git a/devtools/client/webide/content/project-listing.xhtml b/devtools/client/webide/content/project-listing.xhtml deleted file mode 100644 index 337befe5d..000000000 --- a/devtools/client/webide/content/project-listing.xhtml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/panel-listing.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/project-listing.js"></script> - </head> - <body> - <div id="project-panel"> - <div id="project-panel-box"> - <button class="panel-item project-panel-item-newapp" id="new-app">&projectMenu_newApp_label;</button> - <button class="panel-item project-panel-item-openpackaged" id="packaged-app">&projectMenu_importPackagedApp_label;</button> - <button class="panel-item project-panel-item-openhosted" id="hosted-app">&projectMenu_importHostedApp_label;</button> - <label class="panel-header">&projectPanel_myProjects;</label> - <div id="project-panel-projects"></div> - <label class="panel-header" id="panel-header-runtimeapps" hidden="true">&projectPanel_runtimeApps;</label> - <div id="project-panel-runtimeapps"/> - <label class="panel-header" id="panel-header-tabs" hidden="true">&projectPanel_tabs; - <button class="project-panel-item-refreshtabs refresh-icon" id="refresh-tabs" title="&projectMenu_refreshTabs_label;"></button> - </label> - <div id="project-panel-tabs"/> - </div> - </div> - </body> -</html> diff --git a/devtools/client/webide/content/project-panel.js b/devtools/client/webide/content/project-panel.js deleted file mode 100644 index 54eab8251..000000000 --- a/devtools/client/webide/content/project-panel.js +++ /dev/null @@ -1,11 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var ProjectPanel = { - // TODO: Expand function to save toggle state. - toggleSidebar: function () { - document.querySelector("#project-listing-panel").setAttribute("sidebar-displayed", true); - document.querySelector("#project-listing-splitter").setAttribute("sidebar-displayed", true); - } -}; diff --git a/devtools/client/webide/content/runtime-listing.js b/devtools/client/webide/content/runtime-listing.js deleted file mode 100644 index 0a1a40a2a..000000000 --- a/devtools/client/webide/content/runtime-listing.js +++ /dev/null @@ -1,66 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cu = Components.utils; -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const RuntimeList = require("devtools/client/webide/modules/runtime-list"); - -var runtimeList = new RuntimeList(window, window.parent); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad, true); - document.getElementById("runtime-screenshot").onclick = TakeScreenshot; - document.getElementById("runtime-permissions").onclick = ShowPermissionsTable; - document.getElementById("runtime-details").onclick = ShowRuntimeDetails; - document.getElementById("runtime-disconnect").onclick = DisconnectRuntime; - document.getElementById("runtime-preferences").onclick = ShowDevicePreferences; - document.getElementById("runtime-settings").onclick = ShowSettings; - document.getElementById("runtime-panel-installsimulator").onclick = ShowAddons; - document.getElementById("runtime-panel-noadbhelper").onclick = ShowAddons; - document.getElementById("runtime-panel-nousbdevice").onclick = ShowTroubleShooting; - document.getElementById("refresh-devices").onclick = RefreshScanners; - runtimeList.update(); - runtimeList.updateCommands(); -}, true); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - runtimeList.destroy(); -}); - -function TakeScreenshot() { - runtimeList.takeScreenshot(); -} - -function ShowRuntimeDetails() { - runtimeList.showRuntimeDetails(); -} - -function ShowPermissionsTable() { - runtimeList.showPermissionsTable(); -} - -function ShowDevicePreferences() { - runtimeList.showDevicePreferences(); -} - -function ShowSettings() { - runtimeList.showSettings(); -} - -function RefreshScanners() { - runtimeList.refreshScanners(); -} - -function DisconnectRuntime() { - window.parent.Cmds.disconnectRuntime(); -} - -function ShowAddons() { - runtimeList.showAddons(); -} - -function ShowTroubleShooting() { - runtimeList.showTroubleShooting(); -} diff --git a/devtools/client/webide/content/runtime-listing.xhtml b/devtools/client/webide/content/runtime-listing.xhtml deleted file mode 100644 index f648fac12..000000000 --- a/devtools/client/webide/content/runtime-listing.xhtml +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/panel-listing.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/runtime-listing.js"></script> - </head> - <body> - <div id="runtime-panel"> - <div id="runtime-panel-box"> - <label class="panel-header">&runtimePanel_usb; - <button class="runtime-panel-item-refreshdevices refresh-icon" id="refresh-devices" title="&runtimePanel_refreshDevices_label;"></button> - </label> - <button class="panel-item" id="runtime-panel-nousbdevice">&runtimePanel_nousbdevice;</button> - <button class="panel-item" id="runtime-panel-noadbhelper">&runtimePanel_noadbhelper;</button> - <div id="runtime-panel-usb"></div> - <label class="panel-header" id="runtime-header-wifi">&runtimePanel_wifi;</label> - <div id="runtime-panel-wifi"></div> - <label class="panel-header">&runtimePanel_simulator;</label> - <div id="runtime-panel-simulator"></div> - <button class="panel-item" id="runtime-panel-installsimulator">&runtimePanel_installsimulator;</button> - <label class="panel-header">&runtimePanel_other;</label> - <div id="runtime-panel-other"></div> - <div id="runtime-actions"> - <button class="panel-item" id="runtime-details">&runtimeMenu_showDetails_label;</button> - <button class="panel-item" id="runtime-permissions">&runtimeMenu_showPermissionTable_label;</button> - <button class="panel-item" id="runtime-preferences">&runtimeMenu_showDevicePrefs_label;</button> - <button class="panel-item" id="runtime-settings">&runtimeMenu_showSettings_label;</button> - <button class="panel-item" id="runtime-screenshot">&runtimeMenu_takeScreenshot_label;</button> - <button class="panel-item" id="runtime-disconnect">&runtimeMenu_disconnect_label;</button> - </div> - </div> - </div> - </body> -</html> diff --git a/devtools/client/webide/content/runtime-panel.js b/devtools/client/webide/content/runtime-panel.js deleted file mode 100644 index 3646fa15c..000000000 --- a/devtools/client/webide/content/runtime-panel.js +++ /dev/null @@ -1,11 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var RuntimePanel = { - // TODO: Expand function to save toggle state. - toggleSidebar: function () { - document.querySelector("#runtime-listing-panel").setAttribute("sidebar-displayed", true); - document.querySelector("#runtime-listing-splitter").setAttribute("sidebar-displayed", true); - } -}; diff --git a/devtools/client/webide/content/runtimedetails.js b/devtools/client/webide/content/runtimedetails.js deleted file mode 100644 index dea423e81..000000000 --- a/devtools/client/webide/content/runtimedetails.js +++ /dev/null @@ -1,153 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cu = Components.utils; -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const Services = require("Services"); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); -const {Connection} = require("devtools/shared/client/connection-manager"); -const {RuntimeTypes} = require("devtools/client/webide/modules/runtimes"); -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -const UNRESTRICTED_HELP_URL = "https://developer.mozilla.org/docs/Tools/WebIDE/Running_and_debugging_apps#Unrestricted_app_debugging_%28including_certified_apps_main_process_etc.%29"; - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - document.querySelector("#close").onclick = CloseUI; - document.querySelector("#devtools-check button").onclick = EnableCertApps; - document.querySelector("#adb-check button").onclick = RootADB; - document.querySelector("#unrestricted-privileges").onclick = function () { - window.parent.UI.openInBrowser(UNRESTRICTED_HELP_URL); - }; - AppManager.on("app-manager-update", OnAppManagerUpdate); - BuildUI(); - CheckLockState(); -}, true); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - AppManager.off("app-manager-update", OnAppManagerUpdate); -}); - -function CloseUI() { - window.parent.UI.openProject(); -} - -function OnAppManagerUpdate(event, what) { - if (what == "connection" || what == "runtime-global-actors") { - BuildUI(); - CheckLockState(); - } -} - -function generateFields(json) { - let table = document.querySelector("table"); - for (let name in json) { - let tr = document.createElement("tr"); - let td = document.createElement("td"); - td.textContent = name; - tr.appendChild(td); - td = document.createElement("td"); - td.textContent = json[name]; - tr.appendChild(td); - table.appendChild(tr); - } -} - -var getDescriptionPromise; // Used by tests -function BuildUI() { - let table = document.querySelector("table"); - table.innerHTML = ""; - if (AppManager.connection && - AppManager.connection.status == Connection.Status.CONNECTED && - AppManager.deviceFront) { - getDescriptionPromise = AppManager.deviceFront.getDescription() - .then(json => generateFields(json)); - } else { - CloseUI(); - } -} - -function CheckLockState() { - let adbCheckResult = document.querySelector("#adb-check > .yesno"); - let devtoolsCheckResult = document.querySelector("#devtools-check > .yesno"); - let flipCertPerfButton = document.querySelector("#devtools-check button"); - let adbRootButton = document.querySelector("#adb-check button"); - let flipCertPerfAction = document.querySelector("#devtools-check > .action"); - let adbRootAction = document.querySelector("#adb-check > .action"); - - let sYes = Strings.GetStringFromName("runtimedetails_checkyes"); - let sNo = Strings.GetStringFromName("runtimedetails_checkno"); - let sUnknown = Strings.GetStringFromName("runtimedetails_checkunknown"); - let sNotUSB = Strings.GetStringFromName("runtimedetails_notUSBDevice"); - - flipCertPerfButton.setAttribute("disabled", "true"); - flipCertPerfAction.setAttribute("hidden", "true"); - adbRootAction.setAttribute("hidden", "true"); - - adbCheckResult.textContent = sUnknown; - devtoolsCheckResult.textContent = sUnknown; - - if (AppManager.connection && - AppManager.connection.status == Connection.Status.CONNECTED) { - - // ADB check - if (AppManager.selectedRuntime.type === RuntimeTypes.USB) { - let device = AppManager.selectedRuntime.device; - if (device && device.summonRoot) { - device.isRoot().then(isRoot => { - if (isRoot) { - adbCheckResult.textContent = sYes; - flipCertPerfButton.removeAttribute("disabled"); - } else { - adbCheckResult.textContent = sNo; - adbRootAction.removeAttribute("hidden"); - } - }, e => console.error(e)); - } else { - adbCheckResult.textContent = sUnknown; - } - } else { - adbCheckResult.textContent = sNotUSB; - } - - // forbid-certified-apps check - try { - let prefFront = AppManager.preferenceFront; - prefFront.getBoolPref("devtools.debugger.forbid-certified-apps").then(isForbidden => { - if (isForbidden) { - devtoolsCheckResult.textContent = sNo; - flipCertPerfAction.removeAttribute("hidden"); - } else { - devtoolsCheckResult.textContent = sYes; - } - }, e => console.error(e)); - } catch (e) { - // Exception. pref actor is only accessible if forbird-certified-apps is false - devtoolsCheckResult.textContent = sNo; - flipCertPerfAction.removeAttribute("hidden"); - } - - } - -} - -function EnableCertApps() { - let device = AppManager.selectedRuntime.device; - // TODO: Remove `network.disable.ipc.security` once bug 1125916 is fixed. - device.shell( - "stop b2g && " + - "cd /data/b2g/mozilla/*.default/ && " + - "echo 'user_pref(\"devtools.debugger.forbid-certified-apps\", false);' >> prefs.js && " + - "echo 'user_pref(\"dom.apps.developer_mode\", true);' >> prefs.js && " + - "echo 'user_pref(\"network.disable.ipc.security\", true);' >> prefs.js && " + - "echo 'user_pref(\"dom.webcomponents.enabled\", true);' >> prefs.js && " + - "start b2g" - ); -} - -function RootADB() { - let device = AppManager.selectedRuntime.device; - device.summonRoot().then(CheckLockState, (e) => console.error(e)); -} diff --git a/devtools/client/webide/content/runtimedetails.xhtml b/devtools/client/webide/content/runtimedetails.xhtml deleted file mode 100644 index b2f74728a..000000000 --- a/devtools/client/webide/content/runtimedetails.xhtml +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/> - <link rel="stylesheet" href="chrome://webide/skin/runtimedetails.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/runtimedetails.js"></script> - </head> - <body> - - <div id="controls"> - <a id="close">&deck_close;</a> - </div> - - <h1>&runtimedetails_title;</h1> - - <div id="devicePrivileges"> - <p id="adb-check"> - &runtimedetails_adbIsRoot;<span class="yesno"></span> - <div class="action"> - <button>&runtimedetails_summonADBRoot;</button> - <em>&runtimedetails_ADBRootWarning;</em> - </div> - </p> - <p id="devtools-check"> - <a id="unrestricted-privileges">&runtimedetails_unrestrictedPrivileges;</a><span class="yesno"></span> - <div class="action"> - <button>&runtimedetails_requestPrivileges;</button> - <em>&runtimedetails_privilegesWarning;</em> - </div> - </p> - </div> - - <table></table> - </body> -</html> diff --git a/devtools/client/webide/content/simulator.js b/devtools/client/webide/content/simulator.js deleted file mode 100644 index ddc1cbed1..000000000 --- a/devtools/client/webide/content/simulator.js +++ /dev/null @@ -1,352 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cu = Components.utils; -var Ci = Components.interfaces; - -const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const { getDevices, getDeviceString } = require("devtools/client/shared/devices"); -const { Simulators, Simulator } = require("devtools/client/webide/modules/simulators"); -const Services = require("Services"); -const EventEmitter = require("devtools/shared/event-emitter"); -const promise = require("promise"); -const utils = require("devtools/client/webide/modules/utils"); - -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -var SimulatorEditor = { - - // Available Firefox OS Simulator addons (key: `addon.id`). - _addons: {}, - - // Available device simulation profiles (key: `device.name`). - _devices: {}, - - // The names of supported simulation options. - _deviceOptions: [], - - // The <form> element used to edit Simulator options. - _form: null, - - // The Simulator object being edited. - _simulator: null, - - // Generate the dynamic form elements. - init() { - let promises = []; - - // Grab the <form> element. - let form = this._form; - if (!form) { - // This is the first time we run `init()`, bootstrap some things. - form = this._form = document.querySelector("#simulator-editor"); - form.addEventListener("change", this.update.bind(this)); - Simulators.on("configure", (e, simulator) => { this.edit(simulator); }); - // Extract the list of device simulation options we'll support. - let deviceFields = form.querySelectorAll("*[data-device]"); - this._deviceOptions = Array.map(deviceFields, field => field.name); - } - - // Append a new <option> to a <select> (or <optgroup>) element. - function opt(select, value, text) { - let option = document.createElement("option"); - option.value = value; - option.textContent = text; - select.appendChild(option); - } - - // Generate B2G version selector. - promises.push(Simulators.findSimulatorAddons().then(addons => { - this._addons = {}; - form.version.innerHTML = ""; - form.version.classList.remove("custom"); - addons.forEach(addon => { - this._addons[addon.id] = addon; - opt(form.version, addon.id, addon.name); - }); - opt(form.version, "custom", ""); - opt(form.version, "pick", Strings.GetStringFromName("simulator_custom_binary")); - })); - - // Generate profile selector. - form.profile.innerHTML = ""; - form.profile.classList.remove("custom"); - opt(form.profile, "default", Strings.GetStringFromName("simulator_default_profile")); - opt(form.profile, "custom", ""); - opt(form.profile, "pick", Strings.GetStringFromName("simulator_custom_profile")); - - // Generate example devices list. - form.device.innerHTML = ""; - form.device.classList.remove("custom"); - opt(form.device, "custom", Strings.GetStringFromName("simulator_custom_device")); - promises.push(getDevices().then(devices => { - devices.TYPES.forEach(type => { - let b2gDevices = devices[type].filter(d => d.firefoxOS); - if (b2gDevices.length < 1) { - return; - } - let optgroup = document.createElement("optgroup"); - optgroup.label = getDeviceString(type); - b2gDevices.forEach(device => { - this._devices[device.name] = device; - opt(optgroup, device.name, device.name); - }); - form.device.appendChild(optgroup); - }); - })); - - return promise.all(promises); - }, - - // Edit the configuration of an existing Simulator, or create a new one. - edit(simulator) { - // If no Simulator was given to edit, we're creating a new one. - if (!simulator) { - simulator = new Simulator(); // Default options. - Simulators.add(simulator); - } - - this._simulator = null; - - return this.init().then(() => { - this._simulator = simulator; - - // Update the form fields. - this._form.name.value = simulator.name; - - this.updateVersionSelector(); - this.updateProfileSelector(); - this.updateDeviceSelector(); - this.updateDeviceFields(); - - // Change visibility of 'TV Simulator Menu'. - let tvSimMenu = document.querySelector("#tv_simulator_menu"); - tvSimMenu.style.visibility = (this._simulator.type === "television") ? - "visible" : "hidden"; - - // Trigger any listener waiting for this update - let change = document.createEvent("HTMLEvents"); - change.initEvent("change", true, true); - this._form.dispatchEvent(change); - }); - }, - - // Open the directory of TV Simulator config. - showTVConfigDirectory() { - let profD = Services.dirsvc.get("ProfD", Ci.nsIFile); - profD.append("extensions"); - profD.append(this._simulator.addon.id); - profD.append("profile"); - profD.append("dummy"); - let profileDir = profD.path; - - // Show the profile directory. - let nsLocalFile = Components.Constructor("@mozilla.org/file/local;1", - "nsILocalFile", "initWithPath"); - new nsLocalFile(profileDir).reveal(); - }, - - // Close the configuration panel. - close() { - this._simulator = null; - window.parent.UI.openProject(); - }, - - // Restore the simulator to its default configuration. - restoreDefaults() { - let simulator = this._simulator; - this.version = simulator.addon.id; - this.profile = "default"; - simulator.restoreDefaults(); - Simulators.emitUpdated(); - return this.edit(simulator); - }, - - // Delete this simulator. - deleteSimulator() { - Simulators.remove(this._simulator); - this.close(); - }, - - // Select an available option, or set the "custom" option. - updateSelector(selector, value) { - selector.value = value; - if (selector.selectedIndex == -1) { - selector.value = "custom"; - selector.classList.add("custom"); - selector[selector.selectedIndex].textContent = value; - } - }, - - // VERSION: Can be an installed `addon.id` or a custom binary path. - - get version() { - return this._simulator.options.b2gBinary || this._simulator.addon.id; - }, - - set version(value) { - let form = this._form; - let simulator = this._simulator; - let oldVer = simulator.version; - if (this._addons[value]) { - // `value` is a simulator addon ID. - simulator.addon = this._addons[value]; - simulator.options.b2gBinary = null; - } else { - // `value` is a custom binary path. - simulator.options.b2gBinary = value; - // TODO (Bug 1146531) Indicate that a custom profile is now required. - } - // If `form.name` contains the old version, update its last occurrence. - if (form.name.value.includes(oldVer) && simulator.version !== oldVer) { - let regex = new RegExp("(.*)" + oldVer); - let name = form.name.value.replace(regex, "$1" + simulator.version); - simulator.options.name = form.name.value = Simulators.uniqueName(name); - } - }, - - updateVersionSelector() { - this.updateSelector(this._form.version, this.version); - }, - - // PROFILE. Can be "default" or a custom profile directory path. - - get profile() { - return this._simulator.options.gaiaProfile || "default"; - }, - - set profile(value) { - this._simulator.options.gaiaProfile = (value == "default" ? null : value); - }, - - updateProfileSelector() { - this.updateSelector(this._form.profile, this.profile); - }, - - // DEVICE. Can be an existing `device.name` or "custom". - - get device() { - let devices = this._devices; - let simulator = this._simulator; - - // Search for the name of a device matching current simulator options. - for (let name in devices) { - let match = true; - for (let option of this._deviceOptions) { - if (simulator.options[option] === devices[name][option]) { - continue; - } - match = false; - break; - } - if (match) { - return name; - } - } - return "custom"; - }, - - set device(name) { - let device = this._devices[name]; - if (!device) { - return; - } - let form = this._form; - let simulator = this._simulator; - this._deviceOptions.forEach(option => { - simulator.options[option] = form[option].value = device[option] || null; - }); - // TODO (Bug 1146531) Indicate when a custom profile is required (e.g. for - // tablet, TV…). - }, - - updateDeviceSelector() { - this.updateSelector(this._form.device, this.device); - }, - - // Erase any current values, trust only the `simulator.options`. - updateDeviceFields() { - let form = this._form; - let simulator = this._simulator; - this._deviceOptions.forEach(option => { - form[option].value = simulator.options[option]; - }); - }, - - // Handle a change in our form's fields. - update(event) { - let simulator = this._simulator; - if (!simulator) { - return; - } - let form = this._form; - let input = event.target; - switch (input.name) { - case "name": - simulator.options.name = input.value; - break; - case "version": - switch (input.value) { - case "pick": - let file = utils.getCustomBinary(window); - if (file) { - this.version = file.path; - } - // Whatever happens, don't stay on the "pick" option. - this.updateVersionSelector(); - break; - case "custom": - this.version = input[input.selectedIndex].textContent; - break; - default: - this.version = input.value; - } - break; - case "profile": - switch (input.value) { - case "pick": - let directory = utils.getCustomProfile(window); - if (directory) { - this.profile = directory.path; - } - // Whatever happens, don't stay on the "pick" option. - this.updateProfileSelector(); - break; - case "custom": - this.profile = input[input.selectedIndex].textContent; - break; - default: - this.profile = input.value; - } - break; - case "device": - this.device = input.value; - break; - default: - simulator.options[input.name] = input.value || null; - this.updateDeviceSelector(); - } - Simulators.emitUpdated(); - }, -}; - -window.addEventListener("load", function onLoad() { - document.querySelector("#close").onclick = e => { - SimulatorEditor.close(); - }; - document.querySelector("#reset").onclick = e => { - SimulatorEditor.restoreDefaults(); - }; - document.querySelector("#remove").onclick = e => { - SimulatorEditor.deleteSimulator(); - }; - - // We just loaded, so we probably missed the first configure request. - SimulatorEditor.edit(Simulators._lastConfiguredSimulator); - - document.querySelector("#open-tv-dummy-directory").onclick = e => { - SimulatorEditor.showTVConfigDirectory(); - e.preventDefault(); - }; -}); diff --git a/devtools/client/webide/content/simulator.xhtml b/devtools/client/webide/content/simulator.xhtml deleted file mode 100644 index 3ab916248..000000000 --- a/devtools/client/webide/content/simulator.xhtml +++ /dev/null @@ -1,99 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/> - <link rel="stylesheet" href="chrome://webide/skin/simulator.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/simulator.js"></script> - </head> - <body> - - <div id="controls"> - <a id="remove" class="hidden">&simulator_remove;</a> - <a id="reset">&simulator_reset;</a> - <a id="close">&deck_close;</a> - </div> - - <form id="simulator-editor"> - - <h1>&simulator_title;</h1> - - <h2>&simulator_software;</h2> - - <ul> - <li> - <label> - <span class="label">&simulator_name;</span> - <input type="text" name="name"/> - </label> - </li> - <li> - <label> - <span class="label">&simulator_version;</span> - <select name="version"/> - </label> - </li> - <li> - <label> - <span class="label">&simulator_profile;</span> - <select name="profile"/> - </label> - </li> - </ul> - - <h2>&simulator_hardware;</h2> - - <ul> - <li> - <label> - <span class="label">&simulator_device;</span> - <select name="device"/> - </label> - </li> - <li> - <label> - <span class="label">&simulator_screenSize;</span> - <input name="width" data-device="" type="number"/> - <span>×</span> - <input name="height" data-device="" type="number"/> - </label> - </li> - <li class="hidden"> - <label> - <span class="label">&simulator_pixelRatio;</span> - <input name="pixelRatio" data-device="" type="number" step="0.05"/> - </label> - </li> - </ul> - - <!-- This menu is shown when simulator type is television--> - <p id="tv_simulator_menu" style="visibility:hidden;"> - <h2>&simulator_tv_data;</h2> - - <ul> - <li> - <label> - <span class="label">&simulator_tv_data_open;</span> - <button id="open-tv-dummy-directory"> - &simulator_tv_data_open_button; - </button> - </label> - </li> - </ul> - - </p> - - </form> - - </body> -</html> diff --git a/devtools/client/webide/content/webide.js b/devtools/client/webide/content/webide.js deleted file mode 100644 index c222332e3..000000000 --- a/devtools/client/webide/content/webide.js +++ /dev/null @@ -1,1157 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var Cc = Components.classes; -var Cu = Components.utils; -var Ci = Components.interfaces; - -const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const {gDevTools} = require("devtools/client/framework/devtools"); -const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser"); -const {Toolbox} = require("devtools/client/framework/toolbox"); -const Services = require("Services"); -const {AppProjects} = require("devtools/client/webide/modules/app-projects"); -const {Connection} = require("devtools/shared/client/connection-manager"); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); -const EventEmitter = require("devtools/shared/event-emitter"); -const promise = require("promise"); -const ProjectEditor = require("devtools/client/projecteditor/lib/projecteditor"); -const {GetAvailableAddons} = require("devtools/client/webide/modules/addons"); -const {getJSON} = require("devtools/client/shared/getjson"); -const utils = require("devtools/client/webide/modules/utils"); -const Telemetry = require("devtools/client/shared/telemetry"); -const {RuntimeScanners} = require("devtools/client/webide/modules/runtimes"); -const {showDoorhanger} = require("devtools/client/shared/doorhanger"); -const {Simulators} = require("devtools/client/webide/modules/simulators"); -const {Task} = require("devtools/shared/task"); - -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -const HTML = "http://www.w3.org/1999/xhtml"; -const HELP_URL = "https://developer.mozilla.org/docs/Tools/WebIDE/Troubleshooting"; - -const MAX_ZOOM = 1.4; -const MIN_ZOOM = 0.6; - -const MS_PER_DAY = 86400000; - -[["AppManager", AppManager], - ["AppProjects", AppProjects], - ["Connection", Connection]].forEach(([key, value]) => { - Object.defineProperty(this, key, { - value: value, - enumerable: true, - writable: false - }); - }); - -// Download remote resources early -getJSON("devtools.webide.addonsURL"); -getJSON("devtools.webide.templatesURL"); -getJSON("devtools.devices.url"); - -// See bug 989619 -console.log = console.log.bind(console); -console.warn = console.warn.bind(console); -console.error = console.error.bind(console); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - UI.init(); -}); - -window.addEventListener("unload", function onUnload() { - window.removeEventListener("unload", onUnload); - UI.destroy(); -}); - -var UI = { - init: function () { - this._telemetry = new Telemetry(); - this._telemetry.toolOpened("webide"); - - AppManager.init(); - - this.appManagerUpdate = this.appManagerUpdate.bind(this); - AppManager.on("app-manager-update", this.appManagerUpdate); - - Cmds.showProjectPanel(); - Cmds.showRuntimePanel(); - - this.updateCommands(); - - this.onfocus = this.onfocus.bind(this); - window.addEventListener("focus", this.onfocus, true); - - AppProjects.load().then(() => { - this.autoSelectProject(); - }, e => { - console.error(e); - this.reportError("error_appProjectsLoadFailed"); - }); - - // Auto install the ADB Addon Helper and Tools Adapters. Only once. - // If the user decides to uninstall any of this addon, we won't install it again. - let autoinstallADBHelper = Services.prefs.getBoolPref("devtools.webide.autoinstallADBHelper"); - let autoinstallFxdtAdapters = Services.prefs.getBoolPref("devtools.webide.autoinstallFxdtAdapters"); - if (autoinstallADBHelper) { - GetAvailableAddons().then(addons => { - addons.adb.install(); - }, console.error); - } - if (autoinstallFxdtAdapters) { - GetAvailableAddons().then(addons => { - addons.adapters.install(); - }, console.error); - } - Services.prefs.setBoolPref("devtools.webide.autoinstallADBHelper", false); - Services.prefs.setBoolPref("devtools.webide.autoinstallFxdtAdapters", false); - - if (Services.prefs.getBoolPref("devtools.webide.widget.autoinstall") && - !Services.prefs.getBoolPref("devtools.webide.widget.enabled")) { - Services.prefs.setBoolPref("devtools.webide.widget.enabled", true); - gDevToolsBrowser.moveWebIDEWidgetInNavbar(); - } - - this.setupDeck(); - - this.contentViewer = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .contentViewer; - this.contentViewer.fullZoom = Services.prefs.getCharPref("devtools.webide.zoom"); - - gDevToolsBrowser.isWebIDEInitialized.resolve(); - - this.configureSimulator = this.configureSimulator.bind(this); - Simulators.on("configure", this.configureSimulator); - }, - - destroy: function () { - window.removeEventListener("focus", this.onfocus, true); - AppManager.off("app-manager-update", this.appManagerUpdate); - AppManager.destroy(); - Simulators.off("configure", this.configureSimulator); - this.updateConnectionTelemetry(); - this._telemetry.toolClosed("webide"); - this._telemetry.toolClosed("webideProjectEditor"); - this._telemetry.destroy(); - }, - - canCloseProject: function () { - if (this.projecteditor) { - return this.projecteditor.confirmUnsaved(); - } - return true; - }, - - onfocus: function () { - // Because we can't track the activity in the folder project, - // we need to validate the project regularly. Let's assume that - // if a modification happened, it happened when the window was - // not focused. - if (AppManager.selectedProject && - AppManager.selectedProject.type != "mainProcess" && - AppManager.selectedProject.type != "runtimeApp" && - AppManager.selectedProject.type != "tab") { - AppManager.validateAndUpdateProject(AppManager.selectedProject); - } - - // Hook to display promotional Developer Edition doorhanger. Only displayed once. - // Hooked into the `onfocus` event because sometimes does not work - // when run at the end of `init`. ¯\(°_o)/¯ - showDoorhanger({ window, type: "deveditionpromo", anchor: document.querySelector("#deck") }); - }, - - appManagerUpdate: function (event, what, details) { - // Got a message from app-manager.js - // See AppManager.update() for descriptions of what these events mean. - switch (what) { - case "runtime-list": - this.autoConnectRuntime(); - break; - case "connection": - this.updateRuntimeButton(); - this.updateCommands(); - this.updateConnectionTelemetry(); - break; - case "before-project": - if (!this.canCloseProject()) { - details.cancel(); - } - break; - case "project": - this._updatePromise = Task.spawn(function* () { - UI.updateTitle(); - yield UI.destroyToolbox(); - UI.updateCommands(); - UI.openProject(); - yield UI.autoStartProject(); - UI.autoOpenToolbox(); - UI.saveLastSelectedProject(); - UI.updateRemoveProjectButton(); - }); - return; - case "project-started": - this.updateCommands(); - UI.autoOpenToolbox(); - break; - case "project-stopped": - UI.destroyToolbox(); - this.updateCommands(); - break; - case "runtime-global-actors": - // Check runtime version only on runtime-global-actors, - // as we expect to use device actor - this.checkRuntimeVersion(); - this.updateCommands(); - break; - case "runtime-details": - this.updateRuntimeButton(); - break; - case "runtime": - this.updateRuntimeButton(); - this.saveLastConnectedRuntime(); - break; - case "project-validated": - this.updateTitle(); - this.updateCommands(); - this.updateProjectEditorHeader(); - break; - case "install-progress": - this.updateProgress(Math.round(100 * details.bytesSent / details.totalBytes)); - break; - case "runtime-targets": - this.autoSelectProject(); - break; - case "pre-package": - this.prePackageLog(details); - break; - } - this._updatePromise = promise.resolve(); - }, - - configureSimulator: function (event, simulator) { - UI.selectDeckPanel("simulator"); - }, - - openInBrowser: function (url) { - // Open a URL in a Firefox window - let mainWindow = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType); - if (mainWindow) { - mainWindow.openUILinkIn(url, "tab"); - mainWindow.focus() - } else { - window.open(url); - } - }, - - updateTitle: function () { - let project = AppManager.selectedProject; - if (project) { - window.document.title = Strings.formatStringFromName("title_app", [project.name], 1); - } else { - window.document.title = Strings.GetStringFromName("title_noApp"); - } - }, - - /** ******** BUSY UI **********/ - - _busyTimeout: null, - _busyOperationDescription: null, - _busyPromise: null, - - updateProgress: function (percent) { - let progress = document.querySelector("#action-busy-determined"); - progress.mode = "determined"; - progress.value = percent; - this.setupBusyTimeout(); - }, - - busy: function () { - let win = document.querySelector("window"); - win.classList.add("busy"); - win.classList.add("busy-undetermined"); - this.updateCommands(); - this.update("busy"); - }, - - unbusy: function () { - let win = document.querySelector("window"); - win.classList.remove("busy"); - win.classList.remove("busy-determined"); - win.classList.remove("busy-undetermined"); - this.updateCommands(); - this.update("unbusy"); - this._busyPromise = null; - }, - - setupBusyTimeout: function () { - this.cancelBusyTimeout(); - this._busyTimeout = setTimeout(() => { - this.unbusy(); - UI.reportError("error_operationTimeout", this._busyOperationDescription); - }, Services.prefs.getIntPref("devtools.webide.busyTimeout")); - }, - - cancelBusyTimeout: function () { - clearTimeout(this._busyTimeout); - }, - - busyWithProgressUntil: function (promise, operationDescription) { - let busy = this.busyUntil(promise, operationDescription); - let win = document.querySelector("window"); - let progress = document.querySelector("#action-busy-determined"); - progress.mode = "undetermined"; - win.classList.add("busy-determined"); - win.classList.remove("busy-undetermined"); - return busy; - }, - - busyUntil: function (promise, operationDescription) { - // Freeze the UI until the promise is resolved. A timeout will unfreeze the - // UI, just in case the promise never gets resolved. - this._busyPromise = promise; - this._busyOperationDescription = operationDescription; - this.setupBusyTimeout(); - this.busy(); - promise.then(() => { - this.cancelBusyTimeout(); - this.unbusy(); - }, (e) => { - let message; - if (e && e.error && e.message) { - // Some errors come from fronts that are not based on protocol.js. - // Errors are not translated to strings. - message = operationDescription + " (" + e.error + "): " + e.message; - } else { - message = operationDescription + (e ? (": " + e) : ""); - } - this.cancelBusyTimeout(); - let operationCanceled = e && e.canceled; - if (!operationCanceled) { - UI.reportError("error_operationFail", message); - if (e) { - console.error(e); - } - } - this.unbusy(); - }); - return promise; - }, - - reportError: function (l10nProperty, ...l10nArgs) { - let text; - - if (l10nArgs.length > 0) { - text = Strings.formatStringFromName(l10nProperty, l10nArgs, l10nArgs.length); - } else { - text = Strings.GetStringFromName(l10nProperty); - } - - console.error(text); - - let buttons = [{ - label: Strings.GetStringFromName("notification_showTroubleShooting_label"), - accessKey: Strings.GetStringFromName("notification_showTroubleShooting_accesskey"), - callback: function () { - Cmds.showTroubleShooting(); - } - }]; - - let nbox = document.querySelector("#notificationbox"); - nbox.removeAllNotifications(true); - nbox.appendNotification(text, "webide:errornotification", null, - nbox.PRIORITY_WARNING_LOW, buttons); - }, - - dismissErrorNotification: function () { - let nbox = document.querySelector("#notificationbox"); - nbox.removeAllNotifications(true); - }, - - /** ******** COMMANDS **********/ - - /** - * This module emits various events when state changes occur. - * - * The events this module may emit include: - * busy: - * The window is currently busy and certain UI functions may be disabled. - * unbusy: - * The window is not busy and certain UI functions may be re-enabled. - */ - update: function (what, details) { - this.emit("webide-update", what, details); - }, - - updateCommands: function () { - // Action commands - let playCmd = document.querySelector("#cmd_play"); - let stopCmd = document.querySelector("#cmd_stop"); - let debugCmd = document.querySelector("#cmd_toggleToolbox"); - let playButton = document.querySelector("#action-button-play"); - let projectPanelCmd = document.querySelector("#cmd_showProjectPanel"); - - if (document.querySelector("window").classList.contains("busy")) { - playCmd.setAttribute("disabled", "true"); - stopCmd.setAttribute("disabled", "true"); - debugCmd.setAttribute("disabled", "true"); - projectPanelCmd.setAttribute("disabled", "true"); - return; - } - - if (!AppManager.selectedProject || !AppManager.connected) { - playCmd.setAttribute("disabled", "true"); - stopCmd.setAttribute("disabled", "true"); - debugCmd.setAttribute("disabled", "true"); - } else { - let isProjectRunning = AppManager.isProjectRunning(); - if (isProjectRunning) { - playButton.classList.add("reload"); - stopCmd.removeAttribute("disabled"); - debugCmd.removeAttribute("disabled"); - } else { - playButton.classList.remove("reload"); - stopCmd.setAttribute("disabled", "true"); - debugCmd.setAttribute("disabled", "true"); - } - - // If connected and a project is selected - if (AppManager.selectedProject.type == "runtimeApp") { - playCmd.removeAttribute("disabled"); - } else if (AppManager.selectedProject.type == "tab") { - playCmd.removeAttribute("disabled"); - stopCmd.setAttribute("disabled", "true"); - } else if (AppManager.selectedProject.type == "mainProcess") { - playCmd.setAttribute("disabled", "true"); - stopCmd.setAttribute("disabled", "true"); - } else { - if (AppManager.selectedProject.errorsCount == 0 && - AppManager.runtimeCanHandleApps()) { - playCmd.removeAttribute("disabled"); - } else { - playCmd.setAttribute("disabled", "true"); - } - } - } - - // Runtime commands - let monitorCmd = document.querySelector("#cmd_showMonitor"); - let screenshotCmd = document.querySelector("#cmd_takeScreenshot"); - let permissionsCmd = document.querySelector("#cmd_showPermissionsTable"); - let detailsCmd = document.querySelector("#cmd_showRuntimeDetails"); - let disconnectCmd = document.querySelector("#cmd_disconnectRuntime"); - let devicePrefsCmd = document.querySelector("#cmd_showDevicePrefs"); - let settingsCmd = document.querySelector("#cmd_showSettings"); - - if (AppManager.connected) { - if (AppManager.deviceFront) { - monitorCmd.removeAttribute("disabled"); - detailsCmd.removeAttribute("disabled"); - permissionsCmd.removeAttribute("disabled"); - screenshotCmd.removeAttribute("disabled"); - } - if (AppManager.preferenceFront) { - devicePrefsCmd.removeAttribute("disabled"); - } - if (AppManager.settingsFront) { - settingsCmd.removeAttribute("disabled"); - } - disconnectCmd.removeAttribute("disabled"); - } else { - monitorCmd.setAttribute("disabled", "true"); - detailsCmd.setAttribute("disabled", "true"); - permissionsCmd.setAttribute("disabled", "true"); - screenshotCmd.setAttribute("disabled", "true"); - disconnectCmd.setAttribute("disabled", "true"); - devicePrefsCmd.setAttribute("disabled", "true"); - settingsCmd.setAttribute("disabled", "true"); - } - - let runtimePanelButton = document.querySelector("#runtime-panel-button"); - - if (AppManager.connected) { - runtimePanelButton.setAttribute("active", "true"); - runtimePanelButton.removeAttribute("hidden"); - } else { - runtimePanelButton.removeAttribute("active"); - runtimePanelButton.setAttribute("hidden", "true"); - } - - projectPanelCmd.removeAttribute("disabled"); - }, - - updateRemoveProjectButton: function () { - // Remove command - let removeCmdNode = document.querySelector("#cmd_removeProject"); - if (AppManager.selectedProject) { - removeCmdNode.removeAttribute("disabled"); - } else { - removeCmdNode.setAttribute("disabled", "true"); - } - }, - - /** ******** RUNTIME **********/ - - get lastConnectedRuntime() { - return Services.prefs.getCharPref("devtools.webide.lastConnectedRuntime"); - }, - - set lastConnectedRuntime(runtime) { - Services.prefs.setCharPref("devtools.webide.lastConnectedRuntime", runtime); - }, - - autoConnectRuntime: function () { - // Automatically reconnect to the previously selected runtime, - // if available and has an ID and feature is enabled - if (AppManager.selectedRuntime || - !Services.prefs.getBoolPref("devtools.webide.autoConnectRuntime") || - !this.lastConnectedRuntime) { - return; - } - let [_, type, id] = this.lastConnectedRuntime.match(/^(\w+):(.+)$/); - - type = type.toLowerCase(); - - // Local connection is mapped to AppManager.runtimeList.other array - if (type == "local") { - type = "other"; - } - - // We support most runtimes except simulator, that needs to be manually - // launched - if (type == "usb" || type == "wifi" || type == "other") { - for (let runtime of AppManager.runtimeList[type]) { - // Some runtimes do not expose an id and don't support autoconnect (like - // remote connection) - if (runtime.id == id) { - // Only want one auto-connect attempt, so clear last runtime value - this.lastConnectedRuntime = ""; - this.connectToRuntime(runtime); - } - } - } - }, - - connectToRuntime: function (runtime) { - let name = runtime.name; - let promise = AppManager.connectToRuntime(runtime); - promise.then(() => this.initConnectionTelemetry()) - .catch(() => { - // Empty rejection handler to silence uncaught rejection warnings - // |busyUntil| will listen for rejections. - // Bug 1121100 may find a better way to silence these. - }); - promise = this.busyUntil(promise, "Connecting to " + name); - // Stop busy timeout for runtimes that take unknown or long amounts of time - // to connect. - if (runtime.prolongedConnection) { - this.cancelBusyTimeout(); - } - return promise; - }, - - updateRuntimeButton: function () { - let labelNode = document.querySelector("#runtime-panel-button > .panel-button-label"); - if (!AppManager.selectedRuntime) { - labelNode.setAttribute("value", Strings.GetStringFromName("runtimeButton_label")); - } else { - let name = AppManager.selectedRuntime.name; - labelNode.setAttribute("value", name); - } - }, - - saveLastConnectedRuntime: function () { - if (AppManager.selectedRuntime && - AppManager.selectedRuntime.id !== undefined) { - this.lastConnectedRuntime = AppManager.selectedRuntime.type + ":" + - AppManager.selectedRuntime.id; - } else { - this.lastConnectedRuntime = ""; - } - }, - - /** ******** ACTIONS **********/ - - _actionsToLog: new Set(), - - /** - * For each new connection, track whether play and debug were ever used. Only - * one value is collected for each button, even if they are used multiple - * times during a connection. - */ - initConnectionTelemetry: function () { - this._actionsToLog.add("play"); - this._actionsToLog.add("debug"); - }, - - /** - * Action occurred. Log that it happened, and remove it from the loggable - * set. - */ - onAction: function (action) { - if (!this._actionsToLog.has(action)) { - return; - } - this.logActionState(action, true); - this._actionsToLog.delete(action); - }, - - /** - * Connection status changed or we are shutting down. Record any loggable - * actions as having not occurred. - */ - updateConnectionTelemetry: function () { - for (let action of this._actionsToLog.values()) { - this.logActionState(action, false); - } - this._actionsToLog.clear(); - }, - - logActionState: function (action, state) { - let histogramId = "DEVTOOLS_WEBIDE_CONNECTION_" + - action.toUpperCase() + "_USED"; - this._telemetry.log(histogramId, state); - }, - - /** ******** PROJECTS **********/ - - // ProjectEditor & details screen - - destroyProjectEditor: function () { - if (this.projecteditor) { - this.projecteditor.destroy(); - this.projecteditor = null; - } - }, - - /** - * Called when selecting or deselecting the project editor panel. - */ - onChangeProjectEditorSelected: function () { - if (this.projecteditor) { - let panel = document.querySelector("#deck").selectedPanel; - if (panel && panel.id == "deck-panel-projecteditor") { - this.projecteditor.menuEnabled = true; - this._telemetry.toolOpened("webideProjectEditor"); - } else { - this.projecteditor.menuEnabled = false; - this._telemetry.toolClosed("webideProjectEditor"); - } - } - }, - - getProjectEditor: function () { - if (this.projecteditor) { - return this.projecteditor.loaded; - } - - let projecteditorIframe = document.querySelector("#deck-panel-projecteditor"); - this.projecteditor = ProjectEditor.ProjectEditor(projecteditorIframe, { - menubar: document.querySelector("#main-menubar"), - menuindex: 1 - }); - this.projecteditor.on("onEditorSave", () => { - AppManager.validateAndUpdateProject(AppManager.selectedProject); - this._telemetry.actionOccurred("webideProjectEditorSave"); - }); - return this.projecteditor.loaded; - }, - - updateProjectEditorHeader: function () { - let project = AppManager.selectedProject; - if (!project || !this.projecteditor) { - return; - } - let status = project.validationStatus || "unknown"; - if (status == "error warning") { - status = "error"; - } - this.getProjectEditor().then((projecteditor) => { - projecteditor.setProjectToAppPath(project.location, { - name: project.name, - iconUrl: project.icon, - projectOverviewURL: "chrome://webide/content/details.xhtml", - validationStatus: status - }).then(null, console.error); - }, console.error); - }, - - isProjectEditorEnabled: function () { - return Services.prefs.getBoolPref("devtools.webide.showProjectEditor"); - }, - - openProject: function () { - let project = AppManager.selectedProject; - - // Nothing to show - - if (!project) { - this.resetDeck(); - return; - } - - // Make sure the directory exist before we show Project Editor - - let forceDetailsOnly = false; - if (project.type == "packaged") { - forceDetailsOnly = !utils.doesFileExist(project.location); - } - - // Show only the details screen - - if (project.type != "packaged" || - !this.isProjectEditorEnabled() || - forceDetailsOnly) { - this.selectDeckPanel("details"); - return; - } - - // Show ProjectEditor - - this.getProjectEditor().then(() => { - this.updateProjectEditorHeader(); - }, console.error); - - this.selectDeckPanel("projecteditor"); - }, - - autoStartProject: Task.async(function* () { - let project = AppManager.selectedProject; - - if (!project) { - return; - } - if (!(project.type == "runtimeApp" || - project.type == "mainProcess" || - project.type == "tab")) { - return; // For something that is not an editable app, we're done. - } - - // Do not force opening apps that are already running, as they may have - // some activity being opened and don't want to dismiss them. - if (project.type == "runtimeApp" && !AppManager.isProjectRunning()) { - yield UI.busyUntil(AppManager.launchRuntimeApp(), "running app"); - } - }), - - autoOpenToolbox: Task.async(function* () { - let project = AppManager.selectedProject; - - if (!project) { - return; - } - if (!(project.type == "runtimeApp" || - project.type == "mainProcess" || - project.type == "tab")) { - return; // For something that is not an editable app, we're done. - } - - yield UI.createToolbox(); - }), - - importAndSelectApp: Task.async(function* (source) { - let isPackaged = !!source.path; - let project; - try { - project = yield AppProjects[isPackaged ? "addPackaged" : "addHosted"](source); - } catch (e) { - if (e === "Already added") { - // Select project that's already been added, - // and allow it to be revalidated and selected - project = AppProjects.get(isPackaged ? source.path : source); - } else { - throw e; - } - } - - // Select project - AppManager.selectedProject = project; - - this._telemetry.actionOccurred("webideImportProject"); - }), - - // Remember the last selected project on the runtime - saveLastSelectedProject: function () { - let shouldRestore = Services.prefs.getBoolPref("devtools.webide.restoreLastProject"); - if (!shouldRestore) { - return; - } - - // Ignore unselection of project on runtime disconnection - if (!AppManager.connected) { - return; - } - - let project = "", type = ""; - let selected = AppManager.selectedProject; - if (selected) { - if (selected.type == "runtimeApp") { - type = "runtimeApp"; - project = selected.app.manifestURL; - } else if (selected.type == "mainProcess") { - type = "mainProcess"; - } else if (selected.type == "packaged" || - selected.type == "hosted") { - type = "local"; - project = selected.location; - } - } - if (type) { - Services.prefs.setCharPref("devtools.webide.lastSelectedProject", - type + ":" + project); - } else { - Services.prefs.clearUserPref("devtools.webide.lastSelectedProject"); - } - }, - - autoSelectProject: function () { - if (AppManager.selectedProject) { - return; - } - let shouldRestore = Services.prefs.getBoolPref("devtools.webide.restoreLastProject"); - if (!shouldRestore) { - return; - } - let pref = Services.prefs.getCharPref("devtools.webide.lastSelectedProject"); - if (!pref) { - return; - } - let m = pref.match(/^(\w+):(.*)$/); - if (!m) { - return; - } - let [_, type, project] = m; - - if (type == "local") { - let lastProject = AppProjects.get(project); - if (lastProject) { - AppManager.selectedProject = lastProject; - } - } - - // For other project types, we need to be connected to the runtime - if (!AppManager.connected) { - return; - } - - if (type == "mainProcess" && AppManager.isMainProcessDebuggable()) { - AppManager.selectedProject = { - type: "mainProcess", - name: Strings.GetStringFromName("mainProcess_label"), - icon: AppManager.DEFAULT_PROJECT_ICON - }; - } else if (type == "runtimeApp") { - let app = AppManager.apps.get(project); - if (app) { - AppManager.selectedProject = { - type: "runtimeApp", - app: app.manifest, - icon: app.iconURL, - name: app.manifest.name - }; - } - } - }, - - /** ******** DECK **********/ - - setupDeck: function () { - let iframes = document.querySelectorAll("#deck > iframe"); - for (let iframe of iframes) { - iframe.tooltip = "aHTMLTooltip"; - } - }, - - resetFocus: function () { - document.commandDispatcher.focusedElement = document.documentElement; - }, - - selectDeckPanel: function (id) { - let deck = document.querySelector("#deck"); - if (deck.selectedPanel && deck.selectedPanel.id === "deck-panel-" + id) { - // This panel is already displayed. - return; - } - this.resetFocus(); - let panel = deck.querySelector("#deck-panel-" + id); - let lazysrc = panel.getAttribute("lazysrc"); - if (lazysrc) { - panel.removeAttribute("lazysrc"); - panel.setAttribute("src", lazysrc); - } - deck.selectedPanel = panel; - this.onChangeProjectEditorSelected(); - }, - - resetDeck: function () { - this.resetFocus(); - let deck = document.querySelector("#deck"); - deck.selectedPanel = null; - this.onChangeProjectEditorSelected(); - }, - - buildIDToDate(buildID) { - let fields = buildID.match(/(\d{4})(\d{2})(\d{2})/); - // Date expects 0 - 11 for months - return new Date(fields[1], Number.parseInt(fields[2]) - 1, fields[3]); - }, - - checkRuntimeVersion: Task.async(function* () { - if (AppManager.connected && AppManager.deviceFront) { - let desc = yield AppManager.deviceFront.getDescription(); - // Compare device and firefox build IDs - // and only compare by day (strip hours/minutes) to prevent - // warning against builds of the same day. - let deviceID = desc.appbuildid.substr(0, 8); - let localID = Services.appinfo.appBuildID.substr(0, 8); - let deviceDate = this.buildIDToDate(deviceID); - let localDate = this.buildIDToDate(localID); - // Allow device to be newer by up to a week. This accommodates those with - // local device builds, since their devices will almost always be newer - // than the client. - if (deviceDate - localDate > 7 * MS_PER_DAY) { - this.reportError("error_runtimeVersionTooRecent", deviceID, localID); - } - } - }), - - /** ******** TOOLBOX **********/ - - /** - * There are many ways to close a toolbox: - * * Close button inside the toolbox - * * Toggle toolbox wrench in WebIDE - * * Disconnect the current runtime gracefully - * * Yank cord out of device - * * Close or crash the app/tab - * We can't know for sure which one was used here, so reset the - * |toolboxPromise| since someone must be destroying it to reach here, - * and call our own close method. - */ - _onToolboxClosed: function (promise, iframe) { - // Only save toolbox size, disable wrench button, workaround focus issue... - // if we are closing the last toolbox: - // - toolboxPromise is nullified by destroyToolbox and is still null here - // if no other toolbox has been opened in between, - // - having two distinct promise means we are receiving closed event - // for a previous, non-current, toolbox. - if (!this.toolboxPromise || this.toolboxPromise === promise) { - this.toolboxPromise = null; - this.resetFocus(); - Services.prefs.setIntPref("devtools.toolbox.footer.height", iframe.height); - - let splitter = document.querySelector(".devtools-horizontal-splitter"); - splitter.setAttribute("hidden", "true"); - document.querySelector("#action-button-debug").removeAttribute("active"); - } - // We have to destroy the iframe, otherwise, the keybindings of webide don't work - // properly anymore. - iframe.remove(); - }, - - destroyToolbox: function () { - // Only have a live toolbox if |this.toolboxPromise| exists - if (this.toolboxPromise) { - let toolboxPromise = this.toolboxPromise; - this.toolboxPromise = null; - return toolboxPromise.then(toolbox => toolbox.destroy()); - } - return promise.resolve(); - }, - - createToolbox: function () { - // If |this.toolboxPromise| exists, there is already a live toolbox - if (this.toolboxPromise) { - return this.toolboxPromise; - } - - let iframe = document.createElement("iframe"); - iframe.id = "toolbox"; - - // Compute a uid on the iframe in order to identify toolbox iframe - // when receiving toolbox-close event - iframe.uid = new Date().getTime(); - - let height = Services.prefs.getIntPref("devtools.toolbox.footer.height"); - iframe.height = height; - - let promise = this.toolboxPromise = AppManager.getTarget().then(target => { - return this._showToolbox(target, iframe); - }).then(toolbox => { - // Destroy the toolbox on WebIDE side before - // toolbox.destroy's promise resolves. - toolbox.once("destroyed", this._onToolboxClosed.bind(this, promise, iframe)); - return toolbox; - }, console.error); - - return this.busyUntil(this.toolboxPromise, "opening toolbox"); - }, - - _showToolbox: function (target, iframe) { - let splitter = document.querySelector(".devtools-horizontal-splitter"); - splitter.removeAttribute("hidden"); - - document.querySelector("notificationbox").insertBefore(iframe, splitter.nextSibling); - let host = Toolbox.HostType.CUSTOM; - let options = { customIframe: iframe, zoom: false, uid: iframe.uid }; - - document.querySelector("#action-button-debug").setAttribute("active", "true"); - - return gDevTools.showToolbox(target, null, host, options); - }, - - prePackageLog: function (msg) { - if (msg == "start") { - UI.selectDeckPanel("logs"); - } - } -}; - -EventEmitter.decorate(UI); - -var Cmds = { - quit: function () { - if (UI.canCloseProject()) { - window.close(); - } - }, - - showProjectPanel: function () { - ProjectPanel.toggleSidebar(); - return promise.resolve(); - }, - - showRuntimePanel: function () { - RuntimeScanners.scan(); - RuntimePanel.toggleSidebar(); - }, - - disconnectRuntime: function () { - let disconnecting = Task.spawn(function* () { - yield UI.destroyToolbox(); - yield AppManager.disconnectRuntime(); - }); - return UI.busyUntil(disconnecting, "disconnecting from runtime"); - }, - - takeScreenshot: function () { - let url = AppManager.deviceFront.screenshotToDataURL(); - return UI.busyUntil(url.then(longstr => { - return longstr.string().then(dataURL => { - longstr.release().then(null, console.error); - UI.openInBrowser(dataURL); - }); - }), "taking screenshot"); - }, - - showPermissionsTable: function () { - UI.selectDeckPanel("permissionstable"); - }, - - showRuntimeDetails: function () { - UI.selectDeckPanel("runtimedetails"); - }, - - showDevicePrefs: function () { - UI.selectDeckPanel("devicepreferences"); - }, - - showSettings: function () { - UI.selectDeckPanel("devicesettings"); - }, - - showMonitor: function () { - UI.selectDeckPanel("monitor"); - }, - - play: Task.async(function* () { - let busy; - switch (AppManager.selectedProject.type) { - case "packaged": - let autosave = - Services.prefs.getBoolPref("devtools.webide.autosaveFiles"); - if (autosave && UI.projecteditor) { - yield UI.projecteditor.saveAllFiles(); - } - busy = UI.busyWithProgressUntil(AppManager.installAndRunProject(), - "installing and running app"); - break; - case "hosted": - busy = UI.busyUntil(AppManager.installAndRunProject(), - "installing and running app"); - break; - case "runtimeApp": - busy = UI.busyUntil(AppManager.launchOrReloadRuntimeApp(), "launching / reloading app"); - break; - case "tab": - busy = UI.busyUntil(AppManager.reloadTab(), "reloading tab"); - break; - } - if (!busy) { - return promise.reject(); - } - UI.onAction("play"); - return busy; - }), - - stop: function () { - return UI.busyUntil(AppManager.stopRunningApp(), "stopping app"); - }, - - toggleToolbox: function () { - UI.onAction("debug"); - if (UI.toolboxPromise) { - UI.destroyToolbox(); - return promise.resolve(); - } else { - return UI.createToolbox(); - } - }, - - removeProject: function () { - AppManager.removeSelectedProject(); - }, - - toggleEditors: function () { - let isNowEnabled = !UI.isProjectEditorEnabled(); - Services.prefs.setBoolPref("devtools.webide.showProjectEditor", isNowEnabled); - if (!isNowEnabled) { - UI.destroyProjectEditor(); - } - UI.openProject(); - }, - - showTroubleShooting: function () { - UI.openInBrowser(HELP_URL); - }, - - showAddons: function () { - UI.selectDeckPanel("addons"); - }, - - showPrefs: function () { - UI.selectDeckPanel("prefs"); - }, - - zoomIn: function () { - if (UI.contentViewer.fullZoom < MAX_ZOOM) { - UI.contentViewer.fullZoom += 0.1; - Services.prefs.setCharPref("devtools.webide.zoom", UI.contentViewer.fullZoom); - } - }, - - zoomOut: function () { - if (UI.contentViewer.fullZoom > MIN_ZOOM) { - UI.contentViewer.fullZoom -= 0.1; - Services.prefs.setCharPref("devtools.webide.zoom", UI.contentViewer.fullZoom); - } - }, - - resetZoom: function () { - UI.contentViewer.fullZoom = 1; - Services.prefs.setCharPref("devtools.webide.zoom", 1); - } -}; diff --git a/devtools/client/webide/content/webide.xul b/devtools/client/webide/content/webide.xul deleted file mode 100644 index a3e4355b9..000000000 --- a/devtools/client/webide/content/webide.xul +++ /dev/null @@ -1,178 +0,0 @@ -<?xml version="1.0"?> - -<!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - -<!DOCTYPE window [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?> - -<?xml-stylesheet href="chrome://global/skin/global.css"?> -<?xml-stylesheet href="resource://devtools/client/themes/common.css"?> -<?xml-stylesheet href="chrome://webide/skin/webide.css"?> - -<window id="webide" onclose="return UI.canCloseProject();" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:html="http://www.w3.org/1999/xhtml" - title="&windowTitle;" - windowtype="devtools:webide" - macanimationtype="document" - fullscreenbutton="true" - screenX="4" screenY="4" - width="800" height="600" - persist="screenX screenY width height sizemode"> - - <script type="application/javascript" src="chrome://global/content/globalOverlay.js"></script> - <script type="application/javascript" src="project-panel.js"></script> - <script type="application/javascript" src="runtime-panel.js"></script> - <script type="application/javascript" src="webide.js"></script> - - <commandset id="mainCommandSet"> - <commandset id="editMenuCommands"/> - <commandset id="webideCommands"> - <command id="cmd_quit" oncommand="Cmds.quit()"/> - <command id="cmd_newApp" oncommand="Cmds.newApp()" label="&projectMenu_newApp_label;"/> - <command id="cmd_importPackagedApp" oncommand="Cmds.importPackagedApp()" label="&projectMenu_importPackagedApp_label;"/> - <command id="cmd_importHostedApp" oncommand="Cmds.importHostedApp()" label="&projectMenu_importHostedApp_label;"/> - <command id="cmd_showDevicePrefs" label="&runtimeMenu_showDevicePrefs_label;" oncommand="Cmds.showDevicePrefs()"/> - <command id="cmd_showSettings" label="&runtimeMenu_showSettings_label;" oncommand="Cmds.showSettings()"/> - <command id="cmd_removeProject" oncommand="Cmds.removeProject()" label="&projectMenu_remove_label;"/> - <command id="cmd_showProjectPanel" oncommand="Cmds.showProjectPanel()"/> - <command id="cmd_showRuntimePanel" oncommand="Cmds.showRuntimePanel()"/> - <command id="cmd_disconnectRuntime" oncommand="Cmds.disconnectRuntime()" label="&runtimeMenu_disconnect_label;"/> - <command id="cmd_showMonitor" oncommand="Cmds.showMonitor()" label="&runtimeMenu_showMonitor_label;"/> - <command id="cmd_showPermissionsTable" oncommand="Cmds.showPermissionsTable()" label="&runtimeMenu_showPermissionTable_label;"/> - <command id="cmd_showRuntimeDetails" oncommand="Cmds.showRuntimeDetails()" label="&runtimeMenu_showDetails_label;"/> - <command id="cmd_takeScreenshot" oncommand="Cmds.takeScreenshot()" label="&runtimeMenu_takeScreenshot_label;"/> - <command id="cmd_toggleEditor" oncommand="Cmds.toggleEditors()" label="&viewMenu_toggleEditor_label;"/> - <command id="cmd_showAddons" oncommand="Cmds.showAddons()"/> - <command id="cmd_showPrefs" oncommand="Cmds.showPrefs()"/> - <command id="cmd_showTroubleShooting" oncommand="Cmds.showTroubleShooting()"/> - <command id="cmd_play" oncommand="Cmds.play()"/> - <command id="cmd_stop" oncommand="Cmds.stop()" label="&projectMenu_stop_label;"/> - <command id="cmd_toggleToolbox" oncommand="Cmds.toggleToolbox()"/> - <command id="cmd_zoomin" label="&viewMenu_zoomin_label;" oncommand="Cmds.zoomIn()"/> - <command id="cmd_zoomout" label="&viewMenu_zoomout_label;" oncommand="Cmds.zoomOut()"/> - <command id="cmd_resetzoom" label="&viewMenu_resetzoom_label;" oncommand="Cmds.resetZoom()"/> - </commandset> - </commandset> - - <menubar id="main-menubar"> - <menu id="menu-project" label="&projectMenu_label;" accesskey="&projectMenu_accesskey;"> - <menupopup id="menu-project-popup"> - <menuitem command="cmd_newApp" accesskey="&projectMenu_newApp_accesskey;"/> - <menuitem command="cmd_importPackagedApp" accesskey="&projectMenu_importPackagedApp_accesskey;"/> - <menuitem command="cmd_importHostedApp" accesskey="&projectMenu_importHostedApp_accesskey;"/> - <menuitem id="menuitem-show_projectPanel" command="cmd_showProjectPanel" key="key_showProjectPanel" label="&projectMenu_selectApp_label;" accesskey="&projectMenu_selectApp_accesskey;"/> - <menuseparator/> - <menuitem command="cmd_play" key="key_play" label="&projectMenu_play_label;" accesskey="&projectMenu_play_accesskey;"/> - <menuitem command="cmd_stop" accesskey="&projectMenu_stop_accesskey;"/> - <menuitem command="cmd_toggleToolbox" key="key_toggleToolbox" label="&projectMenu_debug_label;" accesskey="&projectMenu_debug_accesskey;"/> - <menuseparator/> - <menuitem command="cmd_removeProject" accesskey="&projectMenu_remove_accesskey;"/> - <menuseparator/> - <menuitem command="cmd_showPrefs" label="&projectMenu_showPrefs_label;" accesskey="&projectMenu_showPrefs_accesskey;"/> - <menuitem command="cmd_showAddons" label="&projectMenu_manageComponents_label;" accesskey="&projectMenu_manageComponents_accesskey;"/> - </menupopup> - </menu> - - <menu id="menu-runtime" label="&runtimeMenu_label;" accesskey="&runtimeMenu_accesskey;"> - <menupopup id="menu-runtime-popup"> - <menuitem command="cmd_showMonitor" accesskey="&runtimeMenu_showMonitor_accesskey;"/> - <menuitem command="cmd_takeScreenshot" accesskey="&runtimeMenu_takeScreenshot_accesskey;"/> - <menuitem command="cmd_showPermissionsTable" accesskey="&runtimeMenu_showPermissionTable_accesskey;"/> - <menuitem command="cmd_showRuntimeDetails" accesskey="&runtimeMenu_showDetails_accesskey;"/> - <menuitem command="cmd_showDevicePrefs" accesskey="&runtimeMenu_showDevicePrefs_accesskey;"/> - <menuitem command="cmd_showSettings" accesskey="&runtimeMenu_showSettings_accesskey;"/> - <menuseparator/> - <menuitem command="cmd_disconnectRuntime" accesskey="&runtimeMenu_disconnect_accesskey;"/> - </menupopup> - </menu> - - <menu id="menu-view" label="&viewMenu_label;" accesskey="&viewMenu_accesskey;"> - <menupopup id="menu-ViewPopup"> - <menuitem command="cmd_toggleEditor" key="key_toggleEditor" accesskey="&viewMenu_toggleEditor_accesskey;"/> - <menuseparator/> - <menuitem command="cmd_zoomin" key="key_zoomin" accesskey="&viewMenu_zoomin_accesskey;"/> - <menuitem command="cmd_zoomout" key="key_zoomout" accesskey="&viewMenu_zoomout_accesskey;"/> - <menuitem command="cmd_resetzoom" key="key_resetzoom" accesskey="&viewMenu_resetzoom_accesskey;"/> - </menupopup> - </menu> - - </menubar> - - <keyset id="mainKeyset"> - <key key="&key_quit;" id="key_quit" command="cmd_quit" modifiers="accel"/> - <key key="&key_showProjectPanel;" id="key_showProjectPanel" command="cmd_showProjectPanel" modifiers="accel"/> - <key key="&key_play;" id="key_play" command="cmd_play" modifiers="accel"/> - <key key="&key_toggleEditor;" id="key_toggleEditor" command="cmd_toggleEditor" modifiers="accel"/> - <key keycode="&key_toggleToolbox;" id="key_toggleToolbox" command="cmd_toggleToolbox"/> - <key key="&key_zoomin;" id="key_zoomin" command="cmd_zoomin" modifiers="accel"/> - <key key="&key_zoomin2;" id="key_zoomin2" command="cmd_zoomin" modifiers="accel"/> - <key key="&key_zoomout;" id="key_zoomout" command="cmd_zoomout" modifiers="accel"/> - <key key="&key_resetzoom;" id="key_resetzoom" command="cmd_resetzoom" modifiers="accel"/> - </keyset> - - <tooltip id="aHTMLTooltip" page="true"/> - - <toolbar id="main-toolbar"> - - <vbox flex="1"> - <hbox id="action-buttons-container" class="busy"> - <toolbarbutton id="action-button-play" class="action-button" command="cmd_play" tooltiptext="&projectMenu_play_label;"/> - <toolbarbutton id="action-button-stop" class="action-button" command="cmd_stop" tooltiptext="&projectMenu_stop_label;"/> - <toolbarbutton id="action-button-debug" class="action-button" command="cmd_toggleToolbox" tooltiptext="&projectMenu_debug_label;"/> - <hbox id="action-busy" align="center"> - <html:img id="action-busy-undetermined" src="chrome://webide/skin/throbber.svg"/> - <progressmeter id="action-busy-determined"/> - </hbox> - </hbox> - - <hbox id="panel-buttons-container"> - <spacer flex="1"/> - <toolbarbutton id="runtime-panel-button" class="panel-button"> - <image class="panel-button-image"/> - <label class="panel-button-label" value="&runtimeButton_label;"/> - </toolbarbutton> - </hbox> - - </vbox> - </toolbar> - - <notificationbox flex="1" id="notificationbox"> - <div flex="1" id="deck-panels"> - <vbox id="project-listing-panel" class="project-listing panel-list" flex="1"> - <div id="project-listing-wrapper" class="panel-list-wrapper"> - <iframe id="project-listing-panel-details" flex="1" src="project-listing.xhtml" tooltip="aHTMLTooltip"/> - </div> - </vbox> - <splitter class="devtools-side-splitter" id="project-listing-splitter"/> - <deck flex="1" id="deck" selectedIndex="-1"> - <iframe id="deck-panel-details" flex="1" src="details.xhtml"/> - <iframe id="deck-panel-projecteditor" flex="1"/> - <iframe id="deck-panel-addons" flex="1" src="addons.xhtml"/> - <iframe id="deck-panel-prefs" flex="1" src="prefs.xhtml"/> - <iframe id="deck-panel-permissionstable" flex="1" lazysrc="permissionstable.xhtml"/> - <iframe id="deck-panel-runtimedetails" flex="1" lazysrc="runtimedetails.xhtml"/> - <iframe id="deck-panel-monitor" flex="1" lazysrc="monitor.xhtml"/> - <iframe id="deck-panel-devicepreferences" flex="1" lazysrc="devicepreferences.xhtml"/> - <iframe id="deck-panel-devicesettings" flex="1" lazysrc="devicesettings.xhtml"/> - <iframe id="deck-panel-logs" flex="1" src="logs.xhtml"/> - <iframe id="deck-panel-simulator" flex="1" lazysrc="simulator.xhtml"/> - </deck> - <splitter class="devtools-side-splitter" id="runtime-listing-splitter"/> - <vbox id="runtime-listing-panel" class="runtime-listing panel-list" flex="1"> - <div id="runtime-listing-wrapper" class="panel-list-wrapper"> - <iframe id="runtime-listing-panel-details" flex="1" src="runtime-listing.xhtml" tooltip="aHTMLTooltip"/> - </div> - </vbox> - </div> - <splitter hidden="true" class="devtools-horizontal-splitter" orient="vertical"/> - <!-- toolbox iframe will be inserted here --> - </notificationbox> - -</window> diff --git a/devtools/client/webide/content/wifi-auth.js b/devtools/client/webide/content/wifi-auth.js deleted file mode 100644 index 5ae5d824c..000000000 --- a/devtools/client/webide/content/wifi-auth.js +++ /dev/null @@ -1,44 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -var Cu = Components.utils; -const { require } = - Cu.import("resource://devtools/shared/Loader.jsm", {}); -const Services = require("Services"); -const QR = require("devtools/shared/qrcode/index"); - -window.addEventListener("load", function onLoad() { - window.removeEventListener("load", onLoad); - document.getElementById("close").onclick = () => window.close(); - document.getElementById("no-scanner").onclick = showToken; - document.getElementById("yes-scanner").onclick = hideToken; - buildUI(); -}); - -function buildUI() { - let { oob } = window.arguments[0]; - createQR(oob); - createToken(oob); -} - -function createQR(oob) { - let oobData = JSON.stringify(oob); - let imgData = QR.encodeToDataURI(oobData, "L" /* low quality */); - document.querySelector("#qr-code img").src = imgData.src; -} - -function createToken(oob) { - let token = oob.sha256.replace(/:/g, "").toLowerCase() + oob.k; - document.querySelector("#token pre").textContent = token; -} - -function showToken() { - document.querySelector("body").setAttribute("token", "true"); -} - -function hideToken() { - document.querySelector("body").removeAttribute("token"); -} diff --git a/devtools/client/webide/content/wifi-auth.xhtml b/devtools/client/webide/content/wifi-auth.xhtml deleted file mode 100644 index cfeec3c96..000000000 --- a/devtools/client/webide/content/wifi-auth.xhtml +++ /dev/null @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- 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/. --> - -<!DOCTYPE html [ - <!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" > - %webideDTD; -]> - -<html id="devtools:wifi-auth" xmlns="http://www.w3.org/1999/xhtml"> - <head> - <meta charset="utf8"/> - <link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/> - <link rel="stylesheet" href="chrome://webide/skin/wifi-auth.css" type="text/css"/> - <script type="application/javascript;version=1.8" src="chrome://webide/content/wifi-auth.js"></script> - </head> - <body> - - <div id="controls"> - <a id="close">&deck_close;</a> - </div> - - <h3 id="header">&wifi_auth_header;</h3> - <div id="scan-request">&wifi_auth_scan_request;</div> - - <div id="qr-code"> - <div id="qr-code-wrapper"> - <img/> - </div> - <a id="no-scanner" class="toggle-scanner">&wifi_auth_no_scanner;</a> - <div id="qr-size-note"> - <h5>&wifi_auth_qr_size_note;</h5> - </div> - </div> - - <div id="token"> - <div>&wifi_auth_token_request;</div> - <pre id="token-value"/> - <a id="yes-scanner" class="toggle-scanner">&wifi_auth_yes_scanner;</a> - </div> - - </body> -</html> diff --git a/devtools/client/webide/modules/addons.js b/devtools/client/webide/modules/addons.js deleted file mode 100644 index 4dc09f1ca..000000000 --- a/devtools/client/webide/modules/addons.js +++ /dev/null @@ -1,197 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const promise = require("promise"); -const {AddonManager} = require("resource://gre/modules/AddonManager.jsm"); -const Services = require("Services"); -const {getJSON} = require("devtools/client/shared/getjson"); -const EventEmitter = require("devtools/shared/event-emitter"); - -const ADDONS_URL = "devtools.webide.addonsURL"; - -var SIMULATOR_LINK = Services.prefs.getCharPref("devtools.webide.simulatorAddonsURL"); -var ADB_LINK = Services.prefs.getCharPref("devtools.webide.adbAddonURL"); -var ADAPTERS_LINK = Services.prefs.getCharPref("devtools.webide.adaptersAddonURL"); -var SIMULATOR_ADDON_ID = Services.prefs.getCharPref("devtools.webide.simulatorAddonID"); -var ADB_ADDON_ID = Services.prefs.getCharPref("devtools.webide.adbAddonID"); -var ADAPTERS_ADDON_ID = Services.prefs.getCharPref("devtools.webide.adaptersAddonID"); - -var platform = Services.appShell.hiddenDOMWindow.navigator.platform; -var OS = ""; -if (platform.indexOf("Win") != -1) { - OS = "win32"; -} else if (platform.indexOf("Mac") != -1) { - OS = "mac64"; -} else if (platform.indexOf("Linux") != -1) { - if (platform.indexOf("x86_64") != -1) { - OS = "linux64"; - } else { - OS = "linux32"; - } -} - -var addonsListener = {}; -addonsListener.onEnabled = -addonsListener.onDisabled = -addonsListener.onInstalled = -addonsListener.onUninstalled = (updatedAddon) => { - GetAvailableAddons().then(addons => { - for (let a of [...addons.simulators, addons.adb, addons.adapters]) { - if (a.addonID == updatedAddon.id) { - a.updateInstallStatus(); - } - } - }); -}; -AddonManager.addAddonListener(addonsListener); - -var GetAvailableAddons_promise = null; -var GetAvailableAddons = exports.GetAvailableAddons = function () { - if (!GetAvailableAddons_promise) { - let deferred = promise.defer(); - GetAvailableAddons_promise = deferred.promise; - let addons = { - simulators: [], - adb: null - }; - getJSON(ADDONS_URL).then(json => { - for (let stability in json) { - for (let version of json[stability]) { - addons.simulators.push(new SimulatorAddon(stability, version)); - } - } - addons.adb = new ADBAddon(); - addons.adapters = new AdaptersAddon(); - deferred.resolve(addons); - }, e => { - GetAvailableAddons_promise = null; - deferred.reject(e); - }); - } - return GetAvailableAddons_promise; -}; - -exports.ForgetAddonsList = function () { - GetAvailableAddons_promise = null; -}; - -function Addon() {} -Addon.prototype = { - _status: "unknown", - set status(value) { - if (this._status != value) { - this._status = value; - this.emit("update"); - } - }, - get status() { - return this._status; - }, - - updateInstallStatus: function () { - AddonManager.getAddonByID(this.addonID, (addon) => { - if (addon && !addon.userDisabled) { - this.status = "installed"; - } else { - this.status = "uninstalled"; - } - }); - }, - - install: function () { - AddonManager.getAddonByID(this.addonID, (addon) => { - if (addon && !addon.userDisabled) { - this.status = "installed"; - return; - } - this.status = "preparing"; - if (addon && addon.userDisabled) { - addon.userDisabled = false; - } else { - AddonManager.getInstallForURL(this.xpiLink, (install) => { - install.addListener(this); - install.install(); - }, "application/x-xpinstall"); - } - }); - }, - - uninstall: function () { - AddonManager.getAddonByID(this.addonID, (addon) => { - addon.uninstall(); - }); - }, - - installFailureHandler: function (install, message) { - this.status = "uninstalled"; - this.emit("failure", message); - }, - - onDownloadStarted: function () { - this.status = "downloading"; - }, - - onInstallStarted: function () { - this.status = "installing"; - }, - - onDownloadProgress: function (install) { - if (install.maxProgress == -1) { - this.emit("progress", -1); - } else { - this.emit("progress", install.progress / install.maxProgress); - } - }, - - onInstallEnded: function ({addon}) { - addon.userDisabled = false; - }, - - onDownloadCancelled: function (install) { - this.installFailureHandler(install, "Download cancelled"); - }, - onDownloadFailed: function (install) { - this.installFailureHandler(install, "Download failed"); - }, - onInstallCancelled: function (install) { - this.installFailureHandler(install, "Install cancelled"); - }, - onInstallFailed: function (install) { - this.installFailureHandler(install, "Install failed"); - }, -}; - -function SimulatorAddon(stability, version) { - EventEmitter.decorate(this); - this.stability = stability; - this.version = version; - // This addon uses the string "linux" for "linux32" - let fixedOS = OS == "linux32" ? "linux" : OS; - this.xpiLink = SIMULATOR_LINK.replace(/#OS#/g, fixedOS) - .replace(/#VERSION#/g, version) - .replace(/#SLASHED_VERSION#/g, version.replace(/\./g, "_")); - this.addonID = SIMULATOR_ADDON_ID.replace(/#SLASHED_VERSION#/g, version.replace(/\./g, "_")); - this.updateInstallStatus(); -} -SimulatorAddon.prototype = Object.create(Addon.prototype); - -function ADBAddon() { - EventEmitter.decorate(this); - // This addon uses the string "linux" for "linux32" - let fixedOS = OS == "linux32" ? "linux" : OS; - this.xpiLink = ADB_LINK.replace(/#OS#/g, fixedOS); - this.addonID = ADB_ADDON_ID; - this.updateInstallStatus(); -} -ADBAddon.prototype = Object.create(Addon.prototype); - -function AdaptersAddon() { - EventEmitter.decorate(this); - this.xpiLink = ADAPTERS_LINK.replace(/#OS#/g, OS); - this.addonID = ADAPTERS_ADDON_ID; - this.updateInstallStatus(); -} -AdaptersAddon.prototype = Object.create(Addon.prototype); diff --git a/devtools/client/webide/modules/app-manager.js b/devtools/client/webide/modules/app-manager.js deleted file mode 100644 index 88dfcdd44..000000000 --- a/devtools/client/webide/modules/app-manager.js +++ /dev/null @@ -1,850 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {Cu} = require("chrome"); - -const promise = require("promise"); -const {TargetFactory} = require("devtools/client/framework/target"); -const Services = require("Services"); -const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {}); -const EventEmitter = require("devtools/shared/event-emitter"); -const {TextEncoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {}); -const {AppProjects} = require("devtools/client/webide/modules/app-projects"); -const TabStore = require("devtools/client/webide/modules/tab-store"); -const {AppValidator} = require("devtools/client/webide/modules/app-validator"); -const {ConnectionManager, Connection} = require("devtools/shared/client/connection-manager"); -const {AppActorFront} = require("devtools/shared/apps/app-actor-front"); -const {getDeviceFront} = require("devtools/shared/fronts/device"); -const {getPreferenceFront} = require("devtools/shared/fronts/preference"); -const {getSettingsFront} = require("devtools/shared/fronts/settings"); -const {Task} = require("devtools/shared/task"); -const {RuntimeScanners, RuntimeTypes} = require("devtools/client/webide/modules/runtimes"); -const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {}); -const Telemetry = require("devtools/client/shared/telemetry"); -const {ProjectBuilding} = require("./build"); - -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -var AppManager = exports.AppManager = { - - DEFAULT_PROJECT_ICON: "chrome://webide/skin/default-app-icon.png", - DEFAULT_PROJECT_NAME: "--", - - _initialized: false, - - init: function () { - if (this._initialized) { - return; - } - this._initialized = true; - - let port = Services.prefs.getIntPref("devtools.debugger.remote-port"); - this.connection = ConnectionManager.createConnection("localhost", port); - this.onConnectionChanged = this.onConnectionChanged.bind(this); - this.connection.on(Connection.Events.STATUS_CHANGED, this.onConnectionChanged); - - this.tabStore = new TabStore(this.connection); - this.onTabList = this.onTabList.bind(this); - this.onTabNavigate = this.onTabNavigate.bind(this); - this.onTabClosed = this.onTabClosed.bind(this); - this.tabStore.on("tab-list", this.onTabList); - this.tabStore.on("navigate", this.onTabNavigate); - this.tabStore.on("closed", this.onTabClosed); - - this._clearRuntimeList(); - this._rebuildRuntimeList = this._rebuildRuntimeList.bind(this); - RuntimeScanners.on("runtime-list-updated", this._rebuildRuntimeList); - RuntimeScanners.enable(); - this._rebuildRuntimeList(); - - this.onInstallProgress = this.onInstallProgress.bind(this); - - this._telemetry = new Telemetry(); - }, - - destroy: function () { - if (!this._initialized) { - return; - } - this._initialized = false; - - this.selectedProject = null; - this.selectedRuntime = null; - RuntimeScanners.off("runtime-list-updated", this._rebuildRuntimeList); - RuntimeScanners.disable(); - this.runtimeList = null; - this.tabStore.off("tab-list", this.onTabList); - this.tabStore.off("navigate", this.onTabNavigate); - this.tabStore.off("closed", this.onTabClosed); - this.tabStore.destroy(); - this.tabStore = null; - this.connection.off(Connection.Events.STATUS_CHANGED, this.onConnectionChanged); - this._listTabsResponse = null; - this.connection.disconnect(); - this.connection = null; - }, - - /** - * This module emits various events when state changes occur. The basic event - * naming scheme is that event "X" means "X has changed" or "X is available". - * Some names are more detailed to clarify their precise meaning. - * - * The events this module may emit include: - * before-project: - * The selected project is about to change. The event includes a special - * |cancel| callback that will abort the project change if desired. - * connection: - * The connection status has changed (connected, disconnected, etc.) - * install-progress: - * A project being installed to a runtime has made further progress. This - * event contains additional details about exactly how far the process is - * when such information is available. - * project: - * The selected project has changed. - * project-started: - * The selected project started running on the connected runtime. - * project-stopped: - * The selected project stopped running on the connected runtime. - * project-removed: - * The selected project was removed from the project list. - * project-validated: - * The selected project just completed validation. As part of validation, - * many pieces of metadata about the project are refreshed, including its - * name, manifest details, etc. - * runtime: - * The selected runtime has changed. - * runtime-apps-icons: - * The list of URLs for the runtime app icons are available. - * runtime-global-actors: - * The list of global actors for the entire runtime (but not actors for a - * specific tab or app) are now available, so we can test for features - * like preferences and settings. - * runtime-details: - * The selected runtime's details have changed, such as its user-visible - * name. - * runtime-list: - * The list of available runtimes has changed, or any of the user-visible - * details (like names) for the non-selected runtimes has changed. - * runtime-telemetry: - * Detailed runtime telemetry has been recorded. Used by tests. - * runtime-targets: - * The list of remote runtime targets available from the currently - * connected runtime (such as tabs or apps) has changed, or any of the - * user-visible details (like names) for the non-selected runtime targets - * has changed. This event includes |type| in the details, to distinguish - * "apps" and "tabs". - */ - update: function (what, details) { - // Anything we want to forward to the UI - this.emit("app-manager-update", what, details); - }, - - reportError: function (l10nProperty, ...l10nArgs) { - let win = Services.wm.getMostRecentWindow("devtools:webide"); - if (win) { - win.UI.reportError(l10nProperty, ...l10nArgs); - } else { - let text; - if (l10nArgs.length > 0) { - text = Strings.formatStringFromName(l10nProperty, l10nArgs, l10nArgs.length); - } else { - text = Strings.GetStringFromName(l10nProperty); - } - console.error(text); - } - }, - - onConnectionChanged: function () { - console.log("Connection status changed: " + this.connection.status); - - if (this.connection.status == Connection.Status.DISCONNECTED) { - this.selectedRuntime = null; - } - - if (!this.connected) { - if (this._appsFront) { - this._appsFront.off("install-progress", this.onInstallProgress); - this._appsFront.unwatchApps(); - this._appsFront = null; - } - this._listTabsResponse = null; - } else { - this.connection.client.listTabs((response) => { - if (response.webappsActor) { - let front = new AppActorFront(this.connection.client, - response); - front.on("install-progress", this.onInstallProgress); - front.watchApps(() => this.checkIfProjectIsRunning()) - .then(() => { - // This can't be done earlier as many operations - // in the apps actor require watchApps to be called - // first. - this._appsFront = front; - this._listTabsResponse = response; - this._recordRuntimeInfo(); - this.update("runtime-global-actors"); - }) - .then(() => { - this.checkIfProjectIsRunning(); - this.update("runtime-targets", { type: "apps" }); - front.fetchIcons().then(() => this.update("runtime-apps-icons")); - }); - } else { - this._listTabsResponse = response; - this._recordRuntimeInfo(); - this.update("runtime-global-actors"); - } - }); - } - - this.update("connection"); - }, - - get connected() { - return this.connection && - this.connection.status == Connection.Status.CONNECTED; - }, - - get apps() { - if (this._appsFront) { - return this._appsFront.apps; - } else { - return new Map(); - } - }, - - onInstallProgress: function (event, details) { - this.update("install-progress", details); - }, - - isProjectRunning: function () { - if (this.selectedProject.type == "mainProcess" || - this.selectedProject.type == "tab") { - return true; - } - - let app = this._getProjectFront(this.selectedProject); - return app && app.running; - }, - - checkIfProjectIsRunning: function () { - if (this.selectedProject) { - if (this.isProjectRunning()) { - this.update("project-started"); - } else { - this.update("project-stopped"); - } - } - }, - - listTabs: function () { - return this.tabStore.listTabs(); - }, - - onTabList: function () { - this.update("runtime-targets", { type: "tabs" }); - }, - - // TODO: Merge this into TabProject as part of project-agnostic work - onTabNavigate: function () { - this.update("runtime-targets", { type: "tabs" }); - if (this.selectedProject.type !== "tab") { - return; - } - let tab = this.selectedProject.app = this.tabStore.selectedTab; - let uri = NetUtil.newURI(tab.url); - // Wanted to use nsIFaviconService here, but it only works for visited - // tabs, so that's no help for any remote tabs. Maybe some favicon wizard - // knows how to get high-res favicons easily, or we could offer actor - // support for this (bug 1061654). - tab.favicon = uri.prePath + "/favicon.ico"; - tab.name = tab.title || Strings.GetStringFromName("project_tab_loading"); - if (uri.scheme.startsWith("http")) { - tab.name = uri.host + ": " + tab.name; - } - this.selectedProject.location = tab.url; - this.selectedProject.name = tab.name; - this.selectedProject.icon = tab.favicon; - this.update("project-validated"); - }, - - onTabClosed: function () { - if (this.selectedProject.type !== "tab") { - return; - } - this.selectedProject = null; - }, - - reloadTab: function () { - if (this.selectedProject && this.selectedProject.type != "tab") { - return promise.reject("tried to reload non-tab project"); - } - return this.getTarget().then(target => { - target.activeTab.reload(); - }, console.error.bind(console)); - }, - - getTarget: function () { - if (this.selectedProject.type == "mainProcess") { - // Fx >=39 exposes a ChromeActor to debug the main process - if (this.connection.client.mainRoot.traits.allowChromeProcess) { - return this.connection.client.getProcess() - .then(aResponse => { - return TargetFactory.forRemoteTab({ - form: aResponse.form, - client: this.connection.client, - chrome: true - }); - }); - } else { - // Fx <39 exposes tab actors on the root actor - return TargetFactory.forRemoteTab({ - form: this._listTabsResponse, - client: this.connection.client, - chrome: true, - isTabActor: false - }); - } - } - - if (this.selectedProject.type == "tab") { - return this.tabStore.getTargetForTab(); - } - - let app = this._getProjectFront(this.selectedProject); - if (!app) { - return promise.reject("Can't find app front for selected project"); - } - - return Task.spawn(function* () { - // Once we asked the app to launch, the app isn't necessary completely loaded. - // launch request only ask the app to launch and immediatly returns. - // We have to keep trying to get app tab actors required to create its target. - - for (let i = 0; i < 10; i++) { - try { - return yield app.getTarget(); - } catch (e) {} - let deferred = promise.defer(); - setTimeout(deferred.resolve, 500); - yield deferred.promise; - } - - AppManager.reportError("error_cantConnectToApp", app.manifest.manifestURL); - throw new Error("can't connect to app"); - }); - }, - - getProjectManifestURL: function (project) { - let manifest = null; - if (project.type == "runtimeApp") { - manifest = project.app.manifestURL; - } - - if (project.type == "hosted") { - manifest = project.location; - } - - if (project.type == "packaged" && project.packagedAppOrigin) { - manifest = "app://" + project.packagedAppOrigin + "/manifest.webapp"; - } - - return manifest; - }, - - _getProjectFront: function (project) { - let manifest = this.getProjectManifestURL(project); - if (manifest && this._appsFront) { - return this._appsFront.apps.get(manifest); - } - return null; - }, - - _selectedProject: null, - set selectedProject(project) { - // A regular comparison doesn't work as we recreate a new object every time - let prev = this._selectedProject; - if (!prev && !project) { - return; - } else if (prev && project && prev.type === project.type) { - let type = project.type; - if (type === "runtimeApp") { - if (prev.app.manifestURL === project.app.manifestURL) { - return; - } - } else if (type === "tab") { - if (prev.app.actor === project.app.actor) { - return; - } - } else if (type === "packaged" || type === "hosted") { - if (prev.location === project.location) { - return; - } - } else if (type === "mainProcess") { - return; - } else { - throw new Error("Unsupported project type: " + type); - } - } - - let cancelled = false; - this.update("before-project", { cancel: () => { cancelled = true; } }); - if (cancelled) { - return; - } - - this._selectedProject = project; - - // Clear out tab store's selected state, if any - this.tabStore.selectedTab = null; - - if (project) { - if (project.type == "packaged" || - project.type == "hosted") { - this.validateAndUpdateProject(project); - } - if (project.type == "tab") { - this.tabStore.selectedTab = project.app; - } - } - - this.update("project"); - this.checkIfProjectIsRunning(); - }, - get selectedProject() { - return this._selectedProject; - }, - - removeSelectedProject: Task.async(function* () { - let location = this.selectedProject.location; - AppManager.selectedProject = null; - // If the user cancels the removeProject operation, don't remove the project - if (AppManager.selectedProject != null) { - return; - } - - yield AppProjects.remove(location); - AppManager.update("project-removed"); - }), - - packageProject: Task.async(function* (project) { - if (!project) { - return; - } - if (project.type == "packaged" || - project.type == "hosted") { - yield ProjectBuilding.build({ - project: project, - logger: this.update.bind(this, "pre-package") - }); - } - }), - - _selectedRuntime: null, - set selectedRuntime(value) { - this._selectedRuntime = value; - if (!value && this.selectedProject && - (this.selectedProject.type == "mainProcess" || - this.selectedProject.type == "runtimeApp" || - this.selectedProject.type == "tab")) { - this.selectedProject = null; - } - this.update("runtime"); - }, - - get selectedRuntime() { - return this._selectedRuntime; - }, - - connectToRuntime: function (runtime) { - - if (this.connected && this.selectedRuntime === runtime) { - // Already connected - return promise.resolve(); - } - - let deferred = promise.defer(); - - this.disconnectRuntime().then(() => { - this.selectedRuntime = runtime; - - let onConnectedOrDisconnected = () => { - this.connection.off(Connection.Events.CONNECTED, onConnectedOrDisconnected); - this.connection.off(Connection.Events.DISCONNECTED, onConnectedOrDisconnected); - if (this.connected) { - deferred.resolve(); - } else { - deferred.reject(); - } - }; - this.connection.on(Connection.Events.CONNECTED, onConnectedOrDisconnected); - this.connection.on(Connection.Events.DISCONNECTED, onConnectedOrDisconnected); - try { - // Reset the connection's state to defaults - this.connection.resetOptions(); - // Only watch for errors here. Final resolution occurs above, once - // we've reached the CONNECTED state. - this.selectedRuntime.connect(this.connection) - .then(null, e => deferred.reject(e)); - } catch (e) { - deferred.reject(e); - } - }, deferred.reject); - - // Record connection result in telemetry - let logResult = result => { - this._telemetry.log("DEVTOOLS_WEBIDE_CONNECTION_RESULT", result); - if (runtime.type) { - this._telemetry.log("DEVTOOLS_WEBIDE_" + runtime.type + - "_CONNECTION_RESULT", result); - } - }; - deferred.promise.then(() => logResult(true), () => logResult(false)); - - // If successful, record connection time in telemetry - deferred.promise.then(() => { - const timerId = "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS"; - this._telemetry.startTimer(timerId); - this.connection.once(Connection.Events.STATUS_CHANGED, () => { - this._telemetry.stopTimer(timerId); - }); - }).catch(() => { - // Empty rejection handler to silence uncaught rejection warnings - // |connectToRuntime| caller should listen for rejections. - // Bug 1121100 may find a better way to silence these. - }); - - return deferred.promise; - }, - - _recordRuntimeInfo: Task.async(function* () { - if (!this.connected) { - return; - } - let runtime = this.selectedRuntime; - this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE", - runtime.type || "UNKNOWN", true); - this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID", - runtime.id || "unknown", true); - if (!this.deviceFront) { - this.update("runtime-telemetry"); - return; - } - let d = yield this.deviceFront.getDescription(); - this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PROCESSOR", - d.processor, true); - this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_OS", - d.os, true); - this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PLATFORM_VERSION", - d.platformversion, true); - this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_APP_TYPE", - d.apptype, true); - this._telemetry.logKeyed("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_VERSION", - d.version, true); - this.update("runtime-telemetry"); - }), - - isMainProcessDebuggable: function () { - // Fx <39 exposes chrome tab actors on RootActor - // Fx >=39 exposes a dedicated actor via getProcess request - return this.connection.client && - this.connection.client.mainRoot && - this.connection.client.mainRoot.traits.allowChromeProcess || - (this._listTabsResponse && - this._listTabsResponse.consoleActor); - }, - - get deviceFront() { - if (!this._listTabsResponse) { - return null; - } - return getDeviceFront(this.connection.client, this._listTabsResponse); - }, - - get preferenceFront() { - if (!this._listTabsResponse) { - return null; - } - return getPreferenceFront(this.connection.client, this._listTabsResponse); - }, - - get settingsFront() { - if (!this._listTabsResponse) { - return null; - } - return getSettingsFront(this.connection.client, this._listTabsResponse); - }, - - disconnectRuntime: function () { - if (!this.connected) { - return promise.resolve(); - } - let deferred = promise.defer(); - this.connection.once(Connection.Events.DISCONNECTED, () => deferred.resolve()); - this.connection.disconnect(); - return deferred.promise; - }, - - launchRuntimeApp: function () { - if (this.selectedProject && this.selectedProject.type != "runtimeApp") { - return promise.reject("attempting to launch a non-runtime app"); - } - let app = this._getProjectFront(this.selectedProject); - return app.launch(); - }, - - launchOrReloadRuntimeApp: function () { - if (this.selectedProject && this.selectedProject.type != "runtimeApp") { - return promise.reject("attempting to launch / reload a non-runtime app"); - } - let app = this._getProjectFront(this.selectedProject); - if (!app.running) { - return app.launch(); - } else { - return app.reload(); - } - }, - - runtimeCanHandleApps: function () { - return !!this._appsFront; - }, - - installAndRunProject: function () { - let project = this.selectedProject; - - if (!project || (project.type != "packaged" && project.type != "hosted")) { - console.error("Can't install project. Unknown type of project."); - return promise.reject("Can't install"); - } - - if (!this._listTabsResponse) { - this.reportError("error_cantInstallNotFullyConnected"); - return promise.reject("Can't install"); - } - - if (!this._appsFront) { - console.error("Runtime doesn't have a webappsActor"); - return promise.reject("Can't install"); - } - - return Task.spawn(function* () { - let self = AppManager; - - // Package and validate project - yield self.packageProject(project); - yield self.validateAndUpdateProject(project); - - if (project.errorsCount > 0) { - self.reportError("error_cantInstallValidationErrors"); - return; - } - - let installPromise; - - if (project.type != "packaged" && project.type != "hosted") { - return promise.reject("Don't know how to install project"); - } - - let response; - if (project.type == "packaged") { - let packageDir = yield ProjectBuilding.getPackageDir(project); - console.log("Installing app from " + packageDir); - - response = yield self._appsFront.installPackaged(packageDir, - project.packagedAppOrigin); - - // If the packaged app specified a custom origin override, - // we need to update the local project origin - project.packagedAppOrigin = response.appId; - // And ensure the indexed db on disk is also updated - AppProjects.update(project); - } - - if (project.type == "hosted") { - let manifestURLObject = Services.io.newURI(project.location, null, null); - let origin = Services.io.newURI(manifestURLObject.prePath, null, null); - let appId = origin.host; - let metadata = { - origin: origin.spec, - manifestURL: project.location - }; - response = yield self._appsFront.installHosted(appId, - metadata, - project.manifest); - } - - // Addons don't have any document to load (yet?) - // So that there is no need to run them, installing is enough - if (project.manifest.manifest_version || project.manifest.role === "addon") { - return; - } - - let {app} = response; - if (!app.running) { - let deferred = promise.defer(); - self.on("app-manager-update", function onUpdate(event, what) { - if (what == "project-started") { - self.off("app-manager-update", onUpdate); - deferred.resolve(); - } - }); - yield app.launch(); - yield deferred.promise; - } else { - yield app.reload(); - } - }); - }, - - stopRunningApp: function () { - let app = this._getProjectFront(this.selectedProject); - return app.close(); - }, - - /* PROJECT VALIDATION */ - - validateAndUpdateProject: function (project) { - if (!project) { - return promise.reject(); - } - - return Task.spawn(function* () { - - let packageDir = yield ProjectBuilding.getPackageDir(project); - let validation = new AppValidator({ - type: project.type, - // Build process may place the manifest in a non-root directory - location: packageDir - }); - - yield validation.validate(); - - if (validation.manifest) { - let manifest = validation.manifest; - let iconPath; - if (manifest.icons) { - let size = Object.keys(manifest.icons).sort((a, b) => b - a)[0]; - if (size) { - iconPath = manifest.icons[size]; - } - } - if (!iconPath) { - project.icon = AppManager.DEFAULT_PROJECT_ICON; - } else { - if (project.type == "hosted") { - let manifestURL = Services.io.newURI(project.location, null, null); - let origin = Services.io.newURI(manifestURL.prePath, null, null); - project.icon = Services.io.newURI(iconPath, null, origin).spec; - } else if (project.type == "packaged") { - let projectFolder = FileUtils.File(packageDir); - let folderURI = Services.io.newFileURI(projectFolder).spec; - project.icon = folderURI + iconPath.replace(/^\/|\\/, ""); - } - } - project.manifest = validation.manifest; - - if ("name" in project.manifest) { - project.name = project.manifest.name; - } else { - project.name = AppManager.DEFAULT_PROJECT_NAME; - } - } else { - project.manifest = null; - project.icon = AppManager.DEFAULT_PROJECT_ICON; - project.name = AppManager.DEFAULT_PROJECT_NAME; - } - - project.validationStatus = "valid"; - - if (validation.warnings.length > 0) { - project.warningsCount = validation.warnings.length; - project.warnings = validation.warnings; - project.validationStatus = "warning"; - } else { - project.warnings = ""; - project.warningsCount = 0; - } - - if (validation.errors.length > 0) { - project.errorsCount = validation.errors.length; - project.errors = validation.errors; - project.validationStatus = "error"; - } else { - project.errors = ""; - project.errorsCount = 0; - } - - if (project.warningsCount && project.errorsCount) { - project.validationStatus = "error warning"; - } - - if (project.type === "hosted" && project.location !== validation.manifestURL) { - yield AppProjects.updateLocation(project, validation.manifestURL); - } else if (AppProjects.get(project.location)) { - yield AppProjects.update(project); - } - - if (AppManager.selectedProject === project) { - AppManager.update("project-validated"); - } - }); - }, - - /* RUNTIME LIST */ - - _clearRuntimeList: function () { - this.runtimeList = { - usb: [], - wifi: [], - simulator: [], - other: [] - }; - }, - - _rebuildRuntimeList: function () { - let runtimes = RuntimeScanners.listRuntimes(); - this._clearRuntimeList(); - - // Reorganize runtimes by type - for (let runtime of runtimes) { - switch (runtime.type) { - case RuntimeTypes.USB: - this.runtimeList.usb.push(runtime); - break; - case RuntimeTypes.WIFI: - this.runtimeList.wifi.push(runtime); - break; - case RuntimeTypes.SIMULATOR: - this.runtimeList.simulator.push(runtime); - break; - default: - this.runtimeList.other.push(runtime); - } - } - - this.update("runtime-details"); - this.update("runtime-list"); - }, - - /* MANIFEST UTILS */ - - writeManifest: function (project) { - if (project.type != "packaged") { - return promise.reject("Not a packaged app"); - } - - if (!project.manifest) { - project.manifest = {}; - } - - let folder = project.location; - let manifestPath = OS.Path.join(folder, "manifest.webapp"); - let text = JSON.stringify(project.manifest, null, 2); - let encoder = new TextEncoder(); - let array = encoder.encode(text); - return OS.File.writeAtomic(manifestPath, array, {tmpPath: manifestPath + ".tmp"}); - }, -}; - -EventEmitter.decorate(AppManager); diff --git a/devtools/client/webide/modules/app-projects.js b/devtools/client/webide/modules/app-projects.js deleted file mode 100644 index 691d09064..000000000 --- a/devtools/client/webide/modules/app-projects.js +++ /dev/null @@ -1,235 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {Cc, Ci, Cu, Cr} = require("chrome"); -const promise = require("promise"); - -const EventEmitter = require("devtools/shared/event-emitter"); -const {generateUUID} = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); -const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {}); - -/** - * IndexedDB wrapper that just save project objects - * - * The only constraint is that project objects have to have - * a unique `location` object. - */ - -const IDB = { - _db: null, - databaseName: "AppProjects", - - open: function () { - let deferred = promise.defer(); - - let request = indexedDB.open(IDB.databaseName, 5); - request.onerror = function (event) { - deferred.reject("Unable to open AppProjects indexedDB: " + - this.error.name + " - " + this.error.message); - }; - request.onupgradeneeded = function (event) { - let db = event.target.result; - db.createObjectStore("projects", { keyPath: "location" }); - }; - - request.onsuccess = function () { - let db = IDB._db = request.result; - let objectStore = db.transaction("projects").objectStore("projects"); - let projects = []; - let toRemove = []; - objectStore.openCursor().onsuccess = function (event) { - let cursor = event.target.result; - if (cursor) { - if (cursor.value.location) { - - // We need to make sure this object has a `.location` property. - // The UI depends on this property. - // This should not be needed as we make sure to register valid - // projects, but in the past (before bug 924568), we might have - // registered invalid objects. - - - // We also want to make sure the location is valid. - // If the location doesn't exist, we remove the project. - - try { - let file = FileUtils.File(cursor.value.location); - if (file.exists()) { - projects.push(cursor.value); - } else { - toRemove.push(cursor.value.location); - } - } catch (e) { - if (e.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH) { - // A URL - projects.push(cursor.value); - } - } - } - cursor.continue(); - } else { - let removePromises = []; - for (let location of toRemove) { - removePromises.push(IDB.remove(location)); - } - promise.all(removePromises).then(() => { - deferred.resolve(projects); - }); - } - }; - }; - - return deferred.promise; - }, - - add: function (project) { - let deferred = promise.defer(); - - if (!project.location) { - // We need to make sure this object has a `.location` property. - deferred.reject("Missing location property on project object."); - } else { - let transaction = IDB._db.transaction(["projects"], "readwrite"); - let objectStore = transaction.objectStore("projects"); - let request = objectStore.add(project); - request.onerror = function (event) { - deferred.reject("Unable to add project to the AppProjects indexedDB: " + - this.error.name + " - " + this.error.message); - }; - request.onsuccess = function () { - deferred.resolve(); - }; - } - - return deferred.promise; - }, - - update: function (project) { - let deferred = promise.defer(); - - var transaction = IDB._db.transaction(["projects"], "readwrite"); - var objectStore = transaction.objectStore("projects"); - var request = objectStore.put(project); - request.onerror = function (event) { - deferred.reject("Unable to update project to the AppProjects indexedDB: " + - this.error.name + " - " + this.error.message); - }; - request.onsuccess = function () { - deferred.resolve(); - }; - - return deferred.promise; - }, - - remove: function (location) { - let deferred = promise.defer(); - - let request = IDB._db.transaction(["projects"], "readwrite") - .objectStore("projects") - .delete(location); - request.onsuccess = function (event) { - deferred.resolve(); - }; - request.onerror = function () { - deferred.reject("Unable to delete project to the AppProjects indexedDB: " + - this.error.name + " - " + this.error.message); - }; - - return deferred.promise; - } -}; - -var loadDeferred = promise.defer(); - -loadDeferred.resolve(IDB.open().then(function (projects) { - AppProjects.projects = projects; - AppProjects.emit("ready", projects); -})); - -const AppProjects = { - load: function () { - return loadDeferred.promise; - }, - - addPackaged: function (folder) { - let file = FileUtils.File(folder.path); - if (!file.exists()) { - return promise.reject("path doesn't exist"); - } - let existingProject = this.get(folder.path); - if (existingProject) { - return promise.reject("Already added"); - } - let project = { - type: "packaged", - location: folder.path, - // We need a unique id, that is the app origin, - // in order to identify the app when being installed on the device. - // The packaged app local path is a valid id, but only on the client. - // This origin will be used to generate the true id of an app: - // its manifest URL. - // If the app ends up specifying an explicit origin in its manifest, - // we will override this random UUID on app install. - packagedAppOrigin: generateUUID().toString().slice(1, -1) - }; - return IDB.add(project).then(() => { - this.projects.push(project); - return project; - }); - }, - - addHosted: function (manifestURL) { - let existingProject = this.get(manifestURL); - if (existingProject) { - return promise.reject("Already added"); - } - let project = { - type: "hosted", - location: manifestURL - }; - return IDB.add(project).then(() => { - this.projects.push(project); - return project; - }); - }, - - update: function (project) { - return IDB.update(project); - }, - - updateLocation: function (project, newLocation) { - return IDB.remove(project.location) - .then(() => { - project.location = newLocation; - return IDB.add(project); - }); - }, - - remove: function (location) { - return IDB.remove(location).then(() => { - for (let i = 0; i < this.projects.length; i++) { - if (this.projects[i].location == location) { - this.projects.splice(i, 1); - return; - } - } - throw new Error("Unable to find project in AppProjects store"); - }); - }, - - get: function (location) { - for (let i = 0; i < this.projects.length; i++) { - if (this.projects[i].location == location) { - return this.projects[i]; - } - } - return null; - }, - - projects: [] -}; - -EventEmitter.decorate(AppProjects); - -exports.AppProjects = AppProjects; diff --git a/devtools/client/webide/modules/app-validator.js b/devtools/client/webide/modules/app-validator.js deleted file mode 100644 index 750720110..000000000 --- a/devtools/client/webide/modules/app-validator.js +++ /dev/null @@ -1,292 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -var {Ci, Cu, CC} = require("chrome"); -const promise = require("promise"); - -const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {}); -const Services = require("Services"); -const {Task} = require("devtools/shared/task"); -var XMLHttpRequest = CC("@mozilla.org/xmlextras/xmlhttprequest;1"); -var strings = Services.strings.createBundle("chrome://devtools/locale/app-manager.properties"); - -function AppValidator({ type, location }) { - this.type = type; - this.location = location; - this.errors = []; - this.warnings = []; -} - -AppValidator.prototype.error = function (message) { - this.errors.push(message); -}; - -AppValidator.prototype.warning = function (message) { - this.warnings.push(message); -}; - -AppValidator.prototype._getPackagedManifestFile = function () { - let manifestFile = FileUtils.File(this.location); - if (!manifestFile.exists()) { - this.error(strings.GetStringFromName("validator.nonExistingFolder")); - return null; - } - if (!manifestFile.isDirectory()) { - this.error(strings.GetStringFromName("validator.expectProjectFolder")); - return null; - } - - let appManifestFile = manifestFile.clone(); - appManifestFile.append("manifest.webapp"); - - let jsonManifestFile = manifestFile.clone(); - jsonManifestFile.append("manifest.json"); - - let hasAppManifest = appManifestFile.exists() && appManifestFile.isFile(); - let hasJsonManifest = jsonManifestFile.exists() && jsonManifestFile.isFile(); - - if (!hasAppManifest && !hasJsonManifest) { - this.error(strings.GetStringFromName("validator.noManifestFile")); - return null; - } - - return hasAppManifest ? appManifestFile : jsonManifestFile; -}; - -AppValidator.prototype._getPackagedManifestURL = function () { - let manifestFile = this._getPackagedManifestFile(); - if (!manifestFile) { - return null; - } - return Services.io.newFileURI(manifestFile).spec; -}; - -AppValidator.checkManifest = function (manifestURL) { - let deferred = promise.defer(); - let error; - - let req = new XMLHttpRequest(); - req.overrideMimeType("text/plain"); - - try { - req.open("GET", manifestURL, true); - req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING; - } catch (e) { - error = strings.formatStringFromName("validator.invalidManifestURL", [manifestURL], 1); - deferred.reject(error); - return deferred.promise; - } - - req.onload = function () { - let manifest = null; - try { - manifest = JSON.parse(req.responseText); - } catch (e) { - error = strings.formatStringFromName("validator.invalidManifestJSON", [e, manifestURL], 2); - deferred.reject(error); - } - - deferred.resolve({manifest, manifestURL}); - }; - - req.onerror = function () { - error = strings.formatStringFromName("validator.noAccessManifestURL", [req.statusText, manifestURL], 2); - deferred.reject(error); - }; - - try { - req.send(null); - } catch (e) { - error = strings.formatStringFromName("validator.noAccessManifestURL", [e, manifestURL], 2); - deferred.reject(error); - } - - return deferred.promise; -}; - -AppValidator.findManifestAtOrigin = function (manifestURL) { - let fixedManifest = Services.io.newURI(manifestURL, null, null).prePath + "/manifest.webapp"; - return AppValidator.checkManifest(fixedManifest); -}; - -AppValidator.findManifestPath = function (manifestURL) { - let deferred = promise.defer(); - - if (manifestURL.endsWith("manifest.webapp")) { - deferred.reject(); - } else { - let fixedManifest = manifestURL + "/manifest.webapp"; - deferred.resolve(AppValidator.checkManifest(fixedManifest)); - } - - return deferred.promise; -}; - -AppValidator.checkAlternateManifest = function (manifestURL) { - return Task.spawn(function* () { - let result; - try { - result = yield AppValidator.findManifestPath(manifestURL); - } catch (e) { - result = yield AppValidator.findManifestAtOrigin(manifestURL); - } - - return result; - }); -}; - -AppValidator.prototype._fetchManifest = function (manifestURL) { - let deferred = promise.defer(); - this.manifestURL = manifestURL; - - AppValidator.checkManifest(manifestURL) - .then(({manifest, manifestURL}) => { - deferred.resolve(manifest); - }, error => { - AppValidator.checkAlternateManifest(manifestURL) - .then(({manifest, manifestURL}) => { - this.manifestURL = manifestURL; - deferred.resolve(manifest); - }, () => { - this.error(error); - deferred.resolve(null); - }); - }); - - return deferred.promise; -}; - -AppValidator.prototype._getManifest = function () { - let manifestURL; - if (this.type == "packaged") { - manifestURL = this._getPackagedManifestURL(); - if (!manifestURL) - return promise.resolve(null); - } else if (this.type == "hosted") { - manifestURL = this.location; - try { - Services.io.newURI(manifestURL, null, null); - } catch (e) { - this.error(strings.formatStringFromName("validator.invalidHostedManifestURL", [manifestURL, e.message], 2)); - return promise.resolve(null); - } - } else { - this.error(strings.formatStringFromName("validator.invalidProjectType", [this.type], 1)); - return promise.resolve(null); - } - return this._fetchManifest(manifestURL); -}; - -AppValidator.prototype.validateManifest = function (manifest) { - if (!manifest.name) { - this.error(strings.GetStringFromName("validator.missNameManifestProperty")); - } - - if (!manifest.icons || Object.keys(manifest.icons).length === 0) { - this.warning(strings.GetStringFromName("validator.missIconsManifestProperty")); - } else if (!manifest.icons["128"]) { - this.warning(strings.GetStringFromName("validator.missIconMarketplace2")); - } -}; - -AppValidator.prototype._getOriginURL = function () { - if (this.type == "packaged") { - let manifestURL = Services.io.newURI(this.manifestURL, null, null); - return Services.io.newURI(".", null, manifestURL).spec; - } else if (this.type == "hosted") { - return Services.io.newURI(this.location, null, null).prePath; - } -}; - -AppValidator.prototype.validateLaunchPath = function (manifest) { - let deferred = promise.defer(); - // The launch_path field has to start with a `/` - if (manifest.launch_path && manifest.launch_path[0] !== "/") { - this.error(strings.formatStringFromName("validator.nonAbsoluteLaunchPath", [manifest.launch_path], 1)); - deferred.resolve(); - return deferred.promise; - } - let origin = this._getOriginURL(); - let path; - if (this.type == "packaged") { - path = "." + (manifest.launch_path || "/index.html"); - } else if (this.type == "hosted") { - path = manifest.launch_path || "/"; - } - let indexURL; - try { - indexURL = Services.io.newURI(path, null, Services.io.newURI(origin, null, null)).spec; - } catch (e) { - this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [origin + path], 1)); - deferred.resolve(); - return deferred.promise; - } - - let req = new XMLHttpRequest(); - req.overrideMimeType("text/plain"); - try { - req.open("HEAD", indexURL, true); - req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING; - } catch (e) { - this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1)); - deferred.resolve(); - return deferred.promise; - } - req.onload = () => { - if (req.status >= 400) - this.error(strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [indexURL, req.status], 2)); - deferred.resolve(); - }; - req.onerror = () => { - this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1)); - deferred.resolve(); - }; - - try { - req.send(null); - } catch (e) { - this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1)); - deferred.resolve(); - } - - return deferred.promise; -}; - -AppValidator.prototype.validateType = function (manifest) { - let appType = manifest.type || "web"; - if (["web", "privileged", "certified"].indexOf(appType) === -1) { - this.error(strings.formatStringFromName("validator.invalidAppType", [appType], 1)); - } else if (this.type == "hosted" && - ["certified", "privileged"].indexOf(appType) !== -1) { - this.error(strings.formatStringFromName("validator.invalidHostedPriviledges", [appType], 1)); - } - - // certified app are not fully supported on the simulator - if (appType === "certified") { - this.warning(strings.GetStringFromName("validator.noCertifiedSupport")); - } -}; - -AppValidator.prototype.validate = function () { - this.errors = []; - this.warnings = []; - return this._getManifest(). - then((manifest) => { - if (manifest) { - this.manifest = manifest; - - // Skip validations for add-ons - if (manifest.role === "addon" || manifest.manifest_version) { - return promise.resolve(); - } - - this.validateManifest(manifest); - this.validateType(manifest); - return this.validateLaunchPath(manifest); - } - }); -}; - -exports.AppValidator = AppValidator; diff --git a/devtools/client/webide/modules/build.js b/devtools/client/webide/modules/build.js deleted file mode 100644 index 34cbcc0b7..000000000 --- a/devtools/client/webide/modules/build.js +++ /dev/null @@ -1,199 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {Cu, Cc, Ci} = require("chrome"); - -const promise = require("promise"); -const { Task } = require("devtools/shared/task"); -const { TextDecoder, OS } = Cu.import("resource://gre/modules/osfile.jsm", {}); -const Subprocess = require("sdk/system/child_process/subprocess"); - -const ProjectBuilding = exports.ProjectBuilding = { - fetchPackageManifest: Task.async(function* (project) { - let manifestPath = OS.Path.join(project.location, "package.json"); - let exists = yield OS.File.exists(manifestPath); - if (!exists) { - // No explicit manifest, try to generate one if possible - return this.generatePackageManifest(project); - } - - let data = yield OS.File.read(manifestPath); - data = new TextDecoder().decode(data); - let manifest; - try { - manifest = JSON.parse(data); - } catch (e) { - throw new Error("Error while reading WebIDE manifest at: '" + manifestPath + - "', invalid JSON: " + e.message); - } - return manifest; - }), - - /** - * For common frameworks in the community, attempt to detect the build - * settings if none are defined. This makes it much easier to get started - * with WebIDE. Later on, perhaps an add-on could define such things for - * different frameworks. - */ - generatePackageManifest: Task.async(function* (project) { - // Cordova - let cordovaConfigPath = OS.Path.join(project.location, "config.xml"); - let exists = yield OS.File.exists(cordovaConfigPath); - if (!exists) { - return; - } - let data = yield OS.File.read(cordovaConfigPath); - data = new TextDecoder().decode(data); - if (data.contains("cordova.apache.org")) { - return { - "webide": { - "prepackage": "cordova prepare", - "packageDir": "./platforms/firefoxos/www" - } - }; - } - }), - - hasPrepackage: Task.async(function* (project) { - let manifest = yield ProjectBuilding.fetchPackageManifest(project); - return manifest && manifest.webide && "prepackage" in manifest.webide; - }), - - // If the app depends on some build step, run it before pushing the app - build: Task.async(function* ({ project, logger }) { - if (!(yield this.hasPrepackage(project))) { - return; - } - - let manifest = yield ProjectBuilding.fetchPackageManifest(project); - - logger("start"); - try { - yield this._build(project, manifest, logger); - logger("succeed"); - } catch (e) { - logger("failed", e); - } - }), - - _build: Task.async(function* (project, manifest, logger) { - // Look for `webide` property - manifest = manifest.webide; - - let command, cwd, args = [], env = []; - - // Copy frequently used env vars - let envService = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment); - ["HOME", "PATH"].forEach(key => { - let value = envService.get(key); - if (value) { - env.push(key + "=" + value); - } - }); - - if (typeof (manifest.prepackage) === "string") { - command = manifest.prepackage.replace(/%project%/g, project.location); - } else if (manifest.prepackage.command) { - command = manifest.prepackage.command; - - args = manifest.prepackage.args || []; - args = args.map(a => a.replace(/%project%/g, project.location)); - - env = env.concat(manifest.prepackage.env || []); - env = env.map(a => a.replace(/%project%/g, project.location)); - - if (manifest.prepackage.cwd) { - // Normalize path for Windows support (converts / to \) - let path = OS.Path.normalize(manifest.prepackage.cwd); - // Note that Path.join also support absolute path and argument. - // So that if cwd is absolute, it will return cwd. - let rel = OS.Path.join(project.location, path); - let exists = yield OS.File.exists(rel); - if (exists) { - cwd = rel; - } - } - } else { - throw new Error("pre-package manifest is invalid, missing or invalid " + - "`prepackage` attribute"); - } - - if (!cwd) { - cwd = project.location; - } - - logger("Running pre-package hook '" + command + "' " + - args.join(" ") + - " with ENV=[" + env.join(", ") + "]" + - " at " + cwd); - - // Run the command through a shell command in order to support non absolute - // paths. - // On Windows `ComSpec` env variable is going to refer to cmd.exe, - // Otherwise, on Linux and Mac, SHELL env variable should refer to - // the user chosen shell program. - // (We do not check for OS, as on windows, with cygwin, ComSpec isn't set) - let shell = envService.get("ComSpec") || envService.get("SHELL"); - args.unshift(command); - - // For cmd.exe, we have to pass the `/C` option, - // but for unix shells we need -c. - // That to interpret next argument as a shell command. - if (envService.exists("ComSpec")) { - args.unshift("/C"); - } else { - args.unshift("-c"); - } - - // Subprocess changes CWD, we have to save and restore it. - let originalCwd = yield OS.File.getCurrentDirectory(); - try { - let defer = promise.defer(); - Subprocess.call({ - command: shell, - arguments: args, - environment: env, - workdir: cwd, - - stdout: data => - logger(data), - stderr: data => - logger(data), - - done: result => { - logger("Terminated with error code: " + result.exitCode); - if (result.exitCode == 0) { - defer.resolve(); - } else { - defer.reject("pre-package command failed with error code " + result.exitCode); - } - } - }); - defer.promise.then(() => { - OS.File.setCurrentDirectory(originalCwd); - }); - yield defer.promise; - } catch (e) { - throw new Error("Unable to run pre-package command '" + command + "' " + - args.join(" ") + ":\n" + (e.message || e)); - } - }), - - getPackageDir: Task.async(function* (project) { - let manifest = yield ProjectBuilding.fetchPackageManifest(project); - if (!manifest || !manifest.webide || !manifest.webide.packageDir) { - return project.location; - } - manifest = manifest.webide; - - let packageDir = OS.Path.join(project.location, manifest.packageDir); - // On Windows, replace / by \\ - packageDir = OS.Path.normalize(packageDir); - let exists = yield OS.File.exists(packageDir); - if (exists) { - return packageDir; - } - throw new Error("Unable to resolve application package directory: '" + manifest.packageDir + "'"); - }) -}; diff --git a/devtools/client/webide/modules/config-view.js b/devtools/client/webide/modules/config-view.js deleted file mode 100644 index 5fb07e235..000000000 --- a/devtools/client/webide/modules/config-view.js +++ /dev/null @@ -1,373 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {Cu} = require("chrome"); - -const EventEmitter = require("devtools/shared/event-emitter"); -const Services = require("Services"); -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -var ConfigView; - -module.exports = ConfigView = function (window) { - EventEmitter.decorate(this); - this._doc = window.document; - this._keys = []; - return this; -}; - -ConfigView.prototype = { - _renderByType: function (input, name, value, customType) { - value = customType || typeof value; - - switch (value) { - case "boolean": - input.setAttribute("data-type", "boolean"); - input.setAttribute("type", "checkbox"); - break; - case "number": - input.setAttribute("data-type", "number"); - input.setAttribute("type", "number"); - break; - case "object": - input.setAttribute("data-type", "object"); - input.setAttribute("type", "text"); - break; - default: - input.setAttribute("data-type", "string"); - input.setAttribute("type", "text"); - break; - } - return input; - }, - - set front(front) { - this._front = front; - }, - - set keys(keys) { - this._keys = keys; - }, - - get keys() { - return this._keys; - }, - - set kind(kind) { - this._kind = kind; - }, - - set includeTypeName(include) { - this._includeTypeName = include; - }, - - search: function (event) { - if (event.target.value.length) { - let stringMatch = new RegExp(event.target.value, "i"); - - for (let i = 0; i < this._keys.length; i++) { - let key = this._keys[i]; - let row = this._doc.getElementById("row-" + key); - if (key.match(stringMatch)) { - row.classList.remove("hide"); - } else if (row) { - row.classList.add("hide"); - } - } - } else { - var trs = this._doc.getElementById("device-fields").querySelectorAll("tr"); - - for (let i = 0; i < trs.length; i++) { - trs[i].classList.remove("hide"); - } - } - }, - - generateDisplay: function (json) { - let deviceItems = Object.keys(json); - deviceItems.sort(); - this.keys = deviceItems; - for (let i = 0; i < this.keys.length; i++) { - let key = this.keys[i]; - this.generateField(key, json[key].value, json[key].hasUserValue); - } - }, - - generateField: function (name, value, hasUserValue, customType, newRow) { - let table = this._doc.querySelector("table"); - let sResetDefault = Strings.GetStringFromName("device_reset_default"); - - if (this._keys.indexOf(name) === -1) { - this._keys.push(name); - } - - let input = this._doc.createElement("input"); - let tr = this._doc.createElement("tr"); - tr.setAttribute("id", "row-" + name); - tr.classList.add("edit-row"); - let td = this._doc.createElement("td"); - td.classList.add("field-name"); - td.textContent = name; - tr.appendChild(td); - td = this._doc.createElement("td"); - input.classList.add("editable"); - input.setAttribute("id", name); - input = this._renderByType(input, name, value, customType); - - if (customType === "boolean" || input.type === "checkbox") { - input.checked = value; - } else { - if (typeof value === "object") { - value = JSON.stringify(value); - } - input.value = value; - } - - if (!(this._includeTypeName || isNaN(parseInt(value, 10)))) { - input.type = "number"; - } - - td.appendChild(input); - tr.appendChild(td); - td = this._doc.createElement("td"); - td.setAttribute("id", "td-" + name); - - let button = this._doc.createElement("button"); - button.setAttribute("data-id", name); - button.setAttribute("id", "btn-" + name); - button.classList.add("reset"); - button.textContent = sResetDefault; - td.appendChild(button); - - if (!hasUserValue) { - button.classList.add("hide"); - } - - tr.appendChild(td); - - // If this is a new field, add it to the top of the table. - if (newRow) { - let existing = table.querySelector("#" + name); - - if (!existing) { - table.insertBefore(tr, newRow); - } else { - existing.value = value; - } - } else { - table.appendChild(tr); - } - }, - - resetTable: function () { - let table = this._doc.querySelector("table"); - let trs = table.querySelectorAll("tr:not(#add-custom-field)"); - - for (var i = 0; i < trs.length; i++) { - table.removeChild(trs[i]); - } - - return table; - }, - - _getCallType: function (type, name) { - let frontName = "get"; - - if (this._includeTypeName) { - frontName += type; - } - - return this._front[frontName + this._kind](name); - }, - - _setCallType: function (type, name, value) { - let frontName = "set"; - - if (this._includeTypeName) { - frontName += type; - } - - return this._front[frontName + this._kind](name, value); - }, - - _saveByType: function (options) { - let fieldName = options.id; - let inputType = options.type; - let value = options.value; - let input = this._doc.getElementById(fieldName); - - switch (inputType) { - case "boolean": - this._setCallType("Bool", fieldName, input.checked); - break; - case "number": - this._setCallType("Int", fieldName, value); - break; - case "object": - try { - value = JSON.parse(value); - } catch (e) {} - this._setCallType("Object", fieldName, value); - break; - default: - this._setCallType("Char", fieldName, value); - break; - } - }, - - updateField: function (event) { - if (event.target) { - let inputType = event.target.getAttribute("data-type"); - let inputValue = event.target.checked || event.target.value; - - if (event.target.nodeName == "input" && - event.target.validity.valid && - event.target.classList.contains("editable")) { - let id = event.target.id; - if (inputType === "boolean") { - if (event.target.checked) { - inputValue = true; - } else { - inputValue = false; - } - } - - this._saveByType({ - id: id, - type: inputType, - value: inputValue - }); - this._doc.getElementById("btn-" + id).classList.remove("hide"); - } - } - }, - - _resetToDefault: function (name, input, button) { - this._front["clearUser" + this._kind](name); - let dataType = input.getAttribute("data-type"); - let tr = this._doc.getElementById("row-" + name); - - switch (dataType) { - case "boolean": - this._defaultField = this._getCallType("Bool", name); - this._defaultField.then(boolean => { - input.checked = boolean; - }, () => { - input.checked = false; - tr.parentNode.removeChild(tr); - }); - break; - case "number": - this._defaultField = this._getCallType("Int", name); - this._defaultField.then(number => { - input.value = number; - }, () => { - tr.parentNode.removeChild(tr); - }); - break; - case "object": - this._defaultField = this._getCallType("Object", name); - this._defaultField.then(object => { - input.value = JSON.stringify(object); - }, () => { - tr.parentNode.removeChild(tr); - }); - break; - default: - this._defaultField = this._getCallType("Char", name); - this._defaultField.then(string => { - input.value = string; - }, () => { - tr.parentNode.removeChild(tr); - }); - break; - } - - button.classList.add("hide"); - }, - - checkReset: function (event) { - if (event.target.classList.contains("reset")) { - let btnId = event.target.getAttribute("data-id"); - let input = this._doc.getElementById(btnId); - this._resetToDefault(btnId, input, event.target); - } - }, - - updateFieldType: function () { - let table = this._doc.querySelector("table"); - let customValueType = table.querySelector("#custom-value-type").value; - let customTextEl = table.querySelector("#custom-value-text"); - let customText = customTextEl.value; - - if (customValueType.length === 0) { - return false; - } - - switch (customValueType) { - case "boolean": - customTextEl.type = "checkbox"; - customText = customTextEl.checked; - break; - case "number": - customText = parseInt(customText, 10) || 0; - customTextEl.type = "number"; - break; - default: - customTextEl.type = "text"; - break; - } - - return customValueType; - }, - - clearNewFields: function () { - let table = this._doc.querySelector("table"); - let customTextEl = table.querySelector("#custom-value-text"); - if (customTextEl.checked) { - customTextEl.checked = false; - } else { - customTextEl.value = ""; - } - - this.updateFieldType(); - }, - - updateNewField: function () { - let table = this._doc.querySelector("table"); - let customValueType = this.updateFieldType(); - - if (!customValueType) { - return; - } - - let customRow = table.querySelector("tr:nth-of-type(2)"); - let customTextEl = table.querySelector("#custom-value-text"); - let customTextNameEl = table.querySelector("#custom-value-name"); - - if (customTextEl.validity.valid) { - let customText = customTextEl.value; - - if (customValueType === "boolean") { - customText = customTextEl.checked; - } - - let customTextName = customTextNameEl.value.replace(/[^A-Za-z0-9\.\-_]/gi, ""); - this.generateField(customTextName, customText, true, customValueType, customRow); - this._saveByType({ - id: customTextName, - type: customValueType, - value: customText - }); - customTextNameEl.value = ""; - this.clearNewFields(); - } - }, - - checkNewFieldSubmit: function (event) { - if (event.keyCode === 13) { - this._doc.getElementById("custom-value").click(); - } - } -}; diff --git a/devtools/client/webide/modules/moz.build b/devtools/client/webide/modules/moz.build deleted file mode 100644 index c4072b703..000000000 --- a/devtools/client/webide/modules/moz.build +++ /dev/null @@ -1,21 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -DevToolsModules( - 'addons.js', - 'app-manager.js', - 'app-projects.js', - 'app-validator.js', - 'build.js', - 'config-view.js', - 'project-list.js', - 'runtime-list.js', - 'runtimes.js', - 'simulator-process.js', - 'simulators.js', - 'tab-store.js', - 'utils.js' -) diff --git a/devtools/client/webide/modules/project-list.js b/devtools/client/webide/modules/project-list.js deleted file mode 100644 index 10766dd4f..000000000 --- a/devtools/client/webide/modules/project-list.js +++ /dev/null @@ -1,375 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public -* License, v. 2.0. If a copy of the MPL was not distributed with this -* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const {Cu} = require("chrome"); - -const Services = require("Services"); -const {AppProjects} = require("devtools/client/webide/modules/app-projects"); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); -const promise = require("promise"); -const EventEmitter = require("devtools/shared/event-emitter"); -const {Task} = require("devtools/shared/task"); -const utils = require("devtools/client/webide/modules/utils"); -const Telemetry = require("devtools/client/shared/telemetry"); - -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -var ProjectList; - -module.exports = ProjectList = function (win, parentWindow) { - EventEmitter.decorate(this); - this._doc = win.document; - this._UI = parentWindow.UI; - this._parentWindow = parentWindow; - this._telemetry = new Telemetry(); - this._panelNodeEl = "div"; - - this.onWebIDEUpdate = this.onWebIDEUpdate.bind(this); - this._UI.on("webide-update", this.onWebIDEUpdate); - - AppManager.init(); - this.appManagerUpdate = this.appManagerUpdate.bind(this); - AppManager.on("app-manager-update", this.appManagerUpdate); -}; - -ProjectList.prototype = { - get doc() { - return this._doc; - }, - - appManagerUpdate: function (event, what, details) { - // Got a message from app-manager.js - // See AppManager.update() for descriptions of what these events mean. - switch (what) { - case "project-removed": - case "runtime-apps-icons": - case "runtime-targets": - case "connection": - this.update(details); - break; - case "project": - this.updateCommands(); - this.update(details); - break; - } - }, - - onWebIDEUpdate: function (event, what, details) { - if (what == "busy" || what == "unbusy") { - this.updateCommands(); - } - }, - - /** - * testOptions: { chrome mochitest support - * folder: nsIFile, where to store the app - * index: Number, index of the app in the template list - * name: String name of the app - * } - */ - newApp: function (testOptions) { - let parentWindow = this._parentWindow; - let self = this; - return this._UI.busyUntil(Task.spawn(function* () { - // Open newapp.xul, which will feed ret.location - let ret = {location: null, testOptions: testOptions}; - parentWindow.openDialog("chrome://webide/content/newapp.xul", "newapp", "chrome,modal", ret); - if (!ret.location) - return; - - // Retrieve added project - let project = AppProjects.get(ret.location); - - // Select project - AppManager.selectedProject = project; - - self._telemetry.actionOccurred("webideNewProject"); - }), "creating new app"); - }, - - importPackagedApp: function (location) { - let parentWindow = this._parentWindow; - let UI = this._UI; - return UI.busyUntil(Task.spawn(function* () { - let directory = utils.getPackagedDirectory(parentWindow, location); - - if (!directory) { - // User cancelled directory selection - return; - } - - yield UI.importAndSelectApp(directory); - }), "importing packaged app"); - }, - - importHostedApp: function (location) { - let parentWindow = this._parentWindow; - let UI = this._UI; - return UI.busyUntil(Task.spawn(function* () { - let url = utils.getHostedURL(parentWindow, location); - - if (!url) { - return; - } - - yield UI.importAndSelectApp(url); - }), "importing hosted app"); - }, - - /** - * opts: { - * panel: Object, currenl project panel node - * name: String, name of the project - * icon: String path of the project icon - * } - */ - _renderProjectItem: function (opts) { - let span = opts.panel.querySelector("span") || this._doc.createElement("span"); - span.textContent = opts.name; - let icon = opts.panel.querySelector("img") || this._doc.createElement("img"); - icon.className = "project-image"; - icon.setAttribute("src", opts.icon); - opts.panel.appendChild(icon); - opts.panel.appendChild(span); - opts.panel.setAttribute("title", opts.name); - }, - - refreshTabs: function () { - if (AppManager.connected) { - return AppManager.listTabs().then(() => { - this.updateTabs(); - }).catch(console.error); - } - }, - - updateTabs: function () { - let tabsHeaderNode = this._doc.querySelector("#panel-header-tabs"); - let tabsNode = this._doc.querySelector("#project-panel-tabs"); - - while (tabsNode.hasChildNodes()) { - tabsNode.firstChild.remove(); - } - - if (!AppManager.connected) { - tabsHeaderNode.setAttribute("hidden", "true"); - return; - } - - let tabs = AppManager.tabStore.tabs; - - tabsHeaderNode.removeAttribute("hidden"); - - for (let i = 0; i < tabs.length; i++) { - let tab = tabs[i]; - let URL = this._parentWindow.URL; - let url; - try { - url = new URL(tab.url); - } catch (e) { - // Don't try to handle invalid URLs, especially from Valence. - continue; - } - // Wanted to use nsIFaviconService here, but it only works for visited - // tabs, so that's no help for any remote tabs. Maybe some favicon wizard - // knows how to get high-res favicons easily, or we could offer actor - // support for this (bug 1061654). - if (url.origin) { - tab.favicon = url.origin + "/favicon.ico"; - } - tab.name = tab.title || Strings.GetStringFromName("project_tab_loading"); - if (url.protocol.startsWith("http")) { - tab.name = url.hostname + ": " + tab.name; - } - let panelItemNode = this._doc.createElement(this._panelNodeEl); - panelItemNode.className = "panel-item"; - tabsNode.appendChild(panelItemNode); - this._renderProjectItem({ - panel: panelItemNode, - name: tab.name, - icon: tab.favicon || AppManager.DEFAULT_PROJECT_ICON - }); - panelItemNode.addEventListener("click", () => { - AppManager.selectedProject = { - type: "tab", - app: tab, - icon: tab.favicon || AppManager.DEFAULT_PROJECT_ICON, - location: tab.url, - name: tab.name - }; - }, true); - } - - return promise.resolve(); - }, - - updateApps: function () { - let doc = this._doc; - let runtimeappsHeaderNode = doc.querySelector("#panel-header-runtimeapps"); - let sortedApps = []; - for (let [manifestURL, app] of AppManager.apps) { - sortedApps.push(app); - } - sortedApps = sortedApps.sort((a, b) => { - return a.manifest.name > b.manifest.name; - }); - let mainProcess = AppManager.isMainProcessDebuggable(); - if (AppManager.connected && (sortedApps.length > 0 || mainProcess)) { - runtimeappsHeaderNode.removeAttribute("hidden"); - } else { - runtimeappsHeaderNode.setAttribute("hidden", "true"); - } - - let runtimeAppsNode = doc.querySelector("#project-panel-runtimeapps"); - while (runtimeAppsNode.hasChildNodes()) { - runtimeAppsNode.firstChild.remove(); - } - - if (mainProcess) { - let panelItemNode = doc.createElement(this._panelNodeEl); - panelItemNode.className = "panel-item"; - this._renderProjectItem({ - panel: panelItemNode, - name: Strings.GetStringFromName("mainProcess_label"), - icon: AppManager.DEFAULT_PROJECT_ICON - }); - runtimeAppsNode.appendChild(panelItemNode); - panelItemNode.addEventListener("click", () => { - AppManager.selectedProject = { - type: "mainProcess", - name: Strings.GetStringFromName("mainProcess_label"), - icon: AppManager.DEFAULT_PROJECT_ICON - }; - }, true); - } - - for (let i = 0; i < sortedApps.length; i++) { - let app = sortedApps[i]; - let panelItemNode = doc.createElement(this._panelNodeEl); - panelItemNode.className = "panel-item"; - this._renderProjectItem({ - panel: panelItemNode, - name: app.manifest.name, - icon: app.iconURL || AppManager.DEFAULT_PROJECT_ICON - }); - runtimeAppsNode.appendChild(panelItemNode); - panelItemNode.addEventListener("click", () => { - AppManager.selectedProject = { - type: "runtimeApp", - app: app.manifest, - icon: app.iconURL || AppManager.DEFAULT_PROJECT_ICON, - name: app.manifest.name - }; - }, true); - } - - return promise.resolve(); - }, - - updateCommands: function () { - let doc = this._doc; - let newAppCmd; - let packagedAppCmd; - let hostedAppCmd; - - newAppCmd = doc.querySelector("#new-app"); - packagedAppCmd = doc.querySelector("#packaged-app"); - hostedAppCmd = doc.querySelector("#hosted-app"); - - if (!newAppCmd || !packagedAppCmd || !hostedAppCmd) { - return; - } - - if (this._parentWindow.document.querySelector("window").classList.contains("busy")) { - newAppCmd.setAttribute("disabled", "true"); - packagedAppCmd.setAttribute("disabled", "true"); - hostedAppCmd.setAttribute("disabled", "true"); - return; - } - - newAppCmd.removeAttribute("disabled"); - packagedAppCmd.removeAttribute("disabled"); - hostedAppCmd.removeAttribute("disabled"); - }, - - /** - * Trigger an update of the project and remote runtime list. - * @param options object (optional) - * An |options| object containing a type of |apps| or |tabs| will limit - * what is updated to only those sections. - */ - update: function (options) { - let deferred = promise.defer(); - - if (options && options.type === "apps") { - return this.updateApps(); - } else if (options && options.type === "tabs") { - return this.updateTabs(); - } - - let doc = this._doc; - let projectsNode = doc.querySelector("#project-panel-projects"); - - while (projectsNode.hasChildNodes()) { - projectsNode.firstChild.remove(); - } - - AppProjects.load().then(() => { - let projects = AppProjects.projects; - for (let i = 0; i < projects.length; i++) { - let project = projects[i]; - let panelItemNode = doc.createElement(this._panelNodeEl); - panelItemNode.className = "panel-item"; - projectsNode.appendChild(panelItemNode); - if (!project.validationStatus) { - // The result of the validation process (storing names, icons, …) is not stored in - // the IndexedDB database when App Manager v1 is used. - // We need to run the validation again and update the name and icon of the app. - AppManager.validateAndUpdateProject(project).then(() => { - this._renderProjectItem({ - panel: panelItemNode, - name: project.name, - icon: project.icon - }); - }); - } else { - this._renderProjectItem({ - panel: panelItemNode, - name: project.name || AppManager.DEFAULT_PROJECT_NAME, - icon: project.icon || AppManager.DEFAULT_PROJECT_ICON - }); - } - panelItemNode.addEventListener("click", () => { - AppManager.selectedProject = project; - }, true); - } - - deferred.resolve(); - }, deferred.reject); - - // List remote apps and the main process, if they exist - this.updateApps(); - - // Build the tab list right now, so it's fast... - this.updateTabs(); - - // But re-list them and rebuild, in case any tabs navigated since the last - // time they were listed. - if (AppManager.connected) { - AppManager.listTabs().then(() => { - this.updateTabs(); - }).catch(console.error); - } - - return deferred.promise; - }, - - destroy: function () { - this._doc = null; - AppManager.off("app-manager-update", this.appManagerUpdate); - this._UI.off("webide-update", this.onWebIDEUpdate); - this._UI = null; - this._parentWindow = null; - this._panelNodeEl = null; - } -}; diff --git a/devtools/client/webide/modules/runtime-list.js b/devtools/client/webide/modules/runtime-list.js deleted file mode 100644 index 295dd1705..000000000 --- a/devtools/client/webide/modules/runtime-list.js +++ /dev/null @@ -1,207 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public -* License, v. 2.0. If a copy of the MPL was not distributed with this -* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const Services = require("Services"); -const {AppManager} = require("devtools/client/webide/modules/app-manager"); -const EventEmitter = require("devtools/shared/event-emitter"); -const {RuntimeScanners, WiFiScanner} = require("devtools/client/webide/modules/runtimes"); -const {Devices} = require("resource://devtools/shared/apps/Devices.jsm"); -const {Task} = require("devtools/shared/task"); -const utils = require("devtools/client/webide/modules/utils"); - -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -var RuntimeList; - -module.exports = RuntimeList = function (window, parentWindow) { - EventEmitter.decorate(this); - this._doc = window.document; - this._UI = parentWindow.UI; - this._Cmds = parentWindow.Cmds; - this._parentWindow = parentWindow; - this._panelNodeEl = "button"; - this._panelBoxEl = "div"; - - this.onWebIDEUpdate = this.onWebIDEUpdate.bind(this); - this._UI.on("webide-update", this.onWebIDEUpdate); - - AppManager.init(); - this.appManagerUpdate = this.appManagerUpdate.bind(this); - AppManager.on("app-manager-update", this.appManagerUpdate); -}; - -RuntimeList.prototype = { - get doc() { - return this._doc; - }, - - appManagerUpdate: function (event, what, details) { - // Got a message from app-manager.js - // See AppManager.update() for descriptions of what these events mean. - switch (what) { - case "runtime-list": - this.update(); - break; - case "connection": - case "runtime-global-actors": - this.updateCommands(); - break; - } - }, - - onWebIDEUpdate: function (event, what, details) { - if (what == "busy" || what == "unbusy") { - this.updateCommands(); - } - }, - - takeScreenshot: function () { - this._Cmds.takeScreenshot(); - }, - - showRuntimeDetails: function () { - this._Cmds.showRuntimeDetails(); - }, - - showPermissionsTable: function () { - this._Cmds.showPermissionsTable(); - }, - - showDevicePreferences: function () { - this._Cmds.showDevicePrefs(); - }, - - showSettings: function () { - this._Cmds.showSettings(); - }, - - showTroubleShooting: function () { - this._Cmds.showTroubleShooting(); - }, - - showAddons: function () { - this._Cmds.showAddons(); - }, - - refreshScanners: function () { - RuntimeScanners.scan(); - }, - - updateCommands: function () { - let doc = this._doc; - - // Runtime commands - let screenshotCmd = doc.querySelector("#runtime-screenshot"); - let permissionsCmd = doc.querySelector("#runtime-permissions"); - let detailsCmd = doc.querySelector("#runtime-details"); - let disconnectCmd = doc.querySelector("#runtime-disconnect"); - let devicePrefsCmd = doc.querySelector("#runtime-preferences"); - let settingsCmd = doc.querySelector("#runtime-settings"); - - if (AppManager.connected) { - if (AppManager.deviceFront) { - detailsCmd.removeAttribute("disabled"); - permissionsCmd.removeAttribute("disabled"); - screenshotCmd.removeAttribute("disabled"); - } - if (AppManager.preferenceFront) { - devicePrefsCmd.removeAttribute("disabled"); - } - if (AppManager.settingsFront) { - settingsCmd.removeAttribute("disabled"); - } - disconnectCmd.removeAttribute("disabled"); - } else { - detailsCmd.setAttribute("disabled", "true"); - permissionsCmd.setAttribute("disabled", "true"); - screenshotCmd.setAttribute("disabled", "true"); - disconnectCmd.setAttribute("disabled", "true"); - devicePrefsCmd.setAttribute("disabled", "true"); - settingsCmd.setAttribute("disabled", "true"); - } - }, - - update: function () { - let doc = this._doc; - let wifiHeaderNode = doc.querySelector("#runtime-header-wifi"); - - if (WiFiScanner.allowed) { - wifiHeaderNode.removeAttribute("hidden"); - } else { - wifiHeaderNode.setAttribute("hidden", "true"); - } - - let usbListNode = doc.querySelector("#runtime-panel-usb"); - let wifiListNode = doc.querySelector("#runtime-panel-wifi"); - let simulatorListNode = doc.querySelector("#runtime-panel-simulator"); - let otherListNode = doc.querySelector("#runtime-panel-other"); - let noHelperNode = doc.querySelector("#runtime-panel-noadbhelper"); - let noUSBNode = doc.querySelector("#runtime-panel-nousbdevice"); - - if (Devices.helperAddonInstalled) { - noHelperNode.setAttribute("hidden", "true"); - } else { - noHelperNode.removeAttribute("hidden"); - } - - let runtimeList = AppManager.runtimeList; - - if (!runtimeList) { - return; - } - - if (runtimeList.usb.length === 0 && Devices.helperAddonInstalled) { - noUSBNode.removeAttribute("hidden"); - } else { - noUSBNode.setAttribute("hidden", "true"); - } - - for (let [type, parent] of [ - ["usb", usbListNode], - ["wifi", wifiListNode], - ["simulator", simulatorListNode], - ["other", otherListNode], - ]) { - while (parent.hasChildNodes()) { - parent.firstChild.remove(); - } - for (let runtime of runtimeList[type]) { - let r = runtime; - let panelItemNode = doc.createElement(this._panelBoxEl); - panelItemNode.className = "panel-item-complex"; - - let connectButton = doc.createElement(this._panelNodeEl); - connectButton.className = "panel-item runtime-panel-item-" + type; - connectButton.textContent = r.name; - - connectButton.addEventListener("click", () => { - this._UI.dismissErrorNotification(); - this._UI.connectToRuntime(r); - }, true); - panelItemNode.appendChild(connectButton); - - if (r.configure) { - let configButton = doc.createElement(this._panelNodeEl); - configButton.className = "configure-button"; - configButton.addEventListener("click", r.configure.bind(r), true); - panelItemNode.appendChild(configButton); - } - - parent.appendChild(panelItemNode); - } - } - }, - - destroy: function () { - this._doc = null; - AppManager.off("app-manager-update", this.appManagerUpdate); - this._UI.off("webide-update", this.onWebIDEUpdate); - this._UI = null; - this._Cmds = null; - this._parentWindow = null; - this._panelNodeEl = null; - } -}; diff --git a/devtools/client/webide/modules/runtimes.js b/devtools/client/webide/modules/runtimes.js deleted file mode 100644 index a23337359..000000000 --- a/devtools/client/webide/modules/runtimes.js +++ /dev/null @@ -1,673 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {Ci} = require("chrome"); -const Services = require("Services"); -const {Devices} = require("resource://devtools/shared/apps/Devices.jsm"); -const {Connection} = require("devtools/shared/client/connection-manager"); -const {DebuggerServer} = require("devtools/server/main"); -const {Simulators} = require("devtools/client/webide/modules/simulators"); -const discovery = require("devtools/shared/discovery/discovery"); -const EventEmitter = require("devtools/shared/event-emitter"); -const promise = require("promise"); -loader.lazyRequireGetter(this, "AuthenticationResult", - "devtools/shared/security/auth", true); -loader.lazyRequireGetter(this, "DevToolsUtils", - "devtools/shared/DevToolsUtils"); - -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -/** - * Runtime and Scanner API - * - * |RuntimeScanners| maintains a set of |Scanner| objects that produce one or - * more |Runtime|s to connect to. Add-ons can extend the set of known runtimes - * by registering additional |Scanner|s that emit them. - * - * Each |Scanner| must support the following API: - * - * enable() - * Bind any event handlers and start any background work the scanner needs to - * maintain an updated set of |Runtime|s. - * Called when the first consumer (such as WebIDE) actively interested in - * maintaining the |Runtime| list enables the registry. - * disable() - * Unbind any event handlers and stop any background work the scanner needs to - * maintain an updated set of |Runtime|s. - * Called when the last consumer (such as WebIDE) actively interested in - * maintaining the |Runtime| list disables the registry. - * emits "runtime-list-updated" - * If the set of runtimes a |Scanner| manages has changed, it must emit this - * event to notify consumers of changes. - * scan() - * Actively refreshes the list of runtimes the scanner knows about. If your - * scanner uses an active scanning approach (as opposed to listening for - * events when changes occur), the bulk of the work would be done here. - * @return Promise - * Should be resolved when scanning is complete. If scanning has no - * well-defined end point, you can resolve immediately, as long as - * update event is emitted later when changes are noticed. - * listRuntimes() - * Return the current list of runtimes known to the |Scanner| instance. - * @return Iterable - * - * Each |Runtime| must support the following API: - * - * |type| field - * The |type| must be one of the values from the |RuntimeTypes| object. This - * is used for Telemetry and to support displaying sets of |Runtime|s - * categorized by type. - * |id| field - * An identifier that is unique in the set of all runtimes with the same - * |type|. WebIDE tries to save the last used runtime via type + id, and - * tries to locate it again in the next session, so this value should attempt - * to be stable across Firefox sessions. - * |name| field - * A user-visible label to identify the runtime that will be displayed in a - * runtime list. - * |prolongedConnection| field - * A boolean value which should be |true| if the connection process is - * expected to take a unknown or large amount of time. A UI may use this as a - * hint to skip timeouts or other time-based code paths. - * connect() - * Configure the passed |connection| object with any settings need to - * successfully connect to the runtime, and call the |connection|'s connect() - * method. - * @param Connection connection - * A |Connection| object from the DevTools |ConnectionManager|. - * @return Promise - * Resolved once you've called the |connection|'s connect() method. - * configure() OPTIONAL - * Show a configuration screen if the runtime is configurable. - */ - -/* SCANNER REGISTRY */ - -var RuntimeScanners = { - - _enabledCount: 0, - _scanners: new Set(), - - get enabled() { - return !!this._enabledCount; - }, - - add(scanner) { - if (this.enabled) { - // Enable any scanner added while globally enabled - this._enableScanner(scanner); - } - this._scanners.add(scanner); - this._emitUpdated(); - }, - - remove(scanner) { - this._scanners.delete(scanner); - if (this.enabled) { - // Disable any scanner removed while globally enabled - this._disableScanner(scanner); - } - this._emitUpdated(); - }, - - has(scanner) { - return this._scanners.has(scanner); - }, - - scan() { - if (!this.enabled) { - return promise.resolve(); - } - - if (this._scanPromise) { - return this._scanPromise; - } - - let promises = []; - - for (let scanner of this._scanners) { - promises.push(scanner.scan()); - } - - this._scanPromise = promise.all(promises); - - // Reset pending promise - this._scanPromise.then(() => { - this._scanPromise = null; - }, () => { - this._scanPromise = null; - }); - - return this._scanPromise; - }, - - listRuntimes: function* () { - for (let scanner of this._scanners) { - for (let runtime of scanner.listRuntimes()) { - yield runtime; - } - } - }, - - _emitUpdated() { - this.emit("runtime-list-updated"); - }, - - enable() { - if (this._enabledCount++ !== 0) { - // Already enabled scanners during a previous call - return; - } - this._emitUpdated = this._emitUpdated.bind(this); - for (let scanner of this._scanners) { - this._enableScanner(scanner); - } - }, - - _enableScanner(scanner) { - scanner.enable(); - scanner.on("runtime-list-updated", this._emitUpdated); - }, - - disable() { - if (--this._enabledCount !== 0) { - // Already disabled scanners during a previous call - return; - } - for (let scanner of this._scanners) { - this._disableScanner(scanner); - } - }, - - _disableScanner(scanner) { - scanner.off("runtime-list-updated", this._emitUpdated); - scanner.disable(); - }, - -}; - -EventEmitter.decorate(RuntimeScanners); - -exports.RuntimeScanners = RuntimeScanners; - -/* SCANNERS */ - -var SimulatorScanner = { - - _runtimes: [], - - enable() { - this._updateRuntimes = this._updateRuntimes.bind(this); - Simulators.on("updated", this._updateRuntimes); - this._updateRuntimes(); - }, - - disable() { - Simulators.off("updated", this._updateRuntimes); - }, - - _emitUpdated() { - this.emit("runtime-list-updated"); - }, - - _updateRuntimes() { - Simulators.findSimulators().then(simulators => { - this._runtimes = []; - for (let simulator of simulators) { - this._runtimes.push(new SimulatorRuntime(simulator)); - } - this._emitUpdated(); - }); - }, - - scan() { - return promise.resolve(); - }, - - listRuntimes: function () { - return this._runtimes; - } - -}; - -EventEmitter.decorate(SimulatorScanner); -RuntimeScanners.add(SimulatorScanner); - -/** - * TODO: Remove this comaptibility layer in the future (bug 1085393) - * This runtime exists to support the ADB Helper add-on below version 0.7.0. - * - * This scanner will list all ADB devices as runtimes, even if they may or may - * not actually connect (since the |DeprecatedUSBRuntime| assumes a Firefox OS - * device). - */ -var DeprecatedAdbScanner = { - - _runtimes: [], - - enable() { - this._updateRuntimes = this._updateRuntimes.bind(this); - Devices.on("register", this._updateRuntimes); - Devices.on("unregister", this._updateRuntimes); - Devices.on("addon-status-updated", this._updateRuntimes); - this._updateRuntimes(); - }, - - disable() { - Devices.off("register", this._updateRuntimes); - Devices.off("unregister", this._updateRuntimes); - Devices.off("addon-status-updated", this._updateRuntimes); - }, - - _emitUpdated() { - this.emit("runtime-list-updated"); - }, - - _updateRuntimes() { - this._runtimes = []; - for (let id of Devices.available()) { - let runtime = new DeprecatedUSBRuntime(id); - this._runtimes.push(runtime); - runtime.updateNameFromADB().then(() => { - this._emitUpdated(); - }, () => {}); - } - this._emitUpdated(); - }, - - scan() { - return promise.resolve(); - }, - - listRuntimes: function () { - return this._runtimes; - } - -}; - -EventEmitter.decorate(DeprecatedAdbScanner); -RuntimeScanners.add(DeprecatedAdbScanner); - -// ADB Helper 0.7.0 and later will replace this scanner on startup -exports.DeprecatedAdbScanner = DeprecatedAdbScanner; - -/** - * This is a lazy ADB scanner shim which only tells the ADB Helper to start and - * stop as needed. The real scanner that lists devices lives in ADB Helper. - * ADB Helper 0.8.0 and later wait until these signals are received before - * starting ADB polling. For earlier versions, they have no effect. - */ -var LazyAdbScanner = { - - enable() { - Devices.emit("adb-start-polling"); - }, - - disable() { - Devices.emit("adb-stop-polling"); - }, - - scan() { - return promise.resolve(); - }, - - listRuntimes: function () { - return []; - } - -}; - -EventEmitter.decorate(LazyAdbScanner); -RuntimeScanners.add(LazyAdbScanner); - -var WiFiScanner = { - - _runtimes: [], - - init() { - this.updateRegistration(); - Services.prefs.addObserver(this.ALLOWED_PREF, this, false); - }, - - enable() { - this._updateRuntimes = this._updateRuntimes.bind(this); - discovery.on("devtools-device-added", this._updateRuntimes); - discovery.on("devtools-device-updated", this._updateRuntimes); - discovery.on("devtools-device-removed", this._updateRuntimes); - this._updateRuntimes(); - }, - - disable() { - discovery.off("devtools-device-added", this._updateRuntimes); - discovery.off("devtools-device-updated", this._updateRuntimes); - discovery.off("devtools-device-removed", this._updateRuntimes); - }, - - _emitUpdated() { - this.emit("runtime-list-updated"); - }, - - _updateRuntimes() { - this._runtimes = []; - for (let device of discovery.getRemoteDevicesWithService("devtools")) { - this._runtimes.push(new WiFiRuntime(device)); - } - this._emitUpdated(); - }, - - scan() { - discovery.scan(); - return promise.resolve(); - }, - - listRuntimes: function () { - return this._runtimes; - }, - - ALLOWED_PREF: "devtools.remote.wifi.scan", - - get allowed() { - return Services.prefs.getBoolPref(this.ALLOWED_PREF); - }, - - updateRegistration() { - if (this.allowed) { - RuntimeScanners.add(WiFiScanner); - } else { - RuntimeScanners.remove(WiFiScanner); - } - this._emitUpdated(); - }, - - observe(subject, topic, data) { - if (data !== WiFiScanner.ALLOWED_PREF) { - return; - } - WiFiScanner.updateRegistration(); - } - -}; - -EventEmitter.decorate(WiFiScanner); -WiFiScanner.init(); - -exports.WiFiScanner = WiFiScanner; - -var StaticScanner = { - enable() {}, - disable() {}, - scan() { return promise.resolve(); }, - listRuntimes() { - let runtimes = [gRemoteRuntime]; - if (Services.prefs.getBoolPref("devtools.webide.enableLocalRuntime")) { - runtimes.push(gLocalRuntime); - } - return runtimes; - } -}; - -EventEmitter.decorate(StaticScanner); -RuntimeScanners.add(StaticScanner); - -/* RUNTIMES */ - -// These type strings are used for logging events to Telemetry. -// You must update Histograms.json if new types are added. -var RuntimeTypes = exports.RuntimeTypes = { - USB: "USB", - WIFI: "WIFI", - SIMULATOR: "SIMULATOR", - REMOTE: "REMOTE", - LOCAL: "LOCAL", - OTHER: "OTHER" -}; - -/** - * TODO: Remove this comaptibility layer in the future (bug 1085393) - * This runtime exists to support the ADB Helper add-on below version 0.7.0. - * - * This runtime assumes it is connecting to a Firefox OS device. - */ -function DeprecatedUSBRuntime(id) { - this._id = id; -} - -DeprecatedUSBRuntime.prototype = { - type: RuntimeTypes.USB, - get device() { - return Devices.getByName(this._id); - }, - connect: function (connection) { - if (!this.device) { - return promise.reject(new Error("Can't find device: " + this.name)); - } - return this.device.connect().then((port) => { - connection.host = "localhost"; - connection.port = port; - connection.connect(); - }); - }, - get id() { - return this._id; - }, - get name() { - return this._productModel || this._id; - }, - updateNameFromADB: function () { - if (this._productModel) { - return promise.reject(); - } - let deferred = promise.defer(); - if (this.device && this.device.shell) { - this.device.shell("getprop ro.product.model").then(stdout => { - this._productModel = stdout; - deferred.resolve(); - }, () => {}); - } else { - this._productModel = null; - deferred.reject(); - } - return deferred.promise; - }, -}; - -// For testing use only -exports._DeprecatedUSBRuntime = DeprecatedUSBRuntime; - -function WiFiRuntime(deviceName) { - this.deviceName = deviceName; -} - -WiFiRuntime.prototype = { - type: RuntimeTypes.WIFI, - // Mark runtime as taking a long time to connect - prolongedConnection: true, - connect: function (connection) { - let service = discovery.getRemoteService("devtools", this.deviceName); - if (!service) { - return promise.reject(new Error("Can't find device: " + this.name)); - } - connection.advertisement = service; - connection.authenticator.sendOOB = this.sendOOB; - // Disable the default connection timeout, since QR scanning can take an - // unknown amount of time. This prevents spurious errors (even after - // eventual success) from being shown. - connection.timeoutDelay = 0; - connection.connect(); - return promise.resolve(); - }, - get id() { - return this.deviceName; - }, - get name() { - return this.deviceName; - }, - - /** - * During OOB_CERT authentication, a notification dialog like this is used to - * to display a token which the user must transfer through some mechanism to the - * server to authenticate the devices. - * - * This implementation presents the token as text for the user to transfer - * manually. For a mobile device, you should override this implementation with - * something more convenient, such as displaying a QR code. - * - * This method receives an object containing: - * @param host string - * The host name or IP address of the debugger server. - * @param port number - * The port number of the debugger server. - * @param cert object (optional) - * The server's cert details. - * @param authResult AuthenticationResult - * Authentication result sent from the server. - * @param oob object (optional) - * The token data to be transferred during OOB_CERT step 8: - * * sha256: hash(ClientCert) - * * k : K(random 128-bit number) - * @return object containing: - * * close: Function to hide the notification - */ - sendOOB(session) { - const WINDOW_ID = "devtools:wifi-auth"; - let { authResult } = session; - // Only show in the PENDING state - if (authResult != AuthenticationResult.PENDING) { - throw new Error("Expected PENDING result, got " + authResult); - } - - // Listen for the window our prompt opens, so we can close it programatically - let promptWindow; - let windowListener = { - onOpenWindow(xulWindow) { - let win = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow); - win.addEventListener("load", function listener() { - win.removeEventListener("load", listener, false); - if (win.document.documentElement.getAttribute("id") != WINDOW_ID) { - return; - } - // Found the window - promptWindow = win; - Services.wm.removeListener(windowListener); - }, false); - }, - onCloseWindow() {}, - onWindowTitleChange() {} - }; - Services.wm.addListener(windowListener); - - // |openDialog| is typically a blocking API, so |executeSoon| to get around this - DevToolsUtils.executeSoon(() => { - // Height determines the size of the QR code. Force a minimum size to - // improve scanability. - const MIN_HEIGHT = 600; - let win = Services.wm.getMostRecentWindow("devtools:webide"); - let width = win.outerWidth * 0.8; - let height = Math.max(win.outerHeight * 0.5, MIN_HEIGHT); - win.openDialog("chrome://webide/content/wifi-auth.xhtml", - WINDOW_ID, - "modal=yes,width=" + width + ",height=" + height, session); - }); - - return { - close() { - if (!promptWindow) { - return; - } - promptWindow.close(); - promptWindow = null; - } - }; - } -}; - -// For testing use only -exports._WiFiRuntime = WiFiRuntime; - -function SimulatorRuntime(simulator) { - this.simulator = simulator; -} - -SimulatorRuntime.prototype = { - type: RuntimeTypes.SIMULATOR, - connect: function (connection) { - return this.simulator.launch().then(port => { - connection.host = "localhost"; - connection.port = port; - connection.keepConnecting = true; - connection.once(Connection.Events.DISCONNECTED, e => this.simulator.kill()); - connection.connect(); - }); - }, - configure() { - Simulators.emit("configure", this.simulator); - }, - get id() { - return this.simulator.id; - }, - get name() { - return this.simulator.name; - }, -}; - -// For testing use only -exports._SimulatorRuntime = SimulatorRuntime; - -var gLocalRuntime = { - type: RuntimeTypes.LOCAL, - connect: function (connection) { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - DebuggerServer.allowChromeProcess = true; - connection.host = null; // Force Pipe transport - connection.port = null; - connection.connect(); - return promise.resolve(); - }, - get id() { - return "local"; - }, - get name() { - return Strings.GetStringFromName("local_runtime"); - }, -}; - -// For testing use only -exports._gLocalRuntime = gLocalRuntime; - -var gRemoteRuntime = { - type: RuntimeTypes.REMOTE, - connect: function (connection) { - let win = Services.wm.getMostRecentWindow("devtools:webide"); - if (!win) { - return promise.reject(new Error("No WebIDE window found")); - } - let ret = {value: connection.host + ":" + connection.port}; - let title = Strings.GetStringFromName("remote_runtime_promptTitle"); - let message = Strings.GetStringFromName("remote_runtime_promptMessage"); - let ok = Services.prompt.prompt(win, title, message, ret, null, {}); - let [host, port] = ret.value.split(":"); - if (!ok) { - return promise.reject({canceled: true}); - } - if (!host || !port) { - return promise.reject(new Error("Invalid host or port")); - } - connection.host = host; - connection.port = port; - connection.connect(); - return promise.resolve(); - }, - get name() { - return Strings.GetStringFromName("remote_runtime"); - }, -}; - -// For testing use only -exports._gRemoteRuntime = gRemoteRuntime; diff --git a/devtools/client/webide/modules/simulator-process.js b/devtools/client/webide/modules/simulator-process.js deleted file mode 100644 index 7d0b57cc6..000000000 --- a/devtools/client/webide/modules/simulator-process.js +++ /dev/null @@ -1,325 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -"use strict"; - -const { Cc, Ci, Cu } = require("chrome"); - -const Environment = require("sdk/system/environment").env; -const EventEmitter = require("devtools/shared/event-emitter"); -const promise = require("promise"); -const Subprocess = require("sdk/system/child_process/subprocess"); -const Services = require("Services"); - -loader.lazyGetter(this, "OS", () => { - const Runtime = require("sdk/system/runtime"); - switch (Runtime.OS) { - case "Darwin": - return "mac64"; - case "Linux": - if (Runtime.XPCOMABI.indexOf("x86_64") === 0) { - return "linux64"; - } else { - return "linux32"; - } - case "WINNT": - return "win32"; - default: - return ""; - } -}); - -function SimulatorProcess() {} -SimulatorProcess.prototype = { - - // Check if B2G is running. - get isRunning() { - return !!this.process; - }, - - // Start the process and connect the debugger client. - run() { - - // Resolve B2G binary. - let b2g = this.b2gBinary; - if (!b2g || !b2g.exists()) { - throw Error("B2G executable not found."); - } - - // Ensure Gaia profile exists. - let gaia = this.gaiaProfile; - if (!gaia || !gaia.exists()) { - throw Error("Gaia profile directory not found."); - } - - this.once("stdout", function () { - if (OS == "mac64") { - console.debug("WORKAROUND run osascript to show b2g-desktop window on OS=='mac64'"); - // Escape double quotes and escape characters for use in AppleScript. - let path = b2g.path.replace(/\\/g, "\\\\").replace(/\"/g, '\\"'); - - Subprocess.call({ - command: "/usr/bin/osascript", - arguments: ["-e", 'tell application "' + path + '" to activate'], - }); - } - }); - - let logHandler = (e, data) => this.log(e, data.trim()); - this.on("stdout", logHandler); - this.on("stderr", logHandler); - this.once("exit", () => { - this.off("stdout", logHandler); - this.off("stderr", logHandler); - }); - - let environment; - if (OS.indexOf("linux") > -1) { - environment = ["TMPDIR=" + Services.dirsvc.get("TmpD", Ci.nsIFile).path]; - ["DISPLAY", "XAUTHORITY"].forEach(key => { - if (key in Environment) { - environment.push(key + "=" + Environment[key]); - } - }); - } - - // Spawn a B2G instance. - this.process = Subprocess.call({ - command: b2g, - arguments: this.args, - environment: environment, - stdout: data => this.emit("stdout", data), - stderr: data => this.emit("stderr", data), - // On B2G instance exit, reset tracked process, remote debugger port and - // shuttingDown flag, then finally emit an exit event. - done: result => { - console.log("B2G terminated with " + result.exitCode); - this.process = null; - this.emit("exit", result.exitCode); - } - }); - }, - - // Request a B2G instance kill. - kill() { - let deferred = promise.defer(); - if (this.process) { - this.once("exit", (e, exitCode) => { - this.shuttingDown = false; - deferred.resolve(exitCode); - }); - if (!this.shuttingDown) { - this.shuttingDown = true; - this.emit("kill", null); - this.process.kill(); - } - return deferred.promise; - } else { - return promise.resolve(undefined); - } - }, - - // Maybe log output messages. - log(level, message) { - if (!Services.prefs.getBoolPref("devtools.webide.logSimulatorOutput")) { - return; - } - if (level === "stderr" || level === "error") { - console.error(message); - return; - } - console.log(message); - }, - - // Compute B2G CLI arguments. - get args() { - let args = []; - - // Gaia profile. - args.push("-profile", this.gaiaProfile.path); - - // Debugger server port. - let port = parseInt(this.options.port); - args.push("-start-debugger-server", "" + port); - - // Screen size. - let width = parseInt(this.options.width); - let height = parseInt(this.options.height); - if (width && height) { - args.push("-screen", width + "x" + height); - } - - // Ignore eventual zombie instances of b2g that are left over. - args.push("-no-remote"); - - // If we are running a simulator based on Mulet, - // we have to override the default chrome URL - // in order to prevent the Browser UI to appear. - if (this.b2gBinary.leafName.includes("firefox")) { - args.push("-chrome", "chrome://b2g/content/shell.html"); - } - - return args; - }, -}; - -EventEmitter.decorate(SimulatorProcess.prototype); - - -function CustomSimulatorProcess(options) { - this.options = options; -} - -var CSPp = CustomSimulatorProcess.prototype = Object.create(SimulatorProcess.prototype); - -// Compute B2G binary file handle. -Object.defineProperty(CSPp, "b2gBinary", { - get: function () { - let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); - file.initWithPath(this.options.b2gBinary); - return file; - } -}); - -// Compute Gaia profile file handle. -Object.defineProperty(CSPp, "gaiaProfile", { - get: function () { - let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); - file.initWithPath(this.options.gaiaProfile); - return file; - } -}); - -exports.CustomSimulatorProcess = CustomSimulatorProcess; - - -function AddonSimulatorProcess(addon, options) { - this.addon = addon; - this.options = options; -} - -var ASPp = AddonSimulatorProcess.prototype = Object.create(SimulatorProcess.prototype); - -// Compute B2G binary file handle. -Object.defineProperty(ASPp, "b2gBinary", { - get: function () { - let file; - try { - let pref = "extensions." + this.addon.id + ".customRuntime"; - file = Services.prefs.getComplexValue(pref, Ci.nsIFile); - } catch (e) {} - - if (!file) { - file = this.addon.getResourceURI().QueryInterface(Ci.nsIFileURL).file; - file.append("b2g"); - let binaries = { - win32: "b2g-bin.exe", - mac64: "B2G.app/Contents/MacOS/b2g-bin", - linux32: "b2g-bin", - linux64: "b2g-bin", - }; - binaries[OS].split("/").forEach(node => file.append(node)); - } - // If the binary doesn't exists, it may be because of a simulator - // based on mulet, which has a different binary name. - if (!file.exists()) { - file = this.addon.getResourceURI().QueryInterface(Ci.nsIFileURL).file; - file.append("firefox"); - let binaries = { - win32: "firefox.exe", - mac64: "FirefoxNightly.app/Contents/MacOS/firefox-bin", - linux32: "firefox-bin", - linux64: "firefox-bin", - }; - binaries[OS].split("/").forEach(node => file.append(node)); - } - return file; - } -}); - -// Compute Gaia profile file handle. -Object.defineProperty(ASPp, "gaiaProfile", { - get: function () { - let file; - - // Custom profile from simulator configuration. - if (this.options.gaiaProfile) { - file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); - file.initWithPath(this.options.gaiaProfile); - return file; - } - - // Custom profile from addon prefs. - try { - let pref = "extensions." + this.addon.id + ".gaiaProfile"; - file = Services.prefs.getComplexValue(pref, Ci.nsIFile); - return file; - } catch (e) {} - - // Default profile from addon. - file = this.addon.getResourceURI().QueryInterface(Ci.nsIFileURL).file; - file.append("profile"); - return file; - } -}); - -exports.AddonSimulatorProcess = AddonSimulatorProcess; - - -function OldAddonSimulatorProcess(addon, options) { - this.addon = addon; - this.options = options; -} - -var OASPp = OldAddonSimulatorProcess.prototype = Object.create(AddonSimulatorProcess.prototype); - -// Compute B2G binary file handle. -Object.defineProperty(OASPp, "b2gBinary", { - get: function () { - let file; - try { - let pref = "extensions." + this.addon.id + ".customRuntime"; - file = Services.prefs.getComplexValue(pref, Ci.nsIFile); - } catch (e) {} - - if (!file) { - file = this.addon.getResourceURI().QueryInterface(Ci.nsIFileURL).file; - let version = this.addon.name.match(/\d+\.\d+/)[0].replace(/\./, "_"); - file.append("resources"); - file.append("fxos_" + version + "_simulator"); - file.append("data"); - file.append(OS == "linux32" ? "linux" : OS); - let binaries = { - win32: "b2g/b2g-bin.exe", - mac64: "B2G.app/Contents/MacOS/b2g-bin", - linux32: "b2g/b2g-bin", - linux64: "b2g/b2g-bin", - }; - binaries[OS].split("/").forEach(node => file.append(node)); - } - return file; - } -}); - -// Compute B2G CLI arguments. -Object.defineProperty(OASPp, "args", { - get: function () { - let args = []; - - // Gaia profile. - args.push("-profile", this.gaiaProfile.path); - - // Debugger server port. - let port = parseInt(this.options.port); - args.push("-dbgport", "" + port); - - // Ignore eventual zombie instances of b2g that are left over. - args.push("-no-remote"); - - return args; - } -}); - -exports.OldAddonSimulatorProcess = OldAddonSimulatorProcess; diff --git a/devtools/client/webide/modules/simulators.js b/devtools/client/webide/modules/simulators.js deleted file mode 100644 index f09df9e05..000000000 --- a/devtools/client/webide/modules/simulators.js +++ /dev/null @@ -1,368 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const { AddonManager } = require("resource://gre/modules/AddonManager.jsm"); -const { Task } = require("devtools/shared/task"); -loader.lazyRequireGetter(this, "ConnectionManager", "devtools/shared/client/connection-manager", true); -loader.lazyRequireGetter(this, "AddonSimulatorProcess", "devtools/client/webide/modules/simulator-process", true); -loader.lazyRequireGetter(this, "OldAddonSimulatorProcess", "devtools/client/webide/modules/simulator-process", true); -loader.lazyRequireGetter(this, "CustomSimulatorProcess", "devtools/client/webide/modules/simulator-process", true); -const asyncStorage = require("devtools/shared/async-storage"); -const EventEmitter = require("devtools/shared/event-emitter"); -const promise = require("promise"); -const Services = require("Services"); - -const SimulatorRegExp = new RegExp(Services.prefs.getCharPref("devtools.webide.simulatorAddonRegExp")); -const LocaleCompare = (a, b) => { - return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); -}; - -var Simulators = { - - // The list of simulator configurations. - _simulators: [], - - /** - * Load a previously saved list of configurations (only once). - * - * @return Promise. - */ - _load() { - if (this._loadingPromise) { - return this._loadingPromise; - } - - this._loadingPromise = Task.spawn(function* () { - let jobs = []; - - let value = yield asyncStorage.getItem("simulators"); - if (Array.isArray(value)) { - value.forEach(options => { - let simulator = new Simulator(options); - Simulators.add(simulator, true); - - // If the simulator had a reference to an addon, fix it. - if (options.addonID) { - let deferred = promise.defer(); - AddonManager.getAddonByID(options.addonID, addon => { - simulator.addon = addon; - delete simulator.options.addonID; - deferred.resolve(); - }); - jobs.push(deferred.promise); - } - }); - } - - yield promise.all(jobs); - yield Simulators._addUnusedAddons(); - Simulators.emitUpdated(); - return Simulators._simulators; - }); - - return this._loadingPromise; - }, - - /** - * Add default simulators to the list for each new (unused) addon. - * - * @return Promise. - */ - _addUnusedAddons: Task.async(function* () { - let jobs = []; - - let addons = yield Simulators.findSimulatorAddons(); - addons.forEach(addon => { - jobs.push(Simulators.addIfUnusedAddon(addon, true)); - }); - - yield promise.all(jobs); - }), - - /** - * Save the current list of configurations. - * - * @return Promise. - */ - _save: Task.async(function* () { - yield this._load(); - - let value = Simulators._simulators.map(simulator => { - let options = JSON.parse(JSON.stringify(simulator.options)); - if (simulator.addon != null) { - options.addonID = simulator.addon.id; - } - return options; - }); - - yield asyncStorage.setItem("simulators", value); - }), - - /** - * List all available simulators. - * - * @return Promised simulator list. - */ - findSimulators: Task.async(function* () { - yield this._load(); - return Simulators._simulators; - }), - - /** - * List all installed simulator addons. - * - * @return Promised addon list. - */ - findSimulatorAddons() { - let deferred = promise.defer(); - AddonManager.getAllAddons(all => { - let addons = []; - for (let addon of all) { - if (Simulators.isSimulatorAddon(addon)) { - addons.push(addon); - } - } - // Sort simulator addons by name. - addons.sort(LocaleCompare); - deferred.resolve(addons); - }); - return deferred.promise; - }, - - /** - * Add a new simulator for `addon` if no other simulator uses it. - */ - addIfUnusedAddon(addon, silently = false) { - let simulators = this._simulators; - let matching = simulators.filter(s => s.addon && s.addon.id == addon.id); - if (matching.length > 0) { - return promise.resolve(); - } - let options = {}; - options.name = addon.name.replace(" Simulator", ""); - // Some addons specify a simulator type at the end of their version string, - // e.g. "2_5_tv". - let type = this.simulatorAddonVersion(addon).split("_")[2]; - if (type) { - // "tv" is shorthand for type "television". - options.type = (type === "tv" ? "television" : type); - } - return this.add(new Simulator(options, addon), silently); - }, - - // TODO (Bug 1146521) Maybe find a better way to deal with removed addons? - removeIfUsingAddon(addon) { - let simulators = this._simulators; - let remaining = simulators.filter(s => !s.addon || s.addon.id != addon.id); - this._simulators = remaining; - if (remaining.length !== simulators.length) { - this.emitUpdated(); - } - }, - - /** - * Add a new simulator to the list. Caution: `simulator.name` may be modified. - * - * @return Promise to added simulator. - */ - add(simulator, silently = false) { - let simulators = this._simulators; - let uniqueName = this.uniqueName(simulator.options.name); - simulator.options.name = uniqueName; - simulators.push(simulator); - if (!silently) { - this.emitUpdated(); - } - return promise.resolve(simulator); - }, - - /** - * Remove a simulator from the list. - */ - remove(simulator) { - let simulators = this._simulators; - let remaining = simulators.filter(s => s !== simulator); - this._simulators = remaining; - if (remaining.length !== simulators.length) { - this.emitUpdated(); - } - }, - - /** - * Get a unique name for a simulator (may add a suffix, e.g. "MyName (1)"). - */ - uniqueName(name) { - let simulators = this._simulators; - - let names = {}; - simulators.forEach(simulator => names[simulator.name] = true); - - // Strip any previous suffix, add a new suffix if necessary. - let stripped = name.replace(/ \(\d+\)$/, ""); - let unique = stripped; - for (let i = 1; names[unique]; i++) { - unique = stripped + " (" + i + ")"; - } - return unique; - }, - - /** - * Compare an addon's ID against the expected form of a simulator addon ID, - * and try to extract its version if there is a match. - * - * Note: If a simulator addon is recognized, but no version can be extracted - * (e.g. custom RegExp pref value), we return "Unknown" to keep the returned - * value 'truthy'. - */ - simulatorAddonVersion(addon) { - let match = SimulatorRegExp.exec(addon.id); - if (!match) { - return null; - } - let version = match[1]; - return version || "Unknown"; - }, - - /** - * Detect simulator addons, including "unofficial" ones. - */ - isSimulatorAddon(addon) { - return !!this.simulatorAddonVersion(addon); - }, - - emitUpdated() { - this.emit("updated", { length: this._simulators.length }); - this._simulators.sort(LocaleCompare); - this._save(); - }, - - onConfigure(e, simulator) { - this._lastConfiguredSimulator = simulator; - }, - - onInstalled(addon) { - if (this.isSimulatorAddon(addon)) { - this.addIfUnusedAddon(addon); - } - }, - - onEnabled(addon) { - if (this.isSimulatorAddon(addon)) { - this.addIfUnusedAddon(addon); - } - }, - - onDisabled(addon) { - if (this.isSimulatorAddon(addon)) { - this.removeIfUsingAddon(addon); - } - }, - - onUninstalled(addon) { - if (this.isSimulatorAddon(addon)) { - this.removeIfUsingAddon(addon); - } - }, -}; -exports.Simulators = Simulators; -AddonManager.addAddonListener(Simulators); -EventEmitter.decorate(Simulators); -Simulators.on("configure", Simulators.onConfigure.bind(Simulators)); - -function Simulator(options = {}, addon = null) { - this.addon = addon; - this.options = options; - - // Fill `this.options` with default values where needed. - let defaults = this.defaults; - for (let option in defaults) { - if (this.options[option] == null) { - this.options[option] = defaults[option]; - } - } -} -Simulator.prototype = { - - // Default simulation options. - _defaults: { - // Based on the Firefox OS Flame. - phone: { - width: 320, - height: 570, - pixelRatio: 1.5 - }, - // Based on a 720p HD TV. - television: { - width: 1280, - height: 720, - pixelRatio: 1, - } - }, - _defaultType: "phone", - - restoreDefaults() { - let defaults = this.defaults; - let options = this.options; - for (let option in defaults) { - options[option] = defaults[option]; - } - }, - - launch() { - // Close already opened simulation. - if (this.process) { - return this.kill().then(this.launch.bind(this)); - } - - this.options.port = ConnectionManager.getFreeTCPPort(); - - // Choose simulator process type. - if (this.options.b2gBinary) { - // Custom binary. - this.process = new CustomSimulatorProcess(this.options); - } else if (this.version > "1.3") { - // Recent simulator addon. - this.process = new AddonSimulatorProcess(this.addon, this.options); - } else { - // Old simulator addon. - this.process = new OldAddonSimulatorProcess(this.addon, this.options); - } - this.process.run(); - - return promise.resolve(this.options.port); - }, - - kill() { - let process = this.process; - if (!process) { - return promise.resolve(); - } - this.process = null; - return process.kill(); - }, - - get defaults() { - let defaults = this._defaults; - return defaults[this.type] || defaults[this._defaultType]; - }, - - get id() { - return this.name; - }, - - get name() { - return this.options.name; - }, - - get type() { - return this.options.type || this._defaultType; - }, - - get version() { - return this.options.b2gBinary ? "Custom" : this.addon.name.match(/\d+\.\d+/)[0]; - }, -}; -exports.Simulator = Simulator; diff --git a/devtools/client/webide/modules/tab-store.js b/devtools/client/webide/modules/tab-store.js deleted file mode 100644 index 0fed366cc..000000000 --- a/devtools/client/webide/modules/tab-store.js +++ /dev/null @@ -1,178 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const { Cu } = require("chrome"); - -const { TargetFactory } = require("devtools/client/framework/target"); -const EventEmitter = require("devtools/shared/event-emitter"); -const { Connection } = require("devtools/shared/client/connection-manager"); -const promise = require("promise"); -const { Task } = require("devtools/shared/task"); - -const _knownTabStores = new WeakMap(); - -var TabStore; - -module.exports = TabStore = function (connection) { - // If we already know about this connection, - // let's re-use the existing store. - if (_knownTabStores.has(connection)) { - return _knownTabStores.get(connection); - } - - _knownTabStores.set(connection, this); - - EventEmitter.decorate(this); - - this._resetStore(); - - this.destroy = this.destroy.bind(this); - this._onStatusChanged = this._onStatusChanged.bind(this); - - this._connection = connection; - this._connection.once(Connection.Events.DESTROYED, this.destroy); - this._connection.on(Connection.Events.STATUS_CHANGED, this._onStatusChanged); - this._onTabListChanged = this._onTabListChanged.bind(this); - this._onTabNavigated = this._onTabNavigated.bind(this); - this._onStatusChanged(); - return this; -}; - -TabStore.prototype = { - - destroy: function () { - if (this._connection) { - // While this.destroy is bound using .once() above, that event may not - // have occurred when the TabStore client calls destroy, so we - // manually remove it here. - this._connection.off(Connection.Events.DESTROYED, this.destroy); - this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged); - _knownTabStores.delete(this._connection); - this._connection = null; - } - }, - - _resetStore: function () { - this.response = null; - this.tabs = []; - this._selectedTab = null; - this._selectedTabTargetPromise = null; - }, - - _onStatusChanged: function () { - if (this._connection.status == Connection.Status.CONNECTED) { - // Watch for changes to remote browser tabs - this._connection.client.addListener("tabListChanged", - this._onTabListChanged); - this._connection.client.addListener("tabNavigated", - this._onTabNavigated); - this.listTabs(); - } else { - if (this._connection.client) { - this._connection.client.removeListener("tabListChanged", - this._onTabListChanged); - this._connection.client.removeListener("tabNavigated", - this._onTabNavigated); - } - this._resetStore(); - } - }, - - _onTabListChanged: function () { - this.listTabs().then(() => this.emit("tab-list")) - .catch(console.error); - }, - - _onTabNavigated: function (e, { from, title, url }) { - if (!this._selectedTab || from !== this._selectedTab.actor) { - return; - } - this._selectedTab.url = url; - this._selectedTab.title = title; - this.emit("navigate"); - }, - - listTabs: function () { - if (!this._connection || !this._connection.client) { - return promise.reject(new Error("Can't listTabs, not connected.")); - } - let deferred = promise.defer(); - this._connection.client.listTabs(response => { - if (response.error) { - this._connection.disconnect(); - deferred.reject(response.error); - return; - } - let tabsChanged = JSON.stringify(this.tabs) !== JSON.stringify(response.tabs); - this.response = response; - this.tabs = response.tabs; - this._checkSelectedTab(); - if (tabsChanged) { - this.emit("tab-list"); - } - deferred.resolve(response); - }); - return deferred.promise; - }, - - // TODO: Tab "selection" should really take place by creating a TabProject - // which is the selected project. This should be done as part of the - // project-agnostic work. - _selectedTab: null, - _selectedTabTargetPromise: null, - get selectedTab() { - return this._selectedTab; - }, - set selectedTab(tab) { - if (this._selectedTab === tab) { - return; - } - this._selectedTab = tab; - this._selectedTabTargetPromise = null; - // Attach to the tab to follow navigation events - if (this._selectedTab) { - this.getTargetForTab(); - } - }, - - _checkSelectedTab: function () { - if (!this._selectedTab) { - return; - } - let alive = this.tabs.some(tab => { - return tab.actor === this._selectedTab.actor; - }); - if (!alive) { - this._selectedTab = null; - this._selectedTabTargetPromise = null; - this.emit("closed"); - } - }, - - getTargetForTab: function () { - if (this._selectedTabTargetPromise) { - return this._selectedTabTargetPromise; - } - let store = this; - this._selectedTabTargetPromise = Task.spawn(function* () { - // If you connect to a tab, then detach from it, the root actor may have - // de-listed the actors that belong to the tab. This breaks the toolbox - // if you try to connect to the same tab again. To work around this - // issue, we force a "listTabs" request before connecting to a tab. - yield store.listTabs(); - return TargetFactory.forRemoteTab({ - form: store._selectedTab, - client: store._connection.client, - chrome: false - }); - }); - this._selectedTabTargetPromise.then(target => { - target.once("close", () => { - this._selectedTabTargetPromise = null; - }); - }); - return this._selectedTabTargetPromise; - }, - -}; diff --git a/devtools/client/webide/modules/utils.js b/devtools/client/webide/modules/utils.js deleted file mode 100644 index 7a19c7044..000000000 --- a/devtools/client/webide/modules/utils.js +++ /dev/null @@ -1,68 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const { Cc, Cu, Ci } = require("chrome"); -const { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {}); -const Services = require("Services"); -const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties"); - -function doesFileExist(location) { - let file = new FileUtils.File(location); - return file.exists(); -} -exports.doesFileExist = doesFileExist; - -function _getFile(location, ...pickerParams) { - if (location) { - return new FileUtils.File(location); - } - let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); - fp.init(...pickerParams); - let res = fp.show(); - if (res == Ci.nsIFilePicker.returnCancel) { - return null; - } - return fp.file; -} - -function getCustomBinary(window, location) { - return _getFile(location, window, Strings.GetStringFromName("selectCustomBinary_title"), Ci.nsIFilePicker.modeOpen); -} -exports.getCustomBinary = getCustomBinary; - -function getCustomProfile(window, location) { - return _getFile(location, window, Strings.GetStringFromName("selectCustomProfile_title"), Ci.nsIFilePicker.modeGetFolder); -} -exports.getCustomProfile = getCustomProfile; - -function getPackagedDirectory(window, location) { - return _getFile(location, window, Strings.GetStringFromName("importPackagedApp_title"), Ci.nsIFilePicker.modeGetFolder); -} -exports.getPackagedDirectory = getPackagedDirectory; - -function getHostedURL(window, location) { - let ret = { value: null }; - - if (!location) { - Services.prompt.prompt(window, - Strings.GetStringFromName("importHostedApp_title"), - Strings.GetStringFromName("importHostedApp_header"), - ret, null, {}); - location = ret.value; - } - - if (!location) { - return null; - } - - // Clean location string and add "http://" if missing - location = location.trim(); - try { // Will fail if no scheme - Services.io.extractScheme(location); - } catch (e) { - location = "http://" + location; - } - return location; -} -exports.getHostedURL = getHostedURL; diff --git a/devtools/client/webide/moz.build b/devtools/client/webide/moz.build deleted file mode 100644 index c5dcb07a9..000000000 --- a/devtools/client/webide/moz.build +++ /dev/null @@ -1,23 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -DIRS += [ - 'content', - 'components', - 'modules', - 'themes', -] - -BROWSER_CHROME_MANIFESTS += [ - 'test/browser.ini' -] -MOCHITEST_CHROME_MANIFESTS += [ - 'test/chrome.ini' -] - -JS_PREFERENCE_PP_FILES += [ - 'webide-prefs.js', -] diff --git a/devtools/client/webide/test/.eslintrc.js b/devtools/client/webide/test/.eslintrc.js deleted file mode 100644 index 8d15a76d9..000000000 --- a/devtools/client/webide/test/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; - -module.exports = { - // Extend from the shared list of defined globals for mochitests. - "extends": "../../../.eslintrc.mochitests.js" -}; diff --git a/devtools/client/webide/test/addons/adbhelper-linux.xpi b/devtools/client/webide/test/addons/adbhelper-linux.xpi Binary files differdeleted file mode 100644 index b56cc03e3..000000000 --- a/devtools/client/webide/test/addons/adbhelper-linux.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/adbhelper-linux64.xpi b/devtools/client/webide/test/addons/adbhelper-linux64.xpi Binary files differdeleted file mode 100644 index b56cc03e3..000000000 --- a/devtools/client/webide/test/addons/adbhelper-linux64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/adbhelper-mac64.xpi b/devtools/client/webide/test/addons/adbhelper-mac64.xpi Binary files differdeleted file mode 100644 index b56cc03e3..000000000 --- a/devtools/client/webide/test/addons/adbhelper-mac64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/adbhelper-win32.xpi b/devtools/client/webide/test/addons/adbhelper-win32.xpi Binary files differdeleted file mode 100644 index b56cc03e3..000000000 --- a/devtools/client/webide/test/addons/adbhelper-win32.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxdt-adapters-linux32.xpi b/devtools/client/webide/test/addons/fxdt-adapters-linux32.xpi Binary files differdeleted file mode 100644 index 5a512ae3d..000000000 --- a/devtools/client/webide/test/addons/fxdt-adapters-linux32.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxdt-adapters-linux64.xpi b/devtools/client/webide/test/addons/fxdt-adapters-linux64.xpi Binary files differdeleted file mode 100644 index 5a512ae3d..000000000 --- a/devtools/client/webide/test/addons/fxdt-adapters-linux64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxdt-adapters-mac64.xpi b/devtools/client/webide/test/addons/fxdt-adapters-mac64.xpi Binary files differdeleted file mode 100644 index 5a512ae3d..000000000 --- a/devtools/client/webide/test/addons/fxdt-adapters-mac64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxdt-adapters-win32.xpi b/devtools/client/webide/test/addons/fxdt-adapters-win32.xpi Binary files differdeleted file mode 100644 index 5a512ae3d..000000000 --- a/devtools/client/webide/test/addons/fxdt-adapters-win32.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_1_0_simulator-linux.xpi b/devtools/client/webide/test/addons/fxos_1_0_simulator-linux.xpi Binary files differdeleted file mode 100644 index 238c97562..000000000 --- a/devtools/client/webide/test/addons/fxos_1_0_simulator-linux.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_1_0_simulator-linux64.xpi b/devtools/client/webide/test/addons/fxos_1_0_simulator-linux64.xpi Binary files differdeleted file mode 100644 index 2f86c4d4d..000000000 --- a/devtools/client/webide/test/addons/fxos_1_0_simulator-linux64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_1_0_simulator-mac64.xpi b/devtools/client/webide/test/addons/fxos_1_0_simulator-mac64.xpi Binary files differdeleted file mode 100644 index 6da2fcbad..000000000 --- a/devtools/client/webide/test/addons/fxos_1_0_simulator-mac64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_1_0_simulator-win32.xpi b/devtools/client/webide/test/addons/fxos_1_0_simulator-win32.xpi Binary files differdeleted file mode 100644 index 546deacaf..000000000 --- a/devtools/client/webide/test/addons/fxos_1_0_simulator-win32.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_2_0_simulator-linux.xpi b/devtools/client/webide/test/addons/fxos_2_0_simulator-linux.xpi Binary files differdeleted file mode 100644 index e2335e3a0..000000000 --- a/devtools/client/webide/test/addons/fxos_2_0_simulator-linux.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_2_0_simulator-linux64.xpi b/devtools/client/webide/test/addons/fxos_2_0_simulator-linux64.xpi Binary files differdeleted file mode 100644 index 75fe209ea..000000000 --- a/devtools/client/webide/test/addons/fxos_2_0_simulator-linux64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_2_0_simulator-mac64.xpi b/devtools/client/webide/test/addons/fxos_2_0_simulator-mac64.xpi Binary files differdeleted file mode 100644 index 58749f724..000000000 --- a/devtools/client/webide/test/addons/fxos_2_0_simulator-mac64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_2_0_simulator-win32.xpi b/devtools/client/webide/test/addons/fxos_2_0_simulator-win32.xpi Binary files differdeleted file mode 100644 index 60cffd46e..000000000 --- a/devtools/client/webide/test/addons/fxos_2_0_simulator-win32.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_3_0_simulator-linux.xpi b/devtools/client/webide/test/addons/fxos_3_0_simulator-linux.xpi Binary files differdeleted file mode 100644 index c54cae3aa..000000000 --- a/devtools/client/webide/test/addons/fxos_3_0_simulator-linux.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_3_0_simulator-linux64.xpi b/devtools/client/webide/test/addons/fxos_3_0_simulator-linux64.xpi Binary files differdeleted file mode 100644 index 9a650a888..000000000 --- a/devtools/client/webide/test/addons/fxos_3_0_simulator-linux64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_3_0_simulator-mac64.xpi b/devtools/client/webide/test/addons/fxos_3_0_simulator-mac64.xpi Binary files differdeleted file mode 100644 index d13dd78de..000000000 --- a/devtools/client/webide/test/addons/fxos_3_0_simulator-mac64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_3_0_simulator-win32.xpi b/devtools/client/webide/test/addons/fxos_3_0_simulator-win32.xpi Binary files differdeleted file mode 100644 index 92d5cc394..000000000 --- a/devtools/client/webide/test/addons/fxos_3_0_simulator-win32.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux.xpi b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux.xpi Binary files differdeleted file mode 100644 index 7a2a432ff..000000000 --- a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux64.xpi b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux64.xpi Binary files differdeleted file mode 100644 index d38932195..000000000 --- a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-mac64.xpi b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-mac64.xpi Binary files differdeleted file mode 100644 index 48e271d54..000000000 --- a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-mac64.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-win32.xpi b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-win32.xpi Binary files differdeleted file mode 100644 index 4c8bb2f10..000000000 --- a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-win32.xpi +++ /dev/null diff --git a/devtools/client/webide/test/addons/simulators.json b/devtools/client/webide/test/addons/simulators.json deleted file mode 100644 index 31d71b4da..000000000 --- a/devtools/client/webide/test/addons/simulators.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "stable": ["1.0", "2.0"], - "unstable": ["3.0", "3.0_tv"] -} diff --git a/devtools/client/webide/test/app.zip b/devtools/client/webide/test/app.zip Binary files differdeleted file mode 100644 index 8a706a3c9..000000000 --- a/devtools/client/webide/test/app.zip +++ /dev/null diff --git a/devtools/client/webide/test/app/index.html b/devtools/client/webide/test/app/index.html deleted file mode 100644 index 3ef4a25e2..000000000 --- a/devtools/client/webide/test/app/index.html +++ /dev/null @@ -1,6 +0,0 @@ -<!doctype html> -<html> -<head><title></title></head> -<body> -</body> -</html> diff --git a/devtools/client/webide/test/app/manifest.webapp b/devtools/client/webide/test/app/manifest.webapp deleted file mode 100644 index 4a198b1ca..000000000 --- a/devtools/client/webide/test/app/manifest.webapp +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "A name (in app directory)", - "description": "desc", - "launch_path": "/index.html" -} diff --git a/devtools/client/webide/test/browser.ini b/devtools/client/webide/test/browser.ini deleted file mode 100644 index 7d6e2de72..000000000 --- a/devtools/client/webide/test/browser.ini +++ /dev/null @@ -1,12 +0,0 @@ -[DEFAULT] -tags = devtools -subsuite = devtools -support-files = - addons/simulators.json - doc_tabs.html - head.js - templates.json - -[browser_tabs.js] -skip-if = e10s # Bug 1072167 - browser_tabs.js test fails under e10s -[browser_widget.js] diff --git a/devtools/client/webide/test/browser_tabs.js b/devtools/client/webide/test/browser_tabs.js deleted file mode 100644 index 541c6b363..000000000 --- a/devtools/client/webide/test/browser_tabs.js +++ /dev/null @@ -1,84 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -const TEST_URI = "http://example.com/browser/devtools/client/webide/test/doc_tabs.html"; - -function test() { - waitForExplicitFinish(); - requestCompleteLog(); - - Task.spawn(function* () { - // Since we test the connections set below, destroy the server in case it - // was left open. - DebuggerServer.destroy(); - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - - let tab = yield addTab(TEST_URI); - - let win = yield openWebIDE(); - let docProject = getProjectDocument(win); - let docRuntime = getRuntimeDocument(win); - - yield connectToLocal(win, docRuntime); - - is(Object.keys(DebuggerServer._connections).length, 1, "Locally connected"); - - yield selectTabProject(win, docProject); - - ok(win.UI.toolboxPromise, "Toolbox promise exists"); - yield win.UI.toolboxPromise; - - let project = win.AppManager.selectedProject; - is(project.location, TEST_URI, "Location is correct"); - is(project.name, "example.com: Test Tab", "Name is correct"); - - // Ensure tab list changes are noticed - let tabsNode = docProject.querySelector("#project-panel-tabs"); - is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available"); - yield removeTab(tab); - yield waitForUpdate(win, "project"); - yield waitForUpdate(win, "runtime-targets"); - is(tabsNode.querySelectorAll(".panel-item").length, 1, "1 tab available"); - - tab = yield addTab(TEST_URI); - - is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available"); - - yield removeTab(tab); - - is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available"); - - docProject.querySelector("#refresh-tabs").click(); - - yield waitForUpdate(win, "runtime-targets"); - - is(tabsNode.querySelectorAll(".panel-item").length, 1, "1 tab available"); - - yield win.Cmds.disconnectRuntime(); - yield closeWebIDE(win); - - DebuggerServer.destroy(); - }).then(finish, handleError); -} - -function connectToLocal(win, docRuntime) { - let deferred = promise.defer(); - win.AppManager.connection.once( - win.Connection.Events.CONNECTED, - () => deferred.resolve()); - docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click(); - return deferred.promise; -} - -function selectTabProject(win, docProject) { - return Task.spawn(function* () { - yield waitForUpdate(win, "runtime-targets"); - let tabsNode = docProject.querySelector("#project-panel-tabs"); - let tabNode = tabsNode.querySelectorAll(".panel-item")[1]; - let project = waitForUpdate(win, "project"); - tabNode.click(); - yield project; - }); -} diff --git a/devtools/client/webide/test/browser_widget.js b/devtools/client/webide/test/browser_widget.js deleted file mode 100644 index 7cfb2782b..000000000 --- a/devtools/client/webide/test/browser_widget.js +++ /dev/null @@ -1,15 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -function test() { - waitForExplicitFinish(); - Task.spawn(function* () { - let win = yield openWebIDE(); - ok(document.querySelector("#webide-button"), "Found WebIDE button"); - Services.prefs.setBoolPref("devtools.webide.widget.enabled", false); - ok(!document.querySelector("#webide-button"), "WebIDE button uninstalled"); - yield closeWebIDE(win); - Services.prefs.clearUserPref("devtools.webide.widget.enabled"); - }).then(finish, handleError); -} diff --git a/devtools/client/webide/test/build_app1/package.json b/devtools/client/webide/test/build_app1/package.json deleted file mode 100644 index c6ae833e1..000000000 --- a/devtools/client/webide/test/build_app1/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "webide": { - "prepackage": "echo \"{\\\"name\\\":\\\"hello\\\"}\" > manifest.webapp" - } -} diff --git a/devtools/client/webide/test/build_app2/manifest.webapp b/devtools/client/webide/test/build_app2/manifest.webapp deleted file mode 100644 index 0967ef424..000000000 --- a/devtools/client/webide/test/build_app2/manifest.webapp +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/devtools/client/webide/test/build_app2/package.json b/devtools/client/webide/test/build_app2/package.json deleted file mode 100644 index 5b7101620..000000000 --- a/devtools/client/webide/test/build_app2/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "webide": { - "prepackage": { - "command": "echo \"{\\\"name\\\":\\\"$NAME\\\"}\" > manifest.webapp", - "cwd": "./stage", - "env": ["NAME=world"] - }, - "packageDir": "./stage" - } -} diff --git a/devtools/client/webide/test/build_app_windows1/package.json b/devtools/client/webide/test/build_app_windows1/package.json deleted file mode 100644 index 036d2d767..000000000 --- a/devtools/client/webide/test/build_app_windows1/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "webide": { - "prepackage": "echo {\"name\":\"hello\"} > manifest.webapp" - } -} diff --git a/devtools/client/webide/test/build_app_windows2/manifest.webapp b/devtools/client/webide/test/build_app_windows2/manifest.webapp deleted file mode 100644 index 0967ef424..000000000 --- a/devtools/client/webide/test/build_app_windows2/manifest.webapp +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/devtools/client/webide/test/build_app_windows2/package.json b/devtools/client/webide/test/build_app_windows2/package.json deleted file mode 100644 index 83caf82ab..000000000 --- a/devtools/client/webide/test/build_app_windows2/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "webide": { - "prepackage": { - "command": "echo {\"name\":\"%NAME%\"} > manifest.webapp", - "cwd": "./stage", - "env": ["NAME=world"] - }, - "packageDir": "./stage" - } -} diff --git a/devtools/client/webide/test/chrome.ini b/devtools/client/webide/test/chrome.ini deleted file mode 100644 index b492ccd9b..000000000 --- a/devtools/client/webide/test/chrome.ini +++ /dev/null @@ -1,71 +0,0 @@ -[DEFAULT] -tags = devtools -support-files = - app/index.html - app/manifest.webapp - app.zip - addons/simulators.json - addons/fxos_1_0_simulator-linux.xpi - addons/fxos_1_0_simulator-linux64.xpi - addons/fxos_1_0_simulator-win32.xpi - addons/fxos_1_0_simulator-mac64.xpi - addons/fxos_2_0_simulator-linux.xpi - addons/fxos_2_0_simulator-linux64.xpi - addons/fxos_2_0_simulator-win32.xpi - addons/fxos_2_0_simulator-mac64.xpi - addons/fxos_3_0_simulator-linux.xpi - addons/fxos_3_0_simulator-linux64.xpi - addons/fxos_3_0_simulator-win32.xpi - addons/fxos_3_0_simulator-mac64.xpi - addons/fxos_3_0_tv_simulator-linux.xpi - addons/fxos_3_0_tv_simulator-linux64.xpi - addons/fxos_3_0_tv_simulator-win32.xpi - addons/fxos_3_0_tv_simulator-mac64.xpi - addons/adbhelper-linux.xpi - addons/adbhelper-linux64.xpi - addons/adbhelper-win32.xpi - addons/adbhelper-mac64.xpi - addons/fxdt-adapters-linux32.xpi - addons/fxdt-adapters-linux64.xpi - addons/fxdt-adapters-win32.xpi - addons/fxdt-adapters-mac64.xpi - build_app1/package.json - build_app2/manifest.webapp - build_app2/package.json - build_app2/stage/empty-directory - build_app_windows1/package.json - build_app_windows2/manifest.webapp - build_app_windows2/package.json - build_app_windows2/stage/empty-directory - device_front_shared.js - head.js - hosted_app.manifest - templates.json - ../../shared/test/browser_devices.json - validator/* - -[test_basic.html] -[test_newapp.html] -skip-if = (os == "win" && os_version == "10.0") # Bug 1197053 -[test_import.html] -skip-if = (os == "linux") # Bug 1024734 -[test_duplicate_import.html] -[test_runtime.html] -[test_manifestUpdate.html] -[test_addons.html] -skip-if = true # Bug 1201392 - Update add-ons after migration -[test_device_runtime.html] -[test_device_permissions.html] -[test_autoconnect_runtime.html] -[test_autoselect_project.html] -[test_telemetry.html] -skip-if = true # Bug 1201392 - Update add-ons after migration -[test_device_preferences.html] -[test_device_settings.html] -[test_fullscreenToolbox.html] -[test_zoom.html] -[test_build.html] -[test_simulators.html] -skip-if = true # Bug 1281138 - intermittent failures -[test_toolbox.html] -[test_app_validator.html] diff --git a/devtools/client/webide/test/device_front_shared.js b/devtools/client/webide/test/device_front_shared.js deleted file mode 100644 index 0ddb5df21..000000000 --- a/devtools/client/webide/test/device_front_shared.js +++ /dev/null @@ -1,219 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -var customName; -var customValue; -var customValueType; -var customBtn; -var newField; -var change; -var doc; -var iframe; -var resetBtn; -var found = false; - -function setDocument(frame) { - iframe = frame; - doc = iframe.contentWindow.document; -} - -function fieldChange(fields, id) { - // Trigger existing field change - for (let field of fields) { - if (field.id == id) { - let button = doc.getElementById("btn-" + id); - found = true; - ok(button.classList.contains("hide"), "Default field detected"); - field.value = "custom"; - field.click(); - ok(!button.classList.contains("hide"), "Custom field detected"); - break; - } - } - ok(found, "Found " + id + " line"); -} - -function addNewField() { - found = false; - customName = doc.querySelector("#custom-value-name"); - customValue = doc.querySelector("#custom-value-text"); - customValueType = doc.querySelector("#custom-value-type"); - customBtn = doc.querySelector("#custom-value"); - change = doc.createEvent("HTMLEvents"); - change.initEvent("change", false, true); - - // Add a new custom string - customValueType.value = "string"; - customValueType.dispatchEvent(change); - customName.value = "new-string-field!"; - customValue.value = "test"; - customBtn.click(); - let newField = doc.querySelector("#new-string-field"); - if (newField) { - found = true; - is(newField.type, "text", "Custom type is a string"); - is(newField.value, "test", "Custom string new value is correct"); - } - ok(found, "Found new string field line"); - is(customName.value, "", "Custom string name reset"); - is(customValue.value, "", "Custom string value reset"); -} - -function addNewFieldWithEnter() { - // Add a new custom value with the <enter> key - found = false; - customName.value = "new-string-field-two"; - customValue.value = "test"; - let newAddField = doc.querySelector("#add-custom-field"); - let enter = doc.createEvent("KeyboardEvent"); - enter.initKeyEvent( - "keyup", true, true, null, false, false, false, false, 13, 0); - newAddField.dispatchEvent(enter); - newField = doc.querySelector("#new-string-field-two"); - if (newField) { - found = true; - is(newField.type, "text", "Custom type is a string"); - is(newField.value, "test", "Custom string new value is correct"); - } - ok(found, "Found new string field line"); - is(customName.value, "", "Custom string name reset"); - is(customValue.value, "", "Custom string value reset"); -} - -function editExistingField() { - // Edit existing custom string preference - newField.value = "test2"; - newField.click(); - is(newField.value, "test2", "Custom string existing value is correct"); -} - -function addNewFieldInteger() { - // Add a new custom integer preference with a valid integer - customValueType.value = "number"; - customValueType.dispatchEvent(change); - customName.value = "new-integer-field"; - customValue.value = 1; - found = false; - - customBtn.click(); - newField = doc.querySelector("#new-integer-field"); - if (newField) { - found = true; - is(newField.type, "number", "Custom type is a number"); - is(newField.value, "1", "Custom integer value is correct"); - } - ok(found, "Found new integer field line"); - is(customName.value, "", "Custom integer name reset"); - is(customValue.value, "", "Custom integer value reset"); -} - -var editFieldInteger = Task.async(function* () { - // Edit existing custom integer preference - newField.value = 3; - newField.click(); - is(newField.value, "3", "Custom integer existing value is correct"); - - // Reset a custom field - let resetBtn = doc.querySelector("#btn-new-integer-field"); - resetBtn.click(); - - try { - yield iframe.contentWindow.configView._defaultField; - } catch (err) { - let fieldRow = doc.querySelector("#row-new-integer-field"); - if (!fieldRow) { - found = false; - } - ok(!found, "Custom field removed"); - } -}); - -var resetExistingField = Task.async(function* (id) { - let existing = doc.getElementById(id); - existing.click(); - is(existing.checked, true, "Existing boolean value is correct"); - resetBtn = doc.getElementById("btn-" + id); - resetBtn.click(); - - yield iframe.contentWindow.configView._defaultField; - - ok(resetBtn.classList.contains("hide"), true, "Reset button hidden"); - is(existing.checked, true, "Existing field reset"); -}); - -var resetNewField = Task.async(function* (id) { - let custom = doc.getElementById(id); - custom.click(); - is(custom.value, "test", "New string value is correct"); - resetBtn = doc.getElementById("btn-" + id); - resetBtn.click(); - - yield iframe.contentWindow.configView._defaultField; - - ok(resetBtn.classList.contains("hide"), true, "Reset button hidden"); -}); - -function addNewFieldBoolean() { - customValueType.value = "boolean"; - customValueType.dispatchEvent(change); - customName.value = "new-boolean-field"; - customValue.checked = true; - found = false; - customBtn.click(); - newField = doc.querySelector("#new-boolean-field"); - if (newField) { - found = true; - is(newField.type, "checkbox", "Custom type is a checkbox"); - is(newField.checked, true, "Custom boolean value is correctly true"); - } - ok(found, "Found new boolean field line"); - - // Mouse event trigger - var mouseClick = new MouseEvent("click", { - canBubble: true, - cancelable: true, - view: doc.parent, - }); - - found = false; - customValueType.value = "boolean"; - customValueType.dispatchEvent(change); - customName.value = "new-boolean-field2"; - customValue.dispatchEvent(mouseClick); - customBtn.dispatchEvent(mouseClick); - newField = doc.querySelector("#new-boolean-field2"); - if (newField) { - found = true; - is(newField.checked, true, "Custom boolean value is correctly false"); - } - ok(found, "Found new second boolean field line"); - - is(customName.value, "", "Custom boolean name reset"); - is(customValue.checked, false, "Custom boolean value reset"); - - newField.click(); - is(newField.checked, false, "Custom boolean existing value is correct"); -} - -function searchFields(deck, keyword) { - // Search for a non-existent field - let searchField = doc.querySelector("#search-bar"); - searchField.value = "![o_O]!"; - searchField.click(); - - let fieldsTotal = doc.querySelectorAll("tr.edit-row").length; - let hiddenFields = doc.querySelectorAll("tr.hide"); - is(hiddenFields.length, fieldsTotal, "Search keyword not found"); - - // Search for existing fields - searchField.value = keyword; - searchField.click(); - hiddenFields = doc.querySelectorAll("tr.hide"); - isnot(hiddenFields.length, fieldsTotal, "Search keyword found"); - - doc.querySelector("#close").click(); - - ok(!deck.selectedPanel, "No panel selected"); -} diff --git a/devtools/client/webide/test/doc_tabs.html b/devtools/client/webide/test/doc_tabs.html deleted file mode 100644 index 4901289fc..000000000 --- a/devtools/client/webide/test/doc_tabs.html +++ /dev/null @@ -1,15 +0,0 @@ -<!-- Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ --> -<!doctype html> - -<html> - <head> - <meta charset="utf-8"/> - <title>Test Tab</title> - </head> - - <body> - Test Tab - </body> - -</html> diff --git a/devtools/client/webide/test/head.js b/devtools/client/webide/test/head.js deleted file mode 100644 index c0171c730..000000000 --- a/devtools/client/webide/test/head.js +++ /dev/null @@ -1,248 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -var {utils: Cu, classes: Cc, interfaces: Ci} = Components; - -const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); -const { FileUtils } = require("resource://gre/modules/FileUtils.jsm"); -const { gDevTools } = require("devtools/client/framework/devtools"); -const promise = require("promise"); -const Services = require("Services"); -const { Task } = require("devtools/shared/task"); -const { AppProjects } = require("devtools/client/webide/modules/app-projects"); -const DevToolsUtils = require("devtools/shared/DevToolsUtils"); -const { DebuggerServer } = require("devtools/server/main"); -const flags = require("devtools/shared/flags"); -flags.testing = true; - -var TEST_BASE; -if (window.location === "chrome://browser/content/browser.xul") { - TEST_BASE = "chrome://mochitests/content/browser/devtools/client/webide/test/"; -} else { - TEST_BASE = "chrome://mochitests/content/chrome/devtools/client/webide/test/"; -} - -Services.prefs.setBoolPref("devtools.webide.enabled", true); -Services.prefs.setBoolPref("devtools.webide.enableLocalRuntime", true); - -Services.prefs.setCharPref("devtools.webide.addonsURL", TEST_BASE + "addons/simulators.json"); -Services.prefs.setCharPref("devtools.webide.simulatorAddonsURL", TEST_BASE + "addons/fxos_#SLASHED_VERSION#_simulator-#OS#.xpi"); -Services.prefs.setCharPref("devtools.webide.adbAddonURL", TEST_BASE + "addons/adbhelper-#OS#.xpi"); -Services.prefs.setCharPref("devtools.webide.adaptersAddonURL", TEST_BASE + "addons/fxdt-adapters-#OS#.xpi"); -Services.prefs.setCharPref("devtools.webide.templatesURL", TEST_BASE + "templates.json"); -Services.prefs.setCharPref("devtools.devices.url", TEST_BASE + "browser_devices.json"); - -var registerCleanupFunction = registerCleanupFunction || - SimpleTest.registerCleanupFunction; -registerCleanupFunction(() => { - flags.testing = false; - Services.prefs.clearUserPref("devtools.webide.enabled"); - Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime"); - Services.prefs.clearUserPref("devtools.webide.autoinstallADBHelper"); - Services.prefs.clearUserPref("devtools.webide.autoinstallFxdtAdapters"); - Services.prefs.clearUserPref("devtools.webide.busyTimeout"); - Services.prefs.clearUserPref("devtools.webide.lastSelectedProject"); - Services.prefs.clearUserPref("devtools.webide.lastConnectedRuntime"); -}); - -var openWebIDE = Task.async(function* (autoInstallAddons) { - info("opening WebIDE"); - - Services.prefs.setBoolPref("devtools.webide.autoinstallADBHelper", !!autoInstallAddons); - Services.prefs.setBoolPref("devtools.webide.autoinstallFxdtAdapters", !!autoInstallAddons); - - let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher); - let win = ww.openWindow(null, "chrome://webide/content/", "webide", "chrome,centerscreen,resizable", null); - - yield new Promise(resolve => { - win.addEventListener("load", function onLoad() { - win.removeEventListener("load", onLoad); - SimpleTest.requestCompleteLog(); - SimpleTest.executeSoon(resolve); - }); - }); - - info("WebIDE open"); - - return win; -}); - -function closeWebIDE(win) { - info("Closing WebIDE"); - - let deferred = promise.defer(); - - Services.prefs.clearUserPref("devtools.webide.widget.enabled"); - - win.addEventListener("unload", function onUnload() { - win.removeEventListener("unload", onUnload); - info("WebIDE closed"); - SimpleTest.executeSoon(() => { - deferred.resolve(); - }); - }); - - win.close(); - - return deferred.promise; -} - -function removeAllProjects() { - return Task.spawn(function* () { - yield AppProjects.load(); - // use a new array so we're not iterating over the same - // underlying array that's being modified by AppProjects - let projects = AppProjects.projects.map(p => p.location); - for (let i = 0; i < projects.length; i++) { - yield AppProjects.remove(projects[i]); - } - }); -} - -function nextTick() { - let deferred = promise.defer(); - SimpleTest.executeSoon(() => { - deferred.resolve(); - }); - - return deferred.promise; -} - -function waitForUpdate(win, update) { - info("Wait: " + update); - let deferred = promise.defer(); - win.AppManager.on("app-manager-update", function onUpdate(e, what) { - info("Got: " + what); - if (what !== update) { - return; - } - win.AppManager.off("app-manager-update", onUpdate); - deferred.resolve(win.UI._updatePromise); - }); - return deferred.promise; -} - -function waitForTime(time) { - let deferred = promise.defer(); - setTimeout(() => { - deferred.resolve(); - }, time); - return deferred.promise; -} - -function documentIsLoaded(doc) { - let deferred = promise.defer(); - if (doc.readyState == "complete") { - deferred.resolve(); - } else { - doc.addEventListener("readystatechange", function onChange() { - if (doc.readyState == "complete") { - doc.removeEventListener("readystatechange", onChange); - deferred.resolve(); - } - }); - } - return deferred.promise; -} - -function lazyIframeIsLoaded(iframe) { - let deferred = promise.defer(); - iframe.addEventListener("load", function onLoad() { - iframe.removeEventListener("load", onLoad, true); - deferred.resolve(nextTick()); - }, true); - return deferred.promise; -} - -function addTab(aUrl, aWindow) { - info("Adding tab: " + aUrl); - - let deferred = promise.defer(); - let targetWindow = aWindow || window; - let targetBrowser = targetWindow.gBrowser; - - targetWindow.focus(); - let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl); - let linkedBrowser = tab.linkedBrowser; - - BrowserTestUtils.browserLoaded(linkedBrowser).then(function () { - info("Tab added and finished loading: " + aUrl); - deferred.resolve(tab); - }); - - return deferred.promise; -} - -function removeTab(aTab, aWindow) { - info("Removing tab."); - - let deferred = promise.defer(); - let targetWindow = aWindow || window; - let targetBrowser = targetWindow.gBrowser; - let tabContainer = targetBrowser.tabContainer; - - tabContainer.addEventListener("TabClose", function onClose(aEvent) { - tabContainer.removeEventListener("TabClose", onClose, false); - info("Tab removed and finished closing."); - deferred.resolve(); - }, false); - - targetBrowser.removeTab(aTab); - return deferred.promise; -} - -function getRuntimeDocument(win) { - return win.document.querySelector("#runtime-listing-panel-details").contentDocument; -} - -function getProjectDocument(win) { - return win.document.querySelector("#project-listing-panel-details").contentDocument; -} - -function getRuntimeWindow(win) { - return win.document.querySelector("#runtime-listing-panel-details").contentWindow; -} - -function getProjectWindow(win) { - return win.document.querySelector("#project-listing-panel-details").contentWindow; -} - -function connectToLocalRuntime(win) { - info("Loading local runtime."); - - let panelNode; - let runtimePanel; - - runtimePanel = getRuntimeDocument(win); - - panelNode = runtimePanel.querySelector("#runtime-panel"); - let items = panelNode.querySelectorAll(".runtime-panel-item-other"); - is(items.length, 2, "Found 2 custom runtime buttons"); - - let updated = waitForUpdate(win, "runtime-global-actors"); - items[1].click(); - return updated; -} - -function handleError(aError) { - ok(false, "Got an error: " + aError.message + "\n" + aError.stack); - finish(); -} - -function waitForConnectionChange(expectedState, count = 1) { - return new Promise(resolve => { - let onConnectionChange = (_, state) => { - if (state != expectedState) { - return; - } - if (--count != 0) { - return; - } - DebuggerServer.off("connectionchange", onConnectionChange); - resolve(); - }; - DebuggerServer.on("connectionchange", onConnectionChange); - }); -} diff --git a/devtools/client/webide/test/hosted_app.manifest b/devtools/client/webide/test/hosted_app.manifest deleted file mode 100644 index ab5069978..000000000 --- a/devtools/client/webide/test/hosted_app.manifest +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "hosted manifest name property" -} diff --git a/devtools/client/webide/test/templates.json b/devtools/client/webide/test/templates.json deleted file mode 100644 index e6ffa3efe..000000000 --- a/devtools/client/webide/test/templates.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "file": "chrome://mochitests/content/chrome/devtools/client/webide/test/app.zip?1", - "icon": "ximgx1", - "name": "app name 1", - "description": "app description 1" - }, - { - "file": "chrome://mochitests/content/chrome/devtools/client/webide/test/app.zip?2", - "icon": "ximgx2", - "name": "app name 2", - "description": "app description 2" - } -] diff --git a/devtools/client/webide/test/test_addons.html b/devtools/client/webide/test/test_addons.html deleted file mode 100644 index 5a1bc7504..000000000 --- a/devtools/client/webide/test/test_addons.html +++ /dev/null @@ -1,176 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - const {GetAvailableAddons} = require("devtools/client/webide/modules/addons"); - const {Devices} = Cu.import("resource://devtools/shared/apps/Devices.jsm"); - const {Simulators} = require("devtools/client/webide/modules/simulators"); - - let adbAddonsInstalled = promise.defer(); - Devices.on("addon-status-updated", function onUpdate1() { - Devices.off("addon-status-updated", onUpdate1); - adbAddonsInstalled.resolve(); - }); - - function getVersion(name) { - return name.match(/(\d+\.\d+)/)[0]; - } - - function onSimulatorInstalled(name) { - let deferred = promise.defer(); - Simulators.on("updated", function onUpdate() { - Simulators.findSimulatorAddons().then(addons => { - for (let addon of addons) { - if (name == addon.name.replace(" Simulator", "")) { - Simulators.off("updated", onUpdate); - nextTick().then(deferred.resolve); - return; - } - } - }); - }); - return deferred.promise; - } - - function installSimulatorFromUI(doc, name) { - let li = doc.querySelector('[addon="simulator-' + getVersion(name) + '"]'); - li.querySelector(".install-button").click(); - return onSimulatorInstalled(name); - } - - function uninstallSimulatorFromUI(doc, name) { - let deferred = promise.defer(); - Simulators.on("updated", function onUpdate() { - nextTick().then(() => { - let li = doc.querySelector('[status="uninstalled"][addon="simulator-' + getVersion(name) + '"]'); - if (li) { - Simulators.off("updated", onUpdate); - deferred.resolve(); - } else { - deferred.reject("Can't find item"); - } - }); - }); - let li = doc.querySelector('[status="installed"][addon="simulator-' + getVersion(name) + '"]'); - li.querySelector(".uninstall-button").click(); - return deferred.promise; - } - - function uninstallADBFromUI(doc) { - let deferred = promise.defer(); - Devices.on("addon-status-updated", function onUpdate() { - nextTick().then(() => { - let li = doc.querySelector('[status="uninstalled"][addon="adb"]'); - if (li) { - Devices.off("addon-status-updated", onUpdate); - deferred.resolve(); - } else { - deferred.reject("Can't find item"); - } - }) - }); - let li = doc.querySelector('[status="installed"][addon="adb"]'); - li.querySelector(".uninstall-button").click(); - return deferred.promise; - } - - Task.spawn(function*() { - - ok(!Devices.helperAddonInstalled, "Helper not installed"); - - let win = yield openWebIDE(true); - let docRuntime = getRuntimeDocument(win); - - yield adbAddonsInstalled.promise; - - ok(Devices.helperAddonInstalled, "Helper has been auto-installed"); - - yield nextTick(); - - let addons = yield GetAvailableAddons(); - - is(addons.simulators.length, 3, "3 simulator addons to install"); - - let sim10 = addons.simulators.filter(a => a.version == "1.0")[0]; - sim10.install(); - - yield onSimulatorInstalled("Firefox OS 1.0"); - - win.Cmds.showAddons(); - - let frame = win.document.querySelector("#deck-panel-addons"); - let addonDoc = frame.contentWindow.document; - let lis; - - lis = addonDoc.querySelectorAll("li"); - is(lis.length, 5, "5 addons listed"); - - lis = addonDoc.querySelectorAll('li[status="installed"]'); - is(lis.length, 3, "3 addons installed"); - - lis = addonDoc.querySelectorAll('li[status="uninstalled"]'); - is(lis.length, 2, "2 addons uninstalled"); - - info("Uninstalling Simulator 2.0"); - - yield installSimulatorFromUI(addonDoc, "Firefox OS 2.0"); - - info("Uninstalling Simulator 3.0"); - - yield installSimulatorFromUI(addonDoc, "Firefox OS 3.0"); - - yield nextTick(); - - let panelNode = docRuntime.querySelector("#runtime-panel"); - let items; - - items = panelNode.querySelectorAll(".runtime-panel-item-usb"); - is(items.length, 1, "Found one runtime button"); - - items = panelNode.querySelectorAll(".runtime-panel-item-simulator"); - is(items.length, 3, "Found 3 simulators button"); - - yield uninstallSimulatorFromUI(addonDoc, "Firefox OS 1.0"); - yield uninstallSimulatorFromUI(addonDoc, "Firefox OS 2.0"); - yield uninstallSimulatorFromUI(addonDoc, "Firefox OS 3.0"); - - items = panelNode.querySelectorAll(".runtime-panel-item-simulator"); - is(items.length, 0, "No simulator listed"); - - let w = addonDoc.querySelector(".warning"); - let display = addonDoc.defaultView.getComputedStyle(w).display - is(display, "none", "Warning about missing ADB hidden"); - - yield uninstallADBFromUI(addonDoc, "adb"); - - items = panelNode.querySelectorAll(".runtime-panel-item-usb"); - is(items.length, 0, "No usb runtime listed"); - - display = addonDoc.defaultView.getComputedStyle(w).display - is(display, "block", "Warning about missing ADB present"); - - yield closeWebIDE(win); - - SimpleTest.finish(); - - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_app_validator.html b/devtools/client/webide/test/test_app_validator.html deleted file mode 100644 index 60ed29aac..000000000 --- a/devtools/client/webide/test/test_app_validator.html +++ /dev/null @@ -1,205 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - const Cu = Components.utils; - const Cc = Components.classes; - const Ci = Components.interfaces; - Cu.import("resource://testing-common/httpd.js"); - const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); - - const {AppValidator} = require("devtools/client/webide/modules/app-validator"); - const Services = require("Services"); - const nsFile = Components.Constructor("@mozilla.org/file/local;1", - "nsILocalFile", "initWithPath"); - const cr = Cc["@mozilla.org/chrome/chrome-registry;1"] - .getService(Ci.nsIChromeRegistry); - const strings = Services.strings.createBundle("chrome://devtools/locale/app-manager.properties"); - let httpserver, origin; - - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - httpserver = new HttpServer(); - httpserver.start(-1); - origin = "http://localhost:" + httpserver.identity.primaryPort + "/"; - - next(); - } - - function createHosted(path, manifestFile="/manifest.webapp") { - let dirPath = getTestFilePath("validator/" + path); - httpserver.registerDirectory("/", nsFile(dirPath)); - return new AppValidator({ - type: "hosted", - location: origin + manifestFile - }); - } - - function createPackaged(path) { - let dirPath = getTestFilePath("validator/" + path); - return new AppValidator({ - type: "packaged", - location: dirPath - }); - } - - function next() { - let test = tests.shift(); - if (test) { - try { - test(); - } catch(e) { - console.error("exception", String(e), e, e.stack); - } - } else { - httpserver.stop(function() { - SimpleTest.finish(); - }); - } - } - - let tests = [ - // Test a 100% valid example - function () { - let validator = createHosted("valid"); - validator.validate().then(() => { - is(validator.errors.length, 0, "valid app got no error"); - is(validator.warnings.length, 0, "valid app got no warning"); - - next(); - }); - }, - - function () { - let validator = createPackaged("valid"); - validator.validate().then(() => { - is(validator.errors.length, 0, "valid packaged app got no error"); - is(validator.warnings.length, 0, "valid packaged app got no warning"); - - next(); - }); - }, - - // Test a launch path that returns a 404 - function () { - let validator = createHosted("wrong-launch-path"); - validator.validate().then(() => { - is(validator.errors.length, 1, "app with non-existant launch path got an error"); - is(validator.errors[0], strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [origin + "wrong-path.html", 404], 2), - "with the right error message"); - is(validator.warnings.length, 0, "but no warning"); - next(); - }); - }, - function () { - let validator = createPackaged("wrong-launch-path"); - validator.validate().then(() => { - is(validator.errors.length, 1, "app with wrong path got an error"); - let file = nsFile(validator.location); - file.append("wrong-path.html"); - let url = Services.io.newFileURI(file); - is(validator.errors[0], strings.formatStringFromName("validator.accessFailedLaunchPath", [url.spec], 1), - "with the expected message"); - is(validator.warnings.length, 0, "but no warning"); - - next(); - }); - }, - - // Test when using a non-absolute path for launch_path - function () { - let validator = createHosted("non-absolute-path"); - validator.validate().then(() => { - is(validator.errors.length, 1, "app with non absolute path got an error"); - is(validator.errors[0], strings.formatStringFromName("validator.nonAbsoluteLaunchPath", ["non-absolute.html"], 1), - "with expected message"); - is(validator.warnings.length, 0, "but no warning"); - next(); - }); - }, - function () { - let validator = createPackaged("non-absolute-path"); - validator.validate().then(() => { - is(validator.errors.length, 1, "app with non absolute path got an error"); - is(validator.errors[0], strings.formatStringFromName("validator.nonAbsoluteLaunchPath", ["non-absolute.html"], 1), - "with expected message"); - is(validator.warnings.length, 0, "but no warning"); - next(); - }); - }, - - // Test multiple failures (missing name [error] and icon [warning]) - function () { - let validator = createHosted("no-name-or-icon"); - validator.validate().then(() => { - checkNoNameOrIcon(validator); - }); - }, - function () { - let validator = createPackaged("no-name-or-icon"); - validator.validate().then(() => { - checkNoNameOrIcon(validator); - }); - }, - - // Test a regular URL instead of a direct link to the manifest - function () { - let validator = createHosted("valid", "/"); - validator.validate().then(() => { - is(validator.warnings.length, 0, "manifest found got no warning"); - is(validator.errors.length, 0, "manifest found got no error"); - - next(); - }); - }, - - // Test finding a manifest at origin's root - function () { - let validator = createHosted("valid", "/unexisting-dir"); - validator.validate().then(() => { - is(validator.warnings.length, 0, "manifest found at origin root got no warning"); - is(validator.errors.length, 0, "manifest found at origin root got no error"); - - next(); - }); - }, - - // Test priorization of manifest.webapp at provided location instead of a manifest located at origin's root - function() { - let validator = createHosted("valid", "/alsoValid"); - validator.validate().then(() => { - is(validator.manifest.name, "valid at subfolder", "manifest at subfolder was used"); - - next(); - }); - } - ]; - - function checkNoNameOrIcon(validator) { - is(validator.errors.length, 1, "app with no name has an error"); - is(validator.errors[0], - strings.GetStringFromName("validator.missNameManifestProperty"), - "with expected message"); - is(validator.warnings.length, 1, "app with no icon has a warning"); - is(validator.warnings[0], - strings.GetStringFromName("validator.missIconsManifestProperty"), - "with expected message"); - next(); - } - - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_autoconnect_runtime.html b/devtools/client/webide/test/test_autoconnect_runtime.html deleted file mode 100644 index 3de00473a..000000000 --- a/devtools/client/webide/test/test_autoconnect_runtime.html +++ /dev/null @@ -1,94 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function*() { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - - let win = yield openWebIDE(); - let docRuntime = getRuntimeDocument(win); - - let fakeRuntime = { - type: "USB", - connect: function(connection) { - is(connection, win.AppManager.connection, "connection is valid"); - connection.host = null; // force connectPipe - connection.connect(); - return promise.resolve(); - }, - - get id() { - return "fakeRuntime"; - }, - - get name() { - return "fakeRuntime"; - } - }; - win.AppManager.runtimeList.usb.push(fakeRuntime); - win.AppManager.update("runtime-list"); - - let panelNode = docRuntime.querySelector("#runtime-panel"); - let items = panelNode.querySelectorAll(".runtime-panel-item-usb"); - is(items.length, 1, "Found one runtime button"); - - let connectionsChanged = waitForConnectionChange("opened", 2); - items[0].click(); - - ok(win.document.querySelector("window").className, "busy", "UI is busy"); - yield win.UI._busyPromise; - - yield connectionsChanged; - is(Object.keys(DebuggerServer._connections).length, 2, "Connected"); - - connectionsChanged = waitForConnectionChange("closed", 2); - - yield nextTick(); - yield closeWebIDE(win); - - yield connectionsChanged; - is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected"); - - connectionsChanged = waitForConnectionChange("opened", 2); - - win = yield openWebIDE(); - - win.AppManager.runtimeList.usb.push(fakeRuntime); - win.AppManager.update("runtime-list"); - - yield waitForUpdate(win, "runtime-targets"); - - yield connectionsChanged; - is(Object.keys(DebuggerServer._connections).length, 2, "Automatically reconnected"); - - yield win.Cmds.disconnectRuntime(); - - yield closeWebIDE(win); - - DebuggerServer.destroy(); - - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_autoselect_project.html b/devtools/client/webide/test/test_autoselect_project.html deleted file mode 100644 index cd5793559..000000000 --- a/devtools/client/webide/test/test_autoselect_project.html +++ /dev/null @@ -1,110 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function* () { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - - let win = yield openWebIDE(); - let docRuntime = getRuntimeDocument(win); - let docProject = getProjectDocument(win); - - let panelNode = docRuntime.querySelector("#runtime-panel"); - let items = panelNode.querySelectorAll(".runtime-panel-item-other"); - is(items.length, 2, "Found 2 runtime buttons"); - - // Connect to local runtime - let connectionsChanged = waitForConnectionChange("opened", 2); - items[1].click(); - - yield waitForUpdate(win, "runtime-targets"); - - yield connectionsChanged; - is(Object.keys(DebuggerServer._connections).length, 2, "Locally connected"); - - ok(win.AppManager.isMainProcessDebuggable(), "Main process available"); - - // Select main process - yield win.Cmds.showProjectPanel(); - yield waitForUpdate(win, "runtime-targets"); - SimpleTest.executeSoon(() => { - docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click(); - }); - - yield waitForUpdate(win, "project"); - - let lastProject = Services.prefs.getCharPref("devtools.webide.lastSelectedProject"); - is(lastProject, "mainProcess:", "Last project is main process"); - - connectionsChanged = waitForConnectionChange("closed", 2); - - yield nextTick(); - yield closeWebIDE(win); - - yield connectionsChanged; - is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected"); - - connectionsChanged = waitForConnectionChange("opened", 2); - - // Re-open, should reselect main process after connection - win = yield openWebIDE(); - - docRuntime = getRuntimeDocument(win); - - panelNode = docRuntime.querySelector("#runtime-panel"); - items = panelNode.querySelectorAll(".runtime-panel-item-other"); - is(items.length, 2, "Found 2 runtime buttons"); - - // Connect to local runtime - items[1].click(); - - yield waitForUpdate(win, "runtime-targets"); - - yield connectionsChanged; - is(Object.keys(DebuggerServer._connections).length, 2, "Locally connected"); - ok(win.AppManager.isMainProcessDebuggable(), "Main process available"); - is(win.AppManager.selectedProject.type, "mainProcess", "Main process reselected"); - - // Wait for the toolbox to be fully loaded - yield win.UI.toolboxPromise; - - // If we happen to pass a project object targeting the same context, - // here, the main process, the `selectedProject` attribute shouldn't be updated - // so that no `project` event would fire. - let oldProject = win.AppManager.selectedProject; - win.AppManager.selectedProject = { - type: "mainProcess" - }; - is(win.AppManager.selectedProject, oldProject, "AppManager.selectedProject shouldn't be updated if we selected the same project"); - - yield win.Cmds.disconnectRuntime(); - - yield closeWebIDE(win); - - DebuggerServer.destroy(); - - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_basic.html b/devtools/client/webide/test/test_basic.html deleted file mode 100644 index e619a0f06..000000000 --- a/devtools/client/webide/test/test_basic.html +++ /dev/null @@ -1,55 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function* () { - let win = yield openWebIDE(); - - const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser"); - yield gDevToolsBrowser.isWebIDEInitialized.promise; - ok(true, "WebIDE was initialized"); - - ok(win, "Found a window"); - ok(win.AppManager, "App Manager accessible"); - let appmgr = win.AppManager; - ok(appmgr.connection, "App Manager connection ready"); - ok(appmgr.runtimeList, "Runtime list ready"); - - // test error reporting - let nbox = win.document.querySelector("#notificationbox"); - let notification = nbox.getNotificationWithValue("webide:errornotification"); - ok(!notification, "No notification yet"); - let deferred = promise.defer(); - nextTick().then(() => { - deferred.reject("BOOM!"); - }); - try { - yield win.UI.busyUntil(deferred.promise, "xx"); - } catch(e) {/* This *will* fail */} - notification = nbox.getNotificationWithValue("webide:errornotification"); - ok(notification, "Error has been reported"); - - yield closeWebIDE(win); - - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_build.html b/devtools/client/webide/test/test_build.html deleted file mode 100644 index ffb01998c..000000000 --- a/devtools/client/webide/test/test_build.html +++ /dev/null @@ -1,128 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - let {TextDecoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {}); - let {ProjectBuilding} = require("devtools/client/webide/modules/build"); - - Task.spawn(function* () { - let win = yield openWebIDE(); - let winProject = getProjectWindow(win); - let AppManager = win.AppManager; - - function isProjectMarkedAsValid() { - let details = win.frames[0]; - return !details.document.body.classList.contains("error"); - } - - // # Test first package.json like this: `{webide: {prepackage: "command line string"}}` - let platform = Services.appShell.hiddenDOMWindow.navigator.platform; - let testSuffix = ""; - if (platform.indexOf("Win") != -1) { - testSuffix = "_windows"; - } - - let packagedAppLocation = getTestFilePath("build_app" + testSuffix + "1"); - - let onValidated = waitForUpdate(win, "project-validated"); - let onDetails = waitForUpdate(win, "details"); - yield winProject.projectList.importPackagedApp(packagedAppLocation); - yield onValidated; - yield onDetails; - - let project = win.AppManager.selectedProject; - - ok(!project.manifest, "manifest includes name"); - is(project.name, "--", "Display name uses manifest name"); - - let loggedMessages = []; - let logger = function (msg) { - loggedMessages.push(msg); - } - - yield ProjectBuilding.build({ - project, - logger - }); - let packageDir = yield ProjectBuilding.getPackageDir(project); - is(packageDir, packagedAppLocation, "no custom packagedir"); - is(loggedMessages[0], "start", "log messages are correct"); - ok(loggedMessages[1].indexOf("Running pre-package hook") != -1, "log messages are correct"); - is(loggedMessages[2], "Terminated with error code: 0", "log messages are correct"); - is(loggedMessages[3], "succeed", "log messages are correct"); - - // Trigger validation - yield AppManager.validateAndUpdateProject(AppManager.selectedProject); - yield nextTick(); - - ok("name" in project.manifest, "manifest includes name"); - is(project.name, "hello", "Display name uses manifest name"); - is(project.manifest.name, project.name, "Display name uses manifest name"); - - yield OS.File.remove(OS.Path.join(packagedAppLocation, "manifest.webapp")); - - // # Now test a full featured package.json - packagedAppLocation = getTestFilePath("build_app" + testSuffix + "2"); - - onValidated = waitForUpdate(win, "project-validated"); - onDetails = waitForUpdate(win, "details"); - yield winProject.projectList.importPackagedApp(packagedAppLocation); - yield onValidated; - yield onDetails; - - project = win.AppManager.selectedProject; - - loggedMessages = []; - yield ProjectBuilding.build({ - project, - logger - }); - packageDir = yield ProjectBuilding.getPackageDir(project); - is(OS.Path.normalize(packageDir), - OS.Path.join(packagedAppLocation, "stage"), "custom packagedir"); - is(loggedMessages[0], "start", "log messages are correct"); - ok(loggedMessages[1].indexOf("Running pre-package hook") != -1, "log messages are correct"); - is(loggedMessages[2], "Terminated with error code: 0", "log messages are correct"); - is(loggedMessages[3], "succeed", "log messages are correct"); - - // Switch to the package dir in order to verify the generated webapp.manifest - onValidated = waitForUpdate(win, "project-validated"); - onDetails = waitForUpdate(win, "details"); - yield winProject.projectList.importPackagedApp(packageDir); - yield onValidated; - yield onDetails; - - project = win.AppManager.selectedProject; - - ok("name" in project.manifest, "manifest includes name"); - is(project.name, "world", "Display name uses manifest name"); - is(project.manifest.name, project.name, "Display name uses manifest name"); - - yield closeWebIDE(win); - - yield removeAllProjects(); - - SimpleTest.finish(); - }); - } - - - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_device_permissions.html b/devtools/client/webide/test/test_device_permissions.html deleted file mode 100644 index eadd9f595..000000000 --- a/devtools/client/webide/test/test_device_permissions.html +++ /dev/null @@ -1,81 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function* () { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - - let win = yield openWebIDE(); - - let permIframe = win.document.querySelector("#deck-panel-permissionstable"); - let docRuntime = getRuntimeDocument(win); - let winRuntime = getRuntimeWindow(win); - - yield connectToLocalRuntime(win); - - let perm = docRuntime.querySelector("#runtime-permissions"); - - ok(!perm.hasAttribute("disabled"), "perm cmd enabled"); - - let deck = win.document.querySelector("#deck"); - - winRuntime.runtimeList.showPermissionsTable(); - is(deck.selectedPanel, permIframe, "permission iframe selected"); - - yield nextTick(); - - yield lazyIframeIsLoaded(permIframe); - - yield permIframe.contentWindow.getRawPermissionsTablePromise; - - doc = permIframe.contentWindow.document; - trs = doc.querySelectorAll(".line"); - found = false; - for (let tr of trs) { - let [name,v1,v2,v3] = tr.querySelectorAll("td"); - if (name.textContent == "geolocation") { - found = true; - is(v1.className, "permprompt", "geolocation perm is valid"); - is(v2.className, "permprompt", "geolocation perm is valid"); - is(v3.className, "permprompt", "geolocation perm is valid"); - break; - } - } - ok(found, "Found geolocation line"); - - doc.querySelector("#close").click(); - - ok(!deck.selectedPanel, "No panel selected"); - - DebuggerServer.destroy(); - - yield closeWebIDE(win); - - SimpleTest.finish(); - }).then(null, e => { - ok(false, "Exception: " + e); - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_device_preferences.html b/devtools/client/webide/test/test_device_preferences.html deleted file mode 100644 index c79db7f79..000000000 --- a/devtools/client/webide/test/test_device_preferences.html +++ /dev/null @@ -1,87 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <script type="application/javascript;version=1.8" src="device_front_shared.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function* () { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - - let win = yield openWebIDE(); - - let prefIframe = win.document.querySelector("#deck-panel-devicepreferences"); - let docRuntime = getRuntimeDocument(win); - - win.AppManager.update("runtime-list"); - - yield connectToLocalRuntime(win); - - let prefs = docRuntime.querySelector("#runtime-preferences"); - - ok(!prefs.hasAttribute("disabled"), "device prefs cmd enabled"); - - let deck = win.document.querySelector("#deck"); - - win.Cmds.showDevicePrefs(); - is(deck.selectedPanel, prefIframe, "device preferences iframe selected"); - - yield nextTick(); - - yield lazyIframeIsLoaded(prefIframe); - - yield prefIframe.contentWindow.getAllPrefs; - - setDocument(prefIframe); - - let fields = doc.querySelectorAll(".editable"); - - addNewField(); - - let preference = "accessibility.accesskeycausesactivation"; - - fieldChange(fields, preference); - - addNewFieldWithEnter(); - - editExistingField(); - - addNewFieldInteger(); - - yield editFieldInteger(); - - yield resetExistingField("accessibility.accesskeycausesactivation"); - - addNewFieldBoolean(); - - searchFields(deck, "debugger"); - - DebuggerServer.destroy(); - - yield closeWebIDE(win); - - SimpleTest.finish(); - }).then(null, e => { - ok(false, "Exception: " + e); - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_device_runtime.html b/devtools/client/webide/test/test_device_runtime.html deleted file mode 100644 index 0ac42b472..000000000 --- a/devtools/client/webide/test/test_device_runtime.html +++ /dev/null @@ -1,81 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function* () { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - - let win = yield openWebIDE(); - - let detailsIframe = win.document.querySelector("#deck-panel-runtimedetails"); - - yield connectToLocalRuntime(win); - - let details = win.document.querySelector("#cmd_showRuntimeDetails"); - - ok(!details.hasAttribute("disabled"), "info cmd enabled"); - - let deck = win.document.querySelector("#deck"); - - win.Cmds.showRuntimeDetails(); - is(deck.selectedPanel, detailsIframe, "info iframe selected"); - - yield nextTick(); - - yield lazyIframeIsLoaded(detailsIframe); - - yield detailsIframe.contentWindow.getDescriptionPromise; - - // device info and permissions content is checked in other tests - // We just test one value to make sure we get something - - let doc = detailsIframe.contentWindow.document; - let trs = doc.querySelectorAll("tr"); - let found = false; - - for (let tr of trs) { - let [name,val] = tr.querySelectorAll("td"); - if (name.textContent == "appid") { - found = true; - is(val.textContent, Services.appinfo.ID, "appid has the right value"); - break; - } - } - ok(found, "Found appid line"); - - doc.querySelector("#close").click(); - - ok(!deck.selectedPanel, "No panel selected"); - - DebuggerServer.destroy(); - - yield closeWebIDE(win); - - SimpleTest.finish(); - }).then(null, e => { - ok(false, "Exception: " + e); - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_device_settings.html b/devtools/client/webide/test/test_device_settings.html deleted file mode 100644 index ec8e7943b..000000000 --- a/devtools/client/webide/test/test_device_settings.html +++ /dev/null @@ -1,87 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <script type="application/javascript;version=1.8" src="device_front_shared.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function*() { - if (SpecialPowers.isMainProcess()) { - Cu.import("resource://gre/modules/SettingsRequestManager.jsm"); - } - - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - - let win = yield openWebIDE(); - - let settingIframe = win.document.querySelector("#deck-panel-devicesettings"); - let docRuntime = getRuntimeDocument(win); - - win.AppManager.update("runtime-list"); - - yield connectToLocalRuntime(win); - - let settings = docRuntime.querySelector("#runtime-settings"); - - ok(!settings.hasAttribute("disabled"), "device settings cmd enabled"); - - let deck = win.document.querySelector("#deck"); - - win.Cmds.showSettings(); - is(deck.selectedPanel, settingIframe, "device settings iframe selected"); - - yield nextTick(); - - yield lazyIframeIsLoaded(settingIframe); - - yield settingIframe.contentWindow.getAllSettings; - - setDocument(settingIframe); - - let fields = doc.querySelectorAll(".editable"); - - addNewField(); - - addNewFieldWithEnter(); - - editExistingField(); - - addNewFieldInteger(); - - yield editFieldInteger(); - - yield resetNewField("new-string-field"); - - addNewFieldBoolean(); - - searchFields(deck, "new-boolean-field2"); - - DebuggerServer.destroy(); - - yield closeWebIDE(win); - - SimpleTest.finish(); - }).then(null, e => { - ok(false, "Exception: " + e); - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_duplicate_import.html b/devtools/client/webide/test/test_duplicate_import.html deleted file mode 100644 index ef01e23e4..000000000 --- a/devtools/client/webide/test/test_duplicate_import.html +++ /dev/null @@ -1,77 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function*() { - let win = yield openWebIDE(); - let docProject = getProjectDocument(win); - let winProject = getProjectWindow(win); - let packagedAppLocation = getTestFilePath("app"); - let hostedAppManifest = TEST_BASE + "hosted_app.manifest"; - - yield win.AppProjects.load(); - is(win.AppProjects.projects.length, 0, "IDB is empty"); - - let onValidated = waitForUpdate(win, "project-validated"); - let onDetails = waitForUpdate(win, "details"); - yield winProject.projectList.importPackagedApp(packagedAppLocation); - yield onValidated; - yield onDetails; - - yield winProject.projectList.importHostedApp(hostedAppManifest); - yield waitForUpdate(win, "project-validated"); - yield nextTick(); - - onValidated = waitForUpdate(win, "project-validated"); - onDetails = waitForUpdate(win, "details"); - yield winProject.projectList.importPackagedApp(packagedAppLocation); - yield onValidated; - yield onDetails; - - let project = win.AppManager.selectedProject; - is(project.location, packagedAppLocation, "Correctly reselected existing packaged app."); - yield nextTick(); - - info("to call importHostedApp(" + hostedAppManifest + ") again"); - yield winProject.projectList.importHostedApp(hostedAppManifest); - yield waitForUpdate(win, "project-validated"); - project = win.AppManager.selectedProject; - is(project.location, hostedAppManifest, "Correctly reselected existing hosted app."); - yield nextTick(); - - let panelNode = docProject.querySelector("#project-panel"); - let items = panelNode.querySelectorAll(".panel-item"); - // 3 controls, + 2 projects - is(items.length, 5, "5 projects in panel"); - is(items[3].querySelector("span").textContent, "A name (in app directory)", "Panel text is correct"); - is(items[4].querySelector("span").textContent, "hosted manifest name property", "Panel text is correct"); - - yield closeWebIDE(win); - - yield removeAllProjects(); - - SimpleTest.finish(); - }).then(null, e => { - ok(false, "Exception: " + e); - SimpleTest.finish(); - }); - } - </script> - </body> -</html> - diff --git a/devtools/client/webide/test/test_fullscreenToolbox.html b/devtools/client/webide/test/test_fullscreenToolbox.html deleted file mode 100644 index 6ae0c4446..000000000 --- a/devtools/client/webide/test/test_fullscreenToolbox.html +++ /dev/null @@ -1,67 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - function connectToLocal(win, docRuntime) { - let deferred = promise.defer(); - win.AppManager.connection.once( - win.Connection.Events.CONNECTED, - () => deferred.resolve()); - docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click(); - return deferred.promise; - } - - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function* () { - let win = yield openWebIDE(); - let docProject = getProjectDocument(win); - let docRuntime = getRuntimeDocument(win); - win.AppManager.update("runtime-list"); - - yield connectToLocal(win, docRuntime); - - // Select main process - yield waitForUpdate(win, "runtime-targets"); - SimpleTest.executeSoon(() => { - docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click(); - }); - - yield waitForUpdate(win, "project"); - - ok(win.UI.toolboxPromise, "Toolbox promise exists"); - yield win.UI.toolboxPromise; - - let nbox = win.document.querySelector("#notificationbox"); - ok(!nbox.hasAttribute("toolboxfullscreen"), "Toolbox is not fullscreen"); - - win.Cmds.showRuntimeDetails(); - - ok(!nbox.hasAttribute("toolboxfullscreen"), "Toolbox is not fullscreen"); - - yield win.Cmds.disconnectRuntime(); - - yield closeWebIDE(win); - - DebuggerServer.destroy(); - - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_import.html b/devtools/client/webide/test/test_import.html deleted file mode 100644 index 830198cca..000000000 --- a/devtools/client/webide/test/test_import.html +++ /dev/null @@ -1,82 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function*() { - let win = yield openWebIDE(); - let docProject = getProjectDocument(win); - let winProject = getProjectWindow(win); - let packagedAppLocation = getTestFilePath("app"); - - yield win.AppProjects.load(); - is(win.AppProjects.projects.length, 0, "IDB is empty"); - - info("to call importPackagedApp(" + packagedAppLocation + ")"); - ok(!win.UI._busyPromise, "UI is not busy"); - - let onValidated = waitForUpdate(win, "project-validated"); - let onDetails = waitForUpdate(win, "details"); - yield winProject.projectList.importPackagedApp(packagedAppLocation); - yield onValidated; - yield onDetails; - - let project = win.AppManager.selectedProject; - is(project.location, packagedAppLocation, "Location is valid"); - is(project.name, "A name (in app directory)", "name field has been updated"); - is(project.manifest.launch_path, "/index.html", "manifest found. launch_path valid."); - is(project.manifest.description, "desc", "manifest found. description valid"); - - yield nextTick(); - - let hostedAppManifest = TEST_BASE + "hosted_app.manifest"; - yield winProject.projectList.importHostedApp(hostedAppManifest); - yield waitForUpdate(win, "project-validated"); - - project = win.AppManager.selectedProject; - is(project.location, hostedAppManifest, "Location is valid"); - is(project.name, "hosted manifest name property", "name field has been updated"); - - yield nextTick(); - - hostedAppManifest = TEST_BASE + "/app"; - yield winProject.projectList.importHostedApp(hostedAppManifest); - yield waitForUpdate(win, "project-validated"); - - project = win.AppManager.selectedProject; - ok(project.location.endsWith('manifest.webapp'), "The manifest was found and the project was updated"); - - let panelNode = docProject.querySelector("#project-panel"); - let items = panelNode.querySelectorAll(".panel-item"); - // 4 controls, + 2 projects - is(items.length, 6, "6 projects in panel"); - is(items[3].querySelector("span").textContent, "A name (in app directory)", "Panel text is correct"); - is(items[4].querySelector("span").textContent, "hosted manifest name property", "Panel text is correct"); - - yield closeWebIDE(win); - - yield removeAllProjects(); - - SimpleTest.finish(); - }).then(null, e => { - ok(false, "Exception: " + e); - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_manifestUpdate.html b/devtools/client/webide/test/test_manifestUpdate.html deleted file mode 100644 index 66f9affd0..000000000 --- a/devtools/client/webide/test/test_manifestUpdate.html +++ /dev/null @@ -1,98 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - let {TextDecoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {}); - - Task.spawn(function* () { - let win = yield openWebIDE(); - let winProject = getProjectWindow(win); - let AppManager = win.AppManager; - - function isProjectMarkedAsValid() { - let details = win.frames[1]; - return !details.document.body.classList.contains("error"); - } - - let packagedAppLocation = getTestFilePath("app"); - - let onValidated = waitForUpdate(win, "project-validated"); - let onDetails = waitForUpdate(win, "details"); - yield winProject.projectList.importPackagedApp(packagedAppLocation); - yield onValidated; - yield onDetails; - - let project = win.AppManager.selectedProject; - - ok("name" in project.manifest, "manifest includes name"); - is(project.name, project.manifest.name, "Display name uses manifest name"); - ok(isProjectMarkedAsValid(), "project is marked as valid"); - - // Change the name - let originalName = project.manifest.name; - - project.manifest.name = "xxx"; - - // Write to disk - yield AppManager.writeManifest(project); - - // Read file - let manifestPath = OS.Path.join(packagedAppLocation, "manifest.webapp"); - let Decoder = new TextDecoder(); - let data = yield OS.File.read(manifestPath); - data = new TextDecoder().decode(data); - let json = JSON.parse(data); - is(json.name, "xxx", "manifest written on disc"); - - // Make the manifest invalid on disk - delete json.name; - let Encoder = new TextEncoder(); - data = Encoder.encode(JSON.stringify(json)); - yield OS.File.writeAtomic(manifestPath, data , {tmpPath: manifestPath + ".tmp"}); - - // Trigger validation - yield AppManager.validateAndUpdateProject(AppManager.selectedProject); - yield nextTick(); - - ok(!("name" in project.manifest), "manifest has been updated"); - is(project.name, "--", "Placeholder is used for display name"); - ok(!isProjectMarkedAsValid(), "project is marked as invalid"); - - // Make the manifest valid on disk - project.manifest.name = originalName; - yield AppManager.writeManifest(project); - - // Trigger validation - yield AppManager.validateAndUpdateProject(AppManager.selectedProject); - yield nextTick(); - - ok("name" in project.manifest, "manifest includes name"); - is(project.name, originalName, "Display name uses original manifest name"); - ok(isProjectMarkedAsValid(), "project is marked as valid"); - - yield closeWebIDE(win); - - yield removeAllProjects(); - - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_newapp.html b/devtools/client/webide/test/test_newapp.html deleted file mode 100644 index 45374f268..000000000 --- a/devtools/client/webide/test/test_newapp.html +++ /dev/null @@ -1,46 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function* () { - let win = yield openWebIDE(); - let winProject = getProjectWindow(win); - let tmpDir = FileUtils.getDir("TmpD", []); - yield winProject.projectList.newApp({ - index: 0, - name: "webideTmpApp", - folder: tmpDir - }); - - let project = win.AppManager.selectedProject; - tmpDir = FileUtils.getDir("TmpD", ["webidetmpapp"]); - ok(tmpDir.isDirectory(), "Directory created"); - is(project.location, tmpDir.path, "Location is valid (and lowercase)"); - is(project.name, "webideTmpApp", "name field has been updated"); - - // Clean up - tmpDir.remove(true); - yield closeWebIDE(win); - yield removeAllProjects(); - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_runtime.html b/devtools/client/webide/test/test_runtime.html deleted file mode 100644 index 9b16ef82d..000000000 --- a/devtools/client/webide/test/test_runtime.html +++ /dev/null @@ -1,203 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - let win; - - SimpleTest.registerCleanupFunction(() => { - Task.spawn(function*() { - if (win) { - yield closeWebIDE(win); - } - DebuggerServer.destroy(); - yield removeAllProjects(); - }); - }); - - Task.spawn(function*() { - function isPlayActive() { - return !win.document.querySelector("#cmd_play").hasAttribute("disabled"); - } - - function isStopActive() { - return !win.document.querySelector("#cmd_stop").hasAttribute("disabled"); - } - - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - - win = yield openWebIDE(); - let docRuntime = getRuntimeDocument(win); - let docProject = getProjectDocument(win); - let winProject = getProjectWindow(win); - - let packagedAppLocation = getTestFilePath("app"); - - let onValidated = waitForUpdate(win, "project-validated"); - let onDetails = waitForUpdate(win, "details"); - yield winProject.projectList.importPackagedApp(packagedAppLocation); - yield onValidated; - yield onDetails; - - win.AppManager.runtimeList.usb.push({ - connect: function(connection) { - is(connection, win.AppManager.connection, "connection is valid"); - connection.host = null; // force connectPipe - connection.connect(); - return promise.resolve(); - }, - - get name() { - return "fakeRuntime"; - } - }); - - win.AppManager.runtimeList.usb.push({ - connect: function(connection) { - let deferred = promise.defer(); - return deferred.promise; - }, - - get name() { - return "infiniteRuntime"; - } - }); - - win.AppManager.runtimeList.usb.push({ - connect: function(connection) { - let deferred = promise.defer(); - return deferred.promise; - }, - - prolongedConnection: true, - - get name() { - return "prolongedRuntime"; - } - }); - - win.AppManager.update("runtime-list"); - - let panelNode = docRuntime.querySelector("#runtime-panel"); - let items = panelNode.querySelectorAll(".runtime-panel-item-usb"); - is(items.length, 3, "Found 3 runtime buttons"); - - let connectionsChanged = waitForConnectionChange("opened", 2); - items[0].click(); - - ok(win.document.querySelector("window").className, "busy", "UI is busy"); - yield win.UI._busyPromise; - - yield connectionsChanged; - is(Object.keys(DebuggerServer._connections).length, 2, "Connected"); - - yield waitForUpdate(win, "runtime-global-actors"); - - // Play button always disabled now, webapps actor removed - ok(!isPlayActive(), "play button is disabled"); - ok(!isStopActive(), "stop button is disabled"); - let oldProject = win.AppManager.selectedProject; - win.AppManager.selectedProject = null; - - yield nextTick(); - - ok(!isPlayActive(), "play button is disabled"); - ok(!isStopActive(), "stop button is disabled"); - win.AppManager._selectedProject = oldProject; - win.UI.updateCommands(); - - yield nextTick(); - - ok(!isPlayActive(), "play button is enabled"); - ok(!isStopActive(), "stop button is disabled"); - - connectionsChanged = waitForConnectionChange("closed", 2); - yield win.Cmds.disconnectRuntime(); - - yield connectionsChanged; - is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected"); - - ok(win.AppManager.selectedProject, "A project is still selected"); - ok(!isPlayActive(), "play button is disabled"); - ok(!isStopActive(), "stop button is disabled"); - - connectionsChanged = waitForConnectionChange("opened", 2); - docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click(); - - yield waitForUpdate(win, "runtime-targets"); - - yield connectionsChanged; - is(Object.keys(DebuggerServer._connections).length, 2, "Locally connected"); - - ok(win.AppManager.isMainProcessDebuggable(), "Main process available"); - - // Select main process - SimpleTest.executeSoon(() => { - docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click(); - }); - - yield waitForUpdate(win, "project"); - - // Toolbox opens automatically for main process / runtime apps - ok(win.UI.toolboxPromise, "Toolbox promise exists"); - yield win.UI.toolboxPromise; - - yield win.Cmds.disconnectRuntime(); - - Services.prefs.setIntPref("devtools.webide.busyTimeout", 100); - - // Wait for error message since connection never completes - let errorDeferred = promise.defer(); - win.UI.reportError = errorName => { - if (errorName === "error_operationTimeout") { - errorDeferred.resolve(); - } - }; - - // Click the infinite runtime - items[1].click(); - ok(win.document.querySelector("window").className, "busy", "UI is busy"); - yield errorDeferred.promise; - - // Check for unexpected error message since this is prolonged - let noErrorDeferred = promise.defer(); - win.UI.reportError = errorName => { - if (errorName === "error_operationTimeout") { - noErrorDeferred.reject(); - } - }; - - // Click the prolonged runtime - items[2].click(); - ok(win.document.querySelector("window").className, "busy", "UI is busy"); - - setTimeout(() => { - noErrorDeferred.resolve(); - }, 1000); - - yield noErrorDeferred.promise; - - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_simulators.html b/devtools/client/webide/test/test_simulators.html deleted file mode 100644 index 204881512..000000000 --- a/devtools/client/webide/test/test_simulators.html +++ /dev/null @@ -1,426 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - const asyncStorage = require("devtools/shared/async-storage"); - const EventEmitter = require("devtools/shared/event-emitter"); - const { GetAvailableAddons } = require("devtools/client/webide/modules/addons"); - const { getDevices } = require("devtools/client/shared/devices"); - const { Simulator, Simulators } = require("devtools/client/webide/modules/simulators"); - const { AddonSimulatorProcess, - OldAddonSimulatorProcess, - CustomSimulatorProcess } = require("devtools/client/webide/modules/simulator-process"); - - function addonStatus(addon, status) { - if (addon.status == status) { - return promise.resolve(); - } - let deferred = promise.defer(); - addon.on("update", function onUpdate() { - if (addon.status == status) { - addon.off("update", onUpdate); - nextTick().then(() => deferred.resolve()); - } - }); - return deferred.promise; - } - - function waitForUpdate(length) { - info(`Wait for update with length ${length}`); - let deferred = promise.defer(); - let handler = (_, data) => { - if (data.length != length) { - return; - } - info(`Got update with length ${length}`); - Simulators.off("updated", handler); - deferred.resolve(); - }; - Simulators.on("updated", handler); - return deferred.promise; - } - - Task.spawn(function* () { - let win = yield openWebIDE(false); - - yield Simulators._load(); - - let docRuntime = getRuntimeDocument(win); - let find = win.document.querySelector.bind(docRuntime); - let findAll = win.document.querySelectorAll.bind(docRuntime); - - let simulatorList = find("#runtime-panel-simulator"); - let simulatorPanel = win.document.querySelector("#deck-panel-simulator"); - - // Hack SimulatorProcesses to spy on simulation parameters. - - let runPromise; - function fakeRun() { - runPromise.resolve({ - path: this.b2gBinary.path, - args: this.args - }); - // Don't actually try to connect to the fake simulator. - throw new Error("Aborting on purpose before connection."); - } - - AddonSimulatorProcess.prototype.run = fakeRun; - OldAddonSimulatorProcess.prototype.run = fakeRun; - CustomSimulatorProcess.prototype.run = fakeRun; - - function runSimulator(i) { - runPromise = promise.defer(); - findAll(".runtime-panel-item-simulator")[i].click(); - return runPromise.promise; - } - - // Install fake "Firefox OS 1.0" simulator addon. - - let addons = yield GetAvailableAddons(); - - let sim10 = addons.simulators.filter(a => a.version == "1.0")[0]; - - sim10.install(); - - let updated = waitForUpdate(1); - yield addonStatus(sim10, "installed"); - yield updated; - // Wait for next tick to ensure UI elements are updated - yield nextTick(); - - is(findAll(".runtime-panel-item-simulator").length, 1, "One simulator in runtime panel"); - - // Install fake "Firefox OS 2.0" simulator addon. - - let sim20 = addons.simulators.filter(a => a.version == "2.0")[0]; - - sim20.install(); - - updated = waitForUpdate(2); - yield addonStatus(sim20, "installed"); - yield updated; - // Wait for next tick to ensure UI elements are updated - yield nextTick(); - - is(findAll(".runtime-panel-item-simulator").length, 2, "Two simulators in runtime panel"); - - // Dry run a simulator to verify that its parameters look right. - - let params = yield runSimulator(0); - - ok(params.path.includes(sim10.addonID) && params.path.includes("b2g-bin"), "Simulator binary path looks right"); - - let pid = params.args.indexOf("-profile"); - ok(pid > -1, "Simulator process arguments have --profile"); - - let profilePath = params.args[pid + 1]; - ok(profilePath.includes(sim10.addonID) && profilePath.includes("profile"), "Simulator profile path looks right"); - - ok(params.args.indexOf("-dbgport") > -1 || params.args.indexOf("-start-debugger-server") > -1, "Simulator process arguments have a debugger port"); - - ok(params.args.indexOf("-no-remote") > -1, "Simulator process arguments have --no-remote"); - - // Wait for next tick to ensure UI elements are updated - yield nextTick(); - - // Configure the fake 1.0 simulator. - - simulatorList.querySelectorAll(".configure-button")[0].click(); - is(win.document.querySelector("#deck").selectedPanel, simulatorPanel, "Simulator deck panel is selected"); - - yield lazyIframeIsLoaded(simulatorPanel); - - let doc = simulatorPanel.contentWindow.document; - let form = doc.querySelector("#simulator-editor"); - - let formReady = new Promise((resolve, reject) => { - form.addEventListener("change", () => { - resolve(); - }); - }); - - let change = doc.createEvent("HTMLEvents"); - change.initEvent("change", true, true); - - function set(input, value) { - input.value = value; - input.dispatchEvent(change); - return nextTick(); - } - - let MockFilePicker = SpecialPowers.MockFilePicker; - MockFilePicker.init(simulatorPanel.contentWindow); - - yield formReady; - - // Test `name`. - - is(form.name.value, find(".runtime-panel-item-simulator").textContent, "Original simulator name"); - - let customName = "CustomFox "; - yield set(form.name, customName + "1.0"); - - is(find(".runtime-panel-item-simulator").textContent, form.name.value, "Updated simulator name"); - - // Test `version`. - - is(form.version.value, sim10.addonID, "Original simulator version"); - ok(!form.version.classList.contains("custom"), "Version selector is not customized"); - - yield set(form.version, sim20.addonID); - - ok(!form.version.classList.contains("custom"), "Version selector is not customized after addon change"); - is(form.name.value, customName + "2.0", "Simulator name was updated to new version"); - - // Pick custom binary, but act like the user aborted the file picker. - - MockFilePicker.returnFiles = []; - yield set(form.version, "pick"); - - is(form.version.value, sim20.addonID, "Version selector reverted to last valid choice after customization abort"); - ok(!form.version.classList.contains("custom"), "Version selector is not customized after customization abort"); - - // Pick custom binary, and actually follow through. (success, verify value = "custom" and textContent = custom path) - - MockFilePicker.useAnyFile(); - yield set(form.version, "pick"); - - let fakeBinary = MockFilePicker.returnFiles[0]; - - ok(form.version.value == "custom", "Version selector was set to a new custom binary"); - ok(form.version.classList.contains("custom"), "Version selector is now customized"); - is(form.version.selectedOptions[0].textContent, fakeBinary.path, "Custom option textContent is correct"); - - yield set(form.version, sim10.addonID); - - ok(form.version.classList.contains("custom"), "Version selector remains customized after change back to addon"); - is(form.name.value, customName + "1.0", "Simulator name was updated to new version"); - - yield set(form.version, "custom"); - - ok(form.version.value == "custom", "Version selector is back to custom"); - - // Test `profile`. - - is(form.profile.value, "default", "Default simulator profile"); - ok(!form.profile.classList.contains("custom"), "Profile selector is not customized"); - - MockFilePicker.returnFiles = []; - yield set(form.profile, "pick"); - - is(form.profile.value, "default", "Profile selector reverted to last valid choice after customization abort"); - ok(!form.profile.classList.contains("custom"), "Profile selector is not customized after customization abort"); - - let fakeProfile = FileUtils.getDir("TmpD", []); - - MockFilePicker.returnFiles = [ fakeProfile ]; - yield set(form.profile, "pick"); - - ok(form.profile.value == "custom", "Profile selector was set to a new custom directory"); - ok(form.profile.classList.contains("custom"), "Profile selector is now customized"); - is(form.profile.selectedOptions[0].textContent, fakeProfile.path, "Custom option textContent is correct"); - - yield set(form.profile, "default"); - - is(form.profile.value, "default", "Profile selector back to default"); - ok(form.profile.classList.contains("custom"), "Profile selector remains customized after change back to default"); - - yield set(form.profile, "custom"); - - is(form.profile.value, "custom", "Profile selector back to custom"); - - params = yield runSimulator(0); - - is(params.path, fakeBinary.path, "Simulator process uses custom binary path"); - - pid = params.args.indexOf("-profile"); - is(params.args[pid + 1], fakeProfile.path, "Simulator process uses custom profile directory"); - - yield set(form.version, sim10.addonID); - - is(form.name.value, customName + "1.0", "Simulator restored to 1.0"); - - params = yield runSimulator(0); - - pid = params.args.indexOf("-profile"); - is(params.args[pid + 1], fakeProfile.path, "Simulator process still uses custom profile directory"); - - yield set(form.version, "custom"); - - // Test `device`. - - let defaults = Simulator.prototype._defaults; - - for (let param in defaults.phone) { - is(form[param].value, String(defaults.phone[param]), "Default phone value for device " + param); - } - - let width = 5000, height = 4000; - yield set(form.width, width); - yield set(form.height, height); - - is(form.device.value, "custom", "Device selector is custom"); - - params = yield runSimulator(0); - - let sid = params.args.indexOf("-screen"); - ok(sid > -1, "Simulator process arguments have --screen"); - ok(params.args[sid + 1].includes(width + "x" + height), "Simulator screen resolution looks right"); - - yield set(form.version, sim10.addonID); - - // Configure the fake 2.0 simulator. - - simulatorList.querySelectorAll(".configure-button")[1].click(); - // Wait for next tick to ensure UI elements are updated - yield nextTick(); - - // Test `name`. - - is(form.name.value, findAll(".runtime-panel-item-simulator")[1].textContent, "Original simulator name"); - - yield set(form.name, customName + "2.0"); - - is(findAll(".runtime-panel-item-simulator")[1].textContent, form.name.value, "Updated simulator name"); - - yield set(form.version, sim10.addonID); - - ok(form.name.value !== customName + "1.0", "Conflicting simulator name was deduplicated"); - - is(form.name.value, findAll(".runtime-panel-item-simulator")[1].textContent, "Deduplicated simulator name stayed consistent"); - - yield set(form.version, sim20.addonID); - - is(form.name.value, customName + "2.0", "Name deduplication was undone when possible"); - - // Test `device`. - - for (let param in defaults.phone) { - is(form[param].value, String(defaults.phone[param]), "Default phone value for device " + param); - } - - let devices = yield getDevices(); - devices = devices[devices.TYPES[0]]; - let device = devices[devices.length - 1]; - - yield set(form.device, device.name); - - is(form.device.value, device.name, "Device selector was changed"); - is(form.width.value, String(device.width), "New device width is correct"); - is(form.height.value, String(device.height), "New device height is correct"); - - params = yield runSimulator(1); - - sid = params.args.indexOf("-screen"); - ok(params.args[sid + 1].includes(device.width + "x" + device.height), "Simulator screen resolution looks right"); - - // Test Simulator Menu. - is(doc.querySelector("#tv_simulator_menu").style.visibility, "hidden", "OpenTVDummyDirectory Button is not hidden"); - - // Restore default simulator options. - - doc.querySelector("#reset").click(); - // Wait for next tick to ensure UI elements are updated - yield nextTick(); - - for (let param in defaults.phone) { - is(form[param].value, String(defaults.phone[param]), "Default phone value for device " + param); - } - - // Install and configure the fake "Firefox OS 3.0 TV" simulator addon. - - let sim30tv = addons.simulators.filter(a => a.version == "3.0_tv")[0]; - - sim30tv.install(); - - updated = waitForUpdate(3); - yield addonStatus(sim30tv, "installed"); - yield updated; - // Wait for next tick to ensure UI elements are updated - yield nextTick(); - - is(findAll(".runtime-panel-item-simulator").length, 3, "Three simulators in runtime panel"); - - simulatorList.querySelectorAll(".configure-button")[2].click(); - // Wait for next tick to ensure UI elements are updated - yield nextTick(); - - for (let param in defaults.television) { - is(form[param].value, String(defaults.television[param]), "Default TV value for device " + param); - } - - // Test Simulator Menu - is(doc.querySelector("#tv_simulator_menu").style.visibility, "visible", "OpenTVDummyDirectory Button is not visible"); - - // Force reload the list of simulators. - - Simulators._loadingPromise = null; - Simulators._simulators = []; - yield Simulators._load(); - // Wait for next tick to ensure UI elements are updated - yield nextTick(); - - is(findAll(".runtime-panel-item-simulator").length, 3, "Three simulators saved and reloaded " + Simulators._simulators.map(s => s.name).join(',')); - - // Uninstall the 3.0 TV and 2.0 addons, and watch their Simulator objects disappear. - - sim30tv.uninstall(); - - yield addonStatus(sim30tv, "uninstalled"); - - is(findAll(".runtime-panel-item-simulator").length, 2, "Two simulators left in runtime panel"); - - sim20.uninstall(); - - yield addonStatus(sim20, "uninstalled"); - - is(findAll(".runtime-panel-item-simulator").length, 1, "One simulator left in runtime panel"); - - // Remove 1.0 simulator. - - simulatorList.querySelectorAll(".configure-button")[0].click(); - // Wait for next tick to ensure UI elements are updated - yield nextTick(); - - doc.querySelector("#remove").click(); - // Wait for next tick to ensure UI elements are updated - yield nextTick(); - - is(findAll(".runtime-panel-item-simulator").length, 0, "Last simulator was removed"); - - yield asyncStorage.removeItem("simulators"); - - sim10.uninstall(); - - MockFilePicker.cleanup(); - - doc.querySelector("#close").click(); - - ok(!win.document.querySelector("#deck").selectedPanel, "No panel selected"); - - yield closeWebIDE(win); - - SimpleTest.finish(); - - }); - } - - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_telemetry.html b/devtools/client/webide/test/test_telemetry.html deleted file mode 100644 index 225ddb89b..000000000 --- a/devtools/client/webide/test/test_telemetry.html +++ /dev/null @@ -1,325 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - const Telemetry = require("devtools/client/shared/telemetry"); - const { _DeprecatedUSBRuntime, _WiFiRuntime, _SimulatorRuntime, - _gRemoteRuntime, _gLocalRuntime, RuntimeTypes } - = require("devtools/client/webide/modules/runtimes"); - - // Because we need to gather stats for the period of time that a tool has - // been opened we make use of setTimeout() to create tool active times. - const TOOL_DELAY = 200; - - function patchTelemetry() { - Telemetry.prototype.telemetryInfo = {}; - Telemetry.prototype._oldlog = Telemetry.prototype.log; - Telemetry.prototype.log = function(histogramId, value) { - if (histogramId) { - if (!this.telemetryInfo[histogramId]) { - this.telemetryInfo[histogramId] = []; - } - this.telemetryInfo[histogramId].push(value); - } - } - Telemetry.prototype._oldlogKeyed = Telemetry.prototype.logKeyed; - Telemetry.prototype.logKeyed = function(histogramId, key, value) { - // This simple reduction is enough to test WebIDE's usage - this.log(`${histogramId}|${key}`, value); - } - } - - function resetTelemetry() { - Telemetry.prototype.log = Telemetry.prototype._oldlog; - Telemetry.prototype.logKeyed = Telemetry.prototype._oldlogKeyed; - delete Telemetry.prototype._oldlog; - delete Telemetry.prototype._oldlogKeyed; - delete Telemetry.prototype.telemetryInfo; - } - - function cycleWebIDE() { - return Task.spawn(function*() { - let win = yield openWebIDE(); - // Wait a bit, so we're open for a non-zero time - yield waitForTime(TOOL_DELAY); - yield closeWebIDE(win); - }); - } - - function addFakeRuntimes(win) { - // We use the real runtimes here (and switch out some functionality) - // so we can ensure that logging happens as it would in real use. - - let usb = new _DeprecatedUSBRuntime("fakeUSB"); - // Use local pipe instead - usb.connect = function(connection) { - ok(connection, win.AppManager.connection, "connection is valid"); - connection.host = null; // force connectPipe - connection.connect(); - return promise.resolve(); - }; - win.AppManager.runtimeList.usb.push(usb); - - let wifi = new _WiFiRuntime("fakeWiFi"); - // Use local pipe instead - wifi.connect = function(connection) { - ok(connection, win.AppManager.connection, "connection is valid"); - connection.host = null; // force connectPipe - connection.connect(); - return promise.resolve(); - }; - win.AppManager.runtimeList.wifi.push(wifi); - - let sim = new _SimulatorRuntime({ id: "fakeSimulator" }); - // Use local pipe instead - sim.connect = function(connection) { - ok(connection, win.AppManager.connection, "connection is valid"); - connection.host = null; // force connectPipe - connection.connect(); - return promise.resolve(); - }; - Object.defineProperty(sim, "name", { - get() { - return this.version; - } - }); - win.AppManager.runtimeList.simulator.push(sim); - - let remote = _gRemoteRuntime; - // Use local pipe instead - remote.connect = function(connection) { - ok(connection, win.AppManager.connection, "connection is valid"); - connection.host = null; // force connectPipe - connection.connect(); - return promise.resolve(); - }; - let local = _gLocalRuntime; - - let other = Object.create(_gLocalRuntime); - other.type = RuntimeTypes.OTHER; - - win.AppManager.runtimeList.other = [remote, local, other]; - - win.AppManager.update("runtime-list"); - } - - function addTestApp(win) { - return Task.spawn(function*() { - let packagedAppLocation = getTestFilePath("../app"); - let winProject = getProjectWindow(win); - let onValidated = waitForUpdate(win, "project-validated"); - let onDetails = waitForUpdate(win, "details"); - yield winProject.projectList.importPackagedApp(packagedAppLocation); - yield onValidated; - yield onDetails; - }); - } - - function startConnection(win, docRuntime, type, index) { - let panelNode = docRuntime.querySelector("#runtime-panel"); - let items = panelNode.querySelectorAll(".runtime-panel-item-" + type); - if (index === undefined) { - is(items.length, 1, "Found one runtime button"); - } - - let deferred = promise.defer(); - win.AppManager.connection.once( - win.Connection.Events.CONNECTED, - () => deferred.resolve()); - - items[index || 0].click(); - - return deferred.promise; - } - - function waitUntilConnected(win) { - return Task.spawn(function*() { - ok(win.document.querySelector("window").className, "busy", "UI is busy"); - yield win.UI._busyPromise; - is(Object.keys(DebuggerServer._connections).length, 1, "Connected"); - // Logging runtime info needs to use the device actor - yield waitForUpdate(win, "runtime-global-actors"); - // Ensure detailed telemetry is recorded - yield waitForUpdate(win, "runtime-telemetry"); - }); - } - - function connectToRuntime(win, docRuntime, type, index) { - return Task.spawn(function*() { - startConnection(win, docRuntime, type, index); - yield waitUntilConnected(win); - }); - } - - function checkResults() { - let result = Telemetry.prototype.telemetryInfo; - for (let [histId, value] of Iterator(result)) { - if (histId === "DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN") { - ok(value.length === 1 && !!value[0], - histId + " has 1 successful entry"); - } else if (histId === - "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_COUNT") { - ok(value.length === 1 && !!value[0], - histId + " has 1 successful entry"); - } else if (histId === "DEVTOOLS_WEBIDE_OPENED_COUNT") { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return !!element; - }); - - ok(okay, "All " + histId + " entries are true"); - } else if (histId.endsWith("WEBIDE_TIME_ACTIVE_SECONDS")) { - ok(value.length > 1, histId + " has more than one entry"); - - let okay = value.every(function(element) { - return element > 0; - }); - - ok(okay, "All " + histId + " entries have time > 0"); - } else if (histId.endsWith("EDITOR_TIME_ACTIVE_SECONDS")) { - ok(value.length === 1 && value[0] > 0, - histId + " has 1 entry with time > 0"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_RESULT") { - ok(value.length === 6, histId + " has 6 connection results"); - - let okay = value.every(function(element) { - return !!element; - }); - - ok(okay, "All " + histId + " connections succeeded"); - } else if (histId.endsWith("CONNECTION_RESULT")) { - ok(value.length === 1 && !!value[0], - histId + " has 1 successful connection"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS") { - ok(value.length === 6, histId + " has 6 connection results"); - - let okay = value.every(function(element) { - return element > 0; - }); - - ok(okay, "All " + histId + " connections have time > 0"); - } else if (histId.endsWith("USED")) { - ok(value.length === 6, histId + " has 6 connection actions"); - - let okay = value.every(function(element) { - return !element; - }); - - ok(okay, "All " + histId + " actions were skipped"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|USB") { - is(value.length, 1, histId + " has 1 connection results"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|WIFI") { - is(value.length, 1, histId + " has 1 connection results"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|SIMULATOR") { - is(value.length, 1, histId + " has 1 connection results"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|REMOTE") { - is(value.length, 1, histId + " has 1 connection results"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|LOCAL") { - is(value.length, 1, histId + " has 1 connection results"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|OTHER") { - is(value.length, 1, histId + " has 1 connection results"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID|fakeUSB") { - is(value.length, 1, histId + " has 1 connection results"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID|fakeWiFi") { - is(value.length, 1, histId + " has 1 connection results"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID|fakeSimulator") { - is(value.length, 1, histId + " has 1 connection results"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID|unknown") { - is(value.length, 1, histId + " has 1 connection results"); - } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID|local") { - is(value.length, 2, histId + " has 2 connection results"); - } else if (histId.startsWith("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PROCESSOR")) { - let processor = histId.split("|")[1]; - is(processor, Services.appinfo.XPCOMABI.split("-")[0], "Found runtime processor"); - is(value.length, 6, histId + " has 6 connection results"); - } else if (histId.startsWith("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_OS")) { - let os = histId.split("|")[1]; - is(os, Services.appinfo.OS, "Found runtime OS"); - is(value.length, 6, histId + " has 6 connection results"); - } else if (histId.startsWith("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PLATFORM_VERSION")) { - let platformversion = histId.split("|")[1]; - is(platformversion, Services.appinfo.platformVersion, "Found runtime platform version"); - is(value.length, 6, histId + " has 6 connection results"); - } else if (histId.startsWith("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_APP_TYPE")) { - let apptype = histId.split("|")[1]; - is(apptype, "firefox", "Found runtime app type"); - is(value.length, 6, histId + " has 6 connection results"); - } else if (histId.startsWith("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_VERSION")) { - let version = histId.split("|")[1]; - is(version, Services.appinfo.version, "Found runtime version"); - is(value.length, 6, histId + " has 6 connection results"); - } else { - ok(false, "Unexpected " + histId + " was logged"); - } - } - } - - window.onload = function() { - SimpleTest.testInChaosMode(); - SimpleTest.waitForExplicitFinish(); - - let win; - - SimpleTest.registerCleanupFunction(() => { - return Task.spawn(function*() { - if (win) { - yield closeWebIDE(win); - } - DebuggerServer.destroy(); - yield removeAllProjects(); - resetTelemetry(); - }); - }); - - Task.spawn(function*() { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - - patchTelemetry(); - - // Cycle once, so we can test for multiple opens - yield cycleWebIDE(); - - win = yield openWebIDE(); - let docRuntime = getRuntimeDocument(win); - - // Wait a bit, so we're open for a non-zero time - yield waitForTime(TOOL_DELAY); - addFakeRuntimes(win); - yield addTestApp(win); - - // Each one should log a connection result and non-zero connection - // time - yield connectToRuntime(win, docRuntime, "usb"); - yield connectToRuntime(win, docRuntime, "wifi"); - yield connectToRuntime(win, docRuntime, "simulator"); - yield connectToRuntime(win, docRuntime, "other", 0 /* remote */); - yield connectToRuntime(win, docRuntime, "other", 1 /* local */); - yield connectToRuntime(win, docRuntime, "other", 2 /* other */); - yield closeWebIDE(win); - win = null; - - checkResults(); - - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_toolbox.html b/devtools/client/webide/test/test_toolbox.html deleted file mode 100644 index 71ac2706c..000000000 --- a/devtools/client/webide/test/test_toolbox.html +++ /dev/null @@ -1,93 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - let win; - - SimpleTest.registerCleanupFunction(() => { - Task.spawn(function*() { - if (win) { - yield closeWebIDE(win); - } - DebuggerServer.destroy(); - yield removeAllProjects(); - }); - }); - - Task.spawn(function*() { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - - win = yield openWebIDE(); - let docRuntime = getRuntimeDocument(win); - let docProject = getProjectDocument(win); - - win.AppManager.update("runtime-list"); - - let deferred = promise.defer(); - win.AppManager.connection.once( - win.Connection.Events.CONNECTED, - () => deferred.resolve()); - - docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click(); - - ok(win.document.querySelector("window").className, "busy", "UI is busy"); - yield win.UI._busyPromise; - - is(Object.keys(DebuggerServer._connections).length, 1, "Connected"); - - yield waitForUpdate(win, "runtime-global-actors"); - - ok(win.AppManager.isMainProcessDebuggable(), "Main process available"); - - // Select main process - SimpleTest.executeSoon(() => { - docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click(); - }); - - yield waitForUpdate(win, "project"); - - // Toolbox opens automatically for main process / runtime apps - ok(win.UI.toolboxPromise, "Toolbox promise exists"); - let toolbox = yield win.UI.toolboxPromise; - - yield toolbox.destroy(); - - ok(!win.UI.toolboxPromise, "Toolbox promise should be unset once toolbox.destroy()'s promise resolves"); - - // Reopen the toolbox right after to check races and also - // opening a toolbox more than just once against the same target - yield win.Cmds.toggleToolbox(); - - ok(win.UI.toolboxPromise, "Toolbox promise exists"); - - yield win.UI.destroyToolbox(); - - ok(!win.UI.toolboxPromise, "Toolbox promise is also nullified the second times"); - - yield win.Cmds.disconnectRuntime(); - - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/test_zoom.html b/devtools/client/webide/test/test_zoom.html deleted file mode 100644 index 4ad3885d2..000000000 --- a/devtools/client/webide/test/test_zoom.html +++ /dev/null @@ -1,77 +0,0 @@ -<!DOCTYPE html> - -<html> - - <head> - <meta charset="utf8"> - <title></title> - - <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> - <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script> - <script type="application/javascript;version=1.8" src="head.js"></script> - <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> - </head> - - <body> - - <script type="application/javascript;version=1.8"> - window.onload = function() { - SimpleTest.waitForExplicitFinish(); - - Task.spawn(function* () { - let win = yield openWebIDE(); - let viewer = win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .contentViewer; - - win.Cmds.zoomOut(); - win.Cmds.zoomOut(); - win.Cmds.zoomOut(); - win.Cmds.zoomOut(); - win.Cmds.zoomOut(); - win.Cmds.zoomOut(); - win.Cmds.zoomOut(); - - let roundZoom = Math.round(10 * viewer.fullZoom) / 10; - is(roundZoom, 0.6, "Reach min zoom"); - - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - win.Cmds.zoomIn(); - - roundZoom = Math.round(10 * viewer.fullZoom) / 10; - is(roundZoom, 1.4, "Reach max zoom"); - - yield closeWebIDE(win); - - win = yield openWebIDE(); - viewer = win.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .contentViewer; - - roundZoom = Math.round(10 * viewer.fullZoom) / 10; - is(roundZoom, 1.4, "Zoom restored"); - - win.Cmds.resetZoom(); - - is(viewer.fullZoom, 1, "Zoom reset"); - - yield closeWebIDE(win); - - SimpleTest.finish(); - }); - } - </script> - </body> -</html> diff --git a/devtools/client/webide/test/validator/no-name-or-icon/manifest.webapp b/devtools/client/webide/test/validator/no-name-or-icon/manifest.webapp deleted file mode 100644 index 149e3fb79..000000000 --- a/devtools/client/webide/test/validator/no-name-or-icon/manifest.webapp +++ /dev/null @@ -1,3 +0,0 @@ -{ - "launch_path": "/home.html" -} diff --git a/devtools/client/webide/test/validator/non-absolute-path/manifest.webapp b/devtools/client/webide/test/validator/non-absolute-path/manifest.webapp deleted file mode 100644 index 64744067f..000000000 --- a/devtools/client/webide/test/validator/non-absolute-path/manifest.webapp +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "non-absolute path", - "icons": { - "128": "/icon.png" - }, - "launch_path": "non-absolute.html" -} diff --git a/devtools/client/webide/test/validator/valid/alsoValid/manifest.webapp b/devtools/client/webide/test/validator/valid/alsoValid/manifest.webapp deleted file mode 100644 index 20bd97bba..000000000 --- a/devtools/client/webide/test/validator/valid/alsoValid/manifest.webapp +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "valid at subfolder", - "launch_path": "/home.html", - "icons": { - "128": "/icon.png" - } -} diff --git a/devtools/client/webide/test/validator/valid/home.html b/devtools/client/webide/test/validator/valid/home.html deleted file mode 100644 index e69de29bb..000000000 --- a/devtools/client/webide/test/validator/valid/home.html +++ /dev/null diff --git a/devtools/client/webide/test/validator/valid/icon.png b/devtools/client/webide/test/validator/valid/icon.png deleted file mode 100644 index e69de29bb..000000000 --- a/devtools/client/webide/test/validator/valid/icon.png +++ /dev/null diff --git a/devtools/client/webide/test/validator/valid/manifest.webapp b/devtools/client/webide/test/validator/valid/manifest.webapp deleted file mode 100644 index 2c22a1567..000000000 --- a/devtools/client/webide/test/validator/valid/manifest.webapp +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "valid", - "launch_path": "/home.html", - "icons": { - "128": "/icon.png" - } -} diff --git a/devtools/client/webide/test/validator/wrong-launch-path/icon.png b/devtools/client/webide/test/validator/wrong-launch-path/icon.png deleted file mode 100644 index e69de29bb..000000000 --- a/devtools/client/webide/test/validator/wrong-launch-path/icon.png +++ /dev/null diff --git a/devtools/client/webide/test/validator/wrong-launch-path/manifest.webapp b/devtools/client/webide/test/validator/wrong-launch-path/manifest.webapp deleted file mode 100644 index 08057bae1..000000000 --- a/devtools/client/webide/test/validator/wrong-launch-path/manifest.webapp +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "valid", - "launch_path": "/wrong-path.html", - "icons": { - "128": "/icon.png" - } -} diff --git a/devtools/client/webide/themes/addons.css b/devtools/client/webide/themes/addons.css deleted file mode 100644 index 1ae41f2d9..000000000 --- a/devtools/client/webide/themes/addons.css +++ /dev/null @@ -1,79 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -button { - line-height: 20px; - font-size: 1em; - height: 30px; - max-height: 30px; - min-width: 120px; - padding: 3px; - color: #737980; - border: 1px solid rgba(23,50,77,.4); - border-radius: 5px; - background-color: #f1f1f1; - background-image: linear-gradient(#fff, rgba(255,255,255,.1)); - box-shadow: 0 1px 1px 0 #fff, inset 0 2px 2px 0 #fff; - text-shadow: 0 1px 1px #fefffe; - -moz-appearance: none; - -moz-border-top-colors: none !important; - -moz-border-right-colors: none !important; - -moz-border-bottom-colors: none !important; - -moz-border-left-colors: none !important; -} - -button:hover { - background-image: linear-gradient(#fff, rgba(255,255,255,.6)); - cursor: pointer; -} - -button:hover:active { - background-image: linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.6)); -} - -progress { - height: 30px; - vertical-align: middle; - padding: 0; - width: 120px; -} - -li { - margin: 20px 0; -} - -.name { - display: inline-block; - min-width: 280px; -} - -.status { - display: inline-block; - min-width: 120px; -} - -.warning { - color: #F06; - margin: 0; - font-size: 0.9em; -} - -li[status="unknown"], -li > .uninstall-button, -li > .install-button, -li > progress { - display: none; -} - -li[status="installed"] > .uninstall-button, -li[status="uninstalled"] > .install-button, -li[status="preparing"] > progress, -li[status="downloading"] > progress, -li[status="installing"] > progress { - display: inline; -} - -li:not([status="uninstalled"]) > .warning { - display: none; -} diff --git a/devtools/client/webide/themes/config-view.css b/devtools/client/webide/themes/config-view.css deleted file mode 100644 index 019e735df..000000000 --- a/devtools/client/webide/themes/config-view.css +++ /dev/null @@ -1,80 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -html, body { - background: white; -} - -.action { - display: inline; -} - -.action[hidden] { - display: none; -} - -#device-fields { - font-family: sans-serif; - padding-left: 6px; - width: 100%; - table-layout: auto; - margin-top: 110px; -} - -#custom-value-name { - width: 50%; -} - -header { - background-color: rgba(255, 255, 255, 0.8); - border-bottom: 1px solid #EEE; - position: fixed; - top: 0; - left: 0; - right: 0; - height: 90px; - padding: 10px 20px; -} - -#device-fields td { - background-color: #F9F9F9; - border-bottom: 1px solid #CCC; - border-right: 1px solid #FFF; - font-size: 0.75em; -} - -#device-fields td:first-child { - max-width: 250px; - min-width: 150px; -} - -#device-fields td.preference-name, #device-fields td.setting-name { - width: 50%; - min-width: 400px; - word-break: break-all; -} - -#device-fields button { - display: inline-block; - font-family: sans-serif; - font-size: 0.7rem; - white-space: nowrap; -} - -#device-fields tr.hide, #device-fields button.hide { - display: none; -} - -#device-fields .custom-input { - width: 130px; -} - -#search { - margin-bottom: 20px; - width: 100%; -} - -#search-bar { - width: 80%; -} diff --git a/devtools/client/webide/themes/deck.css b/devtools/client/webide/themes/deck.css deleted file mode 100644 index 30537f612..000000000 --- a/devtools/client/webide/themes/deck.css +++ /dev/null @@ -1,91 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -html { - font: message-box; - font-size: 0.9em; - font-weight: normal; - margin: 0; - height: 100%; - color: #737980; - background-color: #ededed; -} - -body { - margin: 0; - padding: 20px; - background-image: linear-gradient(#fff, #ededed 100px); -} - -.text-input { - display: flex; -} - -.text-input input { - flex: 0.5; - margin-left: 5px; -} - -h1 { - font-size: 2em; - font-weight: lighter; - line-height: 1.2; - margin: 0; - margin-bottom: .5em; -} - -#controls { - float: right; - position: relative; - top: -10px; - right: -10px; -} - -#controls > a { - color: #4C9ED9; - font-size: small; - cursor: pointer; - border-bottom: 1px dotted; - margin-left: 10px; -} - -table { - font-family: monospace; - border-collapse: collapse; -} - -th, td { - padding: 5px; - border: 1px solid #eee; -} - -th { - min-width: 100px; -} - -th:first-of-type, td:first-of-type { - text-align: left; -} - -li { - list-style: none; - padding: 2px; -} - -li > label:hover { - background-color: rgba(0,0,0,0.02); -} - -li > label > span { - display: inline-block; -} - -input, select { - box-sizing: border-box; -} - -select { - padding-top: 2px; - padding-bottom: 2px; -} diff --git a/devtools/client/webide/themes/default-app-icon.png b/devtools/client/webide/themes/default-app-icon.png Binary files differdeleted file mode 100644 index f186d9c62..000000000 --- a/devtools/client/webide/themes/default-app-icon.png +++ /dev/null diff --git a/devtools/client/webide/themes/details.css b/devtools/client/webide/themes/details.css deleted file mode 100644 index dc73d5357..000000000 --- a/devtools/client/webide/themes/details.css +++ /dev/null @@ -1,138 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -body { - margin: 0; - background-color: white; - font: message-box; -} - -.hidden { - display: none; -} - -h1, h3, p { - margin: 0; -} - -#toolbar { - background-color: #D8D8D8; - border-bottom: 1px solid #AAA; -} - -#toolbar > button { - -moz-appearance: none; - background-color: transparent; - border-width: 0 1px 0 0; - border-color: #AAA; - border-style: solid; - margin: 0; - padding: 0 12px; - font-family: inherit; - font-weight: bold; - height: 24px; -} - -#toolbar > button:hover { - background-color: #CCC; - cursor: pointer; -} - -#validation_status { - float: right; - text-transform: uppercase; - font-size: 10px; - line-height: 24px; - padding: 0 12px; - color: white; -} - - -header { - padding: 20px 0; -} - -header > div { - vertical-align: top; - display: flex; - flex-direction: column; -} - -#icon { - height: 48px; - width: 48px; - float: left; - margin: 0 20px; -} - -h1, #type { - line-height: 24px; - height: 24px; /* avoid collapsing if empty */ - display: block; -} - -h1 { - font-size: 20px; - overflow-x: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -#type { - font-size: 10px; - text-transform: uppercase; - color: #777; -} - -main { - padding-left: 88px; -} - -h3 { - color: #999; - font-size: 10px; - font-weight: normal; -} - -main > p { - margin-bottom: 20px; -} - -.validation_messages { - margin-left: 74px; - list-style: none; - border-left: 4px solid transparent; - padding: 0 10px;; -} - - -body.valid #validation_status { - background-color: #81D135; -} - -body.warning #validation_status { - background-color: #FFAC00; -} - -body.error #validation_status { - background-color: #ED4C62; -} - -#warningslist { - border-color: #FFAC00 -} - -#errorslist { - border-color: #ED4C62; -} - -#validation_status > span { - display: none; -} - -body.valid #validation_status > .valid, -body.warning #validation_status > .warning, -body.error #validation_status > .error { - display: inline; -} diff --git a/devtools/client/webide/themes/icons.png b/devtools/client/webide/themes/icons.png Binary files differdeleted file mode 100644 index 5e1dd5c64..000000000 --- a/devtools/client/webide/themes/icons.png +++ /dev/null diff --git a/devtools/client/webide/themes/jar.mn b/devtools/client/webide/themes/jar.mn deleted file mode 100644 index 4235278da..000000000 --- a/devtools/client/webide/themes/jar.mn +++ /dev/null @@ -1,24 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -webide.jar: -% skin webide classic/1.0 %skin/ -* skin/webide.css (webide.css) - skin/icons.png (icons.png) - skin/details.css (details.css) - skin/newapp.css (newapp.css) - skin/throbber.svg (throbber.svg) - skin/deck.css (deck.css) - skin/addons.css (addons.css) - skin/runtimedetails.css (runtimedetails.css) - skin/permissionstable.css (permissionstable.css) - skin/monitor.css (monitor.css) - skin/config-view.css (config-view.css) - skin/wifi-auth.css (wifi-auth.css) - skin/logs.css (logs.css) - skin/panel-listing.css (panel-listing.css) - skin/simulator.css (simulator.css) - skin/rocket.svg (rocket.svg) - skin/noise.png (noise.png) - skin/default-app-icon.png (default-app-icon.png) diff --git a/devtools/client/webide/themes/logs.css b/devtools/client/webide/themes/logs.css deleted file mode 100644 index 446b6e41c..000000000 --- a/devtools/client/webide/themes/logs.css +++ /dev/null @@ -1,18 +0,0 @@ -html, body { - background: var(--theme-body-background); - color: var(--theme-body-color); -} - -h1 { - font-size: 1.2em; -} - -ul { - padding: 0; - font-size: 1em; -} - -li { - list-style: none; - margin: 0; -} diff --git a/devtools/client/webide/themes/monitor.css b/devtools/client/webide/themes/monitor.css deleted file mode 100644 index ba4b298ed..000000000 --- a/devtools/client/webide/themes/monitor.css +++ /dev/null @@ -1,86 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Graph */ -.graph { - height: 500px; - width: 100%; - padding-top: 20px; - padding-bottom: 20px; - margin-bottom: 30px; - background-color: white; -} -.graph > svg, .sidebar { - display: inline-block; - vertical-align: top; -} -.disabled { - opacity: 0.5; -} -.graph.disabled { - height: 30px; -} -.graph.disabled > svg { - visibility: hidden; -} -.curve path, .event-slot line { - fill: none; - stroke-width: 1.5px; -} -.axis line { - fill: none; - stroke: #000; - shape-rendering: crispEdges; -} -.axis path { - fill: none; - stroke: black; - stroke-width: 1px; - shape-rendering: crispEdges; -} -.tick text, .x.ruler text, .y.ruler text { - font-size: 0.9em; -} -.x.ruler text { - text-anchor: middle; -} -.y.ruler text { - text-anchor: end; -} - -/* Sidebar */ -.sidebar { - width: 150px; - overflow-x: hidden; -} -.sidebar label { - cursor: pointer; - display: block; -} -.sidebar span:not(.color) { - vertical-align: 13%; -} -.sidebar input { - visibility: hidden; -} -.sidebar input:hover { - visibility: visible; -} -.graph-title { - margin-top: 5px; - font-size: 1.2em; -} -.legend-color { - display: inline-block; - height: 10px; - width: 10px; - margin-left: 1px; - margin-right: 3px; -} -.legend-id { - font-size: .9em; -} -.graph.disabled > .sidebar > .legend { - display: none; -} diff --git a/devtools/client/webide/themes/moz.build b/devtools/client/webide/themes/moz.build deleted file mode 100644 index aac3a838c..000000000 --- a/devtools/client/webide/themes/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -JAR_MANIFESTS += ['jar.mn'] diff --git a/devtools/client/webide/themes/newapp.css b/devtools/client/webide/themes/newapp.css deleted file mode 100644 index 0b351a40a..000000000 --- a/devtools/client/webide/themes/newapp.css +++ /dev/null @@ -1,54 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -dialog { - -moz-appearance: none; - background-image: linear-gradient(rgb(255, 255, 255), rgb(237, 237, 237) 100px); - font-family: "Clear Sans", sans-serif; - color: #424E5A; - overflow-y: scroll; -} - -.header-name { - font-size: 1.5rem; - font-weight: normal; - margin: 15px 0; -} - -richlistbox { - -moz-appearance: none; - overflow-y: auto; - border: 1px solid #424E5A; -} - -richlistitem { - padding: 6px 0; -} - -richlistitem:not([selected="true"]):hover { - background-color: rgba(0,0,0,0.04); -} - -richlistitem > vbox > label { - margin: 0; - font-size: 1.1em; -} - -richlistbox > description { - margin: 8px; -} - -richlistitem { - -moz-box-align: start; -} - -richlistitem > image { - height: 24px; - width: 24px; - margin: 0 6px; -} - -textbox { - font-size: 1.2rem; -} diff --git a/devtools/client/webide/themes/noise.png b/devtools/client/webide/themes/noise.png Binary files differdeleted file mode 100644 index b3c42acae..000000000 --- a/devtools/client/webide/themes/noise.png +++ /dev/null diff --git a/devtools/client/webide/themes/panel-listing.css b/devtools/client/webide/themes/panel-listing.css deleted file mode 100644 index 06e51211c..000000000 --- a/devtools/client/webide/themes/panel-listing.css +++ /dev/null @@ -1,150 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -html { - font: message-box; - font-size: 11px; - font-weight: 400; -} - -label, -.panel-item, -#project-panel-projects, -#runtime-panel-projects { - display: block; - float: left; - width: 100%; - text-align: left; -} - -.project-image, -.panel-item span { - display: inline-block; - float: left; - line-height: 20px; -} - -.project-image { - margin-right: 10px; - max-height: 20px; -} - -.panel-header { - color: #ACACAC; - text-transform: uppercase; - line-height: 200%; - margin: 5px 5px 0 5px; - font-weight: 700; - width: 100%; -} - -.panel-header:first-child { - margin-top: 0; -} - -.panel-header[hidden], .panel-item[hidden] { - display: none; -} - -#runtime-panel-simulator, -.panel-item-complex { - clear: both; - position: relative; -} - -.panel-item span { - display: block; - float: left; - overflow: hidden; - text-overflow: ellipsis; - width: 75%; - white-space: nowrap; -} - -.panel-item { - -moz-appearance: none; - -moz-box-align: center; - padding: 3%; - display: block; - width: 94%; - cursor: pointer; - border-top: 1px solid transparent; - border-left: 0; - border-bottom: 1px solid #CCC; - border-right: 0; - background-color: transparent; -} - -button.panel-item { - background-position: 5px 5px; - background-repeat: no-repeat; - background-size: 14px 14px; - padding-left: 25px; - width: 100%; -} - -.panel-item:disabled { - background-color: #FFF; - color: #5A5A5A; - opacity: 0.5; - cursor: default; -} - -.refresh-icon { - background-image: url("chrome://devtools/skin/images/reload.svg"); - height: 14px; - width: 14px; - border: 0; - opacity: 0.6; - display: inline-block; - margin: 3px; - float: right; -} - -.panel-item:not(:disabled):hover, -button.panel-item:not(:disabled):hover { - background-color: #CCF0FD; - border-top: 1px solid #EDEDED; -} - -.configure-button { - display: inline-block; - height: 30px; - width: 30px; - background-color: transparent; - background-image: -moz-image-rect(url("icons.png"), 104, 462, 129, 438); - background-position: center center; - background-repeat: no-repeat; - background-size: 14px 14px; - position: absolute; - top: -2px; - right: 0; - border: 0; -} - -.configure-button:hover { - cursor: pointer; -} - -.project-panel-item-openpackaged { background-image: -moz-image-rect(url("icons.png"), 260, 438, 286, 412); } -.runtime-panel-item-simulator { background-image: -moz-image-rect(url("icons.png"), 0, 438, 26, 412); } -.runtime-panel-item-other { background-image: -moz-image-rect(url("icons.png"), 26, 438, 52, 412); } -#runtime-permissions { background-image: -moz-image-rect(url("icons.png"), 105, 438, 131, 412); } -#runtime-screenshot { background-image: -moz-image-rect(url("icons.png"), 131, 438, 156, 412); } - -#runtime-preferences, -#runtime-settings { background-image: -moz-image-rect(url("icons.png"), 105, 464, 131, 438); } - -#runtime-panel-nousbdevice, -#runtime-details { background-image: -moz-image-rect(url("icons.png"), 156, 438, 182, 412); } - -.runtime-panel-item-usb, -#runtime-disconnect { background-image: -moz-image-rect(url("icons.png"), 52, 438, 78, 412); } - -.runtime-panel-item-wifi, -.project-panel-item-openhosted { background-image: -moz-image-rect(url("icons.png"), 208, 438, 234, 412); } - -.project-panel-item-newapp, -#runtime-panel-noadbhelper, -#runtime-panel-installsimulator { background-image: -moz-image-rect(url("icons.png"), 234, 438, 260, 412); } diff --git a/devtools/client/webide/themes/permissionstable.css b/devtools/client/webide/themes/permissionstable.css deleted file mode 100644 index 3a45e0d74..000000000 --- a/devtools/client/webide/themes/permissionstable.css +++ /dev/null @@ -1,23 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -html, body { - background: white; -} - -.permissionstable td { - text-align: center; -} - -.permallow { - color: rgb(152,207,57); -} - -.permprompt { - color: rgb(0,158,237); -} - -.permdeny { - color: rgb(204,73,8); -} diff --git a/devtools/client/webide/themes/rocket.svg b/devtools/client/webide/themes/rocket.svg deleted file mode 100644 index a0cca5c21..000000000 --- a/devtools/client/webide/themes/rocket.svg +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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/. --> -<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24"> - <g opacity="0.1"> - <path fill="#fff" d="M12,2.3c-1.127,0-3.333,3.721-4.084,7.411l-2.535,2.535v6.619l1.767,0l2.464-2.464 c0.252,0.264,0.529,0.486,0.827,0.662h3.118c0.299-0.175,0.579-0.397,0.831-0.662l2.464,2.464l1.767,0v-6.619l-2.535-2.535 C15.333,6.021,13.127,2.3,12,2.3z M12.003,6.181c0.393,0,1.084,1.103,1.515,2.423c-0.466-0.087-0.963-0.135-1.481-0.135 c-0.545,0-1.066,0.054-1.553,0.15C10.914,7.292,11.608,6.181,12.003,6.181z"/> - <path fill="#fff" d="M12.792,18.755c0,0.778-0.603,1.408-0.805,1.408c-0.201,0-0.805-0.631-0.805-1.408 c0-0.301,0.055-0.579,0.147-0.809h-0.932c-0.109,0.403-0.171,0.854-0.171,1.33c0,1.714,1.33,3.104,1.774,3.104 s1.774-1.389,1.774-3.103c0-0.477-0.062-0.927-0.171-1.331l-0.957,0C12.738,18.175,12.792,18.453,12.792,18.755z"/> - <path fill="#414042" d="M12,2c-1.127,0-3.333,3.721-4.084,7.411l-2.535,2.535v6.619l1.767,0l2.464-2.464 c0.252,0.264,0.529,0.486,0.827,0.662h3.118c0.299-0.175,0.579-0.397,0.831-0.662l2.464,2.464l1.767,0v-6.619l-2.535-2.535 C15.333,5.721,13.127,2,12,2z M12.003,5.881c0.393,0,1.084,1.103,1.515,2.423c-0.466-0.087-0.963-0.135-1.481-0.135 c-0.545,0-1.066,0.054-1.553,0.15C10.914,6.992,11.608,5.881,12.003,5.881z"/> - <path fill="#414042" d="M12.792,18.455c0,0.778-0.603,1.408-0.805,1.408c-0.201,0-0.805-0.631-0.805-1.408 c0-0.301,0.055-0.579,0.147-0.809h-0.932c-0.109,0.403-0.171,0.854-0.171,1.33c0,1.714,1.33,3.104,1.774,3.104 s1.774-1.389,1.774-3.103c0-0.477-0.062-0.927-0.171-1.331l-0.957,0C12.738,17.875,12.792,18.153,12.792,18.455z"/> - </g> -</svg> diff --git a/devtools/client/webide/themes/runtimedetails.css b/devtools/client/webide/themes/runtimedetails.css deleted file mode 100644 index 91ced5bff..000000000 --- a/devtools/client/webide/themes/runtimedetails.css +++ /dev/null @@ -1,25 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -html, body { - background: white; -} - -#devicePrivileges { - font-family: monospace; - padding-left: 6px; -} - -#devtools-check > a { - color: #4C9ED9; - cursor: pointer; -} - -.action { - display: inline; -} - -.action[hidden] { - display: none; -} diff --git a/devtools/client/webide/themes/simulator.css b/devtools/client/webide/themes/simulator.css deleted file mode 100644 index 036cfcdb4..000000000 --- a/devtools/client/webide/themes/simulator.css +++ /dev/null @@ -1,41 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -select:not(.custom) > option[value="custom"] { - display: none; -} - -select, input[type="text"] { - width: 13rem; -} - -input[name="name"] { - height: 1.8rem; -} - -input[type="number"] { - width: 6rem; -} - -input[type="text"], input[type="number"] { - padding-left: 0.2rem; -} - -li > label:hover { - background-color: transparent; -} - -ul { - padding-left: 0; -} - -.label { - width: 6rem; - padding: 0.2rem; - text-align: right; -} - -.hidden { - display: none; -} diff --git a/devtools/client/webide/themes/throbber.svg b/devtools/client/webide/themes/throbber.svg deleted file mode 100644 index d89fb3851..000000000 --- a/devtools/client/webide/themes/throbber.svg +++ /dev/null @@ -1,22 +0,0 @@ -<!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - -<svg xmlns="http://www.w3.org/2000/svg" - width="24" height="24" viewBox="0 0 64 64"> - <g> - <rect x="30" y="4" width="4" height="15" transform="rotate(0, 32, 32)" fill="#BBB"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(30, 32, 32)" fill="#AAA"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(60, 32, 32)" fill="#999"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(90, 32, 32)" fill="#888"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(120, 32, 32)" fill="#777"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(150, 32, 32)" fill="#666"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(180, 32, 32)" fill="#555"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(210, 32, 32)" fill="#444"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(240, 32, 32)" fill="#333"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(270, 32, 32)" fill="#222"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(300, 32, 32)" fill="#111"/> - <rect x="30" y="4" width="4" height="15" transform="rotate(330, 32, 32)" fill="#000"/> - <animateTransform attributeName="transform" type="rotate" calcMode="discrete" values="0 32 32;30 32 32;60 32 32;90 32 32;120 32 32;150 32 32;180 32 32;210 32 32;240 32 32;270 32 32;300 32 32;330 32 32" dur="0.8s" repeatCount="indefinite"/> - </g> -</svg> diff --git a/devtools/client/webide/themes/webide.css b/devtools/client/webide/themes/webide.css deleted file mode 100644 index 0dea91a5f..000000000 --- a/devtools/client/webide/themes/webide.css +++ /dev/null @@ -1,149 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * - * Icons.png: - * - * actions icons: 100x100. Starts at 0x0. - * menu icons: 26x26. Starts at 312x0. - * anchors icons: 27x16. Starts at 364x0. - * - */ - -#main-toolbar { - padding: 0 12px; -} - -#action-buttons-container { - -moz-box-pack: center; - height: 50px; -} - -#panel-buttons-container { - height: 50px; - margin-top: -50px; - pointer-events: none; -} - -#panel-buttons-container > .panel-button { - pointer-events: auto; -} - -#action-busy-undetermined { - height: 24px; - width: 24px; -} - -window.busy .action-button, -window:not(.busy) #action-busy, -window.busy-undetermined #action-busy-determined, -window.busy-determined #action-busy-undetermined { - display: none; -} - -/* Panel buttons - runtime */ - -#runtime-panel-button > .panel-button-image { - list-style-image: url('icons.png'); - -moz-image-region: rect(78px,438px,104px,412px); - width: 13px; - height: 13px; -} - -#runtime-panel-button[active="true"] > .panel-button-image { - -moz-image-region: rect(78px,464px,104px,438px); -} - -/* Action buttons */ - -.action-button { - -moz-appearance: none; - border-width: 0; - margin: 0; - padding: 0; - list-style-image: url('icons.png'); -} - -.action-button[disabled="true"] { - opacity: 0.4; -} - -.action-button > .toolbarbutton-icon { - width: 40px; - height: 40px; -} - -.action-button > .toolbarbutton-text { - display: none; -} - -#action-button-play { -moz-image-region: rect(0,100px,100px,0) } -#action-button-stop { -moz-image-region: rect(0,200px,100px,100px) } -#action-button-debug { -moz-image-region: rect(0,300px,100px,200px) } - -#action-button-play:not([disabled="true"]):hover { -moz-image-region: rect(200px,100px,300px,0) } -#action-button-stop:not([disabled="true"]):hover { -moz-image-region: rect(200px,200px,300px,100px) } -#action-button-debug:not([disabled="true"]):not([active="true"]):hover { -moz-image-region: rect(200px,300px,300px,200px) } - -#action-button-play.reload { -moz-image-region: rect(0,400px,100px,303px) } -#action-button-play.reload:hover { -moz-image-region: rect(200px,400px,300px,303px) } - -#action-button-debug[active="true"] { -moz-image-region: rect(100px,300px,200px,200px) } - -/* Panels */ - -.panel-list { - display: none; - position: relative; - max-width: 190px; - overflow: hidden; -} - -#project-listing-panel { - max-width: 165px; -} - -.panel-list-wrapper { - height: 100%; - width: 100%; - min-width: 100px; - position: absolute; - top: 0; - bottom: 0; - right: 0; - left: 0; -} - -.panel-list-wrapper > iframe { - height: inherit; - width: 100%; - position: absolute; - top: 0; - bottom: 0; - right: 0; - left: 0; -} - -[sidebar-displayed] { - display: block; -} - -/* Main view */ - -#deck { - background-color: rgb(225, 225, 225); - background-image: url('rocket.svg'), url('noise.png'); - background-repeat: no-repeat, repeat; - background-size: 35%, auto; - background-position: center center, top left; -%ifndef XP_MACOSX - border-top: 1px solid #AAA; -%endif -} - -.devtools-horizontal-splitter { - position: relative; - border-bottom: 1px solid #aaa; -} diff --git a/devtools/client/webide/themes/wifi-auth.css b/devtools/client/webide/themes/wifi-auth.css deleted file mode 100644 index de6afc94e..000000000 --- a/devtools/client/webide/themes/wifi-auth.css +++ /dev/null @@ -1,64 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -html, body { - background: white; -} - -body { - display: flex; - flex-direction: column; - height: 90%; -} - -div { - margin-bottom: 1em; -} - -#qr-code { - flex: 1; - display: flex; - flex-direction: column; - align-items: center; -} - -#qr-code-wrapper { - flex: 1; - width: 100%; - margin: 2em 0; - text-align: center; -} - -#qr-code img { - height: 100%; -} - -.toggle-scanner { - color: #4C9ED9; - font-size: small; - cursor: pointer; - border-bottom: 1px dotted; -} - -#token { - display: none; -} - -body[token] > #token { - display: flex; - flex-direction: column; -} - -body[token] > #qr-code { - display: none; -} - -#token pre, -#token a { - align-self: center; -} - -#qr-size-note { - text-align: center -} diff --git a/devtools/client/webide/webide-prefs.js b/devtools/client/webide/webide-prefs.js deleted file mode 100644 index 94871171d..000000000 --- a/devtools/client/webide/webide-prefs.js +++ /dev/null @@ -1,35 +0,0 @@ -# -*- indent-tabs-mode: nil; js-indent-level: 2 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -pref("devtools.webide.showProjectEditor", true); -pref("devtools.webide.templatesURL", "https://code.cdn.mozilla.net/templates/list.json"); -pref("devtools.webide.autoinstallADBHelper", true); -pref("devtools.webide.autoinstallFxdtAdapters", true); -pref("devtools.webide.autoConnectRuntime", true); -pref("devtools.webide.restoreLastProject", true); -pref("devtools.webide.enableLocalRuntime", false); -pref("devtools.webide.addonsURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/fxos-simulator/index.json"); -pref("devtools.webide.simulatorAddonsURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/fxos-simulator/#VERSION#/#OS#/fxos_#SLASHED_VERSION#_simulator-#OS#-latest.xpi"); -pref("devtools.webide.simulatorAddonID", "fxos_#SLASHED_VERSION#_simulator@mozilla.org"); -pref("devtools.webide.simulatorAddonRegExp", "fxos_(.*)_simulator@mozilla\\.org$"); -pref("devtools.webide.adbAddonURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/fxos-simulator/adb-helper/#OS#/adbhelper-#OS#-latest.xpi"); -pref("devtools.webide.adbAddonID", "adbhelper@mozilla.org"); -pref("devtools.webide.adaptersAddonURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/valence/#OS#/valence-#OS#-latest.xpi"); -pref("devtools.webide.adaptersAddonID", "fxdevtools-adapters@mozilla.org"); -pref("devtools.webide.monitorWebSocketURL", "ws://localhost:9000"); -pref("devtools.webide.lastConnectedRuntime", ""); -pref("devtools.webide.lastSelectedProject", ""); -pref("devtools.webide.logSimulatorOutput", false); -pref("devtools.webide.widget.autoinstall", true); -#ifdef MOZ_DEV_EDITION -pref("devtools.webide.widget.enabled", true); -pref("devtools.webide.widget.inNavbarByDefault", true); -#else -pref("devtools.webide.widget.enabled", false); -pref("devtools.webide.widget.inNavbarByDefault", false); -#endif -pref("devtools.webide.zoom", "1"); -pref("devtools.webide.busyTimeout", 10000); -pref("devtools.webide.autosaveFiles", true); diff --git a/devtools/server/actors/webconsole.js b/devtools/server/actors/webconsole.js index a1eba84ed..66715bd34 100644 --- a/devtools/server/actors/webconsole.js +++ b/devtools/server/actors/webconsole.js @@ -888,7 +888,8 @@ WebConsoleActor.prototype = let evalResult = evalInfo.result; let helperResult = evalInfo.helperResult; - let result, errorDocURL, errorMessage, errorGrip = null, frame = null; + let result, errorDocURL, errorMessage, errorNotes = null, errorGrip = null, + frame = null; if (evalResult) { if ("return" in evalResult) { result = evalResult.return; @@ -943,6 +944,23 @@ WebConsoleActor.prototype = }; } } catch (ex) {} + + try { + let notes = error.errorNotes; + if (notes && notes.length) { + errorNotes = []; + for (let note of notes) { + errorNotes.push({ + messageBody: this._createStringGrip(note.message), + frame: { + source: note.fileName, + line: note.lineNumber, + column: note.columnNumber, + } + }); + } + } + } catch (ex) {} } } @@ -967,6 +985,7 @@ WebConsoleActor.prototype = exceptionDocURL: errorDocURL, frame, helperResult: helperResult, + notes: errorNotes, }; }, @@ -1500,6 +1519,23 @@ WebConsoleActor.prototype = lineText = lineText.substr(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH); } + let notesArray = null; + let notes = aPageError.notes; + if (notes && notes.length) { + notesArray = []; + for (let i = 0, len = notes.length; i < len; i++) { + let note = notes.queryElementAt(i, Ci.nsIScriptErrorNote); + notesArray.push({ + messageBody: this._createStringGrip(note.errorMessage), + frame: { + source: note.sourceName, + line: note.lineNumber, + column: note.columnNumber, + } + }); + } + } + return { errorMessage: this._createStringGrip(aPageError.errorMessage), errorMessageName: aPageError.errorMessageName, @@ -1516,7 +1552,8 @@ WebConsoleActor.prototype = strict: !!(aPageError.flags & aPageError.strictFlag), info: !!(aPageError.flags & aPageError.infoFlag), private: aPageError.isFromPrivateWindow, - stacktrace: stack + stacktrace: stack, + notes: notesArray, }; }, diff --git a/devtools/shared/webconsole/test/test_page_errors.html b/devtools/shared/webconsole/test/test_page_errors.html index 78138856e..b4c0fe885 100644 --- a/devtools/shared/webconsole/test/test_page_errors.html +++ b/devtools/shared/webconsole/test/test_page_errors.html @@ -112,6 +112,24 @@ function doPageErrors() warning: true, exception: false, }, + "let a, a;": { + errorMessage: /redeclaration of/, + errorMessageName: "JSMSG_REDECLARED_VAR", + sourceName: /test_page_errors/, + category: "chrome javascript", + timeStamp: /^\d+$/, + error: false, + warning: false, + exception: true, + notes: [ + { + messageBody: /Previously declared at line/, + frame: { + source: /test_page_errors/, + } + } + ] + }, }; let container = document.createElement("script"); diff --git a/dom/base/nsContentPolicy.cpp b/dom/base/nsContentPolicy.cpp index 5511b9086..534466103 100644 --- a/dom/base/nsContentPolicy.cpp +++ b/dom/base/nsContentPolicy.cpp @@ -22,6 +22,7 @@ #include "nsIDOMWindow.h" #include "nsITabChild.h" #include "nsIContent.h" +#include "nsIImageLoadingContent.h" #include "nsILoadContext.h" #include "nsCOMArray.h" #include "nsContentUtils.h" @@ -145,6 +146,16 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, decision); if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) { + // If we are blocking an image, we have to let the + // ImageLoadingContent know that we blocked the load. + if (externalType == nsIContentPolicy::TYPE_IMAGE || + externalType == nsIContentPolicy::TYPE_IMAGESET) { + nsCOMPtr<nsIImageLoadingContent> img = + do_QueryInterface(requestingContext); + if (img) { + img->SetBlockedRequest(*decision); + } + } /* policy says no, no point continuing to check */ return NS_OK; } @@ -193,6 +204,16 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod, decision); if (NS_SUCCEEDED(rv) && NS_CP_REJECTED(*decision)) { + // If we are blocking an image, we have to let the + // ImageLoadingContent know that we blocked the load. + if (externalType == nsIContentPolicy::TYPE_IMAGE || + externalType == nsIContentPolicy::TYPE_IMAGESET) { + nsCOMPtr<nsIImageLoadingContent> img = + do_QueryInterface(requestingContext); + if (img) { + img->SetBlockedRequest(*decision); + } + } /* policy says no, no point continuing to check */ return NS_OK; } diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 1f9c17947..800f40fa1 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -8478,12 +8478,9 @@ nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(nsContentPolicyType bool nsContentUtils::IsPreloadType(nsContentPolicyType aType) { - if (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD || - aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD || - aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD) { - return true; - } - return false; + return (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD || + aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD || + aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD); } nsresult diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index a6ed419df..6b8e11db0 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -9222,19 +9222,23 @@ already_AddRefed<nsIURI> nsDocument::ResolvePreloadImage(nsIURI *aBaseURI, const nsAString& aSrcAttr, const nsAString& aSrcsetAttr, - const nsAString& aSizesAttr) + const nsAString& aSizesAttr, + bool *aIsImgSet) { nsString sourceURL; + bool isImgSet; if (mPreloadPictureDepth == 1 && !mPreloadPictureFoundSource.IsVoid()) { // We're in a <picture> element and found a URI from a source previous to // this image, use it. sourceURL = mPreloadPictureFoundSource; + isImgSet = true; } else { // Otherwise try to use this <img> as a source HTMLImageElement::SelectSourceForTagWithAttrs(this, false, aSrcAttr, aSrcsetAttr, aSizesAttr, NullString(), NullString(), sourceURL); + isImgSet = !aSrcsetAttr.IsEmpty(); } // Empty sources are not loaded by <img> (i.e. not resolved to the baseURI) @@ -9252,6 +9256,8 @@ nsDocument::ResolvePreloadImage(nsIURI *aBaseURI, return nullptr; } + *aIsImgSet = isImgSet; + // We don't clear mPreloadPictureFoundSource because subsequent <img> tags in // this this <picture> share the same <sources> (though this is not valid per // spec) @@ -9260,16 +9266,12 @@ nsDocument::ResolvePreloadImage(nsIURI *aBaseURI, void nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr, - ReferrerPolicy aReferrerPolicy) + ReferrerPolicy aReferrerPolicy, bool aIsImgSet) { // Early exit if the img is already present in the img-cache // which indicates that the "real" load has already started and // that we shouldn't preload it. - int16_t blockingStatus; - if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this)) || - !nsContentUtils::CanLoadImage(uri, static_cast<nsIDocument *>(this), - this, NodePrincipal(), &blockingStatus, - nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD)) { + if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this))) { return; } @@ -9288,6 +9290,10 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr, MOZ_CRASH("Unknown CORS mode!"); } + nsContentPolicyType policyType = + aIsImgSet ? nsIContentPolicy::TYPE_IMAGESET : + nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD; + // Image not in cache - trigger preload RefPtr<imgRequestProxy> request; nsresult rv = @@ -9301,7 +9307,7 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr, loadFlags, NS_LITERAL_STRING("img"), getter_AddRefs(request), - nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD); + policyType); // Pin image-reference to avoid evicting it from the img-cache before // the "real" load occurs. Unpinned in DispatchContentLoadedEvents and @@ -11943,7 +11949,8 @@ nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const &aWindowSizes->mLayoutPresShellSize, &aWindowSizes->mLayoutStyleSetsSize, &aWindowSizes->mLayoutTextRunsSize, - &aWindowSizes->mLayoutPresContextSize); + &aWindowSizes->mLayoutPresContextSize, + &aWindowSizes->mLayoutFramePropertiesSize); } aWindowSizes->mPropertyTablesSize += diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 95fd57545..2b29b98fa 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -948,11 +948,13 @@ public: ResolvePreloadImage(nsIURI *aBaseURI, const nsAString& aSrcAttr, const nsAString& aSrcsetAttr, - const nsAString& aSizesAttr) override; + const nsAString& aSizesAttr, + bool *aIsImgSet) override; virtual void MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr, - ReferrerPolicy aReferrerPolicy) override; + ReferrerPolicy aReferrerPolicy, + bool aIsImgSet) override; virtual void ForgetImagePreload(nsIURI* aURI) override; virtual void MaybePreconnect(nsIURI* uri, diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index e5d12ab8f..d76a12d71 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -2260,21 +2260,27 @@ public: * nesting and possible sources, which are used to inform URL selection * responsive <picture> or <img srcset> images. Unset attributes are expected * to be marked void. + * If this image is for <picture> or <img srcset>, aIsImgSet will be set to + * true, false otherwise. */ virtual already_AddRefed<nsIURI> ResolvePreloadImage(nsIURI *aBaseURI, const nsAString& aSrcAttr, const nsAString& aSrcsetAttr, - const nsAString& aSizesAttr) = 0; + const nsAString& aSizesAttr, + bool *aIsImgSet) = 0; /** * Called by nsParser to preload images. Can be removed and code moved * to nsPreloadURIs::PreloadURIs() in file nsParser.cpp whenever the * parser-module is linked with gklayout-module. aCrossOriginAttr should * be a void string if the attr is not present. + * aIsImgSet is the value got from calling ResolvePreloadImage, it is true + * when this image is for loading <picture> or <img srcset> images. */ virtual void MaybePreLoadImage(nsIURI* uri, const nsAString& aCrossOriginAttr, - ReferrerPolicyEnum aReferrerPolicy) = 0; + ReferrerPolicyEnum aReferrerPolicy, + bool aIsImgSet) = 0; /** * Called by images to forget an image preload when they start doing diff --git a/dom/base/nsIImageLoadingContent.idl b/dom/base/nsIImageLoadingContent.idl index fea261a34..eacc4ac3a 100644 --- a/dom/base/nsIImageLoadingContent.idl +++ b/dom/base/nsIImageLoadingContent.idl @@ -104,6 +104,15 @@ interface nsIImageLoadingContent : imgINotificationObserver imgIRequest getRequest(in long aRequestType); /** + * Call this function when the request was blocked by any of the + * security policies enforced. + * + * @param aContentDecision the decision returned from nsIContentPolicy + * (any of the types REJECT_*) + */ + void setBlockedRequest(in int16_t aContentDecision); + + /** * @return true if the current request's size is available. */ [noscript, notxpcom] boolean currentRequestHasSize(); diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index 0c6c37b44..4aad55941 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -44,6 +44,7 @@ #include "mozAutoDocUpdate.h" #include "mozilla/AsyncEventDispatcher.h" +#include "mozilla/AutoRestore.h" #include "mozilla/EventStates.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/ImageTracker.h" @@ -94,7 +95,8 @@ nsImageLoadingContent::nsImageLoadingContent() mNewRequestsWillNeedAnimationReset(false), mStateChangerDepth(0), mCurrentRequestRegistered(false), - mPendingRequestRegistered(false) + mPendingRequestRegistered(false), + mIsStartingImageLoad(false) { if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) { mLoadingEnabled = false; @@ -785,6 +787,11 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, nsIDocument* aDocument, nsLoadFlags aLoadFlags) { + MOZ_ASSERT(!mIsStartingImageLoad, "some evil code is reentering LoadImage."); + if (mIsStartingImageLoad) { + return NS_OK; + } + // Pending load/error events need to be canceled in some situations. This // is not documented in the spec, but can cause site compat problems if not // done. See bug 1309461 and https://github.com/whatwg/html/issues/1872. @@ -814,6 +821,21 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, } } + AutoRestore<bool> guard(mIsStartingImageLoad); + mIsStartingImageLoad = true; + + // Data documents, or documents from DOMParser shouldn't perform image loading. + if (aDocument->IsLoadedAsData()) { + // This is the only codepath on which we can reach SetBlockedRequest while + // our pending request exists. Just clear it out here if we do have one. + ClearPendingRequest(NS_BINDING_ABORTED, + Some(OnNonvisible::DISCARD_IMAGES)); + SetBlockedRequest(nsIContentPolicy::REJECT_REQUEST); + FireEvent(NS_LITERAL_STRING("error")); + FireEvent(NS_LITERAL_STRING("loadend")); + return NS_OK; + } + // URI equality check. // // We skip the equality check if our current image was blocked, since in that @@ -844,23 +866,8 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, "Principal mismatch?"); #endif - // Are we blocked? - int16_t cpDecision = nsIContentPolicy::REJECT_REQUEST; nsContentPolicyType policyType = PolicyTypeForLoad(aImageLoadType); - nsContentUtils::CanLoadImage(aNewURI, - static_cast<nsIImageLoadingContent*>(this), - aDocument, - aDocument->NodePrincipal(), - &cpDecision, - policyType); - if (!NS_CP_ACCEPTED(cpDecision)) { - FireEvent(NS_LITERAL_STRING("error")); - FireEvent(NS_LITERAL_STRING("loadend")); - SetBlockedRequest(aNewURI, cpDecision); - return NS_OK; - } - nsLoadFlags loadFlags = aLoadFlags; int32_t corsmode = GetCORSMode(); if (corsmode == CORS_ANONYMOUS) { @@ -878,7 +885,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, referrerPolicy = imgReferrerPolicy; } - // Not blocked. Do the load. RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType); nsCOMPtr<nsIContent> content = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this)); @@ -932,7 +938,6 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, FireEvent(NS_LITERAL_STRING("error")); FireEvent(NS_LITERAL_STRING("loadend")); - return NS_OK; } return NS_OK; @@ -1212,46 +1217,42 @@ nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType) mMostRecentRequestChange = now; } - // If we don't have a usable current request, get rid of any half-baked - // request that might be sitting there and make this one current. - if (!HaveSize(mCurrentRequest)) - return PrepareCurrentRequest(aImageLoadType); - // Otherwise, make it pending. - return PreparePendingRequest(aImageLoadType); + // We only want to cancel the existing current request if size is not + // available. bz says the web depends on this behavior. + // Otherwise, we get rid of any half-baked request that might be sitting there + // and make this one current. + // TODO: Bug 583491 + // Investigate/Cleanup NS_ERROR_IMAGE_SRC_CHANGED use in nsImageFrame.cpp + return HaveSize(mCurrentRequest) ? + PreparePendingRequest(aImageLoadType) : + PrepareCurrentRequest(aImageLoadType); } -void -nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision) +nsresult +nsImageLoadingContent::SetBlockedRequest(int16_t aContentDecision) { + // If this is not calling from LoadImage, for example, from ServiceWorker, + // bail out. + if (!mIsStartingImageLoad) { + return NS_OK; + } + // Sanity MOZ_ASSERT(!NS_CP_ACCEPTED(aContentDecision), "Blocked but not?"); - // We do some slightly illogical stuff here to maintain consistency with - // old behavior that people probably depend on. Even in the case where the - // new image is blocked, the old one should really be canceled with the - // reason "image source changed". However, apparently there's some abuse - // over in nsImageFrame where the displaying of the "broken" icon for the - // next image depends on the cancel reason of the previous image. ugh. - // XXX(seth): So shouldn't we fix nsImageFrame?! - ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED, - Some(OnNonvisible::DISCARD_IMAGES)); - - // For the blocked case, we only want to cancel the existing current request - // if size is not available. bz says the web depends on this behavior. - if (!HaveSize(mCurrentRequest)) { + // We should never have a pending request after we got blocked. + MOZ_ASSERT(!mPendingRequest, "mPendingRequest should be null."); + if (HaveSize(mCurrentRequest)) { + // PreparePendingRequest set mPendingRequestFlags, now since we've decided + // to block it, we reset it back to 0. + mPendingRequestFlags = 0; + } else { mImageBlockingStatus = aContentDecision; - uint32_t keepFlags = mCurrentRequestFlags & REQUEST_IS_IMAGESET; - ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED, - Some(OnNonvisible::DISCARD_IMAGES)); - - // We still want to remember what URI we were and if it was an imageset, - // despite not having an actual request. These are both cleared as part of - // ClearCurrentRequest() before a new request is started. - mCurrentURI = aURI; - mCurrentRequestFlags = keepFlags; } + + return NS_OK; } RefPtr<imgRequestProxy>& @@ -1262,7 +1263,7 @@ nsImageLoadingContent::PrepareCurrentRequest(ImageLoadType aImageLoadType) mImageBlockingStatus = nsIContentPolicy::ACCEPT; // Get rid of anything that was there previously. - ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED, + ClearCurrentRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES)); if (mNewRequestsWillNeedAnimationReset) { @@ -1281,7 +1282,7 @@ RefPtr<imgRequestProxy>& nsImageLoadingContent::PreparePendingRequest(ImageLoadType aImageLoadType) { // Get rid of anything that was there previously. - ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED, + ClearPendingRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES)); if (mNewRequestsWillNeedAnimationReset) { diff --git a/dom/base/nsImageLoadingContent.h b/dom/base/nsImageLoadingContent.h index 5f7daff72..cfb2a6207 100644 --- a/dom/base/nsImageLoadingContent.h +++ b/dom/base/nsImageLoadingContent.h @@ -303,17 +303,10 @@ protected: RefPtr<imgRequestProxy>& PrepareNextRequest(ImageLoadType aImageLoadType); /** - * Called when we would normally call PrepareNextRequest(), but the request was - * blocked. - */ - void SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision); - - /** * Returns a COMPtr reference to the current/pending image requests, cleaning * up and canceling anything that was there before. Note that if you just want * to get rid of one of the requests, you should call - * Clear*Request(NS_BINDING_ABORTED) instead, since it passes a more appropriate - * aReason than Prepare*Request() does (NS_ERROR_IMAGE_SRC_CHANGED). + * Clear*Request(NS_BINDING_ABORTED) instead. * * @param aImageLoadType The ImageLoadType for this request */ @@ -459,6 +452,14 @@ private: // registered with the refresh driver. bool mCurrentRequestRegistered; bool mPendingRequestRegistered; + + // This member is used in SetBlockedRequest, if it's true, then this call is + // triggered from LoadImage. + // If this is false, it means this call is from other places like + // ServiceWorker, then we will ignore call to SetBlockedRequest for now. + // + // Also we use this variable to check if some evil code is reentering LoadImage. + bool mIsStartingImageLoad; }; #endif // nsImageLoadingContent_h__ diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index c1b732258..3c850c4cd 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -715,11 +715,13 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent) /// would keep the docshell around, but trash the frameloader UnloadObject(); } - nsIDocument* doc = thisContent->GetComposedDoc(); - if (doc && doc->IsActive()) { + if (mType == eType_Plugin) { + nsIDocument* doc = thisContent->GetComposedDoc(); + if (doc && doc->IsActive()) { nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(doc, NS_LITERAL_STRING("PluginRemoved")); NS_DispatchToCurrentThread(ev); + } } } diff --git a/dom/base/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp index acec4acfb..8f4bf6b11 100644 --- a/dom/base/nsWindowMemoryReporter.cpp +++ b/dom/base/nsWindowMemoryReporter.cpp @@ -400,6 +400,12 @@ CollectWindowReports(nsGlobalWindow *aWindow, aWindowTotalSizes->mLayoutPresContextSize += windowSizes.mLayoutPresContextSize; + REPORT_SIZE("/layout/frame-properties", windowSizes.mLayoutFramePropertiesSize, + "Memory used for frame properties attached to frames " + "within a window."); + aWindowTotalSizes->mLayoutFramePropertiesSize += + windowSizes.mLayoutFramePropertiesSize; + // There are many different kinds of frames, but it is very likely // that only a few matter. Implement a cutoff so we don't bloat // about:memory with many uninteresting entries. @@ -563,6 +569,9 @@ nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport, REPORT("window-objects/layout/pres-contexts", windowTotalSizes.mLayoutPresContextSize, "This is the sum of all windows' 'layout/pres-contexts' numbers."); + REPORT("window-objects/layout/frame-properties", windowTotalSizes.mLayoutFramePropertiesSize, + "This is the sum of all windows' 'layout/frame-properties' numbers."); + size_t frameTotal = 0; #define FRAME_ID(classname) \ frameTotal += windowTotalSizes.mArenaStats.FRAME_ID_STAT_FIELD(classname); diff --git a/dom/base/nsWindowMemoryReporter.h b/dom/base/nsWindowMemoryReporter.h index b9e986959..5d40dc9f5 100644 --- a/dom/base/nsWindowMemoryReporter.h +++ b/dom/base/nsWindowMemoryReporter.h @@ -33,6 +33,7 @@ class nsWindowSizes { macro(Style, mLayoutStyleSetsSize) \ macro(Other, mLayoutTextRunsSize) \ macro(Other, mLayoutPresContextSize) \ + macro(Other, mLayoutFramePropertiesSize) \ macro(Other, mPropertyTablesSize) \ public: diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 8d2bdaac6..a26fc4422 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -1184,14 +1184,6 @@ GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor, } bool -UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp) -{ - JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - args.rval().set(args.thisv()); - return true; -} - -bool ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp) { return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR); diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index a3ec70f47..5cab835b3 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -2045,9 +2045,6 @@ GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID, } bool -UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp); - -bool ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp); bool diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 74acb5918..d7d700a96 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -2390,11 +2390,10 @@ class MethodDefiner(PropertyDefiner): # Synthesize our valueOf method self.regular.append({ "name": 'valueOf', - "nativeName": "UnforgeableValueOf", + "selfHostedName": "Object_valueOf", "methodInfo": False, "length": 0, - "flags": "JSPROP_ENUMERATE", # readonly/permanent added - # automatically. + "flags": "0", # readonly/permanent added automatically. "condition": MemberCondition() }) @@ -3456,19 +3455,15 @@ def InitUnforgeablePropertiesOnHolder(descriptor, properties, failureCode, "nsContentUtils::ThreadsafeIsCallerChrome()")) if descriptor.interface.getExtendedAttribute("Unforgeable"): - # We do our undefined toJSON and toPrimitive here, not as a regular - # property because we don't have a concept of value props anywhere in - # IDL. + # We do our undefined toPrimitive here, not as a regular property + # because we don't have a concept of value props anywhere in IDL. unforgeables.append(CGGeneric(fill( """ JS::RootedId toPrimitive(aCx, SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::toPrimitive))); if (!JS_DefinePropertyById(aCx, ${holderName}, toPrimitive, JS::UndefinedHandleValue, - JSPROP_READONLY | JSPROP_PERMANENT) || - !JS_DefineProperty(aCx, ${holderName}, "toJSON", - JS::UndefinedHandleValue, - JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT)) { + JSPROP_READONLY | JSPROP_PERMANENT)) { $*{failureCode} } """, diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build index 043b3c494..ed8a4d37e 100644 --- a/dom/bindings/moz.build +++ b/dom/bindings/moz.build @@ -6,6 +6,12 @@ TEST_DIRS += ['test'] +XPIDL_SOURCES += [ + 'nsIScriptError.idl' +] + +XPIDL_MODULE = 'dom_bindings' + EXPORTS.ipc += [ 'ErrorIPCUtils.h', ] @@ -91,6 +97,8 @@ UNIFIED_SOURCES += [ 'DOMJSProxyHandler.cpp', 'Exceptions.cpp', 'IterableIterator.cpp', + 'nsScriptError.cpp', + 'nsScriptErrorWithStack.cpp', 'SimpleGlobalObject.cpp', 'ToJSValue.cpp', 'WebIDLGlobalNameHash.cpp', diff --git a/js/xpconnect/idl/nsIScriptError.idl b/dom/bindings/nsIScriptError.idl index 468ca682f..8436361a8 100644 --- a/js/xpconnect/idl/nsIScriptError.idl +++ b/dom/bindings/nsIScriptError.idl @@ -9,13 +9,25 @@ #include "nsISupports.idl" +#include "nsIArray.idl" #include "nsIConsoleMessage.idl" %{C++ #include "nsStringGlue.h" // for nsDependentCString %} -[scriptable, uuid(361be358-76f0-47aa-b37b-6ad833599e8d)] +[scriptable, uuid(e8933fc9-c302-4e12-a55b-4f88611d9c6c)] +interface nsIScriptErrorNote : nsISupports +{ + readonly attribute AString errorMessage; + readonly attribute AString sourceName; + readonly attribute uint32_t lineNumber; + readonly attribute uint32_t columnNumber; + + AUTF8String toString(); +}; + +[scriptable, uuid(63eb4d3e-7d99-4150-b4f3-11314f9d82a9)] interface nsIScriptError : nsIConsoleMessage { /** pseudo-flag for default case */ @@ -74,6 +86,7 @@ interface nsIScriptError : nsIConsoleMessage */ attribute AString errorMessageName; + readonly attribute nsIArray notes; void init(in AString message, in AString sourceName, diff --git a/js/xpconnect/src/nsScriptError.cpp b/dom/bindings/nsScriptError.cpp index ff687bc44..9248d1a31 100644 --- a/js/xpconnect/src/nsScriptError.cpp +++ b/dom/bindings/nsScriptError.cpp @@ -5,18 +5,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* - * nsIScriptError implementation. Defined here, lacking a JS-specific - * place to put XPCOM things. + * nsIScriptError implementation. */ -#include "xpcprivate.h" +#include "nsScriptError.h" #include "jsprf.h" #include "MainThreadUtils.h" #include "mozilla/Assertions.h" #include "nsGlobalWindow.h" +#include "nsNetUtil.h" #include "nsPIDOMWindow.h" #include "nsILoadContext.h" #include "nsIDocShell.h" +#include "nsIMutableArray.h" #include "nsIScriptError.h" #include "nsISensitiveInfoHiddenURI.h" @@ -47,6 +48,12 @@ nsScriptErrorBase::nsScriptErrorBase() nsScriptErrorBase::~nsScriptErrorBase() {} void +nsScriptErrorBase::AddNote(nsIScriptErrorNote* note) +{ + mNotes.AppendObject(note); +} + +void nsScriptErrorBase::InitializeOnMainThread() { MOZ_ASSERT(NS_IsMainThread()); @@ -189,6 +196,28 @@ nsScriptErrorBase::Init(const nsAString& message, 0); } +static void +AssignSourceNameHelper(nsString& aSourceNameDest, const nsAString& aSourceNameSrc) +{ + if (aSourceNameSrc.IsEmpty()) + return; + + aSourceNameDest.Assign(aSourceNameSrc); + + nsCOMPtr<nsIURI> uri; + nsAutoCString pass; + if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), aSourceNameSrc)) && + NS_SUCCEEDED(uri->GetPassword(pass)) && + !pass.IsEmpty()) + { + nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = do_QueryInterface(uri); + + nsAutoCString loc; + if (safeUri && NS_SUCCEEDED(safeUri->GetSensitiveInfoHiddenSpec(loc))) + aSourceNameDest.Assign(NS_ConvertUTF8toUTF16(loc)); + } +} + NS_IMETHODIMP nsScriptErrorBase::InitWithWindowID(const nsAString& message, const nsAString& sourceName, @@ -200,26 +229,7 @@ nsScriptErrorBase::InitWithWindowID(const nsAString& message, uint64_t aInnerWindowID) { mMessage.Assign(message); - - if (!sourceName.IsEmpty()) { - mSourceName.Assign(sourceName); - - nsCOMPtr<nsIURI> uri; - nsAutoCString pass; - if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), sourceName)) && - NS_SUCCEEDED(uri->GetPassword(pass)) && - !pass.IsEmpty()) { - nsCOMPtr<nsISensitiveInfoHiddenURI> safeUri = - do_QueryInterface(uri); - - nsAutoCString loc; - if (safeUri && - NS_SUCCEEDED(safeUri->GetSensitiveInfoHiddenSpec(loc))) { - mSourceName.Assign(NS_ConvertUTF8toUTF16(loc)); - } - } - } - + AssignSourceNameHelper(mSourceName, sourceName); mLineNumber = lineNumber; mSourceLine.Assign(sourceLine); mColumnNumber = columnNumber; @@ -235,8 +245,11 @@ nsScriptErrorBase::InitWithWindowID(const nsAString& message, return NS_OK; } -NS_IMETHODIMP -nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult) +static nsresult +ToStringHelper(const char* aSeverity, const nsString& aMessage, + const nsString& aSourceName, const nsString* aSourceLine, + uint32_t aLineNumber, uint32_t aColumnNumber, + nsACString& /*UTF8*/ aResult) { static const char format0[] = "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]"; @@ -245,43 +258,39 @@ nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult) static const char format2[] = "[%s: \"%s\"]"; - static const char error[] = "JavaScript Error"; - static const char warning[] = "JavaScript Warning"; - - const char* severity = !(mFlags & JSREPORT_WARNING) ? error : warning; - char* temp; char* tempMessage = nullptr; char* tempSourceName = nullptr; char* tempSourceLine = nullptr; - if (!mMessage.IsEmpty()) - tempMessage = ToNewUTF8String(mMessage); - if (!mSourceName.IsEmpty()) + if (!aMessage.IsEmpty()) + tempMessage = ToNewUTF8String(aMessage); + if (!aSourceName.IsEmpty()) // Use at most 512 characters from mSourceName. - tempSourceName = ToNewUTF8String(StringHead(mSourceName, 512)); - if (!mSourceLine.IsEmpty()) + tempSourceName = ToNewUTF8String(StringHead(aSourceName, 512)); + if (aSourceLine && !aSourceLine->IsEmpty()) // Use at most 512 characters from mSourceLine. - tempSourceLine = ToNewUTF8String(StringHead(mSourceLine, 512)); + tempSourceLine = ToNewUTF8String(StringHead(*aSourceLine, 512)); - if (nullptr != tempSourceName && nullptr != tempSourceLine) + if (nullptr != tempSourceName && nullptr != tempSourceLine) { temp = JS_smprintf(format0, - severity, + aSeverity, tempMessage, tempSourceName, - mLineNumber, - mColumnNumber, + aLineNumber, + aColumnNumber, tempSourceLine); - else if (!mSourceName.IsEmpty()) + } else if (!aSourceName.IsEmpty()) { temp = JS_smprintf(format1, - severity, + aSeverity, tempMessage, tempSourceName, - mLineNumber); - else + aLineNumber); + } else { temp = JS_smprintf(format2, - severity, + aSeverity, tempMessage); + } if (nullptr != tempMessage) free(tempMessage); @@ -299,6 +308,18 @@ nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult) } NS_IMETHODIMP +nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult) +{ + static const char error[] = "JavaScript Error"; + static const char warning[] = "JavaScript Warning"; + + const char* severity = !(mFlags & JSREPORT_WARNING) ? error : warning; + + return ToStringHelper(severity, mMessage, mSourceName, &mSourceLine, + mLineNumber, mColumnNumber, aResult); +} + +NS_IMETHODIMP nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID) { NS_WARNING_ASSERTION(NS_IsMainThread() || mInitializedOnMainThread, @@ -342,4 +363,76 @@ nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow) return NS_OK; } +NS_IMETHODIMP +nsScriptErrorBase::GetNotes(nsIArray** aNotes) +{ + nsresult rv = NS_OK; + nsCOMPtr<nsIMutableArray> array = + do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t len = mNotes.Length(); + for (uint32_t i = 0; i < len; i++) + array->AppendElement(mNotes[i], false); + array.forget(aNotes); + + return NS_OK; +} + NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError) + +nsScriptErrorNote::nsScriptErrorNote() + : mMessage(), + mSourceName(), + mLineNumber(0), + mColumnNumber(0) +{ +} + +nsScriptErrorNote::~nsScriptErrorNote() {} + +void +nsScriptErrorNote::Init(const nsAString& message, + const nsAString& sourceName, + uint32_t lineNumber, + uint32_t columnNumber) +{ + mMessage.Assign(message); + AssignSourceNameHelper(mSourceName, sourceName); + mLineNumber = lineNumber; + mColumnNumber = columnNumber; +} + +// nsIScriptErrorNote methods +NS_IMETHODIMP +nsScriptErrorNote::GetErrorMessage(nsAString& aResult) { + aResult.Assign(mMessage); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::GetSourceName(nsAString& aResult) { + aResult.Assign(mSourceName); + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::GetLineNumber(uint32_t* result) { + *result = mLineNumber; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::GetColumnNumber(uint32_t* result) { + *result = mColumnNumber; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptErrorNote::ToString(nsACString& /*UTF8*/ aResult) +{ + return ToStringHelper("JavaScript Note", mMessage, mSourceName, nullptr, + mLineNumber, mColumnNumber, aResult); +} + +NS_IMPL_ISUPPORTS(nsScriptErrorNote, nsIScriptErrorNote) diff --git a/dom/bindings/nsScriptError.h b/dom/bindings/nsScriptError.h new file mode 100644 index 000000000..b8049d0a0 --- /dev/null +++ b/dom/bindings/nsScriptError.h @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 mozilla_dom_nsScriptError_h +#define mozilla_dom_nsScriptError_h + +#include "mozilla/Atomics.h" + +#include <stdint.h> + +#include "jsapi.h" +#include "js/RootingAPI.h" + +#include "nsIScriptError.h" +#include "nsString.h" + +class nsScriptErrorNote final : public nsIScriptErrorNote { + public: + nsScriptErrorNote(); + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSISCRIPTERRORNOTE + + void Init(const nsAString& message, const nsAString& sourceName, + uint32_t lineNumber, uint32_t columnNumber); + + private: + virtual ~nsScriptErrorNote(); + + nsString mMessage; + nsString mSourceName; + nsString mSourceLine; + uint32_t mLineNumber; + uint32_t mColumnNumber; +}; + +// Definition of nsScriptError.. +class nsScriptErrorBase : public nsIScriptError { +public: + nsScriptErrorBase(); + + NS_DECL_NSICONSOLEMESSAGE + NS_DECL_NSISCRIPTERROR + + void AddNote(nsIScriptErrorNote* note); + +protected: + virtual ~nsScriptErrorBase(); + + void + InitializeOnMainThread(); + + nsCOMArray<nsIScriptErrorNote> mNotes; + nsString mMessage; + nsString mMessageName; + nsString mSourceName; + uint32_t mLineNumber; + nsString mSourceLine; + uint32_t mColumnNumber; + uint32_t mFlags; + nsCString mCategory; + // mOuterWindowID is set on the main thread from InitializeOnMainThread(). + uint64_t mOuterWindowID; + uint64_t mInnerWindowID; + int64_t mTimeStamp; + // mInitializedOnMainThread and mIsFromPrivateWindow are set on the main + // thread from InitializeOnMainThread(). + mozilla::Atomic<bool> mInitializedOnMainThread; + bool mIsFromPrivateWindow; +}; + +class nsScriptError final : public nsScriptErrorBase { +public: + nsScriptError() {} + NS_DECL_THREADSAFE_ISUPPORTS + +private: + virtual ~nsScriptError() {} +}; + +class nsScriptErrorWithStack : public nsScriptErrorBase { +public: + explicit nsScriptErrorWithStack(JS::HandleObject); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsScriptErrorWithStack) + + NS_IMETHOD Init(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, + uint32_t columnNumber, + uint32_t flags, + const char* category) override; + + NS_IMETHOD GetStack(JS::MutableHandleValue) override; + NS_IMETHOD ToString(nsACString& aResult) override; + +private: + virtual ~nsScriptErrorWithStack(); + // Complete stackframe where the error happened. + // Must be SavedFrame object. + JS::Heap<JSObject*> mStack; +}; + +#endif /* mozilla_dom_nsScriptError_h */ diff --git a/js/xpconnect/src/nsScriptErrorWithStack.cpp b/dom/bindings/nsScriptErrorWithStack.cpp index 50407da23..74c00999f 100644 --- a/js/xpconnect/src/nsScriptErrorWithStack.cpp +++ b/dom/bindings/nsScriptErrorWithStack.cpp @@ -10,12 +10,14 @@ * that can store a SavedFrame stack trace object. */ -#include "xpcprivate.h" +#include "nsScriptError.h" #include "MainThreadUtils.h" #include "mozilla/Assertions.h" +#include "mozilla/dom/ScriptSettings.h" #include "nsGlobalWindow.h" #include "nsCycleCollectionParticipant.h" +using namespace mozilla::dom; namespace { diff --git a/dom/canvas/WebGLShader.cpp b/dom/canvas/WebGLShader.cpp index 37380f1e0..69ca03fc4 100644 --- a/dom/canvas/WebGLShader.cpp +++ b/dom/canvas/WebGLShader.cpp @@ -168,16 +168,6 @@ WebGLShader::ShaderSource(const nsAString& source) // 7-bit ASCII range, so we can skip the NS_IsAscii() check. const NS_LossyConvertUTF16toASCII sourceCString(cleanSource); - if (mContext->gl->WorkAroundDriverBugs()) { - const size_t maxSourceLength = 0x3ffff; - if (sourceCString.Length() > maxSourceLength) { - mContext->ErrorInvalidValue("shaderSource: Source has more than %d" - " characters. (Driver workaround)", - maxSourceLength); - return; - } - } - if (PR_GetEnv("MOZ_WEBGL_DUMP_SHADERS")) { printf_stderr("////////////////////////////////////////\n"); printf_stderr("// MOZ_WEBGL_DUMP_SHADERS:\n"); diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 6954e9757..b293c251b 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -172,7 +172,8 @@ bool MP4Decoder::IsH264(const nsACString& aMimeType) { return aMimeType.EqualsLiteral("video/mp4") || - aMimeType.EqualsLiteral("video/avc"); + aMimeType.EqualsLiteral("video/avc") || + aMimeType.EqualsLiteral("video/webm; codecs=avc1"); } /* static */ diff --git a/dom/media/mediasource/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp index 4ae37d7e9..b4dcfde8a 100644 --- a/dom/media/mediasource/ContainerParser.cpp +++ b/dom/media/mediasource/ContainerParser.cpp @@ -697,6 +697,9 @@ ContainerParser::CreateForMIMEType(const nsACString& aType) if (aType.LowerCaseEqualsLiteral("video/webm") || aType.LowerCaseEqualsLiteral("audio/webm")) { return new WebMContainerParser(aType); } + if (aType.LowerCaseEqualsLiteral("video/x-matroska") || aType.LowerCaseEqualsLiteral("audio/x-matroska")) { + return new WebMContainerParser(aType); + } #ifdef MOZ_FMP4 if (aType.LowerCaseEqualsLiteral("video/mp4") || aType.LowerCaseEqualsLiteral("audio/mp4")) { diff --git a/dom/media/mediasource/MediaSource.cpp b/dom/media/mediasource/MediaSource.cpp index 152c0085a..1c276cdc1 100644 --- a/dom/media/mediasource/MediaSource.cpp +++ b/dom/media/mediasource/MediaSource.cpp @@ -110,14 +110,16 @@ MediaSource::IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* a } return NS_OK; } - if (mimeType.EqualsASCII("video/webm")) { + if (mimeType.EqualsASCII("video/webm") || + mimeType.EqualsASCII("video/x-matroska")) { if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) || IsWebMForced(aDiagnostics))) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } return NS_OK; } - if (mimeType.EqualsASCII("audio/webm")) { + if (mimeType.EqualsASCII("audio/webm") || + mimeType.EqualsASCII("audio/x-matroska")) { if (!(Preferences::GetBool("media.mediasource.webm.enabled", false) || Preferences::GetBool("media.mediasource.webm.audio.enabled", true))) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index ac6d82411..21fb158b5 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -814,6 +814,8 @@ TrackBuffersManager::CreateDemuxerforMIMEType() ShutdownDemuxers(); if (mType.LowerCaseEqualsLiteral("video/webm") || + mType.LowerCaseEqualsLiteral("video/x-matroska") || + mType.LowerCaseEqualsLiteral("audio/x-matroska") || mType.LowerCaseEqualsLiteral("audio/webm")) { mInputDemuxer = new WebMDemuxer(mCurrentInputBuffer, true /* IsMediaSource*/ ); return; diff --git a/dom/media/webm/WebMDecoder.cpp b/dom/media/webm/WebMDecoder.cpp index 9575d6e42..cbe9ffdb7 100644 --- a/dom/media/webm/WebMDecoder.cpp +++ b/dom/media/webm/WebMDecoder.cpp @@ -42,7 +42,10 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, const bool isWebMAudio = aMIMETypeExcludingCodecs.EqualsASCII("audio/webm"); const bool isWebMVideo = aMIMETypeExcludingCodecs.EqualsASCII("video/webm"); - if (!isWebMAudio && !isWebMVideo) { + const bool isMatroskaAudio = aMIMETypeExcludingCodecs.EqualsASCII("audio/x-matroska") ; + const bool isMatroskaVideo = aMIMETypeExcludingCodecs.EqualsASCII("video/x-matroska") ; + + if (!isWebMAudio && !isWebMVideo && !isMatroskaAudio && !isMatroskaVideo) { return false; } @@ -63,7 +66,7 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, } // Note: Only accept VP8/VP9 in a video content type, not in an audio // content type. - if (isWebMVideo && + if ((isWebMVideo || isMatroskaVideo) && (codec.EqualsLiteral("vp8") || codec.EqualsLiteral("vp8.0") || codec.EqualsLiteral("vp9") || codec.EqualsLiteral("vp9.0"))) { @@ -74,6 +77,15 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, continue; } #endif + + if (IsH264CodecString(codec)) { + continue; + } + + if (IsAACCodecString(codec)) { + continue; + } + // Some unsupported codec. return false; } diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 013da9b2c..84b4b506e 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -326,6 +326,20 @@ WebMDemuxer::ReadMetadata() case NESTEGG_CODEC_AV1: mInfo.mVideo.mMimeType = "video/webm; codecs=av1"; break; + case NESTEGG_CODEC_AVC1: { + mInfo.mVideo.mMimeType = "video/webm; codecs=avc1"; + + unsigned char* data = 0; + size_t length = 0; + r = nestegg_track_codec_data(context, track, 0, &data, &length); + if (r == -1) { + return NS_ERROR_FAILURE; + } + + mInfo.mVideo.mExtraData = new MediaByteBuffer(length); + mInfo.mVideo.mExtraData->AppendElements(data, length); + break; + } default: NS_WARNING("Unknown WebM video codec"); return NS_ERROR_FAILURE; @@ -408,6 +422,8 @@ WebMDemuxer::ReadMetadata() mInfo.mAudio.mMimeType = "audio/opus"; OpusDataDecoder::AppendCodecDelay(mInfo.mAudio.mCodecSpecificConfig, media::TimeUnit::FromNanoseconds(params.codec_delay).ToMicroseconds()); + } else if (mAudioCodec == NESTEGG_CODEC_AAC) { + mInfo.mAudio.mMimeType = "audio/mp4a-latm"; } mSeekPreroll = params.seek_preroll; mInfo.mAudio.mRate = params.rate; @@ -662,6 +678,9 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl isKeyframe = AOMDecoder::IsKeyframe(sample); break; #endif + case NESTEGG_CODEC_AVC1: + isKeyframe = nestegg_packet_has_keyframe(holder->Packet()); + break; default: NS_WARNING("Cannot detect keyframes in unknown WebM video codec"); return NS_ERROR_FAILURE; @@ -682,7 +701,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl dimensions = AOMDecoder::GetFrameSize(sample); break; #endif - } + } if (mLastSeenFrameSize.isSome() && (dimensions != mLastSeenFrameSize.value())) { mInfo.mVideo.mDisplay = dimensions; @@ -749,6 +768,11 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl if (aType == TrackInfo::kVideoTrack) { sample->mTrackInfo = mSharedVideoTrackInfo; } + + if (mVideoCodec == NESTEGG_CODEC_AVC1) { + sample->mExtraData = mInfo.mVideo.mExtraData; + } + aSamples->Push(sample); } return NS_OK; diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 08fd9afd9..5c6701992 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -10,6 +10,7 @@ #include "nsIStreamListener.h" #include "nsCDefaultURIFixup.h" #include "nsIURIFixup.h" +#include "nsIImageLoadingContent.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/TabChild.h" @@ -123,7 +124,7 @@ nsContentSecurityManager::CheckFTPSubresourceLoad(nsIChannel* aChannel) nsCOMPtr<nsIURI> uri; nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_SUCCESS(rv, rv); if (!uri) { return NS_OK; } @@ -801,6 +802,8 @@ nsContentSecurityManager::CheckChannel(nsIChannel* aChannel) // within nsCorsListenerProxy rv = DoCheckLoadURIChecks(uri, loadInfo); NS_ENSURE_SUCCESS(rv, rv); + // TODO: Bug 1371237 + // consider calling SetBlockedRequest in nsContentSecurityManager::CheckChannel } return NS_OK; diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 21f6d8ddf..19c4ded2a 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -988,7 +988,7 @@ Wrap(JSContext *cx, JS::HandleObject existing, JS::HandleObject obj) } if (existing) { - js::Wrapper::Renew(cx, existing, obj, wrapper); + js::Wrapper::Renew(existing, obj, wrapper); } return js::Wrapper::New(cx, obj, wrapper); } diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 6bc5c4f96..27eb570e9 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -87,6 +87,7 @@ #include "nsProxyRelease.h" #include "nsQueryObject.h" #include "nsSandboxFlags.h" +#include "nsScriptError.h" #include "nsUTF8Utils.h" #include "prthread.h" #include "xpcpublic.h" @@ -281,27 +282,34 @@ struct WindowAction }; void -LogErrorToConsole(const nsAString& aMessage, - const nsAString& aFilename, - const nsAString& aLine, - uint32_t aLineNumber, - uint32_t aColumnNumber, - uint32_t aFlags, - uint64_t aInnerWindowId) +LogErrorToConsole(const WorkerErrorReport& aReport, uint64_t aInnerWindowId) { AssertIsOnMainThread(); - nsCOMPtr<nsIScriptError> scriptError = - do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); + RefPtr<nsScriptErrorBase> scriptError = new nsScriptError(); NS_WARNING_ASSERTION(scriptError, "Failed to create script error!"); if (scriptError) { - if (NS_FAILED(scriptError->InitWithWindowID(aMessage, aFilename, aLine, - aLineNumber, aColumnNumber, - aFlags, "Web Worker", + nsAutoCString category("Web Worker"); + if (NS_FAILED(scriptError->InitWithWindowID(aReport.mMessage, + aReport.mFilename, + aReport.mLine, + aReport.mLineNumber, + aReport.mColumnNumber, + aReport.mFlags, + category, aInnerWindowId))) { NS_WARNING("Failed to init script error!"); scriptError = nullptr; + + for (size_t i = 0, len = aReport.mNotes.Length(); i < len; i++) { + const WorkerErrorNote& note = aReport.mNotes.ElementAt(i); + + nsScriptErrorNote* noteObject = new nsScriptErrorNote(); + noteObject->Init(note.mMessage, note.mFilename, + note.mLineNumber, note.mColumnNumber); + scriptError->AddNote(noteObject); + } } } @@ -316,23 +324,23 @@ LogErrorToConsole(const nsAString& aMessage, } NS_WARNING("LogMessage failed!"); } else if (NS_SUCCEEDED(consoleService->LogStringMessage( - aMessage.BeginReading()))) { + aReport.mMessage.BeginReading()))) { return; } NS_WARNING("LogStringMessage failed!"); } - NS_ConvertUTF16toUTF8 msg(aMessage); - NS_ConvertUTF16toUTF8 filename(aFilename); + NS_ConvertUTF16toUTF8 msg(aReport.mMessage); + NS_ConvertUTF16toUTF8 filename(aReport.mFilename); static const char kErrorString[] = "JS error in Web Worker: %s [%s:%u]"; #ifdef ANDROID __android_log_print(ANDROID_LOG_INFO, "Gecko", kErrorString, msg.get(), - filename.get(), aLineNumber); + filename.get(), aReport.mLineNumber); #endif - fprintf(stderr, kErrorString, msg.get(), filename.get(), aLineNumber); + fprintf(stderr, kErrorString, msg.get(), filename.get(), aReport.mLineNumber); fflush(stderr); } @@ -536,10 +544,7 @@ private: } if (aWorkerPrivate->IsSharedWorker()) { - aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, EmptyString(), - EmptyString(), - EmptyString(), 0, 0, - JSREPORT_ERROR, + aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, nullptr, /* isErrorEvent */ false); return true; } @@ -1060,15 +1065,7 @@ private: class ReportErrorRunnable final : public WorkerRunnable { - nsString mMessage; - nsString mFilename; - nsString mLine; - uint32_t mLineNumber; - uint32_t mColumnNumber; - uint32_t mFlags; - uint32_t mErrorNumber; - JSExnType mExnType; - bool mMutedError; + WorkerErrorReport mReport; public: // aWorkerPrivate is the worker thread we're on (or the main thread, if null) @@ -1077,11 +1074,7 @@ public: static void ReportError(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aFireAtScope, WorkerPrivate* aTarget, - const nsString& aMessage, const nsString& aFilename, - const nsString& aLine, uint32_t aLineNumber, - uint32_t aColumnNumber, uint32_t aFlags, - uint32_t aErrorNumber, JSExnType aExnType, - bool aMutedError, uint64_t aInnerWindowId, + const WorkerErrorReport& aReport, uint64_t aInnerWindowId, JS::Handle<JS::Value> aException = JS::NullHandleValue) { if (aWorkerPrivate) { @@ -1092,16 +1085,16 @@ public: // We should not fire error events for warnings but instead make sure that // they show up in the error console. - if (!JSREPORT_IS_WARNING(aFlags)) { + if (!JSREPORT_IS_WARNING(aReport.mFlags)) { // First fire an ErrorEvent at the worker. RootedDictionary<ErrorEventInit> init(aCx); - if (aMutedError) { + if (aReport.mMutedError) { init.mMessage.AssignLiteral("Script error."); } else { - init.mMessage = aMessage; - init.mFilename = aFilename; - init.mLineno = aLineNumber; + init.mMessage = aReport.mMessage; + init.mFilename = aReport.mFilename; + init.mLineno = aReport.mLineNumber; init.mError = aException; } @@ -1128,7 +1121,8 @@ public: // into an error event on our parent worker! // https://bugzilla.mozilla.org/show_bug.cgi?id=1271441 tracks making this // better. - if (aFireAtScope && (aTarget || aErrorNumber != JSMSG_OVER_RECURSED)) { + if (aFireAtScope && + (aTarget || aReport.mErrorNumber != JSMSG_OVER_RECURSED)) { JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx)); NS_ASSERTION(global, "This should never be null!"); @@ -1145,8 +1139,8 @@ public: MOZ_ASSERT_IF(globalScope, globalScope->GetWrapperPreserveColor() == global); if (globalScope || IsDebuggerSandbox(global)) { - aWorkerPrivate->ReportErrorToDebugger(aFilename, aLineNumber, - aMessage); + aWorkerPrivate->ReportErrorToDebugger(aReport.mFilename, aReport.mLineNumber, + aReport.mMessage); return; } @@ -1193,28 +1187,20 @@ public: // Now fire a runnable to do the same on the parent's thread if we can. if (aWorkerPrivate) { RefPtr<ReportErrorRunnable> runnable = - new ReportErrorRunnable(aWorkerPrivate, aMessage, aFilename, aLine, - aLineNumber, aColumnNumber, aFlags, - aErrorNumber, aExnType, aMutedError); + new ReportErrorRunnable(aWorkerPrivate, aReport); runnable->Dispatch(); return; } // Otherwise log an error to the error console. - LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber, - aFlags, aInnerWindowId); + LogErrorToConsole(aReport, aInnerWindowId); } private: - ReportErrorRunnable(WorkerPrivate* aWorkerPrivate, const nsString& aMessage, - const nsString& aFilename, const nsString& aLine, - uint32_t aLineNumber, uint32_t aColumnNumber, - uint32_t aFlags, uint32_t aErrorNumber, - JSExnType aExnType, bool aMutedError) + ReportErrorRunnable(WorkerPrivate* aWorkerPrivate, + const WorkerErrorReport& aReport) : WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount), - mMessage(aMessage), mFilename(aFilename), mLine(aLine), - mLineNumber(aLineNumber), mColumnNumber(aColumnNumber), mFlags(aFlags), - mErrorNumber(aErrorNumber), mExnType(aExnType), mMutedError(aMutedError) + mReport(aReport) { } virtual void @@ -1251,9 +1237,7 @@ private: } if (aWorkerPrivate->IsSharedWorker()) { - aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, mMessage, mFilename, - mLine, mLineNumber, - mColumnNumber, mFlags, + aWorkerPrivate->BroadcastErrorToSharedWorkers(aCx, &mReport, /* isErrorEvent */ true); return true; } @@ -1267,9 +1251,10 @@ private: swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(), aWorkerPrivate->WorkerName(), aWorkerPrivate->ScriptURL(), - mMessage, - mFilename, mLine, mLineNumber, - mColumnNumber, mFlags, mExnType); + mReport.mMessage, + mReport.mFilename, mReport.mLine, mReport.mLineNumber, + mReport.mColumnNumber, mReport.mFlags, + mReport.mExnType); } return true; } @@ -1289,9 +1274,8 @@ private: return true; } - ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mMessage, - mFilename, mLine, mLineNumber, mColumnNumber, mFlags, - mErrorNumber, mExnType, mMutedError, innerWindowId); + ReportError(aCx, parent, fireAtScope, aWorkerPrivate, mReport, + innerWindowId); return true; } }; @@ -3314,21 +3298,16 @@ template <class Derived> void WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers( JSContext* aCx, - const nsAString& aMessage, - const nsAString& aFilename, - const nsAString& aLine, - uint32_t aLineNumber, - uint32_t aColumnNumber, - uint32_t aFlags, + const WorkerErrorReport* aReport, bool aIsErrorEvent) { AssertIsOnMainThread(); - if (JSREPORT_IS_WARNING(aFlags)) { + if (aIsErrorEvent && JSREPORT_IS_WARNING(aReport->mFlags)) { // Don't fire any events anywhere. Just log to console. // XXXbz should we log to all the consoles of all the relevant windows? - LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber, - aFlags, 0); + MOZ_ASSERT(aReport); + LogErrorToConsole(*aReport, 0); return; } @@ -3357,10 +3336,10 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers( RootedDictionary<ErrorEventInit> errorInit(aCx); errorInit.mBubbles = false; errorInit.mCancelable = true; - errorInit.mMessage = aMessage; - errorInit.mFilename = aFilename; - errorInit.mLineno = aLineNumber; - errorInit.mColno = aColumnNumber; + errorInit.mMessage = aReport->mMessage; + errorInit.mFilename = aReport->mFilename; + errorInit.mLineno = aReport->mLineNumber; + errorInit.mColno = aReport->mColumnNumber; event = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"), errorInit); @@ -3426,9 +3405,9 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers( MOZ_ASSERT(NS_IsMainThread()); RootedDictionary<ErrorEventInit> init(aCx); - init.mLineno = aLineNumber; - init.mFilename = aFilename; - init.mMessage = aMessage; + init.mLineno = aReport->mLineNumber; + init.mFilename = aReport->mFilename; + init.mMessage = aReport->mMessage; init.mCancelable = true; init.mBubbles = true; @@ -3446,8 +3425,8 @@ WorkerPrivateParent<Derived>::BroadcastErrorToSharedWorkers( // Finally log a warning in the console if no window tried to prevent it. if (shouldLogErrorToConsole) { - LogErrorToConsole(aMessage, aFilename, aLine, aLineNumber, aColumnNumber, - aFlags, 0); + MOZ_ASSERT(aReport); + LogErrorToConsole(*aReport, 0); } } @@ -4120,7 +4099,10 @@ WorkerDebugger::ReportErrorToDebuggerOnMainThread(const nsAString& aFilename, listeners[index]->OnError(aFilename, aLineno, aMessage); } - LogErrorToConsole(aMessage, aFilename, nsString(), aLineno, 0, 0, 0); + WorkerErrorReport report; + report.mMessage = aMessage; + report.mFilename = aFilename; + LogErrorToConsole(report, 0); } WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent, @@ -5926,6 +5908,47 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus) } void +WorkerErrorBase::AssignErrorBase(JSErrorBase* aReport) +{ + mFilename = NS_ConvertUTF8toUTF16(aReport->filename); + mLineNumber = aReport->lineno; + mColumnNumber = aReport->column; + mErrorNumber = aReport->errorNumber; +} + +void +WorkerErrorNote::AssignErrorNote(JSErrorNotes::Note* aNote) +{ + WorkerErrorBase::AssignErrorBase(aNote); + xpc::ErrorNote::ErrorNoteToMessageString(aNote, mMessage); +} + +void +WorkerErrorReport::AssignErrorReport(JSErrorReport* aReport) +{ + WorkerErrorBase::AssignErrorBase(aReport); + xpc::ErrorReport::ErrorReportToMessageString(aReport, mMessage); + + mLine.Assign(aReport->linebuf(), aReport->linebufLength()); + mFlags = aReport->flags; + MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT); + mExnType = JSExnType(aReport->exnType); + mMutedError = aReport->isMuted; + + if (aReport->notes) { + if (!mNotes.SetLength(aReport->notes->length(), fallible)) { + return; + } + + size_t i = 0; + for (auto&& note : *aReport->notes) { + mNotes.ElementAt(i).AssignErrorNote(note.get()); + i++; + } + } +} + +void WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, JSErrorReport* aReport) { @@ -5947,32 +5970,17 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, } JS_ClearPendingException(aCx); - nsString message, filename, line; - uint32_t lineNumber, columnNumber, flags, errorNumber; - JSExnType exnType = JSEXN_ERR; - bool mutedError = aReport && aReport->isMuted; - + WorkerErrorReport report; if (aReport) { - // We want the same behavior here as xpc::ErrorReport::init here. - xpc::ErrorReport::ErrorReportToMessageString(aReport, message); - - filename = NS_ConvertUTF8toUTF16(aReport->filename); - line.Assign(aReport->linebuf(), aReport->linebufLength()); - lineNumber = aReport->lineno; - columnNumber = aReport->tokenOffset(); - flags = aReport->flags; - errorNumber = aReport->errorNumber; - MOZ_ASSERT(aReport->exnType >= JSEXN_FIRST && aReport->exnType < JSEXN_LIMIT); - exnType = JSExnType(aReport->exnType); + report.AssignErrorReport(aReport); } else { - lineNumber = columnNumber = errorNumber = 0; - flags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag; + report.mFlags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag; } - if (message.IsEmpty() && aToStringResult) { + if (report.mMessage.IsEmpty() && aToStringResult) { nsDependentCString toStringResult(aToStringResult.c_str()); - if (!AppendUTF8toUTF16(toStringResult, message, mozilla::fallible)) { + if (!AppendUTF8toUTF16(toStringResult, report.mMessage, mozilla::fallible)) { // Try again, with only a 1 KB string. Do this infallibly this time. // If the user doesn't have 1 KB to spare we're done anyways. uint32_t index = std::min(uint32_t(1024), toStringResult.Length()); @@ -5982,7 +5990,7 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, nsDependentCString truncatedToStringResult(aToStringResult.c_str(), index); - AppendUTF8toUTF16(truncatedToStringResult, message); + AppendUTF8toUTF16(truncatedToStringResult, report.mMessage); } } @@ -5991,13 +5999,11 @@ WorkerPrivate::ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, // Don't want to run the scope's error handler if this is a recursive error or // if we ran out of memory. bool fireAtScope = mErrorHandlerRecursionCount == 1 && - errorNumber != JSMSG_OUT_OF_MEMORY && + report.mErrorNumber != JSMSG_OUT_OF_MEMORY && JS::CurrentGlobalOrNull(aCx); - ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, message, - filename, line, lineNumber, - columnNumber, flags, errorNumber, exnType, - mutedError, 0, exn); + ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, report, 0, + exn); mErrorHandlerRecursionCount--; } diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 20a530205..885abccd5 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -140,6 +140,45 @@ public: } }; +class WorkerErrorBase { +public: + nsString mMessage; + nsString mFilename; + uint32_t mLineNumber; + uint32_t mColumnNumber; + uint32_t mErrorNumber; + + WorkerErrorBase() + : mLineNumber(0), + mColumnNumber(0), + mErrorNumber(0) + { } + + void AssignErrorBase(JSErrorBase* aReport); +}; + +class WorkerErrorNote : public WorkerErrorBase { +public: + void AssignErrorNote(JSErrorNotes::Note* aNote); +}; + +class WorkerErrorReport : public WorkerErrorBase { +public: + nsString mLine; + uint32_t mFlags; + JSExnType mExnType; + bool mMutedError; + nsTArray<WorkerErrorNote> mNotes; + + WorkerErrorReport() + : mFlags(0), + mExnType(JSEXN_ERR), + mMutedError(false) + { } + + void AssignErrorReport(JSErrorReport* aReport); +}; + template <class Derived> class WorkerPrivateParent : public DOMEventTargetHelper { @@ -401,12 +440,7 @@ public: void BroadcastErrorToSharedWorkers(JSContext* aCx, - const nsAString& aMessage, - const nsAString& aFilename, - const nsAString& aLine, - uint32_t aLineNumber, - uint32_t aColumnNumber, - uint32_t aFlags, + const WorkerErrorReport* aReport, bool aIsErrorEvent); void diff --git a/dom/workers/moz.build b/dom/workers/moz.build index 4f4b52e4a..9fea84193 100644 --- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -94,6 +94,7 @@ LOCAL_INCLUDES += [ '../base', '../system', '/dom/base', + '/dom/bindings', '/xpcom/build', '/xpcom/threads', ] diff --git a/dom/workers/test/test_sharedWorker.html b/dom/workers/test/test_sharedWorker.html index 3d3d4e2c6..c00c4e586 100644 --- a/dom/workers/test/test_sharedWorker.html +++ b/dom/workers/test/test_sharedWorker.html @@ -23,7 +23,7 @@ const errorFilename = href.substring(0, href.lastIndexOf("/") + 1) + filename; const errorLine = 91; - const errorColumn = 0; + const errorColumn = 11; var worker = new SharedWorker(filename); diff --git a/gfx/gl/GLUploadHelpers.cpp b/gfx/gl/GLUploadHelpers.cpp index 75165eedf..0bbb61434 100644 --- a/gfx/gl/GLUploadHelpers.cpp +++ b/gfx/gl/GLUploadHelpers.cpp @@ -161,7 +161,22 @@ TexSubImage2DWithoutUnpackSubimage(GLContext* gl, // isn't supported. We make a copy of the texture data we're using, // such that we're using the whole row of data in the copy. This turns // out to be more efficient than uploading row-by-row; see bug 698197. - unsigned char* newPixels = new (fallible) unsigned char[width*height*pixelsize]; + + // Width and height are never more than 16384. At 16Ki*16Ki, 4Bpp is 1GiB, but + // if we allow 8Bpp (16-bit channels, or higher) here, that's 2GiB+, which would + // overflow on 32-bit. + MOZ_ASSERT(width <= 16384); + MOZ_ASSERT(height <= 16384); + MOZ_ASSERT(pixelsize < 8); + + const auto size = CheckedInt<size_t>(width) * height * pixelsize; + if (!size.isValid()) { + // This should never happen, but we use a defensive check. + MOZ_ASSERT_UNREACHABLE("Unacceptable size calculated.!"); + return; + } + + unsigned char* newPixels = new (fallible) unsigned char[size.value()]; if (newPixels) { unsigned char* rowDest = newPixels; @@ -286,7 +301,22 @@ TexImage2DHelper(GLContext* gl, GLsizei paddedWidth = RoundUpPow2((uint32_t)width); GLsizei paddedHeight = RoundUpPow2((uint32_t)height); - GLvoid* paddedPixels = new unsigned char[paddedWidth * paddedHeight * pixelsize]; + // Width and height are never more than 16384. At 16Ki*16Ki, 4Bpp + // is 1GiB, but if we allow 8Bpp (or higher) here, that's 2GiB, + // which would overflow on 32-bit. + MOZ_ASSERT(width <= 16384); + MOZ_ASSERT(height <= 16384); + MOZ_ASSERT(pixelsize < 8); + + const auto size = + CheckedInt<size_t>(paddedWidth) * paddedHeight * pixelsize; + if (!size.isValid()) { + // This should never happen, but we use a defensive check. + MOZ_ASSERT_UNREACHABLE("Unacceptable size calculated.!"); + return; + } + + GLvoid* paddedPixels = new unsigned char[size.value()]; // Pad out texture data to be in a POT sized buffer for uploading to // a POT sized texture @@ -465,13 +495,17 @@ UploadImageDataToTexture(GLContext* gl, surfaceFormat = SurfaceFormat::A8; break; default: - NS_ASSERTION(false, "Unhandled image surface format!"); + MOZ_ASSERT_UNREACHABLE("Unhandled image surface format!"); } if (aOutUploadSize) { *aOutUploadSize = 0; } + if (surfaceFormat == gfx::SurfaceFormat::UNKNOWN) { + return gfx::SurfaceFormat::UNKNOWN; + } + if (aNeedInit || !CanUploadSubTextures(gl)) { // If the texture needs initialized, or we are unable to // upload sub textures, then initialize and upload the entire diff --git a/gfx/thebes/gfxMatrix.h b/gfx/thebes/gfxMatrix.h index 9282a22db..4f92262cc 100644 --- a/gfx/thebes/gfxMatrix.h +++ b/gfx/thebes/gfxMatrix.h @@ -112,6 +112,18 @@ public: _31 == 0.0 && _32 == 0.0; } + /* Returns true if the matrix is a rectilinear transformation (i.e. + * grid-aligned rectangles are transformed to grid-aligned rectangles) + */ + bool IsRectilinear() const { + if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) { + return true; + } else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) { + return true; + } + return false; + } + /** * Inverts this matrix, if possible. Otherwise, the matrix is left * unchanged. diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index f7fb657bd..996ca01cf 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -1684,6 +1684,7 @@ imgLoader::ValidateRequestWithNewChannel(imgRequest* request, rv = newChannel->AsyncOpen2(listener); if (NS_WARN_IF(NS_FAILED(rv))) { + req->CancelAndForgetObserver(rv); return false; } diff --git a/js/ipc/JavaScriptParent.cpp b/js/ipc/JavaScriptParent.cpp index 6cf9e0591..aafd7f565 100644 --- a/js/ipc/JavaScriptParent.cpp +++ b/js/ipc/JavaScriptParent.cpp @@ -9,6 +9,7 @@ #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ScriptSettings.h" #include "nsJSUtils.h" +#include "nsIScriptError.h" #include "jsfriendapi.h" #include "jswrapper.h" #include "js/Proxy.h" diff --git a/js/public/CallArgs.h b/js/public/CallArgs.h index a7774309a..aae7121ad 100644 --- a/js/public/CallArgs.h +++ b/js/public/CallArgs.h @@ -128,7 +128,10 @@ class MOZ_STACK_CLASS CallArgsBase : public WantUsedRval protected: Value* argv_; unsigned argc_; - bool constructing_; + bool constructing_:1; + + // True if the caller does not use the return value. + bool ignoresReturnValue_:1; public: // CALLEE ACCESS @@ -164,6 +167,10 @@ class MOZ_STACK_CLASS CallArgsBase : public WantUsedRval return true; } + bool ignoresReturnValue() const { + return ignoresReturnValue_; + } + MutableHandleValue newTarget() const { MOZ_ASSERT(constructing_); return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]); @@ -280,14 +287,17 @@ class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsed { private: friend CallArgs CallArgsFromVp(unsigned argc, Value* vp); - friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing); + friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing, + bool ignoresReturnValue); - static CallArgs create(unsigned argc, Value* argv, bool constructing) { + static CallArgs create(unsigned argc, Value* argv, bool constructing, + bool ignoresReturnValue = false) { CallArgs args; args.clearUsedRval(); args.argv_ = argv; args.argc_ = argc; args.constructing_ = constructing; + args.ignoresReturnValue_ = ignoresReturnValue; #ifdef DEBUG for (unsigned i = 0; i < argc; ++i) MOZ_ASSERT_IF(argv[i].isGCThing(), !GCThingIsMarkedGray(GCCellPtr(argv[i]))); @@ -314,9 +324,11 @@ CallArgsFromVp(unsigned argc, Value* vp) // eventually move it to an internal header. Embedders should use // JS::CallArgsFromVp! MOZ_ALWAYS_INLINE CallArgs -CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false) +CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false, + bool ignoresReturnValue = false) { - return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing); + return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing, + ignoresReturnValue); } } // namespace JS diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index 3de3f5f4c..ceee83349 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -1117,7 +1117,7 @@ JSObject* AtomicsObject::initClass(JSContext* cx, Handle<GlobalObject*> global) { // Create Atomics Object. - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return nullptr; RootedObject Atomics(cx, NewObjectWithGivenProto(cx, &AtomicsObject::class_, objProto, diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 71f7b58d4..0cd0c62dd 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -270,7 +270,7 @@ Collator(JSContext* cx, const CallArgs& args, bool construct) // See https://github.com/tc39/ecma402/issues/57 if (!construct) { // ES Intl 1st ed., 10.1.2.1 step 3 - JSObject* intl = cx->global()->getOrCreateIntlObject(cx); + JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global()); if (!intl) return false; RootedValue self(cx, args.thisv()); @@ -298,7 +298,7 @@ Collator(JSContext* cx, const CallArgs& args, bool construct) return false; if (!proto) { - proto = cx->global()->getOrCreateCollatorPrototype(cx); + proto = GlobalObject::getOrCreateCollatorPrototype(cx, cx->global()); if (!proto) return false; } @@ -358,11 +358,12 @@ collator_finalize(FreeOp* fop, JSObject* obj) static JSObject* CreateCollatorPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global) { - RootedFunction ctor(cx, global->createConstructor(cx, &Collator, cx->names().Collator, 0)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, &Collator, cx->names().Collator, + 0)); if (!ctor) return nullptr; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &CollatorClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, &CollatorClass)); if (!proto) return nullptr; proto->setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr)); @@ -772,7 +773,7 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct) // See https://github.com/tc39/ecma402/issues/57 if (!construct) { // ES Intl 1st ed., 11.1.2.1 step 3 - JSObject* intl = cx->global()->getOrCreateIntlObject(cx); + JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global()); if (!intl) return false; RootedValue self(cx, args.thisv()); @@ -800,7 +801,7 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct) return false; if (!proto) { - proto = cx->global()->getOrCreateNumberFormatPrototype(cx); + proto = GlobalObject::getOrCreateNumberFormatPrototype(cx, cx->global()); if (!proto) return false; } @@ -862,11 +863,12 @@ static JSObject* CreateNumberFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global) { RootedFunction ctor(cx); - ctor = global->createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0); + ctor = GlobalObject::createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0); if (!ctor) return nullptr; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &NumberFormatClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, + &NumberFormatClass)); if (!proto) return nullptr; proto->setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr)); @@ -1250,7 +1252,7 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct) // See https://github.com/tc39/ecma402/issues/57 if (!construct) { // ES Intl 1st ed., 12.1.2.1 step 3 - JSObject* intl = cx->global()->getOrCreateIntlObject(cx); + JSObject* intl = GlobalObject::getOrCreateIntlObject(cx, cx->global()); if (!intl) return false; RootedValue self(cx, args.thisv()); @@ -1278,7 +1280,7 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct) return false; if (!proto) { - proto = cx->global()->getOrCreateDateTimeFormatPrototype(cx); + proto = GlobalObject::getOrCreateDateTimeFormatPrototype(cx, cx->global()); if (!proto) return false; } @@ -1340,11 +1342,12 @@ static JSObject* CreateDateTimeFormatPrototype(JSContext* cx, HandleObject Intl, Handle<GlobalObject*> global) { RootedFunction ctor(cx); - ctor = global->createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0); + ctor = GlobalObject::createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0); if (!ctor) return nullptr; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &DateTimeFormatClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, + &DateTimeFormatClass)); if (!proto) return nullptr; proto->setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr)); @@ -2731,10 +2734,10 @@ static const JSFunctionSpec intl_static_methods[] = { * Initializes the Intl Object and its standard built-in properties. * Spec: ECMAScript Internationalization API Specification, 8.0, 8.1 */ -bool +/* static */ bool GlobalObject::initIntlObject(JSContext* cx, Handle<GlobalObject*> global) { - RootedObject proto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return false; diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index c496cfb77..34e2e566d 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -164,7 +164,7 @@ MapIteratorObject::kind() const return MapObject::IteratorKind(i); } -bool +/* static */ bool GlobalObject::initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global) { Rooted<JSObject*> base(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global)); @@ -924,7 +924,7 @@ SetIteratorObject::kind() const return SetObject::IteratorKind(i); } -bool +/* static */ bool GlobalObject::initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global) { Rooted<JSObject*> base(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global)); diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index c6bd2d300..798ef46e1 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -103,7 +103,7 @@ GlobalObject::initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global) JS_PS_END }; - RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global)); if (!proto) return false; @@ -169,7 +169,7 @@ GlobalObject::initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global) JS_PS_END }; - RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global)); if (!proto) return false; @@ -788,7 +788,7 @@ AssertModuleScopesMatch(ModuleObject* module) } void -ModuleObject::fixEnvironmentsAfterCompartmentMerge(JSContext* cx) +ModuleObject::fixEnvironmentsAfterCompartmentMerge() { AssertModuleScopesMatch(this); initialEnvironment().fixEnclosingEnvironmentAfterCompartmentMerge(script()->global()); @@ -1020,7 +1020,7 @@ GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global) JS_FS_END }; - RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global)); if (!proto) return false; diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index d0ed8ed08..e83520ebe 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -244,7 +244,7 @@ class ModuleObject : public NativeObject #ifdef DEBUG static bool IsFrozen(JSContext* cx, HandleModuleObject self); #endif - void fixEnvironmentsAfterCompartmentMerge(JSContext* cx); + void fixEnvironmentsAfterCompartmentMerge(); JSScript* script() const; Scope* enclosingScope() const; diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 389bb57db..56c77f304 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -525,18 +525,6 @@ js::obj_toString(JSContext* cx, unsigned argc, Value* vp) return true; } - -bool -js::obj_valueOf(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - RootedObject obj(cx, ToObject(cx, args.thisv())); - if (!obj) - return false; - args.rval().setObject(*obj); - return true; -} - static bool obj_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp) { @@ -1301,7 +1289,7 @@ static const JSFunctionSpec object_methods[] = { #endif JS_FN(js_toString_str, obj_toString, 0,0), JS_SELF_HOSTED_FN(js_toLocaleString_str, "Object_toLocaleString", 0, 0), - JS_FN(js_valueOf_str, obj_valueOf, 0,0), + JS_SELF_HOSTED_FN(js_valueOf_str, "Object_valueOf", 0,0), #if JS_HAS_OBJ_WATCHPOINT JS_FN(js_watch_str, obj_watch, 2,0), JS_FN(js_unwatch_str, obj_unwatch, 1,0), @@ -1420,8 +1408,8 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro * only set the [[Prototype]] if it hasn't already been set. */ Rooted<TaggedProto> tagged(cx, TaggedProto(proto)); - if (global->shouldSplicePrototype(cx)) { - if (!global->splicePrototype(cx, global->getClass(), tagged)) + if (global->shouldSplicePrototype()) { + if (!JSObject::splicePrototype(cx, global, global->getClass(), tagged)) return false; } return true; diff --git a/js/src/builtin/Object.h b/js/src/builtin/Object.h index 09512be36..8231888b1 100644 --- a/js/src/builtin/Object.h +++ b/js/src/builtin/Object.h @@ -25,9 +25,6 @@ obj_construct(JSContext* cx, unsigned argc, JS::Value* vp); MOZ_MUST_USE bool obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp); -MOZ_MUST_USE bool -obj_valueOf(JSContext* cx, unsigned argc, JS::Value* vp); - PlainObject* ObjectCreateImpl(JSContext* cx, HandleObject proto, NewObjectKind newKind = GenericObject, HandleObjectGroup group = nullptr); diff --git a/js/src/builtin/Object.js b/js/src/builtin/Object.js index a7440aec7..9ed1be0e1 100644 --- a/js/src/builtin/Object.js +++ b/js/src/builtin/Object.js @@ -87,6 +87,12 @@ function Object_toLocaleString() { return callContentFunction(O.toString, O); } +// ES 2017 draft bb96899bb0d9ef9be08164a26efae2ee5f25e875 19.1.3.7 +function Object_valueOf() { + // Step 1. + return ToObject(this); +} + // ES7 draft (2016 March 8) B.2.2.3 function ObjectDefineSetter(name, setter) { // Step 1. diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index c781a336d..ec7845e89 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -603,7 +603,7 @@ ResolvePromise(JSContext* cx, Handle<PromiseObject*> promise, HandleValue valueO // Now that everything else is done, do the things the debugger needs. // Step 7 of RejectPromise implemented in onSettled. - promise->onSettled(cx); + PromiseObject::onSettled(cx, promise); // Step 7 of FulfillPromise. // Step 8 of RejectPromise. @@ -1947,26 +1947,23 @@ PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C, } // ES2016, Sub-steps of 25.4.4.4 and 25.4.4.5. -static MOZ_MUST_USE bool -CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, ResolutionMode mode) +static MOZ_MUST_USE JSObject* +CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue argVal, + ResolutionMode mode) { - CallArgs args = CallArgsFromVp(argc, vp); - RootedValue x(cx, args.get(0)); - // Steps 1-2. - if (!args.thisv().isObject()) { + if (!thisVal.isObject()) { const char* msg = mode == ResolveMode ? "Receiver of Promise.resolve call" : "Receiver of Promise.reject call"; JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, msg); - return false; + return nullptr; } - RootedValue cVal(cx, args.thisv()); - RootedObject C(cx, &cVal.toObject()); + RootedObject C(cx, &thisVal.toObject()); // Step 3 of Resolve. - if (mode == ResolveMode && x.isObject()) { - RootedObject xObj(cx, &x.toObject()); + if (mode == ResolveMode && argVal.isObject()) { + RootedObject xObj(cx, &argVal.toObject()); bool isPromise = false; if (xObj->is<PromiseObject>()) { isPromise = true; @@ -1985,11 +1982,9 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio if (isPromise) { RootedValue ctorVal(cx); if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal)) - return false; - if (ctorVal == cVal) { - args.rval().set(x); - return true; - } + return nullptr; + if (ctorVal == thisVal) + return xObj; } } @@ -1998,15 +1993,17 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio RootedObject resolveFun(cx); RootedObject rejectFun(cx); if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun, true)) - return false; + return nullptr; // Step 5 of Resolve, 4 of Reject. - if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, x, mode, promise)) - return false; + if (!RunResolutionFunction(cx, mode == ResolveMode ? resolveFun : rejectFun, argVal, mode, + promise)) + { + return nullptr; + } // Step 6 of Resolve, 4 of Reject. - args.rval().setObject(*promise); - return true; + return promise; } /** @@ -2015,7 +2012,14 @@ CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, Resolutio bool js::Promise_reject(JSContext* cx, unsigned argc, Value* vp) { - return CommonStaticResolveRejectImpl(cx, argc, vp, RejectMode); + CallArgs args = CallArgsFromVp(argc, vp); + RootedValue thisVal(cx, args.thisv()); + RootedValue argVal(cx, args.get(0)); + JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, RejectMode); + if (!result) + return false; + args.rval().setObject(*result); + return true; } /** @@ -2024,19 +2028,11 @@ js::Promise_reject(JSContext* cx, unsigned argc, Value* vp) /* static */ JSObject* PromiseObject::unforgeableReject(JSContext* cx, HandleValue value) { - // Steps 1-2 (omitted). - - // Roughly step 3. - Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx)); - if (!promise) + RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx)); + if (!promiseCtor) return nullptr; - - // Roughly step 4. - if (!ResolvePromise(cx, promise, value, JS::PromiseState::Rejected)) - return nullptr; - - // Step 5. - return promise; + RootedValue cVal(cx, ObjectValue(*promiseCtor)); + return CommonStaticResolveRejectImpl(cx, cVal, value, RejectMode); } /** @@ -2045,7 +2041,14 @@ PromiseObject::unforgeableReject(JSContext* cx, HandleValue value) bool js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp) { - return CommonStaticResolveRejectImpl(cx, argc, vp, ResolveMode); + CallArgs args = CallArgsFromVp(argc, vp); + RootedValue thisVal(cx, args.thisv()); + RootedValue argVal(cx, args.get(0)); + JSObject* result = CommonStaticResolveRejectImpl(cx, thisVal, argVal, ResolveMode); + if (!result) + return false; + args.rval().setObject(*result); + return true; } /** @@ -2054,30 +2057,11 @@ js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp) /* static */ JSObject* PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value) { - // Steps 1-2 (omitted). - - // Step 3. - if (value.isObject()) { - JSObject* obj = &value.toObject(); - if (IsWrapper(obj)) - obj = CheckedUnwrap(obj); - // Instead of getting the `constructor` property, do an unforgeable - // check. - if (obj && obj->is<PromiseObject>()) - return obj; - } - - // Step 4. - Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx)); - if (!promise) + RootedObject promiseCtor(cx, JS::GetPromiseConstructor(cx)); + if (!promiseCtor) return nullptr; - - // Steps 5. - if (!ResolvePromiseInternal(cx, promise, value)) - return nullptr; - - // Step 6. - return promise; + RootedValue cVal(cx, ObjectValue(*promiseCtor)); + return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode); } // ES2016, 25.4.4.6, implemented in Promise.js. @@ -2647,14 +2631,14 @@ PromiseObject::dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> v return true; } -bool -PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue) +/* static */ bool +PromiseObject::resolve(JSContext* cx, Handle<PromiseObject*> promise, HandleValue resolutionValue) { - MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_ASYNC)); - if (state() != JS::PromiseState::Pending) + MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC)); + if (promise->state() != JS::PromiseState::Pending) return true; - RootedObject resolveFun(cx, GetResolveFunctionFromPromise(this)); + RootedObject resolveFun(cx, GetResolveFunctionFromPromise(promise)); RootedValue funVal(cx, ObjectValue(*resolveFun)); // For xray'd Promises, the resolve fun may have been created in another @@ -2670,14 +2654,14 @@ PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue) return Call(cx, funVal, UndefinedHandleValue, args, &dummy); } -bool -PromiseObject::reject(JSContext* cx, HandleValue rejectionValue) +/* static */ bool +PromiseObject::reject(JSContext* cx, Handle<PromiseObject*> promise, HandleValue rejectionValue) { - MOZ_ASSERT(!PromiseHasAnyFlag(*this, PROMISE_FLAG_ASYNC)); - if (state() != JS::PromiseState::Pending) + MOZ_ASSERT(!PromiseHasAnyFlag(*promise, PROMISE_FLAG_ASYNC)); + if (promise->state() != JS::PromiseState::Pending) return true; - RootedValue funVal(cx, this->getFixedSlot(PromiseSlot_RejectFunction)); + RootedValue funVal(cx, promise->getFixedSlot(PromiseSlot_RejectFunction)); MOZ_ASSERT(IsCallable(funVal)); FixedInvokeArgs<1> args(cx); @@ -2687,10 +2671,9 @@ PromiseObject::reject(JSContext* cx, HandleValue rejectionValue) return Call(cx, funVal, UndefinedHandleValue, args, &dummy); } -void -PromiseObject::onSettled(JSContext* cx) +/* static */ void +PromiseObject::onSettled(JSContext* cx, Handle<PromiseObject*> promise) { - Rooted<PromiseObject*> promise(cx, this); RootedObject stack(cx); if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) { if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames()))) { @@ -2750,7 +2733,7 @@ PromiseTask::executeAndFinish(JSContext* cx) static JSObject* CreatePromisePrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &PromiseObject::protoClass_); + return GlobalObject::createBlankPrototype(cx, cx->global(), &PromiseObject::protoClass_); } static const JSFunctionSpec promise_methods[] = { diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h index bb4778631..c76dc358c 100644 --- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -66,10 +66,12 @@ class PromiseObject : public NativeObject return getFixedSlot(PromiseSlot_ReactionsOrResult); } - MOZ_MUST_USE bool resolve(JSContext* cx, HandleValue resolutionValue); - MOZ_MUST_USE bool reject(JSContext* cx, HandleValue rejectionValue); + static MOZ_MUST_USE bool resolve(JSContext* cx, Handle<PromiseObject*> promise, + HandleValue resolutionValue); + static MOZ_MUST_USE bool reject(JSContext* cx, Handle<PromiseObject*> promise, + HandleValue rejectionValue); - void onSettled(JSContext* cx); + static void onSettled(JSContext* cx, Handle<PromiseObject*> promise); double allocationTime() { return getFixedSlot(PromiseSlot_AllocationTime).toNumber(); } double resolutionTime() { return getFixedSlot(PromiseSlot_ResolutionTime).toNumber(); } diff --git a/js/src/builtin/Reflect.cpp b/js/src/builtin/Reflect.cpp index 2f509a226..4e7fae78c 100644 --- a/js/src/builtin/Reflect.cpp +++ b/js/src/builtin/Reflect.cpp @@ -268,7 +268,8 @@ static const JSFunctionSpec methods[] = { JSObject* js::InitReflect(JSContext* cx, HandleObject obj) { - RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx)); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index beff58e13..8e8bb2417 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -3044,7 +3044,12 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); RootedValue expr(cx); - expr.setString(next->pn_atom); + if (next->isKind(PNK_RAW_UNDEFINED)) { + expr.setUndefined(); + } else { + MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING)); + expr.setString(next->pn_atom); + } cooked.infallibleAppend(expr); } @@ -3136,6 +3141,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: return literal(pn, dst); case PNK_YIELD_STAR: @@ -3216,6 +3222,8 @@ ASTSerializer::property(ParseNode* pn, MutableHandleValue dst) return expression(pn->pn_kid, &val) && builder.prototypeMutation(val, &pn->pn_pos, dst); } + if (pn->isKind(PNK_SPREAD)) + return expression(pn, dst); PropKind kind; switch (pn->getOp()) { @@ -3276,6 +3284,10 @@ ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst) val.setNull(); break; + case PNK_RAW_UNDEFINED: + val.setUndefined(); + break; + case PNK_TRUE: val.setBoolean(true); break; @@ -3332,6 +3344,16 @@ ASTSerializer::objectPattern(ParseNode* pn, MutableHandleValue dst) return false; for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) { + if (propdef->isKind(PNK_SPREAD)) { + RootedValue target(cx); + RootedValue spread(cx); + if (!pattern(propdef->pn_kid, &target)) + return false; + if(!builder.spreadExpression(target, &propdef->pn_pos, &spread)) + return false; + elts.infallibleAppend(spread); + continue; + } LOCAL_ASSERT(propdef->isKind(PNK_MUTATEPROTO) != propdef->isOp(JSOP_INITPROP)); RootedValue key(cx); @@ -3407,12 +3429,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst) : GeneratorStyle::None; bool isAsync = pn->pn_funbox->isAsync(); - bool isExpression = -#if JS_HAS_EXPR_CLOSURES - func->isExprBody(); -#else - false; -#endif + bool isExpression = pn->pn_funbox->isExprBody(); RootedValue id(cx); RootedAtom funcAtom(cx, func->explicitName()); diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index b20f41c53..7cf20d23c 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -140,12 +140,12 @@ ExecuteRegExpImpl(JSContext* cx, RegExpStatics* res, RegExpShared& re, HandleLin /* Legacy ExecuteRegExp behavior is baked into the JSAPI. */ bool -js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj, +js::ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle<RegExpObject*> reobj, HandleLinearString input, size_t* lastIndex, bool test, MutableHandleValue rval) { RegExpGuard shared(cx); - if (!reobj.getShared(cx, &shared)) + if (!RegExpObject::getShared(cx, reobj, &shared)) return false; ScopedMatchPairs matches(&cx->tempLifoAlloc()); @@ -801,7 +801,7 @@ const JSFunctionSpec js::regexp_methods[] = { name(JSContext* cx, unsigned argc, Value* vp) \ { \ CallArgs args = CallArgsFromVp(argc, vp); \ - RegExpStatics* res = cx->global()->getRegExpStatics(cx); \ + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); \ if (!res) \ return false; \ code; \ @@ -827,7 +827,7 @@ DEFINE_STATIC_GETTER(static_paren9_getter, STATIC_PAREN_GETTER_CODE(9)) static bool \ name(JSContext* cx, unsigned argc, Value* vp) \ { \ - RegExpStatics* res = cx->global()->getRegExpStatics(cx); \ + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); \ if (!res) \ return false; \ code; \ @@ -838,7 +838,7 @@ static bool static_input_setter(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - RegExpStatics* res = cx->global()->getRegExpStatics(cx); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); if (!res) return false; @@ -918,12 +918,12 @@ ExecuteRegExp(JSContext* cx, HandleObject regexp, HandleString string, Rooted<RegExpObject*> reobj(cx, ®exp->as<RegExpObject>()); RegExpGuard re(cx); - if (!reobj->getShared(cx, &re)) + if (!RegExpObject::getShared(cx, reobj, &re)) return RegExpRunStatus_Error; RegExpStatics* res; if (staticsUpdate == UpdateRegExpStatics) { - res = cx->global()->getRegExpStatics(cx); + res = GlobalObject::getRegExpStatics(cx, cx->global()); if (!res) return RegExpRunStatus_Error; } else { @@ -1725,7 +1725,7 @@ js::intrinsic_GetElemBaseForLambda(JSContext* cx, unsigned argc, Value* vp) if (!fun->isInterpreted() || fun->isClassConstructor()) return true; - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return false; @@ -1800,7 +1800,7 @@ js::intrinsic_GetStringDataProperty(JSContext* cx, unsigned argc, Value* vp) return false; RootedValue v(cx); - if (HasDataProperty(cx, nobj, AtomToId(atom), v.address()) && v.isString()) + if (GetPropertyPure(cx, nobj, AtomToId(atom), v.address()) && v.isString()) args.rval().set(v); else args.rval().setUndefined(); diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h index 715656f40..4e0ff6948 100644 --- a/js/src/builtin/RegExp.h +++ b/js/src/builtin/RegExp.h @@ -31,7 +31,7 @@ enum RegExpStaticsUpdate { UpdateRegExpStatics, DontUpdateRegExpStatics }; * |chars| and |length|. */ MOZ_MUST_USE bool -ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, RegExpObject& reobj, +ExecuteRegExpLegacy(JSContext* cx, RegExpStatics* res, Handle<RegExpObject*> reobj, HandleLinearString input, size_t* lastIndex, bool test, MutableHandleValue rval); diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index 2383922db..5fe691152 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -475,7 +475,7 @@ const Class SimdObject::class_ = { &SimdObjectClassOps }; -bool +/* static */ bool GlobalObject::initSimdObject(JSContext* cx, Handle<GlobalObject*> global) { // SIMD relies on the TypedObject module being initialized. @@ -483,11 +483,11 @@ GlobalObject::initSimdObject(JSContext* cx, Handle<GlobalObject*> global) // to be able to call GetTypedObjectModule(). It is NOT necessary // to install the TypedObjectModule global, but at the moment // those two things are not separable. - if (!global->getOrCreateTypedObjectModule(cx)) + if (!GlobalObject::getOrCreateTypedObjectModule(cx, global)) return false; RootedObject globalSimdObject(cx); - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; @@ -510,7 +510,7 @@ static bool CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName stringRepr, SimdType simdType, const JSFunctionSpec* methods) { - RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!funcProto) return false; @@ -531,7 +531,7 @@ CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName s return false; // Create prototype property, which inherits from Object.prototype. - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; Rooted<TypedProto*> proto(cx); @@ -551,7 +551,7 @@ CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName s } // Bind type descriptor to the global SIMD object - RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx)); + RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global)); MOZ_ASSERT(globalSimdObject); RootedValue typeValue(cx, ObjectValue(*typeDescr)); @@ -568,7 +568,7 @@ CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName s return !!typeDescr; } -bool +/* static */ bool GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType) { #define CREATE_(Type) \ @@ -584,13 +584,13 @@ GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, SimdType #undef CREATE_ } -SimdTypeDescr* +/* static */ SimdTypeDescr* GlobalObject::getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType) { MOZ_ASSERT(unsigned(simdType) < unsigned(SimdType::Count), "Invalid SIMD type"); - RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx)); + RootedObject globalSimdObject(cx, GlobalObject::getOrCreateSimdGlobalObject(cx, global)); if (!globalSimdObject) return nullptr; @@ -628,8 +628,8 @@ SimdObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* JSObject* js::InitSimdClass(JSContext* cx, HandleObject obj) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); - return global->getOrCreateSimdGlobalObject(cx); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + return GlobalObject::getOrCreateSimdGlobalObject(cx, global); } template<typename V> diff --git a/js/src/builtin/SymbolObject.cpp b/js/src/builtin/SymbolObject.cpp index ae38d5371..8fa860ef3 100644 --- a/js/src/builtin/SymbolObject.cpp +++ b/js/src/builtin/SymbolObject.cpp @@ -53,17 +53,17 @@ const JSFunctionSpec SymbolObject::staticMethods[] = { JSObject* SymbolObject::initClass(JSContext* cx, HandleObject obj) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); // This uses &JSObject::class_ because: "The Symbol prototype object is an // ordinary object. It is not a Symbol instance and does not have a // [[SymbolData]] internal slot." (ES6 rev 24, 19.4.3) - RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global)); if (!proto) return nullptr; - RootedFunction ctor(cx, global->createConstructor(cx, construct, - ClassName(JSProto_Symbol, cx), 0)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, construct, + ClassName(JSProto_Symbol, cx), 0)); if (!ctor) return nullptr; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index c896ce5d1..992fe2c97 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -3218,13 +3218,13 @@ ByteSizeOfScript(JSContext*cx, unsigned argc, Value* vp) return false; } - JSFunction* fun = &args[0].toObject().as<JSFunction>(); + RootedFunction fun(cx, &args[0].toObject().as<JSFunction>()); if (fun->isNative()) { JS_ReportErrorASCII(cx, "Argument must be a scripted function"); return false; } - RootedScript script(cx, fun->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script) return false; @@ -3319,7 +3319,8 @@ GetConstructorName(JSContext* cx, unsigned argc, Value* vp) } RootedAtom name(cx); - if (!args[0].toObject().constructorDisplayAtom(cx, &name)) + RootedObject obj(cx, &args[0].toObject()); + if (!JSObject::constructorDisplayAtom(cx, obj, &name)) return false; if (name) { @@ -4023,7 +4024,7 @@ DisRegExp(JSContext* cx, unsigned argc, Value* vp) return false; } - if (!reobj->dumpBytecode(cx, match_only, input)) + if (!RegExpObject::dumpBytecode(cx, reobj, match_only, input)) return false; args.rval().setUndefined(); @@ -4042,6 +4043,32 @@ IsConstructor(JSContext* cx, unsigned argc, Value* vp) return true; } +static bool +GetErrorNotes(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + if (!args.requireAtLeast(cx, "getErrorNotes", 1)) + return false; + + if (!args[0].isObject() || !args[0].toObject().is<ErrorObject>()) { + args.rval().setNull(); + return true; + } + + JSErrorReport* report = args[0].toObject().as<ErrorObject>().getErrorReport(); + if (!report) { + args.rval().setNull(); + return true; + } + + RootedObject notesArray(cx, CreateErrorNotesArray(cx, report)); + if (!notesArray) + return false; + + args.rval().setObject(*notesArray); + return true; +} + static const JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'zone' [, 'shrinking'])", @@ -4576,6 +4603,10 @@ static const JSFunctionSpecWithHelp FuzzingUnsafeTestingFunctions[] = { " Dumps RegExp bytecode."), #endif + JS_FN_HELP("getErrorNotes", GetErrorNotes, 1, 0, +"getErrorNotes(error)", +" Returns an array of error notes."), + JS_FS_HELP_END }; diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 0dfc1123a..ff3680774 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -1124,11 +1124,11 @@ DefineSimpleTypeDescr(JSContext* cx, typename T::Type type, HandlePropertyName className) { - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; - RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!funcProto) return false; @@ -1185,7 +1185,7 @@ DefineMetaTypeDescr(JSContext* cx, if (!className) return nullptr; - RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!funcProto) return nullptr; @@ -1197,7 +1197,7 @@ DefineMetaTypeDescr(JSContext* cx, // Create ctor.prototype.prototype, which inherits from Object.__proto__ - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return nullptr; RootedObject protoProto(cx); @@ -1216,7 +1216,7 @@ DefineMetaTypeDescr(JSContext* cx, const int constructorLength = 2; RootedFunction ctor(cx); - ctor = global->createConstructor(cx, T::construct, className, constructorLength); + ctor = GlobalObject::createConstructor(cx, T::construct, className, constructorLength); if (!ctor || !LinkConstructorAndPrototype(cx, ctor, proto) || !DefinePropertiesAndFunctions(cx, proto, @@ -1240,10 +1240,10 @@ DefineMetaTypeDescr(JSContext* cx, * initializer for the `TypedObject` class populate the * `TypedObject` global (which is referred to as "module" herein). */ -bool +/* static */ bool GlobalObject::initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global) { - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!objProto) return false; @@ -1317,9 +1317,8 @@ GlobalObject::initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global) JSObject* js::InitTypedObjectModuleObject(JSContext* cx, HandleObject obj) { - MOZ_ASSERT(obj->is<GlobalObject>()); - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); - return global->getOrCreateTypedObjectModule(cx); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + return GlobalObject::getOrCreateTypedObjectModule(cx, global); } /****************************************************************************** diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index c73bc5e7f..d5f233d05 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -229,6 +229,69 @@ function GetInternalError(msg) { // To be used when a function is required but calling it shouldn't do anything. function NullFunction() {} +// Object Rest/Spread Properties proposal +// Abstract operation: CopyDataProperties (target, source, excluded) +function CopyDataProperties(target, source, excluded) { + // Step 1. + assert(IsObject(target), "target is an object"); + + // Step 2. + assert(IsObject(excluded), "excluded is an object"); + + // Steps 3, 6. + if (source === undefined || source === null) + return; + + // Step 4.a. + source = ToObject(source); + + // Step 4.b. + var keys = OwnPropertyKeys(source, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS); + + // Step 5. + for (var index = 0; index < keys.length; index++) { + var key = keys[index]; + + // We abbreviate this by calling propertyIsEnumerable which is faster + // and returns false for not defined properties. + if (!callFunction(std_Object_hasOwnProperty, excluded, key) && callFunction(std_Object_propertyIsEnumerable, source, key)) + _DefineDataProperty(target, key, source[key]); + } + + // Step 6 (Return). +} + +// Object Rest/Spread Properties proposal +// Abstract operation: CopyDataProperties (target, source, excluded) +function CopyDataPropertiesUnfiltered(target, source) { + // Step 1. + assert(IsObject(target), "target is an object"); + + // Step 2 (Not applicable). + + // Steps 3, 6. + if (source === undefined || source === null) + return; + + // Step 4.a. + source = ToObject(source); + + // Step 4.b. + var keys = OwnPropertyKeys(source, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS); + + // Step 5. + for (var index = 0; index < keys.length; index++) { + var key = keys[index]; + + // We abbreviate this by calling propertyIsEnumerable which is faster + // and returns false for not defined properties. + if (callFunction(std_Object_propertyIsEnumerable, source, key)) + _DefineDataProperty(target, key, source[key]); + } + + // Step 6 (Return). +} + /*************************************** Testing functions ***************************************/ function outer() { return function inner() { diff --git a/js/src/builtin/WeakMapObject.cpp b/js/src/builtin/WeakMapObject.cpp index 555b9e03a..dcfa19776 100644 --- a/js/src/builtin/WeakMapObject.cpp +++ b/js/src/builtin/WeakMapObject.cpp @@ -350,14 +350,14 @@ InitWeakMapClass(JSContext* cx, HandleObject obj, bool defineMembers) { MOZ_ASSERT(obj->isNative()); - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx)); if (!proto) return nullptr; - RootedFunction ctor(cx, global->createConstructor(cx, WeakMap_construct, - cx->names().WeakMap, 0)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, WeakMap_construct, + cx->names().WeakMap, 0)); if (!ctor) return nullptr; diff --git a/js/src/builtin/WeakSetObject.cpp b/js/src/builtin/WeakSetObject.cpp index 7ea3f2fef..fbe5e418c 100644 --- a/js/src/builtin/WeakSetObject.cpp +++ b/js/src/builtin/WeakSetObject.cpp @@ -41,14 +41,15 @@ const JSFunctionSpec WeakSetObject::methods[] = { }; JSObject* -WeakSetObject::initClass(JSContext* cx, JSObject* obj) +WeakSetObject::initClass(JSContext* cx, HandleObject obj) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx)); if (!proto) return nullptr; - Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(JSProto_WeakSet, cx), 0)); + Rooted<JSFunction*> ctor(cx, GlobalObject::createConstructor(cx, construct, + ClassName(JSProto_WeakSet, cx), 0)); if (!ctor || !LinkConstructorAndPrototype(cx, ctor, proto) || !DefinePropertiesAndFunctions(cx, proto, properties, methods) || diff --git a/js/src/builtin/WeakSetObject.h b/js/src/builtin/WeakSetObject.h index 0a6ff33f3..50e54c182 100644 --- a/js/src/builtin/WeakSetObject.h +++ b/js/src/builtin/WeakSetObject.h @@ -16,7 +16,7 @@ class WeakSetObject : public NativeObject public: static const unsigned RESERVED_SLOTS = 1; - static JSObject* initClass(JSContext* cx, JSObject* obj); + static JSObject* initClass(JSContext* cx, HandleObject obj); static const Class class_; private: diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index b5be5f5ac..a1abbfeda 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -77,7 +77,13 @@ class MOZ_STACK_CLASS BytecodeCompiler bool canLazilyParse(); bool createParser(); bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing()); - bool createScript(uint32_t preludeStart = 0); + + // If toString{Start,End} are not explicitly passed, assume the script's + // offsets in the source used to parse it are the same as what should be + // used to compute its Function.prototype.toString() value. + bool createScript(); + bool createScript(uint32_t toStringStart, uint32_t toStringEnd); + bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext); bool handleParseFailure(const Directives& newDirectives); bool deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment); @@ -242,11 +248,17 @@ BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = No } bool -BytecodeCompiler::createScript(uint32_t preludeStart /* = 0 */) +BytecodeCompiler::createScript() +{ + return createScript(0, sourceBuffer.length()); +} + +bool +BytecodeCompiler::createScript(uint32_t toStringStart, uint32_t toStringEnd) { script = JSScript::Create(cx, options, sourceObject, /* sourceStart = */ 0, sourceBuffer.length(), - preludeStart); + toStringStart, toStringEnd); return script != nullptr; } @@ -287,7 +299,8 @@ BytecodeCompiler::deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObj RootedObject env(cx, environment); while (env->is<EnvironmentObject>() || env->is<DebugEnvironmentProxy>()) { if (env->is<CallObject>()) { - RootedScript script(cx, env->as<CallObject>().callee().getOrCreateScript(cx)); + RootedFunction fun(cx, &env->as<CallObject>().callee()); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script) return false; if (script->argumentsHasVarBinding()) { @@ -457,7 +470,7 @@ BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun, if (fn->pn_funbox->function()->isInterpreted()) { MOZ_ASSERT(fun == fn->pn_funbox->function()); - if (!createScript(fn->pn_funbox->preludeStart)) + if (!createScript(fn->pn_funbox->toStringStart, fn->pn_funbox->toStringEnd)) return false; Maybe<BytecodeEmitter> emitter; @@ -652,7 +665,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject, lazy->begin(), lazy->end(), - lazy->preludeStart())); + lazy->toStringStart(), lazy->toStringEnd())); if (!script) return false; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 7f9fa8a5d..309d6c290 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -3069,6 +3069,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_ELISION: case PNK_GENERATOR: case PNK_NUMBER: @@ -3538,9 +3539,10 @@ BytecodeEmitter::needsImplicitThis() bool BytecodeEmitter::maybeSetDisplayURL() { - if (tokenStream()->hasDisplayURL()) { - if (!parser->ss->setDisplayURL(cx, tokenStream()->displayURL())) + if (tokenStream().hasDisplayURL()) { + if (!parser->ss->setDisplayURL(cx, tokenStream().displayURL())) { return false; + } } return true; } @@ -3548,10 +3550,11 @@ BytecodeEmitter::maybeSetDisplayURL() bool BytecodeEmitter::maybeSetSourceMap() { - if (tokenStream()->hasSourceMapURL()) { + if (tokenStream().hasSourceMapURL()) { MOZ_ASSERT(!parser->ss->hasSourceMapURL()); - if (!parser->ss->setSourceMapURL(cx, tokenStream()->sourceMapURL())) + if (!parser->ss->setSourceMapURL(cx, tokenStream().sourceMapURL())) { return false; + } } /* @@ -3590,21 +3593,21 @@ BytecodeEmitter::tellDebuggerAboutCompiledScript(ExclusiveContext* cx) } } -inline TokenStream* +inline TokenStream& BytecodeEmitter::tokenStream() { - return &parser->tokenStream; + return parser->tokenStream; } bool BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) { - TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos; + TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos; va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportCompileErrorNumberVA(pos.begin, JSREPORT_ERROR, - errorNumber, args); + bool result = tokenStream().reportCompileErrorNumberVA(nullptr, pos.begin, JSREPORT_ERROR, + errorNumber, args); va_end(args); return result; } @@ -3612,11 +3615,12 @@ BytecodeEmitter::reportError(ParseNode* pn, unsigned errorNumber, ...) bool BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...) { - TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos; + TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos; va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportExtraWarningErrorNumberVA(pos.begin, errorNumber, args); + bool result = tokenStream().reportExtraWarningErrorNumberVA(nullptr, pos.begin, + errorNumber, args); va_end(args); return result; } @@ -3624,12 +3628,12 @@ BytecodeEmitter::reportExtraWarning(ParseNode* pn, unsigned errorNumber, ...) bool BytecodeEmitter::reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...) { - TokenPos pos = pn ? pn->pn_pos : tokenStream()->currentToken().pos; + TokenPos pos = pn ? pn->pn_pos : tokenStream().currentToken().pos; va_list args; va_start(args, errorNumber); - bool result = tokenStream()->reportStrictModeErrorNumberVA(pos.begin, sc->strict(), - errorNumber, args); + bool result = tokenStream().reportStrictModeErrorNumberVA(nullptr, pos.begin, sc->strict(), + errorNumber, args); va_end(args); return result; } @@ -4599,7 +4603,7 @@ BytecodeEmitter::emitSwitch(ParseNode* pn) // If the expression is a literal, suppress line number emission so // that debugging works more naturally. if (caseValue) { - if (!emitTree(caseValue, + if (!emitTree(caseValue, ValueUsage::WantValue, caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE)) { return false; @@ -5810,36 +5814,78 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla if (!emitRequireObjectCoercible()) // ... RHS return false; + bool needsRestPropertyExcludedSet = pattern->pn_count > 1 && + pattern->last()->isKind(PNK_SPREAD); + if (needsRestPropertyExcludedSet) { + if (!emitDestructuringObjRestExclusionSet(pattern)) // ... RHS SET + return false; + + if (!emit1(JSOP_SWAP)) // ... SET RHS + return false; + } + for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { ParseNode* subpattern; - if (member->isKind(PNK_MUTATEPROTO)) + if (member->isKind(PNK_MUTATEPROTO) || member->isKind(PNK_SPREAD)) subpattern = member->pn_kid; else subpattern = member->pn_right; + ParseNode* lhs = subpattern; + MOZ_ASSERT_IF(member->isKind(PNK_SPREAD), !lhs->isKind(PNK_ASSIGN)); if (lhs->isKind(PNK_ASSIGN)) lhs = lhs->pn_left; size_t emitted; - if (!emitDestructuringLHSRef(lhs, &emitted)) // ... RHS *LREF + if (!emitDestructuringLHSRef(lhs, &emitted)) // ... *SET RHS *LREF return false; // Duplicate the value being destructured to use as a reference base. if (emitted) { - if (!emitDupAt(emitted)) // ... RHS *LREF RHS + if (!emitDupAt(emitted)) // ... *SET RHS *LREF RHS return false; } else { - if (!emit1(JSOP_DUP)) // ... RHS RHS + if (!emit1(JSOP_DUP)) // ... *SET RHS RHS return false; } + if (member->isKind(PNK_SPREAD)) { + if (!updateSourceCoordNotes(member->pn_pos.begin)) + return false; + + if (!emitNewInit(JSProto_Object)) // ... *SET RHS *LREF RHS TARGET + return false; + if (!emit1(JSOP_DUP)) // ... *SET RHS *LREF RHS TARGET TARGET + return false; + if (!emit2(JSOP_PICK, 2)) // ... *SET RHS *LREF TARGET TARGET RHS + return false; + + if (needsRestPropertyExcludedSet) { + if (!emit2(JSOP_PICK, emitted + 4)) // ... RHS *LREF TARGET TARGET RHS SET + return false; + } + + CopyOption option = needsRestPropertyExcludedSet + ? CopyOption::Filtered + : CopyOption::Unfiltered; + if (!emitCopyDataProperties(option)) // ... RHS *LREF TARGET + return false; + + // Destructure TARGET per this member's lhs. + if (!emitSetOrInitializeDestructuring(lhs, flav)) // ... RHS + return false; + + MOZ_ASSERT(member == pattern->last(), "Rest property is always last"); + break; + } + // Now push the property name currently being matched, which is the // current property name "label" on the left of a colon in the object // initialiser. bool needsGetElem = true; if (member->isKind(PNK_MUTATEPROTO)) { - if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... RHS *LREF PROP + if (!emitAtomOp(cx->names().proto, JSOP_GETPROP)) // ... *SET RHS *LREF PROP return false; needsGetElem = false; } else { @@ -5847,40 +5893,131 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla ParseNode* key = member->pn_left; if (key->isKind(PNK_NUMBER)) { - if (!emitNumberOp(key->pn_dval)) // ... RHS *LREF RHS KEY + if (!emitNumberOp(key->pn_dval)) // ... *SET RHS *LREF RHS KEY return false; } else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) { - PropertyName* name = key->pn_atom->asPropertyName(); - - // The parser already checked for atoms representing indexes and - // used PNK_NUMBER instead, but also watch for ids which TI treats - // as indexes for simplification of downstream analysis. - jsid id = NameToId(name); - if (id != IdToTypeId(id)) { - if (!emitTree(key)) // ... RHS *LREF RHS KEY + if (!emitAtomOp(key->pn_atom, JSOP_GETPROP)) // ... *SET RHS *LREF PROP + return false; + needsGetElem = false; + } else { + if (!emitComputedPropertyName(key)) // ... *SET RHS *LREF RHS KEY + return false; + + // Add the computed property key to the exclusion set. + if (needsRestPropertyExcludedSet) { + if (!emitDupAt(emitted + 3)) // ... SET RHS *LREF RHS KEY SET return false; - } else { - if (!emitAtomOp(name, JSOP_GETPROP)) // ... RHS *LREF PROP + if (!emitDupAt(1)) // ... SET RHS *LREF RHS KEY SET KEY + return false; + if (!emit1(JSOP_UNDEFINED)) // ... SET RHS *LREF RHS KEY SET KEY UNDEFINED + return false; + if (!emit1(JSOP_INITELEM)) // ... SET RHS *LREF RHS KEY SET + return false; + if (!emit1(JSOP_POP)) // ... SET RHS *LREF RHS KEY return false; - needsGetElem = false; } - } else { - if (!emitComputedPropertyName(key)) // ... RHS *LREF RHS KEY - return false; } } // Get the property value if not done already. - if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... RHS *LREF PROP + if (needsGetElem && !emitElemOpBase(JSOP_GETELEM)) // ... *SET RHS *LREF PROP return false; if (subpattern->isKind(PNK_ASSIGN)) { - if (!emitDefault(subpattern->pn_right, lhs)) // ... RHS *LREF VALUE + if (!emitDefault(subpattern->pn_right, lhs)) // ... *SET RHS *LREF VALUE return false; } // Destructure PROP per this member's lhs. - if (!emitSetOrInitializeDestructuring(subpattern, flav)) // ... RHS + if (!emitSetOrInitializeDestructuring(subpattern, flav)) // ... *SET RHS + return false; + } + + return true; +} + +bool +BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern) +{ + MOZ_ASSERT(pattern->isKind(PNK_OBJECT)); + MOZ_ASSERT(pattern->isArity(PN_LIST)); + MOZ_ASSERT(pattern->last()->isKind(PNK_SPREAD)); + + ptrdiff_t offset = this->offset(); + if (!emitNewInit(JSProto_Object)) + return false; + + // Try to construct the shape of the object as we go, so we can emit a + // JSOP_NEWOBJECT with the final shape instead. + // In the case of computed property names and indices, we cannot fix the + // shape at bytecode compile time. When the shape cannot be determined, + // |obj| is nulled out. + + // No need to do any guessing for the object kind, since we know the upper + // bound of how many properties we plan to have. + gc::AllocKind kind = gc::GetGCObjectKind(pattern->pn_count - 1); + RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject)); + if (!obj) + return false; + + RootedAtom pnatom(cx); + for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { + if (member->isKind(PNK_SPREAD)) + break; + + bool isIndex = false; + if (member->isKind(PNK_MUTATEPROTO)) { + pnatom.set(cx->names().proto); + } else { + ParseNode* key = member->pn_left; + if (key->isKind(PNK_NUMBER)) { + if (!emitNumberOp(key->pn_dval)) + return false; + isIndex = true; + } else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) { + pnatom.set(key->pn_atom); + } else { + // Otherwise this is a computed property name which needs to + // be added dynamically. + obj.set(nullptr); + continue; + } + } + + // Initialize elements with |undefined|. + if (!emit1(JSOP_UNDEFINED)) + return false; + + if (isIndex) { + obj.set(nullptr); + if (!emit1(JSOP_INITELEM)) + return false; + } else { + uint32_t index; + if (!makeAtomIndex(pnatom, &index)) + return false; + + if (obj) { + MOZ_ASSERT(!obj->inDictionaryMode()); + Rooted<jsid> id(cx, AtomToId(pnatom)); + if (!NativeDefineProperty(cx, obj, id, UndefinedHandleValue, nullptr, nullptr, + JSPROP_ENUMERATE)) + { + return false; + } + if (obj->inDictionaryMode()) + obj.set(nullptr); + } + + if (!emitIndex32(JSOP_INITPROP, index)) + return false; + } + } + + if (obj) { + // The object survived and has a predictable shape: update the + // original bytecode. + if (!replaceNewInitWithNewObject(obj, offset)) return false; } @@ -6242,6 +6379,9 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje case PNK_NULL: vp.setNull(); return true; + case PNK_RAW_UNDEFINED: + vp.setUndefined(); + return true; case PNK_CALLSITEOBJ: case PNK_ARRAY: { unsigned count; @@ -6645,7 +6785,7 @@ BytecodeEmitter::emitLexicalScopeBody(ParseNode* body, EmitLineNumberNote emitLi } // Line notes were updated by emitLexicalScope. - return emitTree(body, emitLineNote); + return emitTree(body, ValueUsage::WantValue, emitLineNote); } // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See @@ -6747,9 +6887,9 @@ BytecodeEmitter::emitRequireObjectCoercible() return false; if (!emit2(JSOP_PICK, 2)) // VAL REQUIREOBJECTCOERCIBLE UNDEFINED VAL return false; - if (!emitCall(JSOP_CALL, 1)) // VAL IGNORED + if (!emitCall(JSOP_CALL_IGNORES_RV, 1))// VAL IGNORED return false; - checkTypeSet(JSOP_CALL); + checkTypeSet(JSOP_CALL_IGNORES_RV); if (!emit1(JSOP_POP)) // VAL return false; @@ -6759,6 +6899,53 @@ BytecodeEmitter::emitRequireObjectCoercible() } bool +BytecodeEmitter::emitCopyDataProperties(CopyOption option) +{ + DebugOnly<int32_t> depth = this->stackDepth; + + uint32_t argc; + if (option == CopyOption::Filtered) { + MOZ_ASSERT(depth > 2); // TARGET SOURCE SET + argc = 3; + + if (!emitAtomOp(cx->names().CopyDataProperties, + JSOP_GETINTRINSIC)) // TARGET SOURCE SET COPYDATAPROPERTIES + { + return false; + } + } else { + MOZ_ASSERT(depth > 1); // TARGET SOURCE + argc = 2; + + if (!emitAtomOp(cx->names().CopyDataPropertiesUnfiltered, + JSOP_GETINTRINSIC)) // TARGET SOURCE COPYDATAPROPERTIES + { + return false; + } + } + + if (!emit1(JSOP_UNDEFINED)) // TARGET SOURCE *SET COPYDATAPROPERTIES UNDEFINED + return false; + if (!emit2(JSOP_PICK, argc + 1)) // SOURCE *SET COPYDATAPROPERTIES UNDEFINED TARGET + return false; + if (!emit2(JSOP_PICK, argc + 1)) // *SET COPYDATAPROPERTIES UNDEFINED TARGET SOURCE + return false; + if (option == CopyOption::Filtered) { + if (!emit2(JSOP_PICK, argc + 1)) // COPYDATAPROPERTIES UNDEFINED TARGET SOURCE SET + return false; + } + if (!emitCall(JSOP_CALL_IGNORES_RV, argc)) // IGNORED + return false; + checkTypeSet(JSOP_CALL_IGNORES_RV); + + if (!emit1(JSOP_POP)) // - + return false; + + MOZ_ASSERT(depth - int(argc) == this->stackDepth); + return true; +} + +bool BytecodeEmitter::emitIterator() { // Convert iterable to iterator. @@ -7269,12 +7456,14 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc // scope, but we still need to emit code for the initializers.) if (!updateSourceCoordNotes(init->pn_pos.begin)) return false; - if (!emitTree(init)) - return false; - - if (!init->isForLoopDeclaration()) { + if (init->isForLoopDeclaration()) { + if (!emitTree(init)) + return false; + } else { // 'init' is an expression, not a declaration. emitTree left its // value on the stack. + if (!emitTree(init, ValueUsage::IgnoreValue)) + return false; if (!emit1(JSOP_POP)) return false; } @@ -7356,7 +7545,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc if (!updateSourceCoordNotes(update->pn_pos.begin)) return false; - if (!emitTree(update)) + if (!emitTree(update, ValueUsage::IgnoreValue)) return false; if (!emit1(JSOP_POP)) return false; @@ -7839,7 +8028,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) Rooted<JSObject*> sourceObject(cx, script->sourceObject()); Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject, funbox->bufStart, funbox->bufEnd, - funbox->preludeStart)); + funbox->toStringStart, + funbox->toStringEnd)); if (!script) return false; @@ -8682,8 +8872,9 @@ BytecodeEmitter::emitStatement(ParseNode* pn) if (useful) { JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP; + ValueUsage valueUsage = wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue; MOZ_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP)); - if (!emitTree(pn2)) + if (!emitTree(pn2, valueUsage)) return false; if (!emit1(op)) return false; @@ -9033,7 +9224,7 @@ BytecodeEmitter::emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitte } bool -BytecodeEmitter::emitCallOrNew(ParseNode* pn) +BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */) { bool callop = pn->isKind(PNK_CALL) || pn->isKind(PNK_TAGGED_TEMPLATE); /* @@ -9212,13 +9403,20 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn) } if (!spread) { - if (!emitCall(pn->getOp(), argc, pn)) - return false; + if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) { + if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn)) + return false; + checkTypeSet(JSOP_CALL_IGNORES_RV); + } else { + if (!emitCall(pn->getOp(), argc, pn)) + return false; + checkTypeSet(pn->getOp()); + } } else { if (!emit1(pn->getOp())) return false; + checkTypeSet(pn->getOp()); } - checkTypeSet(pn->getOp()); if (pn->isOp(JSOP_EVAL) || pn->isOp(JSOP_STRICTEVAL) || pn->isOp(JSOP_SPREADEVAL) || @@ -9316,12 +9514,13 @@ BytecodeEmitter::emitLogical(ParseNode* pn) } bool -BytecodeEmitter::emitSequenceExpr(ParseNode* pn) +BytecodeEmitter::emitSequenceExpr(ParseNode* pn, + ValueUsage valueUsage /* = ValueUsage::WantValue */) { for (ParseNode* child = pn->pn_head; ; child = child->pn_next) { if (!updateSourceCoordNotes(child->pn_pos.begin)) return false; - if (!emitTree(child)) + if (!emitTree(child, child->pn_next ? ValueUsage::IgnoreValue : valueUsage)) return false; if (!child->pn_next) break; @@ -9384,7 +9583,8 @@ BytecodeEmitter::emitLabeledStatement(const LabeledStatement* pn) } bool -BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional) +BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional, + ValueUsage valueUsage /* = ValueUsage::WantValue */) { /* Emit the condition, then branch if false to the else part. */ if (!emitTree(&conditional.condition())) @@ -9394,13 +9594,13 @@ BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional) if (!ifThenElse.emitCond()) return false; - if (!emitTreeInBranch(&conditional.thenExpression())) + if (!emitTreeInBranch(&conditional.thenExpression(), valueUsage)) return false; if (!ifThenElse.emitElse()) return false; - if (!emitTreeInBranch(&conditional.elseExpression())) + if (!emitTreeInBranch(&conditional.elseExpression(), valueUsage)) return false; if (!ifThenElse.emitEnd()) @@ -9429,6 +9629,22 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, continue; } + if (propdef->isKind(PNK_SPREAD)) { + MOZ_ASSERT(type == ObjectLiteral); + + if (!emit1(JSOP_DUP)) + return false; + + if (!emitTree(propdef->pn_kid)) + return false; + + if (!emitCopyDataProperties(CopyOption::Unfiltered)) + return false; + + objp.set(nullptr); + continue; + } + bool extraPop = false; if (type == ClassBody && propdef->as<ClassMethod>().isStatic()) { extraPop = true; @@ -9452,16 +9668,6 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, { continue; } - - // The parser already checked for atoms representing indexes and - // used PNK_NUMBER instead, but also watch for ids which TI treats - // as indexes for simpliciation of downstream analysis. - jsid id = NameToId(key->pn_atom->asPropertyName()); - if (id != IdToTypeId(id)) { - if (!emitTree(key)) - return false; - isIndex = true; - } } else { if (!emitComputedPropertyName(key)) return false; @@ -9542,8 +9748,7 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, MOZ_ASSERT(!IsHiddenInitOp(op)); MOZ_ASSERT(!objp->inDictionaryMode()); Rooted<jsid> id(cx, AtomToId(key->pn_atom)); - RootedValue undefinedValue(cx, UndefinedValue()); - if (!NativeDefineProperty(cx, objp, id, undefinedValue, nullptr, nullptr, + if (!NativeDefineProperty(cx, objp, id, UndefinedHandleValue, nullptr, nullptr, JSPROP_ENUMERATE)) { return false; @@ -9586,15 +9791,16 @@ BytecodeEmitter::emitObject(ParseNode* pn) if (!emitNewInit(JSProto_Object)) return false; - /* - * Try to construct the shape of the object as we go, so we can emit a - * JSOP_NEWOBJECT with the final shape instead. - */ - RootedPlainObject obj(cx); - // No need to do any guessing for the object kind, since we know exactly - // how many properties we plan to have. + // Try to construct the shape of the object as we go, so we can emit a + // JSOP_NEWOBJECT with the final shape instead. + // In the case of computed property names and indices, we cannot fix the + // shape at bytecode compile time. When the shape cannot be determined, + // |obj| is nulled out. + + // No need to do any guessing for the object kind, since we know the upper + // bound of how many properties we plan to have. gc::AllocKind kind = gc::GetGCObjectKind(pn->pn_count); - obj = NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject); + RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, kind, TenuredObject)); if (!obj) return false; @@ -9602,25 +9808,34 @@ BytecodeEmitter::emitObject(ParseNode* pn) return false; if (obj) { - /* - * The object survived and has a predictable shape: update the original - * bytecode. - */ - ObjectBox* objbox = parser->newObjectBox(obj); - if (!objbox) + // The object survived and has a predictable shape: update the original + // bytecode. + if (!replaceNewInitWithNewObject(obj, offset)) return false; + } - static_assert(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH, - "newinit and newobject must have equal length to edit in-place"); + return true; +} - uint32_t index = objectList.add(objbox); - jsbytecode* code = this->code(offset); - code[0] = JSOP_NEWOBJECT; - code[1] = jsbytecode(index >> 24); - code[2] = jsbytecode(index >> 16); - code[3] = jsbytecode(index >> 8); - code[4] = jsbytecode(index); - } +bool +BytecodeEmitter::replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset) +{ + ObjectBox* objbox = parser->newObjectBox(obj); + if (!objbox) + return false; + + static_assert(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH, + "newinit and newobject must have equal length to edit in-place"); + + uint32_t index = objectList.add(objbox); + jsbytecode* code = this->code(offset); + + MOZ_ASSERT(code[0] == JSOP_NEWINIT); + code[0] = JSOP_NEWOBJECT; + code[1] = jsbytecode(index >> 24); + code[2] = jsbytecode(index >> 16); + code[3] = jsbytecode(index >> 8); + code[4] = jsbytecode(index); return true; } @@ -10219,6 +10434,13 @@ BytecodeEmitter::emitClass(ParseNode* pn) return false; } } else { + // In the case of default class constructors, emit the start and end + // offsets in the source buffer as source notes so that when we + // actually make the constructor during execution, we can give it the + // correct toString output. + if (!newSrcNote3(SRC_CLASS_SPAN, ptrdiff_t(pn->pn_pos.begin), ptrdiff_t(pn->pn_pos.end))) + return false; + JSAtom *name = names ? names->innerBinding()->pn_atom : cx->names().empty; if (heritageExpression) { if (!emitAtomOp(name, JSOP_DERIVEDCONSTRUCTOR)) @@ -10273,7 +10495,8 @@ BytecodeEmitter::emitClass(ParseNode* pn) } bool -BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) +BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */, + EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */) { JS_CHECK_RECURSION(cx, return false); @@ -10395,7 +10618,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) break; case PNK_COMMA: - if (!emitSequenceExpr(pn)) + if (!emitSequenceExpr(pn, valueUsage)) return false; break; @@ -10417,7 +10640,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) break; case PNK_CONDITIONAL: - if (!emitConditionalExpression(pn->as<ConditionalExpression>())) + if (!emitConditionalExpression(pn->as<ConditionalExpression>(), valueUsage)) return false; break; @@ -10530,7 +10753,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) case PNK_CALL: case PNK_GENEXP: case PNK_SUPERCALL: - if (!emitCallOrNew(pn)) + if (!emitCallOrNew(pn, valueUsage)) return false; break; @@ -10636,6 +10859,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: if (!emit1(pn->getOp())) return false; break; @@ -10687,12 +10911,13 @@ BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote) } bool -BytecodeEmitter::emitTreeInBranch(ParseNode* pn) +BytecodeEmitter::emitTreeInBranch(ParseNode* pn, + ValueUsage valueUsage /* = ValueUsage::WantValue */) { // Code that may be conditionally executed always need their own TDZ // cache. TDZCheckCache tdzCache(this); - return emitTree(pn); + return emitTree(pn, valueUsage); } static bool diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 29050c846..595ee6405 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -171,6 +171,11 @@ struct JumpList { void patchAll(jsbytecode* code, JumpTarget target); }; +enum class ValueUsage { + WantValue, + IgnoreValue +}; + struct MOZ_STACK_CLASS BytecodeEmitter { class TDZCheckCache; @@ -356,7 +361,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool maybeSetSourceMap(); void tellDebuggerAboutCompiledScript(ExclusiveContext* cx); - inline TokenStream* tokenStream(); + inline TokenStream& tokenStream(); BytecodeVector& code() const { return current->code; } jsbytecode* code(ptrdiff_t offset) const { return current->code.begin() + offset; } @@ -434,10 +439,12 @@ struct MOZ_STACK_CLASS BytecodeEmitter }; // Emit code for the tree rooted at pn. - MOZ_MUST_USE bool emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote = EMIT_LINENOTE); + MOZ_MUST_USE bool emitTree(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue, + EmitLineNumberNote emitLineNote = EMIT_LINENOTE); // Emit code for the tree rooted at pn with its own TDZ cache. - MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn); + MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn, + ValueUsage valueUsage = ValueUsage::WantValue); // Emit global, eval, or module code for tree rooted at body. Always // encompasses the entire source. @@ -533,6 +540,8 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_NEVER_INLINE MOZ_MUST_USE bool emitFunction(ParseNode* pn, bool needsProto = false); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitObject(ParseNode* pn); + MOZ_MUST_USE bool replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset); + MOZ_MUST_USE bool emitHoistedFunctionsInList(ParseNode* pn); MOZ_MUST_USE bool emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, @@ -660,6 +669,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter // []/{} expression). MOZ_MUST_USE bool emitSetOrInitializeDestructuring(ParseNode* target, DestructuringFlavor flav); + // emitDestructuringObjRestExclusionSet emits the property exclusion set + // for the rest-property in an object pattern. + MOZ_MUST_USE bool emitDestructuringObjRestExclusionSet(ParseNode* pattern); + // emitDestructuringOps assumes the to-be-destructured value has been // pushed on the stack and emits code to destructure each part of a [] or // {} lhs expression. @@ -677,6 +690,15 @@ struct MOZ_STACK_CLASS BytecodeEmitter // object, with no overall effect on the stack. MOZ_MUST_USE bool emitRequireObjectCoercible(); + enum class CopyOption { + Filtered, Unfiltered + }; + + // Calls either the |CopyDataProperties| or the + // |CopyDataPropertiesUnfiltered| intrinsic function, consumes three (or + // two in the latter case) elements from the stack. + MOZ_MUST_USE bool emitCopyDataProperties(CopyOption option); + // emitIterator expects the iterable to already be on the stack. // It will replace that stack value with the corresponding iterator MOZ_MUST_USE bool emitIterator(); @@ -724,16 +746,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitRightAssociative(ParseNode* pn); MOZ_MUST_USE bool emitLeftAssociative(ParseNode* pn); MOZ_MUST_USE bool emitLogical(ParseNode* pn); - MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn); + MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn, + ValueUsage valueUsage = ValueUsage::WantValue); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn); - MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional); + MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional, + ValueUsage valueUsage = ValueUsage::WantValue); MOZ_MUST_USE bool isRestParameter(ParseNode* pn, bool* result); MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted); - MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn); + MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue); MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn); MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn); MOZ_MUST_USE bool emitSelfHostedForceInterpreter(ParseNode* pn); diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 6f62ffac6..689fa02b4 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -378,6 +378,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_THIS: case PNK_ELISION: case PNK_NUMBER: @@ -468,6 +469,7 @@ IsEffectless(ParseNode* node) node->isKind(PNK_TEMPLATE_STRING) || node->isKind(PNK_NUMBER) || node->isKind(PNK_NULL) || + node->isKind(PNK_RAW_UNDEFINED) || node->isKind(PNK_FUNCTION) || node->isKind(PNK_GENEXP); } @@ -492,6 +494,7 @@ Boolish(ParseNode* pn) case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: return Falsy; case PNK_VOID: { @@ -1342,15 +1345,8 @@ FoldElement(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& if (!name) return true; - // Also don't optimize if the name doesn't map directly to its id for TI's - // purposes. - if (NameToId(name) != IdToTypeId(NameToId(name))) - return true; - // Optimization 3: We have expr["foo"] where foo is not an index. Convert // to a property access (like expr.foo) that optimizes better downstream. - // Don't bother with this for names that TI considers to be indexes, to - // simplify downstream analysis. ParseNode* dottedAccess = parser.handler.newPropertyAccess(expr, name, node->pn_pos.end); if (!dottedAccess) return false; @@ -1643,6 +1639,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_ELISION: case PNK_NUMBER: case PNK_DEBUGGER: diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index b619cf24c..2d7f57e1e 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -10,6 +10,8 @@ #include "mozilla/Attributes.h" #include "mozilla/PodOperations.h" +#include <string.h> + #include "frontend/ParseNode.h" #include "frontend/SharedContext.h" @@ -181,6 +183,10 @@ class FullParseHandler return new_<NullLiteral>(pos); } + ParseNode* newRawUndefinedLiteral(const TokenPos& pos) { + return new_<RawUndefinedLiteral>(pos); + } + // The Boxer object here is any object that can allocate ObjectBoxes. // Specifically, a Boxer has a .newObjectBox(T) method that accepts a // Rooted<RegExpObject*> argument and returns an ObjectBox*. @@ -296,10 +302,9 @@ class FullParseHandler } MOZ_MUST_USE bool addSpreadElement(ParseNode* literal, uint32_t begin, ParseNode* inner) { - TokenPos pos(begin, inner->pn_pos.end); - ParseNode* spread = new_<UnaryNode>(PNK_SPREAD, JSOP_NOP, pos, inner); + ParseNode* spread = newSpread(begin, inner); if (!spread) - return null(); + return false; literal->append(spread); literal->pn_xflags |= PNX_ARRAYHOLESPREAD | PNX_NONCONST; return true; @@ -327,8 +332,10 @@ class FullParseHandler return literal; } - ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock) { - return new_<ClassNode>(name, heritage, methodBlock); + ParseNode* newClass(ParseNode* name, ParseNode* heritage, ParseNode* methodBlock, + const TokenPos& pos) + { + return new_<ClassNode>(name, heritage, methodBlock, pos); } ParseNode* newClassMethodList(uint32_t begin) { return new_<ListNode>(PNK_CLASSMETHODLIST, TokenPos(begin, begin + 1)); @@ -388,6 +395,18 @@ class FullParseHandler return true; } + MOZ_MUST_USE bool addSpreadProperty(ParseNode* literal, uint32_t begin, ParseNode* inner) { + MOZ_ASSERT(literal->isKind(PNK_OBJECT)); + MOZ_ASSERT(literal->isArity(PN_LIST)); + + setListFlag(literal, PNX_NONCONST); + ParseNode* spread = newSpread(begin, inner); + if (!spread) + return false; + literal->append(spread); + return true; + } + MOZ_MUST_USE bool addObjectMethodDefinition(ParseNode* literal, ParseNode* key, ParseNode* fn, JSOp op) { @@ -870,29 +889,29 @@ class FullParseHandler return node->isKind(PNK_NAME); } - bool nameIsEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) { - MOZ_ASSERT(isNameAnyParentheses(node), - "must only call this function on known names"); + bool isArgumentsAnyParentheses(ParseNode* node, ExclusiveContext* cx) { + return node->isKind(PNK_NAME) && node->pn_atom == cx->names().arguments; + } - return node->pn_atom == cx->names().eval; + bool isEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) { + return node->isKind(PNK_NAME) && node->pn_atom == cx->names().eval; } const char* nameIsArgumentsEvalAnyParentheses(ParseNode* node, ExclusiveContext* cx) { MOZ_ASSERT(isNameAnyParentheses(node), "must only call this function on known names"); - if (nameIsEvalAnyParentheses(node, cx)) + if (isEvalAnyParentheses(node, cx)) return js_eval_str; - if (node->pn_atom == cx->names().arguments) + if (isArgumentsAnyParentheses(node, cx)) return js_arguments_str; return nullptr; } - bool nameIsUnparenthesizedAsync(ParseNode* node, ExclusiveContext* cx) { - MOZ_ASSERT(isNameAnyParentheses(node), - "must only call this function on known names"); - - return node->pn_atom == cx->names().async; + bool isAsyncKeyword(ParseNode* node, ExclusiveContext* cx) { + return node->isKind(PNK_NAME) && + node->pn_pos.begin + strlen("async") == node->pn_pos.end && + node->pn_atom == cx->names().async; } bool isCall(ParseNode* pn) { diff --git a/js/src/frontend/GenerateReservedWords.py b/js/src/frontend/GenerateReservedWords.py new file mode 100644 index 000000000..bd698cc5f --- /dev/null +++ b/js/src/frontend/GenerateReservedWords.py @@ -0,0 +1,213 @@ +# 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/. + +import re +import sys + +def read_reserved_word_list(filename): + macro_pat = re.compile(r"^\s*macro\(([^,]+), *[^,]+, *[^\)]+\)\s*\\?$") + + reserved_word_list = [] + index = 0 + with open(filename, 'r') as f: + for line in f: + m = macro_pat.search(line) + if m: + reserved_word_list.append((index, m.group(1))) + index += 1 + + assert(len(reserved_word_list) != 0) + + return reserved_word_list + +def line(opt, s): + opt['output'].write('{}{}\n'.format(' ' * opt['indent_level'], s)) + +def indent(opt): + opt['indent_level'] += 1 + +def dedent(opt): + opt['indent_level'] -= 1 + +def span_and_count_at(reserved_word_list, column): + assert(len(reserved_word_list) != 0); + + chars_dict = {} + for index, word in reserved_word_list: + chars_dict[ord(word[column])] = True + + chars = sorted(chars_dict.keys()) + return chars[-1] - chars[0] + 1, len(chars) + +def optimal_switch_column(opt, reserved_word_list, columns, unprocessed_columns): + assert(len(reserved_word_list) != 0); + assert(unprocessed_columns != 0); + + min_count = 0 + min_span = 0 + min_count_index = 0 + min_span_index = 0 + + for index in range(0, unprocessed_columns): + span, count = span_and_count_at(reserved_word_list, columns[index]) + assert(span != 0) + + if span == 1: + assert(count == 1) + return 1, True + + assert(count != 1) + if index == 0 or min_span > span: + min_span = span + min_span_index = index + + if index == 0 or min_count > count: + min_count = count + min_count_index = index + + if min_count <= opt['use_if_threshold']: + return min_count_index, True + + return min_span_index, False + +def split_list_per_column(reserved_word_list, column): + assert(len(reserved_word_list) != 0); + + column_dict = {} + for item in reserved_word_list: + index, word = item + per_column = column_dict.setdefault(word[column], []) + per_column.append(item) + + return sorted(column_dict.items(), key=lambda (char, word): ord(char)) + +def generate_letter_switch(opt, unprocessed_columns, reserved_word_list, + columns=None): + assert(len(reserved_word_list) != 0); + + if not columns: + columns = range(0, unprocessed_columns) + + if len(reserved_word_list) == 1: + index, word = reserved_word_list[0] + + if unprocessed_columns == 0: + line(opt, 'JSRW_GOT_MATCH({}) /* {} */'.format(index, word)) + return + + if unprocessed_columns > opt['char_tail_test_threshold']: + line(opt, 'JSRW_TEST_GUESS({}) /* {} */'.format(index, word)) + return + + conds = [] + for column in columns[0:unprocessed_columns]: + quoted = repr(word[column]) + conds.append('JSRW_AT({})=={}'.format(column, quoted)) + + line(opt, 'if ({}) {{'.format(' && '.join(conds))) + + indent(opt) + line(opt, 'JSRW_GOT_MATCH({}) /* {} */'.format(index, word)) + dedent(opt) + + line(opt, '}') + line(opt, 'JSRW_NO_MATCH()') + return + + assert(unprocessed_columns != 0); + + optimal_column_index, use_if = optimal_switch_column(opt, reserved_word_list, + columns, + unprocessed_columns) + optimal_column = columns[optimal_column_index] + + # Make a copy to avoid breaking passed list. + columns = columns[:] + columns[optimal_column_index] = columns[unprocessed_columns - 1] + + list_per_column = split_list_per_column(reserved_word_list, optimal_column) + + if not use_if: + line(opt, 'switch (JSRW_AT({})) {{'.format(optimal_column)) + + for char, reserved_word_list_per_column in list_per_column: + quoted = repr(char) + if use_if: + line(opt, 'if (JSRW_AT({}) == {}) {{'.format(optimal_column, + quoted)) + else: + line(opt, ' case {}:'.format(quoted)) + + indent(opt) + generate_letter_switch(opt, unprocessed_columns - 1, + reserved_word_list_per_column, columns) + dedent(opt) + + if use_if: + line(opt, '}') + + if not use_if: + line(opt, '}') + + line(opt, 'JSRW_NO_MATCH()') + +def split_list_per_length(reserved_word_list): + assert(len(reserved_word_list) != 0); + + length_dict = {} + for item in reserved_word_list: + index, word = item + per_length = length_dict.setdefault(len(word), []) + per_length.append(item) + + return sorted(length_dict.items(), key=lambda (length, word): length) + +def generate_switch(opt, reserved_word_list): + assert(len(reserved_word_list) != 0); + + line(opt, '/*') + line(opt, ' * Generating switch for the list of {} entries:'.format(len(reserved_word_list))) + for index, word in reserved_word_list: + line(opt, ' * {}'.format(word)) + line(opt, ' */') + + list_per_length = split_list_per_length(reserved_word_list) + + use_if = False + if len(list_per_length) < opt['use_if_threshold']: + use_if = True + + if not use_if: + line(opt, 'switch (JSRW_LENGTH()) {') + + for length, reserved_word_list_per_length in list_per_length: + if use_if: + line(opt, 'if (JSRW_LENGTH() == {}) {{'.format(length)) + else: + line(opt, ' case {}:'.format(length)) + + indent(opt) + generate_letter_switch(opt, length, reserved_word_list_per_length) + dedent(opt) + + if use_if: + line(opt, '}') + + if not use_if: + line(opt, '}') + line(opt, 'JSRW_NO_MATCH()') + +def main(output, reserved_words_h): + reserved_word_list = read_reserved_word_list(reserved_words_h) + + opt = { + 'indent_level': 1, + 'use_if_threshold': 3, + 'char_tail_test_threshold': 4, + 'output': output + } + generate_switch(opt, reserved_word_list) + +if __name__ == '__main__': + main(sys.stdout, *sys.argv[1:]) diff --git a/js/src/frontend/NameAnalysisTypes.h b/js/src/frontend/NameAnalysisTypes.h index d39e177fb..2d327c827 100644 --- a/js/src/frontend/NameAnalysisTypes.h +++ b/js/src/frontend/NameAnalysisTypes.h @@ -78,6 +78,7 @@ enum class DeclarationKind : uint8_t Const, Import, BodyLevelFunction, + ModuleBodyLevelFunction, LexicalFunction, VarForAnnexBLexicalFunction, SimpleCatchParameter, @@ -95,6 +96,7 @@ DeclarationKindToBindingKind(DeclarationKind kind) case DeclarationKind::Var: case DeclarationKind::BodyLevelFunction: + case DeclarationKind::ModuleBodyLevelFunction: case DeclarationKind::VarForAnnexBLexicalFunction: case DeclarationKind::ForOfVar: return BindingKind::Var; @@ -124,6 +126,7 @@ DeclarationKindIsLexical(DeclarationKind kind) // Used in Parser to track declared names. class DeclaredNameInfo { + uint32_t pos_; DeclarationKind kind_; // If the declared name is a binding, whether the binding is closed @@ -132,8 +135,9 @@ class DeclaredNameInfo bool closedOver_; public: - explicit DeclaredNameInfo(DeclarationKind kind) - : kind_(kind), + explicit DeclaredNameInfo(DeclarationKind kind, uint32_t pos) + : pos_(pos), + kind_(kind), closedOver_(false) { } @@ -144,6 +148,12 @@ class DeclaredNameInfo return kind_; } + static const uint32_t npos = uint32_t(-1); + + uint32_t pos() const { + return pos_; + } + void alterKind(DeclarationKind kind) { kind_ = kind; } diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index ce1318f0b..dc54d0a88 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -316,7 +316,8 @@ class NameResolver return false; // Next is the callsite object node. This node only contains - // internal strings and an array -- no user-controlled expressions. + // internal strings or undefined and an array -- no user-controlled + // expressions. element = element->pn_next; #ifdef DEBUG { @@ -326,7 +327,7 @@ class NameResolver for (ParseNode* kid = array->pn_head; kid; kid = kid->pn_next) MOZ_ASSERT(kid->isKind(PNK_TEMPLATE_STRING)); for (ParseNode* next = array->pn_next; next; next = next->pn_next) - MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING)); + MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING) || next->isKind(PNK_RAW_UNDEFINED)); } #endif @@ -382,6 +383,7 @@ class NameResolver case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_ELISION: case PNK_GENERATOR: case PNK_NUMBER: diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 91f17625c..5fe64e3d3 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -190,6 +190,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) case PNK_TRUE: case PNK_FALSE: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_ELISION: case PNK_GENERATOR: case PNK_NUMBER: @@ -685,6 +686,7 @@ NullaryNode::dump() case PNK_TRUE: fprintf(stderr, "#true"); break; case PNK_FALSE: fprintf(stderr, "#false"); break; case PNK_NULL: fprintf(stderr, "#null"); break; + case PNK_RAW_UNDEFINED: fprintf(stderr, "#undefined"); break; case PNK_NUMBER: { ToCStringBuf cbuf; diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index c3523afe4..1f20f3988 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -54,6 +54,7 @@ class ObjectBox; F(TRUE) \ F(FALSE) \ F(NULL) \ + F(RAW_UNDEFINED) \ F(THIS) \ F(FUNCTION) \ F(MODULE) \ @@ -406,7 +407,8 @@ IsTypeofKind(ParseNodeKind kind) * PNK_NUMBER dval pn_dval: double value of numeric literal * PNK_TRUE, nullary pn_op: JSOp bytecode * PNK_FALSE, - * PNK_NULL + * PNK_NULL, + * PNK_RAW_UNDEFINED * * PNK_THIS, unary pn_kid: '.this' Name if function `this`, else nullptr * PNK_SUPERBASE unary pn_kid: '.this' Name @@ -686,7 +688,8 @@ class ParseNode isKind(PNK_STRING) || isKind(PNK_TRUE) || isKind(PNK_FALSE) || - isKind(PNK_NULL); + isKind(PNK_NULL) || + isKind(PNK_RAW_UNDEFINED); } /* Return true if this node appears in a Directive Prologue. */ @@ -1141,6 +1144,16 @@ class NullLiteral : public ParseNode explicit NullLiteral(const TokenPos& pos) : ParseNode(PNK_NULL, JSOP_NULL, PN_NULLARY, pos) { } }; +// This is only used internally, currently just for tagged templates. +// It represents the value 'undefined' (aka `void 0`), like NullLiteral +// represents the value 'null'. +class RawUndefinedLiteral : public ParseNode +{ + public: + explicit RawUndefinedLiteral(const TokenPos& pos) + : ParseNode(PNK_RAW_UNDEFINED, JSOP_UNDEFINED, PN_NULLARY, pos) { } +}; + class BooleanLiteral : public ParseNode { public: @@ -1296,8 +1309,9 @@ struct ClassNames : public BinaryNode { }; struct ClassNode : public TernaryNode { - ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock) - : TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock) + ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock, + const TokenPos& pos) + : TernaryNode(PNK_CLASS, JSOP_NOP, names, heritage, methodsOrBlock, pos) { MOZ_ASSERT_IF(names, names->is<ClassNames>()); MOZ_ASSERT(methodsOrBlock->is<LexicalScopeNode>() || @@ -1361,6 +1375,7 @@ ParseNode::isConstant() case PNK_STRING: case PNK_TEMPLATE_STRING: case PNK_NULL: + case PNK_RAW_UNDEFINED: case PNK_FALSE: case PNK_TRUE: return true; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 3b7a0e612..0c279591f 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -19,6 +19,8 @@ #include "frontend/Parser.h" +#include "mozilla/Sprintf.h" + #include <new> #include "jsapi.h" @@ -62,19 +64,33 @@ using AddDeclaredNamePtr = ParseContext::Scope::AddDeclaredNamePtr; using BindingIter = ParseContext::Scope::BindingIter; using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr; -/* Read a token. Report an error and return null() if that token isn't of type tt. */ -#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \ +// Read a token. Report an error and return null() if that token doesn't match +// to the condition. Do not use MUST_MATCH_TOKEN_INTERNAL directly. +#define MUST_MATCH_TOKEN_INTERNAL(cond, modifier, errorReport) \ JS_BEGIN_MACRO \ TokenKind token; \ if (!tokenStream.getToken(&token, modifier)) \ return null(); \ - if (token != tt) { \ - error(errorNumber); \ + if (!(cond)) { \ + errorReport; \ return null(); \ } \ JS_END_MACRO -#define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errno) +#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \ + MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, error(errorNumber)) + +#define MUST_MATCH_TOKEN(tt, errorNumber) \ + MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errorNumber) + +#define MUST_MATCH_TOKEN_FUNC_MOD(func, modifier, errorNumber) \ + MUST_MATCH_TOKEN_INTERNAL((func)(token), modifier, error(errorNumber)) + +#define MUST_MATCH_TOKEN_FUNC(func, errorNumber) \ + MUST_MATCH_TOKEN_FUNC_MOD(func, TokenStream::None, errorNumber) + +#define MUST_MATCH_TOKEN_MOD_WITH_REPORT(tt, modifier, errorReport) \ + MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, errorReport) template <class T, class U> static inline void @@ -106,6 +122,7 @@ DeclarationKindString(DeclarationKind kind) case DeclarationKind::Import: return "import"; case DeclarationKind::BodyLevelFunction: + case DeclarationKind::ModuleBodyLevelFunction: case DeclarationKind::LexicalFunction: return "function"; case DeclarationKind::VarForAnnexBLexicalFunction: @@ -127,7 +144,8 @@ StatementKindIsBraced(StatementKind kind) kind == StatementKind::Switch || kind == StatementKind::Try || kind == StatementKind::Catch || - kind == StatementKind::Finally; + kind == StatementKind::Finally || + kind == StatementKind::Class; } void @@ -189,11 +207,12 @@ ParseContext::Scope::addCatchParameters(ParseContext* pc, Scope& catchParamScope for (DeclaredNameMap::Range r = catchParamScope.declared_->all(); !r.empty(); r.popFront()) { DeclarationKind kind = r.front().value()->kind(); + uint32_t pos = r.front().value()->pos(); MOZ_ASSERT(DeclarationKindIsCatchParameter(kind)); JSAtom* name = r.front().key(); AddDeclaredNamePtr p = lookupDeclaredNameForAdd(name); MOZ_ASSERT(!p); - if (!addDeclaredName(pc, p, name, kind)) + if (!addDeclaredName(pc, p, name, kind, pos)) return false; } @@ -332,7 +351,8 @@ ParseContext::init() namedLambdaScope_->lookupDeclaredNameForAdd(fun->explicitName()); MOZ_ASSERT(!p); if (!namedLambdaScope_->addDeclaredName(this, p, fun->explicitName(), - DeclarationKind::Const)) + DeclarationKind::Const, + DeclaredNameInfo::npos)) { return false; } @@ -441,7 +461,7 @@ UsedNameTracker::rewind(RewindToken token) } FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, - JSFunction* fun, uint32_t preludeStart, + JSFunction* fun, uint32_t toStringStart, Directives directives, bool extraWarnings, GeneratorKind generatorKind, FunctionAsyncKind asyncKind) : ObjectBox(fun, traceListHead), @@ -455,7 +475,8 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac bufEnd(0), startLine(1), startColumn(0), - preludeStart(preludeStart), + toStringStart(toStringStart), + toStringEnd(0), length(0), generatorKindBits_(GeneratorKindAsBits(generatorKind)), asyncKindBits_(AsyncKindAsBits(asyncKind)), @@ -474,6 +495,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac usesThis(false), usesReturn(false), hasRest_(false), + isExprBody_(false), funCxFlags() { // Functions created at parse time may be set singleton after parsing and @@ -525,10 +547,16 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt allowNewTarget_ = true; allowSuperProperty_ = fun->allowSuperProperty(); - if (kind == DerivedClassConstructor) { - setDerivedClassConstructor(); - allowSuperCall_ = true; - needsThisTDZChecks_ = true; + if (kind == ClassConstructor || kind == DerivedClassConstructor) { + auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>(); + MOZ_ASSERT(stmt); + stmt->constructorBox = this; + + if (kind == DerivedClassConstructor) { + setDerivedClassConstructor(); + allowSuperCall_ = true; + needsThisTDZChecks_ = true; + } } if (isGenexpLambda) @@ -570,97 +598,136 @@ FunctionBox::initWithEnclosingScope(Scope* enclosingScope) computeInWith(enclosingScope); } -template <typename ParseHandler> void -Parser<ParseHandler>::error(unsigned errorNumber, ...) +ParserBase::error(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); #ifdef DEBUG bool result = #endif - tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_ERROR, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(nullptr, pos().begin, JSREPORT_ERROR, + errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } -template <typename ParseHandler> void -Parser<ParseHandler>::errorAt(uint32_t offset, unsigned errorNumber, ...) +ParserBase::errorWithNotes(UniquePtr<JSErrorNotes> notes, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); #ifdef DEBUG bool result = #endif - tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(Move(notes), pos().begin, JSREPORT_ERROR, + errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + +void +ParserBase::errorAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + +void +ParserBase::errorWithNotesAt(UniquePtr<JSErrorNotes> notes, uint32_t offset, + unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + tokenStream.reportCompileErrorNumberVA(Move(notes), offset, JSREPORT_ERROR, + errorNumber, args); MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } -template <typename ParseHandler> bool -Parser<ParseHandler>::warning(unsigned errorNumber, ...) +ParserBase::warning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); bool result = - tokenStream.reportCompileErrorNumberVA(pos().begin, JSREPORT_WARNING, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(nullptr, pos().begin, JSREPORT_WARNING, + errorNumber, args); va_end(args); return result; } -template <typename ParseHandler> bool -Parser<ParseHandler>::warningAt(uint32_t offset, unsigned errorNumber, ...) +ParserBase::warningAt(uint32_t offset, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); bool result = - tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_WARNING, + errorNumber, args); va_end(args); return result; } -template <typename ParseHandler> bool -Parser<ParseHandler>::extraWarning(unsigned errorNumber, ...) +ParserBase::extraWarning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = tokenStream.reportExtraWarningErrorNumberVA(pos().begin, errorNumber, args); + bool result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, pos().begin, + errorNumber, args); va_end(args); return result; } -template <typename ParseHandler> bool -Parser<ParseHandler>::strictModeError(unsigned errorNumber, ...) +ParserBase::extraWarningAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); + + bool result = + tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset, errorNumber, args); + + va_end(args); + return result; +} + +bool +ParserBase::strictModeError(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); bool res = - tokenStream.reportStrictModeErrorNumberVA(pos().begin, pc->sc()->strict(), + tokenStream.reportStrictModeErrorNumberVA(nullptr, pos().begin, pc->sc()->strict(), errorNumber, args); va_end(args); return res; } -template <typename ParseHandler> bool -Parser<ParseHandler>::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...) +ParserBase::strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); bool res = - tokenStream.reportStrictModeErrorNumberVA(offset, pc->sc()->strict(), errorNumber, args); + tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, pc->sc()->strict(), + errorNumber, args); va_end(args); return res; } -template <typename ParseHandler> bool -Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...) +ParserBase::reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); @@ -668,17 +735,21 @@ Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned uint32_t offset = TokenStream::NoOffset; switch (kind) { case ParseError: - result = tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_ERROR, errorNumber, args); + result = tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR, + errorNumber, args); break; case ParseWarning: result = - tokenStream.reportCompileErrorNumberVA(offset, JSREPORT_WARNING, errorNumber, args); + tokenStream.reportCompileErrorNumberVA(nullptr, offset, JSREPORT_WARNING, + errorNumber, args); break; case ParseExtraWarning: - result = tokenStream.reportExtraWarningErrorNumberVA(offset, errorNumber, args); + result = tokenStream.reportExtraWarningErrorNumberVA(nullptr, offset, + errorNumber, args); break; case ParseStrictError: - result = tokenStream.reportStrictModeErrorNumberVA(offset, strict, errorNumber, args); + result = tokenStream.reportStrictModeErrorNumberVA(nullptr, offset, strict, + errorNumber, args); break; } va_end(args); @@ -686,7 +757,7 @@ Parser<ParseHandler>::reportNoOffset(ParseReportKind kind, bool strict, unsigned } template <> -bool +inline bool Parser<FullParseHandler>::abortIfSyntaxParser() { handler.disableSyntaxParser(); @@ -694,23 +765,21 @@ Parser<FullParseHandler>::abortIfSyntaxParser() } template <> -bool +inline bool Parser<SyntaxParseHandler>::abortIfSyntaxParser() { abortedSyntaxParse = true; return false; } -template <typename ParseHandler> -Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc, - const ReadOnlyCompileOptions& options, - const char16_t* chars, size_t length, - bool foldConstants, - UsedNameTracker& usedNames, - Parser<SyntaxParseHandler>* syntaxParser, - LazyScript* lazyOuterFunction) - : AutoGCRooter(cx, PARSER), - context(cx), +ParserBase::ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, + const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + bool foldConstants, + UsedNameTracker& usedNames, + Parser<SyntaxParseHandler>* syntaxParser, + LazyScript* lazyOuterFunction) + : context(cx), alloc(alloc), tokenStream(cx, options, chars, length, thisForCtor()), traceListHead(nullptr), @@ -725,17 +794,44 @@ Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc, #endif abortedSyntaxParse(false), isUnexpectedEOF_(false), - handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction) + awaitIsKeyword_(false) { cx->perThreadData->frontendCollectionPool.addActiveCompilation(); + tempPoolMark = alloc.mark(); +} + +ParserBase::~ParserBase() +{ + alloc.release(tempPoolMark); + + /* + * The parser can allocate enormous amounts of memory for large functions. + * Eagerly free the memory now (which otherwise won't be freed until the + * next GC) to avoid unnecessary OOMs. + */ + alloc.freeAllIfHugeAndUnused(); + + context->perThreadData->frontendCollectionPool.removeActiveCompilation(); +} +template <typename ParseHandler> +Parser<ParseHandler>::Parser(ExclusiveContext* cx, LifoAlloc& alloc, + const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, + bool foldConstants, + UsedNameTracker& usedNames, + Parser<SyntaxParseHandler>* syntaxParser, + LazyScript* lazyOuterFunction) + : ParserBase(cx, alloc, options, chars, length, foldConstants, usedNames, syntaxParser, + lazyOuterFunction), + AutoGCRooter(cx, PARSER), + handler(cx, alloc, tokenStream, syntaxParser, lazyOuterFunction) +{ // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings // which are not generated if functions are parsed lazily. Note that the // standard "use strict" does not inhibit lazy parsing. if (options.extraWarningsOption) handler.disableSyntaxParser(); - - tempPoolMark = alloc.mark(); } template<typename ParseHandler> @@ -746,26 +842,29 @@ Parser<ParseHandler>::checkOptions() checkOptionsCalled = true; #endif - if (!tokenStream.checkOptions()) - return false; - - return true; + return tokenStream.checkOptions(); } template <typename ParseHandler> Parser<ParseHandler>::~Parser() { MOZ_ASSERT(checkOptionsCalled); - alloc.release(tempPoolMark); +} - /* - * The parser can allocate enormous amounts of memory for large functions. - * Eagerly free the memory now (which otherwise won't be freed until the - * next GC) to avoid unnecessary OOMs. - */ - alloc.freeAllIfHugeAndUnused(); +template <> +void +Parser<SyntaxParseHandler>::setAwaitIsKeyword(bool isKeyword) +{ + awaitIsKeyword_ = isKeyword; +} - context->perThreadData->frontendCollectionPool.removeActiveCompilation(); +template <> +void +Parser<FullParseHandler>::setAwaitIsKeyword(bool isKeyword) +{ + awaitIsKeyword_ = isKeyword; + if (Parser<SyntaxParseHandler>* parser = handler.syntaxParser) + parser->setAwaitIsKeyword(isKeyword); } template <typename ParseHandler> @@ -795,7 +894,7 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj) template <typename ParseHandler> FunctionBox* -Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart, +Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart, Directives inheritedDirectives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB) @@ -811,7 +910,7 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeS * function. */ FunctionBox* funbox = - alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, preludeStart, + alloc.new_<FunctionBox>(context, alloc, traceListHead, fun, toStringStart, inheritedDirectives, options().extraWarningsOption, generatorKind, asyncKind); if (!funbox) { @@ -894,38 +993,17 @@ Parser<ParseHandler>::parse() /* * Strict mode forbids introducing new definitions for 'eval', 'arguments', or - * for any strict mode reserved keyword. + * for any strict mode reserved word. */ -template <typename ParseHandler> bool -Parser<ParseHandler>::isValidStrictBinding(PropertyName* name) +ParserBase::isValidStrictBinding(PropertyName* name) { return name != context->names().eval && name != context->names().arguments && name != context->names().let && name != context->names().static_ && - !(IsKeyword(name) && name != context->names().await); -} - -/* - * Check that it is permitted to introduce a binding for |name|. Use |pos| for - * reporting error locations. - */ -template <typename ParseHandler> -bool -Parser<ParseHandler>::checkStrictBinding(PropertyName* name, TokenPos pos) -{ - if (!pc->sc()->needStrictChecks()) - return true; - - if (!isValidStrictBinding(name)) { - JSAutoByteString bytes; - if (!AtomToPrintableString(context, name, &bytes)) - return false; - return strictModeErrorAt(pos.begin, JSMSG_BAD_BINDING, bytes.ptr()); - } - - return true; + name != context->names().yield && + !IsStrictReservedWord(name); } /* @@ -952,13 +1030,71 @@ Parser<ParseHandler>::hasValidSimpleStrictParameterNames() template <typename ParseHandler> void -Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKind kind, - TokenPos pos) +Parser<ParseHandler>::reportMissingClosing(unsigned errorNumber, unsigned noteNumber, + uint32_t openedPos) +{ + auto notes = MakeUnique<JSErrorNotes>(); + if (!notes) + return; + + uint32_t line, column; + tokenStream.srcCoords.lineNumAndColumnIndex(openedPos, &line, &column); + + const size_t MaxWidth = sizeof("4294967295"); + char columnNumber[MaxWidth]; + SprintfLiteral(columnNumber, "%" PRIu32, column); + char lineNumber[MaxWidth]; + SprintfLiteral(lineNumber, "%" PRIu32, line); + + if (!notes->addNoteASCII(pc->sc()->context, + getFilename(), line, column, + GetErrorMessage, nullptr, + noteNumber, lineNumber, columnNumber)) + { + return; + } + + errorWithNotes(Move(notes), errorNumber); +} + +template <typename ParseHandler> +void +Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind, + TokenPos pos, uint32_t prevPos) { JSAutoByteString bytes; if (!AtomToPrintableString(context, name, &bytes)) return; - errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(kind), bytes.ptr()); + + if (prevPos == DeclaredNameInfo::npos) { + errorAt(pos.begin, JSMSG_REDECLARED_VAR, DeclarationKindString(prevKind), bytes.ptr()); + return; + } + + auto notes = MakeUnique<JSErrorNotes>(); + if (!notes) + return; + + uint32_t line, column; + tokenStream.srcCoords.lineNumAndColumnIndex(prevPos, &line, &column); + + const size_t MaxWidth = sizeof("4294967295"); + char columnNumber[MaxWidth]; + SprintfLiteral(columnNumber, "%" PRIu32, column); + char lineNumber[MaxWidth]; + SprintfLiteral(lineNumber, "%" PRIu32, line); + + if (!notes->addNoteASCII(pc->sc()->context, + getFilename(), line, column, + GetErrorMessage, nullptr, + JSMSG_REDECLARED_PREV, + lineNumber, columnNumber)) + { + return; + } + + errorWithNotesAt(Move(notes), pos.begin, JSMSG_REDECLARED_VAR, + DeclarationKindString(prevKind), bytes.ptr()); } // notePositionalFormalParameter is called for both the arguments of a regular @@ -973,6 +1109,7 @@ Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKi template <typename ParseHandler> bool Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName name, + uint32_t beginPos, bool disallowDuplicateParams, bool* duplicatedParam) { @@ -997,7 +1134,7 @@ Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName *duplicatedParam = true; } else { DeclarationKind kind = DeclarationKind::PositionalFormalParameter; - if (!pc->functionScope().addDeclaredName(pc, p, name, kind)) + if (!pc->functionScope().addDeclaredName(pc, p, name, kind, beginPos)) return false; } @@ -1010,9 +1147,6 @@ Parser<ParseHandler>::notePositionalFormalParameter(Node fn, HandlePropertyName if (!paramNode) return false; - if (!checkStrictBinding(name, pos())) - return false; - handler.addFunctionFormalParameter(fn, paramNode); return true; } @@ -1104,8 +1238,8 @@ DeclarationKindIsParameter(DeclarationKind kind) template <typename ParseHandler> bool -Parser<ParseHandler>::tryDeclareVar(HandlePropertyName name, DeclarationKind kind, - Maybe<DeclarationKind>* redeclaredKind) +Parser<ParseHandler>::tryDeclareVar(HandlePropertyName name, DeclarationKind kind, uint32_t beginPos, + Maybe<DeclarationKind>* redeclaredKind, uint32_t* prevPos) { MOZ_ASSERT(DeclarationKindIsVar(kind)); @@ -1178,17 +1312,29 @@ Parser<ParseHandler>::tryDeclareVar(HandlePropertyName name, DeclarationKind kin if (!annexB35Allowance && !annexB33Allowance) { *redeclaredKind = Some(declaredKind); + *prevPos = p->value()->pos(); return true; } + } else if (kind == DeclarationKind::VarForAnnexBLexicalFunction) { + MOZ_ASSERT(DeclarationKindIsParameter(declaredKind)); + + // Annex B.3.3.1 disallows redeclaring parameter names. + // We don't need to set *prevPos here since this case is not + // an error. + *redeclaredKind = Some(declaredKind); + return true; } } else { - if (!scope->addDeclaredName(pc, p, name, kind)) + if (!scope->addDeclaredName(pc, p, name, kind, beginPos)) return false; } } - if (!pc->sc()->strict() && pc->sc()->isEvalContext()) + if (!pc->sc()->strict() && pc->sc()->isEvalContext()) { *redeclaredKind = isVarRedeclaredInEval(name, kind); + // We don't have position information at runtime. + *prevPos = DeclaredNameInfo::npos; + } return true; } @@ -1196,11 +1342,34 @@ Parser<ParseHandler>::tryDeclareVar(HandlePropertyName name, DeclarationKind kin template <typename ParseHandler> bool Parser<ParseHandler>::tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, - bool* tryAnnexB) + uint32_t beginPos, bool* tryAnnexB) { Maybe<DeclarationKind> redeclaredKind; - if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, &redeclaredKind)) + uint32_t unused; + if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, beginPos, + &redeclaredKind, &unused)) + { return false; + } + + if (!redeclaredKind && pc->isFunctionBox()) { + ParseContext::Scope& funScope = pc->functionScope(); + ParseContext::Scope& varScope = pc->varScope(); + if (&funScope != &varScope) { + // Annex B.3.3.1 disallows redeclaring parameter names. In the + // presence of parameter expressions, parameter names are on the + // function scope, which encloses the var scope. This means + // tryDeclareVar call above would not catch this case, so test it + // manually. + if (AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(name)) { + DeclarationKind declaredKind = p->value()->kind(); + if (DeclarationKindIsParameter(declaredKind)) + redeclaredKind = Some(declaredKind); + else + MOZ_ASSERT(FunctionScope::isSpecialName(context, name)); + } + } + } if (redeclaredKind) { // If an early error would have occurred, undo all the @@ -1248,25 +1417,41 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind if (pc->useAsmOrInsideUseAsm()) return true; - if (!checkStrictBinding(name, pos)) - return false; - switch (kind) { case DeclarationKind::Var: case DeclarationKind::BodyLevelFunction: case DeclarationKind::ForOfVar: { Maybe<DeclarationKind> redeclaredKind; - if (!tryDeclareVar(name, kind, &redeclaredKind)) + uint32_t prevPos; + if (!tryDeclareVar(name, kind, pos.begin, &redeclaredKind, &prevPos)) return false; if (redeclaredKind) { - reportRedeclaration(name, *redeclaredKind, pos); + reportRedeclaration(name, *redeclaredKind, pos, prevPos); return false; } break; } + case DeclarationKind::ModuleBodyLevelFunction: { + MOZ_ASSERT(pc->atModuleLevel()); + + AddDeclaredNamePtr p = pc->varScope().lookupDeclaredNameForAdd(name); + if (p) { + reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos()); + return false; + } + + if (!pc->varScope().addDeclaredName(pc, p, name, kind, pos.begin)) + return false; + + // Body-level functions in modules are always closed over. + pc->varScope().lookupDeclaredName(name)->value()->setClosedOver(); + + break; + } + case DeclarationKind::FormalParameter: { // It is an early error if any non-positional formal parameter name // (e.g., destructuring formal parameter) is duplicated. @@ -1277,7 +1462,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind return false; } - if (!pc->functionScope().addDeclaredName(pc, p, name, kind)) + if (!pc->functionScope().addDeclaredName(pc, p, name, kind, pos.begin)) return false; break; @@ -1300,7 +1485,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind (p->value()->kind() != DeclarationKind::LexicalFunction && p->value()->kind() != DeclarationKind::VarForAnnexBLexicalFunction)) { - reportRedeclaration(name, p->value()->kind(), pos); + reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos()); return false; } @@ -1308,7 +1493,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind // declaration that shadows the VarForAnnexBLexicalFunction. p->value()->alterKind(kind); } else { - if (!scope->addDeclaredName(pc, p, name, kind)) + if (!scope->addDeclaredName(pc, p, name, kind, pos.begin)) return false; } @@ -1348,7 +1533,7 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind if (pc->isFunctionExtraBodyVarScopeInnermost()) { DeclaredNamePtr p = pc->functionScope().lookupDeclaredName(name); if (p && DeclarationKindIsParameter(p->value()->kind())) { - reportRedeclaration(name, p->value()->kind(), pos); + reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos()); return false; } } @@ -1365,12 +1550,12 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind p = scope->lookupDeclaredNameForAdd(name); MOZ_ASSERT(!p); } else { - reportRedeclaration(name, p->value()->kind(), pos); + reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos()); return false; } } - if (!p && !scope->addDeclaredName(pc, p, name, kind)) + if (!p && !scope->addDeclaredName(pc, p, name, kind, pos.begin)) return false; break; @@ -1742,11 +1927,8 @@ Parser<FullParseHandler>::newFunctionScopeData(ParseContext::Scope& scope, bool case BindingKind::Var: // The only vars in the function scope when there are parameter // exprs, which induces a separate var environment, should be the - // special internal bindings. - MOZ_ASSERT_IF(hasParameterExprs, - bi.name() == context->names().arguments || - bi.name() == context->names().dotThis || - bi.name() == context->names().dotGenerator); + // special bindings. + MOZ_ASSERT_IF(hasParameterExprs, FunctionScope::isSpecialName(context, bi.name())); if (!vars.append(binding)) return Nothing(); break; @@ -2031,7 +2213,7 @@ Parser<FullParseHandler>::moduleBody(ModuleSharedContext* modulesc) if (!mn) return null(); - AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, true); + AutoAwaitIsKeyword<FullParseHandler> awaitIsKeyword(this, true); ParseNode* pn = statementList(YieldIsKeyword); if (!pn) return null(); @@ -2123,8 +2305,11 @@ Parser<ParseHandler>::declareFunctionThis() ParseContext::Scope& funScope = pc->functionScope(); AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotThis); MOZ_ASSERT(!p); - if (!funScope.addDeclaredName(pc, p, dotThis, DeclarationKind::Var)) + if (!funScope.addDeclaredName(pc, p, dotThis, DeclarationKind::Var, + DeclaredNameInfo::npos)) + { return false; + } funbox->setHasThisBinding(); } @@ -2166,14 +2351,17 @@ Parser<ParseHandler>::declareDotGeneratorName() ParseContext::Scope& funScope = pc->functionScope(); HandlePropertyName dotGenerator = context->names().dotGenerator; AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(dotGenerator); - if (!p && !funScope.addDeclaredName(pc, p, dotGenerator, DeclarationKind::Var)) + if (!p && !funScope.addDeclaredName(pc, p, dotGenerator, DeclarationKind::Var, + DeclaredNameInfo::npos)) + { return false; + } return true; } template <typename ParseHandler> bool -Parser<ParseHandler>::finishFunctionScopes() +Parser<ParseHandler>::finishFunctionScopes(bool isStandaloneFunction) { FunctionBox* funbox = pc->functionBox(); @@ -2182,7 +2370,7 @@ Parser<ParseHandler>::finishFunctionScopes() return false; } - if (funbox->function()->isNamedLambda()) { + if (funbox->function()->isNamedLambda() && !isStandaloneFunction) { if (!propagateFreeNamesAndMarkClosedOverBindings(pc->namedLambdaScope())) return false; } @@ -2192,9 +2380,9 @@ Parser<ParseHandler>::finishFunctionScopes() template <> bool -Parser<FullParseHandler>::finishFunction() +Parser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */) { - if (!finishFunctionScopes()) + if (!finishFunctionScopes(isStandaloneFunction)) return false; FunctionBox* funbox = pc->functionBox(); @@ -2215,7 +2403,7 @@ Parser<FullParseHandler>::finishFunction() funbox->functionScopeBindings().set(*bindings); } - if (funbox->function()->isNamedLambda()) { + if (funbox->function()->isNamedLambda() && !isStandaloneFunction) { Maybe<LexicalScope::Data*> bindings = newLexicalScopeData(pc->namedLambdaScope()); if (!bindings) return false; @@ -2227,14 +2415,14 @@ Parser<FullParseHandler>::finishFunction() template <> bool -Parser<SyntaxParseHandler>::finishFunction() +Parser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false */) { // The LazyScript for a lazily parsed function needs to know its set of // free variables and inner functions so that when it is fully parsed, we // can skip over any already syntax parsed inner functions and still // retain correct scope information. - if (!finishFunctionScopes()) + if (!finishFunctionScopes(isStandaloneFunction)) return false; // There are too many bindings or inner functions to be saved into the @@ -2251,7 +2439,7 @@ Parser<SyntaxParseHandler>::finishFunction() LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(), pc->innerFunctionsForLazy, versionNumber(), funbox->bufStart, funbox->bufEnd, - funbox->preludeStart, + funbox->toStringStart, funbox->startLine, funbox->startColumn); if (!lazy) return false; @@ -2264,6 +2452,8 @@ Parser<SyntaxParseHandler>::finishFunction() lazy->setAsyncKind(funbox->asyncKind()); if (funbox->hasRest()) lazy->setHasRest(); + if (funbox->isExprBody()) + lazy->setIsExprBody(); if (funbox->isLikelyConstructorWrapper()) lazy->setLikelyConstructorWrapper(); if (funbox->isDerivedClassConstructor()) @@ -2340,7 +2530,7 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun, return null(); fn->pn_body = argsbody; - FunctionBox* funbox = newFunctionBox(fn, fun, /* preludeStart = */ 0, inheritedDirectives, + FunctionBox* funbox = newFunctionBox(fn, fun, /* toStringStart = */ 0, inheritedDirectives, generatorKind, asyncKind, /* tryAnnexB = */ false); if (!funbox) return null(); @@ -2352,9 +2542,9 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun, funpc.setIsStandaloneFunctionBody(); YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); - AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction); + AutoAwaitIsKeyword<FullParseHandler> awaitIsKeyword(this, asyncKind == AsyncFunction); if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement, - parameterListEnd)) + parameterListEnd, /* isStandaloneFunction = */ true)) { return null(); } @@ -2414,8 +2604,11 @@ Parser<ParseHandler>::declareFunctionArgumentsObject() if (tryDeclareArguments) { AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(argumentsName); if (!p) { - if (!funScope.addDeclaredName(pc, p, argumentsName, DeclarationKind::Var)) + if (!funScope.addDeclaredName(pc, p, argumentsName, DeclarationKind::Var, + DeclaredNameInfo::npos)) + { return false; + } funbox->declaredArguments = true; funbox->usesArguments = true; } else if (hasExtraBodyVarScope) { @@ -2631,39 +2824,59 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind, /* * WARNING: Do not call this function directly. - * Call either MatchOrInsertSemicolonAfterExpression or - * MatchOrInsertSemicolonAfterNonExpression instead, depending on context. + * Call either matchOrInsertSemicolonAfterExpression or + * matchOrInsertSemicolonAfterNonExpression instead, depending on context. */ -static bool -MatchOrInsertSemicolonHelper(TokenStream& ts, TokenStream::Modifier modifier) +template <typename ParseHandler> +bool +Parser<ParseHandler>::matchOrInsertSemicolonHelper(TokenStream::Modifier modifier) { TokenKind tt = TOK_EOF; - if (!ts.peekTokenSameLine(&tt, modifier)) + if (!tokenStream.peekTokenSameLine(&tt, modifier)) return false; if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) { + /* + * When current token is `await` and it's outside of async function, + * it's possibly intended to be an await expression. + * + * await f(); + * ^ + * | + * tried to insert semicolon here + * + * Detect this situation and throw an understandable error. Otherwise + * we'd throw a confusing "missing ; before statement" error. + */ + if (!pc->isAsync() && tokenStream.currentToken().type == TOK_AWAIT) { + error(JSMSG_AWAIT_OUTSIDE_ASYNC); + return false; + } + /* Advance the scanner for proper error location reporting. */ - ts.consumeKnownToken(tt, modifier); - ts.reportError(JSMSG_SEMI_BEFORE_STMNT); + tokenStream.consumeKnownToken(tt, modifier); + error(JSMSG_SEMI_BEFORE_STMNT); return false; } bool matched; - if (!ts.matchToken(&matched, TOK_SEMI, modifier)) + if (!tokenStream.matchToken(&matched, TOK_SEMI, modifier)) return false; if (!matched && modifier == TokenStream::None) - ts.addModifierException(TokenStream::OperandIsNone); + tokenStream.addModifierException(TokenStream::OperandIsNone); return true; } -static bool -MatchOrInsertSemicolonAfterExpression(TokenStream& ts) +template <typename ParseHandler> +bool +Parser<ParseHandler>::matchOrInsertSemicolonAfterExpression() { - return MatchOrInsertSemicolonHelper(ts, TokenStream::None); + return matchOrInsertSemicolonHelper(TokenStream::None); } -static bool -MatchOrInsertSemicolonAfterNonExpression(TokenStream& ts) +template <typename ParseHandler> +bool +Parser<ParseHandler>::matchOrInsertSemicolonAfterNonExpression() { - return MatchOrInsertSemicolonHelper(ts, TokenStream::Operand); + return matchOrInsertSemicolonHelper(TokenStream::Operand); } template <typename ParseHandler> @@ -2757,7 +2970,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn firstTokenModifier = funbox->isAsync() ? TokenStream::None : TokenStream::Operand; if (!tokenStream.peekToken(&tt, firstTokenModifier)) return false; - if (tt == TOK_NAME || tt == TOK_YIELD) { + if (TokenKindIsPossibleIdentifier(tt)) { parenFreeArrow = true; argModifier = firstTokenModifier; } @@ -2813,7 +3026,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt, argModifier)) return false; argModifier = TokenStream::Operand; - MOZ_ASSERT_IF(parenFreeArrow, tt == TOK_NAME || tt == TOK_YIELD); + MOZ_ASSERT_IF(parenFreeArrow, TokenKindIsPossibleIdentifier(tt)); if (tt == TOK_TRIPLEDOT) { if (IsSetterKind(kind)) { @@ -2834,7 +3047,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn if (!tokenStream.getToken(&tt)) return false; - if (tt != TOK_NAME && tt != TOK_YIELD && tt != TOK_LB && tt != TOK_LC) { + if (!TokenKindIsPossibleIdentifier(tt) && tt != TOK_LB && tt != TOK_LC) { error(JSMSG_NO_REST_NAME); return false; } @@ -2864,26 +3077,21 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn break; } - case TOK_NAME: - case TOK_YIELD: { - if (parenFreeArrow) - funbox->setStart(tokenStream); - - if (funbox->isAsync() && tokenStream.currentName() == context->names().await) { - // `await` is already gotten as TOK_NAME for the following - // case: - // - // async await => 1 - error(JSMSG_RESERVED_ID, "await"); + default: { + if (!TokenKindIsPossibleIdentifier(tt)) { + error(JSMSG_MISSING_FORMAL); return false; } + if (parenFreeArrow) + funbox->setStart(tokenStream); + RootedPropertyName name(context, bindingIdentifier(yieldHandling)); if (!name) return false; - if (!notePositionalFormalParameter(funcpn, name, disallowDuplicateParams, - &duplicatedParam)) + if (!notePositionalFormalParameter(funcpn, name, pos().begin, + disallowDuplicateParams, &duplicatedParam)) { return false; } @@ -2892,10 +3100,6 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn break; } - - default: - error(JSMSG_MISSING_FORMAL); - return false; } if (positionalFormals.length() >= ARGNO_LIMIT) { @@ -2989,7 +3193,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn template <> bool -Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeStart, +Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t toStringStart, FunctionSyntaxKind kind, bool tryAnnexB) { // When a lazily-parsed function is called, we only fully parse (and emit) @@ -2999,7 +3203,7 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS RootedFunction fun(context, handler.nextLazyInnerFunction()); MOZ_ASSERT(!fun->isLegacyGenerator()); - FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, Directives(/* strict = */ false), + FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, Directives(/* strict = */ false), fun->generatorKind(), fun->asyncKind(), tryAnnexB); if (!funbox) return false; @@ -3007,6 +3211,8 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS LazyScript* lazy = fun->lazyScript(); if (lazy->needsHomeObject()) funbox->setNeedsHomeObject(); + if (lazy->isExprBody()) + funbox->setIsExprBody(); PropagateTransitiveParseFlags(lazy, pc->sc()); @@ -3019,17 +3225,22 @@ Parser<FullParseHandler>::skipLazyInnerFunction(ParseNode* pn, uint32_t preludeS if (!tokenStream.advance(fun->lazyScript()->end() - userbufBase)) return false; - if (kind == Statement && fun->isExprBody()) { - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) +#if JS_HAS_EXPR_CLOSURES + // Only expression closure can be Statement kind. + // If we remove expression closure, we can remove isExprBody flag from + // LazyScript and JSScript. + if (kind == Statement && funbox->isExprBody()) { + if (!matchOrInsertSemicolonAfterExpression()) return false; } +#endif return true; } template <> bool -Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t preludeStart, +Parser<SyntaxParseHandler>::skipLazyInnerFunction(Node pn, uint32_t toStringStart, FunctionSyntaxKind kind, bool tryAnnexB) { MOZ_CRASH("Cannot skip lazy inner functions when syntax parsing"); @@ -3082,7 +3293,7 @@ template <typename ParseHandler> typename ParseHandler::Node Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling) { - Node pn = noSubstitutionTemplate(); + Node pn = noSubstitutionUntaggedTemplate(); if (!pn) return null(); @@ -3095,7 +3306,7 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling) if (!addExprAndGetNextTemplStrToken(yieldHandling, nodeList, &tt)) return null(); - pn = noSubstitutionTemplate(); + pn = noSubstitutionUntaggedTemplate(); if (!pn) return null(); @@ -3106,7 +3317,7 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling) template <typename ParseHandler> typename ParseHandler::Node -Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, Node pn, InHandling inHandling, +Parser<ParseHandler>::functionDefinition(uint32_t toStringStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom funName, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, @@ -3119,7 +3330,7 @@ Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, Node pn, InHandl // functions, which are also lazy. Instead, their free variables and // source extents are recorded and may be skipped. if (handler.canSkipLazyInnerFunctions()) { - if (!skipLazyInnerFunction(pn, preludeStart, kind, tryAnnexB)) + if (!skipLazyInnerFunction(pn, toStringStart, kind, tryAnnexB)) return null(); return pn; } @@ -3152,7 +3363,7 @@ Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, Node pn, InHandl // reparse a function due to failed syntax parsing and encountering new // "use foo" directives. while (true) { - if (trySyntaxParseInnerFunction(pn, fun, preludeStart, inHandling, yieldHandling, kind, + if (trySyntaxParseInnerFunction(pn, fun, toStringStart, inHandling, yieldHandling, kind, generatorKind, asyncKind, tryAnnexB, directives, &newDirectives)) { @@ -3181,7 +3392,7 @@ Parser<ParseHandler>::functionDefinition(uint32_t preludeStart, Node pn, InHandl template <> bool Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunction fun, - uint32_t preludeStart, + uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, @@ -3215,13 +3426,13 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct // Make a FunctionBox before we enter the syntax parser, because |pn| // still expects a FunctionBox to be attached to it during BCE, and // the syntax parser cannot attach one to it. - FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives, + FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, inheritedDirectives, generatorKind, asyncKind, tryAnnexB); if (!funbox) return false; funbox->initWithEnclosingParseContext(pc, kind); - if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, preludeStart, + if (!parser->innerFunction(SyntaxParseHandler::NodeGeneric, pc, funbox, toStringStart, inHandling, yieldHandling, kind, inheritedDirectives, newDirectives)) { @@ -3249,14 +3460,14 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct } while (false); // We failed to do a syntax parse above, so do the full parse. - return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind, + return innerFunction(pn, pc, fun, toStringStart, inHandling, yieldHandling, kind, generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives); } template <> bool Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction fun, - uint32_t preludeStart, + uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, @@ -3267,14 +3478,14 @@ Parser<SyntaxParseHandler>::trySyntaxParseInnerFunction(Node pn, HandleFunction Directives* newDirectives) { // This is already a syntax parser, so just parse the inner function. - return innerFunction(pn, pc, fun, preludeStart, inHandling, yieldHandling, kind, + return innerFunction(pn, pc, fun, toStringStart, inHandling, yieldHandling, kind, generatorKind, asyncKind, tryAnnexB, inheritedDirectives, newDirectives); } template <typename ParseHandler> bool Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, - uint32_t preludeStart, + uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, Directives inheritedDirectives, Directives* newDirectives) @@ -3298,7 +3509,7 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, FunctionBox* template <typename ParseHandler> bool Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, - uint32_t preludeStart, + uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, @@ -3310,13 +3521,13 @@ Parser<ParseHandler>::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti // parser. In that case, outerpc is a ParseContext from the full parser // instead of the current top of the stack of the syntax parser. - FunctionBox* funbox = newFunctionBox(pn, fun, preludeStart, inheritedDirectives, + FunctionBox* funbox = newFunctionBox(pn, fun, toStringStart, inheritedDirectives, generatorKind, asyncKind, tryAnnexB); if (!funbox) return false; funbox->initWithEnclosingParseContext(outerpc, kind); - return innerFunction(pn, outerpc, funbox, preludeStart, inHandling, yieldHandling, kind, + return innerFunction(pn, outerpc, funbox, toStringStart, inHandling, yieldHandling, kind, inheritedDirectives, newDirectives); } @@ -3324,7 +3535,7 @@ template <typename ParseHandler> bool Parser<ParseHandler>::appendToCallSiteObj(Node callSiteObj) { - Node cookedNode = noSubstitutionTemplate(); + Node cookedNode = noSubstitutionTaggedTemplate(); if (!cookedNode) return false; @@ -3352,7 +3563,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict return null(); Directives directives(strict); - FunctionBox* funbox = newFunctionBox(pn, fun, /* preludeStart = */ 0, directives, + FunctionBox* funbox = newFunctionBox(pn, fun, /* toStringStart = */ 0, directives, generatorKind, asyncKind, /* tryAnnexB = */ false); if (!funbox) return null(); @@ -3402,7 +3613,8 @@ bool Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling, Node pn, FunctionSyntaxKind kind, - Maybe<uint32_t> parameterListEnd /* = Nothing() */) + Maybe<uint32_t> parameterListEnd /* = Nothing() */, + bool isStandaloneFunction /* = false */) { // Given a properly initialized parse context, try to parse an actual // function without concern for conversion to strict mode, use of lazy @@ -3411,9 +3623,14 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling, FunctionBox* funbox = pc->functionBox(); RootedFunction fun(context, funbox->function()); - AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, funbox->isAsync()); - if (!functionArguments(yieldHandling, kind, pn)) - return false; + // See below for an explanation why arrow function parameters and arrow + // function bodies are parsed with different yield/await settings. + { + bool asyncOrArrowInAsync = funbox->isAsync() || (kind == Arrow && awaitIsKeyword()); + AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, asyncOrArrowInAsync); + if (!functionArguments(yieldHandling, kind, pn)) + return false; + } Maybe<ParseContext::VarScope> varScope; if (funbox->hasParameterExprs) { @@ -3446,6 +3663,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling, TokenKind tt; if (!tokenStream.getToken(&tt, TokenStream::Operand)) return false; + uint32_t openedPos = 0; if (tt != TOK_LC) { if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method || kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure || @@ -3466,9 +3684,9 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling, tokenStream.ungetToken(); bodyType = ExpressionBody; -#if JS_HAS_EXPR_CLOSURES - fun->setIsExprBody(); -#endif + funbox->setIsExprBody(); + } else { + openedPos = pos().begin; } // Arrow function parameters inherit yieldHandling from the enclosing @@ -3476,41 +3694,59 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling, // |yield| in the parameters is either a name or keyword, depending on // whether the arrow function is enclosed in a generator function or not. // Whereas the |yield| in the function body is always parsed as a name. + // The same goes when parsing |await| in arrow functions. YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind(), pc->asyncKind()); - Node body = functionBody(inHandling, bodyYieldHandling, kind, bodyType); - if (!body) - return false; + Node body; + { + AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, funbox->isAsync()); + body = functionBody(inHandling, bodyYieldHandling, kind, bodyType); + if (!body) + return false; + } - if ((kind != Method && !IsConstructorKind(kind)) && fun->explicitName()) { + if ((kind == Statement || kind == Expression) && fun->explicitName()) { RootedPropertyName propertyName(context, fun->explicitName()->asPropertyName()); - if (!checkStrictBinding(propertyName, handler.getPosition(pn))) + YieldHandling nameYieldHandling; + if (kind == Expression) { + // Named lambda has binding inside it. + nameYieldHandling = bodyYieldHandling; + } else { + // Otherwise YieldHandling cannot be checked at this point + // because of different context. + // It should already be checked before this point. + nameYieldHandling = YieldIsName; + } + + // We already use the correct await-handling at this point, therefore + // we don't need call AutoAwaitIsKeyword here. + + if (!checkBindingIdentifier(propertyName, handler.getPosition(pn).begin, + nameYieldHandling)) + { return false; + } } if (bodyType == StatementListBody) { - bool matched; - if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand)) - return false; - if (!matched) { - error(JSMSG_CURLY_AFTER_BODY); - return false; - } - funbox->bufEnd = pos().end; + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand, + reportMissingClosing(JSMSG_CURLY_AFTER_BODY, + JSMSG_CURLY_OPENED, openedPos)); + funbox->setEnd(pos().end); } else { #if !JS_HAS_EXPR_CLOSURES MOZ_ASSERT(kind == Arrow); #endif if (tokenStream.hadError()) return false; - funbox->bufEnd = pos().end; - if (kind == Statement && !MatchOrInsertSemicolonAfterExpression(tokenStream)) + funbox->setEnd(pos().end); + if (kind == Statement && !matchOrInsertSemicolonAfterExpression()) return false; } if (IsMethodDefinitionKind(kind) && pc->superScopeNeedsHomeObject()) funbox->setNeedsHomeObject(); - if (!finishFunction()) + if (!finishFunction(isStandaloneFunction)) return false; handler.setEndPosition(body, pos().begin); @@ -3522,26 +3758,11 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling, template <typename ParseHandler> typename ParseHandler::Node -Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHandling, +Parser<ParseHandler>::functionStmt(uint32_t toStringStart, YieldHandling yieldHandling, DefaultHandling defaultHandling, FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); - // Annex B.3.4 says we can parse function declarations unbraced under if - // or else as if it were braced. That is, |if (x) function f() {}| is - // parsed as |if (x) { function f() {} }|. - Maybe<ParseContext::Statement> synthesizedStmtForAnnexB; - Maybe<ParseContext::Scope> synthesizedScopeForAnnexB; - if (!pc->sc()->strict()) { - ParseContext::Statement* stmt = pc->innermostStatement(); - if (stmt && stmt->kind() == StatementKind::If) { - synthesizedStmtForAnnexB.emplace(pc, StatementKind::Block); - synthesizedScopeForAnnexB.emplace(this); - if (!synthesizedScopeForAnnexB->init(pc)) - return null(); - } - } - // In sloppy mode, Annex B.3.2 allows labelled function declarations. // Otherwise it's a parse error. ParseContext::Statement* declaredInStmt = pc->innermostStatement(); @@ -3577,7 +3798,7 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan } RootedPropertyName name(context); - if (tt == TOK_NAME || tt == TOK_YIELD) { + if (TokenKindIsPossibleIdentifier(tt)) { name = bindingIdentifier(yieldHandling); if (!name) return null(); @@ -3602,19 +3823,18 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan // early error, do so. This 'var' binding would be assigned // the function object when its declaration is reached, not at // the start of the block. - if (!tryDeclareVarForAnnexBLexicalFunction(name, &tryAnnexB)) + if (!tryDeclareVarForAnnexBLexicalFunction(name, pos().begin, &tryAnnexB)) return null(); } if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos())) return null(); } else { - if (!noteDeclaredName(name, DeclarationKind::BodyLevelFunction, pos())) + DeclarationKind kind = pc->atModuleLevel() + ? DeclarationKind::ModuleBodyLevelFunction + : DeclarationKind::BodyLevelFunction; + if (!noteDeclaredName(name, kind, pos())) return null(); - - // Body-level functions in modules are always closed over. - if (pc->atModuleLevel()) - pc->varScope().lookupDeclaredName(name)->value()->setClosedOver(); } Node pn = handler.newFunctionStatement(); @@ -3622,30 +3842,18 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan return null(); YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind); - Node fun = functionDefinition(preludeStart, pn, InAllowed, newYieldHandling, + return functionDefinition(toStringStart, pn, InAllowed, newYieldHandling, name, Statement, generatorKind, asyncKind, tryAnnexB); - if (!fun) - return null(); - - if (synthesizedStmtForAnnexB) { - Node synthesizedStmtList = handler.newStatementList(handler.getPosition(fun)); - if (!synthesizedStmtList) - return null(); - handler.addStatementToList(synthesizedStmtList, fun); - return finishLexicalScope(*synthesizedScopeForAnnexB, synthesizedStmtList); - } - - return fun; } template <typename ParseHandler> typename ParseHandler::Node -Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invoked, +Parser<ParseHandler>::functionExpr(uint32_t toStringStart, InvokedPrediction invoked, FunctionAsyncKind asyncKind) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); - AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction); + AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, asyncKind == AsyncFunction); GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator; TokenKind tt; if (!tokenStream.getToken(&tt)) @@ -3664,7 +3872,7 @@ Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invo YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind); RootedPropertyName name(context); - if (tt == TOK_NAME || tt == TOK_YIELD) { + if (TokenKindIsPossibleIdentifier(tt)) { name = bindingIdentifier(yieldHandling); if (!name) return null(); @@ -3679,7 +3887,7 @@ Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invo if (invoked) pn = handler.setLikelyIIFE(pn); - return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, name, Expression, + return functionDefinition(toStringStart, pn, InAllowed, yieldHandling, name, Expression, generatorKind, asyncKind); } @@ -3701,18 +3909,6 @@ IsEscapeFreeStringLiteral(const TokenPos& pos, JSAtom* str) return pos.begin + str->length() + 2 == pos.end; } -template <typename ParseHandler> -bool -Parser<ParseHandler>::checkUnescapedName() -{ - const Token& token = tokenStream.currentToken(); - if (!token.nameContainsEscape()) - return true; - - errorAt(token.pos.begin, JSMSG_ESCAPED_KEYWORD); - return false; -} - template <> bool Parser<SyntaxParseHandler>::asmJS(Node list) @@ -3931,7 +4127,7 @@ Parser<ParseHandler>::matchLabel(YieldHandling yieldHandling, MutableHandle<Prop if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand)) return false; - if (tt == TOK_NAME || tt == TOK_YIELD) { + if (TokenKindIsPossibleIdentifier(tt)) { tokenStream.consumeKnownToken(tt, TokenStream::Operand); label.set(labelIdentifier(yieldHandling)); @@ -3954,8 +4150,17 @@ Parser<ParseHandler>::PossibleError::error(ErrorKind kind) { if (kind == ErrorKind::Expression) return exprError_; - MOZ_ASSERT(kind == ErrorKind::Destructuring); - return destructuringError_; + if (kind == ErrorKind::Destructuring) + return destructuringError_; + MOZ_ASSERT(kind == ErrorKind::DestructuringWarning); + return destructuringWarning_; +} + +template <typename ParseHandler> +bool +Parser<ParseHandler>::PossibleError::hasPendingDestructuringError() +{ + return hasError(ErrorKind::Destructuring); } template <typename ParseHandler> @@ -3999,6 +4204,14 @@ Parser<ParseHandler>::PossibleError::setPendingDestructuringErrorAt(const TokenP template <typename ParseHandler> void +Parser<ParseHandler>::PossibleError::setPendingDestructuringWarningAt(const TokenPos& pos, + unsigned errorNumber) +{ + setPending(ErrorKind::DestructuringWarning, pos, errorNumber); +} + +template <typename ParseHandler> +void Parser<ParseHandler>::PossibleError::setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber) { @@ -4019,23 +4232,36 @@ Parser<ParseHandler>::PossibleError::checkForError(ErrorKind kind) template <typename ParseHandler> bool -Parser<ParseHandler>::PossibleError::checkForDestructuringError() +Parser<ParseHandler>::PossibleError::checkForWarning(ErrorKind kind) +{ + if (!hasError(kind)) + return true; + + Error& err = error(kind); + return parser_.extraWarningAt(err.offset_, err.errorNumber_); +} + +template <typename ParseHandler> +bool +Parser<ParseHandler>::PossibleError::checkForDestructuringErrorOrWarning() { // Clear pending expression error, because we're definitely not in an // expression context. setResolved(ErrorKind::Expression); - // Report any pending destructuring error. - return checkForError(ErrorKind::Destructuring); + // Report any pending destructuring error or warning. + return checkForError(ErrorKind::Destructuring) && + checkForWarning(ErrorKind::DestructuringWarning); } template <typename ParseHandler> bool Parser<ParseHandler>::PossibleError::checkForExpressionError() { - // Clear pending destructuring error, because we're definitely not in a - // destructuring context. + // Clear pending destructuring error or warning, because we're definitely + // not in a destructuring context. setResolved(ErrorKind::Destructuring); + setResolved(ErrorKind::DestructuringWarning); // Report any pending expression error. return checkForError(ErrorKind::Expression); @@ -4067,191 +4293,272 @@ Parser<ParseHandler>::PossibleError::transferErrorsTo(PossibleError* other) transferErrorTo(ErrorKind::Expression, other); } -template <> -bool -Parser<FullParseHandler>::checkDestructuringName(ParseNode* expr, Maybe<DeclarationKind> maybeDecl) +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::bindingInitializer(Node lhs, DeclarationKind kind, + YieldHandling yieldHandling) { - MOZ_ASSERT(!handler.isUnparenthesizedDestructuringPattern(expr)); - - // Parentheses are forbidden around destructuring *patterns* (but allowed - // around names). Use our nicer error message for parenthesized, nested - // patterns. - if (handler.isParenthesizedDestructuringPattern(expr)) { - errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_PARENS); - return false; - } + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_ASSIGN)); - // This expression might be in a variable-binding pattern where only plain, - // unparenthesized names are permitted. - if (maybeDecl) { - // Destructuring patterns in declarations must only contain - // unparenthesized names. - if (!handler.isUnparenthesizedName(expr)) { - errorAt(expr->pn_pos.begin, JSMSG_NO_VARIABLE_NAME); - return false; - } + if (kind == DeclarationKind::FormalParameter) + pc->functionBox()->hasParameterExprs = true; - RootedPropertyName name(context, expr->name()); - return noteDeclaredName(name, *maybeDecl, expr->pn_pos); - } + Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); + if (!rhs) + return null(); - // Otherwise this is an expression in destructuring outside a declaration. - if (handler.isNameAnyParentheses(expr)) { - if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(expr, context)) { - if (!strictModeErrorAt(expr->pn_pos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) - return false; - } + handler.checkAndSetIsDirectRHSAnonFunction(rhs); - return true; - } + Node assign = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP); + if (!assign) + return null(); - if (handler.isPropertyAccess(expr)) - return true; + if (foldConstants && !FoldConstants(context, &assign, this)) + return null(); - errorAt(expr->pn_pos.begin, JSMSG_BAD_DESTRUCT_TARGET); - return false; + return assign; } -template <> -bool -Parser<FullParseHandler>::checkDestructuringPattern(ParseNode* pattern, - Maybe<DeclarationKind> maybeDecl, - PossibleError* possibleError /* = nullptr */); - -template <> -bool -Parser<FullParseHandler>::checkDestructuringObject(ParseNode* objectPattern, - Maybe<DeclarationKind> maybeDecl) +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling) { - MOZ_ASSERT(objectPattern->isKind(PNK_OBJECT)); + RootedPropertyName name(context, bindingIdentifier(yieldHandling)); + if (!name) + return null(); - for (ParseNode* member = objectPattern->pn_head; member; member = member->pn_next) { - ParseNode* target; - if (member->isKind(PNK_MUTATEPROTO)) { - target = member->pn_kid; - } else { - MOZ_ASSERT(member->isKind(PNK_COLON) || member->isKind(PNK_SHORTHAND)); - MOZ_ASSERT_IF(member->isKind(PNK_SHORTHAND), - member->pn_left->isKind(PNK_OBJECT_PROPERTY_NAME) && - member->pn_right->isKind(PNK_NAME) && - member->pn_left->pn_atom == member->pn_right->pn_atom); + Node binding = newName(name); + if (!binding || !noteDeclaredName(name, kind, pos())) + return null(); - target = member->pn_right; - } - if (handler.isUnparenthesizedAssignment(target)) - target = target->pn_left; + return binding; +} - if (handler.isUnparenthesizedDestructuringPattern(target)) { - if (!checkDestructuringPattern(target, maybeDecl)) - return false; - } else { - if (!checkDestructuringName(target, maybeDecl)) - return false; - } +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::bindingIdentifierOrPattern(DeclarationKind kind, YieldHandling yieldHandling, + TokenKind tt) +{ + if (tt == TOK_LB) + return arrayBindingPattern(kind, yieldHandling); + + if (tt == TOK_LC) + return objectBindingPattern(kind, yieldHandling); + + if (!TokenKindIsPossibleIdentifierName(tt)) { + error(JSMSG_NO_VARIABLE_NAME); + return null(); } - return true; + return bindingIdentifier(kind, yieldHandling); } -template <> -bool -Parser<FullParseHandler>::checkDestructuringArray(ParseNode* arrayPattern, - Maybe<DeclarationKind> maybeDecl) +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling) { - MOZ_ASSERT(arrayPattern->isKind(PNK_ARRAY)); + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); - for (ParseNode* element = arrayPattern->pn_head; element; element = element->pn_next) { - if (element->isKind(PNK_ELISION)) - continue; + JS_CHECK_RECURSION(context, return null()); - ParseNode* target; - if (element->isKind(PNK_SPREAD)) { - if (element->pn_next) { - errorAt(element->pn_next->pn_pos.begin, JSMSG_PARAMETER_AFTER_REST); - return false; - } - target = element->pn_kid; - } else if (handler.isUnparenthesizedAssignment(element)) { - target = element->pn_left; + uint32_t begin = pos().begin; + Node literal = handler.newObjectLiteral(begin); + if (!literal) + return null(); + + Maybe<DeclarationKind> declKind = Some(kind); + RootedAtom propAtom(context); + for (;;) { + TokenKind tt; + if (!tokenStream.peekToken(&tt)) + return null(); + if (tt == TOK_RC) + break; + + if (tt == TOK_TRIPLEDOT) { + // rest-binding property + tokenStream.consumeKnownToken(TOK_TRIPLEDOT); + uint32_t begin = pos().begin; + + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + + Node inner = bindingIdentifierOrPattern(kind, yieldHandling, tt); + if (!inner) + return null(); + + if (!handler.addSpreadProperty(literal, begin, inner)) + return null(); } else { - target = element; + TokenPos namePos = tokenStream.nextToken().pos; + + PropertyType propType; + Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom); + if (!propName) + return null(); + if (propType == PropertyType::Normal) { + // Handle e.g., |var {p: x} = o| and |var {p: x=0} = o|. + + if (!tokenStream.getToken(&tt, TokenStream::Operand)) + return null(); + + Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt); + if (!binding) + return null(); + + bool hasInitializer; + if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN)) + return null(); + + Node bindingExpr = hasInitializer + ? bindingInitializer(binding, kind, yieldHandling) + : binding; + if (!bindingExpr) + return null(); + + if (!handler.addPropertyDefinition(literal, propName, bindingExpr)) + return null(); + } else if (propType == PropertyType::Shorthand) { + // Handle e.g., |var {x, y} = o| as destructuring shorthand + // for |var {x: x, y: y} = o|. + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt)); + + Node binding = bindingIdentifier(kind, yieldHandling); + if (!binding) + return null(); + + if (!handler.addShorthand(literal, propName, binding)) + return null(); + } else if (propType == PropertyType::CoverInitializedName) { + // Handle e.g., |var {x=1, y=2} = o| as destructuring + // shorthand with default values. + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt)); + + Node binding = bindingIdentifier(kind, yieldHandling); + if (!binding) + return null(); + + tokenStream.consumeKnownToken(TOK_ASSIGN); + + Node bindingExpr = bindingInitializer(binding, kind, yieldHandling); + if (!bindingExpr) + return null(); + + if (!handler.addPropertyDefinition(literal, propName, bindingExpr)) + return null(); + } else { + errorAt(namePos.begin, JSMSG_NO_VARIABLE_NAME); + return null(); + + } } - if (handler.isUnparenthesizedDestructuringPattern(target)) { - if (!checkDestructuringPattern(target, maybeDecl)) - return false; - } else { - if (!checkDestructuringName(target, maybeDecl)) - return false; + bool matched; + if (!tokenStream.matchToken(&matched, TOK_COMMA)) + return null(); + if (!matched) + break; + if (tt == TOK_TRIPLEDOT) { + error(JSMSG_REST_WITH_COMMA); + return null(); } } - return true; + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None, + reportMissingClosing(JSMSG_CURLY_AFTER_LIST, + JSMSG_CURLY_OPENED, begin)); + + handler.setEndPosition(literal, pos().end); + return literal; } -/* - * Destructuring patterns can appear in two kinds of contexts: - * - * - assignment-like: assignment expressions and |for| loop heads. In - * these cases, the patterns' property value positions can be - * arbitrary lvalue expressions; the destructuring is just a fancy - * assignment. - * - * - binding-like: |var| and |let| declarations, functions' formal - * parameter lists, |catch| clauses, and comprehension tails. In - * these cases, the patterns' property value positions must be - * simple names; the destructuring defines them as new variables. - * - * In both cases, other code parses the pattern as an arbitrary - * primaryExpr, and then, here in checkDestructuringPattern, verify - * that the tree is a valid AssignmentPattern or BindingPattern. - * - * In assignment-like contexts, we parse the pattern with - * pc->inDestructuringDecl clear, so the lvalue expressions in the - * pattern are parsed normally. primaryExpr links variable references - * into the appropriate use chains; creates placeholder definitions; - * and so on. checkDestructuringPattern won't bind any new names and - * we specialize lvalues as appropriate. - * - * In declaration-like contexts, the normal variable reference - * processing would just be an obstruction, because we're going to - * define the names that appear in the property value positions as new - * variables anyway. In this case, we parse the pattern with - * pc->inDestructuringDecl set, which directs primaryExpr to leave - * whatever name nodes it creates unconnected. Then, here in - * checkDestructuringPattern, we require the pattern's property value - * positions to be simple names, and define them as appropriate to the - * context. - */ -template <> -bool -Parser<FullParseHandler>::checkDestructuringPattern(ParseNode* pattern, - Maybe<DeclarationKind> maybeDecl, - PossibleError* possibleError /* = nullptr */) +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling) { - if (pattern->isKind(PNK_ARRAYCOMP)) { - errorAt(pattern->pn_pos.begin, JSMSG_ARRAY_COMP_LEFTSIDE); - return false; - } + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LB)); - bool isDestructuring = pattern->isKind(PNK_ARRAY) - ? checkDestructuringArray(pattern, maybeDecl) - : checkDestructuringObject(pattern, maybeDecl); + JS_CHECK_RECURSION(context, return null()); - // Report any pending destructuring error. - if (isDestructuring && possibleError && !possibleError->checkForDestructuringError()) - return false; + uint32_t begin = pos().begin; + Node literal = handler.newArrayLiteral(begin); + if (!literal) + return null(); - return isDestructuring; -} + uint32_t index = 0; + TokenStream::Modifier modifier = TokenStream::Operand; + for (; ; index++) { + if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) { + error(JSMSG_ARRAY_INIT_TOO_BIG); + return null(); + } + + TokenKind tt; + if (!tokenStream.getToken(&tt, TokenStream::Operand)) + return null(); + + if (tt == TOK_RB) { + tokenStream.ungetToken(); + break; + } + + if (tt == TOK_COMMA) { + if (!handler.addElision(literal, pos())) + return null(); + } else if (tt == TOK_TRIPLEDOT) { + uint32_t begin = pos().begin; + + TokenKind tt; + if (!tokenStream.getToken(&tt, TokenStream::Operand)) + return null(); + + Node inner = bindingIdentifierOrPattern(kind, yieldHandling, tt); + if (!inner) + return null(); + + if (!handler.addSpreadElement(literal, begin, inner)) + return null(); + } else { + Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt); + if (!binding) + return null(); + + bool hasInitializer; + if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN)) + return null(); + + Node element = hasInitializer + ? bindingInitializer(binding, kind, yieldHandling) + : binding; + if (!element) + return null(); + + handler.addArrayElement(literal, element); + } + + if (tt != TOK_COMMA) { + // If we didn't already match TOK_COMMA in above case. + bool matched; + if (!tokenStream.matchToken(&matched, TOK_COMMA)) + return null(); + if (!matched) { + modifier = TokenStream::None; + break; + } + if (tt == TOK_TRIPLEDOT) { + error(JSMSG_REST_WITH_COMMA); + return null(); + } + } + } + + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RB, modifier, + reportMissingClosing(JSMSG_BRACKET_AFTER_LIST, + JSMSG_BRACKET_OPENED, begin)); -template <> -bool -Parser<SyntaxParseHandler>::checkDestructuringPattern(Node pattern, - Maybe<DeclarationKind> maybeDecl, - PossibleError* possibleError /* = nullptr */) -{ - return abortIfSyntaxParser(); + handler.setEndPosition(literal, pos().end); + return literal; } template <typename ParseHandler> @@ -4262,18 +4569,9 @@ Parser<ParseHandler>::destructuringDeclaration(DeclarationKind kind, YieldHandli MOZ_ASSERT(tokenStream.isCurrentTokenType(tt)); MOZ_ASSERT(tt == TOK_LB || tt == TOK_LC); - PossibleError possibleError(*this); - Node pattern; - { - pc->inDestructuringDecl = Some(kind); - pattern = primaryExpr(yieldHandling, TripledotProhibited, tt, &possibleError); - pc->inDestructuringDecl = Nothing(); - } - - if (!pattern || !checkDestructuringPattern(pattern, Some(kind), &possibleError)) - return null(); - - return pattern; + return tt == TOK_LB + ? arrayBindingPattern(kind, yieldHandling) + : objectBindingPattern(kind, yieldHandling); } template <typename ParseHandler> @@ -4303,6 +4601,7 @@ typename ParseHandler::Node Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned errorNumber) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); + uint32_t openedPos = pos().begin; ParseContext::Statement stmt(pc, StatementKind::Block); ParseContext::Scope scope(this); @@ -4313,7 +4612,9 @@ Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned error if (!list) return null(); - MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, errorNumber); + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand, + reportMissingClosing(errorNumber, JSMSG_CURLY_OPENED, + openedPos)); return finishLexicalScope(scope, list); } @@ -4384,6 +4685,12 @@ Parser<ParseHandler>::declarationPattern(Node decl, DeclarationKind declKind, To // binary operator (examined with modifier None) terminated |init|. // For all other declarations, through ASI's infinite majesty, a next // token on a new line would begin an expression. + // Similar to the case in initializerInNameDeclaration(), we need to + // peek at the next token when assignExpr() is a lazily parsed arrow + // function. + TokenKind ignored; + if (!tokenStream.peekToken(&ignored)) + return null(); tokenStream.addModifierException(TokenStream::OperandIsNone); } @@ -4484,7 +4791,8 @@ Parser<ParseHandler>::declarationName(Node decl, DeclarationKind declKind, Token ParseNodeKind* forHeadKind, Node* forInOrOfExpression) { // Anything other than TOK_YIELD or TOK_NAME is an error. - if (tt != TOK_NAME && tt != TOK_YIELD) { + // Anything other than possible identifier is an error. + if (!TokenKindIsPossibleIdentifier(tt)) { error(JSMSG_NO_VARIABLE_NAME); return null(); } @@ -4625,8 +4933,10 @@ Parser<ParseHandler>::declarationList(YieldHandling yieldHandling, template <typename ParseHandler> typename ParseHandler::Node -Parser<ParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, bool isConst) +Parser<ParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind) { + MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let); + /* * Parse body-level lets without a new block object. ES6 specs * that an execution environment's initial lexical environment @@ -4638,8 +4948,9 @@ Parser<ParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, bool isCon * * See 8.1.1.1.6 and the note in 13.2.1. */ - Node decl = declarationList(yieldHandling, isConst ? PNK_CONST : PNK_LET); - if (!decl || !MatchOrInsertSemicolonAfterExpression(tokenStream)) + Node decl = declarationList(yieldHandling, + kind == DeclarationKind::Const ? PNK_CONST : PNK_LET); + if (!decl || !matchOrInsertSemicolonAfterExpression()) return null(); return decl; @@ -4650,41 +4961,34 @@ bool Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet) { if (tt == TOK_LC) { - TokenStream::Modifier modifier = TokenStream::KeywordIsName; while (true) { // Handle the forms |import {} from 'a'| and // |import { ..., } from 'a'| (where ... is non empty), by // escaping the loop early if the next token is }. - if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(&tt)) return false; if (tt == TOK_RC) break; - // If the next token is a keyword, the previous call to - // peekToken matched it as a TOK_NAME, and put it in the - // lookahead buffer, so this call will match keywords as well. - MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_IMPORT_NAME); + if (!TokenKindIsPossibleIdentifierName(tt)) { + error(JSMSG_NO_IMPORT_NAME); + return false; + } + Rooted<PropertyName*> importName(context, tokenStream.currentName()); TokenPos importNamePos = pos(); - TokenKind maybeAs; - if (!tokenStream.peekToken(&maybeAs)) + bool matched; + if (!tokenStream.matchToken(&matched, TOK_AS)) return null(); - if (maybeAs == TOK_NAME && - tokenStream.nextName() == context->names().as) - { - tokenStream.consumeKnownToken(TOK_NAME); - - if (!checkUnescapedName()) - return false; - + if (matched) { TokenKind afterAs; if (!tokenStream.getToken(&afterAs)) return false; - if (afterAs != TOK_NAME && afterAs != TOK_YIELD) { + if (!TokenKindIsPossibleIdentifierName(afterAs)) { error(JSMSG_NO_BINDING_NAME); return false; } @@ -4694,10 +4998,7 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor // by the keyword 'as'. // See the ImportSpecifier production in ES6 section 15.2.2. if (IsKeyword(importName)) { - JSAutoByteString bytes; - if (!AtomToPrintableString(context, importName, &bytes)) - return false; - error(JSMSG_AS_AFTER_RESERVED_WORD, bytes.ptr()); + error(JSMSG_AS_AFTER_RESERVED_WORD, ReservedWordToCharZ(importName)); return false; } } @@ -4722,31 +5023,24 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor handler.addList(importSpecSet, importSpec); - bool matched; - if (!tokenStream.matchToken(&matched, TOK_COMMA)) + TokenKind next; + if (!tokenStream.getToken(&next)) return false; - if (!matched) { - modifier = TokenStream::None; + if (next == TOK_RC) break; + + if (next != TOK_COMMA) { + error(JSMSG_RC_AFTER_IMPORT_SPEC_LIST); + return false; } } - - MUST_MATCH_TOKEN_MOD(TOK_RC, modifier, JSMSG_RC_AFTER_IMPORT_SPEC_LIST); } else { MOZ_ASSERT(tt == TOK_MUL); - if (!tokenStream.getToken(&tt)) - return false; - if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) { - error(JSMSG_AS_AFTER_IMPORT_STAR); - return false; - } - - if (!checkUnescapedName()) - return false; + MUST_MATCH_TOKEN(TOK_AS, JSMSG_AS_AFTER_IMPORT_STAR); - MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_BINDING_NAME); + MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_BINDING_NAME); Node importName = newName(context->names().star); if (!importName) @@ -4780,14 +5074,6 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor } template<> -bool -Parser<SyntaxParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet) -{ - MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); - return false; -} - -template<> ParseNode* Parser<FullParseHandler>::importDeclaration() { @@ -4807,8 +5093,15 @@ Parser<FullParseHandler>::importDeclaration() if (!importSpecSet) return null(); - if (tt == TOK_NAME || tt == TOK_LC || tt == TOK_MUL) { - if (tt == TOK_NAME) { + if (tt == TOK_STRING) { + // Handle the form |import 'a'| by leaving the list empty. This is + // equivalent to |import {} from 'a'|. + importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; + } else { + if (tt == TOK_LC || tt == TOK_MUL) { + if (!namedImportsOrNamespaceImport(tt, importSpecSet)) + return null(); + } else if (TokenKindIsPossibleIdentifierName(tt)) { // Handle the form |import a from 'b'|, by adding a single import // specifier to the list, with 'default' as the import name and // 'a' as the binding name. This is equivalent to @@ -4851,36 +5144,20 @@ Parser<FullParseHandler>::importDeclaration() return null(); } } else { - if (!namedImportsOrNamespaceImport(tt, importSpecSet)) - return null(); - } - - if (!tokenStream.getToken(&tt)) - return null(); - - if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - error(JSMSG_FROM_AFTER_IMPORT_CLAUSE); + error(JSMSG_DECLARATION_AFTER_IMPORT); return null(); } - if (!checkUnescapedName()) - return null(); + MUST_MATCH_TOKEN(TOK_FROM, JSMSG_FROM_AFTER_IMPORT_CLAUSE); MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); - } else if (tt == TOK_STRING) { - // Handle the form |import 'a'| by leaving the list empty. This is - // equivalent to |import {} from 'a'|. - importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin; - } else { - error(JSMSG_DECLARATION_AFTER_IMPORT); - return null(); } Node moduleSpec = stringLiteral(); if (!moduleSpec) return null(); - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); ParseNode* node = @@ -4947,284 +5224,539 @@ Parser<SyntaxParseHandler>::checkExportedNamesForDeclaration(Node node) } template<> -ParseNode* -Parser<FullParseHandler>::exportDeclaration() +bool +Parser<FullParseHandler>::checkExportedNameForClause(ParseNode* node) { - MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); + return checkExportedName(node->pn_atom); +} - if (!pc->atModuleLevel()) { - error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL); +template<> +bool +Parser<SyntaxParseHandler>::checkExportedNameForClause(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser<FullParseHandler>::checkExportedNameForFunction(ParseNode* node) +{ + return checkExportedName(node->pn_funbox->function()->explicitName()); +} + +template<> +bool +Parser<SyntaxParseHandler>::checkExportedNameForFunction(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser<FullParseHandler>::checkExportedNameForClass(ParseNode* node) +{ + const ClassNode& cls = node->as<ClassNode>(); + MOZ_ASSERT(cls.names()); + return checkExportedName(cls.names()->innerBinding()->pn_atom); +} + +template<> +bool +Parser<SyntaxParseHandler>::checkExportedNameForClass(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser<FullParseHandler>::processExport(ParseNode* node) +{ + return pc->sc()->asModuleContext()->builder.processExport(node); +} + +template<> +bool +Parser<SyntaxParseHandler>::processExport(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template<> +bool +Parser<FullParseHandler>::processExportFrom(ParseNode* node) +{ + return pc->sc()->asModuleContext()->builder.processExportFrom(node); +} + +template<> +bool +Parser<SyntaxParseHandler>::processExportFrom(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportFrom(uint32_t begin, Node specList) +{ + if (!abortIfSyntaxParser()) return null(); - } - uint32_t begin = pos().begin; + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FROM)); - Node kid; - TokenKind tt; - if (!tokenStream.getToken(&tt)) + if (!abortIfSyntaxParser()) return null(); - switch (tt) { - case TOK_LC: { - kid = handler.newList(PNK_EXPORT_SPEC_LIST); - if (!kid) - return null(); - while (true) { - // Handle the forms |export {}| and |export { ..., }| (where ... - // is non empty), by escaping the loop early if the next token - // is }. - if (!tokenStream.peekToken(&tt)) - return null(); - if (tt == TOK_RC) - break; + MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); - MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_BINDING_NAME); - Node bindingName = newName(tokenStream.currentName()); - if (!bindingName) - return null(); + Node moduleSpec = stringLiteral(); + if (!moduleSpec) + return null(); - bool foundAs; - if (!tokenStream.matchContextualKeyword(&foundAs, context->names().as)) - return null(); - if (foundAs) - MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_EXPORT_NAME); + if (!matchOrInsertSemicolonAfterNonExpression()) + return null(); - Node exportName = newName(tokenStream.currentName()); - if (!exportName) - return null(); + Node node = handler.newExportFromDeclaration(begin, specList, moduleSpec); + if (!node) + return null(); - if (!checkExportedName(exportName->pn_atom)) - return null(); + if (!processExportFrom(node)) + return null(); - Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName); - if (!exportSpec) - return null(); + return node; +} - handler.addList(kid, exportSpec); +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportBatch(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); - bool matched; - if (!tokenStream.matchToken(&matched, TOK_COMMA)) - return null(); - if (!matched) - break; - } + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_MUL)); - MUST_MATCH_TOKEN(TOK_RC, JSMSG_RC_AFTER_EXPORT_SPEC_LIST); + Node kid = handler.newList(PNK_EXPORT_SPEC_LIST); + if (!kid) + return null(); - // Careful! If |from| follows, even on a new line, it must start a - // FromClause: - // - // export { x } - // from "foo"; // a single ExportDeclaration - // - // But if it doesn't, we might have an ASI opportunity in Operand - // context, so simply matching a contextual keyword won't work: - // - // export { x } // ExportDeclaration, terminated by ASI - // fro\u006D // ExpressionStatement, the name "from" - // - // In that case let MatchOrInsertSemicolonAfterNonExpression sort out - // ASI or any necessary error. - TokenKind tt; - if (!tokenStream.getToken(&tt, TokenStream::Operand)) - return null(); + // Handle the form |export *| by adding a special export batch + // specifier to the list. + Node exportSpec = handler.newNullary(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos()); + if (!exportSpec) + return null(); - if (tt == TOK_NAME && - tokenStream.currentToken().name() == context->names().from && - !tokenStream.currentToken().nameContainsEscape()) - { - MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); + handler.addList(kid, exportSpec); - Node moduleSpec = stringLiteral(); - if (!moduleSpec) - return null(); + MUST_MATCH_TOKEN(TOK_FROM, JSMSG_FROM_AFTER_EXPORT_STAR); - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) - return null(); + return exportFrom(begin, kid); +} - ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec); - if (!node || !pc->sc()->asModuleContext()->builder.processExportFrom(node)) - return null(); +template<> +bool +Parser<FullParseHandler>::checkLocalExportNames(ParseNode* node) +{ + // ES 2017 draft 15.2.3.1. + for (ParseNode* next = node->pn_head; next; next = next->pn_next) { + ParseNode* name = next->pn_left; + MOZ_ASSERT(name->isKind(PNK_NAME)); - return node; - } + RootedPropertyName ident(context, name->pn_atom->asPropertyName()); + if (!checkLocalExportName(ident, name->pn_pos.begin)) + return false; + } - tokenStream.ungetToken(); + return true; +} - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) - return null(); - break; - } +template<> +bool +Parser<SyntaxParseHandler>::checkLocalExportNames(Node node) +{ + MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); + return false; +} - case TOK_MUL: { - kid = handler.newList(PNK_EXPORT_SPEC_LIST); - if (!kid) - return null(); +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportClause(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); - // Handle the form |export *| by adding a special export batch - // specifier to the list. - Node exportSpec = handler.newNullary(PNK_EXPORT_BATCH_SPEC, JSOP_NOP, pos()); - if (!exportSpec) - return null(); + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); - handler.addList(kid, exportSpec); + Node kid = handler.newList(PNK_EXPORT_SPEC_LIST); + if (!kid) + return null(); + TokenKind tt; + while (true) { + // Handle the forms |export {}| and |export { ..., }| (where ... is non + // empty), by escaping the loop early if the next token is }. if (!tokenStream.getToken(&tt)) return null(); - if (tt != TOK_NAME || tokenStream.currentName() != context->names().from) { - error(JSMSG_FROM_AFTER_EXPORT_STAR); + + if (tt == TOK_RC) + break; + + if (!TokenKindIsPossibleIdentifierName(tt)) { + error(JSMSG_NO_BINDING_NAME); return null(); } - if (!checkUnescapedName()) + Node bindingName = newName(tokenStream.currentName()); + if (!bindingName) return null(); - MUST_MATCH_TOKEN(TOK_STRING, JSMSG_MODULE_SPEC_AFTER_FROM); - - Node moduleSpec = stringLiteral(); - if (!moduleSpec) + bool foundAs; + if (!tokenStream.matchToken(&foundAs, TOK_AS)) return null(); + if (foundAs) + MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifierName, JSMSG_NO_EXPORT_NAME); - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + Node exportName = newName(tokenStream.currentName()); + if (!exportName) return null(); - ParseNode* node = handler.newExportFromDeclaration(begin, kid, moduleSpec); - if (!node || !pc->sc()->asModuleContext()->builder.processExportFrom(node)) + if (!checkExportedNameForClause(exportName)) return null(); - return node; + Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName); + if (!exportSpec) + return null(); - } + handler.addList(kid, exportSpec); - case TOK_FUNCTION: - kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired); - if (!kid) + TokenKind next; + if (!tokenStream.getToken(&next)) return null(); - if (!checkExportedName(kid->pn_funbox->function()->explicitName())) - return null(); - break; + if (next == TOK_RC) + break; - case TOK_CLASS: { - kid = classDefinition(YieldIsKeyword, ClassStatement, NameRequired); - if (!kid) + if (next != TOK_COMMA) { + error(JSMSG_RC_AFTER_EXPORT_SPEC_LIST); return null(); + } + } - const ClassNode& cls = kid->as<ClassNode>(); - MOZ_ASSERT(cls.names()); - if (!checkExportedName(cls.names()->innerBinding()->pn_atom)) - return null(); - break; - } + // Careful! If |from| follows, even on a new line, it must start a + // FromClause: + // + // export { x } + // from "foo"; // a single ExportDeclaration + // + // But if it doesn't, we might have an ASI opportunity in Operand context: + // + // export { x } // ExportDeclaration, terminated by ASI + // fro\u006D // ExpressionStatement, the name "from" + // + // In that case let matchOrInsertSemicolonAfterNonExpression sort out ASI + // or any necessary error. + bool matched; + if (!tokenStream.matchToken(&matched, TOK_FROM, TokenStream::Operand)) + return null(); - case TOK_VAR: - kid = declarationList(YieldIsName, PNK_VAR); - if (!kid) - return null(); - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) - return null(); - if (!checkExportedNamesForDeclaration(kid)) - return null(); - break; + if (matched) + return exportFrom(begin, kid); - case TOK_DEFAULT: { - if (!tokenStream.getToken(&tt, TokenStream::Operand)) - return null(); + if (!matchOrInsertSemicolonAfterNonExpression()) + return null(); - if (!checkExportedName(context->names().default_)) - return null(); + if (!checkLocalExportNames(kid)) + return null(); - ParseNode* nameNode = nullptr; - switch (tt) { - case TOK_FUNCTION: - kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName); - if (!kid) - return null(); - break; - case TOK_CLASS: - kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName); - if (!kid) - return null(); - break; - default: { - if (tt == TOK_NAME && tokenStream.currentName() == context->names().async) { - TokenKind nextSameLine = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&nextSameLine)) - return null(); + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); - if (nextSameLine == TOK_FUNCTION) { - tokenStream.consumeKnownToken(nextSameLine); - kid = functionStmt(pos().begin, YieldIsName, AllowDefaultName, AsyncFunction); - if (!kid) - return null(); - break; - } - } + if (!processExport(node)) + return null(); - tokenStream.ungetToken(); - RootedPropertyName name(context, context->names().starDefaultStar); - nameNode = newName(name); - if (!nameNode) - return null(); - if (!noteDeclaredName(name, DeclarationKind::Const, pos())) - return null(); - kid = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited); - if (!kid) - return null(); - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) - return null(); - break; - } - } + return node; +} - ParseNode* node = handler.newExportDefaultDeclaration(kid, nameNode, - TokenPos(begin, pos().end)); - if (!node || !pc->sc()->asModuleContext()->builder.processExport(node)) - return null(); +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportVariableStatement(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); - return node; - } + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_VAR)); - case TOK_CONST: - kid = lexicalDeclaration(YieldIsName, /* isConst = */ true); - if (!kid) - return null(); - if (!checkExportedNamesForDeclaration(kid)) - return null(); - break; + Node kid = declarationList(YieldIsName, PNK_VAR); + if (!kid) + return null(); + if (!matchOrInsertSemicolonAfterExpression()) + return null(); + if (!checkExportedNamesForDeclaration(kid)) + return null(); - case TOK_NAME: - if (tokenStream.currentName() == context->names().let) { - if (!checkUnescapedName()) - return null(); + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); - kid = lexicalDeclaration(YieldIsName, /* isConst = */ false); - if (!kid) - return null(); - if (!checkExportedNamesForDeclaration(kid)) - return null(); - break; - } - MOZ_FALLTHROUGH; + if (!processExport(node)) + return null(); - default: - error(JSMSG_DECLARATION_AFTER_EXPORT); + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); + + Node kid = functionStmt(pos().begin, YieldIsKeyword, NameRequired); + if (!kid) + return null(); + + if (!checkExportedNameForFunction(kid)) return null(); - } - ParseNode* node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); - if (!node || !pc->sc()->asModuleContext()->builder.processExport(node)) + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) return null(); return node; } -template<> -SyntaxParseHandler::Node -Parser<SyntaxParseHandler>::exportDeclaration() +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportClassDeclaration(uint32_t begin) { - JS_ALWAYS_FALSE(abortIfSyntaxParser()); - return SyntaxParseHandler::NodeFailure; + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS)); + + Node kid = classDefinition(YieldIsKeyword, ClassStatement, NameRequired); + if (!kid) + return null(); + + if (!checkExportedNameForClass(kid)) + return null(); + + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportLexicalDeclaration(uint32_t begin, DeclarationKind kind) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let); + MOZ_ASSERT_IF(kind == DeclarationKind::Const, tokenStream.isCurrentTokenType(TOK_CONST)); + MOZ_ASSERT_IF(kind == DeclarationKind::Let, tokenStream.isCurrentTokenType(TOK_LET)); + + Node kid = lexicalDeclaration(YieldIsName, kind); + if (!kid) + return null(); + if (!checkExportedNamesForDeclaration(kid)) + return null(); + + Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportDefaultFunctionDeclaration(uint32_t begin, + FunctionAsyncKind asyncKind + /* = SyncFunction */) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION)); + + Node kid = functionStmt(pos().begin, YieldIsKeyword, AllowDefaultName, asyncKind); + if (!kid) + return null(); + + Node node = handler.newExportDefaultDeclaration(kid, null(), TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportDefaultClassDeclaration(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS)); + + Node kid = classDefinition(YieldIsKeyword, ClassStatement, AllowDefaultName); + if (!kid) + return null(); + + Node node = handler.newExportDefaultDeclaration(kid, null(), TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportDefaultAssignExpr(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + RootedPropertyName name(context, context->names().starDefaultStar); + Node nameNode = newName(name); + if (!nameNode) + return null(); + if (!noteDeclaredName(name, DeclarationKind::Const, pos())) + return null(); + + Node kid = assignExpr(InAllowed, YieldIsKeyword, TripledotProhibited); + if (!kid) + return null(); + if (!matchOrInsertSemicolonAfterExpression()) + return null(); + + Node node = handler.newExportDefaultDeclaration(kid, nameNode, TokenPos(begin, pos().end)); + if (!node) + return null(); + + if (!processExport(node)) + return null(); + + return node; +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportDefault(uint32_t begin) +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_DEFAULT)); + + TokenKind tt; + if (!tokenStream.getToken(&tt, TokenStream::Operand)) + return null(); + + if (!checkExportedName(context->names().default_)) + return null(); + + switch (tt) { + case TOK_FUNCTION: + return exportDefaultFunctionDeclaration(begin); + + case TOK_ASYNC: { + TokenKind nextSameLine = TOK_EOF; + if (!tokenStream.peekTokenSameLine(&nextSameLine)) + return null(); + + if (nextSameLine == TOK_FUNCTION) { + tokenStream.consumeKnownToken(TOK_FUNCTION); + return exportDefaultFunctionDeclaration(begin, AsyncFunction); + } + + tokenStream.ungetToken(); + return exportDefaultAssignExpr(begin); + } + + case TOK_CLASS: + return exportDefaultClassDeclaration(begin); + + default: + tokenStream.ungetToken(); + return exportDefaultAssignExpr(begin); + } +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::exportDeclaration() +{ + if (!abortIfSyntaxParser()) + return null(); + + MOZ_ASSERT(tokenStream.currentToken().type == TOK_EXPORT); + + if (!pc->atModuleLevel()) { + error(JSMSG_EXPORT_DECL_AT_TOP_LEVEL); + return null(); + } + + uint32_t begin = pos().begin; + + TokenKind tt; + if (!tokenStream.getToken(&tt)) + return null(); + switch (tt) { + case TOK_MUL: + return exportBatch(begin); + + case TOK_LC: + return exportClause(begin); + + case TOK_VAR: + return exportVariableStatement(begin); + + case TOK_FUNCTION: + return exportFunctionDeclaration(begin); + + case TOK_CLASS: + return exportClassDeclaration(begin); + + case TOK_CONST: + return exportLexicalDeclaration(begin, DeclarationKind::Const); + + case TOK_LET: + return exportLexicalDeclaration(begin, DeclarationKind::Let); + + case TOK_DEFAULT: + return exportDefault(begin); + + default: + error(JSMSG_DECLARATION_AFTER_EXPORT); + return null(); + } } template <typename ParseHandler> @@ -5236,7 +5768,7 @@ Parser<ParseHandler>::expressionStatement(YieldHandling yieldHandling, InvokedPr /* possibleError = */ nullptr, invoked); if (!pnexpr) return null(); - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return null(); return handler.newExprStatement(pnexpr, pos().end); } @@ -5249,14 +5781,71 @@ Parser<ParseHandler>::consequentOrAlternative(YieldHandling yieldHandling) if (!tokenStream.peekToken(&next, TokenStream::Operand)) return null(); - if (next == TOK_FUNCTION) { - // Apply Annex B.3.4 in non-strict code to allow FunctionDeclaration as - // the consequent/alternative of an |if| or |else|. Parser::statement - // will report the strict mode error. - if (!pc->sc()->strict()) { - tokenStream.consumeKnownToken(next, TokenStream::Operand); - return functionStmt(pos().begin, yieldHandling, NameRequired); + // Annex B.3.4 says that unbraced FunctionDeclarations under if/else in + // non-strict code act as if they were braced: |if (x) function f() {}| + // parses as |if (x) { function f() {} }|. + // + // Careful! FunctionDeclaration doesn't include generators or async + // functions. + if (next == TOK_ASYNC) { + tokenStream.consumeKnownToken(next, TokenStream::Operand); + + // Peek only on the same line: ExpressionStatement's lookahead + // restriction is phrased as + // + // [lookahead ∉ { {, function, async [no LineTerminator here] function, class, let [ }] + // + // meaning that code like this is valid: + // + // if (true) + // async // ASI opportunity + // function clownshoes() {} + TokenKind maybeFunction; + if (!tokenStream.peekTokenSameLine(&maybeFunction)) + return null(); + + if (maybeFunction == TOK_FUNCTION) { + error(JSMSG_FORBIDDEN_AS_STATEMENT, "async function declarations"); + return null(); } + + // Otherwise this |async| begins an ExpressionStatement. + tokenStream.ungetToken(); + } else if (next == TOK_FUNCTION) { + tokenStream.consumeKnownToken(next, TokenStream::Operand); + + // Parser::statement would handle this, but as this function handles + // every other error case, it seems best to handle this. + if (pc->sc()->strict()) { + error(JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations"); + return null(); + } + + TokenKind maybeStar; + if (!tokenStream.peekToken(&maybeStar)) + return null(); + + if (maybeStar == TOK_MUL) { + error(JSMSG_FORBIDDEN_AS_STATEMENT, "generator declarations"); + return null(); + } + + ParseContext::Statement stmt(pc, StatementKind::Block); + ParseContext::Scope scope(this); + if (!scope.init(pc)) + return null(); + + TokenPos funcPos = pos(); + Node fun = functionStmt(pos().begin, yieldHandling, NameRequired); + if (!fun) + return null(); + + Node block = handler.newStatementList(funcPos); + if (!block) + return null(); + + handler.addStatementToList(block, fun); + return finishLexicalScope(scope, block); } return statement(yieldHandling); @@ -5371,13 +5960,9 @@ Parser<ParseHandler>::matchInOrOf(bool* isForInp, bool* isForOfp) return false; *isForInp = tt == TOK_IN; - *isForOfp = tt == TOK_NAME && tokenStream.currentToken().name() == context->names().of; - if (!*isForInp && !*isForOfp) { + *isForOfp = tt == TOK_OF; + if (!*isForInp && !*isForOfp) tokenStream.ungetToken(); - } else { - if (tt == TOK_NAME && !checkUnescapedName()) - return false; - } MOZ_ASSERT_IF(*isForInp || *isForOfp, *isForInp != *isForOfp); return true; @@ -5427,15 +6012,12 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling, if (tt == TOK_CONST) { parsingLexicalDeclaration = true; tokenStream.consumeKnownToken(tt, TokenStream::Operand); - } else if (tt == TOK_NAME && - tokenStream.nextName() == context->names().let && - !tokenStream.nextNameContainsEscape()) - { + } else if (tt == TOK_LET) { // We could have a {For,Lexical}Declaration, or we could have a // LeftHandSideExpression with lookahead restrictions so it's not // ambiguous with the former. Check for a continuation of the former // to decide which we have. - tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand); + tokenStream.consumeKnownToken(TOK_LET, TokenStream::Operand); TokenKind next; if (!tokenStream.peekToken(&next)) @@ -5512,7 +6094,7 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling, // Verify the left-hand side expression doesn't have a forbidden form. if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) { - if (!checkDestructuringPattern(*forInitialPart, Nothing(), &possibleError)) + if (!possibleError.checkForDestructuringErrorOrWarning()) return false; } else if (handler.isNameAnyParentheses(*forInitialPart)) { const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context); @@ -5556,7 +6138,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling) if (allowsForEachIn()) { bool matched; - if (!tokenStream.matchContextualKeyword(&matched, context->names().each)) + if (!tokenStream.matchToken(&matched, TOK_EACH)) return null(); if (matched) { iflags = JSITER_FOREACH; @@ -5867,7 +6449,7 @@ Parser<ParseHandler>::continueStatement(YieldHandling yieldHandling) return null(); } - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); return handler.newContinueStatement(label, TokenPos(begin, pos().end)); @@ -5907,7 +6489,7 @@ Parser<ParseHandler>::breakStatement(YieldHandling yieldHandling) } } - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); return handler.newBreakStatement(label, TokenPos(begin, pos().end)); @@ -5947,10 +6529,10 @@ Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling) } if (exprNode) { - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return null(); } else { - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); } @@ -6070,7 +6652,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling) if (pc->funHasReturnExpr #if JS_HAS_EXPR_CLOSURES - || pc->functionBox()->function()->isExprBody() + || pc->functionBox()->isExprBody() #endif ) { @@ -6247,7 +6829,7 @@ Parser<ParseHandler>::throwStatement(YieldHandling yieldHandling) if (!throwExpr) return null(); - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return null(); return handler.newThrowStatement(throwExpr, TokenPos(begin, pos().end)); @@ -6267,12 +6849,12 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling) * kid3 is the finally statement * * catch nodes are ternary. - * kid1 is the lvalue (TOK_NAME, TOK_LB, or TOK_LC) + * kid1 is the lvalue (possible identifier, TOK_LB, or TOK_LC) * kid2 is the catch guard or null if no guard * kid3 is the catch block * * catch lvalue nodes are either: - * TOK_NAME for a single identifier + * a single identifier * TOK_RB or TOK_RC for a destructuring left-hand side * * finally nodes are TOK_LC statement lists. @@ -6282,6 +6864,8 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling) { MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY); + uint32_t openedPos = pos().begin; + ParseContext::Statement stmt(pc, StatementKind::Try); ParseContext::Scope scope(this); if (!scope.init(pc)) @@ -6295,7 +6879,9 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling) if (!innerBlock) return null(); - MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_TRY); + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand, + reportMissingClosing(JSMSG_CURLY_AFTER_TRY, + JSMSG_CURLY_OPENED, openedPos)); } bool hasUnconditionalCatch = false; @@ -6347,22 +6933,18 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling) return null(); break; - case TOK_NAME: - case TOK_YIELD: { - RootedPropertyName param(context, bindingIdentifier(yieldHandling)); - if (!param) + default: { + if (!TokenKindIsPossibleIdentifierName(tt)) { + error(JSMSG_CATCH_IDENTIFIER); return null(); - catchName = newName(param); + } + + catchName = bindingIdentifier(DeclarationKind::SimpleCatchParameter, + yieldHandling); if (!catchName) return null(); - if (!noteDeclaredName(param, DeclarationKind::SimpleCatchParameter, pos())) - return null(); break; } - - default: - error(JSMSG_CATCH_IDENTIFIER); - return null(); } Node catchGuard = null(); @@ -6411,6 +6993,8 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling) if (tt == TOK_FINALLY) { MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY); + uint32_t openedPos = pos().begin; + ParseContext::Statement stmt(pc, StatementKind::Finally); ParseContext::Scope scope(this); if (!scope.init(pc)) @@ -6424,7 +7008,9 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling) if (!finallyBlock) return null(); - MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_FINALLY); + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand, + reportMissingClosing(JSMSG_CURLY_AFTER_FINALLY, + JSMSG_CURLY_OPENED, openedPos)); } else { tokenStream.ungetToken(); } @@ -6441,6 +7027,8 @@ typename ParseHandler::Node Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling, ParseContext::Scope& catchParamScope) { + uint32_t openedPos = pos().begin; + ParseContext::Statement stmt(pc, StatementKind::Block); // ES 13.15.7 CatchClauseEvaluation @@ -6460,7 +7048,9 @@ Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling, if (!list) return null(); - MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_CATCH); + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand, + reportMissingClosing(JSMSG_CURLY_AFTER_CATCH, + JSMSG_CURLY_OPENED, openedPos)); // The catch parameter names are not bound in the body scope, so remove // them before generating bindings. @@ -6474,7 +7064,7 @@ Parser<ParseHandler>::debuggerStatement() { TokenPos p; p.begin = pos().begin; - if (!MatchOrInsertSemicolonAfterNonExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterNonExpression()) return null(); p.end = pos().end; @@ -6514,6 +7104,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS)); + uint32_t classStartOffset = pos().begin; bool savedStrictness = setLocalStrictMode(true); TokenKind tt; @@ -6521,7 +7112,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, return null(); RootedPropertyName name(context); - if (tt == TOK_NAME || tt == TOK_YIELD) { + if (TokenKindIsPossibleIdentifier(tt)) { name = bindingIdentifier(yieldHandling); if (!name) return null(); @@ -6539,16 +7130,20 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, tokenStream.ungetToken(); } + // Push a ParseContext::ClassStatement to keep track of the constructor + // funbox. + ParseContext::ClassStatement classStmt(pc); + RootedAtom propAtom(context); // A named class creates a new lexical scope with a const binding of the - // class name. - Maybe<ParseContext::Statement> classStmt; - Maybe<ParseContext::Scope> classScope; + // class name for the "inner name". + Maybe<ParseContext::Statement> innerScopeStmt; + Maybe<ParseContext::Scope> innerScope; if (name) { - classStmt.emplace(pc, StatementKind::Block); - classScope.emplace(this); - if (!classScope->init(pc)) + innerScopeStmt.emplace(pc, StatementKind::Block); + innerScope.emplace(this); + if (!innerScope->init(pc)) return null(); } @@ -6575,10 +7170,10 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, if (!classMethods) return null(); - bool seenConstructor = false; + Maybe<DeclarationKind> declKind = Nothing(); for (;;) { TokenKind tt; - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(&tt)) return null(); if (tt == TOK_RC) break; @@ -6587,22 +7182,18 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, continue; bool isStatic = false; - if (tt == TOK_NAME && tokenStream.currentName() == context->names().static_) { - if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName)) + if (tt == TOK_STATIC) { + if (!tokenStream.peekToken(&tt)) return null(); if (tt == TOK_RC) { - tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); + tokenStream.consumeKnownToken(tt); error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt)); return null(); } if (tt != TOK_LP) { - if (!checkUnescapedName()) - return null(); - isStatic = true; } else { - tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName); tokenStream.ungetToken(); } } else { @@ -6614,7 +7205,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, return null(); PropertyType propType; - Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom); + Node propName = propertyName(yieldHandling, declKind, classMethods, &propType, &propAtom); if (!propName) return null(); @@ -6631,16 +7222,17 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, propType = PropertyType::GetterNoExpressionClosure; if (propType == PropertyType::Setter) propType = PropertyType::SetterNoExpressionClosure; - if (!isStatic && propAtom == context->names().constructor) { + + bool isConstructor = !isStatic && propAtom == context->names().constructor; + if (isConstructor) { if (propType != PropertyType::Method) { errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); return null(); } - if (seenConstructor) { + if (classStmt.constructorBox) { errorAt(nameOffset, JSMSG_DUPLICATE_PROPERTY, "constructor"); return null(); } - seenConstructor = true; propType = hasHeritage ? PropertyType::DerivedConstructor : PropertyType::Constructor; } else if (isStatic && propAtom == context->names().prototype) { errorAt(nameOffset, JSMSG_BAD_METHOD_DEF); @@ -6665,7 +7257,12 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, if (!tokenStream.isCurrentTokenType(TOK_RB)) funName = propAtom; } - Node fn = methodDefinition(nameOffset, propType, funName); + + // Calling toString on constructors need to return the source text for + // the entire class. The end offset is unknown at this point in + // parsing and will be amended when class parsing finishes below. + Node fn = methodDefinition(isConstructor ? classStartOffset : nameOffset, + propType, funName); if (!fn) return null(); @@ -6676,6 +7273,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, return null(); } + // Amend the toStringEnd offset for the constructor now that we've + // finished parsing the class. + uint32_t classEndOffset = pos().end; + if (FunctionBox* ctorbox = classStmt.constructorBox) { + if (ctorbox->function()->isInterpretedLazy()) + ctorbox->function()->lazyScript()->setToStringEnd(classEndOffset); + ctorbox->toStringEnd = classEndOffset; + } + Node nameNode = null(); Node methodsOrBlock = classMethods; if (name) { @@ -6687,15 +7293,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, if (!innerName) return null(); - Node classBlock = finishLexicalScope(*classScope, classMethods); + Node classBlock = finishLexicalScope(*innerScope, classMethods); if (!classBlock) return null(); methodsOrBlock = classBlock; // Pop the inner scope. - classScope.reset(); - classStmt.reset(); + innerScope.reset(); + innerScopeStmt.reset(); Node outerName = null(); if (classContext == ClassStatement) { @@ -6715,16 +7321,15 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling, MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness)); - return handler.newClass(nameNode, classHeritage, methodsOrBlock); + return handler.newClass(nameNode, classHeritage, methodsOrBlock, + TokenPos(classStartOffset, classEndOffset)); } template <class ParseHandler> bool Parser<ParseHandler>::nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling) { - MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME)); - MOZ_ASSERT(tokenStream.currentName() == context->names().let); - MOZ_ASSERT(!tokenStream.currentToken().nameContainsEscape()); + MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LET)); #ifdef DEBUG TokenKind verify; @@ -6736,18 +7341,19 @@ Parser<ParseHandler>::nextTokenContinuesLetDeclaration(TokenKind next, YieldHand if (next == TOK_LB || next == TOK_LC) return true; - // Otherwise a let declaration must have a name. - if (next == TOK_NAME) { - if (tokenStream.nextName() == context->names().yield) { - MOZ_ASSERT(tokenStream.nextNameContainsEscape(), - "token stream should interpret unescaped 'yield' as TOK_YIELD"); - - // Same as |next == TOK_YIELD|. - return yieldHandling == YieldIsName; - } + // If we have the name "yield", the grammar parameter exactly states + // whether this is okay. (This wasn't true for SpiderMonkey's ancient + // legacy generator syntax, but that's dead now.) If YieldIsName, + // declaration-parsing code will (if necessary) enforce a strict mode + // restriction on defining "yield". If YieldIsKeyword, consider this the + // end of the declaration, in case ASI induces a semicolon that makes the + // "yield" valid. + if (next == TOK_YIELD) + return yieldHandling == YieldIsName; - // One non-"yield" TOK_NAME edge case deserves special comment. - // Consider this: + // Otherwise a let declaration must have a name. + if (TokenKindIsPossibleIdentifier(next)) { + // A "let" edge case deserves special comment. Consider this: // // let // not an ASI opportunity // let; @@ -6760,16 +7366,6 @@ Parser<ParseHandler>::nextTokenContinuesLetDeclaration(TokenKind next, YieldHand return true; } - // If we have the name "yield", the grammar parameter exactly states - // whether this is okay. (This wasn't true for SpiderMonkey's ancient - // legacy generator syntax, but that's dead now.) If YieldIsName, - // declaration-parsing code will (if necessary) enforce a strict mode - // restriction on defining "yield". If YieldIsKeyword, consider this the - // end of the declaration, in case ASI induces a semicolon that makes the - // "yield" valid. - if (next == TOK_YIELD) - return yieldHandling == YieldIsName; - // Otherwise not a let declaration. return false; } @@ -6781,7 +7377,7 @@ Parser<ParseHandler>::variableStatement(YieldHandling yieldHandling) Node vars = declarationList(yieldHandling, PNK_VAR); if (!vars) return null(); - if (!MatchOrInsertSemicolonAfterExpression(tokenStream)) + if (!matchOrInsertSemicolonAfterExpression()) return null(); return vars; } @@ -6832,16 +7428,21 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling) return expressionStatement(yieldHandling); } - case TOK_NAME: { + default: { + // Avoid getting next token with None. + if (tt == TOK_AWAIT && pc->isAsync()) + return expressionStatement(yieldHandling); + + if (!TokenKindIsPossibleIdentifier(tt)) + return expressionStatement(yieldHandling); + TokenKind next; if (!tokenStream.peekToken(&next)) return null(); // |let| here can only be an Identifier, not a declaration. Give nicer // errors for declaration-looking typos. - if (!tokenStream.currentToken().nameContainsEscape() && - tokenStream.currentName() == context->names().let) - { + if (tt == TOK_LET) { bool forbiddenLetDeclaration = false; if (pc->sc()->strict() || versionNumber() >= JSVERSION_1_7) { @@ -6851,7 +7452,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling) } else if (next == TOK_LB) { // Enforce ExpressionStatement's 'let [' lookahead restriction. forbiddenLetDeclaration = true; - } else if (next == TOK_LC || next == TOK_NAME) { + } else if (next == TOK_LC || TokenKindIsPossibleIdentifier(next)) { // 'let {' and 'let foo' aren't completely forbidden, if ASI // causes 'let' to be the entire Statement. But if they're // same-line, we can aggressively give a better error message. @@ -6862,7 +7463,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling) if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); - MOZ_ASSERT(nextSameLine == TOK_NAME || + MOZ_ASSERT(TokenKindIsPossibleIdentifier(nextSameLine) || nextSameLine == TOK_LC || nextSameLine == TOK_EOL); @@ -6886,9 +7487,6 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling) case TOK_NEW: return expressionStatement(yieldHandling, PredictInvoked); - default: - return expressionStatement(yieldHandling); - // IfStatement[?Yield, ?Return] case TOK_IF: return ifStatement(yieldHandling); @@ -6934,7 +7532,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling) return withStatement(yieldHandling); // LabelledStatement[?Yield, ?Return] - // This is really handled by TOK_NAME and TOK_YIELD cases above. + // This is really handled by default and TOK_YIELD cases above. // ThrowStatement[?Yield] case TOK_THROW: @@ -7040,26 +7638,29 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling, return expressionStatement(yieldHandling); } - case TOK_NAME: { + default: { + // Avoid getting next token with None. + if (tt == TOK_AWAIT && pc->isAsync()) + return expressionStatement(yieldHandling); + + if (!TokenKindIsPossibleIdentifier(tt)) + return expressionStatement(yieldHandling); + TokenKind next; if (!tokenStream.peekToken(&next)) return null(); - if (!tokenStream.currentToken().nameContainsEscape() && - tokenStream.currentName() == context->names().let && - nextTokenContinuesLetDeclaration(next, yieldHandling)) - { - return lexicalDeclaration(yieldHandling, /* isConst = */ false); - } + if (tt == TOK_LET && nextTokenContinuesLetDeclaration(next, yieldHandling)) + return lexicalDeclaration(yieldHandling, DeclarationKind::Let); - if (tokenStream.currentName() == context->names().async) { + if (tt == TOK_ASYNC) { TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); if (nextSameLine == TOK_FUNCTION) { - uint32_t preludeStart = pos().begin; + uint32_t toStringStart = pos().begin; tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionStmt(preludeStart, yieldHandling, NameRequired, AsyncFunction); + return functionStmt(toStringStart, yieldHandling, NameRequired, AsyncFunction); } } @@ -7072,9 +7673,6 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling, case TOK_NEW: return expressionStatement(yieldHandling, PredictInvoked); - default: - return expressionStatement(yieldHandling); - // IfStatement[?Yield, ?Return] case TOK_IF: return ifStatement(yieldHandling); @@ -7120,7 +7718,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling, return withStatement(yieldHandling); // LabelledStatement[?Yield, ?Return] - // This is really handled by TOK_NAME and TOK_YIELD cases above. + // This is really handled by default and TOK_YIELD cases above. // ThrowStatement[?Yield] case TOK_THROW: @@ -7149,7 +7747,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling, case TOK_CONST: // [In] is the default behavior, because for-loops specially parse // their heads to handle |in| in this situation. - return lexicalDeclaration(yieldHandling, /* isConst = */ true); + return lexicalDeclaration(yieldHandling, DeclarationKind::Const); // ImportDeclaration (only inside modules) case TOK_IMPORT: @@ -7438,26 +8036,6 @@ Parser<ParseHandler>::condExpr1(InHandling inHandling, YieldHandling yieldHandli return handler.newConditional(condition, thenExpr, elseExpr); } -class AutoClearInDestructuringDecl -{ - ParseContext* pc_; - Maybe<DeclarationKind> saved_; - - public: - explicit AutoClearInDestructuringDecl(ParseContext* pc) - : pc_(pc), - saved_(pc->inDestructuringDecl) - { - pc->inDestructuringDecl = Nothing(); - if (saved_ && *saved_ == DeclarationKind::FormalParameter) - pc->functionBox()->hasParameterExprs = true; - } - - ~AutoClearInDestructuringDecl() { - pc_->inDestructuringDecl = saved_; - } -}; - template <typename ParseHandler> typename ParseHandler::Node Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandling, @@ -7482,10 +8060,13 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&tt, TokenStream::Operand)) return null(); - uint32_t exprOffset = pos().begin; + TokenPos exprPos = pos(); bool endsExpr; + // This only handles identifiers that *never* have special meaning anywhere + // in the language. Contextual keywords, reserved words in strict mode, + // and other hard cases are handled outside this fast path. if (tt == TOK_NAME) { if (!tokenStream.nextTokenEndsExpr(&endsExpr)) return null(); @@ -7516,12 +8097,12 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl return yieldExpression(inHandling); bool maybeAsyncArrow = false; - if (tt == TOK_NAME && tokenStream.currentName() == context->names().async) { + if (tt == TOK_ASYNC) { TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); - if (nextSameLine == TOK_NAME || nextSameLine == TOK_YIELD) + if (TokenKindIsPossibleIdentifier(nextSameLine)) maybeAsyncArrow = true; } @@ -7535,13 +8116,12 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl PossibleError possibleErrorInner(*this); Node lhs; if (maybeAsyncArrow) { - tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand); - MOZ_ASSERT(tokenStream.currentName() == context->names().async); + tokenStream.consumeKnownToken(TOK_ASYNC, TokenStream::Operand); TokenKind tt; if (!tokenStream.getToken(&tt)) return null(); - MOZ_ASSERT(tt == TOK_NAME || tt == TOK_YIELD); + MOZ_ASSERT(TokenKindIsPossibleIdentifier(tt)); // Check yield validity here. RootedPropertyName name(context, bindingIdentifier(yieldHandling)); @@ -7604,28 +8184,24 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.getToken(&next, TokenStream::Operand)) return null(); - uint32_t preludeStart = pos().begin; + uint32_t toStringStart = pos().begin; tokenStream.ungetToken(); GeneratorKind generatorKind = NotGenerator; FunctionAsyncKind asyncKind = SyncFunction; - if (next == TOK_NAME) { + if (next == TOK_ASYNC) { tokenStream.consumeKnownToken(next, TokenStream::Operand); - if (tokenStream.currentName() == context->names().async) { - TokenKind nextSameLine = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&nextSameLine)) - return null(); + TokenKind nextSameLine = TOK_EOF; + if (!tokenStream.peekTokenSameLine(&nextSameLine)) + return null(); - if (nextSameLine == TOK_ARROW) { - tokenStream.ungetToken(); - } else { - generatorKind = StarGenerator; - asyncKind = AsyncFunction; - } - } else { + if (nextSameLine == TOK_ARROW) { tokenStream.ungetToken(); + } else { + generatorKind = StarGenerator; + asyncKind = AsyncFunction; } } @@ -7633,7 +8209,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!pn) return null(); - Node arrowFunc = functionDefinition(preludeStart, pn, inHandling, yieldHandling, nullptr, + Node arrowFunc = functionDefinition(toStringStart, pn, inHandling, yieldHandling, nullptr, Arrow, generatorKind, asyncKind); if (!arrowFunc) return null(); @@ -7690,12 +8266,12 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl return null(); } - if (!checkDestructuringPattern(lhs, Nothing(), &possibleErrorInner)) + if (!possibleErrorInner.checkForDestructuringErrorOrWarning()) return null(); } else if (handler.isNameAnyParentheses(lhs)) { if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) { // |chars| is "arguments" or "eval" here. - if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars)) + if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) return null(); } @@ -7703,23 +8279,22 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl } else if (handler.isPropertyAccess(lhs)) { // Permitted: no additional testing/fixup needed. } else if (handler.isFunctionCall(lhs)) { - if (!strictModeErrorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS)) + if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS)) return null(); + + if (possibleError) + possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET); } else { - errorAt(exprOffset, JSMSG_BAD_LEFTSIDE_OF_ASS); + errorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS); return null(); } if (!possibleErrorInner.checkForExpressionError()) return null(); - Node rhs; - { - AutoClearInDestructuringDecl autoClear(pc); - rhs = assignExpr(inHandling, yieldHandling, TripledotProhibited); - if (!rhs) - return null(); - } + Node rhs = assignExpr(inHandling, yieldHandling, TripledotProhibited); + if (!rhs) + return null(); if (kind == PNK_ASSIGN) handler.checkAndSetIsDirectRHSAnonFunction(rhs); @@ -7874,20 +8449,17 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t } case TOK_AWAIT: { - if (!pc->isAsync()) { - // TOK_AWAIT can be returned in module, even if it's not inside - // async function. - error(JSMSG_RESERVED_ID, "await"); - return null(); + if (pc->isAsync()) { + Node kid = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked); + if (!kid) + return null(); + pc->lastAwaitOffset = begin; + return newAwaitExpression(begin, kid); } - - Node kid = unaryExpr(yieldHandling, tripledotHandling, possibleError, invoked); - if (!kid) - return null(); - pc->lastAwaitOffset = begin; - return newAwaitExpression(begin, kid); } + MOZ_FALLTHROUGH; + default: { Node expr = memberExpr(yieldHandling, tripledotHandling, tt, /* allowCallSyntax = */ true, possibleError, invoked); @@ -7949,7 +8521,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin) // Create box for fun->object early to root it. Directives directives(/* strict = */ outerpc->sc()->strict()); - FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* preludeStart = */ 0, directives, + FunctionBox* genFunbox = newFunctionBox(genfn, fun, /* toStringStart = */ 0, directives, StarGenerator, SyncFunction, /* tryAnnexB = */ false); if (!genFunbox) return null(); @@ -7985,7 +8557,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(unsigned begin) uint32_t end = pos().end; handler.setBeginPosition(comp, begin); handler.setEndPosition(comp, end); - genFunbox->bufEnd = end; + genFunbox->setEnd(end); handler.addStatementToList(body, comp); handler.setEndPosition(body, end); handler.setBeginPosition(genfn, begin); @@ -8025,8 +8597,10 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind) // FIXME: Destructuring binding (bug 980828). - MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); - RootedPropertyName name(context, tokenStream.currentName()); + MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifier, JSMSG_NO_VARIABLE_NAME); + RootedPropertyName name(context, bindingIdentifier(YieldIsKeyword)); + if (!name) + return null(); if (name == context->names().let) { error(JSMSG_LET_COMP_BINDING); return null(); @@ -8036,7 +8610,7 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind) if (!lhs) return null(); bool matched; - if (!tokenStream.matchContextualKeyword(&matched, context->names().of)) + if (!tokenStream.matchToken(&matched, TOK_OF)) return null(); if (!matched) { error(JSMSG_OF_AFTER_FOR_NAME); @@ -8371,9 +8945,9 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling Node nextMember; if (tt == TOK_DOT) { - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(&tt)) return null(); - if (tt == TOK_NAME) { + if (TokenKindIsPossibleIdentifierName(tt)) { PropertyName* field = tokenStream.currentName(); if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) { error(JSMSG_BAD_SUPERPROP, "property"); @@ -8448,8 +9022,27 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling JSOp op = JSOP_CALL; bool maybeAsyncArrow = false; - if (tt == TOK_LP && handler.isNameAnyParentheses(lhs)) { - if (handler.nameIsEvalAnyParentheses(lhs, context)) { + if (PropertyName* prop = handler.maybeDottedProperty(lhs)) { + // Use the JSOP_FUN{APPLY,CALL} optimizations given the + // right syntax. + if (prop == context->names().apply) { + op = JSOP_FUNAPPLY; + if (pc->isFunctionBox()) { + pc->functionBox()->usesApply = true; + } + } else if (prop == context->names().call) { + op = JSOP_FUNCALL; + } + } else if (tt == TOK_LP) { + if (handler.isAsyncKeyword(lhs, context)) { + // |async (| can be the start of an async arrow + // function, so we need to defer reporting possible + // errors from destructuring syntax. To give better + // error messages, we only allow the AsyncArrowHead + // part of the CoverCallExpressionAndAsyncArrowHead + // syntax when the initial name is "async". + maybeAsyncArrow = true; + } else if (handler.isEvalAnyParentheses(lhs, context)) { // Select the right EVAL op and flag pc as having a // direct eval. op = pc->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL; @@ -8466,24 +9059,6 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TripledotHandling // it. (If we're not in a method, that's fine, so // ignore the return value.) checkAndMarkSuperScope(); - } else if (handler.nameIsUnparenthesizedAsync(lhs, context)) { - // |async (| can be the start of an async arrow - // function, so we need to defer reporting possible - // errors from destructuring syntax. To give better - // error messages, we only allow the AsyncArrowHead - // part of the CoverCallExpressionAndAsyncArrowHead - // syntax when the initial name is "async". - maybeAsyncArrow = true; - } - } else if (PropertyName* prop = handler.maybeDottedProperty(lhs)) { - // Use the JSOP_FUN{APPLY,CALL} optimizations given the - // right syntax. - if (prop == context->names().apply) { - op = JSOP_FUNAPPLY; - if (pc->isFunctionBox()) - pc->functionBox()->usesApply = true; - } else if (prop == context->names().call) { - op = JSOP_FUNCALL; } } @@ -8542,106 +9117,117 @@ Parser<ParseHandler>::newName(PropertyName* name, TokenPos pos) } template <typename ParseHandler> -PropertyName* -Parser<ParseHandler>::labelOrIdentifierReference(YieldHandling yieldHandling, - bool yieldTokenizedAsName) -{ - PropertyName* ident; - bool isYield; - const Token& tok = tokenStream.currentToken(); - if (tok.type == TOK_NAME) { - MOZ_ASSERT(tok.name() != context->names().yield || - tok.nameContainsEscape() || - yieldTokenizedAsName, - "tokenizer should have treated unescaped 'yield' as TOK_YIELD"); - MOZ_ASSERT_IF(yieldTokenizedAsName, tok.name() == context->names().yield); - - ident = tok.name(); - isYield = ident == context->names().yield; - } else { - MOZ_ASSERT(tok.type == TOK_YIELD && !yieldTokenizedAsName); +bool +Parser<ParseHandler>::checkLabelOrIdentifierReference(HandlePropertyName ident, + uint32_t offset, + YieldHandling yieldHandling) +{ + if (ident == context->names().yield) { + if (yieldHandling == YieldIsKeyword || + versionNumber() >= JSVERSION_1_7) + { + errorAt(offset, JSMSG_RESERVED_ID, "yield"); + return false; + } + if (pc->sc()->needStrictChecks()) { + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "yield")) + return false; + } - ident = context->names().yield; - isYield = true; + return true; } - if (!isYield) { - if (pc->sc()->strict()) { - const char* badName = ident == context->names().let - ? "let" - : ident == context->names().static_ - ? "static" - : nullptr; - if (badName) { - error(JSMSG_RESERVED_ID, badName); - return nullptr; - } + if (ident == context->names().await) { + if (awaitIsKeyword()) { + errorAt(offset, JSMSG_RESERVED_ID, "await"); + return false; } - } else { - if (yieldHandling == YieldIsKeyword || - pc->sc()->strict() || - versionNumber() >= JSVERSION_1_7) - { - error(JSMSG_RESERVED_ID, "yield"); - return nullptr; + return true; + } + + if (IsKeyword(ident) || IsReservedWordLiteral(ident)) { + errorAt(offset, JSMSG_INVALID_ID, ReservedWordToCharZ(ident)); + return false; + } + + if (IsFutureReservedWord(ident)) { + errorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident)); + return false; + } + + if (pc->sc()->needStrictChecks()) { + if (IsStrictReservedWord(ident)) { + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, ReservedWordToCharZ(ident))) + return false; + return true; + } + + if (ident == context->names().let) { + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "let")) + return false; + return true; + } + + if (ident == context->names().static_) { + if (!strictModeErrorAt(offset, JSMSG_RESERVED_ID, "static")) + return false; + return true; } } - return ident; + return true; } template <typename ParseHandler> -PropertyName* -Parser<ParseHandler>::bindingIdentifier(YieldHandling yieldHandling) +bool +Parser<ParseHandler>::checkBindingIdentifier(HandlePropertyName ident, + uint32_t offset, + YieldHandling yieldHandling) { - PropertyName* ident; - bool isYield; - const Token& tok = tokenStream.currentToken(); - if (tok.type == TOK_NAME) { - MOZ_ASSERT(tok.name() != context->names().yield || tok.nameContainsEscape(), - "tokenizer should have treated unescaped 'yield' as TOK_YIELD"); + if (!checkLabelOrIdentifierReference(ident, offset, yieldHandling)) + return false; - ident = tok.name(); - isYield = ident == context->names().yield; - } else { - MOZ_ASSERT(tok.type == TOK_YIELD); + if (pc->sc()->needStrictChecks()) { + if (ident == context->names().arguments) { + if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "arguments")) + return false; + return true; + } - ident = context->names().yield; - isYield = true; + if (ident == context->names().eval) { + if (!strictModeErrorAt(offset, JSMSG_BAD_STRICT_ASSIGN, "eval")) + return false; + return true; + } } - if (!isYield) { - if (pc->sc()->strict()) { - const char* badName = ident == context->names().arguments - ? "arguments" - : ident == context->names().eval - ? "eval" - : nullptr; - if (badName) { - error(JSMSG_BAD_STRICT_ASSIGN, badName); - return nullptr; - } + return true; +} - badName = ident == context->names().let - ? "let" - : ident == context->names().static_ - ? "static" - : nullptr; - if (badName) { - error(JSMSG_RESERVED_ID, badName); - return nullptr; - } - } - } else { - if (yieldHandling == YieldIsKeyword || - pc->sc()->strict() || - versionNumber() >= JSVERSION_1_7) - { - error(JSMSG_RESERVED_ID, "yield"); - return nullptr; - } - } +template <typename ParseHandler> +PropertyName* +Parser<ParseHandler>::labelOrIdentifierReference(YieldHandling yieldHandling) +{ + // ES 2017 draft 12.1.1. + // StringValue of IdentifierName normalizes any Unicode escape sequences + // in IdentifierName hence such escapes cannot be used to write an + // Identifier whose code point sequence is the same as a ReservedWord. + // + // Use PropertyName* instead of TokenKind to reflect the normalization. + RootedPropertyName ident(context, tokenStream.currentName()); + if (!checkLabelOrIdentifierReference(ident, pos().begin, yieldHandling)) + return nullptr; + return ident; +} + +template <typename ParseHandler> +PropertyName* +Parser<ParseHandler>::bindingIdentifier(YieldHandling yieldHandling) +{ + RootedPropertyName ident(context, tokenStream.currentName()); + if (!checkBindingIdentifier(ident, pos().begin, yieldHandling)) + return nullptr; return ident; } @@ -8653,7 +9239,7 @@ Parser<ParseHandler>::identifierReference(Handle<PropertyName*> name) if (!pn) return null(); - if (!pc->inDestructuringDecl && !noteUsedName(name)) + if (!noteUsedName(name)) return null(); return pn; @@ -8668,8 +9254,23 @@ Parser<ParseHandler>::stringLiteral() template <typename ParseHandler> typename ParseHandler::Node -Parser<ParseHandler>::noSubstitutionTemplate() +Parser<ParseHandler>::noSubstitutionTaggedTemplate() +{ + if (tokenStream.hasInvalidTemplateEscape()) { + tokenStream.clearInvalidTemplateEscape(); + return handler.newRawUndefinedLiteral(pos()); + } + + return handler.newTemplateStringLiteral(stopStringCompression(), pos()); +} + +template <typename ParseHandler> +typename ParseHandler::Node +Parser<ParseHandler>::noSubstitutionUntaggedTemplate() { + if (!tokenStream.checkForInvalidTemplateEscapeError()) + return null(); + return handler.newTemplateStringLiteral(stopStringCompression(), pos()); } @@ -8705,6 +9306,74 @@ Parser<ParseHandler>::newRegExp() } template <typename ParseHandler> +void +Parser<ParseHandler>::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos, + PossibleError* possibleError) +{ + // Return early if a pending destructuring error is already present. + if (possibleError->hasPendingDestructuringError()) + return; + + if (pc->sc()->needStrictChecks()) { + if (handler.isArgumentsAnyParentheses(expr, context)) { + if (pc->sc()->strict()) { + possibleError->setPendingDestructuringErrorAt(exprPos, + JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS); + } else { + possibleError->setPendingDestructuringWarningAt(exprPos, + JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS); + } + return; + } + + if (handler.isEvalAnyParentheses(expr, context)) { + if (pc->sc()->strict()) { + possibleError->setPendingDestructuringErrorAt(exprPos, + JSMSG_BAD_STRICT_ASSIGN_EVAL); + } else { + possibleError->setPendingDestructuringWarningAt(exprPos, + JSMSG_BAD_STRICT_ASSIGN_EVAL); + } + return; + } + } + + // The expression must be either a simple assignment target, i.e. a name + // or a property accessor, or a nested destructuring pattern. + if (!handler.isUnparenthesizedDestructuringPattern(expr) && + !handler.isNameAnyParentheses(expr) && + !handler.isPropertyAccess(expr)) + { + // Parentheses are forbidden around destructuring *patterns* (but + // allowed around names). Use our nicer error message for + // parenthesized, nested patterns. + if (handler.isParenthesizedDestructuringPattern(expr)) + possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_PARENS); + else + possibleError->setPendingDestructuringErrorAt(exprPos, JSMSG_BAD_DESTRUCT_TARGET); + } +} + +template <typename ParseHandler> +void +Parser<ParseHandler>::checkDestructuringAssignmentElement(Node expr, TokenPos exprPos, + PossibleError* possibleError) +{ + // ES2018 draft rev 0719f44aab93215ed9a626b2f45bd34f36916834 + // 12.15.5 Destructuring Assignment + // + // AssignmentElement[Yield, Await]: + // DestructuringAssignmentTarget[?Yield, ?Await] + // DestructuringAssignmentTarget[?Yield, ?Await] Initializer[+In, ?Yield, ?Await] + + // If |expr| is an assignment element with an initializer expression, its + // destructuring assignment target was already validated in assignExpr(). + // Otherwise we need to check that |expr| is a valid destructuring target. + if (!handler.isUnparenthesizedAssignment(expr)) + checkDestructuringAssignmentTarget(expr, exprPos, possibleError); +} + +template <typename ParseHandler> typename ParseHandler::Node Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError) { @@ -8753,17 +9422,29 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro } else if (tt == TOK_TRIPLEDOT) { tokenStream.consumeKnownToken(TOK_TRIPLEDOT, TokenStream::Operand); uint32_t begin = pos().begin; + + TokenPos innerPos; + if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand)) + return null(); + Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited, possibleError); if (!inner) return null(); + if (possibleError) + checkDestructuringAssignmentTarget(inner, innerPos, possibleError); if (!handler.addSpreadElement(literal, begin, inner)) return null(); } else { + TokenPos elementPos; + if (!tokenStream.peekTokenPos(&elementPos, TokenStream::Operand)) + return null(); Node element = assignExpr(InAllowed, yieldHandling, TripledotProhibited, possibleError); if (!element) return null(); + if (possibleError) + checkDestructuringAssignmentElement(element, elementPos, possibleError); if (foldConstants && !FoldConstants(context, &element, this)) return null(); handler.addArrayElement(literal, element); @@ -8783,7 +9464,9 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro } } - MUST_MATCH_TOKEN_MOD(TOK_RB, modifier, JSMSG_BRACKET_AFTER_LIST); + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RB, modifier, + reportMissingClosing(JSMSG_BRACKET_AFTER_LIST, + JSMSG_BRACKET_OPENED, begin)); } handler.setEndPosition(literal, pos().end); return literal; @@ -8799,11 +9482,12 @@ DoubleToAtom(ExclusiveContext* cx, double value) template <typename ParseHandler> typename ParseHandler::Node -Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList, +Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, + const Maybe<DeclarationKind>& maybeDecl, Node propList, PropertyType* propType, MutableHandleAtom propAtom) { TokenKind ltok; - if (!tokenStream.getToken(<ok, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(<ok)) return null(); MOZ_ASSERT(ltok != TOK_RC, "caller should have handled TOK_RC"); @@ -8812,11 +9496,11 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList, bool isAsync = false; if (ltok == TOK_MUL) { isGenerator = true; - if (!tokenStream.getToken(<ok, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(<ok)) return null(); } - if (ltok == TOK_NAME && tokenStream.currentName() == context->names().async) { + if (ltok == TOK_ASYNC) { // AsyncMethod[Yield, Await]: // async [no LineTerminator here] PropertyName[?Yield, ?Await] ... // @@ -8832,16 +9516,13 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList, // ComputedPropertyName[Yield, Await]: // [ ... TokenKind tt = TOK_EOF; - if (!tokenStream.peekTokenSameLine(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.getToken(&tt)) return null(); - if (tt == TOK_STRING || tt == TOK_NUMBER || tt == TOK_LB || - tt == TOK_NAME || tt == TOK_YIELD) - { + if (tt != TOK_LP && tt != TOK_COLON && tt != TOK_RC && tt != TOK_ASSIGN) { isAsync = true; - tokenStream.consumeKnownToken(tt, TokenStream::KeywordIsName); ltok = tt; } else { - tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName); + tokenStream.ungetToken(); } } @@ -8863,46 +9544,41 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList, break; case TOK_LB: - propName = computedPropertyName(yieldHandling, propList); + propName = computedPropertyName(yieldHandling, maybeDecl, propList); if (!propName) return null(); break; - case TOK_NAME: { + default: { + if (!TokenKindIsPossibleIdentifierName(ltok)) { + error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(ltok)); + return null(); + } + propAtom.set(tokenStream.currentName()); // Do not look for accessor syntax on generators - if (isGenerator || isAsync || - !(propAtom.get() == context->names().get || - propAtom.get() == context->names().set)) - { + if (isGenerator || isAsync || !(ltok == TOK_GET || ltok == TOK_SET)) { propName = handler.newObjectLiteralPropertyName(propAtom, pos()); if (!propName) return null(); break; } - *propType = propAtom.get() == context->names().get ? PropertyType::Getter - : PropertyType::Setter; + *propType = ltok == TOK_GET ? PropertyType::Getter : PropertyType::Setter; // We have parsed |get| or |set|. Look for an accessor property // name next. TokenKind tt; - if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.peekToken(&tt)) return null(); - if (tt == TOK_NAME) { - if (!checkUnescapedName()) - return null(); - - tokenStream.consumeKnownToken(TOK_NAME, TokenStream::KeywordIsName); + if (TokenKindIsPossibleIdentifierName(tt)) { + tokenStream.consumeKnownToken(tt); propAtom.set(tokenStream.currentName()); return handler.newObjectLiteralPropertyName(propAtom, pos()); } if (tt == TOK_STRING) { - if (!checkUnescapedName()) - return null(); - - tokenStream.consumeKnownToken(TOK_STRING, TokenStream::KeywordIsName); + tokenStream.consumeKnownToken(TOK_STRING); propAtom.set(tokenStream.currentToken().atom()); @@ -8916,10 +9592,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList, return stringLiteral(); } if (tt == TOK_NUMBER) { - if (!checkUnescapedName()) - return null(); - - tokenStream.consumeKnownToken(TOK_NUMBER, TokenStream::KeywordIsName); + tokenStream.consumeKnownToken(TOK_NUMBER); propAtom.set(DoubleToAtom(context, tokenStream.currentToken().number())); if (!propAtom.get()) @@ -8927,19 +9600,15 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList, return newNumber(tokenStream.currentToken()); } if (tt == TOK_LB) { - if (!checkUnescapedName()) - return null(); + tokenStream.consumeKnownToken(TOK_LB); - tokenStream.consumeKnownToken(TOK_LB, TokenStream::KeywordIsName); - - return computedPropertyName(yieldHandling, propList); + return computedPropertyName(yieldHandling, maybeDecl, propList); } // Not an accessor property after all. propName = handler.newObjectLiteralPropertyName(propAtom.get(), pos()); if (!propName) return null(); - tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName); break; } @@ -8957,10 +9626,6 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList, return null(); break; } - - default: - error(JSMSG_BAD_PROP_ID); - return null(); } TokenKind tt; @@ -8976,7 +9641,9 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList, return propName; } - if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) { + if (TokenKindIsPossibleIdentifierName(ltok) && + (tt == TOK_COMMA || tt == TOK_RC || tt == TOK_ASSIGN)) + { if (isGenerator) { error(JSMSG_BAD_PROP_ID); return null(); @@ -9005,28 +9672,25 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList, template <typename ParseHandler> typename ParseHandler::Node -Parser<ParseHandler>::computedPropertyName(YieldHandling yieldHandling, Node literal) +Parser<ParseHandler>::computedPropertyName(YieldHandling yieldHandling, + const Maybe<DeclarationKind>& maybeDecl, + Node literal) { uint32_t begin = pos().begin; - Node assignNode; - { - // Turn off the inDestructuringDecl flag when parsing computed property - // names. In short, when parsing 'let {[x + y]: z} = obj;', noteUsedName() - // should be called on x and y, but not on z. See the comment on - // Parser<>::checkDestructuringPattern() for details. - AutoClearInDestructuringDecl autoClear(pc); - assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited); - if (!assignNode) - return null(); + if (maybeDecl) { + if (*maybeDecl == DeclarationKind::FormalParameter) + pc->functionBox()->hasParameterExprs = true; + } else { + handler.setListFlag(literal, PNX_NONCONST); } - MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR); - Node propname = handler.newComputedName(assignNode, begin, pos().end); - if (!propname) + Node assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited); + if (!assignNode) return null(); - handler.setListFlag(literal, PNX_NONCONST); - return propname; + + MUST_MATCH_TOKEN(TOK_RB, JSMSG_COMP_PROP_UNTERM_EXPR); + return handler.newComputedName(assignNode, begin, pos().end); } template <typename ParseHandler> @@ -9035,200 +9699,219 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError* { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); + uint32_t openedPos = pos().begin; + Node literal = handler.newObjectLiteral(pos().begin); if (!literal) return null(); bool seenPrototypeMutation = false; bool seenCoverInitializedName = false; + Maybe<DeclarationKind> declKind = Nothing(); RootedAtom propAtom(context); for (;;) { TokenKind tt; - if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName)) + if (!tokenStream.peekToken(&tt)) return null(); if (tt == TOK_RC) break; - TokenPos namePos = pos(); - - tokenStream.ungetToken(); - - PropertyType propType; - Node propName = propertyName(yieldHandling, literal, &propType, &propAtom); - if (!propName) - return null(); + if (tt == TOK_TRIPLEDOT) { + // object spread + tokenStream.consumeKnownToken(TOK_TRIPLEDOT); + uint32_t begin = pos().begin; - if (propType == PropertyType::Normal) { - Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited, - possibleError); - if (!propExpr) + TokenPos innerPos; + if (!tokenStream.peekTokenPos(&innerPos, TokenStream::Operand)) return null(); - handler.checkAndSetIsDirectRHSAnonFunction(propExpr); - - if (foldConstants && !FoldConstants(context, &propExpr, this)) + Node inner = assignExpr(InAllowed, yieldHandling, TripledotProhibited, + possibleError); + if (!inner) + return null(); + if (possibleError) + checkDestructuringAssignmentTarget(inner, innerPos, possibleError); + if (!handler.addSpreadProperty(literal, begin, inner)) return null(); + } else { + TokenPos namePos = tokenStream.nextToken().pos; - if (propAtom == context->names().proto) { - if (seenPrototypeMutation) { - // Directly report the error when we're not in a - // destructuring context. - if (!possibleError) { - errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY); - return null(); - } + PropertyType propType; + Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom); + if (!propName) - // Otherwise delay error reporting until we've determined - // whether or not we're destructuring. - possibleError->setPendingExpressionErrorAt(namePos, - JSMSG_DUPLICATE_PROTO_PROPERTY); - } - seenPrototypeMutation = true; + return null(); - // Note: this occurs *only* if we observe TOK_COLON! Only - // __proto__: v mutates [[Prototype]]. Getters, setters, - // method/generator definitions, computed property name - // versions of all of these, and shorthands do not. - if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr)) + if (propType == PropertyType::Normal) { + TokenPos exprPos; + if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand)) return null(); - } else { - if (!handler.isConstant(propExpr)) - handler.setListFlag(literal, PNX_NONCONST); - if (!handler.addPropertyDefinition(literal, propName, propExpr)) + Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited, + possibleError); + if (!propExpr) return null(); - } - } else if (propType == PropertyType::Shorthand) { - /* - * Support, e.g., |var {x, y} = o| as destructuring shorthand - * for |var {x: x, y: y} = o|, and |var o = {x, y}| as initializer - * shorthand for |var o = {x: x, y: y}|. - */ - TokenKind propToken = TOK_NAME; - if (!tokenStream.checkForKeyword(propAtom, &propToken)) - return null(); - if (propToken != TOK_NAME && propToken != TOK_YIELD) { - error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); - return null(); - } + handler.checkAndSetIsDirectRHSAnonFunction(propExpr); - Rooted<PropertyName*> name(context, - identifierReference(yieldHandling, propToken == TOK_YIELD)); - if (!name) - return null(); + if (possibleError) + checkDestructuringAssignmentElement(propExpr, exprPos, possibleError); - Node nameExpr = identifierReference(name); - if (!nameExpr) - return null(); + if (foldConstants && !FoldConstants(context, &propExpr, this)) + return null(); - if (!handler.addShorthand(literal, propName, nameExpr)) - return null(); - } else if (propType == PropertyType::CoverInitializedName) { - /* - * Support, e.g., |var {x=1, y=2} = o| as destructuring shorthand - * with default values, as per ES6 12.14.5 - */ - TokenKind propToken = TOK_NAME; - if (!tokenStream.checkForKeyword(propAtom, &propToken)) - return null(); + if (propAtom == context->names().proto) { + if (seenPrototypeMutation) { + // Directly report the error when we're not in a + // destructuring context. + if (!possibleError) { + errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY); + return null(); + } - if (propToken != TOK_NAME && propToken != TOK_YIELD) { - error(JSMSG_RESERVED_ID, TokenKindToDesc(propToken)); - return null(); - } + // Otherwise delay error reporting until we've + // determined whether or not we're destructuring. + possibleError->setPendingExpressionErrorAt(namePos, + JSMSG_DUPLICATE_PROTO_PROPERTY); + } + seenPrototypeMutation = true; - Rooted<PropertyName*> name(context, - identifierReference(yieldHandling, propToken == TOK_YIELD)); - if (!name) - return null(); + // Note: this occurs *only* if we observe TOK_COLON! Only + // __proto__: v mutates [[Prototype]]. Getters, setters, + // method/generator definitions, computed property name + // versions of all of these, and shorthands do not. + if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr)) + return null(); + } else { + if (!handler.isConstant(propExpr)) + handler.setListFlag(literal, PNX_NONCONST); - Node lhs = identifierReference(name); - if (!lhs) - return null(); + if (!handler.addPropertyDefinition(literal, propName, propExpr)) + return null(); + } + } else if (propType == PropertyType::Shorthand) { + /* + * Support, e.g., |({x, y} = o)| as destructuring shorthand + * for |({x: x, y: y} = o)|, and |var o = {x, y}| as + * initializer shorthand for |var o = {x: x, y: y}|. + */ + Rooted<PropertyName*> name(context, identifierReference(yieldHandling)); + if (!name) + return null(); - tokenStream.consumeKnownToken(TOK_ASSIGN); + Node nameExpr = identifierReference(name); + if (!nameExpr) + return null(); - if (!seenCoverInitializedName) { - // "shorthand default" or "CoverInitializedName" syntax is only - // valid in the case of destructuring. - seenCoverInitializedName = true; + if (possibleError) + checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError); - if (!possibleError) { - // Destructuring defaults are definitely not allowed in this object literal, - // because of something the caller knows about the preceding code. - // For example, maybe the preceding token is an operator: `x + {y=z}`. - error(JSMSG_COLON_AFTER_ID); + if (!handler.addShorthand(literal, propName, nameExpr)) return null(); + } else if (propType == PropertyType::CoverInitializedName) { + /* + * Support, e.g., |({x=1, y=2} = o)| as destructuring + * shorthand with default values, as per ES6 12.14.5 + */ + Rooted<PropertyName*> name(context, identifierReference(yieldHandling)); + if (!name) + return null(); + + Node lhs = identifierReference(name); + if (!lhs) + return null(); + + tokenStream.consumeKnownToken(TOK_ASSIGN); + + if (!seenCoverInitializedName) { + // "shorthand default" or "CoverInitializedName" syntax is + // only valid in the case of destructuring. + seenCoverInitializedName = true; + + if (!possibleError) { + // Destructuring defaults are definitely not allowed + // in this object literal, because of something the + // caller knows about the preceding code. For example, + // maybe the preceding token is an operator: + // |x + {y=z}|. + error(JSMSG_COLON_AFTER_ID); + return null(); + } + + // Here we set a pending error so that later in the parse, + // once we've determined whether or not we're + // destructuring, the error can be reported or ignored + // appropriately. + possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID); } - // Here we set a pending error so that later in the parse, once we've - // determined whether or not we're destructuring, the error can be - // reported or ignored appropriately. - possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID); - } + if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) { + // |chars| is "arguments" or "eval" here. + if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN, chars)) + return null(); + } - Node rhs; - { - // Clearing `inDestructuringDecl` allows name use to be noted - // in Parser::identifierReference. See bug 1255167. - AutoClearInDestructuringDecl autoClear(pc); - rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); + Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); if (!rhs) return null(); - } - handler.checkAndSetIsDirectRHSAnonFunction(rhs); + handler.checkAndSetIsDirectRHSAnonFunction(rhs); - Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP); - if (!propExpr) - return null(); - - if (!handler.addPropertyDefinition(literal, propName, propExpr)) - return null(); + Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP); + if (!propExpr) + return null(); - if (!abortIfSyntaxParser()) - return null(); - } else { - RootedAtom funName(context); - if (!tokenStream.isCurrentTokenType(TOK_RB)) { - funName = propAtom; + if (!handler.addPropertyDefinition(literal, propName, propExpr)) + return null(); + } else { + RootedAtom funName(context); + if (!tokenStream.isCurrentTokenType(TOK_RB)) { + funName = propAtom; - if (propType == PropertyType::Getter || propType == PropertyType::Setter) { - funName = prefixAccessorName(propType, propAtom); - if (!funName) - return null(); + if (propType == PropertyType::Getter || propType == PropertyType::Setter) { + funName = prefixAccessorName(propType, propAtom); + if (!funName) + return null(); + } } - } - Node fn = methodDefinition(namePos.begin, propType, funName); - if (!fn) - return null(); + Node fn = methodDefinition(namePos.begin, propType, funName); + if (!fn) + return null(); - handler.checkAndSetIsDirectRHSAnonFunction(fn); + handler.checkAndSetIsDirectRHSAnonFunction(fn); - JSOp op = JSOpFromPropertyType(propType); - if (!handler.addObjectMethodDefinition(literal, propName, fn, op)) - return null(); + JSOp op = JSOpFromPropertyType(propType); + if (!handler.addObjectMethodDefinition(literal, propName, fn, op)) + return null(); + + if (possibleError) { + possibleError->setPendingDestructuringErrorAt(namePos, + JSMSG_BAD_DESTRUCT_TARGET); + } + } } - if (!tokenStream.getToken(&tt)) + bool matched; + if (!tokenStream.matchToken(&matched, TOK_COMMA)) return null(); - if (tt == TOK_RC) + if (!matched) break; - if (tt != TOK_COMMA) { - error(JSMSG_CURLY_AFTER_LIST); - return null(); - } + if (tt == TOK_TRIPLEDOT && possibleError) + possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA); } + MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None, + reportMissingClosing(JSMSG_CURLY_AFTER_LIST, + JSMSG_CURLY_OPENED, openedPos)); + handler.setEndPosition(literal, pos().end); return literal; } template <typename ParseHandler> typename ParseHandler::Node -Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propType, +Parser<ParseHandler>::methodDefinition(uint32_t toStringStart, PropertyType propType, HandleAtom funName) { FunctionSyntaxKind kind; @@ -9282,7 +9965,7 @@ Parser<ParseHandler>::methodDefinition(uint32_t preludeStart, PropertyType propT if (!pn) return null(); - return functionDefinition(preludeStart, pn, InAllowed, yieldHandling, funName, + return functionDefinition(toStringStart, pn, InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind); } @@ -9312,14 +9995,11 @@ Parser<ParseHandler>::tryNewTarget(Node &newTarget) if (!tokenStream.getToken(&next)) return false; - if (next != TOK_NAME || tokenStream.currentName() != context->names().target) { + if (next != TOK_TARGET) { error(JSMSG_UNEXPECTED_TOKEN, "target", TokenKindToDesc(next)); return false; } - if (!checkUnescapedName()) - return false; - if (!pc->sc()->allowNewTarget()) { errorAt(begin, JSMSG_BAD_NEWTARGET); return false; @@ -9389,7 +10069,6 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling if (!expr) return null(); MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN); - handler.setEndPosition(expr, pos().end); return handler.parenthesize(expr); } @@ -9397,22 +10076,26 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling return templateLiteral(yieldHandling); case TOK_NO_SUBS_TEMPLATE: - return noSubstitutionTemplate(); + return noSubstitutionUntaggedTemplate(); case TOK_STRING: return stringLiteral(); - case TOK_YIELD: - case TOK_NAME: { - if (tokenStream.currentName() == context->names().async) { + default: { + if (!TokenKindIsPossibleIdentifier(tt)) { + error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); + return null(); + } + + if (tt == TOK_ASYNC) { TokenKind nextSameLine = TOK_EOF; if (!tokenStream.peekTokenSameLine(&nextSameLine)) return null(); if (nextSameLine == TOK_FUNCTION) { - uint32_t preludeStart = pos().begin; + uint32_t toStringStart = pos().begin; tokenStream.consumeKnownToken(TOK_FUNCTION); - return functionExpr(preludeStart, PredictUninvoked, AsyncFunction); + return functionExpr(toStringStart, PredictUninvoked, AsyncFunction); } } @@ -9476,7 +10159,7 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling // the enclosing code is strict mode code, any of "let", "yield", // or "arguments" should be prohibited. Argument-parsing code // handles that. - if (next != TOK_NAME && next != TOK_YIELD) { + if (!TokenKindIsPossibleIdentifier(next)) { error(JSMSG_UNEXPECTED_TOKEN, "rest argument name", TokenKindToDesc(next)); return null(); } @@ -9503,10 +10186,6 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling // Return an arbitrary expression node. See case TOK_RP above. return handler.newNullLiteral(pos()); } - - default: - error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(tt)); - return null(); } } @@ -9520,9 +10199,8 @@ Parser<ParseHandler>::exprInParens(InHandling inHandling, YieldHandling yieldHan return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked); } -template <typename ParseHandler> bool -Parser<ParseHandler>::warnOnceAboutExprClosure() +ParserBase::warnOnceAboutExprClosure() { #ifndef RELEASE_OR_BETA JSContext* cx = context->maybeJSContext(); @@ -9538,9 +10216,8 @@ Parser<ParseHandler>::warnOnceAboutExprClosure() return true; } -template <typename ParseHandler> bool -Parser<ParseHandler>::warnOnceAboutForEach() +ParserBase::warnOnceAboutForEach() { JSContext* cx = context->maybeJSContext(); if (!cx) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 156a1c1b0..88d2dad18 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -85,6 +85,16 @@ class ParseContext : public Nestable<ParseContext> } }; + struct ClassStatement : public Statement + { + FunctionBox* constructorBox; + + explicit ClassStatement(ParseContext* pc) + : Statement(pc, StatementKind::Class), + constructorBox(nullptr) + { } + }; + // The intra-function scope stack. // // Tracks declared and used names within a scope. @@ -146,9 +156,9 @@ class ParseContext : public Nestable<ParseContext> } MOZ_MUST_USE bool addDeclaredName(ParseContext* pc, AddDeclaredNamePtr& p, JSAtom* name, - DeclarationKind kind) + DeclarationKind kind, uint32_t pos) { - return maybeReportOOM(pc, declared_->add(p, name, DeclaredNameInfo(kind))); + return maybeReportOOM(pc, declared_->add(p, name, DeclaredNameInfo(kind, pos))); } // Remove all VarForAnnexBLexicalFunction declarations of a certain @@ -330,17 +340,6 @@ class ParseContext : public Nestable<ParseContext> // pointer may be nullptr. Directives* newDirectives; - // Set when parsing a declaration-like destructuring pattern. This flag - // causes PrimaryExpr to create PN_NAME parse nodes for variable references - // which are not hooked into any definition's use chain, added to any tree - // context's AtomList, etc. etc. checkDestructuring will do that work - // later. - // - // The comments atop checkDestructuring explain the distinction between - // assignment-like and declaration-like destructuring patterns, and why - // they need to be treated differently. - mozilla::Maybe<DeclarationKind> inDestructuringDecl; - // Set when parsing a function and it has 'return <expr>;' bool funHasReturnExpr; @@ -432,6 +431,11 @@ class ParseContext : public Nestable<ParseContext> return Statement::findNearest<T>(innermostStatement_, predicate); } + template <typename T> + T* findInnermostStatement() { + return Statement::findNearest<T>(innermostStatement_); + } + AtomVector& positionalFormalParameterNames() { return *positionalFormalParameterNames_; } @@ -532,6 +536,13 @@ ParseContext::Statement::is<ParseContext::LabelStatement>() const return kind_ == StatementKind::Label; } +template <> +inline bool +ParseContext::Statement::is<ParseContext::ClassStatement>() const +{ + return kind_ == StatementKind::Class; +} + template <typename T> inline T& ParseContext::Statement::as() @@ -735,7 +746,155 @@ class UsedNameTracker }; template <typename ParseHandler> -class Parser final : private JS::AutoGCRooter, public StrictModeGetter +class AutoAwaitIsKeyword; + +class ParserBase : public StrictModeGetter +{ + private: + ParserBase* thisForCtor() { return this; } + + public: + ExclusiveContext* const context; + + LifoAlloc& alloc; + + TokenStream tokenStream; + LifoAlloc::Mark tempPoolMark; + + /* list of parsed objects for GC tracing */ + ObjectBox* traceListHead; + + /* innermost parse context (stack-allocated) */ + ParseContext* pc; + + // For tracking used names in this parsing session. + UsedNameTracker& usedNames; + + /* Compression token for aborting. */ + SourceCompressionTask* sct; + + ScriptSource* ss; + + /* Root atoms and objects allocated for the parsed tree. */ + AutoKeepAtoms keepAtoms; + + /* Perform constant-folding; must be true when interfacing with the emitter. */ + const bool foldConstants:1; + + protected: +#if DEBUG + /* Our fallible 'checkOptions' member function has been called. */ + bool checkOptionsCalled:1; +#endif + + /* + * Not all language constructs can be handled during syntax parsing. If it + * is not known whether the parse succeeds or fails, this bit is set and + * the parse will return false. + */ + bool abortedSyntaxParse:1; + + /* Unexpected end of input, i.e. TOK_EOF not at top-level. */ + bool isUnexpectedEOF_:1; + + bool awaitIsKeyword_:1; + + public: + bool awaitIsKeyword() const { + return awaitIsKeyword_; + } + + ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, + const char16_t* chars, size_t length, bool foldConstants, + UsedNameTracker& usedNames, Parser<SyntaxParseHandler>* syntaxParser, + LazyScript* lazyOuterFunction); + ~ParserBase(); + + const char* getFilename() const { return tokenStream.getFilename(); } + JSVersion versionNumber() const { return tokenStream.versionNumber(); } + TokenPos pos() const { return tokenStream.currentToken().pos; } + + // Determine whether |yield| is a valid name in the current context, or + // whether it's prohibited due to strictness, JS version, or occurrence + // inside a star generator. + bool yieldExpressionsSupported() { + return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync(); + } + + virtual bool strictMode() { return pc->sc()->strict(); } + bool setLocalStrictMode(bool strict) { + MOZ_ASSERT(tokenStream.debugHasNoLookahead()); + return pc->sc()->setLocalStrictMode(strict); + } + + const ReadOnlyCompileOptions& options() const { + return tokenStream.options(); + } + + bool hadAbortedSyntaxParse() { + return abortedSyntaxParse; + } + void clearAbortedSyntaxParse() { + abortedSyntaxParse = false; + } + + bool isUnexpectedEOF() const { return isUnexpectedEOF_; } + + bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); + + /* Report the given error at the current offset. */ + void error(unsigned errorNumber, ...); + void errorWithNotes(UniquePtr<JSErrorNotes> notes, unsigned errorNumber, ...); + + /* Report the given error at the given offset. */ + void errorAt(uint32_t offset, unsigned errorNumber, ...); + void errorWithNotesAt(UniquePtr<JSErrorNotes> notes, uint32_t offset, + unsigned errorNumber, ...); + + /* + * Handle a strict mode error at the current offset. Report an error if in + * strict mode code, or warn if not, using the given error number and + * arguments. + */ + MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); + + /* + * Handle a strict mode error at the given offset. Report an error if in + * strict mode code, or warn if not, using the given error number and + * arguments. + */ + MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...); + + /* Report the given warning at the current offset. */ + MOZ_MUST_USE bool warning(unsigned errorNumber, ...); + + /* Report the given warning at the given offset. */ + MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...); + + /* + * If extra warnings are enabled, report the given warning at the current + * offset. + */ + MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...); + + /* + * If extra warnings are enabled, report the given warning at the given + * offset. + */ + MOZ_MUST_USE bool extraWarningAt(uint32_t offset, unsigned errorNumber, ...); + + bool isValidStrictBinding(PropertyName* name); + + bool warnOnceAboutExprClosure(); + bool warnOnceAboutForEach(); + + protected: + enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true }; + enum ForInitLocation { InForInit, NotInForInit }; +}; + +template <typename ParseHandler> +class Parser final : public ParserBase, private JS::AutoGCRooter { private: using Node = typename ParseHandler::Node; @@ -788,7 +947,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter class MOZ_STACK_CLASS PossibleError { private: - enum class ErrorKind { Expression, Destructuring }; + enum class ErrorKind { Expression, Destructuring, DestructuringWarning }; enum class ErrorState { None, Pending }; @@ -803,11 +962,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Parser<ParseHandler>& parser_; Error exprError_; Error destructuringError_; + Error destructuringWarning_; // Returns the error report. Error& error(ErrorKind kind); - // Return true if an error is pending without reporting + // Return true if an error is pending without reporting. bool hasError(ErrorKind kind); // Resolve any pending error. @@ -819,7 +979,11 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // If there is a pending error, report it and return false, otherwise // return true. - bool checkForError(ErrorKind kind); + MOZ_MUST_USE bool checkForError(ErrorKind kind); + + // If there is a pending warning, report it and return either false or + // true depending on the werror option, otherwise return true. + MOZ_MUST_USE bool checkForWarning(ErrorKind kind); // Transfer an existing error to another instance. void transferErrorTo(ErrorKind kind, PossibleError* other); @@ -827,23 +991,33 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter public: explicit PossibleError(Parser<ParseHandler>& parser); + // Return true if a pending destructuring error is present. + bool hasPendingDestructuringError(); + // Set a pending destructuring error. Only a single error may be set // per instance, i.e. subsequent calls to this method are ignored and // won't overwrite the existing pending error. void setPendingDestructuringErrorAt(const TokenPos& pos, unsigned errorNumber); + // Set a pending destructuring warning. Only a single warning may be + // set per instance, i.e. subsequent calls to this method are ignored + // and won't overwrite the existing pending warning. + void setPendingDestructuringWarningAt(const TokenPos& pos, unsigned errorNumber); + // Set a pending expression error. Only a single error may be set per // instance, i.e. subsequent calls to this method are ignored and won't // overwrite the existing pending error. void setPendingExpressionErrorAt(const TokenPos& pos, unsigned errorNumber); - // If there is a pending destructuring error, report it and return - // false, otherwise return true. Clears any pending expression error. - bool checkForDestructuringError(); + // If there is a pending destructuring error or warning, report it and + // return false, otherwise return true. Clears any pending expression + // error. + MOZ_MUST_USE bool checkForDestructuringErrorOrWarning(); // If there is a pending expression error, report it and return false, - // otherwise return true. Clears any pending destructuring error. - bool checkForExpressionError(); + // otherwise return true. Clears any pending destructuring error or + // warning. + MOZ_MUST_USE bool checkForExpressionError(); // Pass pending errors between possible error instances. This is useful // for extending the lifetime of a pending error beyond the scope of @@ -853,50 +1027,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter }; public: - ExclusiveContext* const context; - - LifoAlloc& alloc; - - TokenStream tokenStream; - LifoAlloc::Mark tempPoolMark; - - /* list of parsed objects for GC tracing */ - ObjectBox* traceListHead; - - /* innermost parse context (stack-allocated) */ - ParseContext* pc; - - // For tracking used names in this parsing session. - UsedNameTracker& usedNames; - - /* Compression token for aborting. */ - SourceCompressionTask* sct; - - ScriptSource* ss; - - /* Root atoms and objects allocated for the parsed tree. */ - AutoKeepAtoms keepAtoms; - - /* Perform constant-folding; must be true when interfacing with the emitter. */ - const bool foldConstants:1; - - private: -#if DEBUG - /* Our fallible 'checkOptions' member function has been called. */ - bool checkOptionsCalled:1; -#endif - - /* - * Not all language constructs can be handled during syntax parsing. If it - * is not known whether the parse succeeds or fails, this bit is set and - * the parse will return false. - */ - bool abortedSyntaxParse:1; - - /* Unexpected end of input, i.e. TOK_EOF not at top-level. */ - bool isUnexpectedEOF_:1; - - public: /* State specific to the kind of parse being performed. */ ParseHandler handler; @@ -904,45 +1034,14 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter void freeTree(Node node) { handler.freeTree(node); } public: - bool reportNoOffset(ParseReportKind kind, bool strict, unsigned errorNumber, ...); - - /* Report the given error at the current offset. */ - void error(unsigned errorNumber, ...); - - /* Report the given error at the given offset. */ - void errorAt(uint32_t offset, unsigned errorNumber, ...); - - /* - * Handle a strict mode error at the current offset. Report an error if in - * strict mode code, or warn if not, using the given error number and - * arguments. - */ - MOZ_MUST_USE bool strictModeError(unsigned errorNumber, ...); - - /* - * Handle a strict mode error at the given offset. Report an error if in - * strict mode code, or warn if not, using the given error number and - * arguments. - */ - MOZ_MUST_USE bool strictModeErrorAt(uint32_t offset, unsigned errorNumber, ...); - - /* Report the given warning at the current offset. */ - MOZ_MUST_USE bool warning(unsigned errorNumber, ...); - - /* Report the given warning at the given offset. */ - MOZ_MUST_USE bool warningAt(uint32_t offset, unsigned errorNumber, ...); - - /* - * If extra warnings are enabled, report the given warning at the current - * offset. - */ - MOZ_MUST_USE bool extraWarning(unsigned errorNumber, ...); - Parser(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, bool foldConstants, UsedNameTracker& usedNames, Parser<SyntaxParseHandler>* syntaxParser, LazyScript* lazyOuterFunction); ~Parser(); + friend class AutoAwaitIsKeyword<ParseHandler>; + void setAwaitIsKeyword(bool isKeyword); + bool checkOptions(); // A Parser::Mark is the extension of the LifoAlloc::Mark to the entire @@ -967,9 +1066,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter friend void js::frontend::MarkParser(JSTracer* trc, JS::AutoGCRooter* parser); - const char* getFilename() const { return tokenStream.getFilename(); } - JSVersion versionNumber() const { return tokenStream.versionNumber(); } - /* * Parse a top-level JS script. */ @@ -980,7 +1076,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * cx->tempLifoAlloc. */ ObjectBox* newObjectBox(JSObject* obj); - FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t preludeStart, + FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart, Directives directives, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB); @@ -995,24 +1091,14 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter void trace(JSTracer* trc); - bool hadAbortedSyntaxParse() { - return abortedSyntaxParse; - } - void clearAbortedSyntaxParse() { - abortedSyntaxParse = false; - } - - bool isUnexpectedEOF() const { return isUnexpectedEOF_; } - - bool checkUnescapedName(); - private: Parser* thisForCtor() { return this; } JSAtom* stopStringCompression(); Node stringLiteral(); - Node noSubstitutionTemplate(); + Node noSubstitutionTaggedTemplate(); + Node noSubstitutionUntaggedTemplate(); Node templateLiteral(YieldHandling yieldHandling); bool taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt); bool appendToCallSiteObj(Node callSiteObj); @@ -1061,7 +1147,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // Parse an inner function given an enclosing ParseContext and a // FunctionBox for the inner function. - bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t preludeStart, + bool innerFunction(Node pn, ParseContext* outerpc, FunctionBox* funbox, uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, Directives inheritedDirectives, Directives* newDirectives); @@ -1070,35 +1156,14 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // ParseContext is already on the stack. bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling, Node pn, FunctionSyntaxKind kind, - mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing()); - - - // Determine whether |yield| is a valid name in the current context, or - // whether it's prohibited due to strictness, JS version, or occurrence - // inside a star generator. - bool yieldExpressionsSupported() { - return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync(); - } + mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing(), + bool isStandaloneFunction = false); // Match the current token against the BindingIdentifier production with // the given Yield parameter. If there is no match, report a syntax // error. PropertyName* bindingIdentifier(YieldHandling yieldHandling); - virtual bool strictMode() { return pc->sc()->strict(); } - bool setLocalStrictMode(bool strict) { - MOZ_ASSERT(tokenStream.debugHasNoLookahead()); - return pc->sc()->setLocalStrictMode(strict); - } - - const ReadOnlyCompileOptions& options() const { - return tokenStream.options(); - } - - private: - enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true }; - enum ForInitLocation { InForInit, NotInForInit }; - private: /* * JS parsers, from lowest to highest precedence. @@ -1116,10 +1181,10 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter * Some parsers have two versions: an always-inlined version (with an 'i' * suffix) and a never-inlined version (with an 'n' suffix). */ - Node functionStmt(uint32_t preludeStart, + Node functionStmt(uint32_t toStringStart, YieldHandling yieldHandling, DefaultHandling defaultHandling, FunctionAsyncKind asyncKind = SyncFunction); - Node functionExpr(uint32_t preludeStart, InvokedPrediction invoked = PredictUninvoked, + Node functionExpr(uint32_t toStringStart, InvokedPrediction invoked = PredictUninvoked, FunctionAsyncKind asyncKind = SyncFunction); Node statementList(YieldHandling yieldHandling); @@ -1160,9 +1225,27 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter // continues a LexicalDeclaration. bool nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling); - Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst); + Node lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind); Node importDeclaration(); + + bool processExport(Node node); + bool processExportFrom(Node node); + + Node exportFrom(uint32_t begin, Node specList); + Node exportBatch(uint32_t begin); + bool checkLocalExportNames(Node node); + Node exportClause(uint32_t begin); + Node exportFunctionDeclaration(uint32_t begin); + Node exportVariableStatement(uint32_t begin); + Node exportClassDeclaration(uint32_t begin); + Node exportLexicalDeclaration(uint32_t begin, DeclarationKind kind); + Node exportDefaultFunctionDeclaration(uint32_t begin, + FunctionAsyncKind asyncKind = SyncFunction); + Node exportDefaultClassDeclaration(uint32_t begin); + Node exportDefaultAssignExpr(uint32_t begin); + Node exportDefault(uint32_t begin); + Node exportDeclaration(); Node expressionStatement(YieldHandling yieldHandling, InvokedPrediction invoked = PredictUninvoked); @@ -1250,7 +1333,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool tryNewTarget(Node& newTarget); bool checkAndMarkSuperScope(); - Node methodDefinition(uint32_t preludeStart, PropertyType propType, HandleAtom funName); + Node methodDefinition(uint32_t toStringStart, PropertyType propType, HandleAtom funName); /* * Additional JS parsers. @@ -1258,7 +1341,7 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, Node funcpn); - Node functionDefinition(uint32_t preludeStart, Node pn, + Node functionDefinition(uint32_t toStringStart, Node pn, InHandling inHandling, YieldHandling yieldHandling, HandleAtom name, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, @@ -1294,21 +1377,34 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter bool checkExportedName(JSAtom* exportName); bool checkExportedNamesForDeclaration(Node node); + bool checkExportedNameForClause(Node node); + bool checkExportedNameForFunction(Node node); + bool checkExportedNameForClass(Node node); + enum ClassContext { ClassStatement, ClassExpression }; Node classDefinition(YieldHandling yieldHandling, ClassContext classContext, DefaultHandling defaultHandling); - PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling, - bool yieldTokenizedAsName); + bool checkLabelOrIdentifierReference(HandlePropertyName ident, + uint32_t offset, + YieldHandling yieldHandling); + + bool checkLocalExportName(HandlePropertyName ident, uint32_t offset) { + return checkLabelOrIdentifierReference(ident, offset, YieldIsName); + } + + bool checkBindingIdentifier(HandlePropertyName ident, + uint32_t offset, + YieldHandling yieldHandling); + + PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling); PropertyName* labelIdentifier(YieldHandling yieldHandling) { - return labelOrIdentifierReference(yieldHandling, false); + return labelOrIdentifierReference(yieldHandling); } - PropertyName* identifierReference(YieldHandling yieldHandling, - bool yieldTokenizedAsName = false) - { - return labelOrIdentifierReference(yieldHandling, yieldTokenizedAsName); + PropertyName* identifierReference(YieldHandling yieldHandling) { + return labelOrIdentifierReference(yieldHandling); } PropertyName* importedBinding() { @@ -1337,23 +1433,27 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter Node newDotGeneratorName(); bool declareDotGeneratorName(); - bool skipLazyInnerFunction(Node pn, uint32_t preludeStart, FunctionSyntaxKind kind, + bool skipLazyInnerFunction(Node pn, uint32_t toStringStart, FunctionSyntaxKind kind, bool tryAnnexB); - bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t preludeStart, + bool innerFunction(Node pn, ParseContext* outerpc, HandleFunction fun, uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); - bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t preludeStart, + bool trySyntaxParseInnerFunction(Node pn, HandleFunction fun, uint32_t toStringStart, InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind, bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); - bool finishFunctionScopes(); - bool finishFunction(); + bool finishFunctionScopes(bool isStandaloneFunction); + bool finishFunction(bool isStandaloneFunction = false); bool leaveInnerFunction(ParseContext* outerpc); + bool matchOrInsertSemicolonHelper(TokenStream::Modifier modifier); + bool matchOrInsertSemicolonAfterExpression(); + bool matchOrInsertSemicolonAfterNonExpression(); + public: enum FunctionCallBehavior { PermitAssignmentToFunctionCalls, @@ -1366,21 +1466,22 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter private: bool checkIncDecOperand(Node operand, uint32_t operandOffset); bool checkStrictAssignment(Node lhs); - bool checkStrictBinding(PropertyName* name, TokenPos pos); bool hasValidSimpleStrictParameterNames(); - bool isValidStrictBinding(PropertyName* name); + void reportMissingClosing(unsigned errorNumber, unsigned noteNumber, uint32_t openedPos); - void reportRedeclaration(HandlePropertyName name, DeclarationKind kind, TokenPos pos); - bool notePositionalFormalParameter(Node fn, HandlePropertyName name, + void reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind, TokenPos pos, + uint32_t prevPos); + bool notePositionalFormalParameter(Node fn, HandlePropertyName name, uint32_t beginPos, bool disallowDuplicateParams, bool* duplicatedParam); bool noteDestructuredPositionalFormalParameter(Node fn, Node destruct); mozilla::Maybe<DeclarationKind> isVarRedeclaredInEval(HandlePropertyName name, DeclarationKind kind); - bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind, - mozilla::Maybe<DeclarationKind>* redeclaredKind); - bool tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, bool* tryAnnexB); + bool tryDeclareVar(HandlePropertyName name, DeclarationKind kind, uint32_t beginPos, + mozilla::Maybe<DeclarationKind>* redeclaredKind, uint32_t* prevPos); + bool tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName name, uint32_t beginPos, + bool* tryAnnexB); bool checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt, DeclarationKind kind, TokenPos pos); bool noteDeclaredName(HandlePropertyName name, DeclarationKind kind, TokenPos pos); @@ -1399,25 +1500,27 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter mozilla::Maybe<LexicalScope::Data*> newLexicalScopeData(ParseContext::Scope& scope); Node finishLexicalScope(ParseContext::Scope& scope, Node body); - Node propertyName(YieldHandling yieldHandling, Node propList, + Node propertyName(YieldHandling yieldHandling, + const mozilla::Maybe<DeclarationKind>& maybeDecl, Node propList, PropertyType* propType, MutableHandleAtom propAtom); - Node computedPropertyName(YieldHandling yieldHandling, Node literal); + Node computedPropertyName(YieldHandling yieldHandling, + const mozilla::Maybe<DeclarationKind>& maybeDecl, Node literal); Node arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError); Node newRegExp(); Node objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError); - // Top-level entrypoint into destructuring pattern checking/name-analyzing. - bool checkDestructuringPattern(Node pattern, mozilla::Maybe<DeclarationKind> maybeDecl, - PossibleError* possibleError = nullptr); + Node bindingInitializer(Node lhs, DeclarationKind kind, YieldHandling yieldHandling); + Node bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling); + Node bindingIdentifierOrPattern(DeclarationKind kind, YieldHandling yieldHandling, + TokenKind tt); + Node objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling); + Node arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling); - // Recursive methods for checking/name-analyzing subcomponents of a - // destructuring pattern. The array/object methods *must* be passed arrays - // or objects. The name method may be passed anything but will report an - // error if not passed a name. - bool checkDestructuringArray(Node arrayPattern, mozilla::Maybe<DeclarationKind> maybeDecl); - bool checkDestructuringObject(Node objectPattern, mozilla::Maybe<DeclarationKind> maybeDecl); - bool checkDestructuringName(Node expr, mozilla::Maybe<DeclarationKind> maybeDecl); + void checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos, + PossibleError* possibleError); + void checkDestructuringAssignmentElement(Node expr, TokenPos exprPos, + PossibleError* possibleError); Node newNumber(const Token& tok) { return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos); @@ -1427,12 +1530,26 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom); - TokenPos pos() const { return tokenStream.currentToken().pos; } - bool asmJS(Node list); +}; - bool warnOnceAboutExprClosure(); - bool warnOnceAboutForEach(); +template <typename ParseHandler> +class MOZ_STACK_CLASS AutoAwaitIsKeyword +{ + private: + Parser<ParseHandler>* parser_; + bool oldAwaitIsKeyword_; + + public: + AutoAwaitIsKeyword(Parser<ParseHandler>* parser, bool awaitIsKeyword) { + parser_ = parser; + oldAwaitIsKeyword_ = parser_->awaitIsKeyword_; + parser_->setAwaitIsKeyword(awaitIsKeyword); + } + + ~AutoAwaitIsKeyword() { + parser_->setAwaitIsKeyword(oldAwaitIsKeyword_); + } }; } /* namespace frontend */ diff --git a/js/src/vm/Keywords.h b/js/src/frontend/ReservedWords.h index ef37c4419..27f5b11c1 100644 --- a/js/src/vm/Keywords.h +++ b/js/src/frontend/ReservedWords.h @@ -4,15 +4,16 @@ * 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/. */ -/* A higher-order macro for enumerating keyword tokens. */ +/* A higher-order macro for enumerating reserved word tokens. */ -#ifndef vm_Keywords_h -#define vm_Keywords_h +#ifndef vm_ReservedWords_h +#define vm_ReservedWords_h -#define FOR_EACH_JAVASCRIPT_KEYWORD(macro) \ +#define FOR_EACH_JAVASCRIPT_RESERVED_WORD(macro) \ macro(false, false_, TOK_FALSE) \ macro(true, true_, TOK_TRUE) \ macro(null, null, TOK_NULL) \ + \ /* Keywords. */ \ macro(break, break_, TOK_BREAK) \ macro(case, case_, TOK_CASE) \ @@ -36,31 +37,45 @@ macro(this, this_, TOK_THIS) \ macro(throw, throw_, TOK_THROW) \ macro(try, try_, TOK_TRY) \ - macro(typeof, typeof, TOK_TYPEOF) \ + macro(typeof, typeof_, TOK_TYPEOF) \ macro(var, var, TOK_VAR) \ macro(void, void_, TOK_VOID) \ macro(while, while_, TOK_WHILE) \ macro(with, with, TOK_WITH) \ macro(import, import, TOK_IMPORT) \ - macro(export, export, TOK_EXPORT) \ + macro(export, export_, TOK_EXPORT) \ macro(class, class_, TOK_CLASS) \ macro(extends, extends, TOK_EXTENDS) \ macro(super, super, TOK_SUPER) \ - /* Reserved keywords. */ \ - macro(enum, enum_, TOK_RESERVED) \ - /* Future reserved keywords, but only in strict mode. */ \ - macro(implements, implements, TOK_STRICT_RESERVED) \ - macro(interface, interface, TOK_STRICT_RESERVED) \ - macro(package, package, TOK_STRICT_RESERVED) \ - macro(private, private_, TOK_STRICT_RESERVED) \ - macro(protected, protected_, TOK_STRICT_RESERVED) \ - macro(public, public_, TOK_STRICT_RESERVED) \ + \ + /* Future reserved words. */ \ + macro(enum, enum_, TOK_ENUM) \ + \ + /* Future reserved words, but only in strict mode. */ \ + macro(implements, implements, TOK_IMPLEMENTS) \ + macro(interface, interface, TOK_INTERFACE) \ + macro(package, package, TOK_PACKAGE) \ + macro(private, private_, TOK_PRIVATE) \ + macro(protected, protected_, TOK_PROTECTED) \ + macro(public, public_, TOK_PUBLIC) \ + \ + /* Contextual keywords. */ \ + macro(as, as, TOK_AS) \ + macro(async, async, TOK_ASYNC) \ macro(await, await, TOK_AWAIT) \ + macro(each, each, TOK_EACH) \ + macro(from, from, TOK_FROM) \ + macro(get, get, TOK_GET) \ + macro(let, let, TOK_LET) \ + macro(of, of, TOK_OF) \ + macro(set, set, TOK_SET) \ + macro(static, static_, TOK_STATIC) \ + macro(target, target, TOK_TARGET) \ /* \ * Yield is a token inside function*. Outside of a function*, it is a \ - * future reserved keyword in strict mode, but a keyword in JS1.7 even \ + * future reserved word in strict mode, but a keyword in JS1.7 even \ * when strict. Punt logic to parser. \ */ \ macro(yield, yield, TOK_YIELD) -#endif /* vm_Keywords_h */ +#endif /* vm_ReservedWords_h */ diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index b20417d5d..013444690 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -38,6 +38,7 @@ enum class StatementKind : uint8_t ForOfLoop, DoLoop, WhileLoop, + Class, // Used only by BytecodeEmitter. Spread @@ -450,7 +451,8 @@ class FunctionBox : public ObjectBox, public SharedContext uint32_t bufEnd; uint32_t startLine; uint32_t startColumn; - uint32_t preludeStart; + uint32_t toStringStart; + uint32_t toStringEnd; uint16_t length; uint8_t generatorKindBits_; /* The GeneratorKind of this function. */ @@ -473,11 +475,14 @@ class FunctionBox : public ObjectBox, public SharedContext bool usesThis:1; /* contains 'this' */ bool usesReturn:1; /* contains a 'return' statement */ bool hasRest_:1; /* has rest parameter */ + bool isExprBody_:1; /* arrow function with expression + * body or expression closure: + * function(x) x*x */ FunctionContextFlags funCxFlags; FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun, - uint32_t preludeStart, Directives directives, bool extraWarnings, + uint32_t toStringStart, Directives directives, bool extraWarnings, GeneratorKind generatorKind, FunctionAsyncKind asyncKind); MutableHandle<LexicalScope::Data*> namedLambdaBindings() { @@ -546,6 +551,11 @@ class FunctionBox : public ObjectBox, public SharedContext hasRest_ = true; } + bool isExprBody() const { return isExprBody_; } + void setIsExprBody() { + isExprBody_ = true; + } + void setGeneratorKind(GeneratorKind kind) { // A generator kind can be set at initialization, or when "yield" is // first seen. In both cases the transition can only happen from @@ -595,6 +605,14 @@ class FunctionBox : public ObjectBox, public SharedContext tokenStream.srcCoords.lineNumAndColumnIndex(bufStart, &startLine, &startColumn); } + void setEnd(uint32_t end) { + // For all functions except class constructors, the buffer and + // toString ending positions are the same. Class constructors override + // the toString ending position with the end of the class definition. + bufEnd = end; + toStringEnd = end; + } + void trace(JSTracer* trc) override; }; diff --git a/js/src/frontend/SourceNotes.h b/js/src/frontend/SourceNotes.h index dd2a95ad1..6ae184ae4 100644 --- a/js/src/frontend/SourceNotes.h +++ b/js/src/frontend/SourceNotes.h @@ -56,13 +56,14 @@ namespace js { M(SRC_NEXTCASE, "nextcase", 1) /* Distance forward from one CASE in a CONDSWITCH to \ the next. */ \ M(SRC_ASSIGNOP, "assignop", 0) /* += or another assign-op follows. */ \ + M(SRC_CLASS_SPAN, "class", 2) /* The starting and ending offsets for the class, used \ + for toString correctness for default ctors. */ \ M(SRC_TRY, "try", 1) /* JSOP_TRY, offset points to goto at the end of the \ try block. */ \ /* All notes above here are "gettable". See SN_IS_GETTABLE below. */ \ M(SRC_COLSPAN, "colspan", 1) /* Number of columns this opcode spans. */ \ M(SRC_NEWLINE, "newline", 0) /* Bytecode follows a source newline. */ \ M(SRC_SETLINE, "setline", 1) /* A file-absolute source line number note. */ \ - M(SRC_UNUSED20, "unused20", 0) /* Unused. */ \ M(SRC_UNUSED21, "unused21", 0) /* Unused. */ \ M(SRC_UNUSED22, "unused22", 0) /* Unused. */ \ M(SRC_UNUSED23, "unused23", 0) /* Unused. */ \ diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 00ea9d35d..a604b599f 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -9,6 +9,8 @@ #include "mozilla/Attributes.h" +#include <string.h> + #include "frontend/ParseNode.h" #include "frontend/TokenStream.h" @@ -94,10 +96,13 @@ class SyntaxParseHandler // Nodes representing unparenthesized names. NodeUnparenthesizedArgumentsName, - NodeUnparenthesizedAsyncName, NodeUnparenthesizedEvalName, NodeUnparenthesizedName, + // Node representing the "async" name, which may actually be a + // contextual keyword. + NodePotentialAsyncKeyword, + // Valuable for recognizing potential destructuring patterns. NodeUnparenthesizedArray, NodeUnparenthesizedObject, @@ -183,8 +188,8 @@ class SyntaxParseHandler lastAtom = name; if (name == cx->names().arguments) return NodeUnparenthesizedArgumentsName; - if (name == cx->names().async) - return NodeUnparenthesizedAsyncName; + if (pos.begin + strlen("async") == pos.end && name == cx->names().async) + return NodePotentialAsyncKeyword; if (name == cx->names().eval) return NodeUnparenthesizedEvalName; return NodeUnparenthesizedName; @@ -219,6 +224,7 @@ class SyntaxParseHandler Node newThisLiteral(const TokenPos& pos, Node thisName) { return NodeGeneric; } Node newNullLiteral(const TokenPos& pos) { return NodeGeneric; } + Node newRawUndefinedLiteral(const TokenPos& pos) { return NodeGeneric; } template <class Boxer> Node newRegExp(RegExpObject* reobj, const TokenPos& pos, Boxer& boxer) { return NodeGeneric; } @@ -235,6 +241,10 @@ class SyntaxParseHandler return NodeUnparenthesizedUnary; } + Node newNullary(ParseNodeKind kind, JSOp op, const TokenPos& pos) { + return NodeGeneric; + } + Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) { return NodeUnparenthesizedUnary; } @@ -279,7 +289,7 @@ class SyntaxParseHandler Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; } Node newClassMethodList(uint32_t begin) { return NodeGeneric; } Node newClassNames(Node outer, Node inner, const TokenPos& pos) { return NodeGeneric; } - Node newClass(Node name, Node heritage, Node methodBlock) { return NodeGeneric; } + Node newClass(Node name, Node heritage, Node methodBlock, const TokenPos& pos) { return NodeGeneric; } Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; } Node newPosHolder(const TokenPos& pos) { return NodeGeneric; } @@ -288,6 +298,7 @@ class SyntaxParseHandler MOZ_MUST_USE bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; } MOZ_MUST_USE bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } MOZ_MUST_USE bool addShorthand(Node literal, Node name, Node expr) { return true; } + MOZ_MUST_USE bool addSpreadProperty(Node literal, uint32_t begin, Node inner) { return true; } MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } @@ -302,6 +313,16 @@ class SyntaxParseHandler MOZ_MUST_USE bool prependInitialYield(Node stmtList, Node gen) { return true; } Node newEmptyStatement(const TokenPos& pos) { return NodeEmptyStatement; } + Node newExportDeclaration(Node kid, const TokenPos& pos) { + return NodeGeneric; + } + Node newExportFromDeclaration(uint32_t begin, Node exportSpecSet, Node moduleSpec) { + return NodeGeneric; + } + Node newExportDefaultDeclaration(Node kid, Node maybeBinding, const TokenPos& pos) { + return NodeGeneric; + } + Node newSetThis(Node thisName, Node value) { return value; } Node newExprStatement(Node expr, uint32_t end) { @@ -497,7 +518,7 @@ class SyntaxParseHandler return NodeParenthesizedArgumentsName; if (node == NodeUnparenthesizedEvalName) return NodeParenthesizedEvalName; - if (node == NodeUnparenthesizedName || node == NodeUnparenthesizedAsyncName) + if (node == NodeUnparenthesizedName || node == NodePotentialAsyncKeyword) return NodeParenthesizedName; if (node == NodeUnparenthesizedArray) @@ -528,9 +549,9 @@ class SyntaxParseHandler bool isUnparenthesizedName(Node node) { return node == NodeUnparenthesizedArgumentsName || - node == NodeUnparenthesizedAsyncName || node == NodeUnparenthesizedEvalName || - node == NodeUnparenthesizedName; + node == NodeUnparenthesizedName || + node == NodePotentialAsyncKeyword; } bool isNameAnyParentheses(Node node) { @@ -541,9 +562,11 @@ class SyntaxParseHandler node == NodeParenthesizedName; } - bool nameIsEvalAnyParentheses(Node node, ExclusiveContext* cx) { - MOZ_ASSERT(isNameAnyParentheses(node), - "must only call this function on known names"); + bool isArgumentsAnyParentheses(Node node, ExclusiveContext* cx) { + return node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName; + } + + bool isEvalAnyParentheses(Node node, ExclusiveContext* cx) { return node == NodeUnparenthesizedEvalName || node == NodeParenthesizedEvalName; } @@ -551,17 +574,15 @@ class SyntaxParseHandler MOZ_ASSERT(isNameAnyParentheses(node), "must only call this method on known names"); - if (nameIsEvalAnyParentheses(node, cx)) + if (isEvalAnyParentheses(node, cx)) return js_eval_str; - if (node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName) + if (isArgumentsAnyParentheses(node, cx)) return js_arguments_str; return nullptr; } - bool nameIsUnparenthesizedAsync(Node node, ExclusiveContext* cx) { - MOZ_ASSERT(isNameAnyParentheses(node), - "must only call this function on known names"); - return node == NodeUnparenthesizedAsyncName; + bool isAsyncKeyword(Node node, ExclusiveContext* cx) { + return node == NodePotentialAsyncKeyword; } PropertyName* maybeDottedProperty(Node node) { diff --git a/js/src/frontend/TokenKind.h b/js/src/frontend/TokenKind.h index 6f22d78e5..98f23fec8 100644 --- a/js/src/frontend/TokenKind.h +++ b/js/src/frontend/TokenKind.h @@ -81,9 +81,12 @@ \ macro(REGEXP, "regular expression literal") \ macro(TRUE, "boolean literal 'true'") \ + range(RESERVED_WORD_LITERAL_FIRST, TRUE) \ macro(FALSE, "boolean literal 'false'") \ macro(NULL, "null literal") \ + range(RESERVED_WORD_LITERAL_LAST, NULL) \ macro(THIS, "keyword 'this'") \ + range(KEYWORD_FIRST, THIS) \ macro(FUNCTION, "keyword 'function'") \ macro(IF, "keyword 'if'") \ macro(ELSE, "keyword 'else'") \ @@ -106,16 +109,43 @@ macro(FINALLY, "keyword 'finally'") \ macro(THROW, "keyword 'throw'") \ macro(DEBUGGER, "keyword 'debugger'") \ - macro(YIELD, "keyword 'yield'") \ - macro(AWAIT, "keyword 'await'") \ macro(EXPORT, "keyword 'export'") \ macro(IMPORT, "keyword 'import'") \ macro(CLASS, "keyword 'class'") \ macro(EXTENDS, "keyword 'extends'") \ macro(SUPER, "keyword 'super'") \ - macro(RESERVED, "reserved keyword") \ - /* reserved keywords in strict mode */ \ - macro(STRICT_RESERVED, "reserved keyword") \ + range(KEYWORD_LAST, SUPER) \ + \ + /* contextual keywords */ \ + macro(AS, "'as'") \ + range(CONTEXTUAL_KEYWORD_FIRST, AS) \ + macro(ASYNC, "'async'") \ + macro(AWAIT, "'await'") \ + macro(EACH, "'each'") \ + macro(FROM, "'from'") \ + macro(GET, "'get'") \ + macro(LET, "'let'") \ + macro(OF, "'of'") \ + macro(SET, "'set'") \ + macro(STATIC, "'static'") \ + macro(TARGET, "'target'") \ + macro(YIELD, "'yield'") \ + range(CONTEXTUAL_KEYWORD_LAST, YIELD) \ + \ + /* future reserved words */ \ + macro(ENUM, "reserved word 'enum'") \ + range(FUTURE_RESERVED_KEYWORD_FIRST, ENUM) \ + range(FUTURE_RESERVED_KEYWORD_LAST, ENUM) \ + \ + /* reserved words in strict mode */ \ + macro(IMPLEMENTS, "reserved word 'implements'") \ + range(STRICT_RESERVED_KEYWORD_FIRST, IMPLEMENTS) \ + macro(INTERFACE, "reserved word 'interface'") \ + macro(PACKAGE, "reserved word 'package'") \ + macro(PRIVATE, "reserved word 'private'") \ + macro(PROTECTED, "reserved word 'protected'") \ + macro(PUBLIC, "reserved word 'public'") \ + range(STRICT_RESERVED_KEYWORD_LAST, PUBLIC) \ \ /* \ * The following token types occupy contiguous ranges to enable easy \ @@ -149,7 +179,9 @@ range(RELOP_LAST, GE) \ \ macro(INSTANCEOF, "keyword 'instanceof'") \ + range(KEYWORD_BINOP_FIRST, INSTANCEOF) \ macro(IN, "keyword 'in'") \ + range(KEYWORD_BINOP_LAST, IN) \ \ /* Shift ops, per TokenKindIsShift. */ \ macro(LSH, "'<<'") \ @@ -168,7 +200,9 @@ \ /* Unary operation tokens. */ \ macro(TYPEOF, "keyword 'typeof'") \ + range(KEYWORD_UNOP_FIRST, TYPEOF) \ macro(VOID, "keyword 'void'") \ + range(KEYWORD_UNOP_LAST, VOID) \ macro(NOT, "'!'") \ macro(BITNOT, "'~'") \ \ @@ -239,6 +273,61 @@ TokenKindIsAssignment(TokenKind tt) return TOK_ASSIGNMENT_START <= tt && tt <= TOK_ASSIGNMENT_LAST; } +inline MOZ_MUST_USE bool +TokenKindIsKeyword(TokenKind tt) +{ + return (TOK_KEYWORD_FIRST <= tt && tt <= TOK_KEYWORD_LAST) || + (TOK_KEYWORD_BINOP_FIRST <= tt && tt <= TOK_KEYWORD_BINOP_LAST) || + (TOK_KEYWORD_UNOP_FIRST <= tt && tt <= TOK_KEYWORD_UNOP_LAST); +} + +inline MOZ_MUST_USE bool +TokenKindIsContextualKeyword(TokenKind tt) +{ + return TOK_CONTEXTUAL_KEYWORD_FIRST <= tt && tt <= TOK_CONTEXTUAL_KEYWORD_LAST; +} + +inline MOZ_MUST_USE bool +TokenKindIsFutureReservedWord(TokenKind tt) +{ + return TOK_FUTURE_RESERVED_KEYWORD_FIRST <= tt && tt <= TOK_FUTURE_RESERVED_KEYWORD_LAST; +} + +inline MOZ_MUST_USE bool +TokenKindIsStrictReservedWord(TokenKind tt) +{ + return TOK_STRICT_RESERVED_KEYWORD_FIRST <= tt && tt <= TOK_STRICT_RESERVED_KEYWORD_LAST; +} + +inline MOZ_MUST_USE bool +TokenKindIsReservedWordLiteral(TokenKind tt) +{ + return TOK_RESERVED_WORD_LITERAL_FIRST <= tt && tt <= TOK_RESERVED_WORD_LITERAL_LAST; +} + +inline MOZ_MUST_USE bool +TokenKindIsReservedWord(TokenKind tt) +{ + return TokenKindIsKeyword(tt) || + TokenKindIsFutureReservedWord(tt) || + TokenKindIsReservedWordLiteral(tt); +} + +inline MOZ_MUST_USE bool +TokenKindIsPossibleIdentifier(TokenKind tt) +{ + return tt == TOK_NAME || + TokenKindIsContextualKeyword(tt) || + TokenKindIsStrictReservedWord(tt); +} + +inline MOZ_MUST_USE bool +TokenKindIsPossibleIdentifierName(TokenKind tt) +{ + return TokenKindIsPossibleIdentifier(tt) || + TokenKindIsReservedWord(tt); +} + } // namespace frontend } // namespace js diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 8438ff7c5..b8623d545 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -8,6 +8,7 @@ #include "frontend/TokenStream.h" +#include "mozilla/ArrayUtils.h" #include "mozilla/IntegerTypeTraits.h" #include "mozilla/PodOperations.h" @@ -23,80 +24,81 @@ #include "jsnum.h" #include "frontend/BytecodeCompiler.h" +#include "frontend/ReservedWords.h" #include "js/CharacterEncoding.h" #include "js/UniquePtr.h" #include "vm/HelperThreads.h" -#include "vm/Keywords.h" #include "vm/StringBuffer.h" #include "vm/Unicode.h" using namespace js; using namespace js::frontend; +using mozilla::ArrayLength; using mozilla::Maybe; using mozilla::PodAssign; using mozilla::PodCopy; using mozilla::PodZero; -struct KeywordInfo { - const char* chars; // C string with keyword text +struct ReservedWordInfo { + const char* chars; // C string with reserved word text TokenKind tokentype; }; -static const KeywordInfo keywords[] = { -#define KEYWORD_INFO(keyword, name, type) \ - {js_##keyword##_str, type}, - FOR_EACH_JAVASCRIPT_KEYWORD(KEYWORD_INFO) -#undef KEYWORD_INFO +static const ReservedWordInfo reservedWords[] = { +#define RESERVED_WORD_INFO(word, name, type) \ + {js_##word##_str, type}, + FOR_EACH_JAVASCRIPT_RESERVED_WORD(RESERVED_WORD_INFO) +#undef RESERVED_WORD_INFO }; -// Returns a KeywordInfo for the specified characters, or nullptr if the string -// is not a keyword. +// Returns a ReservedWordInfo for the specified characters, or nullptr if the +// string is not a reserved word. template <typename CharT> -static const KeywordInfo* -FindKeyword(const CharT* s, size_t length) +static const ReservedWordInfo* +FindReservedWord(const CharT* s, size_t length) { MOZ_ASSERT(length != 0); size_t i; - const KeywordInfo* kw; + const ReservedWordInfo* rw; const char* chars; -#define JSKW_LENGTH() length -#define JSKW_AT(column) s[column] -#define JSKW_GOT_MATCH(index) i = (index); goto got_match; -#define JSKW_TEST_GUESS(index) i = (index); goto test_guess; -#define JSKW_NO_MATCH() goto no_match; -#include "jsautokw.h" -#undef JSKW_NO_MATCH -#undef JSKW_TEST_GUESS -#undef JSKW_GOT_MATCH -#undef JSKW_AT -#undef JSKW_LENGTH +#define JSRW_LENGTH() length +#define JSRW_AT(column) s[column] +#define JSRW_GOT_MATCH(index) i = (index); goto got_match; +#define JSRW_TEST_GUESS(index) i = (index); goto test_guess; +#define JSRW_NO_MATCH() goto no_match; +#include "frontend/ReservedWordsGenerated.h" +#undef JSRW_NO_MATCH +#undef JSRW_TEST_GUESS +#undef JSRW_GOT_MATCH +#undef JSRW_AT +#undef JSRW_LENGTH got_match: - return &keywords[i]; + return &reservedWords[i]; test_guess: - kw = &keywords[i]; - chars = kw->chars; + rw = &reservedWords[i]; + chars = rw->chars; do { if (*s++ != (unsigned char)(*chars++)) goto no_match; } while (--length != 0); - return kw; + return rw; no_match: return nullptr; } -static const KeywordInfo* -FindKeyword(JSLinearString* str) +static const ReservedWordInfo* +FindReservedWord(JSLinearString* str) { JS::AutoCheckCannotGC nogc; return str->hasLatin1Chars() - ? FindKeyword(str->latin1Chars(nogc), str->length()) - : FindKeyword(str->twoByteChars(nogc), str->length()); + ? FindReservedWord(str->latin1Chars(nogc), str->length()) + : FindReservedWord(str->twoByteChars(nogc), str->length()); } template <typename CharT> @@ -186,7 +188,68 @@ frontend::IsIdentifier(const char16_t* chars, size_t length) bool frontend::IsKeyword(JSLinearString* str) { - return FindKeyword(str) != nullptr; + if (const ReservedWordInfo* rw = FindReservedWord(str)) + return TokenKindIsKeyword(rw->tokentype); + + return false; +} + +bool +frontend::IsFutureReservedWord(JSLinearString* str) +{ + if (const ReservedWordInfo* rw = FindReservedWord(str)) + return TokenKindIsFutureReservedWord(rw->tokentype); + + return false; +} + +bool +frontend::IsStrictReservedWord(JSLinearString* str) +{ + if (const ReservedWordInfo* rw = FindReservedWord(str)) + return TokenKindIsStrictReservedWord(rw->tokentype); + + return false; +} + +bool +frontend::IsReservedWordLiteral(JSLinearString* str) +{ + if (const ReservedWordInfo* rw = FindReservedWord(str)) + return TokenKindIsReservedWordLiteral(rw->tokentype); + + return false; +} + +const char* +frontend::ReservedWordToCharZ(PropertyName* str) +{ + const ReservedWordInfo* rw = FindReservedWord(str); + if (rw == nullptr) + return nullptr; + + switch (rw->tokentype) { +#define EMIT_CASE(word, name, type) case type: return js_##word##_str; + FOR_EACH_JAVASCRIPT_RESERVED_WORD(EMIT_CASE) +#undef EMIT_CASE + default: + MOZ_ASSERT_UNREACHABLE("Not a reserved word PropertyName."); + } + return nullptr; +} + +PropertyName* +TokenStream::reservedWordToPropertyName(TokenKind tt) const +{ + MOZ_ASSERT(tt != TOK_NAME); + switch (tt) { +#define EMIT_CASE(word, name, type) case type: return cx->names().name; + FOR_EACH_JAVASCRIPT_RESERVED_WORD(EMIT_CASE) +#undef EMIT_CASE + default: + MOZ_ASSERT_UNREACHABLE("Not a reserved word TokenKind."); + } + return nullptr; } TokenStream::SourceCoords::SourceCoords(ExclusiveContext* cx, uint32_t ln) @@ -223,8 +286,13 @@ TokenStream::SourceCoords::add(uint32_t lineNum, uint32_t lineStartOffset) // only if lineStartOffsets_.append succeeds, to keep sentinel. // Otherwise return false to tell TokenStream about OOM. uint32_t maxPtr = MAX_PTR; - if (!lineStartOffsets_.append(maxPtr)) + if (!lineStartOffsets_.append(maxPtr)) { + static_assert(mozilla::IsSame<decltype(lineStartOffsets_.allocPolicy()), + TempAllocPolicy&>::value, + "this function's caller depends on it reporting an " + "error on failure, as TempAllocPolicy ensures"); return false; + } lineStartOffsets_[lineIndex] = lineStartOffset; } else { @@ -554,8 +622,9 @@ TokenStream::advance(size_t position) MOZ_MAKE_MEM_UNDEFINED(&cur->type, sizeof(cur->type)); lookahead = 0; - if (flags.hitOOM) - return reportError(JSMSG_OUT_OF_MEMORY); + if (flags.hitOOM) { + return false; + } return true; } @@ -599,8 +668,8 @@ TokenStream::seek(const Position& pos, const TokenStream& other) } bool -TokenStream::reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber, - va_list args) +TokenStream::reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, + bool strictMode, unsigned errorNumber, va_list args) { // In strict mode code, this is an error, not merely a warning. unsigned flags; @@ -611,7 +680,7 @@ TokenStream::reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, uns else return true; - return reportCompileErrorNumberVA(offset, flags, errorNumber, args); + return reportCompileErrorNumberVA(Move(notes), offset, flags, errorNumber, args); } void @@ -637,8 +706,8 @@ CompileError::throwError(JSContext* cx) } bool -TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigned errorNumber, - va_list args) +TokenStream::reportCompileErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, + unsigned flags, unsigned errorNumber, va_list args) { bool warning = JSREPORT_IS_WARNING(flags); @@ -655,6 +724,7 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne return false; CompileError& err = *tempErrPtr; + err.notes = Move(notes); err.flags = flags; err.errorNumber = errorNumber; err.filename = filename; @@ -746,7 +816,7 @@ TokenStream::reportStrictModeError(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportStrictModeErrorNumberVA(currentToken().pos.begin, strictMode(), + bool result = reportStrictModeErrorNumberVA(nullptr, currentToken().pos.begin, strictMode(), errorNumber, args); va_end(args); return result; @@ -757,8 +827,8 @@ TokenStream::reportError(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportCompileErrorNumberVA(currentToken().pos.begin, JSREPORT_ERROR, errorNumber, - args); + bool result = reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_ERROR, + errorNumber, args); va_end(args); return result; } @@ -768,30 +838,32 @@ TokenStream::reportErrorNoOffset(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportCompileErrorNumberVA(NoOffset, JSREPORT_ERROR, errorNumber, - args); + bool result = reportCompileErrorNumberVA(nullptr, NoOffset, JSREPORT_ERROR, + errorNumber, args); va_end(args); return result; } bool -TokenStream::reportWarning(unsigned errorNumber, ...) +TokenStream::warning(unsigned errorNumber, ...) { va_list args; va_start(args, errorNumber); - bool result = reportCompileErrorNumberVA(currentToken().pos.begin, JSREPORT_WARNING, + bool result = reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_WARNING, errorNumber, args); va_end(args); return result; } bool -TokenStream::reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args) +TokenStream::reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, + unsigned errorNumber, va_list args) { if (!options().extraWarningsOption) return true; - return reportCompileErrorNumberVA(offset, JSREPORT_STRICT|JSREPORT_WARNING, errorNumber, args); + return reportCompileErrorNumberVA(Move(notes), offset, JSREPORT_STRICT|JSREPORT_WARNING, + errorNumber, args); } void @@ -802,7 +874,34 @@ TokenStream::reportAsmJSError(uint32_t offset, unsigned errorNumber, ...) unsigned flags = options().throwOnAsmJSValidationFailureOption ? JSREPORT_ERROR : JSREPORT_WARNING; - reportCompileErrorNumberVA(offset, flags, errorNumber, args); + reportCompileErrorNumberVA(nullptr, offset, flags, errorNumber, args); + va_end(args); +} + +void +TokenStream::error(unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + reportCompileErrorNumberVA(nullptr, currentToken().pos.begin, JSREPORT_ERROR, + errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); + va_end(args); +} + +void +TokenStream::errorAt(uint32_t offset, unsigned errorNumber, ...) +{ + va_list args; + va_start(args, errorNumber); +#ifdef DEBUG + bool result = +#endif + reportCompileErrorNumberVA(nullptr, offset, JSREPORT_ERROR, errorNumber, args); + MOZ_ASSERT(!result, "reporting an error returned true?"); va_end(args); } @@ -934,34 +1033,49 @@ TokenStream::getDirectives(bool isMultiline, bool shouldWarnDeprecated) bool TokenStream::getDirective(bool isMultiline, bool shouldWarnDeprecated, - const char* directive, int directiveLength, + const char* directive, uint8_t directiveLength, const char* errorMsgPragma, UniqueTwoByteChars* destination) { MOZ_ASSERT(directiveLength <= 18); char16_t peeked[18]; - int32_t c; if (peekChars(directiveLength, peeked) && CharsMatch(peeked, directive)) { - if (shouldWarnDeprecated && - !reportWarning(JSMSG_DEPRECATED_PRAGMA, errorMsgPragma)) - return false; + if (shouldWarnDeprecated) { + if (!warning(JSMSG_DEPRECATED_PRAGMA, errorMsgPragma)) + return false; + } skipChars(directiveLength); tokenbuf.clear(); - while ((c = peekChar()) && c != EOF && !unicode::IsSpaceOrBOM2(c)) { - getChar(); + do { + int32_t c; + if (!peekChar(&c)) + return false; + + if (c == EOF || unicode::IsSpaceOrBOM2(c)) + break; + + consumeKnownChar(c); + // Debugging directives can occur in both single- and multi-line // comments. If we're currently inside a multi-line comment, we also // need to recognize multi-line comment terminators. - if (isMultiline && c == '*' && peekChar() == '/') { - ungetChar('*'); - break; + if (isMultiline && c == '*') { + int32_t c2; + if (!peekChar(&c2)) + return false; + + if (c2 == '/') { + ungetChar('*'); + break; + } } + if (!tokenbuf.append(c)) return false; - } + } while (true); if (tokenbuf.empty()) { // The directive's URL was missing, but this is not quite an @@ -993,7 +1107,10 @@ TokenStream::getDisplayURL(bool isMultiline, bool shouldWarnDeprecated) // developer would like to refer to the source as from the source's actual // URL. - return getDirective(isMultiline, shouldWarnDeprecated, " sourceURL=", 11, + static const char sourceURLDirective[] = " sourceURL="; + constexpr uint8_t sourceURLDirectiveLength = ArrayLength(sourceURLDirective) - 1; + return getDirective(isMultiline, shouldWarnDeprecated, + sourceURLDirective, sourceURLDirectiveLength, "sourceURL", &displayURL_); } @@ -1003,7 +1120,10 @@ TokenStream::getSourceMappingURL(bool isMultiline, bool shouldWarnDeprecated) // Match comments of the form "//# sourceMappingURL=<url>" or // "/\* //# sourceMappingURL=<url> *\/" - return getDirective(isMultiline, shouldWarnDeprecated, " sourceMappingURL=", 18, + static const char sourceMappingURLDirective[] = " sourceMappingURL="; + constexpr uint8_t sourceMappingURLDirectiveLength = ArrayLength(sourceMappingURLDirective) - 1; + return getDirective(isMultiline, shouldWarnDeprecated, + sourceMappingURLDirective, sourceMappingURLDirectiveLength, "sourceMappingURL", &sourceMapURL_); } @@ -1110,36 +1230,6 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart) return true; } -bool -TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp) -{ - if (!awaitIsKeyword && kw->tokentype == TOK_AWAIT) { - if (ttp) - *ttp = TOK_NAME; - return true; - } - - if (kw->tokentype == TOK_RESERVED) - return reportError(JSMSG_RESERVED_ID, kw->chars); - - if (kw->tokentype == TOK_STRICT_RESERVED) - return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars); - - // Working keyword. - *ttp = kw->tokentype; - return true; -} - -bool -TokenStream::checkForKeyword(JSAtom* atom, TokenKind* ttp) -{ - const KeywordInfo* kw = FindKeyword(atom); - if (!kw) - return true; - - return checkForKeyword(kw, ttp); -} - enum FirstCharKind { // A char16_t has the 'OneChar' kind if it, by itself, constitutes a valid // token that cannot also be a prefix of a longer token. E.g. ';' has the @@ -1363,36 +1453,18 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) length = userbuf.addressOfNextRawChar() - identStart; } - // Represent keywords as keyword tokens unless told otherwise. - if (modifier != KeywordIsName) { - if (const KeywordInfo* kw = FindKeyword(chars, length)) { - // That said, keywords can't contain escapes. (Contexts where - // keywords are treated as names, that also sometimes treat - // keywords as keywords, must manually check this requirement.) - // There are two exceptions - // 1) StrictReservedWords: These keywords need to be treated as - // names in non-strict mode. - // 2) yield is also treated as a name if it contains an escape - // sequence. The parser must handle this case separately. - if (hadUnicodeEscape && !( - (kw->tokentype == TOK_STRICT_RESERVED && !strictMode()) || - kw->tokentype == TOK_YIELD)) - { - reportError(JSMSG_ESCAPED_KEYWORD); - goto error; - } - - tp->type = TOK_NAME; - if (!checkForKeyword(kw, &tp->type)) - goto error; - if (tp->type != TOK_NAME && !hadUnicodeEscape) - goto out; + // Represent reserved words as reserved word tokens. + if (!hadUnicodeEscape) { + if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) { + tp->type = rw->tokentype; + goto out; } } JSAtom* atom = AtomizeChars(cx, chars, length); - if (!atom) + if (!atom) { goto error; + } tp->type = TOK_NAME; tp->setName(atom->asPropertyName()); goto out; @@ -1538,10 +1610,11 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) // grammar. We might not always be so permissive, so we warn // about it. if (c >= '8') { - if (!reportWarning(JSMSG_BAD_OCTAL, c == '8' ? "08" : "09")) { + if (!warning(JSMSG_BAD_OCTAL, c == '8' ? "08" : "09")) goto error; - } - goto decimal; // use the decimal scanner for the rest of the number + + // Use the decimal scanner for the rest of the number. + goto decimal; } c = getCharIgnoreEOL(); } @@ -1690,7 +1763,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) case '/': // Look for a single-line comment. if (matchChar('/')) { - c = peekChar(); + if (!peekChar(&c)) + goto error; if (c == '@' || c == '#') { bool shouldWarn = getChar() == '@'; if (!getDirectives(false, shouldWarn)) @@ -1757,7 +1831,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) RegExpFlag reflags = NoFlags; unsigned length = tokenbuf.length() + 1; while (true) { - c = peekChar(); + if (!peekChar(&c)) + goto error; if (c == 'g' && !(reflags & GlobalFlag)) reflags = RegExpFlag(reflags | GlobalFlag); else if (c == 'i' && !(reflags & IgnoreCaseFlag)) @@ -1774,7 +1849,8 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) length++; } - c = peekChar(); + if (!peekChar(&c)) + goto error; if (JS7_ISLET(c)) { char buf[2] = { '\0', '\0' }; tp->pos.begin += length + 1; @@ -1797,8 +1873,13 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) case '-': if (matchChar('-')) { - if (peekChar() == '>' && !flags.isDirtyLine) + int32_t c2; + if (!peekChar(&c2)) + goto error; + + if (c2 == '>' && !flags.isDirtyLine) goto skipline; + tp->type = TOK_DEC; } else { tp->type = matchChar('=') ? TOK_SUBASSIGN : TOK_SUB; @@ -1814,8 +1895,9 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) MOZ_CRASH("should have jumped to |out| or |error|"); out: - if (flags.hitOOM) - return reportError(JSMSG_OUT_OF_MEMORY); + if (flags.hitOOM) { + return false; + } flags.isDirtyLine = true; tp->pos.end = userbuf.offset(); @@ -1831,8 +1913,9 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) return true; error: - if (flags.hitOOM) - return reportError(JSMSG_OUT_OF_MEMORY); + if (flags.hitOOM) { + return false; + } flags.isDirtyLine = true; tp->pos.end = userbuf.offset(); @@ -1850,37 +1933,6 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier) } bool -TokenStream::getBracedUnicode(uint32_t* cp) -{ - consumeKnownChar('{'); - - bool first = true; - int32_t c; - uint32_t code = 0; - while (true) { - c = getCharIgnoreEOL(); - if (c == EOF) - return false; - if (c == '}') { - if (first) - return false; - break; - } - - if (!JS7_ISHEX(c)) - return false; - - code = (code << 4) | JS7_UNHEX(c); - if (code > unicode::NonBMPMax) - return false; - first = false; - } - - *cp = code; - return true; -} - -bool TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) { int c; @@ -1897,11 +1949,15 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) while ((c = getCharIgnoreEOL()) != untilChar) { if (c == EOF) { ungetCharIgnoreEOL(c); - reportError(JSMSG_UNTERMINATED_STRING); + error(JSMSG_UNTERMINATED_STRING); return false; } if (c == '\\') { + // When parsing templates, we don't immediately report errors for + // invalid escapes; these are handled by the parser. + // In those cases we don't append to tokenbuf, since it won't be + // read. switch (c = getChar()) { case 'b': c = '\b'; break; case 'f': c = '\f'; break; @@ -1917,12 +1973,73 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) // Unicode character specification. case 'u': { - if (peekChar() == '{') { - uint32_t code; - if (!getBracedUnicode(&code)) { - reportError(JSMSG_MALFORMED_ESCAPE, "Unicode"); - return false; - } + uint32_t code = 0; + + int32_t c2; + if (!peekChar(&c2)) + return false; + + uint32_t start = userbuf.offset() - 2; + + if (c2 == '{') { + consumeKnownChar('{'); + + bool first = true; + bool valid = true; + do { + int32_t c = getCharIgnoreEOL(); + if (c == EOF) { + if (parsingTemplate) { + setInvalidTemplateEscape(start, InvalidEscapeType::Unicode); + valid = false; + break; + } + reportInvalidEscapeError(start, InvalidEscapeType::Unicode); + return false; + } + if (c == '}') { + if (first) { + if (parsingTemplate) { + setInvalidTemplateEscape(start, InvalidEscapeType::Unicode); + valid = false; + break; + } + reportInvalidEscapeError(start, InvalidEscapeType::Unicode); + return false; + } + break; + } + + if (!JS7_ISHEX(c)) { + if (parsingTemplate) { + // We put the character back so that we read + // it on the next pass, which matters if it + // was '`' or '\'. + ungetCharIgnoreEOL(c); + setInvalidTemplateEscape(start, InvalidEscapeType::Unicode); + valid = false; + break; + } + reportInvalidEscapeError(start, InvalidEscapeType::Unicode); + return false; + } + + code = (code << 4) | JS7_UNHEX(c); + if (code > unicode::NonBMPMax) { + if (parsingTemplate) { + setInvalidTemplateEscape(start + 3, InvalidEscapeType::UnicodeOverflow); + valid = false; + break; + } + reportInvalidEscapeError(start + 3, InvalidEscapeType::UnicodeOverflow); + return false; + } + + first = false; + } while (true); + + if (!valid) + continue; MOZ_ASSERT(code <= unicode::NonBMPMax); if (code < unicode::NonBMPMin) { @@ -1945,7 +2062,11 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) c = (c << 4) + JS7_UNHEX(cp[3]); skipChars(4); } else { - reportError(JSMSG_MALFORMED_ESCAPE, "Unicode"); + if (parsingTemplate) { + setInvalidTemplateEscape(start, InvalidEscapeType::Unicode); + continue; + } + reportInvalidEscapeError(start, InvalidEscapeType::Unicode); return false; } break; @@ -1958,7 +2079,12 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]); skipChars(2); } else { - reportError(JSMSG_MALFORMED_ESCAPE, "hexadecimal"); + uint32_t start = userbuf.offset() - 2; + if (parsingTemplate) { + setInvalidTemplateEscape(start, InvalidEscapeType::Hexadecimal); + continue; + } + reportInvalidEscapeError(start, InvalidEscapeType::Hexadecimal); return false; } break; @@ -1969,13 +2095,14 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) if (JS7_ISOCT(c)) { int32_t val = JS7_UNOCT(c); - c = peekChar(); + if (!peekChar(&c)) + return false; // Strict mode code allows only \0, then a non-digit. if (val != 0 || JS7_ISDEC(c)) { if (parsingTemplate) { - reportError(JSMSG_DEPRECATED_OCTAL); - return false; + setInvalidTemplateEscape(userbuf.offset() - 2, InvalidEscapeType::Octal); + continue; } if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL)) return false; @@ -1985,7 +2112,8 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) if (JS7_ISOCT(c)) { val = 8 * val + JS7_UNOCT(c); getChar(); - c = peekChar(); + if (!peekChar(&c)) + return false; if (JS7_ISOCT(c)) { int32_t save = val; val = 8 * val + JS7_UNOCT(c); @@ -2003,7 +2131,7 @@ TokenStream::getStringOrTemplateToken(int untilChar, Token** tp) } else if (TokenBuf::isRawEOLChar(c)) { if (!parsingTemplate) { ungetCharIgnoreEOL(c); - reportError(JSMSG_UNTERMINATED_STRING); + error(JSMSG_UNTERMINATED_STRING); return false; } if (c == '\r') { diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 6ba9fba5a..2744fd144 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -26,14 +26,13 @@ #include "js/UniquePtr.h" #include "js/Vector.h" #include "vm/RegExpObject.h" +#include "vm/String.h" struct KeywordInfo; namespace js { namespace frontend { -class AutoAwaitIsKeyword; - struct TokenPos { uint32_t begin; // Offset of the token's first char. uint32_t end; // Offset of 1 past the token's last char. @@ -80,6 +79,20 @@ struct TokenPos { enum DecimalPoint { NoDecimal = false, HasDecimal = true }; +enum class InvalidEscapeType { + // No invalid character escapes. + None, + // A malformed \x escape. + Hexadecimal, + // A malformed \u escape. + Unicode, + // An otherwise well-formed \u escape which represents a + // codepoint > 10FFFF. + UnicodeOverflow, + // An octal escape in a template token. + Octal +}; + class TokenStream; struct Token @@ -106,9 +119,6 @@ struct Token // TOK_DIV. Operand, - // Treat keywords as names by returning TOK_NAME. - KeywordIsName, - // Treat subsequent characters as the tail of a template literal, after // a template substitution, beginning with a "}", continuing with zero // or more template literal characters, and ending with either "${" or @@ -150,10 +160,6 @@ struct Token // If a semicolon is inserted automatically, the next token is already // gotten with None, but we expect Operand. OperandIsNone, - - // If name of method definition is `get` or `set`, the next token is - // already gotten with KeywordIsName, but we expect None. - NoneIsKeywordIsName, }; friend class TokenStream; @@ -210,11 +216,6 @@ struct Token return u.name->JSAtom::asPropertyName(); // poor-man's type verification } - bool nameContainsEscape() const { - PropertyName* n = name(); - return pos.begin + n->length() != pos.end; - } - JSAtom* atom() const { MOZ_ASSERT(type == TOK_STRING || type == TOK_TEMPLATE_HEAD || @@ -240,10 +241,22 @@ struct Token }; class CompileError : public JSErrorReport { -public: + public: void throwError(JSContext* cx); }; +extern const char* +ReservedWordToCharZ(PropertyName* str); + +extern MOZ_MUST_USE bool +IsFutureReservedWord(JSLinearString* str); + +extern MOZ_MUST_USE bool +IsReservedWordLiteral(JSLinearString* str); + +extern MOZ_MUST_USE bool +IsStrictReservedWord(JSLinearString* str); + // Ideally, tokenizing would be entirely independent of context. But the // strict mode flag, which is in SharedContext, affects tokenizing, and // TokenStream needs to see it. @@ -330,25 +343,26 @@ class MOZ_STACK_CLASS TokenStream JSVersion versionNumber() const { return VersionNumber(options().version); } JSVersion versionWithFlags() const { return options().version; } + private: + PropertyName* reservedWordToPropertyName(TokenKind tt) const; + + public: PropertyName* currentName() const { - if (isCurrentTokenType(TOK_YIELD)) - return cx->names().yield; - MOZ_ASSERT(isCurrentTokenType(TOK_NAME)); - return currentToken().name(); + if (isCurrentTokenType(TOK_NAME)) { + return currentToken().name(); + } + + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(currentToken().type)); + return reservedWordToPropertyName(currentToken().type); } PropertyName* nextName() const { - if (nextToken().type == TOK_YIELD) - return cx->names().yield; - MOZ_ASSERT(nextToken().type == TOK_NAME); - return nextToken().name(); - } + if (nextToken().type != TOK_NAME) { + return nextToken().name(); + } - bool nextNameContainsEscape() const { - if (nextToken().type == TOK_YIELD) - return false; - MOZ_ASSERT(nextToken().type == TOK_NAME); - return nextToken().nameContainsEscape(); + MOZ_ASSERT(TokenKindIsPossibleIdentifierName(nextToken().type)); + return reservedWordToPropertyName(nextToken().type); } bool isCurrentTokenAssignment() const { @@ -361,21 +375,47 @@ class MOZ_STACK_CLASS TokenStream bool hadError() const { return flags.hadError; } void clearSawOctalEscape() { flags.sawOctalEscape = false; } + bool hasInvalidTemplateEscape() const { + return invalidTemplateEscapeType != InvalidEscapeType::None; + } + void clearInvalidTemplateEscape() { + invalidTemplateEscapeType = InvalidEscapeType::None; + } + + // If there is an invalid escape in a template, report it and return false, + // otherwise return true. + bool checkForInvalidTemplateEscapeError() { + if (invalidTemplateEscapeType == InvalidEscapeType::None) + return true; + + reportInvalidEscapeError(invalidTemplateEscapeOffset, invalidTemplateEscapeType); + return false; + } + // TokenStream-specific error reporters. bool reportError(unsigned errorNumber, ...); bool reportErrorNoOffset(unsigned errorNumber, ...); - bool reportWarning(unsigned errorNumber, ...); + + // Report the given error at the current offset. + void error(unsigned errorNumber, ...); + + // Report the given error at the given offset. + void errorAt(uint32_t offset, unsigned errorNumber, ...); + + // Warn at the current offset. + MOZ_MUST_USE bool warning(unsigned errorNumber, ...); static const uint32_t NoOffset = UINT32_MAX; // General-purpose error reporters. You should avoid calling these - // directly, and instead use the more succinct alternatives (e.g. - // reportError()) in TokenStream, Parser, and BytecodeEmitter. - bool reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigned errorNumber, - va_list args); - bool reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, unsigned errorNumber, - va_list args); - bool reportExtraWarningErrorNumberVA(uint32_t offset, unsigned errorNumber, va_list args); + // directly, and instead use the more succinct alternatives (error(), + // warning(), &c.) in TokenStream, Parser, and BytecodeEmitter. + bool reportCompileErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, unsigned flags, + unsigned errorNumber, va_list args); + bool reportStrictModeErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, + bool strictMode, unsigned errorNumber, va_list args); + bool reportExtraWarningErrorNumberVA(UniquePtr<JSErrorNotes> notes, uint32_t offset, + unsigned errorNumber, va_list args); // asm.js reporter void reportAsmJSError(uint32_t offset, unsigned errorNumber, ...); @@ -414,6 +454,33 @@ class MOZ_STACK_CLASS TokenStream bool reportStrictModeError(unsigned errorNumber, ...); bool strictMode() const { return strictModeGetter && strictModeGetter->strictMode(); } + void setInvalidTemplateEscape(uint32_t offset, InvalidEscapeType type) { + MOZ_ASSERT(type != InvalidEscapeType::None); + if (invalidTemplateEscapeType != InvalidEscapeType::None) + return; + invalidTemplateEscapeOffset = offset; + invalidTemplateEscapeType = type; + } + void reportInvalidEscapeError(uint32_t offset, InvalidEscapeType type) { + switch (type) { + case InvalidEscapeType::None: + MOZ_ASSERT_UNREACHABLE("unexpected InvalidEscapeType"); + return; + case InvalidEscapeType::Hexadecimal: + errorAt(offset, JSMSG_MALFORMED_ESCAPE, "hexadecimal"); + return; + case InvalidEscapeType::Unicode: + errorAt(offset, JSMSG_MALFORMED_ESCAPE, "Unicode"); + return; + case InvalidEscapeType::UnicodeOverflow: + errorAt(offset, JSMSG_UNICODE_OVERFLOW, "escape sequence"); + return; + case InvalidEscapeType::Octal: + errorAt(offset, JSMSG_DEPRECATED_OCTAL); + return; + } + } + static JSAtom* atomize(ExclusiveContext* cx, CharBuffer& cb); MOZ_MUST_USE bool putIdentInTokenbuf(const char16_t* identStart); @@ -431,21 +498,19 @@ class MOZ_STACK_CLASS TokenStream {} }; - bool awaitIsKeyword = false; - friend class AutoAwaitIsKeyword; + uint32_t invalidTemplateEscapeOffset = 0; + InvalidEscapeType invalidTemplateEscapeType = InvalidEscapeType::None; public: typedef Token::Modifier Modifier; static constexpr Modifier None = Token::None; static constexpr Modifier Operand = Token::Operand; - static constexpr Modifier KeywordIsName = Token::KeywordIsName; static constexpr Modifier TemplateTail = Token::TemplateTail; typedef Token::ModifierException ModifierException; static constexpr ModifierException NoException = Token::NoException; static constexpr ModifierException NoneIsOperand = Token::NoneIsOperand; static constexpr ModifierException OperandIsNone = Token::OperandIsNone; - static constexpr ModifierException NoneIsKeywordIsName = Token::NoneIsKeywordIsName; void addModifierException(ModifierException modifierException) { #ifdef DEBUG @@ -474,10 +539,6 @@ class MOZ_STACK_CLASS TokenStream MOZ_ASSERT(next.type != TOK_DIV && next.type != TOK_REGEXP, "next token requires contextual specifier to be parsed unambiguously"); break; - case NoneIsKeywordIsName: - MOZ_ASSERT(next.modifier == KeywordIsName); - MOZ_ASSERT(next.type != TOK_NAME); - break; default: MOZ_CRASH("unexpected modifier exception"); } @@ -504,18 +565,17 @@ class MOZ_STACK_CLASS TokenStream return; } - if (lookaheadToken.modifierException == NoneIsKeywordIsName) { - // getToken() permissibly following getToken(KeywordIsName). - if (modifier == None && lookaheadToken.modifier == KeywordIsName) - return; - } - MOZ_ASSERT_UNREACHABLE("this token was previously looked up with a " "different modifier, potentially making " "tokenization non-deterministic"); #endif } + const Token& nextToken() const { + MOZ_ASSERT(hasLookahead()); + return tokens[(cursor + 1) & ntokensMask]; + } + // Advance to the next token. If the token stream encountered an error, // return false. Otherwise return true and store the token kind in |*ttp|. MOZ_MUST_USE bool getToken(TokenKind* ttp, Modifier modifier = None) { @@ -644,36 +704,6 @@ class MOZ_STACK_CLASS TokenStream MOZ_ALWAYS_TRUE(matched); } - // Like matchToken(..., TOK_NAME) but further matching the name token only - // if it has the given characters, without containing escape sequences. - // If the name token has the given characters yet *does* contain an escape, - // a syntax error will be reported. - // - // This latter behavior makes this method unsuitable for use in any context - // where ASI might occur. In such places, an escaped "contextual keyword" - // on a new line is the start of an ExpressionStatement, not a continuation - // of a StatementListItem (or ImportDeclaration or ExportDeclaration, in - // modules). - MOZ_MUST_USE bool matchContextualKeyword(bool* matchedp, Handle<PropertyName*> keyword, - Modifier modifier = None) - { - TokenKind token; - if (!getToken(&token, modifier)) - return false; - if (token == TOK_NAME && currentToken().name() == keyword) { - if (currentToken().nameContainsEscape()) { - reportError(JSMSG_ESCAPED_KEYWORD); - return false; - } - - *matchedp = true; - } else { - *matchedp = false; - ungetToken(); - } - return true; - } - MOZ_MUST_USE bool nextTokenEndsExpr(bool* endsExpr) { TokenKind tt; if (!peekToken(&tt)) @@ -739,19 +769,6 @@ class MOZ_STACK_CLASS TokenStream return sourceMapURL_.get(); } - // If |atom| is not a keyword in this version, return true with *ttp - // unchanged. - // - // If it is a reserved word in this version and strictness mode, and thus - // can't be present in correct code, report a SyntaxError and return false. - // - // If it is a keyword, like "if", return true with the keyword's TokenKind - // in *ttp. - MOZ_MUST_USE bool checkForKeyword(JSAtom* atom, TokenKind* ttp); - - // Same semantics as above, but for the provided keyword. - MOZ_MUST_USE bool checkForKeyword(const KeywordInfo* kw, TokenKind* ttp); - // This class maps a userbuf offset (which is 0-indexed) to a line number // (which is 1-indexed) and a column index (which is 0-indexed). class SourceCoords @@ -947,7 +964,6 @@ class MOZ_STACK_CLASS TokenStream MOZ_MUST_USE bool getTokenInternal(TokenKind* ttp, Modifier modifier); - MOZ_MUST_USE bool getBracedUnicode(uint32_t* code); MOZ_MUST_USE bool getStringOrTemplateToken(int untilChar, Token** tp); int32_t getChar(); @@ -964,7 +980,7 @@ class MOZ_STACK_CLASS TokenStream MOZ_MUST_USE bool getDirectives(bool isMultiline, bool shouldWarnDeprecated); MOZ_MUST_USE bool getDirective(bool isMultiline, bool shouldWarnDeprecated, - const char* directive, int directiveLength, + const char* directive, uint8_t directiveLength, const char* errorMsgPragma, UniquePtr<char16_t[], JS::FreePolicy>* destination); MOZ_MUST_USE bool getDisplayURL(bool isMultiline, bool shouldWarnDeprecated); @@ -982,29 +998,30 @@ class MOZ_STACK_CLASS TokenStream MOZ_ASSERT(c == expect); } - int32_t peekChar() { - int32_t c = getChar(); - ungetChar(c); - return c; + MOZ_MUST_USE bool peekChar(int32_t* c) { + *c = getChar(); + ungetChar(*c); + return true; } - void skipChars(int n) { - while (--n >= 0) - getChar(); + void skipChars(uint8_t n) { + while (n-- > 0) { + MOZ_ASSERT(userbuf.hasRawChars()); + mozilla::DebugOnly<int32_t> c = getCharIgnoreEOL(); + MOZ_ASSERT(c != '\n'); + } } - void skipCharsIgnoreEOL(int n) { - while (--n >= 0) + void skipCharsIgnoreEOL(uint8_t n) { + while (n-- > 0) { + MOZ_ASSERT(userbuf.hasRawChars()); getCharIgnoreEOL(); + } } void updateLineInfoForEOL(); void updateFlagsForEOL(); - const Token& nextToken() const { - MOZ_ASSERT(hasLookahead()); - return tokens[(cursor + 1) & ntokensMask]; - } bool hasLookahead() const { return lookahead > 0; } @@ -1029,25 +1046,6 @@ class MOZ_STACK_CLASS TokenStream StrictModeGetter* strictModeGetter; // used to test for strict mode }; -class MOZ_STACK_CLASS AutoAwaitIsKeyword -{ -private: - TokenStream* ts_; - bool oldAwaitIsKeyword_; - -public: - AutoAwaitIsKeyword(TokenStream* ts, bool awaitIsKeyword) { - ts_ = ts; - oldAwaitIsKeyword_ = ts_->awaitIsKeyword; - ts_->awaitIsKeyword = awaitIsKeyword; - } - - ~AutoAwaitIsKeyword() { - ts_->awaitIsKeyword = oldAwaitIsKeyword_; - ts_ = nullptr; - } -}; - extern const char* TokenKindToDesc(TokenKind tt); diff --git a/js/src/irregexp/RegExpParser.cpp b/js/src/irregexp/RegExpParser.cpp index ccc6ae3eb..8bd88047a 100644 --- a/js/src/irregexp/RegExpParser.cpp +++ b/js/src/irregexp/RegExpParser.cpp @@ -243,10 +243,10 @@ RegExpParser<CharT>::RegExpParser(frontend::TokenStream& ts, LifoAlloc* alloc, template <typename CharT> RegExpTree* -RegExpParser<CharT>::ReportError(unsigned errorNumber) +RegExpParser<CharT>::ReportError(unsigned errorNumber, const char* param /* = nullptr */) { gc::AutoSuppressGC suppressGC(ts.context()); - ts.reportError(errorNumber); + ts.reportError(errorNumber, param); return nullptr; } @@ -350,7 +350,7 @@ RegExpParser<CharT>::ParseBracedHexEscape(widechar* value) } code = (code << 4) | d; if (code > unicode::NonBMPMax) { - ReportError(JSMSG_UNICODE_OVERFLOW); + ReportError(JSMSG_UNICODE_OVERFLOW, "regular expression"); return false; } Advance(); diff --git a/js/src/irregexp/RegExpParser.h b/js/src/irregexp/RegExpParser.h index b5228a86f..0a7e61858 100644 --- a/js/src/irregexp/RegExpParser.h +++ b/js/src/irregexp/RegExpParser.h @@ -211,7 +211,7 @@ class RegExpParser bool ParseBackReferenceIndex(int* index_out); bool ParseClassAtom(char16_t* char_class, widechar *value); - RegExpTree* ReportError(unsigned errorNumber); + RegExpTree* ReportError(unsigned errorNumber, const char* param = nullptr); void Advance(); void Advance(int dist) { next_pos_ += dist - 1; diff --git a/js/src/jit-test/modules/export-default-async-asi.js b/js/src/jit-test/modules/export-default-async-asi.js new file mode 100644 index 000000000..a69a7aa3d --- /dev/null +++ b/js/src/jit-test/modules/export-default-async-asi.js @@ -0,0 +1,2 @@ +export default async // ASI occurs here due to the [no LineTerminator here] restriction on default-exporting an async function +function async() { return 17; } diff --git a/js/src/jit-test/tests/asm.js/import-function-toPrimitive.js b/js/src/jit-test/tests/asm.js/import-function-toPrimitive.js new file mode 100644 index 000000000..aa529b465 --- /dev/null +++ b/js/src/jit-test/tests/asm.js/import-function-toPrimitive.js @@ -0,0 +1,26 @@ +var counter = 0; + +function f(stdlib, foreign) +{ + "use asm"; + var a = +foreign.a; + var b = +foreign.b; + function g() {} + return g; +} + +var foreign = + { + a: function() {}, + b: /value that doesn't coerce purely/, + }; + +foreign.a[Symbol.toPrimitive] = + function() + { + counter++; + return 0; + }; + +f(null, foreign); +assertEq(counter, 1); diff --git a/js/src/jit-test/tests/baseline/bug1344334.js b/js/src/jit-test/tests/baseline/bug1344334.js new file mode 100644 index 000000000..66994338a --- /dev/null +++ b/js/src/jit-test/tests/baseline/bug1344334.js @@ -0,0 +1,14 @@ +if (!('oomTest' in this)) + quit(); + +function f(s) { + s + "x"; + s.indexOf("y") === 0; + oomTest(new Function(s)); +} +var s = ` + class TestClass { constructor() {} } + for (var fun of hasPrototype) {} +`; +if (s.length) + f(s); diff --git a/js/src/jit-test/tests/basic/bug713226.js b/js/src/jit-test/tests/basic/bug713226.js index 3ae991f43..36858b86c 100644 --- a/js/src/jit-test/tests/basic/bug713226.js +++ b/js/src/jit-test/tests/basic/bug713226.js @@ -8,7 +8,7 @@ function addDebug(g, id) {\ var debuggerGlobal = newGlobal();\ debuggerGlobal.debuggee = g;\ debuggerGlobal.id = id;\ - debuggerGlobal.print = function (s) { (g) += s; };\ + debuggerGlobal.print = function (s) { print(s); };\ debuggerGlobal.eval('var dbg = new Debugger(debuggee);dbg.onDebuggerStatement = function () { print(id); debugger; };');\ return debuggerGlobal;\ }\ diff --git a/js/src/jit-test/tests/basic/hasnativemethodpure-optimization.js b/js/src/jit-test/tests/basic/hasnativemethodpure-optimization.js new file mode 100644 index 000000000..2f5e99186 --- /dev/null +++ b/js/src/jit-test/tests/basic/hasnativemethodpure-optimization.js @@ -0,0 +1,21 @@ +load(libdir + "asserts.js"); + +let string = Object.defineProperty(new String("123"), "valueOf", { + get: function() { throw "get-valueOf"; } +}); +assertThrowsValue(() => "" + string, "get-valueOf"); + +string = Object.defineProperty(new String("123"), "toString", { + get: function() { throw "get-toString"; } +}); +assertThrowsValue(() => string.toLowerCase(), "get-toString"); + +string = Object.defineProperty(new String("123"), Symbol.toPrimitive, { + get: function() { throw "get-toPrimitive"; } +}); +assertThrowsValue(() => string.toLowerCase(), "get-toPrimitive"); + +let number = Object.defineProperty(new Number(123), "valueOf", { + get: function() { throw "get-valueOf"; } +}); +assertThrowsValue(() => +number, "get-valueOf");
\ No newline at end of file diff --git a/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js b/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js index 7be49b7f3..be7f528b9 100644 --- a/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js +++ b/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js @@ -8,9 +8,11 @@ assertEq(typeof f1(true), "function"); assertEq(f1(false), 3); function f2(b, w) { + // Annex B doesn't apply to functions in blocks with the same name as a + // parameter. if (b) function w() {} return w; } -assertEq(typeof f2(true, 3), "function"); +assertEq(typeof f2(true, 3), "number"); assertEq(f2(false, 3), 3); diff --git a/js/src/jit-test/tests/class/bug1357506.js b/js/src/jit-test/tests/class/bug1357506.js new file mode 100644 index 000000000..52a5643e6 --- /dev/null +++ b/js/src/jit-test/tests/class/bug1357506.js @@ -0,0 +1,8 @@ +// Test that constructors that abort due to asm.js do not assert due to the +// parser keeping track of the FunctionBox corresponding to the constructor. + +class a { + constructor() { + "use asm"; + } +} diff --git a/js/src/jit-test/tests/class/bug1359622.js b/js/src/jit-test/tests/class/bug1359622.js new file mode 100644 index 000000000..b4a0df749 --- /dev/null +++ b/js/src/jit-test/tests/class/bug1359622.js @@ -0,0 +1,4 @@ +setDiscardSource(true) +evaluate(` + unescape(class get { static staticMethod() {} }); +`); diff --git a/js/src/jit-test/tests/debug/wasm-12.js b/js/src/jit-test/tests/debug/wasm-12.js new file mode 100644 index 000000000..18d3b574d --- /dev/null +++ b/js/src/jit-test/tests/debug/wasm-12.js @@ -0,0 +1,26 @@ +// Tests that wasm module scripts have special URLs. + +if (!wasmIsSupported()) + quit(); + +var g = newGlobal(); +g.eval(` +function initWasm(s) { return new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(s))); } +o = initWasm('(module (func) (export "" 0))'); +o2 = initWasm('(module (func) (func) (export "" 1))'); +`); + +function isWasm(script) { return script.format === "wasm"; } + +function isValidWasmURL(url) { + // The URLs will have the following format: + // wasm: [<uri-econded-filename-of-host> ":"] <64-bit-hash> + return /^wasm:(?:[^:]*:)*?[0-9a-f]{16}$/.test(url); +} + +var dbg = new Debugger(g); +var foundScripts = dbg.findScripts().filter(isWasm); +assertEq(foundScripts.length, 2); +assertEq(isValidWasmURL(foundScripts[0].source.url), true); +assertEq(isValidWasmURL(foundScripts[1].source.url), true); +assertEq(foundScripts[0].source.url != foundScripts[1].source.url, true); diff --git a/js/src/jit-test/tests/modules/export-declaration.js b/js/src/jit-test/tests/modules/export-declaration.js index 3c4a9b735..9925f2c68 100644 --- a/js/src/jit-test/tests/modules/export-declaration.js +++ b/js/src/jit-test/tests/modules/export-declaration.js @@ -403,12 +403,52 @@ assertThrowsInstanceOf(function() { parseAsModule("export {,} from 'a'"); }, SyntaxError); +program([ + exportDeclaration( + null, + [ + exportSpecifier( + ident("true"), + ident("true") + ), + ], + lit("b"), + false + ) +]).assert(parseAsModule("export { true } from 'b'")); + +program([ + exportDeclaration( + null, + [ + exportSpecifier( + ident("true"), + ident("name") + ), + ], + lit("b"), + false + ) +]).assert(parseAsModule("export { true as name } from 'b'")); + +assertThrowsInstanceOf(function() { + parseAsModule("export { true }"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export { true as name }"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export { static }"); +}, SyntaxError); + assertThrowsInstanceOf(function() { - parseAsModule("export { true as a } from 'b'"); + parseAsModule("export { static as name }"); }, SyntaxError); assertThrowsInstanceOf(function () { - parseAsModule("export { a } from 'b' f();"); + parseAsModule("export { name } from 'b' f();"); }, SyntaxError); assertThrowsInstanceOf(function () { diff --git a/js/src/jit-test/tests/modules/function-redeclaration.js b/js/src/jit-test/tests/modules/function-redeclaration.js new file mode 100644 index 000000000..b84704641 --- /dev/null +++ b/js/src/jit-test/tests/modules/function-redeclaration.js @@ -0,0 +1,94 @@ +load(libdir + "asserts.js"); + +var functionDeclarations = [ + "function f(){}", + "function* f(){}", + "async function f(){}", +]; + +var varDeclarations = [ + "var f", + "{ var f; }", + "for (var f in null);", + "for (var f of null);", + "for (var f; ;);", +]; + +var lexicalDeclarations = [ + "let f;", + "const f = 0;", + "class f {};", +]; + +var imports = [ + "import f from '';", + "import f, {} from '';", + "import d, {f} from '';", + "import d, {f as f} from '';", + "import d, {foo as f} from '';", + "import f, * as d from '';", + "import d, * as f from '';", + "import {f} from '';", + "import {f as f} from '';", + "import {foo as f} from '';", + "import* as f from '';", +]; + +var exports = [ + "export var f;", + ...functionDeclarations.map(fn => `export ${fn};`), + ...lexicalDeclarations.map(ld => `export ${ld};`), + ...functionDeclarations.map(fn => `export default ${fn};`), + "export default class f {};", +]; + +var redeclarations = [ + ...functionDeclarations, + ...varDeclarations, + ...lexicalDeclarations, + ...imports, + ...exports, +]; + +var noredeclarations = [ + ...functionDeclarations.map(fn => `{ ${fn} }`), + ...lexicalDeclarations.map(ld => `{ ${ld} }`), + ...["let", "const"].map(ld => `for (${ld} f in null);`), + ...["let", "const"].map(ld => `for (${ld} f of null);`), + ...["let", "const"].map(ld => `for (${ld} f = 0; ;);`), + "export {f};", + "export {f as f};", + "export {foo as f}; var foo;", + "export {f} from '';", + "export {f as f} from '';", + "export {foo as f} from '';", +]; + +for (var decl of functionDeclarations) { + for (var redecl of redeclarations) { + assertThrowsInstanceOf(() => { + parseModule(` + ${decl} + ${redecl} + `); + }, SyntaxError); + + assertThrowsInstanceOf(() => { + parseModule(` + ${redecl} + ${decl} + `); + }, SyntaxError); + } + + for (var redecl of noredeclarations) { + parseModule(` + ${decl} + ${redecl} + `); + parseModule(` + ${redecl} + ${decl} + `); + } +} diff --git a/js/src/jit-test/tests/parser/arrow-rest.js b/js/src/jit-test/tests/parser/arrow-rest.js index 53750f25b..b1429066e 100644 --- a/js/src/jit-test/tests/parser/arrow-rest.js +++ b/js/src/jit-test/tests/parser/arrow-rest.js @@ -39,7 +39,7 @@ testThrow(` testThrow(` ({...a)=> -`, 2); +`, 6); testThrow(` function f([... ...a)=> @@ -47,7 +47,7 @@ function f([... ...a)=> testThrow(` function f({...a)=> -`, 12); +`, 16); // arrow @@ -67,7 +67,7 @@ var [... ...a)=> testThrow(` var {...a)=> -`, 5); +`, 9); // initializer diff --git a/js/src/jit-test/tests/parser/missing-closing-brace.js b/js/src/jit-test/tests/parser/missing-closing-brace.js new file mode 100644 index 000000000..6820954ae --- /dev/null +++ b/js/src/jit-test/tests/parser/missing-closing-brace.js @@ -0,0 +1,90 @@ +function test(source, [lineNumber, columnNumber], openType = "{", closeType = "}") { + let caught = false; + try { + Reflect.parse(source, { source: "foo.js" }); + } catch (e) { + assertEq(e.message.includes("missing " + closeType + " "), true); + let notes = getErrorNotes(e); + assertEq(notes.length, 1); + let note = notes[0]; + assertEq(note.message, openType + " opened at line " + lineNumber + ", column " + columnNumber); + assertEq(note.fileName, "foo.js"); + assertEq(note.lineNumber, lineNumber); + assertEq(note.columnNumber, columnNumber); + caught = true; + } + assertEq(caught, true); +} + +// Function + +test(` +function test1() { +} +function test2() { + if (true) { + //} +} +function test3() { +} +`, [4, 17]); + +// Block statement. +test(` +{ + if (true) { +} +`, [2, 0]); +test(` +if (true) { + if (true) { +} +`, [2, 10]); +test(` +for (;;) { + if (true) { +} +`, [2, 9]); +test(` +while (true) { + if (true) { +} +`, [2, 13]); +test(` +do { + do { +} while(true); +`, [2, 3]); + +// try-catch-finally. +test(` +try { + if (true) { +} +`, [2, 4]); +test(` +try { +} catch (e) { + if (true) { +} +`, [3, 12]); +test(` +try { +} finally { + if (true) { +} +`, [3, 10]); + +// Object literal. +test(` +var x = { + foo: { +}; +`, [2, 8]); + +// Array literal. +test(` +var x = [ + [ +]; +`, [2, 8], "[", "]"); diff --git a/js/src/jit-test/tests/parser/redeclaration.js b/js/src/jit-test/tests/parser/redeclaration.js new file mode 100644 index 000000000..f719021ac --- /dev/null +++ b/js/src/jit-test/tests/parser/redeclaration.js @@ -0,0 +1,230 @@ +// Error message for redeclaration should show the position where the variable +// was declared. + +const npos = -1; + +function test_one(fun, filename, name, + [prevLineNumber, prevColumnNumber], + [lineNumber, columnNumber]) { + let caught = false; + try { + fun(); + } catch (e) { + assertEq(e.message.includes("redeclaration"), true); + assertEq(e.lineNumber, lineNumber); + assertEq(e.columnNumber, columnNumber); + let notes = getErrorNotes(e); + if (prevLineNumber == npos) { + assertEq(notes.length, 0); + } else { + assertEq(notes.length, 1); + let note = notes[0]; + assertEq(note.message, + `Previously declared at line ${prevLineNumber}, column ${prevColumnNumber}`); + assertEq(note.lineNumber, prevLineNumber); + assertEq(note.columnNumber, prevColumnNumber); + if (filename) + assertEq(note.fileName, filename); + } + caught = true; + } + assertEq(caught, true); +} + +function test_parse(source, ...args) { + test_one(() => { + Reflect.parse(source, { source: "foo.js" }); + }, "foo.js", ...args); +} + +function test_eval(source, ...args) { + test_one(() => { + eval(source); + }, undefined, ...args); +} + +function test(...args) { + test_parse(...args); + test_eval(...args); +} + +// let + +test(` +let a, a; +`, "a", [2, 4], [2, 7]); + +test(` +let a; +let a; +`, "a", [2, 4], [3, 4]); + +test(` +let a; +const a = 1; +`, "a", [2, 4], [3, 6]); + +test(` +let a; +var a; +`, "a", [2, 4], [3, 4]); + +test(` +let a; +function a() { +} +`, "a", [2, 4], [3, 9]); + +test(` +{ + let a; + function a() { + } +} +`, "a", [3, 6], [4, 11]); + +// const + +test(` +const a = 1, a = 2; +`, "a", [2, 6], [2, 13]); + +test(` +const a = 1; +const a = 2; +`, "a", [2, 6], [3, 6]); + +test(` +const a = 1; +let a; +`, "a", [2, 6], [3, 4]); + +test(` +const a = 1; +var a; +`, "a", [2, 6], [3, 4]); + +test(` +const a = 1; +function a() { +} +`, "a", [2, 6], [3, 9]); + +test(` +{ + const a = 1; + function a() { + } +} +`, "a", [3, 8], [4, 11]); + +// var + +test(` +var a; +let a; +`, "a", [2, 4], [3, 4]); + +test(` +var a; +const a = 1; +`, "a", [2, 4], [3, 6]); + +// function + +test(` +function a() {}; +let a; +`, "a", [2, 9], [3, 4]); + +test(` +function a() {}; +const a = 1; +`, "a", [2, 9], [3, 6]); + +// Annex B lexical function + +test(` +{ + function a() {}; + let a; +} +`, "a", [3, 11], [4, 6]); + +test(` +{ + function a() {}; + const a = 1; +} +`, "a", [3, 11], [4, 8]); + +// catch parameter + +test(` +try { +} catch (a) { + let a; +} +`, "a", [3, 9], [4, 6]); + +test(` +try { +} catch (a) { + const a = 1; +} +`, "a", [3, 9], [4, 8]); + +test(` +try { +} catch (a) { + function a() { + } +} +`, "a", [3, 9], [4, 11]); + +// parameter + +test(` +function f(a) { + let a; +} +`, "a", [2, 11], [3, 6]); + +test(` +function f(a) { + const a = 1; +} +`, "a", [2, 11], [3, 8]); + +test(` +function f([a]) { + let a; +} +`, "a", [2, 12], [3, 6]); + +test(` +function f({a}) { + let a; +} +`, "a", [2, 12], [3, 6]); + +test(` +function f(...a) { + let a; +} +`, "a", [2, 14], [3, 6]); + +test(` +function f(a=1) { + let a; +} +`, "a", [2, 11], [3, 6]); + +// eval +// We don't have position information at runtime. +// No note should be shown. + +test_eval(` +let a; +eval("var a"); +`, "a", [npos, npos], [1, 4]); diff --git a/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js b/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js index d66548680..e9dd5d526 100644 --- a/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js +++ b/js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js @@ -31,7 +31,7 @@ cold_and_warm(Object.prototype.toString, { ToString: {} }, []); var toS = { toString: function myToString() { return "string"; } }; cold_and_warm(toS.toString, { ToString: toS }, [ "myToString" ]); -cold_and_warm(undefined, { ToNumber: {} }, []); +cold_and_warm(undefined, { ToNumber: 5 }, []); var vOf = { valueOf: function myValueOf() { return 42; } }; cold_and_warm(vOf.valueOf, { ToNumber: vOf }, [ "myValueOf" ]); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 6b64bfb44..b2f9d3b23 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -3292,6 +3292,12 @@ BaselineCompiler::emit_JSOP_CALL() } bool +BaselineCompiler::emit_JSOP_CALL_IGNORES_RV() +{ + return emitCall(); +} + +bool BaselineCompiler::emit_JSOP_CALLITER() { return emitCall(); diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index 910a52980..95e0c77ad 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -159,6 +159,7 @@ namespace jit { _(JSOP_INITALIASEDLEXICAL) \ _(JSOP_UNINITIALIZED) \ _(JSOP_CALL) \ + _(JSOP_CALL_IGNORES_RV) \ _(JSOP_CALLITER) \ _(JSOP_FUNCALL) \ _(JSOP_FUNAPPLY) \ diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 2f20ffa4f..a001357f8 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -10,6 +10,8 @@ #include "mozilla/SizePrintfMacros.h" #include "mozilla/TemplateLib.h" +#include "jsfriendapi.h" +#include "jsfun.h" #include "jslibmath.h" #include "jstypes.h" @@ -321,7 +323,14 @@ DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, H MOZ_CRASH("Invalid stub"); } - return stub->addUpdateStubForValue(cx, script /* = outerScript */, obj, id, value); + if (!stub->addUpdateStubForValue(cx, script /* = outerScript */, obj, id, value)) { + // The calling JIT code assumes this function is infallible (for + // instance we may reallocate dynamic slots before calling this), + // so ignore OOMs if we failed to attach a stub. + cx->recoverFromOutOfMemory(); + } + + return true; } typedef bool (*DoTypeUpdateFallbackFn)(JSContext*, BaselineFrame*, ICUpdatedStub*, HandleValue, @@ -2253,14 +2262,20 @@ DenseOrUnboxedArraySetElemStubExists(JSContext* cx, ICStub::Kind kind, for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) { if (kind == ICStub::SetElem_DenseOrUnboxedArray && iter->isSetElem_DenseOrUnboxedArray()) { ICSetElem_DenseOrUnboxedArray* nstub = iter->toSetElem_DenseOrUnboxedArray(); - if (obj->maybeShape() == nstub->shape() && obj->getGroup(cx) == nstub->group()) + if (obj->maybeShape() == nstub->shape() && + JSObject::getGroup(cx, obj) == nstub->group()) + { return true; + } } if (kind == ICStub::SetElem_DenseOrUnboxedArrayAdd && iter->isSetElem_DenseOrUnboxedArrayAdd()) { ICSetElem_DenseOrUnboxedArrayAdd* nstub = iter->toSetElem_DenseOrUnboxedArrayAdd(); - if (obj->getGroup(cx) == nstub->group() && SetElemAddHasSameShapes(nstub, obj)) + if (JSObject::getGroup(cx, obj) == nstub->group() && + SetElemAddHasSameShapes(nstub, obj)) + { return true; + } } } return false; @@ -2446,7 +2461,7 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_ &addingCase, &protoDepth)) { RootedShape shape(cx, obj->maybeShape()); - RootedObjectGroup group(cx, obj->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj)); if (!group) return false; @@ -4277,7 +4292,7 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_ if (!obj) return false; RootedShape oldShape(cx, obj->maybeShape()); - RootedObjectGroup oldGroup(cx, obj->getGroup(cx)); + RootedObjectGroup oldGroup(cx, JSObject::getGroup(cx, obj)); if (!oldGroup) return false; RootedReceiverGuard oldGuard(cx, ReceiverGuard(obj)); @@ -5175,14 +5190,13 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& if (native == js::array_slice) { if (args.thisv().isObject()) { - JSObject* obj = &args.thisv().toObject(); + RootedObject obj(cx, &args.thisv().toObject()); if (!obj->isSingleton()) { if (obj->group()->maybePreliminaryObjects()) { *skipAttach = true; return true; } - res.set(NewFullyAllocatedArrayTryReuseGroup(cx, &args.thisv().toObject(), 0, - TenuredObject)); + res.set(NewFullyAllocatedArrayTryReuseGroup(cx, obj, 0, TenuredObject)); return !!res; } } @@ -5489,11 +5503,17 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb MOZ_ASSERT_IF(templateObject, !templateObject->group()->maybePreliminaryObjects()); } + bool ignoresReturnValue = false; + if (op == JSOP_CALL_IGNORES_RV && fun->isNative()) { + const JSJitInfo* jitInfo = fun->jitInfo(); + ignoresReturnValue = jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative; + } + JitSpew(JitSpew_BaselineIC, " Generating Call_Native stub (fun=%p, cons=%s, spread=%s)", fun.get(), constructing ? "yes" : "no", isSpread ? "yes" : "no"); ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(), - fun, templateObject, constructing, isSpread, - script->pcToOffset(pc)); + fun, templateObject, constructing, ignoresReturnValue, + isSpread, script->pcToOffset(pc)); ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; @@ -5596,12 +5616,14 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint MOZ_ASSERT(argc == GET_ARGC(pc)); bool constructing = (op == JSOP_NEW); + bool ignoresReturnValue = (op == JSOP_CALL_IGNORES_RV); // Ensure vp array is rooted - we may GC in here. size_t numValues = argc + 2 + constructing; AutoArrayRooter vpRoot(cx, numValues, vp); - CallArgs callArgs = CallArgsFromSp(argc + constructing, vp + numValues, constructing); + CallArgs callArgs = CallArgsFromSp(argc + constructing, vp + numValues, constructing, + ignoresReturnValue); RootedValue callee(cx, vp[0]); // Handle funapply with JSOP_ARGUMENTS @@ -5631,6 +5653,7 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint return false; } else { MOZ_ASSERT(op == JSOP_CALL || + op == JSOP_CALL_IGNORES_RV || op == JSOP_CALLITER || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY || @@ -6681,7 +6704,12 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm) // stub and use that instead of the original one. masm.callWithABI(Address(ICStubReg, ICCall_Native::offsetOfNative())); #else - masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript())); + if (ignoresReturnValue_) { + masm.loadPtr(Address(callee, JSFunction::offsetOfJitInfo()), callee); + masm.callWithABI(Address(callee, JSJitInfo::offsetOfIgnoresReturnValueNative())); + } else { + masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript())); + } #endif // Test for failure. @@ -7961,7 +7989,7 @@ ICUpdatedStub* ICSetElemDenseOrUnboxedArrayAddCompiler::getStubSpecific(ICStubSpace* space, Handle<ShapeVector> shapes) { - RootedObjectGroup group(cx, obj_->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj_)); if (!group) return nullptr; Rooted<JitCode*> stubCode(cx, getStubCode()); @@ -8098,7 +8126,7 @@ ICSetProp_Native::ICSetProp_Native(JitCode* stubCode, ObjectGroup* group, Shape* ICSetProp_Native* ICSetProp_Native::Compiler::getStub(ICStubSpace* space) { - RootedObjectGroup group(cx, obj_->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj_)); if (!group) return nullptr; diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 98f0e1c59..e1ad12559 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -1940,7 +1940,7 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler template <size_t ProtoChainDepth> ICUpdatedStub* getStubSpecific(ICStubSpace* space, Handle<ShapeVector> shapes) { - RootedObjectGroup newGroup(cx, obj_->getGroup(cx)); + RootedObjectGroup newGroup(cx, JSObject::getGroup(cx, obj_)); if (!newGroup) return nullptr; @@ -2277,6 +2277,7 @@ class ICSetProp_CallNative : public ICSetPropCallSetter // Call // JSOP_CALL +// JSOP_CALL_IGNORES_RV // JSOP_FUNAPPLY // JSOP_FUNCALL // JSOP_NEW @@ -2547,6 +2548,7 @@ class ICCall_Native : public ICMonitoredStub protected: ICStub* firstMonitorStub_; bool isConstructing_; + bool ignoresReturnValue_; bool isSpread_; RootedFunction callee_; RootedObject templateObject_; @@ -2556,17 +2558,19 @@ class ICCall_Native : public ICMonitoredStub virtual int32_t getKey() const { return static_cast<int32_t>(engine_) | (static_cast<int32_t>(kind) << 1) | - (static_cast<int32_t>(isConstructing_) << 17) | - (static_cast<int32_t>(isSpread_) << 18); + (static_cast<int32_t>(isSpread_) << 17) | + (static_cast<int32_t>(isConstructing_) << 18) | + (static_cast<int32_t>(ignoresReturnValue_) << 19); } public: Compiler(JSContext* cx, ICStub* firstMonitorStub, HandleFunction callee, HandleObject templateObject, - bool isConstructing, bool isSpread, uint32_t pcOffset) + bool isConstructing, bool ignoresReturnValue, bool isSpread, uint32_t pcOffset) : ICCallStubCompiler(cx, ICStub::Call_Native), firstMonitorStub_(firstMonitorStub), isConstructing_(isConstructing), + ignoresReturnValue_(ignoresReturnValue), isSpread_(isSpread), callee_(cx, callee), templateObject_(cx, templateObject), diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index d0e297c2d..5c21926b5 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -273,7 +273,7 @@ jit::BaselineCompile(JSContext* cx, JSScript* script, bool forceDebugInstrumenta MOZ_ASSERT(script->canBaselineCompile()); MOZ_ASSERT(IsBaselineEnabled(cx)); - script->ensureNonLazyCanonicalFunction(cx); + script->ensureNonLazyCanonicalFunction(); LifoAlloc alloc(TempAllocator::PreferredLifoChunkSize); TempAllocator* temp = alloc.new_<TempAllocator>(&alloc); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index fcb711237..205812942 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1053,7 +1053,7 @@ PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Re Address pairsVectorAddress(masm.getStackPointer(), pairsVectorStartOffset); - RegExpStatics* res = cx->global()->getRegExpStatics(cx); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, cx->global()); if (!res) return false; #ifdef JS_USE_LINK_REGISTER @@ -3688,7 +3688,13 @@ CodeGenerator::visitCallNative(LCallNative* call) masm.passABIArg(argContextReg); masm.passABIArg(argUintNReg); masm.passABIArg(argVpReg); - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->native())); + JSNative native = target->native(); + if (call->ignoresReturnValue()) { + const JSJitInfo* jitInfo = target->jitInfo(); + if (jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative) + native = jitInfo->ignoresReturnValueMethod; + } + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, native)); emitTracelogStopEvent(TraceLogger_Call); @@ -3845,13 +3851,15 @@ CodeGenerator::visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir) callVM(GetIntrinsicValueInfo, lir); } -typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, uint32_t, Value*, MutableHandleValue); +typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, bool, uint32_t, Value*, + MutableHandleValue); static const VMFunction InvokeFunctionInfo = FunctionInfo<InvokeFunctionFn>(InvokeFunction, "InvokeFunction"); void CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg, - bool constructing, uint32_t argc, uint32_t unusedStack) + bool constructing, bool ignoresReturnValue, + uint32_t argc, uint32_t unusedStack) { // Nestle %esp up to the argument vector. // Each path must account for framePushed_ separately, for callVM to be valid. @@ -3859,6 +3867,7 @@ CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg, pushArg(masm.getStackPointer()); // argv. pushArg(Imm32(argc)); // argc. + pushArg(Imm32(ignoresReturnValue)); pushArg(Imm32(constructing)); // constructing. pushArg(calleereg); // JSFunction*. @@ -3945,8 +3954,8 @@ CodeGenerator::visitCallGeneric(LCallGeneric* call) // Handle uncompiled or native functions. masm.bind(&invoke); - emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), - unusedStack); + emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(), + call->numActualArgs(), unusedStack); masm.bind(&end); @@ -4001,7 +4010,8 @@ CodeGenerator::visitCallKnown(LCallKnown* call) masm.checkStackAlignment(); if (target->isClassConstructor() && !call->isConstructing()) { - emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), unusedStack); + emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(), + call->numActualArgs(), unusedStack); return; } @@ -4045,7 +4055,8 @@ CodeGenerator::visitCallKnown(LCallKnown* call) if (call->isConstructing() && target->nargs() > call->numActualArgs()) emitCallInvokeFunctionShuffleNewTarget(call, calleereg, target->nargs(), unusedStack); else - emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), unusedStack); + emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(), + call->numActualArgs(), unusedStack); masm.bind(&end); @@ -4072,6 +4083,7 @@ CodeGenerator::emitCallInvokeFunction(T* apply, Register extraStackSize) pushArg(objreg); // argv. pushArg(ToRegister(apply->getArgc())); // argc. + pushArg(Imm32(false)); // ignoresReturnValue. pushArg(Imm32(false)); // isConstrucing. pushArg(ToRegister(apply->getFunction())); // JSFunction*. @@ -4428,19 +4440,6 @@ CodeGenerator::visitApplyArrayGeneric(LApplyArrayGeneric* apply) emitApplyGeneric(apply); } -typedef bool (*ArraySpliceDenseFn)(JSContext*, HandleObject, uint32_t, uint32_t); -static const VMFunction ArraySpliceDenseInfo = - FunctionInfo<ArraySpliceDenseFn>(ArraySpliceDense, "ArraySpliceDense"); - -void -CodeGenerator::visitArraySplice(LArraySplice* lir) -{ - pushArg(ToRegister(lir->getDeleteCount())); - pushArg(ToRegister(lir->getStart())); - pushArg(ToRegister(lir->getObject())); - callVM(ArraySpliceDenseInfo, lir); -} - void CodeGenerator::visitBail(LBail* lir) { diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index b5f170d84..12f1238ef 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -165,8 +165,8 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteElementBarrier* ool); void visitCallNative(LCallNative* call); void emitCallInvokeFunction(LInstruction* call, Register callereg, - bool isConstructing, uint32_t argc, - uint32_t unusedStack); + bool isConstructing, bool ignoresReturnValue, + uint32_t argc, uint32_t unusedStack); void visitCallGeneric(LCallGeneric* call); void emitCallInvokeFunctionShuffleNewTarget(LCallKnown *call, Register calleeReg, @@ -251,7 +251,6 @@ class CodeGenerator final : public CodeGeneratorSpecific void emitSetPropertyPolymorphic(LInstruction* lir, Register obj, Register scratch, const ConstantOrRegister& value); void visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV* ins); - void visitArraySplice(LArraySplice* splice); void visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins); void visitAbsI(LAbsI* lir); void visitAtan2D(LAtan2D* lir); diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index 18535389a..1d0506f74 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -15,7 +15,6 @@ _(ArrayShift) \ _(ArrayPush) \ _(ArraySlice) \ - _(ArraySplice) \ \ _(AtomicsCompareExchange) \ _(AtomicsExchange) \ diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index c61b414e0..b8a2d2fba 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -2153,7 +2153,7 @@ IonCompile(JSContext* cx, JSScript* script, // Make sure the script's canonical function isn't lazy. We can't de-lazify // it in a helper thread. - script->ensureNonLazyCanonicalFunction(cx); + script->ensureNonLazyCanonicalFunction(); TrackPropertiesForSingletonScopes(cx, script, baselineFrame); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 41c71c9c3..5fc624fb1 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -4055,7 +4055,7 @@ AnalyzePoppedThis(JSContext* cx, ObjectGroup* group, // Add the property to the object, being careful not to update type information. DebugOnly<unsigned> slotSpan = baseobj->slotSpan(); MOZ_ASSERT(!baseobj->containsPure(id)); - if (!baseobj->addDataProperty(cx, id, baseobj->slotSpan(), JSPROP_ENUMERATE)) + if (!NativeObject::addDataProperty(cx, baseobj, id, baseobj->slotSpan(), JSPROP_ENUMERATE)) return false; MOZ_ASSERT(baseobj->slotSpan() != slotSpan); MOZ_ASSERT(!baseobj->inDictionaryMode()); @@ -4132,7 +4132,7 @@ CmpInstructions(const void* a, const void* b) } bool -jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun, +jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun, ObjectGroup* group, HandlePlainObject baseobj, Vector<TypeNewScript::Initializer>* initializerList) { @@ -4142,7 +4142,7 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun, // which will definitely be added to the created object before it has a // chance to escape and be accessed elsewhere. - RootedScript script(cx, fun->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script) return false; diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h index 1ce8edc80..efd31415b 100644 --- a/js/src/jit/IonAnalysis.h +++ b/js/src/jit/IonAnalysis.h @@ -196,7 +196,7 @@ MCompare* ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const LinearSum& sum); MOZ_MUST_USE bool -AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun, +AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun, ObjectGroup* group, HandlePlainObject baseobj, Vector<TypeNewScript::Initializer>* initializerList); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index a54a58add..2d053de5a 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -466,7 +466,8 @@ IonBuilder::canInlineTarget(JSFunction* target, CallInfo& callInfo) // Allow constructing lazy scripts when performing the definite properties // analysis, as baseline has not been used to warm the caller up yet. if (target->isInterpreted() && info().analysisMode() == Analysis_DefiniteProperties) { - RootedScript script(analysisContext, target->getOrCreateScript(analysisContext)); + RootedFunction fun(analysisContext, target); + RootedScript script(analysisContext, JSFunction::getOrCreateScript(analysisContext, fun)); if (!script) return InliningDecision_Error; @@ -1938,6 +1939,7 @@ IonBuilder::inspectOpcode(JSOp op) return jsop_funapply(GET_ARGC(pc)); case JSOP_CALL: + case JSOP_CALL_IGNORES_RV: case JSOP_CALLITER: case JSOP_NEW: case JSOP_SUPERCALL: @@ -1945,7 +1947,8 @@ IonBuilder::inspectOpcode(JSOp op) if (!outermostBuilder()->iterators_.append(current->peek(-1))) return false; } - return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL); + return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL, + (JSOp)*pc == JSOP_CALL_IGNORES_RV); case JSOP_EVAL: case JSOP_STRICTEVAL: @@ -5873,7 +5876,7 @@ IonBuilder::inlineGenericFallback(JSFunction* target, CallInfo& callInfo, MBasic return false; // Create a new CallInfo to track modified state within this block. - CallInfo fallbackInfo(alloc(), callInfo.constructing()); + CallInfo fallbackInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue()); if (!fallbackInfo.init(callInfo)) return false; fallbackInfo.popFormals(fallbackBlock); @@ -5912,7 +5915,7 @@ IonBuilder::inlineObjectGroupFallback(CallInfo& callInfo, MBasicBlock* dispatchB MOZ_ASSERT(cache->idempotent()); // Create a new CallInfo to track modified state within the fallback path. - CallInfo fallbackInfo(alloc(), callInfo.constructing()); + CallInfo fallbackInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue()); if (!fallbackInfo.init(callInfo)) return false; @@ -6088,7 +6091,7 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const ObjectVector& targets, BoolVec inlineBlock->rewriteSlot(funIndex, funcDef); // Create a new CallInfo to track modified state within the inline block. - CallInfo inlineInfo(alloc(), callInfo.constructing()); + CallInfo inlineInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue()); if (!inlineInfo.init(callInfo)) return false; inlineInfo.popFormals(inlineBlock); @@ -6537,7 +6540,8 @@ IonBuilder::jsop_funcall(uint32_t argc) TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet(); JSFunction* native = getSingleCallTarget(calleeTypes); if (!native || !native->isNative() || native->native() != &fun_call) { - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, argc)) return false; return makeCall(native, callInfo); @@ -6562,7 +6566,8 @@ IonBuilder::jsop_funcall(uint32_t argc) argc -= 1; } - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, argc)) return false; @@ -6599,7 +6604,8 @@ IonBuilder::jsop_funapply(uint32_t argc) TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet(); JSFunction* native = getSingleCallTarget(calleeTypes); if (argc != 2 || info().analysisMode() == Analysis_ArgumentsUsage) { - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, argc)) return false; return makeCall(native, callInfo); @@ -6628,7 +6634,8 @@ IonBuilder::jsop_funapply(uint32_t argc) return jsop_funapplyarray(argc); } - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, argc)) return false; return makeCall(native, callInfo); @@ -6737,7 +6744,8 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc) // can inline the apply() target and don't care about the actual arguments // that were passed in. - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); // Vp MDefinition* vp = current->pop(); @@ -6783,7 +6791,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc) } bool -IonBuilder::jsop_call(uint32_t argc, bool constructing) +IonBuilder::jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue) { startTrackingOptimizations(); @@ -6809,7 +6817,7 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing) if (calleeTypes && !getPolyCallTargets(calleeTypes, constructing, targets, 4)) return false; - CallInfo callInfo(alloc(), constructing); + CallInfo callInfo(alloc(), constructing, ignoresReturnValue); if (!callInfo.init(current, argc)) return false; @@ -6945,7 +6953,8 @@ IonBuilder::makeCallHelper(JSFunction* target, CallInfo& callInfo) } MCall* call = MCall::New(alloc(), target, targetArgs + 1 + callInfo.constructing(), - callInfo.argc(), callInfo.constructing(), isDOMCall); + callInfo.argc(), callInfo.constructing(), + callInfo.ignoresReturnValue(), isDOMCall); if (!call) return nullptr; @@ -7046,7 +7055,7 @@ IonBuilder::jsop_eval(uint32_t argc) // Emit a normal call if the eval has never executed. This keeps us from // disabling compilation for the script when testing with --ion-eager. if (calleeTypes && calleeTypes->empty()) - return jsop_call(argc, /* constructing = */ false); + return jsop_call(argc, /* constructing = */ false, false); JSFunction* singleton = getSingleCallTarget(calleeTypes); if (!singleton) @@ -7062,7 +7071,8 @@ IonBuilder::jsop_eval(uint32_t argc) if (info().funMaybeLazy()->isArrow()) return abort("Direct eval from arrow function"); - CallInfo callInfo(alloc(), /* constructing = */ false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, argc)) return false; callInfo.setImplicitlyUsedUnchecked(); @@ -7101,7 +7111,8 @@ IonBuilder::jsop_eval(uint32_t argc) current->push(dynamicName); current->push(constant(UndefinedValue())); // thisv - CallInfo evalCallInfo(alloc(), /* constructing = */ false); + CallInfo evalCallInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!evalCallInfo.init(current, /* argc = */ 0)) return false; @@ -7118,7 +7129,7 @@ IonBuilder::jsop_eval(uint32_t argc) return resumeAfter(ins) && pushTypeBarrier(ins, types, BarrierKind::TypeSet); } - return jsop_call(argc, /* constructing = */ false); + return jsop_call(argc, /* constructing = */ false, false); } bool @@ -12000,7 +12011,8 @@ IonBuilder::getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName current->push(obj); - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, 0)) return false; @@ -12495,7 +12507,8 @@ IonBuilder::setPropTryCommonSetter(bool* emitted, MDefinition* obj, // Call the setter. Note that we have to push the original value, not // the setter's return value. - CallInfo callInfo(alloc(), false); + CallInfo callInfo(alloc(), /* constructing = */ false, + /* ignoresReturnValue = */ BytecodeIsPopped(pc)); if (!callInfo.init(current, 1)) return false; diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index dd40b4bd6..1f763a4f2 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -699,6 +699,7 @@ class IonBuilder MOZ_MUST_USE bool jsop_funapplyarguments(uint32_t argc); MOZ_MUST_USE bool jsop_funapplyarray(uint32_t argc); MOZ_MUST_USE bool jsop_call(uint32_t argc, bool constructing); + MOZ_MUST_USE bool jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue); MOZ_MUST_USE bool jsop_eval(uint32_t argc); MOZ_MUST_USE bool jsop_ifeq(JSOp op); MOZ_MUST_USE bool jsop_try(); @@ -820,7 +821,6 @@ class IonBuilder InliningStatus inlineArrayPush(CallInfo& callInfo); InliningStatus inlineArraySlice(CallInfo& callInfo); InliningStatus inlineArrayJoin(CallInfo& callInfo); - InliningStatus inlineArraySplice(CallInfo& callInfo); // Math natives. InliningStatus inlineMathAbs(CallInfo& callInfo); @@ -1352,16 +1352,21 @@ class CallInfo MDefinition* newTargetArg_; MDefinitionVector args_; - bool constructing_; - bool setter_; + bool constructing_:1; + + // True if the caller does not use the return value. + bool ignoresReturnValue_:1; + + bool setter_:1; public: - CallInfo(TempAllocator& alloc, bool constructing) + CallInfo(TempAllocator& alloc, bool constructing, bool ignoresReturnValue) : fun_(nullptr), thisArg_(nullptr), newTargetArg_(nullptr), args_(alloc), constructing_(constructing), + ignoresReturnValue_(ignoresReturnValue), setter_(false) { } @@ -1370,6 +1375,7 @@ class CallInfo fun_ = callInfo.fun(); thisArg_ = callInfo.thisArg(); + ignoresReturnValue_ = callInfo.ignoresReturnValue(); if (constructing()) newTargetArg_ = callInfo.getNewTarget(); @@ -1466,6 +1472,10 @@ class CallInfo return constructing_; } + bool ignoresReturnValue() const { + return ignoresReturnValue_; + } + void setNewTarget(MDefinition* newTarget) { MOZ_ASSERT(constructing()); newTargetArg_ = newTarget; diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 9901bdd07..48e0792bb 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -3316,7 +3316,7 @@ SetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex RootedObjectGroup oldGroup(cx); RootedShape oldShape(cx); if (cache.canAttachStub()) { - oldGroup = obj->getGroup(cx); + oldGroup = JSObject::getGroup(cx, obj); if (!oldGroup) return false; diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 68417138b..22f1d5f70 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -657,16 +657,6 @@ LIRGenerator::visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* assertion } void -LIRGenerator::visitArraySplice(MArraySplice* ins) -{ - LArraySplice* lir = new(alloc()) LArraySplice(useRegisterAtStart(ins->object()), - useRegisterAtStart(ins->start()), - useRegisterAtStart(ins->deleteCount())); - add(lir, ins); - assignSafepoint(lir, ins); -} - -void LIRGenerator::visitGetDynamicName(MGetDynamicName* ins) { MDefinition* envChain = ins->getEnvironmentChain(); diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index b096bb143..9342ef471 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -107,7 +107,6 @@ class LIRGenerator : public LIRGeneratorSpecific void visitCall(MCall* call); void visitApplyArgs(MApplyArgs* apply); void visitApplyArray(MApplyArray* apply); - void visitArraySplice(MArraySplice* splice); void visitBail(MBail* bail); void visitUnreachable(MUnreachable* unreachable); void visitEncodeSnapshot(MEncodeSnapshot* ins); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 359f04639..5eee30e49 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -85,8 +85,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return inlineArrayPush(callInfo); case InlinableNative::ArraySlice: return inlineArraySlice(callInfo); - case InlinableNative::ArraySplice: - return inlineArraySplice(callInfo); // Atomic natives. case InlinableNative::AtomicsCompareExchange: @@ -654,46 +652,6 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode) } IonBuilder::InliningStatus -IonBuilder::inlineArraySplice(CallInfo& callInfo) -{ - if (callInfo.argc() != 2 || callInfo.constructing()) { - trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); - return InliningStatus_NotInlined; - } - - // Ensure |this|, argument and result are objects. - if (getInlineReturnType() != MIRType::Object) - return InliningStatus_NotInlined; - if (callInfo.thisArg()->type() != MIRType::Object) - return InliningStatus_NotInlined; - if (callInfo.getArg(0)->type() != MIRType::Int32) - return InliningStatus_NotInlined; - if (callInfo.getArg(1)->type() != MIRType::Int32) - return InliningStatus_NotInlined; - - callInfo.setImplicitlyUsedUnchecked(); - - // Specialize arr.splice(start, deleteCount) with unused return value and - // avoid creating the result array in this case. - if (!BytecodeIsPopped(pc)) { - trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric); - return InliningStatus_NotInlined; - } - - MArraySplice* ins = MArraySplice::New(alloc(), - callInfo.thisArg(), - callInfo.getArg(0), - callInfo.getArg(1)); - - current->add(ins); - pushConstant(UndefinedValue()); - - if (!resumeAfter(ins)) - return InliningStatus_Error; - return InliningStatus_Inlined; -} - -IonBuilder::InliningStatus IonBuilder::inlineArrayJoin(CallInfo& callInfo) { if (callInfo.argc() != 1 || callInfo.constructing()) { diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index fa9cc3019..0cf31adb3 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1970,7 +1970,7 @@ WrappedFunction::WrappedFunction(JSFunction* fun) MCall* MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs, - bool construct, bool isDOMCall) + bool construct, bool ignoresReturnValue, bool isDOMCall) { WrappedFunction* wrappedTarget = target ? new(alloc) WrappedFunction(target) : nullptr; MOZ_ASSERT(maxArgc >= numActualArgs); @@ -1979,7 +1979,7 @@ MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numA MOZ_ASSERT(!construct); ins = new(alloc) MCallDOMNative(wrappedTarget, numActualArgs); } else { - ins = new(alloc) MCall(wrappedTarget, numActualArgs, construct); + ins = new(alloc) MCall(wrappedTarget, numActualArgs, construct, ignoresReturnValue); } if (!ins->init(alloc, maxArgc + NumNonArgumentOperands)) return nullptr; @@ -2630,40 +2630,6 @@ jit::EqualTypes(MIRType type1, TemporaryTypeSet* typeset1, return typeset1->equals(typeset2); } -// Tests whether input/inputTypes can always be stored to an unboxed -// object/array property with the given unboxed type. -bool -jit::CanStoreUnboxedType(TempAllocator& alloc, - JSValueType unboxedType, MIRType input, TypeSet* inputTypes) -{ - TemporaryTypeSet types; - - switch (unboxedType) { - case JSVAL_TYPE_BOOLEAN: - case JSVAL_TYPE_INT32: - case JSVAL_TYPE_DOUBLE: - case JSVAL_TYPE_STRING: - types.addType(TypeSet::PrimitiveType(unboxedType), alloc.lifoAlloc()); - break; - - case JSVAL_TYPE_OBJECT: - types.addType(TypeSet::AnyObjectType(), alloc.lifoAlloc()); - types.addType(TypeSet::NullType(), alloc.lifoAlloc()); - break; - - default: - MOZ_CRASH("Bad unboxed type"); - } - - return TypeSetIncludes(&types, input, inputTypes); -} - -static bool -CanStoreUnboxedType(TempAllocator& alloc, JSValueType unboxedType, MDefinition* value) -{ - return CanStoreUnboxedType(alloc, unboxedType, value->type(), value->resultTypeSet()); -} - bool MPhi::specializeType(TempAllocator& alloc) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 9076339f1..6c376d528 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -4043,14 +4043,18 @@ class MCall uint32_t numActualArgs_; // True if the call is for JSOP_NEW. - bool construct_; + bool construct_:1; - bool needsArgCheck_; + // True if the caller does not use the return value. + bool ignoresReturnValue_:1; - MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct) + bool needsArgCheck_:1; + + MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct, bool ignoresReturnValue) : target_(target), numActualArgs_(numActualArgs), construct_(construct), + ignoresReturnValue_(ignoresReturnValue), needsArgCheck_(true) { setResultType(MIRType::Value); @@ -4059,7 +4063,7 @@ class MCall public: INSTRUCTION_HEADER(Call) static MCall* New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs, - bool construct, bool isDOMCall); + bool construct, bool ignoresReturnValue, bool isDOMCall); void initFunction(MDefinition* func) { initOperand(FunctionOperandIndex, func); @@ -4104,6 +4108,10 @@ class MCall return construct_; } + bool ignoresReturnValue() const { + return ignoresReturnValue_; + } + // The number of stack arguments is the max between the number of formal // arguments and the number of actual arguments. The number of stack // argument includes the |undefined| padding added in case of underflow. @@ -4147,7 +4155,7 @@ class MCallDOMNative : public MCall // virtual things from MCall. protected: MCallDOMNative(WrappedFunction* target, uint32_t numActualArgs) - : MCall(target, numActualArgs, false) + : MCall(target, numActualArgs, false, false) { MOZ_ASSERT(getJitInfo()->type() != JSJitInfo::InlinableNative); @@ -4162,7 +4170,8 @@ class MCallDOMNative : public MCall } friend MCall* MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, - size_t numActualArgs, bool construct, bool isDOMCall); + size_t numActualArgs, bool construct, bool ignoresReturnValue, + bool isDOMCall); const JSJitInfo* getJitInfo() const; public: @@ -4177,27 +4186,6 @@ class MCallDOMNative : public MCall virtual void computeMovable() override; }; -// arr.splice(start, deleteCount) with unused return value. -class MArraySplice - : public MTernaryInstruction, - public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >::Data -{ - private: - - MArraySplice(MDefinition* object, MDefinition* start, MDefinition* deleteCount) - : MTernaryInstruction(object, start, deleteCount) - { } - - public: - INSTRUCTION_HEADER(ArraySplice) - TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object), (1, start), (2, deleteCount)) - - bool possiblyCalls() const override { - return true; - } -}; - // fun.apply(self, arguments) class MApplyArgs : public MAryInstruction<3>, diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index ab37604b4..9e460a2ba 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -69,7 +69,6 @@ namespace jit { _(Call) \ _(ApplyArgs) \ _(ApplyArray) \ - _(ArraySplice) \ _(Bail) \ _(Unreachable) \ _(EncodeSnapshot) \ diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 402d910b9..1ff7adfd1 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -54,8 +54,8 @@ VMFunction::addToFunctions() } bool -InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, uint32_t argc, Value* argv, - MutableHandleValue rval) +InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, bool ignoresReturnValue, + uint32_t argc, Value* argv, MutableHandleValue rval) { TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); TraceLogStartEvent(logger, TraceLogger_Call); @@ -104,7 +104,7 @@ InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, uint32_t argc return InternalConstructWithProvidedThis(cx, fval, thisv, cargs, newTarget, rval); } - InvokeArgs args(cx); + InvokeArgsMaybeIgnoresReturnValue args(cx, ignoresReturnValue); if (!args.init(cx, argc)) return false; @@ -120,7 +120,7 @@ InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActu { MOZ_ASSERT(numFormalArgs > numActualArgs); argv[1 + numActualArgs] = argv[1 + numFormalArgs]; - return InvokeFunction(cx, obj, true, numActualArgs, argv, rval); + return InvokeFunction(cx, obj, true, false, numActualArgs, argv, rval); } bool @@ -304,18 +304,6 @@ template bool StringsEqual<true>(JSContext* cx, HandleString lhs, HandleString r template bool StringsEqual<false>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res); bool -ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t deleteCount) -{ - JS::AutoValueArray<4> argv(cx); - argv[0].setUndefined(); - argv[1].setObject(*obj); - argv[2].set(Int32Value(start)); - argv[3].set(Int32Value(deleteCount)); - - return js::array_splice_impl(cx, 2, argv.begin(), false); -} - -bool ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) { MOZ_ASSERT(obj->is<ArrayObject>()); @@ -555,7 +543,7 @@ CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHa if (callee->is<JSFunction>()) { RootedFunction fun(cx, &callee->as<JSFunction>()); if (fun->isInterpreted() && fun->isConstructor()) { - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script || !script->ensureHasTypes(cx)) return false; if (fun->isBoundFunction() || script->isDerivedClassConstructor()) { diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 9a2edd0f3..94f741397 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -584,8 +584,8 @@ class AutoDetectInvalidation }; MOZ_MUST_USE bool -InvokeFunction(JSContext* cx, HandleObject obj0, bool constructing, uint32_t argc, Value* argv, - MutableHandleValue rval); +InvokeFunction(JSContext* cx, HandleObject obj0, bool constructing, bool ignoresReturnValue, + uint32_t argc, Value* argv, MutableHandleValue rval); MOZ_MUST_USE bool InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs, uint32_t numFormalArgs, Value* argv, MutableHandleValue rval); @@ -739,9 +739,6 @@ JSObject* CreateDerivedTypedObj(JSContext* cx, HandleObject descr, HandleObject owner, int32_t offset); MOZ_MUST_USE bool -ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t deleteCount); - -MOZ_MUST_USE bool Recompile(JSContext* cx); MOZ_MUST_USE bool ForcedRecompile(JSContext* cx); diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index ffa4d8367..ecf02816e 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -1898,6 +1898,9 @@ class LJSCallInstructionHelper : public LCallInstructionHelper<Defs, Operands, T bool isConstructing() const { return mir()->isConstructing(); } + bool ignoresReturnValue() const { + return mir()->ignoresReturnValue(); + } }; // Generates a polymorphic callsite, wherein the function being called is @@ -2218,34 +2221,6 @@ class LApplyArrayGeneric : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES } }; -class LArraySplice : public LCallInstructionHelper<0, 3, 0> -{ - public: - LIR_HEADER(ArraySplice) - - LArraySplice(const LAllocation& object, const LAllocation& start, - const LAllocation& deleteCount) - { - setOperand(0, object); - setOperand(1, start); - setOperand(2, deleteCount); - } - - MArraySplice* mir() const { - return mir_->toArraySplice(); - } - - const LAllocation* getObject() { - return getOperand(0); - } - const LAllocation* getStart() { - return getOperand(1); - } - const LAllocation* getDeleteCount() { - return getOperand(2); - } -}; - class LGetDynamicName : public LCallInstructionHelper<BOX_PIECES, 2, 3> { public: diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index deae92839..e260d7e94 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -69,7 +69,6 @@ _(NewArrayDynamicLength) \ _(NewTypedArray) \ _(NewTypedArrayDynamicLength) \ - _(ArraySplice) \ _(NewObject) \ _(NewTypedObject) \ _(NewNamedLambdaObject) \ diff --git a/js/src/js.msg b/js/src/js.msg index 4ded69a25..f57b36a90 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -63,6 +63,7 @@ MSG_DEF(JSMSG_SPREAD_TOO_LARGE, 0, JSEXN_RANGEERR, "array too large due t MSG_DEF(JSMSG_BAD_WEAKMAP_KEY, 0, JSEXN_TYPEERR, "cannot use the given object as a weak map key") MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 1, JSEXN_TYPEERR, "invalid {0} usage") MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 0, JSEXN_RANGEERR, "invalid array length") +MSG_DEF(JSMSG_REDECLARED_PREV, 2, JSEXN_NOTE, "Previously declared at line {0}, column {1}") MSG_DEF(JSMSG_REDECLARED_VAR, 2, JSEXN_SYNTAXERR, "redeclaration of {0} {1}") MSG_DEF(JSMSG_UNDECLARED_VAR, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}") MSG_DEF(JSMSG_GETTER_ONLY, 1, JSEXN_TYPEERR, "setting getter-only property {0}") @@ -186,6 +187,7 @@ MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'") MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async") MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression") +MSG_DEF(JSMSG_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid in async functions") MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)") MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated") MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration") @@ -209,6 +211,8 @@ MSG_DEF(JSMSG_BAD_POW_LEFTSIDE, 0, JSEXN_SYNTAXERR, "unparenthesized unar MSG_DEF(JSMSG_BAD_PROP_ID, 0, JSEXN_SYNTAXERR, "invalid property id") MSG_DEF(JSMSG_BAD_RETURN_OR_YIELD, 1, JSEXN_SYNTAXERR, "{0} not in function") MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "'{0}' can't be defined or assigned to in strict mode code") +MSG_DEF(JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS, 0, JSEXN_SYNTAXERR, "'arguments' can't be defined or assigned to in strict mode code") +MSG_DEF(JSMSG_BAD_STRICT_ASSIGN_EVAL, 0, JSEXN_SYNTAXERR, "'eval' can't be defined or assigned to in strict mode code") MSG_DEF(JSMSG_BAD_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement") MSG_DEF(JSMSG_BAD_SUPER, 0, JSEXN_SYNTAXERR, "invalid use of keyword 'super'") MSG_DEF(JSMSG_BAD_SUPERPROP, 1, JSEXN_SYNTAXERR, "use of super {0} accesses only valid within methods or eval code within methods") @@ -216,6 +220,7 @@ MSG_DEF(JSMSG_BAD_SUPERCALL, 0, JSEXN_SYNTAXERR, "super() is only vali MSG_DEF(JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION, 0, JSEXN_SYNTAXERR, "missing ] after array comprehension") MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing ] after element list") MSG_DEF(JSMSG_BRACKET_IN_INDEX, 0, JSEXN_SYNTAXERR, "missing ] in index expression") +MSG_DEF(JSMSG_BRACKET_OPENED, 2, JSEXN_NOTE, "[ opened at line {0}, column {1}") MSG_DEF(JSMSG_CATCH_AFTER_GENERAL, 0, JSEXN_SYNTAXERR, "catch after unconditional catch") MSG_DEF(JSMSG_CATCH_IDENTIFIER, 0, JSEXN_SYNTAXERR, "missing identifier in catch") MSG_DEF(JSMSG_CATCH_OR_FINALLY, 0, JSEXN_SYNTAXERR, "missing catch or finally after try") @@ -226,6 +231,7 @@ MSG_DEF(JSMSG_COLON_IN_COND, 0, JSEXN_SYNTAXERR, "missing : in conditi MSG_DEF(JSMSG_COMP_PROP_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing ] in computed property name") MSG_DEF(JSMSG_CONTRARY_NONDIRECTIVE, 1, JSEXN_SYNTAXERR, "'{0}' statement won't be enforced as a directive because it isn't in directive prologue position") MSG_DEF(JSMSG_CURLY_AFTER_BODY, 0, JSEXN_SYNTAXERR, "missing } after function body") +MSG_DEF(JSMSG_CURLY_OPENED, 2, JSEXN_NOTE, "{ opened at line {0}, column {1}") MSG_DEF(JSMSG_CURLY_AFTER_CATCH, 0, JSEXN_SYNTAXERR, "missing } after catch block") MSG_DEF(JSMSG_CURLY_AFTER_FINALLY, 0, JSEXN_SYNTAXERR, "missing } after finally block") MSG_DEF(JSMSG_CURLY_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing } after property list") @@ -264,6 +270,7 @@ MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations MSG_DEF(JSMSG_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer") MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer") MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers") +MSG_DEF(JSMSG_INVALID_ID, 1, JSEXN_SYNTAXERR, "{0} is an invalid identifier") MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable") MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block") @@ -501,7 +508,7 @@ MSG_DEF(JSMSG_RANGE_WITH_CLASS_ESCAPE, 0, JSEXN_SYNTAXERR, "character class esca MSG_DEF(JSMSG_RAW_BRACE_IN_REGEP, 0, JSEXN_SYNTAXERR, "raw brace is not allowed in regular expression with unicode flag") MSG_DEF(JSMSG_RAW_BRACKET_IN_REGEP, 0, JSEXN_SYNTAXERR, "raw bracket is not allowed in regular expression with unicode flag") MSG_DEF(JSMSG_TOO_MANY_PARENS, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression") -MSG_DEF(JSMSG_UNICODE_OVERFLOW, 0, JSEXN_SYNTAXERR, "unicode codepoint should not be greater than 0x10FFFF in regular expression") +MSG_DEF(JSMSG_UNICODE_OVERFLOW, 1, JSEXN_SYNTAXERR, "Unicode codepoint must not be greater than 0x10FFFF in {0}") MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") MSG_DEF(JSMSG_UNTERM_CLASS, 0, JSEXN_SYNTAXERR, "unterminated character class") diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index 277a145b0..c176fbf0a 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -37,6 +37,7 @@ UNIFIED_SOURCES += [ 'testForOfIterator.cpp', 'testForwardSetProperty.cpp', 'testFreshGlobalEvalRedefinition.cpp', + 'testFunctionBinding.cpp', 'testFunctionProperties.cpp', 'testGCAllocator.cpp', 'testGCCellPtr.cpp', diff --git a/js/src/jsapi-tests/testFunctionBinding.cpp b/js/src/jsapi-tests/testFunctionBinding.cpp new file mode 100644 index 000000000..33632db14 --- /dev/null +++ b/js/src/jsapi-tests/testFunctionBinding.cpp @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * + * Test function name binding. + */ +/* 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 "jsfriendapi.h" + +#include "jsapi-tests/tests.h" + +using namespace js; + +BEGIN_TEST(test_functionBinding) +{ + RootedFunction fun(cx); + + JS::CompileOptions options(cx); + options.setFileAndLine(__FILE__, __LINE__); + + // Named function shouldn't have it's binding. + const char s1chars[] = "return (typeof s1) == 'undefined';"; + JS::AutoObjectVector emptyScopeChain(cx); + CHECK(JS::CompileFunction(cx, emptyScopeChain, options, "s1", 0, nullptr, s1chars, + strlen(s1chars), &fun)); + CHECK(fun); + + JS::AutoValueVector args(cx); + RootedValue rval(cx); + CHECK(JS::Call(cx, UndefinedHandleValue, fun, args, &rval)); + CHECK(rval.isBoolean()); + CHECK(rval.toBoolean()); + + // Named function shouldn't have `anonymous` binding. + const char s2chars[] = "return (typeof anonymous) == 'undefined';"; + CHECK(JS::CompileFunction(cx, emptyScopeChain, options, "s2", 0, nullptr, s2chars, + strlen(s2chars), &fun)); + CHECK(fun); + + CHECK(JS::Call(cx, UndefinedHandleValue, fun, args, &rval)); + CHECK(rval.isBoolean()); + CHECK(rval.toBoolean()); + + // Anonymous function shouldn't have `anonymous` binding. + const char s3chars[] = "return (typeof anonymous) == 'undefined';"; + CHECK(JS::CompileFunction(cx, emptyScopeChain, options, nullptr, 0, nullptr, s3chars, + strlen(s3chars), &fun)); + CHECK(fun); + + CHECK(JS::Call(cx, UndefinedHandleValue, fun, args, &rval)); + CHECK(rval.isBoolean()); + CHECK(rval.toBoolean()); + + return true; +} +END_TEST(test_functionBinding) diff --git a/js/src/jsapi-tests/testUbiNode.cpp b/js/src/jsapi-tests/testUbiNode.cpp index 075e777d6..00b1253e7 100644 --- a/js/src/jsapi-tests/testUbiNode.cpp +++ b/js/src/jsapi-tests/testUbiNode.cpp @@ -646,7 +646,7 @@ BEGIN_TEST(test_JS_ubi_Node_scriptFilename) CHECK(obj->is<JSFunction>()); JS::RootedFunction func(cx, &obj->as<JSFunction>()); - JS::RootedScript script(cx, func->getOrCreateScript(cx)); + JS::RootedScript script(cx, JSFunction::getOrCreateScript(cx, func)); CHECK(script); CHECK(script->filename()); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 9ee29ffe4..84a315587 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -69,7 +69,6 @@ #include "js/Proxy.h" #include "js/SliceBudget.h" #include "js/StructuredClone.h" -#include "js/UniquePtr.h" #include "js/Utility.h" #include "vm/AsyncFunction.h" #include "vm/DateObject.h" @@ -1022,7 +1021,7 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); *resolved = false; if (!JSID_IS_ATOM(id)) @@ -1066,10 +1065,7 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso // more way: its prototype chain is lazily initialized. That is, // global->getProto() might be null right now because we haven't created // Object.prototype yet. Force it now. - if (!global->getOrCreateObjectPrototype(cx)) - return false; - - return true; + return GlobalObject::getOrCreateObjectPrototype(cx, global); } JS_PUBLIC_API(bool) @@ -1102,8 +1098,7 @@ JS_EnumerateStandardClasses(JSContext* cx, HandleObject obj) AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - MOZ_ASSERT(obj->is<GlobalObject>()); - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); return GlobalObject::initStandardClasses(cx, global); } @@ -1159,7 +1154,8 @@ JS_GetObjectPrototype(JSContext* cx, HandleObject forObj) { CHECK_REQUEST(cx); assertSameCompartment(cx, forObj); - return forObj->global().getOrCreateObjectPrototype(cx); + Rooted<GlobalObject*> global(cx, &forObj->global()); + return GlobalObject::getOrCreateObjectPrototype(cx, global); } JS_PUBLIC_API(JSObject*) @@ -1167,7 +1163,8 @@ JS_GetFunctionPrototype(JSContext* cx, HandleObject forObj) { CHECK_REQUEST(cx); assertSameCompartment(cx, forObj); - return forObj->global().getOrCreateFunctionPrototype(cx); + Rooted<GlobalObject*> global(cx, &forObj->global()); + return GlobalObject::getOrCreateFunctionPrototype(cx, global); } JS_PUBLIC_API(JSObject*) @@ -3489,7 +3486,7 @@ CreateNonSyntacticEnvironmentChain(JSContext* cx, AutoObjectVector& envChain, // declaration was qualified by "var". There is only sadness. // // See JSObject::isQualifiedVarObj. - if (!env->setQualifiedVarObj(cx)) + if (!JSObject::setQualifiedVarObj(cx, env)) return false; // Also get a non-syntactic lexical environment to capture 'let' and @@ -3549,7 +3546,7 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject env, Handle RootedFunction fun(cx, &funobj->as<JSFunction>()); if (fun->isInterpretedLazy()) { AutoCompartment ac(cx, funobj); - if (!fun->getOrCreateScript(cx)) + if (!JSFunction::getOrCreateScript(cx, fun)) return nullptr; } @@ -3581,7 +3578,7 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject env, Handle // Fail here if we OOM during debug asserting. // CloneFunctionReuseScript will delazify the script anyways, so we // are not creating an extra failure condition for DEBUG builds. - if (!fun->getOrCreateScript(cx)) + if (!JSFunction::getOrCreateScript(cx, fun)) return nullptr; MOZ_ASSERT(scope->as<GlobalScope>().isSyntactic() || fun->nonLazyScript()->hasNonSyntacticScope()); @@ -4234,7 +4231,7 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun) return nullptr; if (fun->isInterpretedLazy()) { AutoCompartment funCompartment(cx, fun); - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) MOZ_CRASH(); return script; @@ -4405,14 +4402,15 @@ JS_DecompileScript(JSContext* cx, HandleScript script, const char* name, unsigne AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - script->ensureNonLazyCanonicalFunction(cx); + script->ensureNonLazyCanonicalFunction(); RootedFunction fun(cx, script->functionNonDelazifying()); if (fun) return JS_DecompileFunction(cx, fun, indent); bool haveSource = script->scriptSource()->hasSourceData(); if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) return nullptr; - return haveSource ? script->sourceData(cx) : NewStringCopyZ<CanGC>(cx, "[no source]"); + return haveSource ? JSScript::sourceData(cx, script) + : NewStringCopyZ<CanGC>(cx, "[no source]"); } JS_PUBLIC_API(JSString*) @@ -4884,7 +4882,7 @@ JS::CallOriginalPromiseResolve(JSContext* cx, JS::HandleValue resolutionValue) assertSameCompartment(cx, resolutionValue); RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, resolutionValue)); - MOZ_ASSERT_IF(promise, promise->is<PromiseObject>()); + MOZ_ASSERT_IF(promise, CheckedUnwrap(promise)->is<PromiseObject>()); return promise; } @@ -4896,7 +4894,7 @@ JS::CallOriginalPromiseReject(JSContext* cx, JS::HandleValue rejectionValue) assertSameCompartment(cx, rejectionValue); RootedObject promise(cx, PromiseObject::unforgeableReject(cx, rejectionValue)); - MOZ_ASSERT_IF(promise, promise->is<PromiseObject>()); + MOZ_ASSERT_IF(promise, CheckedUnwrap(promise)->is<PromiseObject>()); return promise; } @@ -4926,8 +4924,8 @@ ResolveOrRejectPromise(JSContext* cx, JS::HandleObject promiseObj, JS::HandleVal } return reject - ? promise->reject(cx, resultOrReason) - : promise->resolve(cx, resultOrReason); + ? PromiseObject::reject(cx, promise, resultOrReason) + : PromiseObject::resolve(cx, promise, resultOrReason); } JS_PUBLIC_API(bool) @@ -6014,7 +6012,8 @@ JS_SetRegExpInput(JSContext* cx, HandleObject obj, HandleString input) CHECK_REQUEST(cx); assertSameCompartment(cx, input); - RegExpStatics* res = obj->as<GlobalObject>().getRegExpStatics(cx); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, global); if (!res) return false; @@ -6029,7 +6028,8 @@ JS_ClearRegExpStatics(JSContext* cx, HandleObject obj) CHECK_REQUEST(cx); MOZ_ASSERT(obj); - RegExpStatics* res = obj->as<GlobalObject>().getRegExpStatics(cx); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, global); if (!res) return false; @@ -6044,7 +6044,8 @@ JS_ExecuteRegExp(JSContext* cx, HandleObject obj, HandleObject reobj, char16_t* AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - RegExpStatics* res = obj->as<GlobalObject>().getRegExpStatics(cx); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + RegExpStatics* res = GlobalObject::getRegExpStatics(cx, global); if (!res) return false; @@ -6052,7 +6053,7 @@ JS_ExecuteRegExp(JSContext* cx, HandleObject obj, HandleObject reobj, char16_t* if (!input) return false; - return ExecuteRegExpLegacy(cx, res, reobj->as<RegExpObject>(), input, indexp, test, rval); + return ExecuteRegExpLegacy(cx, res, reobj.as<RegExpObject>(), input, indexp, test, rval); } JS_PUBLIC_API(bool) @@ -6066,7 +6067,7 @@ JS_ExecuteRegExpNoStatics(JSContext* cx, HandleObject obj, char16_t* chars, size if (!input) return false; - return ExecuteRegExpLegacy(cx, nullptr, obj->as<RegExpObject>(), input, indexp, test, + return ExecuteRegExpLegacy(cx, nullptr, obj.as<RegExpObject>(), input, indexp, test, rval); } @@ -6298,7 +6299,7 @@ JSErrorReport::freeLinebuf() } JSString* -JSErrorReport::newMessageString(JSContext* cx) +JSErrorBase::newMessageString(JSContext* cx) { if (!message_) return cx->runtime()->emptyString; @@ -6307,7 +6308,7 @@ JSErrorReport::newMessageString(JSContext* cx) } void -JSErrorReport::freeMessage() +JSErrorBase::freeMessage() { if (ownsMessage_) { js_free((void*)message_.get()); @@ -6316,6 +6317,132 @@ JSErrorReport::freeMessage() message_ = JS::ConstUTF8CharsZ(); } +JSErrorNotes::JSErrorNotes() + : notes_() +{} + +JSErrorNotes::~JSErrorNotes() +{ +} + +static UniquePtr<JSErrorNotes::Note> +CreateErrorNoteVA(ExclusiveContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, + ErrorArgumentsType argumentsType, va_list ap) +{ + auto note = MakeUnique<JSErrorNotes::Note>(); + if (!note) + return nullptr; + + note->errorNumber = errorNumber; + note->filename = filename; + note->lineno = lineno; + note->column = column; + + if (!ExpandErrorArgumentsVA(cx, errorCallback, userRef, errorNumber, + nullptr, argumentsType, note.get(), ap)) { + return nullptr; + } + + return note; +} + +bool +JSErrorNotes::addNoteASCII(ExclusiveContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...) +{ + va_list ap; + va_start(ap, errorNumber); + auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, + errorNumber, ArgumentsAreASCII, ap); + va_end(ap); + + if (!note) + return false; + if (!notes_.append(Move(note))) + return false; + return true; +} + +bool +JSErrorNotes::addNoteLatin1(ExclusiveContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...) +{ + va_list ap; + va_start(ap, errorNumber); + auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, + errorNumber, ArgumentsAreLatin1, ap); + va_end(ap); + + if (!note) + return false; + if (!notes_.append(Move(note))) + return false; + return true; +} + +bool +JSErrorNotes::addNoteUTF8(ExclusiveContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...) +{ + va_list ap; + va_start(ap, errorNumber); + auto note = CreateErrorNoteVA(cx, filename, lineno, column, errorCallback, userRef, + errorNumber, ArgumentsAreUTF8, ap); + va_end(ap); + + if (!note) + return false; + if (!notes_.append(Move(note))) + return false; + return true; +} + +size_t +JSErrorNotes::length() +{ + return notes_.length(); +} + +UniquePtr<JSErrorNotes> +JSErrorNotes::copy(JSContext* cx) +{ + auto copiedNotes = MakeUnique<JSErrorNotes>(); + if (!copiedNotes) + return nullptr; + + for (auto&& note : *this) { + js::UniquePtr<JSErrorNotes::Note> copied(CopyErrorNote(cx, note.get())); + if (!copied) + return nullptr; + + if (!copiedNotes->notes_.append(Move(copied))) + return nullptr; + } + + return copiedNotes; +} + +JSErrorNotes::iterator +JSErrorNotes::begin() +{ + return iterator(notes_.begin()); +} + +JSErrorNotes::iterator +JSErrorNotes::end() +{ + return iterator(notes_.end()); +} + JS_PUBLIC_API(bool) JS_ThrowStopIteration(JSContext* cx) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 3f65dad34..67b3d4267 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -18,6 +18,7 @@ #include "mozilla/RefPtr.h" #include "mozilla/Variant.h" +#include <iterator> #include <stdarg.h> #include <stddef.h> #include <stdint.h> @@ -36,6 +37,7 @@ #include "js/Realm.h" #include "js/RootingAPI.h" #include "js/TracingAPI.h" +#include "js/UniquePtr.h" #include "js/Utility.h" #include "js/Value.h" #include "js/Vector.h" @@ -652,6 +654,7 @@ typedef enum JSExnType { JSEXN_WASMRUNTIMEERROR, JSEXN_ERROR_LIMIT, JSEXN_WARN = JSEXN_ERROR_LIMIT, + JSEXN_NOTE, JSEXN_LIMIT } JSExnType; @@ -5362,14 +5365,130 @@ JS_ReportOutOfMemory(JSContext* cx); extern JS_PUBLIC_API(void) JS_ReportAllocationOverflow(JSContext* cx); -class JSErrorReport +/** + * Base class that implements parts shared by JSErrorReport and + * JSErrorNotes::Note. + */ +class JSErrorBase { // The (default) error message. // If ownsMessage_ is true, the it is freed in destructor. JS::ConstUTF8CharsZ message_; + public: + JSErrorBase() + : filename(nullptr), lineno(0), column(0), + errorNumber(0), + ownsMessage_(false) + {} + + ~JSErrorBase() { + freeMessage(); + } + + // Source file name, URL, etc., or null. + const char* filename; + + // Source line number. + unsigned lineno; + + // Zero-based column index in line. + unsigned column; + + // the error number, e.g. see js.msg. + unsigned errorNumber; + + private: + bool ownsMessage_ : 1; + + public: + const JS::ConstUTF8CharsZ message() const { + return message_; + } + + void initOwnedMessage(const char* messageArg) { + initBorrowedMessage(messageArg); + ownsMessage_ = true; + } + void initBorrowedMessage(const char* messageArg) { + MOZ_ASSERT(!message_); + message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg)); + } + + JSString* newMessageString(JSContext* cx); + + private: + void freeMessage(); +}; + +/** + * Notes associated with JSErrorReport. + */ +class JSErrorNotes +{ + public: + class Note : public JSErrorBase + {}; + + private: + // Stores pointers to each note. + js::Vector<js::UniquePtr<Note>, 1, js::SystemAllocPolicy> notes_; + + public: + JSErrorNotes(); + ~JSErrorNotes(); + + // Add an note to the given position. + bool addNoteASCII(js::ExclusiveContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + bool addNoteLatin1(js::ExclusiveContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + bool addNoteUTF8(js::ExclusiveContext* cx, + const char* filename, unsigned lineno, unsigned column, + JSErrorCallback errorCallback, void* userRef, + const unsigned errorNumber, ...); + + size_t length(); + + // Create a deep copy of notes. + js::UniquePtr<JSErrorNotes> copy(JSContext* cx); + + class iterator : public std::iterator<std::input_iterator_tag, js::UniquePtr<Note>> + { + js::UniquePtr<Note>* note_; + public: + explicit iterator(js::UniquePtr<Note>* note = nullptr) : note_(note) + {} + + bool operator==(iterator other) const { + return note_ == other.note_; + } + bool operator!=(iterator other) const { + return !(*this == other); + } + iterator& operator++() { + note_++; + return *this; + } + reference operator*() { + return *note_; + } + }; + iterator begin(); + iterator end(); +}; + +/** + * Describes a single error or warning that occurs in the execution of script. + */ +class JSErrorReport : public JSErrorBase +{ // Offending source line without final '\n'. - // If ownsLinebuf__ is true, the buffer is freed in destructor. + // If ownsLinebuf_ is true, the buffer is freed in destructor. const char16_t* linebuf_; // Number of chars in linebuf_. Does not include trailing '\0'. @@ -5381,28 +5500,29 @@ class JSErrorReport public: JSErrorReport() : linebuf_(nullptr), linebufLength_(0), tokenOffset_(0), - filename(nullptr), lineno(0), column(0), - flags(0), errorNumber(0), - exnType(0), isMuted(false), - ownsLinebuf_(false), ownsMessage_(false) + notes(nullptr), + flags(0), exnType(0), isMuted(false), + ownsLinebuf_(false) {} ~JSErrorReport() { freeLinebuf(); - freeMessage(); } - const char* filename; /* source file name, URL, etc., or null */ - unsigned lineno; /* source line number */ - unsigned column; /* zero-based column index in line */ - unsigned flags; /* error/warning, etc. */ - unsigned errorNumber; /* the error number, e.g. see js.msg */ - int16_t exnType; /* One of the JSExnType constants */ - bool isMuted : 1; /* See the comment in ReadOnlyCompileOptions. */ + // Associated notes, or nullptr if there's no note. + js::UniquePtr<JSErrorNotes> notes; + + // error/warning, etc. + unsigned flags; + + // One of the JSExnType constants. + int16_t exnType; + + // See the comment in ReadOnlyCompileOptions. + bool isMuted : 1; private: bool ownsLinebuf_ : 1; - bool ownsMessage_ : 1; public: const char16_t* linebuf() const { @@ -5414,29 +5534,16 @@ class JSErrorReport size_t tokenOffset() const { return tokenOffset_; } - void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, size_t tokenOffsetArg) { + void initOwnedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, + size_t tokenOffsetArg) { initBorrowedLinebuf(linebufArg, linebufLengthArg, tokenOffsetArg); ownsLinebuf_ = true; } - void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, size_t tokenOffsetArg); - void freeLinebuf(); - - const JS::ConstUTF8CharsZ message() const { - return message_; - } - - void initOwnedMessage(const char* messageArg) { - initBorrowedMessage(messageArg); - ownsMessage_ = true; - } - void initBorrowedMessage(const char* messageArg) { - MOZ_ASSERT(!message_); - message_ = JS::ConstUTF8CharsZ(messageArg, strlen(messageArg)); - } + void initBorrowedLinebuf(const char16_t* linebufArg, size_t linebufLengthArg, + size_t tokenOffsetArg); - JSString* newMessageString(JSContext* cx); - - void freeMessage(); + private: + void freeLinebuf(); }; /* diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index ff581beec..e618c319f 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -602,7 +602,7 @@ js::ArraySetLength(JSContext* cx, Handle<ArrayObject*> arr, HandleId id, // for..in iteration over the array. Keys deleted before being reached // during the iteration must not be visited, and suppressing them here // would be too costly. - ObjectGroup* arrGroup = arr->getGroup(cx); + ObjectGroup* arrGroup = JSObject::getGroup(cx, arr); if (MOZ_UNLIKELY(!arrGroup)) return false; if (!arr->isIndexed() && !MOZ_UNLIKELY(arrGroup->hasAllFlags(OBJECT_FLAG_ITERATED))) { @@ -1285,7 +1285,7 @@ InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start, if (count == 0) return true; - ObjectGroup* group = obj->getGroup(cx); + ObjectGroup* group = JSObject::getGroup(cx, obj); if (!group) return false; @@ -1662,11 +1662,11 @@ MatchNumericComparator(JSContext* cx, const Value& v) if (!obj.is<JSFunction>()) return Match_None; - JSFunction* fun = &obj.as<JSFunction>(); + RootedFunction fun(cx, &obj.as<JSFunction>()); if (!fun->isInterpreted() || fun->isClassConstructor()) return Match_None; - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return Match_Failure; @@ -2144,7 +2144,7 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval) if (ObjectMayHaveExtraIndexedProperties(obj)) return DenseElementResult::Incomplete; - RootedObjectGroup group(cx, obj->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj)); if (MOZ_UNLIKELY(!group)) return DenseElementResult::Failure; @@ -2340,7 +2340,7 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co * deleted if a hole is moved from one location to another location not yet * visited. See bug 690622. */ - ObjectGroup* arrGroup = arr->getGroup(cx); + ObjectGroup* arrGroup = JSObject::getGroup(cx, arr); if (!arrGroup) { cx->recoverFromOutOfMemory(); return false; @@ -2380,13 +2380,6 @@ CopyDenseElements(JSContext* cx, NativeObject* dst, NativeObject* src, return DenseElementResult::Success; } -/* ES 2016 draft Mar 25, 2016 22.1.3.26. */ -bool -js::array_splice(JSContext* cx, unsigned argc, Value* vp) -{ - return array_splice_impl(cx, argc, vp, true); -} - static inline bool ArraySpliceCopy(JSContext* cx, HandleObject arr, HandleObject obj, uint32_t actualStart, uint32_t actualDeleteCount) @@ -2416,8 +2409,8 @@ ArraySpliceCopy(JSContext* cx, HandleObject arr, HandleObject obj, return SetLengthProperty(cx, arr, actualDeleteCount); } -bool -js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed) +static bool +array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed) { AutoSPSEntry pseudoFrame(cx->runtime(), "Array.prototype.splice"); CallArgs args = CallArgsFromVp(argc, vp); @@ -2667,6 +2660,19 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI return true; } +/* ES 2016 draft Mar 25, 2016 22.1.3.26. */ +bool +js::array_splice(JSContext* cx, unsigned argc, Value* vp) +{ + return array_splice_impl(cx, argc, vp, true); +} + +static bool +array_splice_noRetVal(JSContext* cx, unsigned argc, Value* vp) +{ + return array_splice_impl(cx, argc, vp, false); +} + struct SortComparatorIndexes { bool operator()(uint32_t a, uint32_t b, bool* lessOrEqualp) { @@ -3084,6 +3090,15 @@ array_of(JSContext* cx, unsigned argc, Value* vp) return true; } +const JSJitInfo js::array_splice_info = { + { (JSJitGetterOp)array_splice_noRetVal }, + { 0 }, /* unused */ + { 0 }, /* unused */ + JSJitInfo::IgnoresReturnValueNative, + JSJitInfo::AliasEverything, + JSVAL_TYPE_UNDEFINED, +}; + static const JSFunctionSpec array_methods[] = { #if JS_HAS_TOSOURCE JS_FN(js_toSource_str, array_toSource, 0,0), @@ -3099,7 +3114,7 @@ static const JSFunctionSpec array_methods[] = { JS_INLINABLE_FN("pop", array_pop, 0,0, ArrayPop), JS_INLINABLE_FN("shift", array_shift, 0,0, ArrayShift), JS_FN("unshift", array_unshift, 1,0), - JS_INLINABLE_FN("splice", array_splice, 2,0, ArraySplice), + JS_FNINFO("splice", array_splice, &array_splice_info, 2,0), /* Pythonic sequence methods. */ JS_SELF_HOSTED_FN("concat", "ArrayConcat", 1,0), @@ -3246,7 +3261,7 @@ static JSObject* CreateArrayPrototype(JSContext* cx, JSProtoKey key) { MOZ_ASSERT(key == JSProto_Array); - RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global())); if (!proto) return nullptr; @@ -3266,7 +3281,7 @@ CreateArrayPrototype(JSContext* cx, JSProtoKey key) metadata)); if (!arrayProto || !JSObject::setSingleton(cx, arrayProto) || - !arrayProto->setDelegate(cx) || + !JSObject::setDelegate(cx, arrayProto) || !AddLengthProperty(cx, arrayProto)) { return nullptr; @@ -3586,7 +3601,7 @@ js::NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup g // will have unknown property types. template <uint32_t maxLength> static inline ArrayObject* -NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, +NewArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length, NewObjectKind newKind = GenericObject) { if (!obj->is<ArrayObject>()) @@ -3595,7 +3610,7 @@ NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, if (obj->staticPrototype() != cx->global()->maybeGetArrayPrototype()) return NewArray<maxLength>(cx, length, nullptr, newKind); - RootedObjectGroup group(cx, obj->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj)); if (!group) return nullptr; @@ -3603,14 +3618,14 @@ NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, } ArrayObject* -js::NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, +js::NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length, NewObjectKind newKind) { return NewArrayTryReuseGroup<UINT32_MAX>(cx, obj, length, newKind); } ArrayObject* -js::NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length) +js::NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length) { return NewArrayTryReuseGroup<ArrayObject::EagerAllocationMaxLength>(cx, obj, length); } @@ -3643,7 +3658,7 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, if (!obj) return nullptr; - DenseElementResult result = obj->setOrExtendDenseElements(cx->asJSContext(), 0, vp, length, updateTypes); + DenseElementResult result = obj->setOrExtendDenseElements(cx, 0, vp, length, updateTypes); if (result == DenseElementResult::Failure) return nullptr; MOZ_ASSERT(result == DenseElementResult::Success); diff --git a/js/src/jsarray.h b/js/src/jsarray.h index ec2e4f514..d0084731f 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -83,11 +83,11 @@ extern ArrayObject* NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length); extern ArrayObject* -NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, +NewFullyAllocatedArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length, NewObjectKind newKind = GenericObject); extern ArrayObject* -NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length); +NewPartlyAllocatedArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length); extern ArrayObject* NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, @@ -147,9 +147,6 @@ extern bool array_pop(JSContext* cx, unsigned argc, js::Value* vp); extern bool -array_splice_impl(JSContext* cx, unsigned argc, js::Value* vp, bool pop); - -extern bool array_join(JSContext* cx, unsigned argc, js::Value* vp); extern void @@ -173,6 +170,8 @@ array_reverse(JSContext* cx, unsigned argc, js::Value* vp); extern bool array_splice(JSContext* cx, unsigned argc, js::Value* vp); +extern const JSJitInfo array_splice_info; + /* * Append the given (non-hole) value to the end of an array. The array must be * a newborn array -- that is, one which has not been exposed to script for diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index 2a3c58638..280ec3e9c 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -54,41 +54,9 @@ FOR_EACH_COMMON_PROPERTYNAME(CONST_CHAR_STR) #undef CONST_CHAR_STR /* Constant strings that are not atomized. */ -const char js_break_str[] = "break"; -const char js_case_str[] = "case"; -const char js_catch_str[] = "catch"; -const char js_class_str[] = "class"; -const char js_const_str[] = "const"; -const char js_continue_str[] = "continue"; -const char js_debugger_str[] = "debugger"; -const char js_default_str[] = "default"; -const char js_do_str[] = "do"; -const char js_else_str[] = "else"; -const char js_enum_str[] = "enum"; -const char js_export_str[] = "export"; -const char js_extends_str[] = "extends"; -const char js_finally_str[] = "finally"; -const char js_for_str[] = "for"; const char js_getter_str[] = "getter"; -const char js_if_str[] = "if"; -const char js_implements_str[] = "implements"; -const char js_import_str[] = "import"; -const char js_in_str[] = "in"; -const char js_instanceof_str[] = "instanceof"; -const char js_interface_str[] = "interface"; -const char js_package_str[] = "package"; -const char js_private_str[] = "private"; -const char js_protected_str[] = "protected"; -const char js_public_str[] = "public"; const char js_send_str[] = "send"; const char js_setter_str[] = "setter"; -const char js_switch_str[] = "switch"; -const char js_this_str[] = "this"; -const char js_try_str[] = "try"; -const char js_typeof_str[] = "typeof"; -const char js_void_str[] = "void"; -const char js_while_str[] = "while"; -const char js_with_str[] = "with"; // Use a low initial capacity for atom hash tables to avoid penalizing runtimes // which create a small number of atoms. diff --git a/js/src/jsatom.h b/js/src/jsatom.h index 496dcbb4c..0a5fd3c14 100644 --- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -142,44 +142,9 @@ FOR_EACH_COMMON_PROPERTYNAME(DECLARE_CONST_CHAR_STR) #undef DECLARE_CONST_CHAR_STR /* Constant strings that are not atomized. */ -extern const char js_break_str[]; -extern const char js_case_str[]; -extern const char js_catch_str[]; -extern const char js_class_str[]; -extern const char js_close_str[]; -extern const char js_const_str[]; -extern const char js_continue_str[]; -extern const char js_debugger_str[]; -extern const char js_default_str[]; -extern const char js_do_str[]; -extern const char js_else_str[]; -extern const char js_enum_str[]; -extern const char js_export_str[]; -extern const char js_extends_str[]; -extern const char js_finally_str[]; -extern const char js_for_str[]; extern const char js_getter_str[]; -extern const char js_if_str[]; -extern const char js_implements_str[]; -extern const char js_import_str[]; -extern const char js_in_str[]; -extern const char js_instanceof_str[]; -extern const char js_interface_str[]; -extern const char js_package_str[]; -extern const char js_private_str[]; -extern const char js_protected_str[]; -extern const char js_public_str[]; extern const char js_send_str[]; extern const char js_setter_str[]; -extern const char js_static_str[]; -extern const char js_super_str[]; -extern const char js_switch_str[]; -extern const char js_this_str[]; -extern const char js_try_str[]; -extern const char js_typeof_str[]; -extern const char js_void_str[]; -extern const char js_while_str[]; -extern const char js_with_str[]; namespace js { diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index c8109b02c..b2d07c628 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -137,14 +137,14 @@ js::InitBooleanClass(JSContext* cx, HandleObject obj) { MOZ_ASSERT(obj->isNative()); - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); - Rooted<BooleanObject*> booleanProto(cx, global->createBlankPrototype<BooleanObject>(cx)); + Rooted<BooleanObject*> booleanProto(cx, GlobalObject::createBlankPrototype<BooleanObject>(cx, global)); if (!booleanProto) return nullptr; booleanProto->setFixedSlot(BooleanObject::PRIMITIVE_VALUE_SLOT, BooleanValue(false)); - RootedFunction ctor(cx, global->createConstructor(cx, Boolean, cx->names().Boolean, 1)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, Boolean, cx->names().Boolean, 1)); if (!ctor) return nullptr; diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 31d62332d..e505a4b34 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -381,49 +381,16 @@ js::ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg) } } -bool -js::PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, - JSErrorReport* report, bool reportWarnings) -{ - MOZ_ASSERT(report); - - /* Conditionally ignore reported warnings. */ - if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) - return false; - - char* prefix = nullptr; - if (report->filename) - prefix = JS_smprintf("%s:", report->filename); - if (report->lineno) { - char* tmp = prefix; - prefix = JS_smprintf("%s%u:%u ", tmp ? tmp : "", report->lineno, report->column); - JS_free(cx, tmp); - } - if (JSREPORT_IS_WARNING(report->flags)) { - char* tmp = prefix; - prefix = JS_smprintf("%s%swarning: ", - tmp ? tmp : "", - JSREPORT_IS_STRICT(report->flags) ? "strict " : ""); - JS_free(cx, tmp); - } - - const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str(); - - /* embedded newlines -- argh! */ - const char* ctmp; - while ((ctmp = strchr(message, '\n')) != 0) { - ctmp++; - if (prefix) - fputs(prefix, file); - fwrite(message, 1, ctmp - message, file); - message = ctmp; - } - - /* If there were no filename or lineno, the prefix might be empty */ - if (prefix) - fputs(prefix, file); - fputs(message, file); +enum class PrintErrorKind { + Error, + Warning, + StrictWarning, + Note +}; +static void +PrintErrorLine(JSContext* cx, FILE* file, const char* prefix, JSErrorReport* report) +{ if (const char16_t* linebuf = report->linebuf()) { size_t n = report->linebufLength(); @@ -453,9 +420,96 @@ js::PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, } fputc('^', file); } +} + +static void +PrintErrorLine(JSContext* cx, FILE* file, const char* prefix, JSErrorNotes::Note* note) +{ +} + +template <typename T> +static bool +PrintSingleError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, + T* report, PrintErrorKind kind) +{ + UniquePtr<char> prefix; + if (report->filename) + prefix.reset(JS_smprintf("%s:", report->filename)); + + if (report->lineno) { + UniquePtr<char> tmp(JS_smprintf("%s%u:%u ", prefix ? prefix.get() : "", report->lineno, + report->column)); + prefix = Move(tmp); + } + + if (kind != PrintErrorKind::Error) { + const char* kindPrefix = nullptr; + switch (kind) { + case PrintErrorKind::Error: + break; + case PrintErrorKind::Warning: + kindPrefix = "warning"; + break; + case PrintErrorKind::StrictWarning: + kindPrefix = "strict warning"; + break; + case PrintErrorKind::Note: + kindPrefix = "note"; + break; + } + + UniquePtr<char> tmp(JS_smprintf("%s%s: ", prefix ? prefix.get() : "", kindPrefix)); + prefix = Move(tmp); + } + + const char* message = toStringResult ? toStringResult.c_str() : report->message().c_str(); + + /* embedded newlines -- argh! */ + const char* ctmp; + while ((ctmp = strchr(message, '\n')) != 0) { + ctmp++; + if (prefix) + fputs(prefix.get(), file); + fwrite(message, 1, ctmp - message, file); + message = ctmp; + } + + /* If there were no filename or lineno, the prefix might be empty */ + if (prefix) + fputs(prefix.get(), file); + fputs(message, file); + + PrintErrorLine(cx, file, prefix.get(), report); fputc('\n', file); + fflush(file); - JS_free(cx, prefix); + return true; +} + +bool +js::PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult, + JSErrorReport* report, bool reportWarnings) +{ + MOZ_ASSERT(report); + + /* Conditionally ignore reported warnings. */ + if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) + return false; + + PrintErrorKind kind = PrintErrorKind::Error; + if (JSREPORT_IS_WARNING(report->flags)) { + if (JSREPORT_IS_STRICT(report->flags)) + kind = PrintErrorKind::StrictWarning; + else + kind = PrintErrorKind::Warning; + } + PrintSingleError(cx, file, toStringResult, report, kind); + + if (report->notes) { + for (auto&& note : *report->notes) + PrintSingleError(cx, file, JS::ConstUTF8CharsZ(), note.get(), PrintErrorKind::Note); + } + return true; } @@ -557,6 +611,18 @@ class MOZ_RAII AutoMessageArgs } }; +static void +SetExnType(JSErrorReport* reportp, int16_t exnType) +{ + reportp->exnType = exnType; +} + +static void +SetExnType(JSErrorNotes::Note* notep, int16_t exnType) +{ + // Do nothing for JSErrorNotes::Note. +} + /* * The arguments from ap need to be packaged up into an array and stored * into the report struct. @@ -568,12 +634,13 @@ class MOZ_RAII AutoMessageArgs * * Returns true if the expansion succeeds (can fail if out of memory). */ +template <typename T> bool -js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, +ExpandErrorArgumentsHelper(ExclusiveContext* cx, JSErrorCallback callback, void* userRef, const unsigned errorNumber, const char16_t** messageArgs, ErrorArgumentsType argumentsType, - JSErrorReport* reportp, va_list ap) + T* reportp, va_list ap) { const JSErrorFormatString* efs; @@ -586,7 +653,7 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, } if (efs) { - reportp->exnType = efs->exnType; + SetExnType(reportp, efs->exnType); MOZ_ASSERT_IF(argumentsType == ArgumentsAreASCII, JS::StringIsASCII(efs->format)); @@ -670,6 +737,28 @@ js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, } bool +js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, + void* userRef, const unsigned errorNumber, + const char16_t** messageArgs, + ErrorArgumentsType argumentsType, + JSErrorReport* reportp, va_list ap) +{ + return ExpandErrorArgumentsHelper(cx, callback, userRef, errorNumber, + messageArgs, argumentsType, reportp, ap); +} + +bool +js::ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, + void* userRef, const unsigned errorNumber, + const char16_t** messageArgs, + ErrorArgumentsType argumentsType, + JSErrorNotes::Note* notep, va_list ap) +{ + return ExpandErrorArgumentsHelper(cx, callback, userRef, errorNumber, + messageArgs, argumentsType, notep, ap); +} + +bool js::ReportErrorNumberVA(JSContext* cx, unsigned flags, JSErrorCallback callback, void* userRef, const unsigned errorNumber, ErrorArgumentsType argumentsType, va_list ap) @@ -832,6 +921,52 @@ js::ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNum return ok; } +JSObject* +js::CreateErrorNotesArray(JSContext* cx, JSErrorReport* report) +{ + RootedArrayObject notesArray(cx, NewDenseEmptyArray(cx)); + if (!notesArray) + return nullptr; + + if (!report->notes) + return notesArray; + + for (auto&& note : *report->notes) { + RootedPlainObject noteObj(cx, NewBuiltinClassInstance<PlainObject>(cx)); + if (!noteObj) + return nullptr; + + RootedString messageStr(cx, note->newMessageString(cx)); + if (!messageStr) + return nullptr; + RootedValue messageVal(cx, StringValue(messageStr)); + if (!DefineProperty(cx, noteObj, cx->names().message, messageVal)) + return nullptr; + + RootedValue filenameVal(cx); + if (note->filename) { + RootedString filenameStr(cx, NewStringCopyZ<CanGC>(cx, note->filename)); + if (!filenameStr) + return nullptr; + filenameVal = StringValue(filenameStr); + } + if (!DefineProperty(cx, noteObj, cx->names().fileName, filenameVal)) + return nullptr; + + RootedValue linenoVal(cx, Int32Value(note->lineno)); + if (!DefineProperty(cx, noteObj, cx->names().lineNumber, linenoVal)) + return nullptr; + RootedValue columnVal(cx, Int32Value(note->column)); + if (!DefineProperty(cx, noteObj, cx->names().columnNumber, columnVal)) + return nullptr; + + if (!NewbornArrayPush(cx, notesArray, ObjectValue(*noteObj))) + return nullptr; + } + + return notesArray; +} + const JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = { #define MSG_DEF(name, count, exception, format) \ { #name, format, count, exception } , diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 0a2841242..8be3376cf 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -621,6 +621,13 @@ ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, ErrorArgumentsType argumentsType, JSErrorReport* reportp, va_list ap); +extern bool +ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback, + void* userRef, const unsigned errorNumber, + const char16_t** messageArgs, + ErrorArgumentsType argumentsType, + JSErrorNotes::Note* notep, va_list ap); + /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */ extern void ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg); @@ -678,6 +685,9 @@ ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNumber, ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \ spindex, v, fallback, arg1, arg2)) +JSObject* +CreateErrorNotesArray(JSContext* cx, JSErrorReport* report); + } /* namespace js */ extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit]; diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 6024a1768..d0caeb558 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -1075,18 +1075,18 @@ CreateLazyScriptsForCompartment(JSContext* cx) // Create scripts for each lazy function, updating the list of functions to // process with any newly exposed inner functions in created scripts. // A function cannot be delazified until its outer script exists. + RootedFunction fun(cx); for (size_t i = 0; i < lazyFunctions.length(); i++) { - JSFunction* fun = &lazyFunctions[i]->as<JSFunction>(); + fun = &lazyFunctions[i]->as<JSFunction>(); // lazyFunctions may have been populated with multiple functions for // a lazy script. if (!fun->isInterpretedLazy()) continue; - LazyScript* lazy = fun->lazyScript(); - bool lazyScriptHadNoScript = !lazy->maybeScript(); + bool lazyScriptHadNoScript = !fun->lazyScript()->maybeScript(); - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return false; if (lazyScriptHadNoScript && !AddInnerLazyFunctionsFromScript(script, lazyFunctions)) diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 52294a5df..c6a369e2d 100755 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -3163,7 +3163,7 @@ js::DateConstructor(JSContext* cx, unsigned argc, Value* vp) static JSObject* CreateDatePrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &DateObject::protoClass_); + return GlobalObject::createBlankPrototype(cx, cx->global(), &DateObject::protoClass_); } static bool diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 1e70a3890..65cc81a1a 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -201,28 +201,77 @@ ErrorObject::classes[JSEXN_ERROR_LIMIT] = { IMPLEMENT_ERROR_CLASS(RuntimeError) }; -JSErrorReport* -js::CopyErrorReport(JSContext* cx, JSErrorReport* report) +size_t +ExtraMallocSize(JSErrorReport* report) +{ + if (report->linebuf()) + return (report->linebufLength() + 1) * sizeof(char16_t); + + return 0; +} + +size_t +ExtraMallocSize(JSErrorNotes::Note* note) +{ + return 0; +} + +bool +CopyExtraData(JSContext* cx, uint8_t** cursor, JSErrorReport* copy, JSErrorReport* report) +{ + if (report->linebuf()) { + size_t linebufSize = (report->linebufLength() + 1) * sizeof(char16_t); + const char16_t* linebufCopy = (const char16_t*)(*cursor); + js_memcpy(*cursor, report->linebuf(), linebufSize); + *cursor += linebufSize; + copy->initBorrowedLinebuf(linebufCopy, report->linebufLength(), report->tokenOffset()); + } + + /* Copy non-pointer members. */ + copy->isMuted = report->isMuted; + copy->exnType = report->exnType; + + /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */ + copy->flags = report->flags; + + /* Deep copy notes. */ + if (report->notes) { + auto copiedNotes = report->notes->copy(cx); + if (!copiedNotes) + return false; + copy->notes = Move(copiedNotes); + } else { + copy->notes.reset(nullptr); + } + + return true; +} + +bool +CopyExtraData(JSContext* cx, uint8_t** cursor, JSErrorNotes::Note* copy, JSErrorNotes::Note* report) +{ + return true; +} + +template <typename T> +static T* +CopyErrorHelper(JSContext* cx, T* report) { /* - * We use a single malloc block to make a deep copy of JSErrorReport with + * We use a single malloc block to make a deep copy of JSErrorReport or + * JSErrorNotes::Note, except JSErrorNotes linked from JSErrorReport with * the following layout: - * JSErrorReport + * JSErrorReport or JSErrorNotes::Note * char array with characters for message_ - * char16_t array with characters for linebuf * char array with characters for filename + * char16_t array with characters for linebuf (only for JSErrorReport) * Such layout together with the properties enforced by the following * asserts does not need any extra alignment padding. */ - JS_STATIC_ASSERT(sizeof(JSErrorReport) % sizeof(const char*) == 0); + JS_STATIC_ASSERT(sizeof(T) % sizeof(const char*) == 0); JS_STATIC_ASSERT(sizeof(const char*) % sizeof(char16_t) == 0); -#define JS_CHARS_SIZE(chars) ((js_strlen(chars) + 1) * sizeof(char16_t)) - size_t filenameSize = report->filename ? strlen(report->filename) + 1 : 0; - size_t linebufSize = 0; - if (report->linebuf()) - linebufSize = (report->linebufLength() + 1) * sizeof(char16_t); size_t messageSize = 0; if (report->message()) messageSize = strlen(report->message().c_str()) + 1; @@ -231,13 +280,13 @@ js::CopyErrorReport(JSContext* cx, JSErrorReport* report) * The mallocSize can not overflow since it represents the sum of the * sizes of already allocated objects. */ - size_t mallocSize = sizeof(JSErrorReport) + messageSize + linebufSize + filenameSize; + size_t mallocSize = sizeof(T) + messageSize + filenameSize + ExtraMallocSize(report); uint8_t* cursor = cx->pod_calloc<uint8_t>(mallocSize); if (!cursor) return nullptr; - JSErrorReport* copy = (JSErrorReport*)cursor; - cursor += sizeof(JSErrorReport); + T* copy = new (cursor) T(); + cursor += sizeof(T); if (report->message()) { copy->initBorrowedMessage((const char*)cursor); @@ -245,33 +294,40 @@ js::CopyErrorReport(JSContext* cx, JSErrorReport* report) cursor += messageSize; } - if (report->linebuf()) { - const char16_t* linebufCopy = (const char16_t*)cursor; - js_memcpy(cursor, report->linebuf(), linebufSize); - cursor += linebufSize; - copy->initBorrowedLinebuf(linebufCopy, report->linebufLength(), report->tokenOffset()); - } - if (report->filename) { copy->filename = (const char*)cursor; js_memcpy(cursor, report->filename, filenameSize); + cursor += filenameSize; } - MOZ_ASSERT(cursor + filenameSize == (uint8_t*)copy + mallocSize); + + if (!CopyExtraData(cx, &cursor, copy, report)) { + /* js_delete calls destructor for T and js_free for pod_calloc. */ + js_delete(copy); + return nullptr; + } + + MOZ_ASSERT(cursor == (uint8_t*)copy + mallocSize); /* Copy non-pointer members. */ - copy->isMuted = report->isMuted; copy->lineno = report->lineno; copy->column = report->column; copy->errorNumber = report->errorNumber; - copy->exnType = report->exnType; - - /* Note that this is before it gets flagged with JSREPORT_EXCEPTION */ - copy->flags = report->flags; -#undef JS_CHARS_SIZE return copy; } +JSErrorNotes::Note* +js::CopyErrorNote(JSContext* cx, JSErrorNotes::Note* note) +{ + return CopyErrorHelper(cx, note); +} + +JSErrorReport* +js::CopyErrorReport(JSContext* cx, JSErrorReport* report) +{ + return CopyErrorHelper(cx, report); +} + struct SuppressErrorsGuard { JSContext* cx; @@ -322,7 +378,7 @@ exn_finalize(FreeOp* fop, JSObject* obj) { MOZ_ASSERT(fop->maybeOffMainThread()); if (JSErrorReport* report = obj->as<ErrorObject>().getErrorReport()) - fop->free_(report); + fop->delete_(report); } JSErrorReport* @@ -512,14 +568,17 @@ ErrorObject::createProto(JSContext* cx, JSProtoKey key) { JSExnType type = ExnTypeFromProtoKey(key); - if (type == JSEXN_ERR) - return cx->global()->createBlankPrototype(cx, &ErrorObject::protoClasses[JSEXN_ERR]); + if (type == JSEXN_ERR) { + return GlobalObject::createBlankPrototype(cx, cx->global(), + &ErrorObject::protoClasses[JSEXN_ERR]); + } RootedObject protoProto(cx, GlobalObject::getOrCreateErrorPrototype(cx, cx->global())); if (!protoProto) return nullptr; - return cx->global()->createBlankPrototypeInheriting(cx, &ErrorObject::protoClasses[type], + return GlobalObject::createBlankPrototypeInheriting(cx, cx->global(), + &ErrorObject::protoClasses[type], protoProto); } @@ -586,6 +645,7 @@ js::ErrorToException(JSContext* cx, JSErrorReport* reportp, const JSErrorFormatString* errorString = callback(userRef, errorNumber); JSExnType exnType = errorString ? static_cast<JSExnType>(errorString->exnType) : JSEXN_ERR; MOZ_ASSERT(exnType < JSEXN_LIMIT); + MOZ_ASSERT(exnType != JSEXN_NOTE); if (exnType == JSEXN_WARN) { // werror must be enabled, so we use JSEXN_ERR. @@ -669,7 +729,7 @@ ErrorReportToString(JSContext* cx, JSErrorReport* reportp) */ JSExnType type = static_cast<JSExnType>(reportp->exnType); RootedString str(cx); - if (type != JSEXN_WARN) + if (type != JSEXN_WARN && type != JSEXN_NOTE) str = ClassName(GetExceptionProtoKey(type), cx); /* diff --git a/js/src/jsexn.h b/js/src/jsexn.h index ae6335209..00120d89c 100644 --- a/js/src/jsexn.h +++ b/js/src/jsexn.h @@ -18,6 +18,9 @@ namespace js { class ErrorObject; +JSErrorNotes::Note* +CopyErrorNote(JSContext* cx, JSErrorNotes::Note* note); + JSErrorReport* CopyErrorReport(JSContext* cx, JSErrorReport* report); @@ -67,7 +70,8 @@ static_assert(JSEXN_ERR == 0 && JSProto_Error + JSEXN_WASMCOMPILEERROR == JSProto_CompileError && JSProto_Error + JSEXN_WASMRUNTIMEERROR == JSProto_RuntimeError && JSEXN_WASMRUNTIMEERROR + 1 == JSEXN_WARN && - JSEXN_WARN + 1 == JSEXN_LIMIT, + JSEXN_WARN + 1 == JSEXN_NOTE && + JSEXN_NOTE + 1 == JSEXN_LIMIT, "GetExceptionProtoKey and ExnTypeFromProtoKey require that " "each corresponding JSExnType and JSProtoKey value be separated " "by the same constant value"); diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 5baba0beb..f7622cb44 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -113,7 +113,7 @@ JS_SplicePrototype(JSContext* cx, HandleObject obj, HandleObject proto) } Rooted<TaggedProto> tagged(cx, TaggedProto(proto)); - return obj->splicePrototype(cx, obj->getClass(), tagged); + return JSObject::splicePrototype(cx, obj, obj->getClass(), tagged); } JS_FRIEND_API(JSObject*) diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index d29285483..351667fb3 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -2254,6 +2254,7 @@ struct JSJitInfo { Method, StaticMethod, InlinableNative, + IgnoresReturnValueNative, // Must be last OpTypeCount }; @@ -2345,8 +2346,13 @@ struct JSJitInfo { JSJitMethodOp method; /** A DOM static method, used for Promise wrappers */ JSNative staticMethod; + JSNative ignoresReturnValueMethod; }; + static unsigned offsetOfIgnoresReturnValueNative() { + return offsetof(JSJitInfo, ignoresReturnValueMethod); + } + union { uint16_t protoID; js::jit::InlinableNative inlinableNative; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index e624aa415..9edf238ef 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -129,6 +129,11 @@ IsFunctionInStrictMode(JSFunction* fun) return IsAsmJSStrictModeModuleOrFunction(fun); } +static bool +IsNewerTypeFunction(JSFunction* fun) { + return fun->isArrow() || fun->isGenerator() || fun->isAsync() || fun->isMethod(); +} + // Beware: this function can be invoked on *any* function! That includes // natives, strict mode functions, bound functions, arrow functions, // self-hosted functions and constructors, asm.js functions, functions with @@ -142,7 +147,9 @@ ArgumentsRestrictions(JSContext* cx, HandleFunction fun) // a strict mode function, or a bound function. // TODO (bug 1057208): ensure semantics are correct for all possible // pairings of callee/caller. - if (fun->isBuiltin() || IsFunctionInStrictMode(fun) || fun->isBoundFunction()) { + if (fun->isBuiltin() || IsFunctionInStrictMode(fun) || + fun->isBoundFunction() || IsNewerTypeFunction(fun)) + { ThrowTypeErrorBehavior(cx); return false; } @@ -229,7 +236,9 @@ CallerRestrictions(JSContext* cx, HandleFunction fun) // a strict mode function, or a bound function. // TODO (bug 1057208): ensure semantics are correct for all possible // pairings of callee/caller. - if (fun->isBuiltin() || IsFunctionInStrictMode(fun) || fun->isBoundFunction()) { + if (fun->isBuiltin() || IsFunctionInStrictMode(fun) || + fun->isBoundFunction() || IsNewerTypeFunction(fun)) + { ThrowTypeErrorBehavior(cx); return false; } @@ -275,6 +284,8 @@ CallerGetterImpl(JSContext* cx, const CallArgs& args) } RootedObject caller(cx, iter.callee(cx)); + if (caller->is<JSFunction>() && caller->as<JSFunction>().isAsync()) + caller = GetWrappedAsyncFunction(&caller->as<JSFunction>()); if (!cx->compartment()->wrap(cx, &caller)) return false; @@ -295,6 +306,8 @@ CallerGetterImpl(JSContext* cx, const CallArgs& args) } JSFunction* callerFun = &callerObj->as<JSFunction>(); + if (IsWrappedAsyncFunction(callerFun)) + callerFun = GetUnwrappedAsyncFunction(callerFun); MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?"); if (callerFun->strict()) { @@ -366,7 +379,7 @@ ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId if (isStarGenerator) objProto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global); else - objProto = fun->global().getOrCreateObjectPrototype(cx); + objProto = GlobalObject::getOrCreateObjectPrototype(cx, global); if (!objProto) return false; @@ -463,7 +476,7 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp) if (fun->hasResolvedLength()) return true; - if (!fun->getUnresolvedLength(cx, &v)) + if (!JSFunction::getUnresolvedLength(cx, fun, &v)) return false; } else { if (fun->hasResolvedName()) @@ -808,12 +821,13 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) sourceObject, begin, ss->length(), - 0)); + 0, + ss->length())); if (!script || !JSScript::initFunctionPrototype(cx, script, functionProto)) return nullptr; functionProto->initScript(script); - ObjectGroup* protoGroup = functionProto->getGroup(cx); + ObjectGroup* protoGroup = JSObject::getGroup(cx, functionProto); if (!protoGroup) return nullptr; @@ -848,6 +862,28 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key) if (!throwTypeError || !PreventExtensions(cx, throwTypeError)) return nullptr; + // The "length" property of %ThrowTypeError% is non-configurable, adjust + // the default property attributes accordingly. + Rooted<PropertyDescriptor> nonConfigurableDesc(cx); + nonConfigurableDesc.setAttributes(JSPROP_PERMANENT | JSPROP_IGNORE_READONLY | + JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_VALUE); + + RootedId lengthId(cx, NameToId(cx->names().length)); + ObjectOpResult lengthResult; + if (!NativeDefineProperty(cx, throwTypeError, lengthId, nonConfigurableDesc, lengthResult)) + return nullptr; + MOZ_ASSERT(lengthResult); + + // Non-standard: Also change "name" to non-configurable. ECMAScript defines + // %ThrowTypeError% as an anonymous function, i.e. it shouldn't actually + // get an own "name" property. To be consistent with other built-in, + // anonymous functions, we don't delete %ThrowTypeError%'s "name" property. + RootedId nameId(cx, NameToId(cx->names().name)); + ObjectOpResult nameResult; + if (!NativeDefineProperty(cx, throwTypeError, nameId, nonConfigurableDesc, nameResult)) + return nullptr; + MOZ_ASSERT(nameResult); + self->setThrowTypeError(throwTypeError); return functionProto; @@ -886,80 +922,10 @@ const Class JSFunction::class_ = { const Class* const js::FunctionClassPtr = &JSFunction::class_; -/* Find the body of a function (not including braces). */ -bool -js::FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart, - size_t* bodyEnd) -{ - // We don't need principals, since those are only used for error reporting. - CompileOptions options(cx); - options.setFileAndLine("internal-findBody", 0); - - // For asm.js/wasm modules, there's no script. - if (fun->hasScript()) - options.setVersion(fun->nonLazyScript()->getVersion()); - - AutoKeepAtoms keepAtoms(cx->perThreadData); - - AutoStableStringChars stableChars(cx); - if (!stableChars.initTwoByte(cx, src)) - return false; - - const mozilla::Range<const char16_t> srcChars = stableChars.twoByteRange(); - TokenStream ts(cx, options, srcChars.begin().get(), srcChars.length(), nullptr); - int nest = 0; - bool onward = true; - // Skip arguments list. - do { - TokenKind tt; - if (!ts.getToken(&tt)) - return false; - switch (tt) { - case TOK_NAME: - case TOK_YIELD: - if (nest == 0) - onward = false; - break; - case TOK_LP: - nest++; - break; - case TOK_RP: - if (--nest == 0) - onward = false; - break; - default: - break; - } - } while (onward); - TokenKind tt; - if (!ts.getToken(&tt)) - return false; - if (tt == TOK_ARROW) { - if (!ts.getToken(&tt)) - return false; - } - bool braced = tt == TOK_LC; - MOZ_ASSERT_IF(fun->isExprBody(), !braced); - *bodyStart = ts.currentToken().pos.begin; - if (braced) - *bodyStart += 1; - mozilla::RangedPtr<const char16_t> end = srcChars.end(); - if (end[-1] == '}') { - end--; - } else { - MOZ_ASSERT(!braced); - for (; unicode::IsSpaceOrBOM2(end[-1]); end--) - ; - } - *bodyEnd = end - srcChars.begin(); - MOZ_ASSERT(*bodyStart <= *bodyEnd); - return true; -} - JSString* js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) { - if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) + if (fun->isInterpretedLazy() && !JSFunction::getOrCreateScript(cx, fun)) return nullptr; if (IsAsmJSModule(fun)) @@ -989,7 +955,13 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) } bool funIsNonArrowLambda = fun->isLambda() && !fun->isArrow(); - bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin(); + + // Default class constructors are self-hosted, but have their source + // objects overridden to refer to the span of the class statement or + // expression. Non-default class constructors are never self-hosted. So, + // all class constructors always have source. + bool haveSource = fun->isInterpreted() && (fun->isClassConstructor() || + !fun->isSelfHostedBuiltin()); // If we're not in pretty mode, put parentheses around lambda functions // so that eval returns lambda, not function statement. @@ -1030,7 +1002,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) }; if (haveSource) { - Rooted<JSFlatString*> src(cx, script->sourceDataWithPrelude(cx)); + Rooted<JSFlatString*> src(cx, JSScript::sourceDataForToString(cx, script)); if (!src) return nullptr; @@ -1041,7 +1013,20 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) if (!out.append(")")) return nullptr; } - } else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) { + } else if (fun->isInterpreted() && + (!fun->isSelfHostedBuiltin() || + fun->infallibleIsDefaultClassConstructor(cx))) + { + // Default class constructors should always haveSource except; + // + // 1. Source has been discarded for the whole compartment. + // + // 2. The source is marked as "lazy", i.e., retrieved on demand, and + // the embedding has not provided a hook to retrieve sources. + MOZ_ASSERT_IF(fun->infallibleIsDefaultClassConstructor(cx), + !cx->runtime()->sourceHook || + !script->scriptSource()->sourceRetrievable() || + fun->compartment()->behaviors().discardSource()); if (!AppendPrelude() || !out.append("() {\n ") || !out.append("[sourceless code]") || @@ -1050,29 +1035,16 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) return nullptr; } } else { - MOZ_ASSERT(!fun->isExprBody()); - bool derived = fun->infallibleIsDefaultClassConstructor(cx); - if (derived && fun->isDerivedClassConstructor()) { - if (!AppendPrelude() || - !out.append("(...args) {\n ") || - !out.append("super(...args);\n}")) - { - return nullptr; - } - } else { - if (!AppendPrelude() || - !out.append("() {\n ")) - return nullptr; + if (!AppendPrelude() || + !out.append("() {\n ")) + return nullptr; - if (!derived) { - if (!out.append("[native code]")) - return nullptr; - } + if (!out.append("[native code]")) + return nullptr; - if (!out.append("\n}")) - return nullptr; - } + if (!out.append("\n}")) + return nullptr; } return out.finishString(); } @@ -1301,34 +1273,33 @@ JSFunction::isDerivedClassConstructor() return derived; } -bool -JSFunction::getLength(JSContext* cx, uint16_t* length) +/* static */ bool +JSFunction::getLength(JSContext* cx, HandleFunction fun, uint16_t* length) { - JS::RootedFunction self(cx, this); - MOZ_ASSERT(!self->isBoundFunction()); - if (self->isInterpretedLazy() && !self->getOrCreateScript(cx)) + MOZ_ASSERT(!fun->isBoundFunction()); + if (fun->isInterpretedLazy() && !getOrCreateScript(cx, fun)) return false; - *length = self->isNative() ? self->nargs() : self->nonLazyScript()->funLength(); + *length = fun->isNative() ? fun->nargs() : fun->nonLazyScript()->funLength(); return true; } -bool -JSFunction::getUnresolvedLength(JSContext* cx, MutableHandleValue v) +/* static */ bool +JSFunction::getUnresolvedLength(JSContext* cx, HandleFunction fun, MutableHandleValue v) { - MOZ_ASSERT(!IsInternalFunctionObject(*this)); - MOZ_ASSERT(!hasResolvedLength()); + MOZ_ASSERT(!IsInternalFunctionObject(*fun)); + MOZ_ASSERT(!fun->hasResolvedLength()); // Bound functions' length can have values up to MAX_SAFE_INTEGER, so // they're handled differently from other functions. - if (isBoundFunction()) { - MOZ_ASSERT(getExtendedSlot(BOUND_FUN_LENGTH_SLOT).isNumber()); - v.set(getExtendedSlot(BOUND_FUN_LENGTH_SLOT)); + if (fun->isBoundFunction()) { + MOZ_ASSERT(fun->getExtendedSlot(BOUND_FUN_LENGTH_SLOT).isNumber()); + v.set(fun->getExtendedSlot(BOUND_FUN_LENGTH_SLOT)); return true; } uint16_t length; - if (!getLength(cx, &length)) + if (!JSFunction::getLength(cx, fun, &length)) return false; v.setInt32(length); @@ -1385,13 +1356,11 @@ GetBoundFunctionArguments(const JSFunction* boundFun) } const js::Value& -JSFunction::getBoundFunctionArgument(JSContext* cx, unsigned which) const +JSFunction::getBoundFunctionArgument(unsigned which) const { MOZ_ASSERT(which < getBoundFunctionArgumentCount()); - RootedArrayObject boundArgs(cx, GetBoundFunctionArguments(this)); - RootedValue res(cx); - return boundArgs->getDenseElement(which); + return GetBoundFunctionArguments(this)->getDenseElement(which); } size_t @@ -1428,7 +1397,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti } if (fun != lazy->functionNonDelazifying()) { - if (!lazy->functionDelazifying(cx)) + if (!LazyScript::functionDelazifying(cx, lazy)) return false; script = lazy->functionNonDelazifying()->nonLazyScript(); if (!script) diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 1c7da57ec..234169507 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -58,8 +58,6 @@ class JSFunction : public js::NativeObject CONSTRUCTOR = 0x0002, /* function that can be called as a constructor */ EXTENDED = 0x0004, /* structure is FunctionExtended */ BOUND_FUN = 0x0008, /* function was created with Function.prototype.bind. */ - EXPR_BODY = 0x0010, /* arrow function with expression body or - * expression closure: function(x) x*x */ HAS_GUESSED_ATOM = 0x0020, /* function had no explicit name, but a name was guessed for it anyway */ LAMBDA = 0x0040, /* function comes from a FunctionExpression, ArrowFunction, or @@ -102,7 +100,7 @@ class JSFunction : public js::NativeObject INTERPRETED_GENERATOR = INTERPRETED, NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME, - STABLE_ACROSS_CLONES = CONSTRUCTOR | EXPR_BODY | HAS_GUESSED_ATOM | LAMBDA | + STABLE_ACROSS_CLONES = CONSTRUCTOR | HAS_GUESSED_ATOM | LAMBDA | SELF_HOSTED | HAS_COMPILE_TIME_NAME | FUNCTION_KIND_MASK }; @@ -187,7 +185,6 @@ class JSFunction : public js::NativeObject bool isAsmJSNative() const { return kind() == AsmJS; } /* Possible attributes of an interpreted function: */ - bool isExprBody() const { return flags() & EXPR_BODY; } bool hasCompileTimeName() const { return flags() & HAS_COMPILE_TIME_NAME; } bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; } bool isLambda() const { return flags() & LAMBDA; } @@ -290,11 +287,6 @@ class JSFunction : public js::NativeObject flags_ |= SELF_HOSTED; } - // Can be called multiple times by the parser. - void setIsExprBody() { - flags_ |= EXPR_BODY; - } - void setArrow() { setKind(Arrow); } @@ -314,7 +306,8 @@ class JSFunction : public js::NativeObject nonLazyScript()->setAsyncKind(asyncKind); } - bool getUnresolvedLength(JSContext* cx, js::MutableHandleValue v); + static bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun, + js::MutableHandleValue v); JSAtom* getUnresolvedName(JSContext* cx); @@ -419,16 +412,15 @@ class JSFunction : public js::NativeObject // // - For functions known to have a JSScript, nonLazyScript() will get it. - JSScript* getOrCreateScript(JSContext* cx) { - MOZ_ASSERT(isInterpreted()); + static JSScript* getOrCreateScript(JSContext* cx, js::HandleFunction fun) { + MOZ_ASSERT(fun->isInterpreted()); MOZ_ASSERT(cx); - if (isInterpretedLazy()) { - JS::RootedFunction self(cx, this); - if (!createScriptForLazilyInterpretedFunction(cx, self)) + if (fun->isInterpretedLazy()) { + if (!createScriptForLazilyInterpretedFunction(cx, fun)) return nullptr; - return self->nonLazyScript(); + return fun->nonLazyScript(); } - return nonLazyScript(); + return fun->nonLazyScript(); } JSScript* existingScriptNonDelazifying() const { @@ -486,7 +478,7 @@ class JSFunction : public js::NativeObject return u.i.s.script_; } - bool getLength(JSContext* cx, uint16_t* length); + static bool getLength(JSContext* cx, js::HandleFunction fun, uint16_t* length); js::LazyScript* lazyScript() const { MOZ_ASSERT(isInterpretedLazy() && u.i.s.lazy_); @@ -593,13 +585,17 @@ class JSFunction : public js::NativeObject return offsetof(JSFunction, u.nativeOrScript); } + static unsigned offsetOfJitInfo() { + return offsetof(JSFunction, u.n.jitinfo); + } + inline void trace(JSTracer* trc); /* Bound function accessors. */ JSObject* getBoundFunctionTarget() const; const js::Value& getBoundFunctionThis() const; - const js::Value& getBoundFunctionArgument(JSContext* cx, unsigned which) const; + const js::Value& getBoundFunctionArgument(unsigned which) const; size_t getBoundFunctionArgumentCount() const; private: @@ -802,10 +798,6 @@ CloneFunctionAndScript(JSContext* cx, HandleFunction fun, HandleObject parent, gc::AllocKind kind = gc::AllocKind::FUNCTION, HandleObject proto = nullptr); -extern bool -FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart, - size_t* bodyEnd); - } // namespace js inline js::FunctionExtended* diff --git a/js/src/jsfuninlines.h b/js/src/jsfuninlines.h index e134def61..13fe51e26 100644 --- a/js/src/jsfuninlines.h +++ b/js/src/jsfuninlines.h @@ -88,7 +88,7 @@ CloneFunctionObjectIfNotSingleton(JSContext* cx, HandleFunction fun, HandleObjec if (CanReuseScriptForClone(cx->compartment(), fun, parent)) return CloneFunctionReuseScript(cx, fun, parent, kind, newKind, proto); - RootedScript script(cx, fun->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script) return nullptr; RootedScope enclosingScope(cx, script->enclosingScope()); diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 004c7fc0d..749e15d27 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -654,7 +654,7 @@ VectorToKeyIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVecto { MOZ_ASSERT(!(flags & JSITER_FOREACH)); - if (obj->isSingleton() && !obj->setIteratedSingleton(cx)) + if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj)) return false; MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED); @@ -698,7 +698,7 @@ VectorToValueIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVec { MOZ_ASSERT(flags & JSITER_FOREACH); - if (obj->isSingleton() && !obj->setIteratedSingleton(cx)) + if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj)) return false; MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED); @@ -921,7 +921,7 @@ js::CreateItrResultObject(JSContext* cx, HandleValue value, bool done) // FIXME: We can cache the iterator result object shape somewhere. AssertHeapIsIdle(cx); - RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global())); if (!proto) return nullptr; @@ -1497,7 +1497,7 @@ GlobalObject::initIteratorProto(JSContext* cx, Handle<GlobalObject*> global) if (global->getReservedSlot(ITERATOR_PROTO).isObject()) return true; - RootedObject proto(cx, global->createBlankPrototype<PlainObject>(cx)); + RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global)); if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, iterator_proto_methods)) return false; @@ -1516,7 +1516,8 @@ GlobalObject::initArrayIteratorProto(JSContext* cx, Handle<GlobalObject*> global return false; const Class* cls = &ArrayIteratorPrototypeClass; - RootedObject proto(cx, global->createBlankPrototypeInheriting(cx, cls, iteratorProto)); + RootedObject proto(cx, GlobalObject::createBlankPrototypeInheriting(cx, global, cls, + iteratorProto)); if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, array_iterator_methods) || !DefineToStringTag(cx, proto, cx->names().ArrayIterator)) @@ -1539,7 +1540,8 @@ GlobalObject::initStringIteratorProto(JSContext* cx, Handle<GlobalObject*> globa return false; const Class* cls = &StringIteratorPrototypeClass; - RootedObject proto(cx, global->createBlankPrototypeInheriting(cx, cls, iteratorProto)); + RootedObject proto(cx, GlobalObject::createBlankPrototypeInheriting(cx, global, cls, + iteratorProto)); if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, string_iterator_methods) || !DefineToStringTag(cx, proto, cx->names().StringIterator)) @@ -1560,7 +1562,8 @@ js::InitLegacyIteratorClass(JSContext* cx, HandleObject obj) return &global->getPrototype(JSProto_Iterator).toObject(); RootedObject iteratorProto(cx); - iteratorProto = global->createBlankPrototype(cx, &PropertyIteratorObject::class_); + iteratorProto = GlobalObject::createBlankPrototype(cx, global, + &PropertyIteratorObject::class_); if (!iteratorProto) return nullptr; @@ -1572,7 +1575,7 @@ js::InitLegacyIteratorClass(JSContext* cx, HandleObject obj) ni->init(nullptr, nullptr, 0 /* flags */, 0, 0); Rooted<JSFunction*> ctor(cx); - ctor = global->createConstructor(cx, IteratorConstructor, cx->names().Iterator, 2); + ctor = GlobalObject::createConstructor(cx, IteratorConstructor, cx->names().Iterator, 2); if (!ctor) return nullptr; if (!LinkConstructorAndPrototype(cx, ctor, iteratorProto)) @@ -1593,7 +1596,8 @@ js::InitStopIterationClass(JSContext* cx, HandleObject obj) { Handle<GlobalObject*> global = obj.as<GlobalObject>(); if (!global->getPrototype(JSProto_StopIteration).isObject()) { - RootedObject proto(cx, global->createBlankPrototype(cx, &StopIterationObject::class_)); + RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global, + &StopIterationObject::class_)); if (!proto || !FreezeObject(cx, proto)) return nullptr; diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index 08fbe048c..78a231003 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -1417,7 +1417,8 @@ static const JSFunctionSpec math_static_methods[] = { JSObject* js::InitMathClass(JSContext* cx, HandleObject obj) { - RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx)); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; RootedObject Math(cx, NewObjectWithGivenProto(cx, &MathClass, proto, SingletonObject)); diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 28ed15159..bde1f918e 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -1005,15 +1005,16 @@ js::InitNumberClass(JSContext* cx, HandleObject obj) /* XXX must do at least once per new thread, so do it per JSContext... */ FIX_FPU(); - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); - RootedObject numberProto(cx, global->createBlankPrototype(cx, &NumberObject::class_)); + RootedObject numberProto(cx, GlobalObject::createBlankPrototype(cx, global, + &NumberObject::class_)); if (!numberProto) return nullptr; numberProto->as<NumberObject>().setPrimitiveValue(0); RootedFunction ctor(cx); - ctor = global->createConstructor(cx, Number, cx->names().Number, 1); + ctor = GlobalObject::createConstructor(cx, Number, cx->names().Number, 1); if (!ctor) return nullptr; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 2364f707e..6f9596924 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -471,7 +471,7 @@ js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level) // Steps 8-9, loosely interpreted. if (obj->isNative() && !obj->as<NativeObject>().inDictionaryMode() && - !obj->is<TypedArrayObject>()) + !obj->is<TypedArrayObject>() && !obj->is<MappedArgumentsObject>()) { HandleNativeObject nobj = obj.as<NativeObject>(); @@ -884,7 +884,7 @@ CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group, if (newKind == SingletonObject) { Rooted<TaggedProto> proto(cx, TaggedProto(templateObject->staticPrototype())); - if (!res->splicePrototype(cx, &PlainObject::class_, proto)) + if (!JSObject::splicePrototype(cx, res, &PlainObject::class_, proto)) return nullptr; } else { res->setGroup(group); @@ -952,7 +952,7 @@ js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObj } if (res) { - JSScript* script = callee->as<JSFunction>().getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, callee.as<JSFunction>()); if (!script) return nullptr; TypeScript::SetThis(cx, script, TypeSet::ObjectType(res)); @@ -1430,40 +1430,41 @@ js::XDRObjectLiteral(XDRState<XDR_ENCODE>* xdr, MutableHandleObject obj); template bool js::XDRObjectLiteral(XDRState<XDR_DECODE>* xdr, MutableHandleObject obj); -bool -NativeObject::fillInAfterSwap(JSContext* cx, const Vector<Value>& values, void* priv) +/* static */ bool +NativeObject::fillInAfterSwap(JSContext* cx, HandleNativeObject obj, + const Vector<Value>& values, void* priv) { // This object has just been swapped with some other object, and its shape // no longer reflects its allocated size. Correct this information and // fill the slots in with the specified values. - MOZ_ASSERT(slotSpan() == values.length()); + MOZ_ASSERT(obj->slotSpan() == values.length()); // Make sure the shape's numFixedSlots() is correct. - size_t nfixed = gc::GetGCKindSlots(asTenured().getAllocKind(), getClass()); - if (nfixed != shape_->numFixedSlots()) { - if (!generateOwnShape(cx)) + size_t nfixed = gc::GetGCKindSlots(obj->asTenured().getAllocKind(), obj->getClass()); + if (nfixed != obj->shape_->numFixedSlots()) { + if (!NativeObject::generateOwnShape(cx, obj)) return false; - shape_->setNumFixedSlots(nfixed); + obj->shape_->setNumFixedSlots(nfixed); } - if (hasPrivate()) - setPrivate(priv); + if (obj->hasPrivate()) + obj->setPrivate(priv); else MOZ_ASSERT(!priv); - if (slots_) { - js_free(slots_); - slots_ = nullptr; + if (obj->slots_) { + js_free(obj->slots_); + obj->slots_ = nullptr; } - if (size_t ndynamic = dynamicSlotsCount(nfixed, values.length(), getClass())) { - slots_ = cx->zone()->pod_malloc<HeapSlot>(ndynamic); - if (!slots_) + if (size_t ndynamic = dynamicSlotsCount(nfixed, values.length(), obj->getClass())) { + obj->slots_ = cx->zone()->pod_malloc<HeapSlot>(ndynamic); + if (!obj->slots_) return false; - Debug_SetSlotRangeToCrashOnTouch(slots_, ndynamic); + Debug_SetSlotRangeToCrashOnTouch(obj->slots_, ndynamic); } - initSlotRange(0, values.begin(), values.length()); + obj->initSlotRange(0, values.begin(), values.length()); return true; } @@ -1489,9 +1490,9 @@ JSObject::swap(JSContext* cx, HandleObject a, HandleObject b) AutoCompartment ac(cx, a); - if (!a->getGroup(cx)) + if (!JSObject::getGroup(cx, a)) oomUnsafe.crash("JSObject::swap"); - if (!b->getGroup(cx)) + if (!JSObject::getGroup(cx, b)) oomUnsafe.crash("JSObject::swap"); /* @@ -1573,10 +1574,14 @@ JSObject::swap(JSContext* cx, HandleObject a, HandleObject b) a->fixDictionaryShapeAfterSwap(); b->fixDictionaryShapeAfterSwap(); - if (na && !b->as<NativeObject>().fillInAfterSwap(cx, avals, apriv)) - oomUnsafe.crash("fillInAfterSwap"); - if (nb && !a->as<NativeObject>().fillInAfterSwap(cx, bvals, bpriv)) - oomUnsafe.crash("fillInAfterSwap"); + if (na) { + if (!NativeObject::fillInAfterSwap(cx, b.as<NativeObject>(), avals, apriv)) + oomUnsafe.crash("fillInAfterSwap"); + } + if (nb) { + if (!NativeObject::fillInAfterSwap(cx, a.as<NativeObject>(), bvals, bpriv)) + oomUnsafe.crash("fillInAfterSwap"); + } } // Swapping the contents of two objects invalidates type sets which contain @@ -1722,7 +1727,7 @@ DefineConstructorAndPrototype(JSContext* cx, HandleObject obj, JSProtoKey key, H /* Bootstrap Function.prototype (see also JS_InitStandardClasses). */ Rooted<TaggedProto> tagged(cx, TaggedProto(proto)); - if (ctor->getClass() == clasp && !ctor->splicePrototype(cx, clasp, tagged)) + if (ctor->getClass() == clasp && !JSObject::splicePrototype(cx, ctor, clasp, tagged)) goto bad; } @@ -1839,10 +1844,10 @@ js::SetClassAndProto(JSContext* cx, HandleObject obj, // We always generate a new shape if the object is a singleton, // regardless of the uncacheable-proto flag. ICs may rely on // this. - if (!oldproto->as<NativeObject>().generateOwnShape(cx)) + if (!NativeObject::generateOwnShape(cx, oldproto.as<NativeObject>())) return false; } else { - if (!oldproto->setUncacheableProto(cx)) + if (!JSObject::setUncacheableProto(cx, oldproto)) return false; } if (!obj->isDelegate()) { @@ -1854,15 +1859,18 @@ js::SetClassAndProto(JSContext* cx, HandleObject obj, oldproto = oldproto->staticPrototype(); } - if (proto.isObject() && !proto.toObject()->setDelegate(cx)) - return false; + if (proto.isObject()) { + RootedObject protoObj(cx, proto.toObject()); + if (!JSObject::setDelegate(cx, protoObj)) + return false; + } if (obj->isSingleton()) { /* * Just splice the prototype, but mark the properties as unknown for * consistent behavior. */ - if (!obj->splicePrototype(cx, clasp, proto)) + if (!JSObject::splicePrototype(cx, obj, clasp, proto)) return false; MarkObjectGroupUnknownProperties(cx, obj->group()); return true; @@ -1982,7 +1990,8 @@ js::GetObjectFromIncumbentGlobal(JSContext* cx, MutableHandleObject obj) { AutoCompartment ac(cx, globalObj); - obj.set(globalObj->as<GlobalObject>().getOrCreateObjectPrototype(cx)); + Handle<GlobalObject*> global = globalObj.as<GlobalObject>(); + obj.set(GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!obj) return false; } @@ -2195,7 +2204,8 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e // environments. if (env->is<DebugEnvironmentProxy>()) { RootedValue v(cx); - if (!env->as<DebugEnvironmentProxy>().getMaybeSentinelValue(cx, id, &v)) + Rooted<DebugEnvironmentProxy*> envProxy(cx, &env->as<DebugEnvironmentProxy>()); + if (!DebugEnvironmentProxy::getMaybeSentinelValue(cx, envProxy, id, &v)) return false; isTDZ = IsUninitializedLexical(v); } else { @@ -2326,9 +2336,18 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** } static inline bool -NativeGetPureInline(NativeObject* pobj, Shape* shape, Value* vp) +NativeGetPureInline(NativeObject* pobj, jsid id, Shape* shape, Value* vp) { - /* Fail if we have a custom getter. */ + if (IsImplicitDenseOrTypedArrayElement(shape)) { + // For simplicity we ignore the TypedArray with string index case. + if (!JSID_IS_INT(id)) + return false; + + *vp = pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id)); + return true; + } + + // Fail if we have a custom getter. if (!shape->hasDefaultGetter()) return false; @@ -2355,13 +2374,13 @@ js::GetPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Value* vp) return true; } - return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), shape, vp); + return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, shape, vp); } static inline bool NativeGetGetterPureInline(Shape* shape, JSFunction** fp) { - if (shape->hasGetterObject()) { + if (!IsImplicitDenseOrTypedArrayElement(shape) && shape->hasGetterObject()) { if (shape->getterObject()->is<JSFunction>()) { *fp = &shape->getterObject()->as<JSFunction>(); return true; @@ -2442,7 +2461,7 @@ js::HasOwnDataPropertyPure(JSContext* cx, JSObject* obj, jsid id, bool* result) return true; } -bool +/* static */ bool JSObject::reportReadOnly(JSContext* cx, jsid id, unsigned report) { RootedValue val(cx, IdToValue(id)); @@ -2451,7 +2470,7 @@ JSObject::reportReadOnly(JSContext* cx, jsid id, unsigned report) nullptr, nullptr); } -bool +/* static */ bool JSObject::reportNotConfigurable(JSContext* cx, jsid id, unsigned report) { RootedValue val(cx, IdToValue(id)); @@ -2460,10 +2479,10 @@ JSObject::reportNotConfigurable(JSContext* cx, jsid id, unsigned report) nullptr, nullptr); } -bool -JSObject::reportNotExtensible(JSContext* cx, unsigned report) +/* static */ bool +JSObject::reportNotExtensible(JSContext* cx, HandleObject obj, unsigned report) { - RootedValue val(cx, ObjectValue(*this)); + RootedValue val(cx, ObjectValue(*obj)); return ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE, JSDVG_IGNORE_STACK, val, nullptr, nullptr, nullptr); @@ -2535,7 +2554,7 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object // [[Prototype]] chain is always properly immutable, even in the presence // of lazy standard classes. if (obj->is<GlobalObject>()) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); if (!GlobalObject::ensureConstructor(cx, global, JSProto_Object)) return false; } @@ -2602,7 +2621,7 @@ js::PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result, I } } - if (!obj->setFlags(cx, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE)) { + if (!JSObject::setFlags(cx, obj, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE)) { // We failed to mark the object non-extensible, so reset the frozen // flag on the elements. MOZ_ASSERT(obj->nonProxyIsExtensible()); @@ -2742,7 +2761,7 @@ js::SetImmutablePrototype(ExclusiveContext* cx, HandleObject obj, bool* succeede return Proxy::setImmutablePrototype(cx->asJSContext(), obj, succeeded); } - if (!obj->setFlags(cx, BaseShape::IMMUTABLE_PROTOTYPE)) + if (!JSObject::setFlags(cx, obj, BaseShape::IMMUTABLE_PROTOTYPE)) return false; *succeeded = true; return true; @@ -2852,24 +2871,6 @@ js::GetObjectClassName(JSContext* cx, HandleObject obj) /* * */ -bool -js::HasDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp) -{ - if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) { - *vp = obj->getDenseElement(JSID_TO_INT(id)); - return true; - } - - if (Shape* shape = obj->lookup(cx, id)) { - if (shape->hasDefaultGetter() && shape->hasSlot()) { - *vp = obj->getSlot(shape->slot()); - return true; - } - } - - return false; -} - extern bool PropertySpecNameToId(JSContext* cx, const char* name, MutableHandleId id, js::PinningBehavior pin = js::DoNotPinAtom); @@ -2985,7 +2986,7 @@ JS::OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType hint, MutableHan /* Optimize (new String(...)).toString(). */ if (clasp == &StringObject::class_) { StringObject* nobj = &obj->as<StringObject>(); - if (ClassMethodIsNative(cx, nobj, &StringObject::class_, id, str_toString)) { + if (HasNativeMethodPure(nobj, cx->names().toString, str_toString, cx)) { vp.setString(nobj->unbox()); return true; } @@ -3007,7 +3008,7 @@ JS::OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType hint, MutableHan /* Optimize new String(...).valueOf(). */ if (clasp == &StringObject::class_) { StringObject* nobj = &obj->as<StringObject>(); - if (ClassMethodIsNative(cx, nobj, &StringObject::class_, id, str_toString)) { + if (HasNativeMethodPure(nobj, cx->names().valueOf, str_toString, cx)) { vp.setString(nobj->unbox()); return true; } @@ -3016,7 +3017,7 @@ JS::OrdinaryToPrimitive(JSContext* cx, HandleObject obj, JSType hint, MutableHan /* Optimize new Number(...).valueOf(). */ if (clasp == &NumberObject::class_) { NumberObject* nobj = &obj->as<NumberObject>(); - if (ClassMethodIsNative(cx, nobj, &NumberObject::class_, id, num_valueOf)) { + if (HasNativeMethodPure(nobj, cx->names().valueOf, num_valueOf, cx)) { vp.setNumber(nobj->unbox()); return true; } @@ -3858,10 +3859,10 @@ displayAtomFromObjectGroup(ObjectGroup& group) return script->function()->displayAtom(); } -bool -JSObject::constructorDisplayAtom(JSContext* cx, js::MutableHandleAtom name) +/* static */ bool +JSObject::constructorDisplayAtom(JSContext* cx, js::HandleObject obj, js::MutableHandleAtom name) { - ObjectGroup *g = getGroup(cx); + ObjectGroup *g = JSObject::getGroup(cx, obj); if (!g) return false; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index af79131af..db2c22b76 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -200,8 +200,8 @@ class JSObject : public js::gc::Cell GENERATE_SHAPE }; - bool setFlags(js::ExclusiveContext* cx, js::BaseShape::Flag flags, - GenerateShape generateShape = GENERATE_NONE); + static bool setFlags(js::ExclusiveContext* cx, JS::HandleObject obj, js::BaseShape::Flag flags, + GenerateShape generateShape = GENERATE_NONE); inline bool hasAllFlags(js::BaseShape::Flag flags) const; /* @@ -214,16 +214,16 @@ class JSObject : public js::gc::Cell * (see Purge{Scope,Proto}Chain in jsobj.cpp). */ inline bool isDelegate() const; - bool setDelegate(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE); + static bool setDelegate(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::DELEGATE, GENERATE_SHAPE); } inline bool isBoundFunction() const; inline bool hasSpecialEquality() const; inline bool watched() const; - bool setWatched(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::WATCHED, GENERATE_SHAPE); + static bool setWatched(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::WATCHED, GENERATE_SHAPE); } // A "qualified" varobj is the object on which "qualified" variable @@ -247,8 +247,8 @@ class JSObject : public js::gc::Cell // (e.g., Gecko and XPConnect), as they often wish to run scripts under a // scope that captures var bindings. inline bool isQualifiedVarObj() const; - bool setQualifiedVarObj(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::QUALIFIED_VAROBJ); + static bool setQualifiedVarObj(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::QUALIFIED_VAROBJ); } // An "unqualified" varobj is the object on which "unqualified" @@ -262,11 +262,11 @@ class JSObject : public js::gc::Cell // generate a new shape when their prototype changes, regardless of this // hasUncacheableProto flag. inline bool hasUncacheableProto() const; - bool setUncacheableProto(js::ExclusiveContext* cx) { - MOZ_ASSERT(hasStaticPrototype(), + static bool setUncacheableProto(js::ExclusiveContext* cx, JS::HandleObject obj) { + MOZ_ASSERT(obj->hasStaticPrototype(), "uncacheability as a concept is only applicable to static " "(not dynamically-computed) prototypes"); - return setFlags(cx, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE); + return setFlags(cx, obj, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE); } /* @@ -274,8 +274,8 @@ class JSObject : public js::gc::Cell * PropertyTree::MAX_HEIGHT. */ inline bool hadElementsAccess() const; - bool setHadElementsAccess(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::HAD_ELEMENTS_ACCESS); + static bool setHadElementsAccess(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::HAD_ELEMENTS_ACCESS); } /* @@ -288,7 +288,8 @@ class JSObject : public js::gc::Cell * If this object was instantiated with `new Ctor`, return the constructor's * display atom. Otherwise, return nullptr. */ - bool constructorDisplayAtom(JSContext* cx, js::MutableHandleAtom name); + static bool constructorDisplayAtom(JSContext* cx, js::HandleObject obj, + js::MutableHandleAtom name); /* * The same as constructorDisplayAtom above, however if this object has a @@ -348,7 +349,7 @@ class JSObject : public js::gc::Cell // Change an existing object to have a singleton group. static bool changeToSingleton(JSContext* cx, js::HandleObject obj); - inline js::ObjectGroup* getGroup(JSContext* cx); + static inline js::ObjectGroup* getGroup(JSContext* cx, js::HandleObject obj); const js::GCPtrObjectGroup& groupFromGC() const { /* Direct field access for use by GC. */ @@ -420,8 +421,8 @@ class JSObject : public js::gc::Cell * is purged on GC. */ inline bool isIteratedSingleton() const; - bool setIteratedSingleton(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::ITERATED_SINGLETON); + static bool setIteratedSingleton(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::ITERATED_SINGLETON); } /* @@ -433,18 +434,19 @@ class JSObject : public js::gc::Cell // Mark an object as having its 'new' script information cleared. inline bool wasNewScriptCleared() const; - bool setNewScriptCleared(js::ExclusiveContext* cx) { - return setFlags(cx, js::BaseShape::NEW_SCRIPT_CLEARED); + static bool setNewScriptCleared(js::ExclusiveContext* cx, JS::HandleObject obj) { + return setFlags(cx, obj, js::BaseShape::NEW_SCRIPT_CLEARED); } /* Set a new prototype for an object with a singleton type. */ - bool splicePrototype(JSContext* cx, const js::Class* clasp, js::Handle<js::TaggedProto> proto); + static bool splicePrototype(JSContext* cx, js::HandleObject obj, const js::Class* clasp, + js::Handle<js::TaggedProto> proto); /* * For bootstrapping, whether to splice a prototype for Function.prototype * or the global object. */ - bool shouldSplicePrototype(JSContext* cx); + bool shouldSplicePrototype(); /* * Environment chains. @@ -518,8 +520,9 @@ class JSObject : public js::gc::Cell public: static bool reportReadOnly(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR); - bool reportNotConfigurable(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR); - bool reportNotExtensible(JSContext* cx, unsigned report = JSREPORT_ERROR); + static bool reportNotConfigurable(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR); + static bool reportNotExtensible(JSContext* cx, js::HandleObject obj, + unsigned report = JSREPORT_ERROR); static bool nonNativeSetProperty(JSContext* cx, js::HandleObject obj, js::HandleId id, js::HandleValue v, js::HandleValue receiver, diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index b1d817bca..c132ee6b2 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -117,17 +117,16 @@ JSObject::setSingleton(js::ExclusiveContext* cx, js::HandleObject obj) return true; } -inline js::ObjectGroup* -JSObject::getGroup(JSContext* cx) +/* static */ inline js::ObjectGroup* +JSObject::getGroup(JSContext* cx, js::HandleObject obj) { - MOZ_ASSERT(cx->compartment() == compartment()); - if (hasLazyGroup()) { - JS::RootedObject self(cx, this); - if (cx->compartment() != compartment()) + MOZ_ASSERT(cx->compartment() == obj->compartment()); + if (obj->hasLazyGroup()) { + if (cx->compartment() != obj->compartment()) MOZ_CRASH(); - return makeLazyGroup(cx, self); + return makeLazyGroup(cx, obj); } - return group_; + return obj->group_; } inline void @@ -557,48 +556,30 @@ IsNativeFunction(const js::Value& v, JSNative native) return IsFunctionObject(v, &fun) && fun->maybeNative() == native; } -/* - * When we have an object of a builtin class, we don't quite know what its - * valueOf/toString methods are, since these methods may have been overwritten - * or shadowed. However, we can still do better than the general case by - * hard-coding the necessary properties for us to find the native we expect. - * - * TODO: a per-thread shape-based cache would be faster and simpler. - */ +// Return whether looking up a method on 'obj' definitely resolves to the +// original specified native function. The method may conservatively return +// 'false' in the case of proxies or other non-native objects. static MOZ_ALWAYS_INLINE bool -ClassMethodIsNative(JSContext* cx, NativeObject* obj, const Class* clasp, jsid methodid, JSNative native) +HasNativeMethodPure(JSObject* obj, PropertyName* name, JSNative native, JSContext* cx) { - MOZ_ASSERT(obj->getClass() == clasp); - Value v; - if (!HasDataProperty(cx, obj, methodid, &v)) { - JSObject* proto = obj->staticPrototype(); - if (!proto || proto->getClass() != clasp || !HasDataProperty(cx, &proto->as<NativeObject>(), methodid, &v)) - return false; - } + if (!GetPropertyPure(cx, obj, NameToId(name), &v)) + return false; return IsNativeFunction(v, native); } -// Return whether looking up 'valueOf' on 'obj' definitely resolves to the -// original Object.prototype.valueOf. The method may conservatively return -// 'false' in the case of proxies or other non-native objects. +// Return whether 'obj' definitely has no @@toPrimitive method. static MOZ_ALWAYS_INLINE bool -HasObjectValueOf(JSObject* obj, JSContext* cx) +HasNoToPrimitiveMethodPure(JSObject* obj, JSContext* cx) { - if (obj->is<ProxyObject>() || !obj->isNative()) + jsid id = SYMBOL_TO_JSID(cx->wellKnownSymbols().toPrimitive); + JSObject* pobj; + Shape* shape; + if (!LookupPropertyPure(cx, obj, id, &pobj, &shape)) return false; - jsid valueOf = NameToId(cx->names().valueOf); - - Value v; - while (!HasDataProperty(cx, &obj->as<NativeObject>(), valueOf, &v)) { - obj = obj->staticPrototype(); - if (!obj || obj->is<ProxyObject>() || !obj->isNative()) - return false; - } - - return IsNativeFunction(v, obj_valueOf); + return !shape; } /* ES6 draft rev 28 (2014 Oct 14) 7.1.14 */ diff --git a/js/src/json.cpp b/js/src/json.cpp index 425a2f117..08382b97b 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -971,9 +971,9 @@ static const JSFunctionSpec json_static_methods[] = { JSObject* js::InitJSONClass(JSContext* cx, HandleObject obj) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); - RootedObject proto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; RootedObject JSON(cx, NewObjectWithGivenProto(cx, &JSONClass, proto, SingletonObject)); diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 6adb5401e..d1ae3cd5e 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -132,7 +132,8 @@ js::StackUses(JSScript* script, jsbytecode* pc) return 2 + GET_ARGC(pc) + 1; default: /* stack: fun, this, [argc arguments] */ - MOZ_ASSERT(op == JSOP_CALL || op == JSOP_EVAL || op == JSOP_CALLITER || + MOZ_ASSERT(op == JSOP_CALL || op == JSOP_CALL_IGNORES_RV || op == JSOP_EVAL || + op == JSOP_CALLITER || op == JSOP_STRICTEVAL || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY); return 2 + GET_ARGC(pc); } @@ -1363,6 +1364,7 @@ ExpressionDecompiler::decompilePC(jsbytecode* pc) case JSOP_NEWTARGET: return write("new.target"); case JSOP_CALL: + case JSOP_CALL_IGNORES_RV: case JSOP_CALLITER: case JSOP_FUNCALL: return decompilePCForStackOperand(pc, -int32_t(GET_ARGC(pc) + 2)) && @@ -1662,7 +1664,7 @@ DecompileArgumentFromStack(JSContext* cx, int formalIndex, char** res) /* Don't handle getters, setters or calls from fun.call/fun.apply. */ JSOp op = JSOp(*current); - if (op != JSOP_CALL && op != JSOP_NEW) + if (op != JSOP_CALL && op != JSOP_CALL_IGNORES_RV && op != JSOP_NEW) return true; if (static_cast<unsigned>(formalIndex) >= GET_ARGC(current)) @@ -1725,6 +1727,8 @@ js::CallResultEscapes(jsbytecode* pc) if (*pc == JSOP_CALL) pc += JSOP_CALL_LENGTH; + else if (*pc == JSOP_CALL_IGNORES_RV) + pc += JSOP_CALL_IGNORES_RV_LENGTH; else if (*pc == JSOP_SPREADCALL) pc += JSOP_SPREADCALL_LENGTH; else @@ -2214,6 +2218,7 @@ GenerateLcovInfo(JSContext* cx, JSCompartment* comp, GenericPrinter& out) return false; RootedScript script(cx); + RootedFunction fun(cx); do { script = queue.popCopy(); compCover.collectCodeCoverageInfo(comp, script->sourceObject(), script); @@ -2231,15 +2236,15 @@ GenerateLcovInfo(JSContext* cx, JSCompartment* comp, GenericPrinter& out) // Only continue on JSFunction objects. if (!obj->is<JSFunction>()) continue; - JSFunction& fun = obj->as<JSFunction>(); + fun = &obj->as<JSFunction>(); // Let's skip wasm for now. - if (!fun.isInterpreted()) + if (!fun->isInterpreted()) continue; // Queue the script in the list of script associated to the // current source. - JSScript* childScript = fun.getOrCreateScript(cx); + JSScript* childScript = JSFunction::getOrCreateScript(cx, fun); if (!childScript || !queue.append(childScript)) return false; } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 33ae56d6f..fc7438e3b 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -235,7 +235,8 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri { uint32_t begin = script->sourceStart(); uint32_t end = script->sourceEnd(); - uint32_t preludeStart = script->preludeStart(); + uint32_t toStringStart = script->toStringStart(); + uint32_t toStringEnd = script->toStringEnd(); uint32_t lineno = script->lineno(); uint32_t column = script->column(); @@ -243,7 +244,8 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri packedFields = lazy->packedFields(); MOZ_ASSERT(begin == lazy->begin()); MOZ_ASSERT(end == lazy->end()); - MOZ_ASSERT(preludeStart == lazy->preludeStart()); + MOZ_ASSERT(toStringStart == lazy->toStringStart()); + MOZ_ASSERT(toStringEnd == lazy->toStringEnd()); MOZ_ASSERT(lineno == lazy->lineno()); MOZ_ASSERT(column == lazy->column()); // We can assert we have no inner functions because we don't @@ -257,7 +259,12 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri if (mode == XDR_DECODE) { lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, script, - packedFields, begin, end, preludeStart, lineno, column)); + packedFields, begin, end, toStringStart, lineno, column)); + + if (!lazy) + return false; + + lazy->setToStringEnd(toStringEnd); // As opposed to XDRLazyScript, we need to restore the runtime bits // of the script, as we are trying to match the fact this function @@ -319,6 +326,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip IsStarGenerator, IsAsync, HasRest, + IsExprBody, OwnSource, ExplicitUseStrict, SelfHosted, @@ -436,6 +444,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip scriptBits |= (1 << IsAsync); if (script->hasRest()) scriptBits |= (1 << HasRest); + if (script->isExprBody()) + scriptBits |= (1 << IsExprBody); if (script->hasSingletons()) scriptBits |= (1 << HasSingleton); if (script->treatAsRunOnce()) @@ -519,7 +529,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip sourceObject = &enclosingScript->sourceObject()->as<ScriptSourceObject>(); } - script = JSScript::Create(cx, options, sourceObject, 0, 0, 0); + script = JSScript::Create(cx, options, sourceObject, 0, 0, 0, 0); if (!script) return false; @@ -589,6 +599,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip script->setAsyncKind(AsyncFunction); if (scriptBits & (1 << HasRest)) script->setHasRest(); + if (scriptBits & (1 << IsExprBody)) + script->setIsExprBody(); } JS_STATIC_ASSERT(sizeof(jsbytecode) == 1); @@ -602,7 +614,9 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip return false; if (!xdr->codeUint32(&script->sourceEnd_)) return false; - if (!xdr->codeUint32(&script->preludeStart_)) + if (!xdr->codeUint32(&script->toStringStart_)) + return false; + if (!xdr->codeUint32(&script->toStringEnd_)) return false; if (!xdr->codeUint32(&lineno) || @@ -934,7 +948,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript { uint32_t begin; uint32_t end; - uint32_t preludeStart; + uint32_t toStringStart; + uint32_t toStringEnd; uint32_t lineno; uint32_t column; uint64_t packedFields; @@ -948,14 +963,16 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript begin = lazy->begin(); end = lazy->end(); - preludeStart = lazy->preludeStart(); + toStringStart = lazy->toStringStart(); + toStringEnd = lazy->toStringEnd(); lineno = lazy->lineno(); column = lazy->column(); packedFields = lazy->packedFields(); } if (!xdr->codeUint32(&begin) || !xdr->codeUint32(&end) || - !xdr->codeUint32(&preludeStart) || + !xdr->codeUint32(&toStringStart) || + !xdr->codeUint32(&toStringEnd) || !xdr->codeUint32(&lineno) || !xdr->codeUint32(&column) || !xdr->codeUint64(&packedFields)) { @@ -964,9 +981,10 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope, HandleScript if (mode == XDR_DECODE) { lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, enclosingScript, - packedFields, begin, end, preludeStart, lineno, column)); + packedFields, begin, end, toStringStart, lineno, column)); if (!lazy) return false; + lazy->setToStringEnd(toStringEnd); fun->initLazyScript(lazy); } } @@ -1010,6 +1028,15 @@ JSScript::setSourceObject(JSObject* object) sourceObject_ = object; } +void +JSScript::setDefaultClassConstructorSpan(JSObject* sourceObject, uint32_t start, uint32_t end) +{ + MOZ_ASSERT(isDefaultClassConstructor()); + setSourceObject(sourceObject); + toStringStart_ = start; + toStringEnd_ = end; +} + js::ScriptSourceObject& JSScript::scriptSourceUnwrap() const { return UncheckedUnwrap(sourceObject())->as<ScriptSourceObject>(); @@ -1430,18 +1457,18 @@ JSScript::loadSource(JSContext* cx, ScriptSource* ss, bool* worked) return true; } -JSFlatString* -JSScript::sourceData(JSContext* cx) +/* static */ JSFlatString* +JSScript::sourceData(JSContext* cx, HandleScript script) { - MOZ_ASSERT(scriptSource()->hasSourceData()); - return scriptSource()->substring(cx, sourceStart(), sourceEnd()); + MOZ_ASSERT(script->scriptSource()->hasSourceData()); + return script->scriptSource()->substring(cx, script->sourceStart(), script->sourceEnd()); } -JSFlatString* -JSScript::sourceDataWithPrelude(JSContext* cx) +/* static */ JSFlatString* +JSScript::sourceDataForToString(JSContext* cx, HandleScript script) { - MOZ_ASSERT(scriptSource()->hasSourceData()); - return scriptSource()->substring(cx, preludeStart(), sourceEnd()); + MOZ_ASSERT(script->scriptSource()->hasSourceData()); + return script->scriptSource()->substring(cx, script->toStringStart(), script->toStringEnd()); } UncompressedSourceCache::AutoHoldEntry::AutoHoldEntry() @@ -2443,9 +2470,15 @@ JSScript::initCompartment(ExclusiveContext* cx) /* static */ JSScript* JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, HandleObject sourceObject, uint32_t bufStart, uint32_t bufEnd, - uint32_t preludeStart) + uint32_t toStringStart, uint32_t toStringEnd) { + // bufStart and bufEnd specify the range of characters parsed by the + // Parser to produce this script. toStringStart and toStringEnd specify + // the range of characters to be returned for Function.prototype.toString. MOZ_ASSERT(bufStart <= bufEnd); + MOZ_ASSERT(toStringStart <= toStringEnd); + MOZ_ASSERT(toStringStart <= bufStart); + MOZ_ASSERT(toStringEnd >= bufEnd); RootedScript script(cx, Allocate<JSScript>(cx)); if (!script) @@ -2465,7 +2498,8 @@ JSScript::Create(ExclusiveContext* cx, const ReadOnlyCompileOptions& options, script->setSourceObject(sourceObject); script->sourceStart_ = bufStart; script->sourceEnd_ = bufEnd; - script->preludeStart_ = preludeStart; + script->toStringStart_ = toStringStart; + script->toStringEnd_ = toStringEnd; return script; } @@ -2660,6 +2694,8 @@ JSScript::initFromFunctionBox(ExclusiveContext* cx, HandleScript script, script->setAsyncKind(funbox->asyncKind()); if (funbox->hasRest()) script->setHasRest(); + if (funbox->isExprBody()) + script->setIsExprBody(); PositionalFormalParameterIter fi(script); while (fi && !fi.closedOver()) @@ -3261,7 +3297,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst, } else { if (innerFun->isInterpretedLazy()) { AutoCompartment ac(cx, innerFun); - if (!innerFun->getOrCreateScript(cx)) + if (!JSFunction::getOrCreateScript(cx, innerFun)) return false; } @@ -3320,6 +3356,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst, dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor(); dst->isAsync_ = src->asyncKind() == AsyncFunction; dst->hasRest_ = src->hasRest_; + dst->isExprBody_ = src->isExprBody_; if (nconsts != 0) { GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector); @@ -3399,7 +3436,7 @@ CreateEmptyScriptForClone(JSContext* cx, HandleScript src) .setVersion(src->getVersion()); return JSScript::Create(cx, options, sourceObject, src->sourceStart(), src->sourceEnd(), - src->preludeStart()); + src->toStringStart(), src->toStringEnd()); } JSScript* @@ -3950,7 +3987,7 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot) LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column) + uint32_t toStringStart, uint32_t lineno, uint32_t column) : script_(nullptr), function_(fun), enclosingScope_(nullptr), @@ -3959,11 +3996,13 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields, packedFields_(packedFields), begin_(begin), end_(end), - preludeStart_(preludeStart), + toStringStart_(toStringStart), + toStringEnd_(end), lineno_(lineno), column_(column) { MOZ_ASSERT(begin <= end); + MOZ_ASSERT(toStringStart <= begin); } void @@ -4009,7 +4048,7 @@ LazyScript::maybeForwardedScriptSource() const /* static */ LazyScript* LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column) + uint32_t toStringStart, uint32_t lineno, uint32_t column) { union { PackedView p; @@ -4038,7 +4077,7 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, cx->compartment()->scheduleDelazificationForDebugger(); return new (res) LazyScript(fun, table.forget(), packed, begin, end, - preludeStart, lineno, column); + toStringStart, lineno, column); } /* static */ LazyScript* @@ -4047,7 +4086,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, Handle<GCVector<JSFunction*, 8>> innerFunctions, JSVersion version, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column) + uint32_t toStringStart, uint32_t lineno, uint32_t column) { union { PackedView p; @@ -4059,6 +4098,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, p.hasThisBinding = false; p.isAsync = false; p.hasRest = false; + p.isExprBody = false; p.numClosedOverBindings = closedOverBindings.length(); p.numInnerFunctions = innerFunctions.length(); p.generatorKindBits = GeneratorKindAsBits(NotGenerator); @@ -4070,7 +4110,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, p.isDerivedClassConstructor = false; p.needsHomeObject = false; - LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart, + LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart, lineno, column); if (!res) return nullptr; @@ -4092,7 +4132,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, HandleScript script, HandleScope enclosingScope, HandleScript enclosingScript, uint64_t packedFields, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column) + uint32_t toStringStart, uint32_t lineno, uint32_t column) { // Dummy atom which is not a valid property name. RootedAtom dummyAtom(cx, cx->names().comma); @@ -4101,7 +4141,7 @@ LazyScript::Create(ExclusiveContext* cx, HandleFunction fun, // holding this lazy script. HandleFunction dummyFun = fun; - LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, preludeStart, + LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart, lineno, column); if (!res) return nullptr; @@ -4287,7 +4327,7 @@ JSScript::AutoDelazify::holdScript(JS::HandleFunction fun) script_ = fun->nonLazyScript(); } else { JSAutoCompartment ac(cx_, fun); - script_ = fun->getOrCreateScript(cx_); + script_ = JSFunction::getOrCreateScript(cx_, fun); if (script_) { oldDoNotRelazify_ = script_->doNotRelazify_; script_->setDoNotRelazify(true); diff --git a/js/src/jsscript.h b/js/src/jsscript.h index bb8635581..85eb2938d 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -853,19 +853,36 @@ class JSScript : public js::gc::TenuredCell uint32_t bodyScopeIndex_; /* index into the scopes array of the body scope */ - // Range of characters in scriptSource which contains this script's source. - // each field points the following location. + // Range of characters in scriptSource which contains this script's + // source, that is, the range used by the Parser to produce this script. + // + // Most scripted functions have sourceStart_ == toStringStart_ and + // sourceEnd_ == toStringEnd_. However, for functions with extra + // qualifiers (e.g. generators, async) and for class constructors (which + // need to return the entire class source), their values differ. + // + // Each field points the following locations. // // function * f(a, b) { return a + b; } // ^ ^ ^ // | | | // | sourceStart_ sourceEnd_ - // | - // preludeStart_ + // | | + // toStringStart_ toStringEnd_ + // + // And, in the case of class constructors, an additional toStringEnd + // offset is used. // + // class C { constructor() { this.field = 42; } } + // ^ ^ ^ ^ + // | | | `---------` + // | sourceStart_ sourceEnd_ | + // | | + // toStringStart_ toStringEnd_ uint32_t sourceStart_; uint32_t sourceEnd_; - uint32_t preludeStart_; + uint32_t toStringStart_; + uint32_t toStringEnd_; // Number of times the script has been called or has had backedges taken. // When running in ion, also increased for any inlined scripts. Reset if @@ -1021,12 +1038,13 @@ class JSScript : public js::gc::TenuredCell bool isAsync_:1; bool hasRest_:1; + bool isExprBody_:1; // Add padding so JSScript is gc::Cell aligned. Make padding protected // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - uint32_t padding; + // Currently no padding is needed. #endif // @@ -1036,8 +1054,9 @@ class JSScript : public js::gc::TenuredCell public: static JSScript* Create(js::ExclusiveContext* cx, const JS::ReadOnlyCompileOptions& options, - js::HandleObject sourceObject, uint32_t sourceStart, - uint32_t sourceEnd, uint32_t preludeStart); + js::HandleObject sourceObject, + uint32_t sourceStart, uint32_t sourceEnd, + uint32_t toStringStart, uint32_t toStringEnd); void initCompartment(js::ExclusiveContext* cx); @@ -1184,8 +1203,12 @@ class JSScript : public js::gc::TenuredCell return sourceEnd_; } - size_t preludeStart() const { - return preludeStart_; + uint32_t toStringStart() const { + return toStringStart_; + } + + uint32_t toStringEnd() const { + return toStringEnd_; } bool noScriptRval() const { @@ -1329,6 +1352,13 @@ class JSScript : public js::gc::TenuredCell hasRest_ = true; } + bool isExprBody() const { + return isExprBody_; + } + void setIsExprBody() { + isExprBody_ = true; + } + void setNeedsHomeObject() { needsHomeObject_ = true; } @@ -1464,6 +1494,7 @@ class JSScript : public js::gc::TenuredCell bool isRelazifiable() const { return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ && !isGenerator() && !hasBaselineScript() && !hasAnyIonScript() && + !isDefaultClassConstructor() && !doNotRelazify_; } void setLazyScript(js::LazyScript* lazy) { @@ -1491,7 +1522,7 @@ class JSScript : public js::gc::TenuredCell * De-lazifies the canonical function. Must be called before entering code * that expects the function to be non-lazy. */ - inline void ensureNonLazyCanonicalFunction(JSContext* cx); + inline void ensureNonLazyCanonicalFunction(); js::ModuleObject* module() const { if (bodyScope()->is<js::ModuleScope>()) @@ -1510,8 +1541,8 @@ class JSScript : public js::gc::TenuredCell // directly, via lazy arguments or a rest parameter. bool mayReadFrameArgsDirectly(); - JSFlatString* sourceData(JSContext* cx); - JSFlatString* sourceDataWithPrelude(JSContext* cx); + static JSFlatString* sourceData(JSContext* cx, JS::HandleScript script); + static JSFlatString* sourceDataForToString(JSContext* cx, JS::HandleScript script); static bool loadSource(JSContext* cx, js::ScriptSource* ss, bool* worked); @@ -1526,6 +1557,8 @@ class JSScript : public js::gc::TenuredCell const char* filename() const { return scriptSource()->filename(); } const char* maybeForwardedFilename() const { return maybeForwardedScriptSource()->filename(); } + void setDefaultClassConstructorSpan(JSObject* sourceObject, uint32_t start, uint32_t end); + public: /* Return whether this script was compiled for 'eval' */ @@ -1931,12 +1964,11 @@ class LazyScript : public gc::TenuredCell // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - // uint32_t padding; - // Currently no padding is needed. + uint32_t padding; #endif private: - static const uint32_t NumClosedOverBindingsBits = 21; + static const uint32_t NumClosedOverBindingsBits = 20; static const uint32_t NumInnerFunctionsBits = 20; struct PackedView { @@ -1946,7 +1978,12 @@ class LazyScript : public gc::TenuredCell uint32_t shouldDeclareArguments : 1; uint32_t hasThisBinding : 1; uint32_t isAsync : 1; + uint32_t isExprBody : 1; + uint32_t numClosedOverBindings : NumClosedOverBindingsBits; + + // -- 32bit boundary -- + uint32_t numInnerFunctions : NumInnerFunctionsBits; uint32_t generatorKindBits : 2; @@ -1975,14 +2012,15 @@ class LazyScript : public gc::TenuredCell // See the comment in JSScript for the details. uint32_t begin_; uint32_t end_; - uint32_t preludeStart_; + uint32_t toStringStart_; + uint32_t toStringEnd_; // Line and column of |begin_| position, that is the position where we // start parsing. uint32_t lineno_; uint32_t column_; LazyScript(JSFunction* fun, void* table, uint64_t packedFields, - uint32_t begin, uint32_t end, uint32_t preludeStart, + uint32_t begin, uint32_t end, uint32_t toStringStart, uint32_t lineno, uint32_t column); // Create a LazyScript without initializing the closedOverBindings and the @@ -1990,7 +2028,7 @@ class LazyScript : public gc::TenuredCell // with valid atoms and functions. static LazyScript* CreateRaw(ExclusiveContext* cx, HandleFunction fun, uint64_t packedData, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column); + uint32_t toStringStart, uint32_t lineno, uint32_t column); public: static const uint32_t NumClosedOverBindingsLimit = 1 << NumClosedOverBindingsBits; @@ -2002,7 +2040,7 @@ class LazyScript : public gc::TenuredCell const frontend::AtomVector& closedOverBindings, Handle<GCVector<JSFunction*, 8>> innerFunctions, JSVersion version, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column); + uint32_t toStringStart, uint32_t lineno, uint32_t column); // Create a LazyScript and initialize the closedOverBindings and the // innerFunctions with dummy values to be replaced in a later initialization @@ -2017,11 +2055,11 @@ class LazyScript : public gc::TenuredCell HandleScript script, HandleScope enclosingScope, HandleScript enclosingScript, uint64_t packedData, uint32_t begin, uint32_t end, - uint32_t preludeStart, uint32_t lineno, uint32_t column); + uint32_t toStringStart, uint32_t lineno, uint32_t column); void initRuntimeFields(uint64_t packedFields); - inline JSFunction* functionDelazifying(JSContext* cx) const; + static inline JSFunction* functionDelazifying(JSContext* cx, Handle<LazyScript*>); JSFunction* functionNonDelazifying() const { return function_; } @@ -2104,6 +2142,13 @@ class LazyScript : public gc::TenuredCell p_.hasRest = true; } + bool isExprBody() const { + return p_.isExprBody; + } + void setIsExprBody() { + p_.isExprBody = true; + } + bool strict() const { return p_.strict; } @@ -2190,8 +2235,11 @@ class LazyScript : public gc::TenuredCell uint32_t end() const { return end_; } - uint32_t preludeStart() const { - return preludeStart_; + uint32_t toStringStart() const { + return toStringStart_; + } + uint32_t toStringEnd() const { + return toStringEnd_; } uint32_t lineno() const { return lineno_; @@ -2200,6 +2248,12 @@ class LazyScript : public gc::TenuredCell return column_; } + void setToStringEnd(uint32_t toStringEnd) { + MOZ_ASSERT(toStringStart_ <= toStringEnd); + MOZ_ASSERT(toStringEnd_ >= end_); + toStringEnd_ = toStringEnd; + } + bool hasUncompiledEnclosingScript() const; friend class GCMarker; diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index da23804ac..e1052111b 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -74,13 +74,13 @@ void SetFrameArgumentsObject(JSContext* cx, AbstractFramePtr frame, HandleScript script, JSObject* argsobj); -inline JSFunction* -LazyScript::functionDelazifying(JSContext* cx) const +/* static */ inline JSFunction* +LazyScript::functionDelazifying(JSContext* cx, Handle<LazyScript*> script) { - Rooted<const LazyScript*> self(cx, this); - if (self->function_ && !self->function_->getOrCreateScript(cx)) + RootedFunction fun(cx, script->function_); + if (script->function_ && !JSFunction::getOrCreateScript(cx, fun)) return nullptr; - return self->function_; + return script->function_; } } // namespace js @@ -100,7 +100,7 @@ JSScript::functionDelazifying() const } inline void -JSScript::ensureNonLazyCanonicalFunction(JSContext* cx) +JSScript::ensureNonLazyCanonicalFunction() { // Infallibly delazify the canonical script. JSFunction* fun = function(); diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index d7db5129d..74f61b87d 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -461,9 +461,13 @@ ToStringForStringFunction(JSContext* cx, HandleValue thisv) RootedObject obj(cx, &thisv.toObject()); if (obj->is<StringObject>()) { StringObject* nobj = &obj->as<StringObject>(); - Rooted<jsid> id(cx, NameToId(cx->names().toString)); - if (ClassMethodIsNative(cx, nobj, &StringObject::class_, id, str_toString)) + // We have to make sure that the ToPrimitive call from ToString + // would be unobservable. + if (HasNoToPrimitiveMethodPure(nobj, cx) && + HasNativeMethodPure(nobj, cx->names().toString, str_toString, cx)) + { return nobj->unbox(); + } } } else if (thisv.isNullOrUndefined()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO, @@ -2901,8 +2905,8 @@ StringObject::assignInitialShape(ExclusiveContext* cx, Handle<StringObject*> obj { MOZ_ASSERT(obj->empty()); - return obj->addDataProperty(cx, cx->names().length, LENGTH_SLOT, - JSPROP_PERMANENT | JSPROP_READONLY); + return NativeObject::addDataProperty(cx, obj, cx->names().length, LENGTH_SLOT, + JSPROP_PERMANENT | JSPROP_READONLY); } JSObject* @@ -2910,17 +2914,20 @@ js::InitStringClass(JSContext* cx, HandleObject obj) { MOZ_ASSERT(obj->isNative()); - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); Rooted<JSString*> empty(cx, cx->runtime()->emptyString); - RootedObject proto(cx, global->createBlankPrototype(cx, &StringObject::class_)); - if (!proto || !proto->as<StringObject>().init(cx, empty)) + RootedObject proto(cx, GlobalObject::createBlankPrototype(cx, global, &StringObject::class_)); + if (!proto) + return nullptr; + Handle<StringObject*> protoObj = proto.as<StringObject>(); + if (!StringObject::init(cx, protoObj, empty)) return nullptr; /* Now create the String function. */ RootedFunction ctor(cx); - ctor = global->createConstructor(cx, StringConstructor, cx->names().String, 1, - AllocKind::FUNCTION, &jit::JitInfo_String); + ctor = GlobalObject::createConstructor(cx, StringConstructor, cx->names().String, 1, + AllocKind::FUNCTION, &jit::JitInfo_String); if (!ctor) return nullptr; diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index e37323555..34479a990 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -64,7 +64,7 @@ WatchpointMap::watch(JSContext* cx, HandleObject obj, HandleId id, { MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id)); - if (!obj->setWatched(cx)) + if (!JSObject::setWatched(cx, obj)) return false; Watchpoint w(handler, closure, false); diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 84ebe2732..5f3704e32 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -136,7 +136,7 @@ class JS_FRIEND_API(Wrapper) : public BaseProxyHandler static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler, const WrapperOptions& options = WrapperOptions()); - static JSObject* Renew(JSContext* cx, JSObject* existing, JSObject* obj, const Wrapper* handler); + static JSObject* Renew(JSObject* existing, JSObject* obj, const Wrapper* handler); static const Wrapper* wrapperHandler(JSObject* wrapper); diff --git a/js/src/moz.build b/js/src/moz.build index eb30866c8..a0f074d1c 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -619,11 +619,11 @@ else: 'perf/pm_stub.cpp' ] -GENERATED_FILES += ['jsautokw.h'] -jsautokw = GENERATED_FILES['jsautokw.h'] -jsautokw.script = 'jsautokw.py' -jsautokw.inputs += [ - 'vm/Keywords.h' +GENERATED_FILES += ['frontend/ReservedWordsGenerated.h'] +ReservedWordsGenerated = GENERATED_FILES['frontend/ReservedWordsGenerated.h'] +ReservedWordsGenerated.script = 'frontend/GenerateReservedWords.py' +ReservedWordsGenerated.inputs += [ + 'frontend/ReservedWords.h' ] # JavaScript must be built shared, even for static builds, as it is used by diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index 2a6cb5400..246639956 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -89,7 +89,7 @@ CrossCompartmentWrapper::getPrototype(JSContext* cx, HandleObject wrapper, if (!GetPrototype(cx, wrapped, protop)) return false; if (protop) { - if (!protop->setDelegate(cx)) + if (!JSObject::setDelegate(cx, protop)) return false; } } @@ -122,7 +122,7 @@ CrossCompartmentWrapper::getPrototypeIfOrdinary(JSContext* cx, HandleObject wrap return true; if (protop) { - if (!protop->setDelegate(cx)) + if (!JSObject::setDelegate(cx, protop)) return false; } } diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index b43fd02d2..2c1cffb77 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -774,7 +774,7 @@ js::NewProxyObject(JSContext* cx, const BaseProxyHandler* handler, HandleValue p } void -ProxyObject::renew(JSContext* cx, const BaseProxyHandler* handler, const Value& priv) +ProxyObject::renew(const BaseProxyHandler* handler, const Value& priv) { MOZ_ASSERT(!IsInsideNursery(this)); MOZ_ASSERT_IF(IsCrossCompartmentWrapper(this), IsDeadProxyObject(this)); @@ -796,9 +796,9 @@ js::InitProxyClass(JSContext* cx, HandleObject obj) JS_FS_END }; - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); RootedFunction ctor(cx); - ctor = global->createConstructor(cx, proxy, cx->names().Proxy, 2); + ctor = GlobalObject::createConstructor(cx, proxy, cx->names().Proxy, 2); if (!ctor) return nullptr; diff --git a/js/src/proxy/Wrapper.cpp b/js/src/proxy/Wrapper.cpp index 43d559ff3..67f437262 100644 --- a/js/src/proxy/Wrapper.cpp +++ b/js/src/proxy/Wrapper.cpp @@ -312,9 +312,9 @@ Wrapper::New(JSContext* cx, JSObject* obj, const Wrapper* handler, } JSObject* -Wrapper::Renew(JSContext* cx, JSObject* existing, JSObject* obj, const Wrapper* handler) +Wrapper::Renew(JSObject* existing, JSObject* obj, const Wrapper* handler) { - existing->as<ProxyObject>().renew(cx, handler, ObjectValue(*obj)); + existing->as<ProxyObject>().renew(handler, ObjectValue(*obj)); return existing; } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 617b5e902..51cd11fe8 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2310,7 +2310,7 @@ ValueToScript(JSContext* cx, HandleValue v, JSFunction** funp = nullptr) return nullptr; } - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return nullptr; @@ -2550,6 +2550,14 @@ SrcNotes(JSContext* cx, HandleScript script, Sprinter* sp) return false; break; + case SRC_CLASS_SPAN: { + unsigned startOffset = GetSrcNoteOffset(sn, 0); + unsigned endOffset = GetSrcNoteOffset(sn, 1); + if (!sp->jsprintf(" %u %u", startOffset, endOffset)) + return false; + break; + } + default: MOZ_ASSERT_UNREACHABLE("unrecognized srcnote"); } @@ -2689,7 +2697,7 @@ DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun, if (sp->put(" CONSTRUCTOR") < 0) return false; } - if (fun->isExprBody()) { + if (script->isExprBody()) { if (sp->put(" EXPRESSION_CLOSURE") < 0) return false; } @@ -2726,7 +2734,7 @@ DisassembleScript(JSContext* cx, HandleScript script, HandleFunction fun, RootedFunction fun(cx, &obj->as<JSFunction>()); if (fun->isInterpreted()) { - RootedScript script(cx, fun->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (script) { if (!DisassembleScript(cx, script, fun, lines, recursive, sourceNotes, sp)) return false; @@ -3488,8 +3496,8 @@ GroupOf(JSContext* cx, unsigned argc, JS::Value* vp) JS_ReportErrorASCII(cx, "groupOf: object expected"); return false; } - JSObject* obj = &args[0].toObject(); - ObjectGroup* group = obj->getGroup(cx); + RootedObject obj(cx, &args[0].toObject()); + ObjectGroup* group = JSObject::getGroup(cx, obj); if (!group) return false; args.rval().set(JS_NumberValue(double(uintptr_t(group) >> 3))); @@ -5403,7 +5411,7 @@ DumpScopeChain(JSContext* cx, unsigned argc, Value* vp) ReportUsageErrorASCII(cx, callee, "Argument must be an interpreted function"); return false; } - script = fun->getOrCreateScript(cx); + script = JSFunction::getOrCreateScript(cx, fun); } else { script = obj->as<ModuleObject>().script(); } @@ -6419,6 +6427,14 @@ CreateLastWarningObject(JSContext* cx, JSErrorReport* report) if (!DefineProperty(cx, warningObj, cx->names().columnNumber, columnVal)) return false; + RootedObject notesArray(cx, CreateErrorNotesArray(cx, report)); + if (!notesArray) + return false; + + RootedValue notesArrayVal(cx, ObjectValue(*notesArray)); + if (!DefineProperty(cx, warningObj, cx->names().notes, notesArrayVal)) + return false; + GetShellContext(cx)->lastWarning.setObject(*warningObj); return true; } diff --git a/js/src/tests/ecma_2017/AsyncFunctions/await-error.js b/js/src/tests/ecma_2017/AsyncFunctions/await-error.js new file mode 100644 index 000000000..1f40ea8a0 --- /dev/null +++ b/js/src/tests/ecma_2017/AsyncFunctions/await-error.js @@ -0,0 +1,16 @@ +var BUGNUMBER = 1317153; +var summary = "await outside of async function should provide better error"; + +print(BUGNUMBER + ": " + summary); + +let caught = false; +try { + eval("await 10"); +} catch(e) { + assertEq(e.message, "await is only valid in async functions"); + caught = true; +} +assertEq(caught, true); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_2017/AsyncFunctions/await-in-arrow-parameters.js b/js/src/tests/ecma_2017/AsyncFunctions/await-in-arrow-parameters.js new file mode 100644 index 000000000..ebb4ea9da --- /dev/null +++ b/js/src/tests/ecma_2017/AsyncFunctions/await-in-arrow-parameters.js @@ -0,0 +1,94 @@ +var ieval = eval; +var AsyncFunction = async function(){}.constructor; + +var functionContext = { + Function: { + constructor: Function, + toSourceBody: code => `function f() { ${code} }`, + toSourceParameter: code => `function f(x = ${code}) { }`, + }, + AsyncFunction: { + constructor: AsyncFunction, + toSourceBody: code => `async function f() { ${code} }`, + toSourceParameter: code => `async function f(x = ${code}) { }`, + }, +}; + +function assertSyntaxError(kind, code) { + var {constructor, toSourceBody, toSourceParameter} = functionContext[kind]; + var body = toSourceBody(code); + var parameter = toSourceParameter(code); + + assertThrowsInstanceOf(() => { constructor(code); }, SyntaxError, constructor.name + ":" + code); + assertThrowsInstanceOf(() => { constructor(`x = ${code}`, ""); }, SyntaxError, constructor.name + ":" + code); + + assertThrowsInstanceOf(() => { eval(body); }, SyntaxError, "eval:" + body); + assertThrowsInstanceOf(() => { ieval(body); }, SyntaxError, "indirect eval:" + body); + + assertThrowsInstanceOf(() => { eval(parameter); }, SyntaxError, "eval:" + parameter); + assertThrowsInstanceOf(() => { ieval(parameter); }, SyntaxError, "indirect eval:" + parameter); +} + +function assertNoSyntaxError(kind, code) { + var {constructor, toSourceBody, toSourceParameter} = functionContext[kind]; + var body = toSourceBody(code); + var parameter = toSourceParameter(code); + + constructor(code); + constructor(`x = ${code}`, ""); + + eval(body); + ieval(body); + + eval(parameter); + ieval(parameter); +} + +function assertSyntaxErrorAsync(code) { + assertNoSyntaxError("Function", code); + assertSyntaxError("AsyncFunction", code); +} + +function assertSyntaxErrorBoth(code) { + assertSyntaxError("Function", code); + assertSyntaxError("AsyncFunction", code); +} + + +// Bug 1353691 +// |await| expression is invalid in arrow functions in async-context. +// |await/r/g| first parses as |AwaitExpression RegularExpressionLiteral|, when reparsing the +// arrow function, it is parsed as |IdentRef DIV IdentRef DIV IdentRef|. We need to ensure in this +// case, that we still treat |await| as a keyword and hence throw a SyntaxError. +assertSyntaxErrorAsync("(a = await/r/g) => {}"); +assertSyntaxErrorBoth("async(a = await/r/g) => {}"); + +// Also applies when nesting arrow functions. +assertSyntaxErrorAsync("(a = (b = await/r/g) => {}) => {}"); +assertSyntaxErrorBoth("async(a = (b = await/r/g) => {}) => {}"); +assertSyntaxErrorBoth("(a = async(b = await/r/g) => {}) => {}"); +assertSyntaxErrorBoth("async(a = async(b = await/r/g) => {}) => {}"); + + +// Bug 1355860 +// |await| cannot be used as rest-binding parameter in arrow functions in async-context. +assertSyntaxErrorAsync("(...await) => {}"); +assertSyntaxErrorBoth("async(...await) => {}"); + +assertSyntaxErrorAsync("(a, ...await) => {}"); +assertSyntaxErrorBoth("async(a, ...await) => {}"); + +// Also test nested arrow functions. +assertSyntaxErrorAsync("(a = (...await) => {}) => {}"); +assertSyntaxErrorBoth("(a = async(...await) => {}) => {}"); +assertSyntaxErrorBoth("async(a = (...await) => {}) => {}"); +assertSyntaxErrorBoth("async(a = async(...await) => {}) => {}"); + +assertSyntaxErrorAsync("(a = (b, ...await) => {}) => {}"); +assertSyntaxErrorBoth("(a = async(b, ...await) => {}) => {}"); +assertSyntaxErrorBoth("async(a = (b, ...await) => {}) => {}"); +assertSyntaxErrorBoth("async(a = async(b, ...await) => {}) => {}"); + + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_2017/AsyncFunctions/forbidden-as-consequent.js b/js/src/tests/ecma_2017/AsyncFunctions/forbidden-as-consequent.js new file mode 100644 index 000000000..656ed46de --- /dev/null +++ b/js/src/tests/ecma_2017/AsyncFunctions/forbidden-as-consequent.js @@ -0,0 +1,14 @@ +/* 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/. */ + +assertThrowsInstanceOf(() => eval("if (1) async function foo() {}"), + SyntaxError); +assertThrowsInstanceOf(() => eval("'use strict'; if (1) async function foo() {}"), + SyntaxError); + +var async = 42; +assertEq(eval("if (1) async \n function foo() {}"), 42); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_2017/AsyncFunctions/inner-caller.js b/js/src/tests/ecma_2017/AsyncFunctions/inner-caller.js new file mode 100644 index 000000000..523eb79ea --- /dev/null +++ b/js/src/tests/ecma_2017/AsyncFunctions/inner-caller.js @@ -0,0 +1,26 @@ +var BUGNUMBER = 1185106; +var summary = "caller property of function inside async function should return wrapped async function"; + +print(BUGNUMBER + ": " + summary); + +(async function f() { + var inner = (function g() { + return g.caller; + })(); + assertEq(inner, f); +})(); + +(async function f() { + "use strict"; + try { + (function g() { + return g.caller; + })(); + assertEq(true, false); + } catch (e) { + assertEq(e instanceof TypeError, true); + } +})(); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Class/parenExprToString.js b/js/src/tests/ecma_6/Class/parenExprToString.js new file mode 100644 index 000000000..a93972ce9 --- /dev/null +++ b/js/src/tests/ecma_6/Class/parenExprToString.js @@ -0,0 +1,8 @@ +// Test that parenthesized class expressions don't get their toString offsets +// messed up. + +assertEq((class {}).toString(), "class {}"); +assertEq(((class {})).toString(), "class {}"); + +if (typeof reportCompare === "function") + reportCompare(0, 0, "OK"); diff --git a/js/src/tests/ecma_6/Comprehensions/for-reserved-word.js b/js/src/tests/ecma_6/Comprehensions/for-reserved-word.js new file mode 100644 index 000000000..9b320fc91 --- /dev/null +++ b/js/src/tests/ecma_6/Comprehensions/for-reserved-word.js @@ -0,0 +1,107 @@ +var BUGNUMBER = 1340089; +var summary = "Comprehension should check the binding names"; + +print(BUGNUMBER + ": " + summary); + +// Non strict mode. +// Keywords, literals, 'let', and 'yield' are not allowed. + +assertThrowsInstanceOf(function () { + eval("[for (true of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + eval("(for (true of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + eval("[for (throw of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + eval("(for (throw of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + eval("[for (let of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + eval("(for (let of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + eval("[for (yield of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + eval("(for (yield of [1]) 2)"); +}, SyntaxError); + +eval("[for (public of [1]) 2]"); +eval("(for (public of [1]) 2)"); + +eval("[for (static of [1]) 2]"); +eval("(for (static of [1]) 2)"); + +// Strict mode. +// All reserved words are not allowed. + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (true of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (true of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (throw of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (throw of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (let of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (let of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (yield of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (yield of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (public of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (public of [1]) 2)"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + "use strict"; + eval("[for (static of [1]) 2]"); +}, SyntaxError); +assertThrowsInstanceOf(function () { + "use strict"; + eval("(for (static of [1]) 2)"); +}, SyntaxError); + +(function () { + "use strict"; + eval("[for (await of [1]) 2]"); + eval("(for (await of [1]) 2)"); +})(); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Function/constructor-binding.js b/js/src/tests/ecma_6/Function/constructor-binding.js new file mode 100644 index 000000000..e82274d27 --- /dev/null +++ b/js/src/tests/ecma_6/Function/constructor-binding.js @@ -0,0 +1,11 @@ +var BUGNUMBER = 636635; +var summary = "A function created by Function constructor shouldn't have anonymous binding"; + +print(BUGNUMBER + ": " + summary); + +assertEq(new Function("return typeof anonymous")(), "undefined"); +assertEq(new Function("return function() { return typeof anonymous; }")()(), "undefined"); +assertEq(new Function("return function() { eval(''); return typeof anonymous; }")()(), "undefined"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Function/throw-type-error.js b/js/src/tests/ecma_6/Function/throw-type-error.js new file mode 100644 index 000000000..68dd6e1d0 --- /dev/null +++ b/js/src/tests/ecma_6/Function/throw-type-error.js @@ -0,0 +1,16 @@ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/publicdomain/zero/1.0/ + +const ThrowTypeError = function(){ + "use strict"; + return Object.getOwnPropertyDescriptor(arguments, "callee").get; +}(); + +assertDeepEq(Object.getOwnPropertyDescriptor(ThrowTypeError, "length"), { + value: 0, writable: false, enumerable: false, configurable: false +}); + +assertEq(Object.isFrozen(ThrowTypeError), true); + +if (typeof reportCompare == "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Generators/forbidden-as-consequent.js b/js/src/tests/ecma_6/Generators/forbidden-as-consequent.js new file mode 100644 index 000000000..13647e154 --- /dev/null +++ b/js/src/tests/ecma_6/Generators/forbidden-as-consequent.js @@ -0,0 +1,11 @@ +/* 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/. */ + +assertThrowsInstanceOf(() => eval("if (1) function* foo() {}"), + SyntaxError); +assertThrowsInstanceOf(() => eval("'use strict'; if (1) function* foo() {}"), + SyntaxError); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js new file mode 100644 index 000000000..ae7fbe879 --- /dev/null +++ b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js @@ -0,0 +1,21 @@ +// Annex B.3.3.1 disallows Annex B lexical function behavior when redeclaring a +// parameter. + +(function(f) { + if (true) function f() { } + assertEq(f, 123); +}(123)); + +(function(f) { + { function f() { } } + assertEq(f, 123); +}(123)); + +(function(f = 123) { + assertEq(f, 123); + { function f() { } } + assertEq(f, 123); +}()); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/TemplateStrings/tagTempl.js b/js/src/tests/ecma_6/TemplateStrings/tagTempl.js index 1e3f52bfb..99c2098dc 100644 --- a/js/src/tests/ecma_6/TemplateStrings/tagTempl.js +++ b/js/src/tests/ecma_6/TemplateStrings/tagTempl.js @@ -287,5 +287,176 @@ assertEq(String.raw`h\r\ney${4}there\n`, "h\\r\\ney4there\\n"); assertEq(String.raw`hey`, "hey"); assertEq(String.raw``, ""); +// Invalid escape sequences +check(raw`\01`, ["\\01"]); +check(raw`\01${0}right`, ["\\01","right"]); +check(raw`left${0}\01`, ["left","\\01"]); +check(raw`left${0}\01${1}right`, ["left","\\01","right"]); +check(raw`\1`, ["\\1"]); +check(raw`\1${0}right`, ["\\1","right"]); +check(raw`left${0}\1`, ["left","\\1"]); +check(raw`left${0}\1${1}right`, ["left","\\1","right"]); +check(raw`\xg`, ["\\xg"]); +check(raw`\xg${0}right`, ["\\xg","right"]); +check(raw`left${0}\xg`, ["left","\\xg"]); +check(raw`left${0}\xg${1}right`, ["left","\\xg","right"]); +check(raw`\xAg`, ["\\xAg"]); +check(raw`\xAg${0}right`, ["\\xAg","right"]); +check(raw`left${0}\xAg`, ["left","\\xAg"]); +check(raw`left${0}\xAg${1}right`, ["left","\\xAg","right"]); +check(raw`\u0`, ["\\u0"]); +check(raw`\u0${0}right`, ["\\u0","right"]); +check(raw`left${0}\u0`, ["left","\\u0"]); +check(raw`left${0}\u0${1}right`, ["left","\\u0","right"]); +check(raw`\u0g`, ["\\u0g"]); +check(raw`\u0g${0}right`, ["\\u0g","right"]); +check(raw`left${0}\u0g`, ["left","\\u0g"]); +check(raw`left${0}\u0g${1}right`, ["left","\\u0g","right"]); +check(raw`\u00g`, ["\\u00g"]); +check(raw`\u00g${0}right`, ["\\u00g","right"]); +check(raw`left${0}\u00g`, ["left","\\u00g"]); +check(raw`left${0}\u00g${1}right`, ["left","\\u00g","right"]); +check(raw`\u000g`, ["\\u000g"]); +check(raw`\u000g${0}right`, ["\\u000g","right"]); +check(raw`left${0}\u000g`, ["left","\\u000g"]); +check(raw`left${0}\u000g${1}right`, ["left","\\u000g","right"]); +check(raw`\u{}`, ["\\u{}"]); +check(raw`\u{}${0}right`, ["\\u{}","right"]); +check(raw`left${0}\u{}`, ["left","\\u{}"]); +check(raw`left${0}\u{}${1}right`, ["left","\\u{}","right"]); +check(raw`\u{-0}`, ["\\u{-0}"]); +check(raw`\u{-0}${0}right`, ["\\u{-0}","right"]); +check(raw`left${0}\u{-0}`, ["left","\\u{-0}"]); +check(raw`left${0}\u{-0}${1}right`, ["left","\\u{-0}","right"]); +check(raw`\u{g}`, ["\\u{g}"]); +check(raw`\u{g}${0}right`, ["\\u{g}","right"]); +check(raw`left${0}\u{g}`, ["left","\\u{g}"]); +check(raw`left${0}\u{g}${1}right`, ["left","\\u{g}","right"]); +check(raw`\u{0`, ["\\u{0"]); +check(raw`\u{0${0}right`, ["\\u{0","right"]); +check(raw`left${0}\u{0`, ["left","\\u{0"]); +check(raw`left${0}\u{0${1}right`, ["left","\\u{0","right"]); +check(raw`\u{\u{0}`, ["\\u{\\u{0}"]); +check(raw`\u{\u{0}${0}right`, ["\\u{\\u{0}","right"]); +check(raw`left${0}\u{\u{0}`, ["left","\\u{\\u{0}"]); +check(raw`left${0}\u{\u{0}${1}right`, ["left","\\u{\\u{0}","right"]); +check(raw`\u{110000}`, ["\\u{110000}"]); +check(raw`\u{110000}${0}right`, ["\\u{110000}","right"]); +check(raw`left${0}\u{110000}`, ["left","\\u{110000}"]); +check(raw`left${0}\u{110000}${1}right`, ["left","\\u{110000}","right"]); + +check(cooked`\01`, [void 0]); +check(cooked`\01${0}right`, [void 0,"right"]); +check(cooked`left${0}\01`, ["left",void 0]); +check(cooked`left${0}\01${1}right`, ["left",void 0,"right"]); +check(cooked`\1`, [void 0]); +check(cooked`\1${0}right`, [void 0,"right"]); +check(cooked`left${0}\1`, ["left",void 0]); +check(cooked`left${0}\1${1}right`, ["left",void 0,"right"]); +check(cooked`\xg`, [void 0]); +check(cooked`\xg${0}right`, [void 0,"right"]); +check(cooked`left${0}\xg`, ["left",void 0]); +check(cooked`left${0}\xg${1}right`, ["left",void 0,"right"]); +check(cooked`\xAg`, [void 0]); +check(cooked`\xAg${0}right`, [void 0,"right"]); +check(cooked`left${0}\xAg`, ["left",void 0]); +check(cooked`left${0}\xAg${1}right`, ["left",void 0,"right"]); +check(cooked`\u0`, [void 0]); +check(cooked`\u0${0}right`, [void 0,"right"]); +check(cooked`left${0}\u0`, ["left",void 0]); +check(cooked`left${0}\u0${1}right`, ["left",void 0,"right"]); +check(cooked`\u0g`, [void 0]); +check(cooked`\u0g${0}right`, [void 0,"right"]); +check(cooked`left${0}\u0g`, ["left",void 0]); +check(cooked`left${0}\u0g${1}right`, ["left",void 0,"right"]); +check(cooked`\u00g`, [void 0]); +check(cooked`\u00g${0}right`, [void 0,"right"]); +check(cooked`left${0}\u00g`, ["left",void 0]); +check(cooked`left${0}\u00g${1}right`, ["left",void 0,"right"]); +check(cooked`\u000g`, [void 0]); +check(cooked`\u000g${0}right`, [void 0,"right"]); +check(cooked`left${0}\u000g`, ["left",void 0]); +check(cooked`left${0}\u000g${1}right`, ["left",void 0,"right"]); +check(cooked`\u{}`, [void 0]); +check(cooked`\u{}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{}`, ["left",void 0]); +check(cooked`left${0}\u{}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{-0}`, [void 0]); +check(cooked`\u{-0}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{-0}`, ["left",void 0]); +check(cooked`left${0}\u{-0}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{g}`, [void 0]); +check(cooked`\u{g}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{g}`, ["left",void 0]); +check(cooked`left${0}\u{g}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{0`, [void 0]); +check(cooked`\u{0${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{0`, ["left",void 0]); +check(cooked`left${0}\u{0${1}right`, ["left",void 0,"right"]); +check(cooked`\u{\u{0}`, [void 0]); +check(cooked`\u{\u{0}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{\u{0}`, ["left",void 0]); +check(cooked`left${0}\u{\u{0}${1}right`, ["left",void 0,"right"]); +check(cooked`\u{110000}`, [void 0]); +check(cooked`\u{110000}${0}right`, [void 0,"right"]); +check(cooked`left${0}\u{110000}`, ["left",void 0]); +check(cooked`left${0}\u{110000}${1}right`, ["left",void 0,"right"]); + +syntaxError("`\\01`"); +syntaxError("`\\01${0}right`"); +syntaxError("`left${0}\\01`"); +syntaxError("`left${0}\\01${1}right`"); +syntaxError("`\\1`"); +syntaxError("`\\1${0}right`"); +syntaxError("`left${0}\\1`"); +syntaxError("`left${0}\\1${1}right`"); +syntaxError("`\\xg`"); +syntaxError("`\\xg${0}right`"); +syntaxError("`left${0}\\xg`"); +syntaxError("`left${0}\\xg${1}right`"); +syntaxError("`\\xAg`"); +syntaxError("`\\xAg${0}right`"); +syntaxError("`left${0}\\xAg`"); +syntaxError("`left${0}\\xAg${1}right`"); +syntaxError("`\\u0`"); +syntaxError("`\\u0${0}right`"); +syntaxError("`left${0}\\u0`"); +syntaxError("`left${0}\\u0${1}right`"); +syntaxError("`\\u0g`"); +syntaxError("`\\u0g${0}right`"); +syntaxError("`left${0}\\u0g`"); +syntaxError("`left${0}\\u0g${1}right`"); +syntaxError("`\\u00g`"); +syntaxError("`\\u00g${0}right`"); +syntaxError("`left${0}\\u00g`"); +syntaxError("`left${0}\\u00g${1}right`"); +syntaxError("`\\u000g`"); +syntaxError("`\\u000g${0}right`"); +syntaxError("`left${0}\\u000g`"); +syntaxError("`left${0}\\u000g${1}right`"); +syntaxError("`\\u{}`"); +syntaxError("`\\u{}${0}right`"); +syntaxError("`left${0}\\u{}`"); +syntaxError("`left${0}\\u{}${1}right`"); +syntaxError("`\\u{-0}`"); +syntaxError("`\\u{-0}${0}right`"); +syntaxError("`left${0}\\u{-0}`"); +syntaxError("`left${0}\\u{-0}${1}right`"); +syntaxError("`\\u{g}`"); +syntaxError("`\\u{g}${0}right`"); +syntaxError("`left${0}\\u{g}`"); +syntaxError("`left${0}\\u{g}${1}right`"); +syntaxError("`\\u{0`"); +syntaxError("`\\u{0${0}right`"); +syntaxError("`left${0}\\u{0`"); +syntaxError("`left${0}\\u{0${1}right`"); +syntaxError("`\\u{\\u{0}`"); +syntaxError("`\\u{\\u{0}${0}right`"); +syntaxError("`left${0}\\u{\\u{0}`"); +syntaxError("`left${0}\\u{\\u{0}${1}right`"); +syntaxError("`\\u{110000}`"); +syntaxError("`\\u{110000}${0}right`"); +syntaxError("`left${0}\\u{110000}`"); +syntaxError("`left${0}\\u{110000}${1}right`"); reportCompare(0, 0, "ok"); diff --git a/js/src/tests/ecma_6/extensions/newer-type-functions-caller-arguments.js b/js/src/tests/ecma_6/extensions/newer-type-functions-caller-arguments.js new file mode 100644 index 000000000..7fed18037 --- /dev/null +++ b/js/src/tests/ecma_6/extensions/newer-type-functions-caller-arguments.js @@ -0,0 +1,43 @@ +// Tests that newer-type functions (i.e. anything not defined by regular function declarations and +// expressions) throw when accessing their 'arguments' and 'caller' properties. + +// 9.2.7 (AddRestrictedFunctionProperties) defines accessors on Function.prototype which throw on +// every 'get' and 'set' of 'caller' and 'arguments'. +// Additionally, 16.2 (Forbidden Extensions) forbids adding properties to all non-"legacy" function +// declarations and expressions. This creates the effect that all newer-style functions act like +// strict-mode functions when accessing their 'caller' and 'arguments' properties. + +const container = { + async asyncMethod() {}, + *genMethod() {}, + method() {} +}; + +[ + async function(){}, + function*(){}, + () => {}, + async () => {}, + + container.asyncMethod, + container.genMethod, + container.method +].forEach(f => { + checkArgumentsAccess(f); + checkCallerAccess(f); +}); + +function checkArgumentsAccess(f) { + assertThrowsInstanceOf(() => f.arguments, TypeError, + `Expected 'arguments' property access to throw on ${f}`); +} + +function checkCallerAccess(f) { + assertThrowsInstanceOf(() => f.caller, TypeError, + `Expected 'caller' property access to throw on ${f}`); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("Tests complete"); diff --git a/js/src/tests/ecma_7/AsyncFunctions/async-contains-unicode-escape.js b/js/src/tests/ecma_7/AsyncFunctions/async-contains-unicode-escape.js new file mode 100644 index 000000000..d53dff696 --- /dev/null +++ b/js/src/tests/ecma_7/AsyncFunctions/async-contains-unicode-escape.js @@ -0,0 +1,54 @@ +var BUGNUMBER = 1315815; +var summary = "async/await containing escapes"; + +print(BUGNUMBER + ": " + summary); + +// Using "eval" as the argument name is fugly, but it means evals below are +// *direct* evals, and so their effects in the unescaped case won't extend +// past each separate |test| call (as would happen if we used a different name +// that made each eval into an indirect eval, affecting code in the global +// scope). +function test(code, eval) +{ + var unescaped = code.replace("###", "async"); + var escaped = code.replace("###", "\\u0061"); + + assertThrowsInstanceOf(() => eval(escaped), SyntaxError); + eval(unescaped); +} + +test("### function f() {}", eval); +test("var x = ### function f() {}", eval); +test("### x => {};", eval); +test("var x = ### x => {}", eval); +test("### () => {};", eval); +test("var x = ### () => {}", eval); +test("### (y) => {};", eval); +test("var x = ### (y) => {}", eval); +test("({ ### x() {} })", eval); +test("var x = ### function f() {}", eval); + +if (typeof parseModule === "function") + test("export default ### function f() {}", parseModule); + +assertThrowsInstanceOf(() => eval("async await => 1;"), + SyntaxError); +assertThrowsInstanceOf(() => eval("async aw\\u0061it => 1;"), + SyntaxError); + +var async = 0; +assertEq(\u0061sync, 0); + +var obj = { \u0061sync() { return 1; } }; +assertEq(obj.async(), 1); + +async = function() { return 42; }; + +var z = async(obj); +assertEq(z, 42); + +var w = async(obj)=>{}; +assertEq(typeof w, "function"); + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/js1_8/regress/regress-467495-05.js b/js/src/tests/js1_8/regress/regress-467495-05.js index 505fb6bd6..ecf47b8fe 100644 --- a/js/src/tests/js1_8/regress/regress-467495-05.js +++ b/js/src/tests/js1_8/regress/regress-467495-05.js @@ -20,7 +20,7 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - expect = 'function x() {}'; + expect = '1'; function g(x) { if (1) function x() {} return x; } print(actual = g(1) + ''); diff --git a/js/src/tests/js1_8/regress/regress-467495-06.js b/js/src/tests/js1_8/regress/regress-467495-06.js index d8bc81c83..72adeee9e 100644 --- a/js/src/tests/js1_8/regress/regress-467495-06.js +++ b/js/src/tests/js1_8/regress/regress-467495-06.js @@ -32,7 +32,7 @@ function test() var r = f(0); - if (typeof(r[0]) != "function") + if (typeof(r[0]) != "number") actual += "Bad r[0]"; if (typeof(r[1]) != "function") diff --git a/js/src/tests/js1_8_5/reflect-parse/object-rest.js b/js/src/tests/js1_8_5/reflect-parse/object-rest.js new file mode 100644 index 000000000..5af06909b --- /dev/null +++ b/js/src/tests/js1_8_5/reflect-parse/object-rest.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!xulRuntime.shell) + +function property(key, value = key, shorthand = key === value) { + return { key, value, shorthand }; +} + +function assertDestrAssign(src, pattern) { + assertExpr(`(${src} = 0)`, aExpr("=", pattern, lit(0))); +} + +function assertDestrBinding(src, pattern) { + assertDecl(`var ${src} = 0`, varDecl([{id: pattern, init: lit(0)}])); +} + +function test() { + // Target expression must be a simple assignment target or a nested pattern + // in object assignment patterns. + assertDestrAssign("{...x}", objPatt([spread(ident("x"))])); + assertDestrAssign("{...(x)}", objPatt([spread(ident("x"))])); + assertDestrAssign("{...obj.p}", objPatt([spread(dotExpr(ident("obj"), ident("p")))])); + assertDestrAssign("{...{}}", objPatt([spread(objPatt([]))])); + assertDestrAssign("{...[]}", objPatt([spread(arrPatt([]))])); + + // Object binding patterns only allow binding identifiers or nested patterns. + assertDestrBinding("{...x}", objPatt([spread(ident("x"))])); + assertDestrBinding("{...{}}", objPatt([spread(objPatt([]))])); + assertDestrBinding("{...[]}", objPatt([spread(arrPatt([]))])); + + // The rest-property can be preceded by other properties. + for (var assertDestr of [assertDestrAssign, assertDestrBinding]) { + assertDestr("{a, ...x}", objPatt([property(ident("a")), spread(ident("x"))])); + assertDestr("{a: b, ...x}", objPatt([property(ident("a"), ident("b")), spread(ident("x"))])); + assertDestr("{[a]: b, ...x}", objPatt([property(comp(ident("a")), ident("b")), spread(ident("x"))])); + } + + // Tests when __proto__ is used in the object pattern. + for (var assertDestr of [assertDestrAssign, assertDestrBinding]) { + assertDestr("{...__proto__}", objPatt([spread(ident("__proto__"))])); + assertDestr("{__proto__, ...x}", objPatt([property(ident("__proto__")), spread(ident("x"))])); + } + assertDestrAssign("{__proto__: a, ...x}", objPatt([property(lit("__proto__"), ident("a")), spread(ident("x"))])); + assertDestrBinding("{__proto__: a, ...x}", objPatt([property(ident("__proto__"), ident("a")), spread(ident("x"))])); +} + +runtest(test); diff --git a/js/src/tests/js1_8_5/reflect-parse/object-spread.js b/js/src/tests/js1_8_5/reflect-parse/object-spread.js new file mode 100644 index 000000000..a4b269c40 --- /dev/null +++ b/js/src/tests/js1_8_5/reflect-parse/object-spread.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!xulRuntime.shell) + +function property(key, value = key, shorthand = key === value) { + return { key, value, shorthand }; +} + +function test() { + // Any expression can be spreaded. + assertExpr("({...x})", objExpr([spread(ident("x"))])); + assertExpr("({...f()})", objExpr([spread(callExpr(ident("f"), []))])); + assertExpr("({...123})", objExpr([spread(lit(123))])); + + // Multiple spread expression are allowed. + assertExpr("({...x, ...obj.p})", objExpr([spread(ident("x")), spread(dotExpr(ident("obj"), ident("p")))])); + + // Spread expression can appear anywhere in an object literal. + assertExpr("({p, ...x})", objExpr([property(ident("p")), spread(ident("x"))])); + assertExpr("({p: a, ...x})", objExpr([property(ident("p"), ident("a")), spread(ident("x"))])); + assertExpr("({...x, p: a})", objExpr([spread(ident("x")), property(ident("p"), ident("a"))])); + + // Trailing comma after spread expression is allowed. + assertExpr("({...x,})", objExpr([spread(ident("x"))])); + + // __proto__ is not special in spread expressions. + assertExpr("({...__proto__})", objExpr([spread(ident("__proto__"))])); + assertExpr("({...__proto__, ...__proto__})", objExpr([spread(ident("__proto__")), spread(ident("__proto__"))])); +} + +runtest(test); diff --git a/js/src/tests/js1_8_5/reflect-parse/templateStrings.js b/js/src/tests/js1_8_5/reflect-parse/templateStrings.js index c87ba96b8..fb12afd00 100644 --- a/js/src/tests/js1_8_5/reflect-parse/templateStrings.js +++ b/js/src/tests/js1_8_5/reflect-parse/templateStrings.js @@ -7,6 +7,8 @@ assertStringExpr("`hey\nthere`", literal("hey\nthere")); assertExpr("`hey${\"there\"}`", templateLit([lit("hey"), lit("there"), lit("")])); assertExpr("`hey${\"there\"}mine`", templateLit([lit("hey"), lit("there"), lit("mine")])); assertExpr("`hey${a == 5}mine`", templateLit([lit("hey"), binExpr("==", ident("a"), lit(5)), lit("mine")])); +assertExpr("func`hey\\x`", taggedTemplate(ident("func"), template(["hey\\x"], [void 0]))); +assertExpr("func`hey${4}\\x`", taggedTemplate(ident("func"), template(["hey","\\x"], ["hey",void 0], lit(4)))); assertExpr("`hey${`there${\"how\"}`}mine`", templateLit([lit("hey"), templateLit([lit("there"), lit("how"), lit("")]), lit("mine")])); assertExpr("func`hey`", taggedTemplate(ident("func"), template(["hey"], ["hey"]))); diff --git a/js/src/tests/test262/built-ins/Object/getOwnPropertyDescriptors/shell.js b/js/src/tests/test262/built-ins/Object/getOwnPropertyDescriptors/shell.js index 6ed766e94..e69de29bb 100644 --- a/js/src/tests/test262/built-ins/Object/getOwnPropertyDescriptors/shell.js +++ b/js/src/tests/test262/built-ins/Object/getOwnPropertyDescriptors/shell.js @@ -1,27 +0,0 @@ -var assert = { - sameValue: assertEq, - notSameValue(a, b, msg) { - try { - assertEq(a, b); - throw "equal" - } catch (e) { - if (e === "equal") - throw new Error("Assertion failed: expected different values, got " + a); - } - }, - throws(ctor, f) { - var fullmsg; - try { - f(); - } catch (exc) { - if (exc instanceof ctor) - return; - fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc; - } - if (fullmsg === undefined) - fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown"; - if (msg !== undefined) - fullmsg += " - " + msg; - throw new Error(fullmsg); - } -} diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-1.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-1.js new file mode 100755 index 000000000..08925e079 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-1.js @@ -0,0 +1,17 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped value is not changed when property was made non-configurable. +flags: [noStrict] +---*/ + +function argumentsNonConfigurable(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); +} +argumentsNonConfigurable(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-2.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-2.js new file mode 100755 index 000000000..265481e01 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-2.js @@ -0,0 +1,19 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, variable is + changed with SetMutableBinding. +flags: [noStrict] +---*/ + +function argumentsAndSetMutableBinding(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndSetMutableBinding(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-3.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-3.js new file mode 100755 index 000000000..6877a0c9d --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-3.js @@ -0,0 +1,19 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + is changed with [[DefineOwnProperty]]. +flags: [noStrict] +---*/ + +function argumentsAndDefineOwnProperty(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + Object.defineProperty(arguments, "0", {value: 2}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndDefineOwnProperty(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-4.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-4.js new file mode 100755 index 000000000..d2ac4d376 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-4.js @@ -0,0 +1,19 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + is changed with [[Set]]. +flags: [noStrict] +---*/ + +function argumentsAndSet(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + arguments[0] = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndSet(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-1.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-1.js new file mode 100755 index 000000000..67f971369 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-1.js @@ -0,0 +1,19 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. [[Delete]] operation returns false. +flags: [noStrict] +---*/ + +function argumentsAndDelete(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + assert.sameValue(delete arguments[0], false); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); +} +argumentsAndDelete(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-2.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-2.js new file mode 100755 index 000000000..9a089eaac --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-2.js @@ -0,0 +1,24 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. Variable is changed with SetMutableBinding. +flags: [noStrict] +---*/ + +function argumentsAndDeleteSetMutableBinding(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + assert.sameValue(delete arguments[0], false); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndDeleteSetMutableBinding(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-3.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-3.js new file mode 100755 index 000000000..26676a4ee --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-3.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. Arguments property is changed with + [[DefineOwnProperty]]. +flags: [noStrict] +---*/ + +function argumentsAndDeleteDefineOwnProperty(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + assert.sameValue(delete arguments[0], false); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + Object.defineProperty(arguments, "0", {value: 2}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndDeleteDefineOwnProperty(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-4.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-4.js new file mode 100755 index 000000000..ed96a0e67 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-delete-4.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. Arguments property is changed with + [[Set]]. +flags: [noStrict] +---*/ + +function argumentsAndDeleteSet(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + assert.sameValue(delete arguments[0], false); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + arguments[0] = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndDeleteSet(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-1.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-1.js new file mode 100755 index 000000000..cfeba05c4 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-1.js @@ -0,0 +1,24 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-configurable and + non-writable. Perform property attribute changes with a single + [[DefineOwnProperty]] call. Mapped values are unchanged, mapping + itself is removed. +flags: [noStrict] +---*/ + +function argumentsNonConfigurableAndNonWritable(a) { + Object.defineProperty(arguments, "0", {configurable: false, writable: false}); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + // Postcondition: Arguments mapping is removed. + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 1); +} +argumentsNonConfigurableAndNonWritable(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-2.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-2.js new file mode 100755 index 000000000..69c0e125b --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-2.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-configurable and + non-writable. Perform property attribute changes with two + consecutive [[DefineOwnProperty]] calls. Mapped values are + unchanged, mapping itself is removed. +flags: [noStrict] +---*/ + +function argumentsNonConfigurableThenNonWritable(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + Object.defineProperty(arguments, "0", {writable: false}); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + // Postcondition: Arguments mapping is removed. + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 1); +} +argumentsNonConfigurableThenNonWritable(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-3.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-3.js new file mode 100755 index 000000000..dca0adcd2 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-3.js @@ -0,0 +1,28 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-configurable and + non-writable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to + SetMutableBinding. +flags: [noStrict] +---*/ + +function argumentsNonConfigurableThenNonWritableWithInterveningSetMutableBinding(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + a = 2; + Object.defineProperty(arguments, "0", {writable: false}); + assert.sameValue(a, 2); + // `arguments[0] === 1` per ES2015, Rev 38, April 14, 2015 Final Draft. + // Specification bug: https://bugs.ecmascript.org/show_bug.cgi?id=4371 + assert.sameValue(arguments[0], 2); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 2); +} +argumentsNonConfigurableThenNonWritableWithInterveningSetMutableBinding(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-4.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-4.js new file mode 100755 index 000000000..80d56fe1c --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-4.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-configurable and + non-writable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to [[Set]]. +flags: [noStrict] +---*/ + +function argumentsNonConfigurableThenNonWritableWithInterveningSet(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + arguments[0] = 2; + Object.defineProperty(arguments, "0", {writable: false}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 2); +} +argumentsNonConfigurableThenNonWritableWithInterveningSet(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-5.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-5.js new file mode 100755 index 000000000..bbb951502 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-nonwritable-5.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-configurable and + non-writable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to + [[DefineOwnProperty]]. +flags: [noStrict] +---*/ + +function argumentsNonConfigurableThenNonWritableWithDefineOwnProperty(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + Object.defineProperty(arguments, "0", {value: 2}); + Object.defineProperty(arguments, "0", {writable: false}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 2); +} +argumentsNonConfigurableThenNonWritableWithDefineOwnProperty(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-1.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-1.js new file mode 100755 index 000000000..b918f75a1 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-1.js @@ -0,0 +1,21 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. [[Delete]] operations throws TypeError if called + from strict-mode code. +flags: [noStrict] +---*/ + +function argumentsAndStrictDelete(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + var args = arguments; + assert.throws(TypeError, function() { "use strict"; delete args[0]; }); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); +} +argumentsAndStrictDelete(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-2.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-2.js new file mode 100755 index 000000000..01afbe4de --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-2.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. [[Delete]] operations throws TypeError if called + from strict-mode code. Variable is changed with SetMutableBinding. +flags: [noStrict] +---*/ + +function argumentsAndStrictDeleteSetMutableBinding(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + var args = arguments; + assert.throws(TypeError, function() { "use strict"; delete args[0]; }); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndStrictDeleteSetMutableBinding(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-3.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-3.js new file mode 100755 index 000000000..9aa2a2ed2 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-3.js @@ -0,0 +1,27 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. [[Delete]] operations throws TypeError if called + from strict-mode code. Arguments property is changed with + [[DefineOwnProperty]]. +flags: [noStrict] +---*/ + +function argumentsAndStrictDeleteDefineOwnProperty(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + var args = arguments; + assert.throws(TypeError, function() { "use strict"; delete args[0]; }); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + Object.defineProperty(arguments, "0", {value: 2}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndStrictDeleteDefineOwnProperty(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-4.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-4.js new file mode 100755 index 000000000..b48018843 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonconfigurable-strict-delete-4.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapping works when property is non-configurable, arguments property + was not deleted. [[Delete]] operations throws TypeError if called + from strict-mode code. Arguments property is changed with [[Set]]. +flags: [noStrict] +---*/ + +function argumentsAndStrictDeleteSet(a) { + Object.defineProperty(arguments, "0", {configurable: false}); + + // Precondition: Delete is unsuccessful and doesn't affect mapping. + var args = arguments; + assert.throws(TypeError, function() { "use strict"; delete args[0]; }); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + arguments[0] = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 2); +} +argumentsAndStrictDeleteSet(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-1.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-1.js new file mode 100755 index 000000000..2dae07678 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-1.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-writable and + non-configurable. Perform property attribute changes with two + consecutive [[DefineOwnProperty]] calls. Mapped values are + unchanged, mapping itself is removed. +flags: [noStrict] +---*/ + +function argumentsNonWritableThenNonConfigurable(a) { + Object.defineProperty(arguments, "0", {writable: false}); + Object.defineProperty(arguments, "0", {configurable: false}); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + // Postcondition: Arguments mapping is removed. + a = 2; + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 1); +} +argumentsNonWritableThenNonConfigurable(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-2.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-2.js new file mode 100755 index 000000000..63585b437 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-2.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-writable and + non-configurable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to + SetMutableBinding. +flags: [noStrict] +---*/ + +function argumentsNonWritableThenNonConfigurableWithInterveningSetMutableBinding(a) { + Object.defineProperty(arguments, "0", {writable: false}); + a = 2; + Object.defineProperty(arguments, "0", {configurable: false}); + assert.sameValue(a, 2); + assert.sameValue(arguments[0], 1); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 1); +} +argumentsNonWritableThenNonConfigurableWithInterveningSetMutableBinding(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-3.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-3.js new file mode 100755 index 000000000..2bd1bc9c1 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-3.js @@ -0,0 +1,25 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-writable and + non-configurable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to [[Set]]. +flags: [noStrict] +---*/ + +function argumentsNonWritableThenNonConfigurableWithInterveningSet(a) { + Object.defineProperty(arguments, "0", {writable: false}); + arguments[0] = 2; + Object.defineProperty(arguments, "0", {configurable: false}); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 1); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 1); +} +argumentsNonWritableThenNonConfigurableWithInterveningSet(1); diff --git a/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-4.js b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-4.js new file mode 100755 index 000000000..ea40a49a8 --- /dev/null +++ b/js/src/tests/test262/language/arguments-object/mapped/mapped-arguments-nonwritable-nonconfigurable-4.js @@ -0,0 +1,26 @@ +// Copyright (C) 2015 André Bargull. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +info: Mapped arguments object with non-configurable property +description: > + Mapped arguments property is changed to non-writable and + non-configurable. Perform property attribute changes with two + [[DefineOwnProperty]] calls. Add intervening call to + [[DefineOwnProperty]]. +flags: [noStrict] +---*/ + +function argumentsNonWritableThenNonConfigurableWithInterveningDefineOwnProperty(a) { + Object.defineProperty(arguments, "0", {writable: false}); + Object.defineProperty(arguments, "0", {value: 2}); + Object.defineProperty(arguments, "0", {configurable: false}); + assert.sameValue(a, 1); + assert.sameValue(arguments[0], 2); + + // Postcondition: Arguments mapping is removed. + a = 3; + assert.sameValue(a, 3); + assert.sameValue(arguments[0], 2); +} +argumentsNonWritableThenNonConfigurableWithInterveningDefineOwnProperty(1); diff --git a/devtools/client/webide/test/build_app2/stage/empty-directory b/js/src/tests/test262/language/arguments-object/mapped/shell.js index e69de29bb..e69de29bb 100644 --- a/devtools/client/webide/test/build_app2/stage/empty-directory +++ b/js/src/tests/test262/language/arguments-object/mapped/shell.js diff --git a/devtools/client/webide/test/build_app_windows2/stage/empty-directory b/js/src/tests/test262/language/arguments-object/shell.js index e69de29bb..e69de29bb 100644 --- a/devtools/client/webide/test/build_app_windows2/stage/empty-directory +++ b/js/src/tests/test262/language/arguments-object/shell.js diff --git a/devtools/client/webide/test/validator/no-name-or-icon/home.html b/js/src/tests/test262/language/shell.js index e69de29bb..e69de29bb 100644 --- a/devtools/client/webide/test/validator/no-name-or-icon/home.html +++ b/js/src/tests/test262/language/shell.js diff --git a/js/src/tests/test262/shell.js b/js/src/tests/test262/shell.js index b70bb5dbb..462ec9cf8 100644 --- a/js/src/tests/test262/shell.js +++ b/js/src/tests/test262/shell.js @@ -938,3 +938,31 @@ var fnGlobalObject = (function() var global = Function("return this")(); return function fnGlobalObject() { return global; }; })(); + +var assert = { + sameValue: assertEq, + notSameValue(a, b, msg) { + try { + assertEq(a, b); + throw "equal" + } catch (e) { + if (e === "equal") + throw new Error("Assertion failed: expected different values, got " + a); + } + }, + throws(ctor, f) { + var fullmsg; + try { + f(); + } catch (exc) { + if (exc instanceof ctor) + return; + fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc; + } + if (fullmsg === undefined) + fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown"; + if (msg !== undefined) + fullmsg += " - " + msg; + throw new Error(fullmsg); + } +} diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index 717aa1050..66e0f40a2 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -214,7 +214,7 @@ ArgumentsObject::createTemplateObject(JSContext* cx, bool mapped) ? &MappedArgumentsObject::class_ : &UnmappedArgumentsObject::class_; - RootedObject proto(cx, cx->global()->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global())); if (!proto) return nullptr; @@ -475,7 +475,7 @@ MappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */ RootedFunction callee(cx, &argsobj->callee()); - RootedScript script(cx, callee->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee)); if (!script) return false; @@ -590,6 +590,64 @@ MappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj) return true; } +// ES 2017 draft 9.4.4.2 +/* static */ bool +MappedArgumentsObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, + Handle<PropertyDescriptor> desc, ObjectOpResult& result) +{ + // Step 1. + Rooted<MappedArgumentsObject*> argsobj(cx, &obj->as<MappedArgumentsObject>()); + + // Steps 2-3. + bool isMapped = false; + if (JSID_IS_INT(id)) { + unsigned arg = unsigned(JSID_TO_INT(id)); + isMapped = arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg); + } + + // Step 4. + Rooted<PropertyDescriptor> newArgDesc(cx, desc); + if (!desc.isAccessorDescriptor() && isMapped) { + // In this case the live mapping is supposed to keep working, + // we have to pass along the Getter/Setter otherwise they are overwritten. + newArgDesc.setGetter(MappedArgGetter); + newArgDesc.setSetter(MappedArgSetter); + } + + // Steps 5-6. NativeDefineProperty will lookup [[Value]] for us. + if (!NativeDefineProperty(cx, obj.as<NativeObject>(), id, newArgDesc, result)) + return false; + // Step 7. + if (!result.ok()) + return true; + + // Step 8. + if (isMapped) { + unsigned arg = unsigned(JSID_TO_INT(id)); + if (desc.isAccessorDescriptor()) { + if (!argsobj->markElementDeleted(cx, arg)) + return false; + } else { + if (desc.hasValue()) { + RootedFunction callee(cx, &argsobj->callee()); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee)); + if (!script) + return false; + argsobj->setElement(cx, arg, desc.value()); + if (arg < script->functionNonDelazifying()->nargs()) + TypeScript::SetArgument(cx, script, arg, desc.value()); + } + if (desc.hasWritable() && !desc.writable()) { + if (!argsobj->markElementDeleted(cx, arg)) + return false; + } + } + } + + // Step 9. + return result.succeed(); +} + static bool UnmappedArgGetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp) { @@ -804,6 +862,11 @@ const ClassOps MappedArgumentsObject::classOps_ = { ArgumentsObject::trace }; +const ObjectOps MappedArgumentsObject::objectOps_ = { + nullptr, /* lookupProperty */ + MappedArgumentsObject::obj_defineProperty +}; + const Class MappedArgumentsObject::class_ = { "Arguments", JSCLASS_DELAY_METADATA_BUILDER | @@ -811,7 +874,10 @@ const Class MappedArgumentsObject::class_ = { JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | JSCLASS_SKIP_NURSERY_FINALIZE | JSCLASS_BACKGROUND_FINALIZE, - &MappedArgumentsObject::classOps_ + &MappedArgumentsObject::classOps_, + nullptr, + nullptr, + &MappedArgumentsObject::objectOps_ }; /* diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index 247c7cd94..988e41951 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -389,6 +389,7 @@ class ArgumentsObject : public NativeObject class MappedArgumentsObject : public ArgumentsObject { static const ClassOps classOps_; + static const ObjectOps objectOps_; public: static const Class class_; @@ -410,6 +411,8 @@ class MappedArgumentsObject : public ArgumentsObject private: static bool obj_enumerate(JSContext* cx, HandleObject obj); static bool obj_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp); + static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, + Handle<JS::PropertyDescriptor> desc, ObjectOpResult& result); }; class UnmappedArgumentsObject : public ArgumentsObject diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 1053fa99d..392724b21 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -140,7 +140,7 @@ static const Class ArrayBufferObjectProtoClass = { static JSObject* CreateArrayBufferPrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &ArrayBufferObjectProtoClass); + return GlobalObject::createBlankPrototype(cx, cx->global(), &ArrayBufferObjectProtoClass); } static const ClassOps ArrayBufferObjectClassOps = { @@ -344,7 +344,7 @@ ArrayBufferObject::detach(JSContext* cx, Handle<ArrayBufferObject*> buffer, // Make sure the global object's group has been instantiated, so the // flag change will be observed. AutoEnterOOMUnsafeRegion oomUnsafe; - if (!cx->global()->getGroup(cx)) + if (!JSObject::getGroup(cx, cx->global())) oomUnsafe.crash("ArrayBufferObject::detach"); MarkObjectGroupFlags(cx, cx->global(), OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER); cx->compartment()->detachedTypedObjects = 1; diff --git a/js/src/vm/AsyncFunction.cpp b/js/src/vm/AsyncFunction.cpp index f50c87114..e14b77424 100644 --- a/js/src/vm/AsyncFunction.cpp +++ b/js/src/vm/AsyncFunction.cpp @@ -118,7 +118,7 @@ js::WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleOb RootedAtom funName(cx, unwrapped->explicitName()); uint16_t length; - if (!unwrapped->getLength(cx, &length)) + if (!JSFunction::getLength(cx, unwrapped, &length)) return nullptr; // Steps 3 (partially). diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 8a36df083..fd1c9f5e6 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -38,6 +38,7 @@ macro(Bool32x4, Bool32x4, "Bool32x4") \ macro(Bool64x2, Bool64x2, "Bool64x2") \ macro(boundWithSpace, boundWithSpace, "bound ") \ + macro(break, break_, "break") \ macro(breakdown, breakdown, "breakdown") \ macro(buffer, buffer, "buffer") \ macro(builder, builder, "builder") \ @@ -52,8 +53,10 @@ macro(callee, callee, "callee") \ macro(caller, caller, "caller") \ macro(callFunction, callFunction, "callFunction") \ + macro(case, case_, "case") \ macro(caseFirst, caseFirst, "caseFirst") \ - macro(class_, class_, "class") \ + macro(catch, catch_, "catch") \ + macro(class, class_, "class") \ macro(close, close, "close") \ macro(Collator, Collator, "Collator") \ macro(CollatorCompareGet, CollatorCompareGet, "Intl_Collator_compare_get") \ @@ -62,10 +65,14 @@ macro(comma, comma, ",") \ macro(compare, compare, "compare") \ macro(configurable, configurable, "configurable") \ + macro(const, const_, "const") \ macro(construct, construct, "construct") \ macro(constructContentFunction, constructContentFunction, "constructContentFunction") \ macro(constructor, constructor, "constructor") \ + macro(continue, continue_, "continue") \ macro(ConvertAndCopyTo, ConvertAndCopyTo, "ConvertAndCopyTo") \ + macro(CopyDataProperties, CopyDataProperties, "CopyDataProperties") \ + macro(CopyDataPropertiesUnfiltered, CopyDataPropertiesUnfiltered, "CopyDataPropertiesUnfiltered") \ macro(copyWithin, copyWithin, "copyWithin") \ macro(count, count, "count") \ macro(CreateResolvingFunctions, CreateResolvingFunctions, "CreateResolvingFunctions") \ @@ -76,28 +83,32 @@ macro(DateTimeFormatFormatToParts, DateTimeFormatFormatToParts, "Intl_DateTimeFormat_formatToParts") \ macro(day, day, "day") \ macro(dayPeriod, dayPeriod, "dayPeriod") \ + macro(debugger, debugger, "debugger") \ macro(decodeURI, decodeURI, "decodeURI") \ macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \ macro(DefaultBaseClassConstructor, DefaultBaseClassConstructor, "DefaultBaseClassConstructor") \ macro(DefaultDerivedClassConstructor, DefaultDerivedClassConstructor, "DefaultDerivedClassConstructor") \ - macro(default_, default_, "default") \ + macro(default, default_, "default") \ macro(defineGetter, defineGetter, "__defineGetter__") \ macro(defineProperty, defineProperty, "defineProperty") \ macro(defineSetter, defineSetter, "__defineSetter__") \ macro(delete, delete_, "delete") \ macro(deleteProperty, deleteProperty, "deleteProperty") \ macro(displayURL, displayURL, "displayURL") \ + macro(do, do_, "do") \ macro(done, done, "done") \ macro(dotGenerator, dotGenerator, ".generator") \ macro(dotThis, dotThis, ".this") \ macro(each, each, "each") \ macro(elementType, elementType, "elementType") \ + macro(else, else_, "else") \ macro(empty, empty, "") \ macro(emptyRegExp, emptyRegExp, "(?:)") \ macro(encodeURI, encodeURI, "encodeURI") \ macro(encodeURIComponent, encodeURIComponent, "encodeURIComponent") \ macro(endTimestamp, endTimestamp, "endTimestamp") \ macro(entries, entries, "entries") \ + macro(enum, enum_, "enum") \ macro(enumerable, enumerable, "enumerable") \ macro(enumerate, enumerate, "enumerate") \ macro(era, era, "era") \ @@ -105,11 +116,14 @@ macro(escape, escape, "escape") \ macro(eval, eval, "eval") \ macro(exec, exec, "exec") \ + macro(export, export_, "export") \ + macro(extends, extends, "extends") \ macro(false, false_, "false") \ macro(fieldOffsets, fieldOffsets, "fieldOffsets") \ macro(fieldTypes, fieldTypes, "fieldTypes") \ macro(fileName, fileName, "fileName") \ macro(fill, fill, "fill") \ + macro(finally, finally_, "finally") \ macro(find, find, "find") \ macro(findIndex, findIndex, "findIndex") \ macro(firstDayOfWeek, firstDayOfWeek, "firstDayOfWeek") \ @@ -121,6 +135,7 @@ macro(Float32x4, Float32x4, "Float32x4") \ macro(float64, float64, "float64") \ macro(Float64x2, Float64x2, "Float64x2") \ + macro(for, for_, "for") \ macro(forceInterpreter, forceInterpreter, "forceInterpreter") \ macro(forEach, forEach, "forEach") \ macro(format, format, "format") \ @@ -146,8 +161,12 @@ macro(hasOwn, hasOwn, "hasOwn") \ macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \ macro(hour, hour, "hour") \ + macro(if, if_, "if") \ macro(ignoreCase, ignoreCase, "ignoreCase") \ macro(ignorePunctuation, ignorePunctuation, "ignorePunctuation") \ + macro(implements, implements, "implements") \ + macro(import, import, "import") \ + macro(in, in, "in") \ macro(includes, includes, "includes") \ macro(incumbentGlobal, incumbentGlobal, "incumbentGlobal") \ macro(index, index, "index") \ @@ -158,12 +177,14 @@ macro(innermost, innermost, "innermost") \ macro(inNursery, inNursery, "inNursery") \ macro(input, input, "input") \ + macro(instanceof, instanceof, "instanceof") \ macro(int8, int8, "int8") \ macro(int16, int16, "int16") \ macro(int32, int32, "int32") \ macro(Int8x16, Int8x16, "Int8x16") \ macro(Int16x8, Int16x8, "Int16x8") \ macro(Int32x4, Int32x4, "Int32x4") \ + macro(interface, interface, "interface") \ macro(InterpretGeneratorResume, InterpretGeneratorResume, "InterpretGeneratorResume") \ macro(isEntryPoint, isEntryPoint, "isEntryPoint") \ macro(isExtensible, isExtensible, "isExtensible") \ @@ -217,6 +238,7 @@ macro(noFilename, noFilename, "noFilename") \ macro(nonincrementalReason, nonincrementalReason, "nonincrementalReason") \ macro(noStack, noStack, "noStack") \ + macro(notes, notes, "notes") \ macro(NumberFormat, NumberFormat, "NumberFormat") \ macro(NumberFormatFormatGet, NumberFormatFormatGet, "Intl_NumberFormat_format_get") \ macro(numeric, numeric, "numeric") \ @@ -238,13 +260,18 @@ macro(other, other, "other") \ macro(outOfMemory, outOfMemory, "out of memory") \ macro(ownKeys, ownKeys, "ownKeys") \ + macro(Object_valueOf, Object_valueOf, "Object_valueOf") \ + macro(package, package, "package") \ macro(parseFloat, parseFloat, "parseFloat") \ macro(parseInt, parseInt, "parseInt") \ macro(pattern, pattern, "pattern") \ macro(pending, pending, "pending") \ + macro(public, public_, "public") \ macro(preventExtensions, preventExtensions, "preventExtensions") \ + macro(private, private_, "private") \ macro(promise, promise, "promise") \ macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \ + macro(protected, protected_, "protected") \ macro(proto, proto, "__proto__") \ macro(prototype, prototype, "prototype") \ macro(proxy, proxy, "proxy") \ @@ -293,10 +320,12 @@ macro(StructType, StructType, "StructType") \ macro(style, style, "style") \ macro(super, super, "super") \ + macro(switch, switch_, "switch") \ macro(Symbol_iterator_fun, Symbol_iterator_fun, "[Symbol.iterator]") \ macro(target, target, "target") \ macro(test, test, "test") \ macro(then, then, "then") \ + macro(this, this_, "this") \ macro(throw, throw_, "throw") \ macro(timestamp, timestamp, "timestamp") \ macro(timeZone, timeZone, "timeZone") \ @@ -309,7 +338,9 @@ macro(toString, toString, "toString") \ macro(toUTCString, toUTCString, "toUTCString") \ macro(true, true_, "true") \ + macro(try, try_, "try") \ macro(type, type, "type") \ + macro(typeof, typeof_, "typeof") \ macro(uint8, uint8, "uint8") \ macro(uint8Clamped, uint8Clamped, "uint8Clamped") \ macro(uint16, uint16, "uint16") \ @@ -329,6 +360,7 @@ macro(useAsm, useAsm, "use asm") \ macro(useGrouping, useGrouping, "useGrouping") \ macro(useStrict, useStrict, "use strict") \ + macro(void, void_, "void") \ macro(value, value, "value") \ macro(valueOf, valueOf, "valueOf") \ macro(values, values, "values") \ @@ -343,6 +375,8 @@ macro(weekday, weekday, "weekday") \ macro(weekendEnd, weekendEnd, "weekendEnd") \ macro(weekendStart, weekendStart, "weekendStart") \ + macro(while, while_, "while") \ + macro(with, with, "with") \ macro(writable, writable, "writable") \ macro(year, year, "year") \ macro(yield, yield, "yield") \ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index d16781326..d68d1b75e 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -224,7 +224,7 @@ EnsureFunctionHasScript(JSContext* cx, HandleFunction fun) { if (fun->isInterpretedLazy()) { AutoCompartment ac(cx, fun); - return !!fun->getOrCreateScript(cx); + return !!JSFunction::getOrCreateScript(cx, fun); } return true; } @@ -2234,7 +2234,7 @@ Debugger::appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame RootedAtom ctorName(cx); { AutoCompartment ac(cx, obj); - if (!obj->constructorDisplayAtom(cx, &ctorName)) + if (!JSObject::constructorDisplayAtom(cx, obj, &ctorName)) return false; } @@ -7227,8 +7227,8 @@ static const JSFunctionSpec DebuggerSource_methods[] = { /* static */ NativeObject* DebuggerFrame::initClass(JSContext* cx, HandleObject dbgCtor, HandleObject obj) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); return InitClass(cx, dbgCtor, objProto, &class_, construct, 0, properties_, methods_, nullptr, nullptr); @@ -8666,6 +8666,14 @@ DebuggerObject::errorMessageNameGetter(JSContext *cx, unsigned argc, Value* vp) } /* static */ bool +DebuggerObject::errorNotesGetter(JSContext *cx, unsigned argc, Value* vp) +{ + THIS_DEBUGOBJECT(cx, argc, vp, "get errorNotes", args, object) + + return DebuggerObject::getErrorNotes(cx, object, args.rval()); +} + +/* static */ bool DebuggerObject::errorLineNumberGetter(JSContext *cx, unsigned argc, Value* vp) { THIS_DEBUGOBJECT(cx, argc, vp, "get errorLineNumber", args, object) @@ -9324,6 +9332,7 @@ const JSPropertySpec DebuggerObject::properties_[] = { JS_PSG("global", DebuggerObject::globalGetter, 0), JS_PSG("allocationSite", DebuggerObject::allocationSiteGetter, 0), JS_PSG("errorMessageName", DebuggerObject::errorMessageNameGetter, 0), + JS_PSG("errorNotes", DebuggerObject::errorNotesGetter, 0), JS_PSG("errorLineNumber", DebuggerObject::errorLineNumberGetter, 0), JS_PSG("errorColumnNumber", DebuggerObject::errorColumnNumberGetter, 0), JS_PSG("isProxy", DebuggerObject::isProxyGetter, 0), @@ -9376,8 +9385,8 @@ const JSFunctionSpec DebuggerObject::methods_[] = { /* static */ NativeObject* DebuggerObject::initClass(JSContext* cx, HandleObject obj, HandleObject debugCtor) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); RootedNativeObject objectProto(cx, InitClass(cx, debugCtor, objProto, &class_, construct, 0, properties_, @@ -9611,7 +9620,7 @@ DebuggerObject::getBoundArguments(JSContext* cx, HandleDebuggerObject object, if (!result.resize(length)) return false; for (size_t i = 0; i < length; i++) { - result[i].set(referent->getBoundFunctionArgument(cx, i)); + result[i].set(referent->getBoundFunctionArgument(i)); if (!dbg->wrapDebuggeeValue(cx, result[i])) return false; } @@ -9695,6 +9704,30 @@ DebuggerObject::getErrorMessageName(JSContext* cx, HandleDebuggerObject object, } /* static */ bool +DebuggerObject::getErrorNotes(JSContext* cx, HandleDebuggerObject object, + MutableHandleValue result) +{ + RootedObject referent(cx, object->referent()); + JSErrorReport* report; + if (!getErrorReport(cx, referent, report)) + return false; + + if (!report) { + result.setUndefined(); + return true; + } + + RootedObject errorNotesArray(cx, CreateErrorNotesArray(cx, report)); + if (!errorNotesArray) + return false; + + if (!cx->compartment()->wrap(cx, &errorNotesArray)) + return false; + result.setObject(*errorNotesArray); + return true; +} + +/* static */ bool DebuggerObject::getErrorLineNumber(JSContext* cx, HandleDebuggerObject object, MutableHandleValue result) { @@ -10577,8 +10610,8 @@ const JSFunctionSpec DebuggerEnvironment::methods_[] = { /* static */ NativeObject* DebuggerEnvironment::initClass(JSContext* cx, HandleObject dbgCtor, HandleObject obj) { - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); - RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx)); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); + RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); return InitClass(cx, dbgCtor, objProto, &DebuggerEnvironment::class_, construct, 0, properties_, methods_, nullptr, nullptr); @@ -10774,7 +10807,8 @@ DebuggerEnvironment::getVariable(JSContext* cx, HandleDebuggerEnvironment enviro // // See wrapDebuggeeValue for how the sentinel values are wrapped. if (referent->is<DebugEnvironmentProxy>()) { - if (!referent->as<DebugEnvironmentProxy>().getMaybeSentinelValue(cx, id, result)) + Rooted<DebugEnvironmentProxy*> env(cx, &referent->as<DebugEnvironmentProxy>()); + if (!DebugEnvironmentProxy::getMaybeSentinelValue(cx, env, id, result)) return false; } else { if (!GetProperty(cx, referent, referent, id, result)) @@ -10942,9 +10976,9 @@ JS_DefineDebuggerObject(JSContext* cx, HandleObject obj) memoryProto(cx); RootedObject debuggeeWouldRunProto(cx); RootedValue debuggeeWouldRunCtor(cx); - Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>()); + Handle<GlobalObject*> global = obj.as<GlobalObject>(); - objProto = global->getOrCreateObjectPrototype(cx); + objProto = GlobalObject::getOrCreateObjectPrototype(cx, global); if (!objProto) return false; debugProto = InitClass(cx, obj, diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 3239ade6d..cdcf2d67f 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -1246,6 +1246,8 @@ class DebuggerObject : public NativeObject MutableHandleObject result); static MOZ_MUST_USE bool getErrorMessageName(JSContext* cx, HandleDebuggerObject object, MutableHandleString result); + static MOZ_MUST_USE bool getErrorNotes(JSContext* cx, HandleDebuggerObject object, + MutableHandleValue result); static MOZ_MUST_USE bool getErrorLineNumber(JSContext* cx, HandleDebuggerObject object, MutableHandleValue result); static MOZ_MUST_USE bool getErrorColumnNumber(JSContext* cx, HandleDebuggerObject object, @@ -1371,6 +1373,7 @@ class DebuggerObject : public NativeObject static MOZ_MUST_USE bool globalGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool allocationSiteGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool errorMessageNameGetter(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool errorNotesGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool errorLineNumberGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool errorColumnNumberGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool isProxyGetter(JSContext* cx, unsigned argc, Value* vp); diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp index 34c39eabf..a5aac2ab4 100644 --- a/js/src/vm/EnvironmentObject.cpp +++ b/js/src/vm/EnvironmentObject.cpp @@ -816,7 +816,7 @@ NonSyntacticVariablesObject::create(JSContext* cx) return nullptr; MOZ_ASSERT(obj->isUnqualifiedVarObj()); - if (!obj->setQualifiedVarObj(cx)) + if (!JSObject::setQualifiedVarObj(cx, obj)) return nullptr; obj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment()); @@ -957,7 +957,7 @@ LexicalEnvironmentObject::createHollowForDebug(JSContext* cx, Handle<LexicalScop return nullptr; } - if (!env->setFlags(cx, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE)) + if (!JSObject::setFlags(cx, env, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE)) return nullptr; env->initScopeUnchecked(scope); @@ -1425,7 +1425,8 @@ class DebugEnvironmentProxyHandler : public BaseProxyHandler /* Handle unaliased formals, vars, lets, and consts at function scope. */ if (env->is<CallObject>()) { CallObject& callobj = env->as<CallObject>(); - RootedScript script(cx, callobj.callee().getOrCreateScript(cx)); + RootedFunction fun(cx, &callobj.callee()); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx)) return false; @@ -2233,11 +2234,11 @@ DebugEnvironmentProxy::isForDeclarative() const e.is<LexicalEnvironmentObject>(); } -bool -DebugEnvironmentProxy::getMaybeSentinelValue(JSContext* cx, HandleId id, MutableHandleValue vp) +/* static */ bool +DebugEnvironmentProxy::getMaybeSentinelValue(JSContext* cx, Handle<DebugEnvironmentProxy*> env, + HandleId id, MutableHandleValue vp) { - Rooted<DebugEnvironmentProxy*> self(cx, this); - return DebugEnvironmentProxyHandler::singleton.getMaybeSentinelValue(cx, self, id, vp); + return DebugEnvironmentProxyHandler::singleton.getMaybeSentinelValue(cx, env, id, vp); } bool @@ -2960,7 +2961,7 @@ js::GetDebugEnvironmentForFunction(JSContext* cx, HandleFunction fun) MOZ_ASSERT(CanUseDebugEnvironmentMaps(cx)); if (!DebugEnvironments::updateLiveEnvironments(cx)) return nullptr; - JSScript* script = fun->getOrCreateScript(cx); + JSScript* script = JSFunction::getOrCreateScript(cx, fun); if (!script) return nullptr; EnvironmentIter ei(cx, fun->environment(), script->enclosingScope()); @@ -3468,11 +3469,13 @@ RemoveReferencedNames(JSContext* cx, HandleScript script, PropertyNameSet& remai if (script->hasObjects()) { ObjectArray* objects = script->objects(); + RootedFunction fun(cx); + RootedScript innerScript(cx); for (size_t i = 0; i < objects->length; i++) { JSObject* obj = objects->vector[i]; if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) { - JSFunction* fun = &obj->as<JSFunction>(); - RootedScript innerScript(cx, fun->getOrCreateScript(cx)); + fun = &obj->as<JSFunction>(); + innerScript = JSFunction::getOrCreateScript(cx, fun); if (!innerScript) return false; @@ -3535,11 +3538,13 @@ AnalyzeEntrainedVariablesInScript(JSContext* cx, HandleScript script, HandleScri if (innerScript->hasObjects()) { ObjectArray* objects = innerScript->objects(); + RootedFunction fun(cx); + RootedScript innerInnerScript(cx); for (size_t i = 0; i < objects->length; i++) { JSObject* obj = objects->vector[i]; if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) { - JSFunction* fun = &obj->as<JSFunction>(); - RootedScript innerInnerScript(cx, fun->getOrCreateScript(cx)); + fun = &obj->as<JSFunction>(); + innerInnerScript = JSFunction::getOrCreateScript(cx, fun); if (!innerInnerScript || !AnalyzeEntrainedVariablesInScript(cx, script, innerInnerScript)) { @@ -3570,11 +3575,13 @@ js::AnalyzeEntrainedVariables(JSContext* cx, HandleScript script) return true; ObjectArray* objects = script->objects(); + RootedFunction fun(cx); + RootedScript innerScript(cx); for (size_t i = 0; i < objects->length; i++) { JSObject* obj = objects->vector[i]; if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) { - JSFunction* fun = &obj->as<JSFunction>(); - RootedScript innerScript(cx, fun->getOrCreateScript(cx)); + fun = &obj->as<JSFunction>(); + innerScript = JSFunction::getOrCreateScript(cx, fun); if (!innerScript) return false; diff --git a/js/src/vm/EnvironmentObject.h b/js/src/vm/EnvironmentObject.h index 032286116..c527cd1b0 100644 --- a/js/src/vm/EnvironmentObject.h +++ b/js/src/vm/EnvironmentObject.h @@ -872,7 +872,8 @@ class DebugEnvironmentProxy : public ProxyObject // Get a property by 'id', but returns sentinel values instead of throwing // on exceptional cases. - bool getMaybeSentinelValue(JSContext* cx, HandleId id, MutableHandleValue vp); + static bool getMaybeSentinelValue(JSContext* cx, Handle<DebugEnvironmentProxy*> env, + HandleId id, MutableHandleValue vp); // Returns true iff this is a function environment with its own this-binding // (all functions except arrow functions and generator expression lambdas). diff --git a/js/src/vm/ErrorObject.cpp b/js/src/vm/ErrorObject.cpp index d8d29830b..271132801 100644 --- a/js/src/vm/ErrorObject.cpp +++ b/js/src/vm/ErrorObject.cpp @@ -29,11 +29,11 @@ js::ErrorObject::assignInitialShape(ExclusiveContext* cx, Handle<ErrorObject*> o { MOZ_ASSERT(obj->empty()); - if (!obj->addDataProperty(cx, cx->names().fileName, FILENAME_SLOT, 0)) + if (!NativeObject::addDataProperty(cx, obj, cx->names().fileName, FILENAME_SLOT, 0)) return nullptr; - if (!obj->addDataProperty(cx, cx->names().lineNumber, LINENUMBER_SLOT, 0)) + if (!NativeObject::addDataProperty(cx, obj, cx->names().lineNumber, LINENUMBER_SLOT, 0)) return nullptr; - return obj->addDataProperty(cx, cx->names().columnNumber, COLUMNNUMBER_SLOT, 0); + return NativeObject::addDataProperty(cx, obj, cx->names().columnNumber, COLUMNNUMBER_SLOT, 0); } /* static */ bool @@ -57,7 +57,7 @@ js::ErrorObject::init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type, // |new Error()|. RootedShape messageShape(cx); if (message) { - messageShape = obj->addDataProperty(cx, cx->names().message, MESSAGE_SLOT, 0); + messageShape = NativeObject::addDataProperty(cx, obj, cx->names().message, MESSAGE_SLOT, 0); if (!messageShape) return false; MOZ_ASSERT(messageShape->slot() == MESSAGE_SLOT); diff --git a/js/src/vm/ErrorReporting.cpp b/js/src/vm/ErrorReporting.cpp new file mode 100644 index 000000000..5877f3a4b --- /dev/null +++ b/js/src/vm/ErrorReporting.cpp @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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 "vm/ErrorReporting.h" + +#include "mozilla/Move.h" + +#include <stdarg.h> + +#include "jscntxt.h" +#include "jsexn.h" + +using mozilla::Move; + +using JS::UniqueTwoByteChars; + +void +CallWarningReporter(JSContext* cx, JSErrorReport* reportp) +{ + MOZ_ASSERT(reportp); + MOZ_ASSERT(JSREPORT_IS_WARNING(reportp->flags)); + + if (JS::WarningReporter warningReporter = cx->runtime()->warningReporter) + warningReporter(cx, reportp); +} + +void +CompileError::throwError(JSContext* cx) +{ + if (JSREPORT_IS_WARNING(flags)) { + CallWarningReporter(cx, this); + return; + } + + // If there's a runtime exception type associated with this error + // number, set that as the pending exception. For errors occuring at + // compile time, this is very likely to be a JSEXN_SYNTAXERR. + // + // If an exception is thrown but not caught, the JSREPORT_EXCEPTION + // flag will be set in report.flags. Proper behavior for an error + // reporter is to ignore a report with this flag for all but top-level + // compilation errors. The exception will remain pending, and so long + // as the non-top-level "load", "eval", or "compile" native function + // returns false, the top-level reporter will eventually receive the + // uncaught exception report. + ErrorToException(cx, this, nullptr, nullptr); +} + +bool +ReportCompileWarning(JSContext* cx, ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes, + unsigned flags, unsigned errorNumber, va_list args) +{ + // On the main thread, report the error immediately. When compiling off + // thread, save the error so that the thread finishing the parse can report + // it later. + CompileError tempErr; + CompileError* err = &tempErr; + if (!cx->isJSContext() && !cx->addPendingCompileError(&err)) { + return false; + } + + err->notes = Move(notes); + err->flags = flags; + err->errorNumber = errorNumber; + + err->filename = metadata.filename; + err->lineno = metadata.lineNumber; + err->column = metadata.columnNumber; + err->isMuted = metadata.isMuted; + + if (UniqueTwoByteChars lineOfContext = Move(metadata.lineOfContext)) + err->initOwnedLinebuf(lineOfContext.release(), metadata.lineLength, metadata.tokenOffset); + + if (!ExpandErrorArgumentsVA(cx, GetErrorMessage, nullptr, errorNumber, + nullptr, ArgumentsAreLatin1, err, args)) + { + return false; + } + + if (cx->isJSContext()) { + err->throwError(cx->asJSContext()); + } + + return true; +} + +void +ReportCompileError(JSContext* cx, ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes, + unsigned flags, unsigned errorNumber, va_list args) +{ + // On the main thread, report the error immediately. When compiling off + // thread, save the error so that the thread finishing the parse can report + // it later. + CompileError tempErr; + CompileError* err = &tempErr; + if (!cx->isJSContext() && !cx->addPendingCompileError(&err)) { + return; + } + + err->notes = Move(notes); + err->flags = flags; + err->errorNumber = errorNumber; + + err->filename = metadata.filename; + err->lineno = metadata.lineNumber; + err->column = metadata.columnNumber; + err->isMuted = metadata.isMuted; + + if (UniqueTwoByteChars lineOfContext = Move(metadata.lineOfContext)) + err->initOwnedLinebuf(lineOfContext.release(), metadata.lineLength, metadata.tokenOffset); + + if (!ExpandErrorArgumentsVA(cx, GetErrorMessage, nullptr, errorNumber, + nullptr, ArgumentsAreLatin1, err, args)) + { + return; + } + + if (cx->isJSContext()) { + err->throwError(cx->asJSContext()); + } +} diff --git a/js/src/vm/ErrorReporting.h b/js/src/vm/ErrorReporting.h new file mode 100644 index 000000000..02bbe2c63 --- /dev/null +++ b/js/src/vm/ErrorReporting.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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 vm_ErrorReporting_h +#define vm_ErrorReporting_h + +#include "mozilla/Move.h" + +#include <stdarg.h> + +#include "jsapi.h" // for JSErrorNotes, JSErrorReport + +#include "js/UniquePtr.h" // for UniquePtr +#include "js/Utility.h" // for UniqueTwoByteChars + +struct JSContext; + +namespace js { + +/** + * Metadata for a compilation error (or warning) at a particular offset, or at + * no offset (i.e. with respect to a script overall). + */ +struct ErrorMetadata +{ + // The file/URL where the error occurred. + const char* filename; + + // The line and column numbers where the error occurred. If the error + // is with respect to the entire script and not with respect to a + // particular location, these will both be zero. + uint32_t lineNumber; + uint32_t columnNumber; + + // If the error occurs at a particular location, context surrounding the + // location of the error: the line that contained the error, or a small + // portion of it if the line is long. + // + // This information is provided on a best-effort basis: code populating + // ErrorMetadata instances isn't obligated to supply this. + JS::UniqueTwoByteChars lineOfContext; + + // If |lineOfContext| is non-null, its length. + size_t lineLength; + + // If |lineOfContext| is non-null, the offset within it of the token that + // triggered the error. + size_t tokenOffset; + + // Whether the error is "muted" because it derives from a cross-origin + // load. See the comment in TransitiveCompileOptions in jsapi.h for + // details. + bool isMuted; +}; + +class CompileError : public JSErrorReport +{ + public: + void throwError(JSContext* cx); +}; + +/** Send a JSErrorReport to the warningReporter callback. */ +extern void +CallWarningReporter(JSContext* cx, JSErrorReport* report); + +/** + * Report a compile error during script processing prior to execution of the + * script. + */ +extern void +ReportCompileError(ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes, + unsigned flags, unsigned errorNumber, va_list args); + +/** + * Report a compile warning during script processing prior to execution of the + * script. Returns true if the warning was successfully reported, false if an + * error occurred. + * + * This function DOES NOT respect an existing werror option. If the caller + * wishes such option to be respected, it must do so itself. + */ +extern MOZ_MUST_USE bool +ReportCompileWarning(JSContext* cx, ErrorMetadata&& metadata, UniquePtr<JSErrorNotes> notes, + unsigned flags, unsigned errorNumber, va_list args); + +} // namespace js + +#endif /* vm_ErrorReporting_h */ diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp index 690c0bf48..ba28501e6 100644 --- a/js/src/vm/GeneratorObject.cpp +++ b/js/src/vm/GeneratorObject.cpp @@ -256,7 +256,7 @@ static const JSFunctionSpec legacy_generator_methods[] = { static JSObject* NewSingletonObjectWithObjectPrototype(JSContext* cx, Handle<GlobalObject*> global) { - RootedObject proto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject); @@ -265,7 +265,7 @@ NewSingletonObjectWithObjectPrototype(JSContext* cx, Handle<GlobalObject*> globa JSObject* js::NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global) { - RootedObject proto(cx, global->getOrCreateFunctionPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global)); if (!proto) return nullptr; return NewObjectWithGivenProto<PlainObject>(cx, proto, SingletonObject); @@ -278,7 +278,7 @@ GlobalObject::initLegacyGeneratorProto(JSContext* cx, Handle<GlobalObject*> glob return true; RootedObject proto(cx, NewSingletonObjectWithObjectPrototype(cx, global)); - if (!proto || !proto->setDelegate(cx)) + if (!proto || !JSObject::setDelegate(cx, proto)) return false; if (!DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods)) return false; @@ -297,9 +297,9 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global) if (!iteratorProto) return false; - RootedObject genObjectProto(cx, global->createBlankPrototypeInheriting(cx, - &PlainObject::class_, - iteratorProto)); + RootedObject genObjectProto(cx, GlobalObject::createBlankPrototypeInheriting(cx, global, + &PlainObject::class_, + iteratorProto)); if (!genObjectProto) return false; if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods) || @@ -309,7 +309,7 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global) } RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global)); - if (!genFunctionProto || !genFunctionProto->setDelegate(cx)) + if (!genFunctionProto || !JSObject::setDelegate(cx, genFunctionProto)) return false; if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto) || !DefineToStringTag(cx, genFunctionProto, cx->names().GeneratorFunction)) diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index c90b6b85f..85707e1c6 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -329,15 +329,15 @@ GlobalObject::createInternal(JSContext* cx, const Class* clasp) cx->compartment()->initGlobal(*global); - if (!global->setQualifiedVarObj(cx)) + if (!JSObject::setQualifiedVarObj(cx, global)) return nullptr; - if (!global->setDelegate(cx)) + if (!JSObject::setDelegate(cx, global)) return nullptr; return global; } -GlobalObject* +/* static */ GlobalObject* GlobalObject::new_(JSContext* cx, const Class* clasp, JSPrincipals* principals, JS::OnNewGlobalHookOption hookOption, const JS::CompartmentOptions& options) @@ -398,7 +398,7 @@ GlobalObject::emptyGlobalScope() const GlobalObject::getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global, MutableHandleObject eval) { - if (!global->getOrCreateObjectPrototype(cx)) + if (!getOrCreateObjectPrototype(cx, global)) return false; eval.set(&global->getSlot(EVAL).toObject()); return true; @@ -573,7 +573,7 @@ GlobalObject::warnOnceAbout(JSContext* cx, HandleObject obj, WarnOnceFlag flag, return true; } -JSFunction* +/* static */ JSFunction* GlobalObject::createConstructor(JSContext* cx, Native ctor, JSAtom* nameArg, unsigned length, gc::AllocKind kind, const JSJitInfo* jitInfo) { @@ -595,28 +595,27 @@ CreateBlankProto(JSContext* cx, const Class* clasp, HandleObject proto, HandleOb RootedNativeObject blankProto(cx, NewNativeObjectWithGivenProto(cx, clasp, proto, SingletonObject)); - if (!blankProto || !blankProto->setDelegate(cx)) + if (!blankProto || !JSObject::setDelegate(cx, blankProto)) return nullptr; return blankProto; } -NativeObject* -GlobalObject::createBlankPrototype(JSContext* cx, const Class* clasp) +/* static */ NativeObject* +GlobalObject::createBlankPrototype(JSContext* cx, Handle<GlobalObject*> global, const Class* clasp) { - Rooted<GlobalObject*> self(cx, this); - RootedObject objectProto(cx, getOrCreateObjectPrototype(cx)); + RootedObject objectProto(cx, getOrCreateObjectPrototype(cx, global)); if (!objectProto) return nullptr; - return CreateBlankProto(cx, clasp, objectProto, self); + return CreateBlankProto(cx, clasp, objectProto, global); } -NativeObject* -GlobalObject::createBlankPrototypeInheriting(JSContext* cx, const Class* clasp, HandleObject proto) +/* static */ NativeObject* +GlobalObject::createBlankPrototypeInheriting(JSContext* cx, Handle<GlobalObject*> global, + const Class* clasp, HandleObject proto) { - Rooted<GlobalObject*> self(cx, this); - return CreateBlankProto(cx, clasp, proto, self); + return CreateBlankProto(cx, clasp, proto, global); } bool @@ -729,21 +728,20 @@ GlobalObject::hasRegExpStatics() const return !getSlot(REGEXP_STATICS).isUndefined(); } -RegExpStatics* -GlobalObject::getRegExpStatics(ExclusiveContext* cx) const +/* static */ RegExpStatics* +GlobalObject::getRegExpStatics(ExclusiveContext* cx, Handle<GlobalObject*> global) { MOZ_ASSERT(cx); - Rooted<GlobalObject*> self(cx, const_cast<GlobalObject*>(this)); RegExpStaticsObject* resObj = nullptr; - const Value& val = this->getSlot(REGEXP_STATICS); + const Value& val = global->getSlot(REGEXP_STATICS); if (!val.isObject()) { MOZ_ASSERT(val.isUndefined()); - resObj = RegExpStatics::create(cx, self); + resObj = RegExpStatics::create(cx, global); if (!resObj) return nullptr; - self->initSlot(REGEXP_STATICS, ObjectValue(*resObj)); + global->initSlot(REGEXP_STATICS, ObjectValue(*resObj)); } else { resObj = &val.toObject().as<RegExpStaticsObject>(); } @@ -866,7 +864,7 @@ GlobalObject::addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global, /* static */ bool GlobalObject::ensureModulePrototypesCreated(JSContext *cx, Handle<GlobalObject*> global) { - return global->getOrCreateObject(cx, MODULE_PROTO, initModuleProto) && - global->getOrCreateObject(cx, IMPORT_ENTRY_PROTO, initImportEntryProto) && - global->getOrCreateObject(cx, EXPORT_ENTRY_PROTO, initExportEntryProto); + return getOrCreateObject(cx, global, MODULE_PROTO, initModuleProto) && + getOrCreateObject(cx, global, IMPORT_ENTRY_PROTO, initImportEntryProto) && + getOrCreateObject(cx, global, EXPORT_ENTRY_PROTO, initExportEntryProto); } diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 3534ef2f6..5aacfc5dc 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -290,8 +290,8 @@ class GlobalObject : public NativeObject * Create a constructor function with the specified name and length using * ctor, a method which creates objects with the given class. */ - JSFunction* - createConstructor(JSContext* cx, JSNative ctor, JSAtom* name, unsigned length, + static JSFunction* + createConstructor(JSContext* cx, JSNative ctor, JSAtom* name, unsigned length, gc::AllocKind kind = gc::AllocKind::FUNCTION, const JSJitInfo* jitInfo = nullptr); @@ -303,48 +303,44 @@ class GlobalObject : public NativeObject * complete the minimal initialization to make the returned object safe to * touch. */ - NativeObject* createBlankPrototype(JSContext* cx, const js::Class* clasp); + static NativeObject* + createBlankPrototype(JSContext* cx, Handle<GlobalObject*> global, const js::Class* clasp); /* * Identical to createBlankPrototype, but uses proto as the [[Prototype]] * of the returned blank prototype. */ - NativeObject* createBlankPrototypeInheriting(JSContext* cx, const js::Class* clasp, - HandleObject proto); + static NativeObject* + createBlankPrototypeInheriting(JSContext* cx, Handle<GlobalObject*> global, + const js::Class* clasp, HandleObject proto); template <typename T> - T* createBlankPrototype(JSContext* cx) { - NativeObject* res = createBlankPrototype(cx, &T::class_); + static T* + createBlankPrototype(JSContext* cx, Handle<GlobalObject*> global) { + NativeObject* res = createBlankPrototype(cx, global, &T::class_); return res ? &res->template as<T>() : nullptr; } - NativeObject* getOrCreateObjectPrototype(JSContext* cx) { - if (functionObjectClassesInitialized()) - return &getPrototype(JSProto_Object).toObject().as<NativeObject>(); - RootedGlobalObject self(cx, this); - if (!ensureConstructor(cx, self, JSProto_Object)) + static NativeObject* + getOrCreateObjectPrototype(JSContext* cx, Handle<GlobalObject*> global) { + if (global->functionObjectClassesInitialized()) + return &global->getPrototype(JSProto_Object).toObject().as<NativeObject>(); + if (!ensureConstructor(cx, global, JSProto_Object)) return nullptr; - return &self->getPrototype(JSProto_Object).toObject().as<NativeObject>(); - } - - static NativeObject* getOrCreateObjectPrototype(JSContext* cx, Handle<GlobalObject*> global) { - return global->getOrCreateObjectPrototype(cx); + return &global->getPrototype(JSProto_Object).toObject().as<NativeObject>(); } - NativeObject* getOrCreateFunctionPrototype(JSContext* cx) { - if (functionObjectClassesInitialized()) - return &getPrototype(JSProto_Function).toObject().as<NativeObject>(); - RootedGlobalObject self(cx, this); - if (!ensureConstructor(cx, self, JSProto_Object)) + static NativeObject* + getOrCreateFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global) { + if (global->functionObjectClassesInitialized()) + return &global->getPrototype(JSProto_Function).toObject().as<NativeObject>(); + if (!ensureConstructor(cx, global, JSProto_Object)) return nullptr; - return &self->getPrototype(JSProto_Function).toObject().as<NativeObject>(); - } - - static NativeObject* getOrCreateFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global) { - return global->getOrCreateFunctionPrototype(cx); + return &global->getPrototype(JSProto_Function).toObject().as<NativeObject>(); } - static NativeObject* getOrCreateArrayPrototype(JSContext* cx, Handle<GlobalObject*> global) { + static NativeObject* + getOrCreateArrayPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_Array)) return nullptr; return &global->getPrototype(JSProto_Array).toObject().as<NativeObject>(); @@ -356,37 +352,43 @@ class GlobalObject : public NativeObject return nullptr; } - static NativeObject* getOrCreateBooleanPrototype(JSContext* cx, Handle<GlobalObject*> global) { + static NativeObject* + getOrCreateBooleanPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_Boolean)) return nullptr; return &global->getPrototype(JSProto_Boolean).toObject().as<NativeObject>(); } - static NativeObject* getOrCreateNumberPrototype(JSContext* cx, Handle<GlobalObject*> global) { + static NativeObject* + getOrCreateNumberPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_Number)) return nullptr; return &global->getPrototype(JSProto_Number).toObject().as<NativeObject>(); } - static NativeObject* getOrCreateStringPrototype(JSContext* cx, Handle<GlobalObject*> global) { + static NativeObject* + getOrCreateStringPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_String)) return nullptr; return &global->getPrototype(JSProto_String).toObject().as<NativeObject>(); } - static NativeObject* getOrCreateSymbolPrototype(JSContext* cx, Handle<GlobalObject*> global) { + static NativeObject* + getOrCreateSymbolPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_Symbol)) return nullptr; return &global->getPrototype(JSProto_Symbol).toObject().as<NativeObject>(); } - static NativeObject* getOrCreatePromisePrototype(JSContext* cx, Handle<GlobalObject*> global) { + static NativeObject* + getOrCreatePromisePrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_Promise)) return nullptr; return &global->getPrototype(JSProto_Promise).toObject().as<NativeObject>(); } - static NativeObject* getOrCreateRegExpPrototype(JSContext* cx, Handle<GlobalObject*> global) { + static NativeObject* + getOrCreateRegExpPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_RegExp)) return nullptr; return &global->getPrototype(JSProto_RegExp).toObject().as<NativeObject>(); @@ -398,28 +400,30 @@ class GlobalObject : public NativeObject return nullptr; } - static NativeObject* getOrCreateSavedFramePrototype(JSContext* cx, - Handle<GlobalObject*> global) { + static NativeObject* + getOrCreateSavedFramePrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_SavedFrame)) return nullptr; return &global->getPrototype(JSProto_SavedFrame).toObject().as<NativeObject>(); } - static JSObject* getOrCreateArrayBufferPrototype(JSContext* cx, Handle<GlobalObject*> global) { + static JSObject* + getOrCreateArrayBufferPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) return nullptr; return &global->getPrototype(JSProto_ArrayBuffer).toObject(); } - JSObject* getOrCreateSharedArrayBufferPrototype(JSContext* cx, Handle<GlobalObject*> global) { + static JSObject* + getOrCreateSharedArrayBufferPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer)) return nullptr; return &global->getPrototype(JSProto_SharedArrayBuffer).toObject(); } - static JSObject* getOrCreateCustomErrorPrototype(JSContext* cx, - Handle<GlobalObject*> global, - JSExnType exnType) + static JSObject* + getOrCreateCustomErrorPrototype(JSContext* cx, Handle<GlobalObject*> global, + JSExnType exnType) { JSProtoKey key = GetExceptionProtoKey(exnType); if (!ensureConstructor(cx, global, key)) @@ -439,35 +443,41 @@ class GlobalObject : public NativeObject return getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR); } - static NativeObject* getOrCreateSetPrototype(JSContext* cx, Handle<GlobalObject*> global) { + static NativeObject* + getOrCreateSetPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_Set)) return nullptr; return &global->getPrototype(JSProto_Set).toObject().as<NativeObject>(); } - static NativeObject* getOrCreateWeakSetPrototype(JSContext* cx, Handle<GlobalObject*> global) { + static NativeObject* + getOrCreateWeakSetPrototype(JSContext* cx, Handle<GlobalObject*> global) { if (!ensureConstructor(cx, global, JSProto_WeakSet)) return nullptr; return &global->getPrototype(JSProto_WeakSet).toObject().as<NativeObject>(); } - JSObject* getOrCreateIntlObject(JSContext* cx) { - return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Intl, initIntlObject); + static JSObject* + getOrCreateIntlObject(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, APPLICATION_SLOTS + JSProto_Intl, initIntlObject); } - JSObject* getOrCreateTypedObjectModule(JSContext* cx) { - return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_TypedObject, initTypedObjectModule); + static JSObject* + getOrCreateTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, APPLICATION_SLOTS + JSProto_TypedObject, + initTypedObjectModule); } - JSObject* getOrCreateSimdGlobalObject(JSContext* cx) { - return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_SIMD, initSimdObject); + static JSObject* + getOrCreateSimdGlobalObject(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, APPLICATION_SLOTS + JSProto_SIMD, initSimdObject); } // Get the type descriptor for one of the SIMD types. // simdType is one of the JS_SIMDTYPEREPR_* constants. // Implemented in builtin/SIMD.cpp. - static SimdTypeDescr* getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global, - SimdType simdType); + static SimdTypeDescr* + getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global, SimdType simdType); TypedObjectModuleObject& getTypedObjectModule() const; @@ -475,16 +485,19 @@ class GlobalObject : public NativeObject return &getPrototype(JSProto_Iterator).toObject(); } - JSObject* getOrCreateCollatorPrototype(JSContext* cx) { - return getOrCreateObject(cx, COLLATOR_PROTO, initIntlObject); + static JSObject* + getOrCreateCollatorPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, COLLATOR_PROTO, initIntlObject); } - JSObject* getOrCreateNumberFormatPrototype(JSContext* cx) { - return getOrCreateObject(cx, NUMBER_FORMAT_PROTO, initIntlObject); + static JSObject* + getOrCreateNumberFormatPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, NUMBER_FORMAT_PROTO, initIntlObject); } - JSObject* getOrCreateDateTimeFormatPrototype(JSContext* cx) { - return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initIntlObject); + static JSObject* + getOrCreateDateTimeFormatPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, DATE_TIME_FORMAT_PROTO, initIntlObject); } static bool ensureModulePrototypesCreated(JSContext *cx, Handle<GlobalObject*> global); @@ -539,88 +552,86 @@ class GlobalObject : public NativeObject private: typedef bool (*ObjectInitOp)(JSContext* cx, Handle<GlobalObject*> global); - JSObject* getOrCreateObject(JSContext* cx, unsigned slot, ObjectInitOp init) { - Value v = getSlotRef(slot); + static JSObject* + getOrCreateObject(JSContext* cx, Handle<GlobalObject*> global, unsigned slot, + ObjectInitOp init) + { + Value v = global->getSlotRef(slot); if (v.isObject()) return &v.toObject(); - RootedGlobalObject self(cx, this); - if (!init(cx, self)) + if (!init(cx, global)) return nullptr; - return &self->getSlot(slot).toObject(); + return &global->getSlot(slot).toObject(); } public: - static NativeObject* getOrCreateIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, ITERATOR_PROTO, initIteratorProto)); + static NativeObject* + getOrCreateIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return MaybeNativeObject(getOrCreateObject(cx, global, ITERATOR_PROTO, initIteratorProto)); } - static NativeObject* getOrCreateArrayIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, ARRAY_ITERATOR_PROTO, initArrayIteratorProto)); + static NativeObject* + getOrCreateArrayIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return MaybeNativeObject(getOrCreateObject(cx, global, ARRAY_ITERATOR_PROTO, + initArrayIteratorProto)); } - static NativeObject* getOrCreateStringIteratorPrototype(JSContext* cx, - Handle<GlobalObject*> global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, STRING_ITERATOR_PROTO, initStringIteratorProto)); + static NativeObject* + getOrCreateStringIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return MaybeNativeObject(getOrCreateObject(cx, global, STRING_ITERATOR_PROTO, + initStringIteratorProto)); } - static NativeObject* getOrCreateLegacyGeneratorObjectPrototype(JSContext* cx, - Handle<GlobalObject*> global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, LEGACY_GENERATOR_OBJECT_PROTO, - initLegacyGeneratorProto)); + static NativeObject* + getOrCreateLegacyGeneratorObjectPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return MaybeNativeObject(getOrCreateObject(cx, global, LEGACY_GENERATOR_OBJECT_PROTO, + initLegacyGeneratorProto)); } - static NativeObject* getOrCreateStarGeneratorObjectPrototype(JSContext* cx, - Handle<GlobalObject*> global) + static NativeObject* + getOrCreateStarGeneratorObjectPrototype(JSContext* cx, Handle<GlobalObject*> global) { - return MaybeNativeObject(global->getOrCreateObject(cx, STAR_GENERATOR_OBJECT_PROTO, initStarGenerators)); + return MaybeNativeObject(getOrCreateObject(cx, global, STAR_GENERATOR_OBJECT_PROTO, + initStarGenerators)); } - static NativeObject* getOrCreateStarGeneratorFunctionPrototype(JSContext* cx, - Handle<GlobalObject*> global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION_PROTO, initStarGenerators)); + static NativeObject* + getOrCreateStarGeneratorFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return MaybeNativeObject(getOrCreateObject(cx, global, STAR_GENERATOR_FUNCTION_PROTO, + initStarGenerators)); } - static JSObject* getOrCreateStarGeneratorFunction(JSContext* cx, - Handle<GlobalObject*> global) - { - return global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION, initStarGenerators); + static JSObject* + getOrCreateStarGeneratorFunction(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, STAR_GENERATOR_FUNCTION, initStarGenerators); } - static NativeObject* getOrCreateAsyncFunctionPrototype(JSContext* cx, - Handle<GlobalObject*> global) - { - return MaybeNativeObject(global->getOrCreateObject(cx, ASYNC_FUNCTION_PROTO, - initAsyncFunction)); + static NativeObject* + getOrCreateAsyncFunctionPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_FUNCTION_PROTO, + initAsyncFunction)); } - static JSObject* getOrCreateAsyncFunction(JSContext* cx, - Handle<GlobalObject*> global) - { - return global->getOrCreateObject(cx, ASYNC_FUNCTION, initAsyncFunction); + static JSObject* + getOrCreateAsyncFunction(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, ASYNC_FUNCTION, initAsyncFunction); } - static JSObject* getOrCreateMapIteratorPrototype(JSContext* cx, - Handle<GlobalObject*> global) - { - return global->getOrCreateObject(cx, MAP_ITERATOR_PROTO, initMapIteratorProto); + static JSObject* + getOrCreateMapIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, MAP_ITERATOR_PROTO, initMapIteratorProto); } - static JSObject* getOrCreateSetIteratorPrototype(JSContext* cx, - Handle<GlobalObject*> global) - { - return global->getOrCreateObject(cx, SET_ITERATOR_PROTO, initSetIteratorProto); + static JSObject* + getOrCreateSetIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, SET_ITERATOR_PROTO, initSetIteratorProto); } - JSObject* getOrCreateDataViewPrototype(JSContext* cx) { - RootedGlobalObject self(cx, this); - if (!ensureConstructor(cx, self, JSProto_DataView)) + static JSObject* + getOrCreateDataViewPrototype(JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_DataView)) return nullptr; - return &self->getPrototype(JSProto_DataView).toObject(); + return &global->getPrototype(JSProto_DataView).toObject(); } static JSFunction* @@ -678,8 +689,9 @@ class GlobalObject : public NativeObject return true; } - static bool getIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global, - HandlePropertyName name, MutableHandleValue value) + static bool + getIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global, + HandlePropertyName name, MutableHandleValue value) { bool exists = false; if (!GlobalObject::maybeGetIntrinsicValue(cx, global, name, value, &exists)) @@ -709,7 +721,8 @@ class GlobalObject : public NativeObject unsigned nargs, MutableHandleValue funVal); bool hasRegExpStatics() const; - RegExpStatics* getRegExpStatics(ExclusiveContext* cx) const; + static RegExpStatics* getRegExpStatics(ExclusiveContext* cx, + Handle<GlobalObject*> global); RegExpStatics* getAlreadyCreatedRegExpStatics() const; JSObject* getThrowTypeError() const { @@ -996,7 +1009,7 @@ GenericCreateConstructor(JSContext* cx, JSProtoKey key) // Note - We duplicate the trick from ClassName() so that we don't need to // include jsatominlines.h here. PropertyName* name = (&cx->names().Null)[key]; - return cx->global()->createConstructor(cx, ctor, name, length, kind, jitInfo); + return GlobalObject::createConstructor(cx, ctor, name, length, kind, jitInfo); } inline JSObject* @@ -1009,7 +1022,7 @@ GenericCreatePrototype(JSContext* cx, JSProtoKey key) if (!GlobalObject::ensureConstructor(cx, cx->global(), protoKey)) return nullptr; RootedObject parentProto(cx, &cx->global()->getPrototype(protoKey).toObject()); - return cx->global()->createBlankPrototypeInheriting(cx, clasp, parentProto); + return GlobalObject::createBlankPrototypeInheriting(cx, cx->global(), clasp, parentProto); } inline JSProtoKey diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index bd29d0c79..44915521f 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1291,7 +1291,7 @@ GlobalHelperThreadState::finishModuleParseTask(JSContext* cx, void* token) MOZ_ASSERT(script->module()); RootedModuleObject module(cx, script->module()); - module->fixEnvironmentsAfterCompartmentMerge(cx); + module->fixEnvironmentsAfterCompartmentMerge(); if (!ModuleObject::Freeze(cx, module)) return nullptr; diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index a2c8e220a..acfa8f74b 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -830,7 +830,7 @@ class FastCallGuard if (useIon_ && fun_) { if (!script_) { - script_ = fun_->getOrCreateScript(cx); + script_ = JSFunction::getOrCreateScript(cx, fun_); if (!script_) return false; } diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 0f83c3435..030f0f3b6 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -261,11 +261,16 @@ SetPropertyOperation(JSContext* cx, JSOp op, HandleValue lval, HandleId id, Hand } static JSFunction* -MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto) +MakeDefaultConstructor(JSContext* cx, HandleScript script, jsbytecode* pc, HandleObject proto) { + JSOp op = JSOp(*pc); + JSAtom* atom = script->getAtom(pc); bool derived = op == JSOP_DERIVEDCONSTRUCTOR; MOZ_ASSERT(derived == !!proto); + jssrcnote* classNote = GetSrcNote(cx, script, pc); + MOZ_ASSERT(classNote && SN_TYPE(classNote) == SRC_CLASS_SPAN); + PropertyName* lookup = derived ? cx->names().DefaultDerivedClassConstructor : cx->names().DefaultBaseClassConstructor; @@ -285,6 +290,17 @@ MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto) MOZ_ASSERT(ctor->infallibleIsDefaultClassConstructor(cx)); + // Create the script now, as the source span needs to be overridden for + // toString. Calling toString on a class constructor must not return the + // source for just the constructor function. + JSScript *ctorScript = JSFunction::getOrCreateScript(cx, ctor); + if (!ctorScript) + return nullptr; + uint32_t classStartOffset = GetSrcNoteOffset(classNote, 0); + uint32_t classEndOffset = GetSrcNoteOffset(classNote, 1); + ctorScript->setDefaultClassConstructorSpan(script->sourceObject(), classStartOffset, + classEndOffset); + return ctor; } @@ -373,7 +389,7 @@ js::RunScript(JSContext* cx, RunState& state) SPSEntryMarker marker(cx->runtime(), state.script()); - state.script()->ensureNonLazyCanonicalFunction(cx); + state.script()->ensureNonLazyCanonicalFunction(); if (jit::IsIonEnabled(cx)) { jit::MethodStatus status = jit::CanEnter(cx, state); @@ -446,7 +462,7 @@ js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args, MaybeConstruct } /* Invoke native functions. */ - JSFunction* fun = &args.callee().as<JSFunction>(); + RootedFunction fun(cx, &args.callee().as<JSFunction>()); if (construct != CONSTRUCT && fun->isClassConstructor()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CALL_CLASS_CONSTRUCTOR); return false; @@ -454,10 +470,16 @@ js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args, MaybeConstruct if (fun->isNative()) { MOZ_ASSERT_IF(construct, !fun->isConstructor()); - return CallJSNative(cx, fun->native(), args); + JSNative native = fun->native(); + if (!construct && args.ignoresReturnValue()) { + const JSJitInfo* jitInfo = fun->jitInfo(); + if (jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative) + native = jitInfo->ignoresReturnValueMethod; + } + return CallJSNative(cx, native, args); } - if (!fun->getOrCreateScript(cx)) + if (!JSFunction::getOrCreateScript(cx, fun)) return false; /* Run function until JSOP_RETRVAL, JSOP_RETURN or error. */ @@ -1543,7 +1565,7 @@ SetObjectElementOperation(JSContext* cx, HandleObject obj, HandleId id, HandleVa } } - if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx)) + if (obj->isNative() && !JSID_IS_INT(id) && !JSObject::setHadElementsAccess(cx, obj)) return false; ObjectOpResult result; @@ -2959,6 +2981,7 @@ CASE(JSOP_FUNAPPLY) CASE(JSOP_NEW) CASE(JSOP_CALL) +CASE(JSOP_CALL_IGNORES_RV) CASE(JSOP_CALLITER) CASE(JSOP_SUPERCALL) CASE(JSOP_FUNCALL) @@ -2967,10 +2990,11 @@ CASE(JSOP_FUNCALL) cx->runtime()->spsProfiler.updatePC(script, REGS.pc); MaybeConstruct construct = MaybeConstruct(*REGS.pc == JSOP_NEW || *REGS.pc == JSOP_SUPERCALL); + bool ignoresReturnValue = *REGS.pc == JSOP_CALL_IGNORES_RV; unsigned argStackSlots = GET_ARGC(REGS.pc) + construct; MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc)); - CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct); + CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct, ignoresReturnValue); JSFunction* maybeFun; bool isFunction = IsFunctionObject(args.calleev(), &maybeFun); @@ -3000,7 +3024,7 @@ CASE(JSOP_FUNCALL) { MOZ_ASSERT(maybeFun); ReservedRooted<JSFunction*> fun(&rootFunction0, maybeFun); - ReservedRooted<JSScript*> funScript(&rootScript0, fun->getOrCreateScript(cx)); + ReservedRooted<JSScript*> funScript(&rootScript0, JSFunction::getOrCreateScript(cx, fun)); if (!funScript) goto error; @@ -4174,8 +4198,8 @@ CASE(JSOP_DERIVEDCONSTRUCTOR) MOZ_ASSERT(REGS.sp[-1].isObject()); ReservedRooted<JSObject*> proto(&rootObject0, ®S.sp[-1].toObject()); - JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc), - proto); + JSFunction* constructor = MakeDefaultConstructor(cx, script, REGS.pc, proto); + if (!constructor) goto error; @@ -4185,8 +4209,7 @@ END_CASE(JSOP_DERIVEDCONSTRUCTOR) CASE(JSOP_CLASSCONSTRUCTOR) { - JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc), - nullptr); + JSFunction* constructor = MakeDefaultConstructor(cx, script, REGS.pc, nullptr); if (!constructor) goto error; PUSH_OBJECT(*constructor); @@ -4725,7 +4748,8 @@ js::RunOnceScriptPrologue(JSContext* cx, HandleScript script) // Force instantiation of the script's function's group to ensure the flag // is preserved in type information. - if (!script->functionNonDelazifying()->getGroup(cx)) + RootedFunction fun(cx, script->functionNonDelazifying()); + if (!JSObject::getGroup(cx, fun)) return false; MarkObjectGroupFlags(cx, script->functionNonDelazifying(), OBJECT_FLAG_RUNONCE_INVALIDATED); diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 052a3385c..e55e3db04 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -236,7 +236,7 @@ NativeObject::ensureDenseElements(ExclusiveContext* cx, uint32_t index, uint32_t } inline DenseElementResult -NativeObject::setOrExtendDenseElements(JSContext* cx, uint32_t start, const Value* vp, +NativeObject::setOrExtendDenseElements(ExclusiveContext* cx, uint32_t start, const Value* vp, uint32_t count, ShouldUpdateTypes updateTypes) { diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index a3f28653a..da0f59fe2 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -672,10 +672,10 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO */ if (shape != obj->lastProperty()) { shape = shape->previous(); - if (!obj->removeProperty(cx, id)) + if (!NativeObject::removeProperty(cx, obj, id)) return DenseElementResult::Failure; } else { - if (!obj->removeProperty(cx, id)) + if (!NativeObject::removeProperty(cx, obj, id)) return DenseElementResult::Failure; shape = obj->lastProperty(); } @@ -691,7 +691,7 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO * flag so that we will not start using sparse indexes again if we need * to grow the object. */ - if (!obj->clearFlag(cx, BaseShape::INDEXED)) + if (!NativeObject::clearFlag(cx, obj, BaseShape::INDEXED)) return DenseElementResult::Failure; return DenseElementResult::Success; @@ -996,23 +996,22 @@ NativeObject::freeSlot(ExclusiveContext* cx, uint32_t slot) setSlot(slot, UndefinedValue()); } -Shape* -NativeObject::addDataProperty(ExclusiveContext* cx, jsid idArg, uint32_t slot, unsigned attrs) +/* static */ Shape* +NativeObject::addDataProperty(ExclusiveContext* cx, HandleNativeObject obj, + jsid idArg, uint32_t slot, unsigned attrs) { MOZ_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); - RootedNativeObject self(cx, this); RootedId id(cx, idArg); - return addProperty(cx, self, id, nullptr, nullptr, slot, attrs, 0); + return addProperty(cx, obj, id, nullptr, nullptr, slot, attrs, 0); } -Shape* -NativeObject::addDataProperty(ExclusiveContext* cx, HandlePropertyName name, - uint32_t slot, unsigned attrs) +/* static */ Shape* +NativeObject::addDataProperty(ExclusiveContext* cx, HandleNativeObject obj, + HandlePropertyName name, uint32_t slot, unsigned attrs) { MOZ_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); - RootedNativeObject self(cx, this); RootedId id(cx, NameToId(name)); - return addProperty(cx, self, id, nullptr, nullptr, slot, attrs, 0); + return addProperty(cx, obj, id, nullptr, nullptr, slot, attrs, 0); } template <AllowGC allowGC> @@ -1046,7 +1045,7 @@ CallAddPropertyHook(ExclusiveContext* cx, HandleNativeObject obj, HandleShape sh RootedId id(cx, shape->propid()); if (!CallJSAddPropertyOp(cx->asJSContext(), addProperty, obj, id, value)) { - obj->removeProperty(cx, shape->propid()); + NativeObject::removeProperty(cx, obj, shape->propid()); return false; } } @@ -1118,7 +1117,7 @@ PurgeProtoChain(ExclusiveContext* cx, JSObject* objArg, HandleId id) shape = obj->as<NativeObject>().lookup(cx, id); if (shape) - return obj->as<NativeObject>().shadowingShapeChange(cx, *shape); + return NativeObject::shadowingShapeChange(cx, obj.as<NativeObject>(), *shape); obj = obj->staticPrototype(); } @@ -2529,7 +2528,7 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id, obj->setDenseElementHole(cx, JSID_TO_INT(id)); } else { - if (!obj->removeProperty(cx, id)) + if (!NativeObject::removeProperty(cx, obj, id)) return false; } diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index d9d8b8aec..9cc6d5436 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -491,8 +491,8 @@ class NativeObject : public ShapedObject void checkShapeConsistency() { } #endif - Shape* - replaceWithNewEquivalentShape(ExclusiveContext* cx, + static Shape* + replaceWithNewEquivalentShape(ExclusiveContext* cx, HandleNativeObject obj, Shape* existingShape, Shape* newShape = nullptr, bool accessorShape = false); @@ -510,7 +510,7 @@ class NativeObject : public ShapedObject */ bool setSlotSpan(ExclusiveContext* cx, uint32_t span); - bool toDictionaryMode(ExclusiveContext* cx); + static MOZ_MUST_USE bool toDictionaryMode(ExclusiveContext* cx, HandleNativeObject obj); private: friend class TenuringTracer; @@ -609,12 +609,15 @@ class NativeObject : public ShapedObject } public: - bool generateOwnShape(ExclusiveContext* cx, Shape* newShape = nullptr) { - return replaceWithNewEquivalentShape(cx, lastProperty(), newShape); + static MOZ_MUST_USE bool generateOwnShape(ExclusiveContext* cx, HandleNativeObject obj, + Shape* newShape = nullptr) + { + return replaceWithNewEquivalentShape(cx, obj, obj->lastProperty(), newShape); } - bool shadowingShapeChange(ExclusiveContext* cx, const Shape& shape); - bool clearFlag(ExclusiveContext* cx, BaseShape::Flag flag); + static MOZ_MUST_USE bool shadowingShapeChange(ExclusiveContext* cx, HandleNativeObject obj, + const Shape& shape); + static bool clearFlag(ExclusiveContext* cx, HandleNativeObject obj, BaseShape::Flag flag); // The maximum number of slots in an object. // |MAX_SLOTS_COUNT * sizeof(JS::Value)| shouldn't overflow @@ -741,10 +744,10 @@ class NativeObject : public ShapedObject bool allowDictionary = true); /* Add a data property whose id is not yet in this scope. */ - Shape* addDataProperty(ExclusiveContext* cx, - jsid id_, uint32_t slot, unsigned attrs); - Shape* addDataProperty(ExclusiveContext* cx, HandlePropertyName name, - uint32_t slot, unsigned attrs); + static Shape* addDataProperty(ExclusiveContext* cx, HandleNativeObject obj, + jsid id_, uint32_t slot, unsigned attrs); + static Shape* addDataProperty(ExclusiveContext* cx, HandleNativeObject obj, + HandlePropertyName name, uint32_t slot, unsigned attrs); /* Add or overwrite a property for id in this scope. */ static Shape* @@ -764,7 +767,7 @@ class NativeObject : public ShapedObject unsigned attrs, JSGetterOp getter, JSSetterOp setter); /* Remove the property named by id from this object. */ - bool removeProperty(ExclusiveContext* cx, jsid id); + static bool removeProperty(ExclusiveContext* cx, HandleNativeObject obj, jsid id); /* Clear the scope, making it empty. */ static void clear(ExclusiveContext* cx, HandleNativeObject obj); @@ -783,7 +786,8 @@ class NativeObject : public ShapedObject unsigned flags, ShapeTable::Entry* entry, bool allowDictionary, const AutoKeepShapeTables& keep); - bool fillInAfterSwap(JSContext* cx, const Vector<Value>& values, void* priv); + static MOZ_MUST_USE bool fillInAfterSwap(JSContext* cx, HandleNativeObject obj, + const Vector<Value>& values, void* priv); public: // Return true if this object has been converted from shared-immutable @@ -1146,7 +1150,7 @@ class NativeObject : public ShapedObject } inline DenseElementResult - setOrExtendDenseElements(JSContext* cx, uint32_t start, const Value* vp, uint32_t count, + setOrExtendDenseElements(ExclusiveContext* cx, uint32_t start, const Value* vp, uint32_t count, ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update); bool shouldConvertDoubleElements() { @@ -1470,19 +1474,6 @@ NativeGetExistingProperty(JSContext* cx, HandleObject receiver, HandleNativeObje /* * */ -/* - * If obj has an already-resolved data property for id, return true and - * store the property value in *vp. - */ -extern bool -HasDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp); - -inline bool -HasDataProperty(JSContext* cx, NativeObject* obj, PropertyName* name, Value* vp) -{ - return HasDataProperty(cx, obj, NameToId(name), vp); -} - extern bool GetPropertyForNameLookup(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp); diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 676792379..ec0a7aec1 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -249,7 +249,7 @@ ObjectGroup::useSingletonForAllocationSite(JSScript* script, jsbytecode* pc, con ///////////////////////////////////////////////////////////////////// bool -JSObject::shouldSplicePrototype(JSContext* cx) +JSObject::shouldSplicePrototype() { /* * During bootstrapping, if inference is enabled we need to make sure not @@ -262,33 +262,36 @@ JSObject::shouldSplicePrototype(JSContext* cx) return isSingleton(); } -bool -JSObject::splicePrototype(JSContext* cx, const Class* clasp, Handle<TaggedProto> proto) +/* static */ bool +JSObject::splicePrototype(JSContext* cx, HandleObject obj, const Class* clasp, + Handle<TaggedProto> proto) { - MOZ_ASSERT(cx->compartment() == compartment()); - - RootedObject self(cx, this); + MOZ_ASSERT(cx->compartment() == obj->compartment()); /* * For singleton groups representing only a single JSObject, the proto * can be rearranged as needed without destroying type information for * the old or new types. */ - MOZ_ASSERT(self->isSingleton()); + MOZ_ASSERT(obj->isSingleton()); // Windows may not appear on prototype chains. MOZ_ASSERT_IF(proto.isObject(), !IsWindow(proto.toObject())); - if (proto.isObject() && !proto.toObject()->setDelegate(cx)) - return false; + if (proto.isObject()) { + RootedObject protoObj(cx, proto.toObject()); + if (!JSObject::setDelegate(cx, protoObj)) + return false; + } // Force type instantiation when splicing lazy group. - RootedObjectGroup group(cx, self->getGroup(cx)); + RootedObjectGroup group(cx, JSObject::getGroup(cx, obj)); if (!group) return false; RootedObjectGroup protoGroup(cx, nullptr); if (proto.isObject()) { - protoGroup = proto.toObject()->getGroup(cx); + RootedObject protoObj(cx, proto.toObject()); + protoGroup = JSObject::getGroup(cx, protoObj); if (!protoGroup) return false; } @@ -307,7 +310,7 @@ JSObject::makeLazyGroup(JSContext* cx, HandleObject obj) /* De-lazification of functions can GC, so we need to do it up here. */ if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpretedLazy()) { RootedFunction fun(cx, &obj->as<JSFunction>()); - if (!fun->getOrCreateScript(cx)) + if (!JSFunction::getOrCreateScript(cx, fun)) return nullptr; } @@ -346,7 +349,7 @@ JSObject::makeLazyGroup(JSContext* cx, HandleObject obj) JSObject::setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj) { ObjectGroup::setDefaultNewGroupUnknown(cx, clasp, obj); - return obj->setFlags(cx, BaseShape::NEW_GROUP_UNKNOWN); + return JSObject::setFlags(cx, obj, BaseShape::NEW_GROUP_UNKNOWN); } ///////////////////////////////////////////////////////////////////// @@ -508,7 +511,7 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp, if (proto.isObject() && !proto.toObject()->isDelegate()) { RootedObject protoObj(cx, proto.toObject()); - if (!protoObj->setDelegate(cx)) + if (!JSObject::setDelegate(cx, protoObj)) return nullptr; // Objects which are prototypes of one another should be singletons, so diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index 095ef57ae..3c4d61a67 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -2282,14 +2282,23 @@ * Operands: * Stack: => */ \ - macro(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE) + macro(JSOP_JUMPTARGET, 230, "jumptarget", NULL, 1, 0, 0, JOF_BYTE)\ + /* + * Like JSOP_CALL, but tells the function that the return value is ignored. + * stack. + * Category: Statements + * Type: Function + * Operands: uint16_t argc + * Stack: callee, this, args[0], ..., args[argc-1] => rval + * nuses: (argc+2) + */ \ + macro(JSOP_CALL_IGNORES_RV, 231, "call-ignores-rv", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) /* * In certain circumstances it may be useful to "pad out" the opcode space to * a power of two. Use this macro to do so. */ #define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \ - macro(231) \ macro(232) \ macro(233) \ macro(234) \ diff --git a/js/src/vm/ProxyObject.h b/js/src/vm/ProxyObject.h index a0a929b20..d86d72cc9 100644 --- a/js/src/vm/ProxyObject.h +++ b/js/src/vm/ProxyObject.h @@ -104,7 +104,7 @@ class ProxyObject : public ShapedObject public: static unsigned grayLinkExtraSlot(JSObject* obj); - void renew(JSContext* cx, const BaseProxyHandler* handler, const Value& priv); + void renew(const BaseProxyHandler* handler, const Value& priv); static void trace(JSTracer* trc, JSObject* obj); diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index e0b44e1eb..ef97ed816 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -129,10 +129,10 @@ RegExpSharedReadBarrier(JSContext* cx, RegExpShared* shared) shared->unmarkGray(); } -bool -RegExpObject::getShared(JSContext* cx, RegExpGuard* g) +/* static */ bool +RegExpObject::getShared(JSContext* cx, Handle<RegExpObject*> regexp, RegExpGuard* g) { - if (RegExpShared* shared = maybeShared()) { + if (RegExpShared* shared = regexp->maybeShared()) { // Fetching a RegExpShared from an object requires a read // barrier, as the shared pointer might be weak. RegExpSharedReadBarrier(cx, shared); @@ -141,7 +141,7 @@ RegExpObject::getShared(JSContext* cx, RegExpGuard* g) return true; } - return createShared(cx, g); + return createShared(cx, regexp, g); } /* static */ bool @@ -199,7 +199,7 @@ RegExpObject::trace(JSTracer* trc, JSObject* obj) static JSObject* CreateRegExpPrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &RegExpObject::protoClass_); + return GlobalObject::createBlankPrototype(cx, cx->global(), &RegExpObject::protoClass_); } static const ClassOps RegExpObjectClassOps = { @@ -279,16 +279,14 @@ RegExpObject::create(ExclusiveContext* cx, HandleAtom source, RegExpFlag flags, return regexp; } -bool -RegExpObject::createShared(JSContext* cx, RegExpGuard* g) +/* static */ bool +RegExpObject::createShared(JSContext* cx, Handle<RegExpObject*> regexp, RegExpGuard* g) { - Rooted<RegExpObject*> self(cx, this); - - MOZ_ASSERT(!maybeShared()); - if (!cx->compartment()->regExps.get(cx, getSource(), getFlags(), g)) + MOZ_ASSERT(!regexp->maybeShared()); + if (!cx->compartment()->regExps.get(cx, regexp->getSource(), regexp->getFlags(), g)) return false; - self->setShared(**g); + regexp->setShared(**g); return true; } @@ -300,7 +298,8 @@ RegExpObject::assignInitialShape(ExclusiveContext* cx, Handle<RegExpObject*> sel JS_STATIC_ASSERT(LAST_INDEX_SLOT == 0); /* The lastIndex property alone is writable but non-configurable. */ - return self->addDataProperty(cx, cx->names().lastIndex, LAST_INDEX_SLOT, JSPROP_PERMANENT); + return NativeObject::addDataProperty(cx, self, cx->names().lastIndex, LAST_INDEX_SLOT, + JSPROP_PERMANENT); } void @@ -891,11 +890,12 @@ RegExpShared::dumpBytecode(JSContext* cx, bool match_only, HandleLinearString in return true; } -bool -RegExpObject::dumpBytecode(JSContext* cx, bool match_only, HandleLinearString input) +/* static */ bool +RegExpObject::dumpBytecode(JSContext* cx, Handle<RegExpObject*> regexp, + bool match_only, HandleLinearString input) { RegExpGuard g(cx); - if (!getShared(cx, &g)) + if (!getShared(cx, regexp, &g)) return false; return g.re()->dumpBytecode(cx, match_only, input); @@ -1430,7 +1430,7 @@ js::CloneRegExpObject(JSContext* cx, JSObject* obj_) Rooted<JSAtom*> source(cx, regex->getSource()); RegExpGuard g(cx); - if (!regex->getShared(cx, &g)) + if (!RegExpObject::getShared(cx, regex, &g)) return nullptr; clone->initAndZeroLastIndex(source, g->getFlags(), cx); diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index dc428a973..f1ea101ed 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -483,7 +483,8 @@ class RegExpObject : public NativeObject static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask); - bool getShared(JSContext* cx, RegExpGuard* g); + static MOZ_MUST_USE bool getShared(JSContext* cx, Handle<RegExpObject*> regexp, + RegExpGuard* g); void setShared(RegExpShared& shared) { MOZ_ASSERT(!maybeShared()); @@ -500,7 +501,8 @@ class RegExpObject : public NativeObject void initAndZeroLastIndex(HandleAtom source, RegExpFlag flags, ExclusiveContext* cx); #ifdef DEBUG - bool dumpBytecode(JSContext* cx, bool match_only, HandleLinearString input); + static MOZ_MUST_USE bool dumpBytecode(JSContext* cx, Handle<RegExpObject*> regexp, + bool match_only, HandleLinearString input); #endif private: @@ -508,7 +510,8 @@ class RegExpObject : public NativeObject * Precondition: the syntax for |source| has already been validated. * Side effect: sets the private field. */ - bool createShared(JSContext* cx, RegExpGuard* g); + static MOZ_MUST_USE bool createShared(JSContext* cx, Handle<RegExpObject*> regexp, + RegExpGuard* g); RegExpShared* maybeShared() const { return static_cast<RegExpShared*>(NativeObject::getPrivate(PRIVATE_SLOT)); } @@ -531,7 +534,7 @@ inline bool RegExpToShared(JSContext* cx, HandleObject obj, RegExpGuard* g) { if (obj->is<RegExpObject>()) - return obj->as<RegExpObject>().getShared(cx, g); + return RegExpObject::getShared(cx, obj.as<RegExpObject>(), g); return Proxy::regexp_toShared(cx, obj, g); } diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp index a71c03695..0f80d7b69 100644 --- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -669,6 +669,14 @@ FunctionScope::script() const return canonicalFunction()->nonLazyScript(); } +/* static */ bool +FunctionScope::isSpecialName(ExclusiveContext* cx, JSAtom* name) +{ + return name == cx->names().arguments || + name == cx->names().dotThis || + name == cx->names().dotGenerator; +} + /* static */ Shape* FunctionScope::getEmptyEnvironmentShape(ExclusiveContext* cx, bool hasParameterExprs) { diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h index 1d04fd9f6..4a4ae8090 100644 --- a/js/src/vm/Scope.h +++ b/js/src/vm/Scope.h @@ -446,10 +446,11 @@ Scope::is<LexicalScope>() const } // -// Scope corresponding to a function. Holds formal parameter names and, if the -// function parameters contain no expressions that might possibly be -// evaluated, the function's var bindings. For example, in these functions, -// the FunctionScope will store a/b/c bindings but not d/e/f bindings: +// Scope corresponding to a function. Holds formal parameter names, special +// internal names (see FunctionScope::isSpecialName), and, if the function +// parameters contain no expressions that might possibly be evaluated, the +// function's var bindings. For example, in these functions, the FunctionScope +// will store a/b/c bindings but not d/e/f bindings: // // function f1(a, b) { // var c; @@ -562,6 +563,8 @@ class FunctionScope : public Scope return data().nonPositionalFormalStart; } + static bool isSpecialName(ExclusiveContext* cx, JSAtom* name); + static Shape* getEmptyEnvironmentShape(ExclusiveContext* cx, bool hasParameterExprs); }; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index ccd4cc8d7..792a00490 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -477,7 +477,7 @@ intrinsic_FinishBoundFunctionInit(JSContext* cx, unsigned argc, Value* vp) // Try to avoid invoking the resolve hook. if (targetObj->is<JSFunction>() && !targetObj->as<JSFunction>().hasResolvedLength()) { RootedValue targetLength(cx); - if (!targetObj->as<JSFunction>().getUnresolvedLength(cx, &targetLength)) + if (!JSFunction::getUnresolvedLength(cx, targetObj.as<JSFunction>(), &targetLength)) return false; length = Max(0.0, targetLength.toNumber() - argCount); @@ -2154,7 +2154,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_INLINABLE_FN("std_Array_slice", array_slice, 2,0, ArraySlice), JS_FN("std_Array_sort", array_sort, 1,0), JS_FN("std_Array_reverse", array_reverse, 0,0), - JS_INLINABLE_FN("std_Array_splice", array_splice, 2,0, ArraySplice), + JS_FNINFO("std_Array_splice", array_splice, &array_splice_info, 2,0), JS_FN("std_Date_now", date_now, 0,0), JS_FN("std_Date_valueOf", date_valueOf, 0,0), @@ -3008,7 +3008,7 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name, MOZ_ASSERT(targetFun->isInterpretedLazy()); MOZ_ASSERT(targetFun->isSelfHostedBuiltin()); - RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx)); + RootedScript sourceScript(cx, JSFunction::getOrCreateScript(cx, sourceFun)); if (!sourceScript) return false; diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 306a2c540..8fe2145e5 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -460,15 +460,13 @@ NativeObject::getChildProperty(ExclusiveContext* cx, return shape; } -bool -js::NativeObject::toDictionaryMode(ExclusiveContext* cx) +/* static */ bool +js::NativeObject::toDictionaryMode(ExclusiveContext* cx, HandleNativeObject obj) { - MOZ_ASSERT(!inDictionaryMode()); - MOZ_ASSERT(cx->isInsideCurrentCompartment(this)); - - uint32_t span = slotSpan(); + MOZ_ASSERT(!obj->inDictionaryMode()); + MOZ_ASSERT(cx->isInsideCurrentCompartment(obj)); - Rooted<NativeObject*> self(cx, this); + uint32_t span = obj->slotSpan(); // Clone the shapes into a new dictionary list. Don't update the last // property of this object until done, otherwise a GC triggered while @@ -476,7 +474,7 @@ js::NativeObject::toDictionaryMode(ExclusiveContext* cx) RootedShape root(cx); RootedShape dictionaryShape(cx); - RootedShape shape(cx, lastProperty()); + RootedShape shape(cx, obj->lastProperty()); while (shape) { MOZ_ASSERT(!shape->inDictionary()); @@ -488,7 +486,7 @@ js::NativeObject::toDictionaryMode(ExclusiveContext* cx) GCPtrShape* listp = dictionaryShape ? &dictionaryShape->parent : nullptr; StackShape child(shape); - dprop->initDictionaryShape(child, self->numFixedSlots(), listp); + dprop->initDictionaryShape(child, obj->numFixedSlots(), listp); if (!dictionaryShape) root = dprop; @@ -503,18 +501,18 @@ js::NativeObject::toDictionaryMode(ExclusiveContext* cx) return false; } - if (IsInsideNursery(self) && - !cx->asJSContext()->gc.nursery.queueDictionaryModeObjectToSweep(self)) + if (IsInsideNursery(obj) && + !cx->asJSContext()->gc.nursery.queueDictionaryModeObjectToSweep(obj)) { ReportOutOfMemory(cx); return false; } MOZ_ASSERT(root->listp == nullptr); - root->listp = &self->shape_; - self->shape_ = root; + root->listp = &obj->shape_; + obj->shape_ = root; - MOZ_ASSERT(self->inDictionaryMode()); + MOZ_ASSERT(obj->inDictionaryMode()); root->base()->setSlotSpan(span); return true; @@ -534,7 +532,7 @@ NativeObject::addProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId return nullptr; if (!extensible) { if (cx->isJSContext()) - obj->reportNotExtensible(cx->asJSContext()); + JSObject::reportNotExtensible(cx->asJSContext(), obj); return nullptr; } @@ -592,7 +590,7 @@ NativeObject::addPropertyInternal(ExclusiveContext* cx, if (allowDictionary && (!stableSlot || ShouldConvertToDictionary(obj))) { - if (!obj->toDictionaryMode(cx)) + if (!toDictionaryMode(cx, obj)) return nullptr; table = obj->lastProperty()->maybeTable(keep); entry = &table->search<MaybeAdding::Adding>(id, keep); @@ -727,7 +725,7 @@ CheckCanChangeAttrs(ExclusiveContext* cx, JSObject* obj, Shape* shape, unsigned* (*attrsp & (JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED))) { if (cx->isJSContext()) - obj->reportNotConfigurable(cx->asJSContext(), shape->propid()); + JSObject::reportNotConfigurable(cx->asJSContext(), shape->propid()); return false; } @@ -785,7 +783,7 @@ NativeObject::putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId if (!extensible) { if (cx->isJSContext()) - obj->reportNotExtensible(cx->asJSContext()); + JSObject::reportNotExtensible(cx->asJSContext(), obj); return nullptr; } @@ -834,7 +832,7 @@ NativeObject::putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId * addPropertyInternal because a failure under add would lose data. */ if (shape != obj->lastProperty() && !obj->inDictionaryMode()) { - if (!obj->toDictionaryMode(cx)) + if (!toDictionaryMode(cx, obj)) return nullptr; ShapeTable* table = obj->lastProperty()->maybeTable(keep); MOZ_ASSERT(table); @@ -853,10 +851,11 @@ NativeObject::putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId */ bool updateLast = (shape == obj->lastProperty()); bool accessorShape = getter || setter || (attrs & (JSPROP_GETTER | JSPROP_SETTER)); - shape = obj->replaceWithNewEquivalentShape(cx, shape, nullptr, accessorShape); + shape = NativeObject::replaceWithNewEquivalentShape(cx, obj, shape, nullptr, + accessorShape); if (!shape) return nullptr; - if (!updateLast && !obj->generateOwnShape(cx)) + if (!updateLast && !NativeObject::generateOwnShape(cx, obj)) return nullptr; /* @@ -968,16 +967,15 @@ NativeObject::changeProperty(ExclusiveContext* cx, HandleNativeObject obj, Handl return newShape; } -bool -NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) +/* static */ bool +NativeObject::removeProperty(ExclusiveContext* cx, HandleNativeObject obj, jsid id_) { RootedId id(cx, id_); - RootedNativeObject self(cx, this); AutoKeepShapeTables keep(cx); ShapeTable::Entry* entry; RootedShape shape(cx); - if (!Shape::search(cx, lastProperty(), id, keep, shape.address(), &entry)) + if (!Shape::search(cx, obj->lastProperty(), id, keep, shape.address(), &entry)) return false; if (!shape) @@ -987,10 +985,10 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) * If shape is not the last property added, or the last property cannot * be removed, switch to dictionary mode. */ - if (!self->inDictionaryMode() && (shape != self->lastProperty() || !self->canRemoveLastProperty())) { - if (!self->toDictionaryMode(cx)) + if (!obj->inDictionaryMode() && (shape != obj->lastProperty() || !obj->canRemoveLastProperty())) { + if (!toDictionaryMode(cx, obj)) return false; - ShapeTable* table = self->lastProperty()->maybeTable(keep); + ShapeTable* table = obj->lastProperty()->maybeTable(keep); MOZ_ASSERT(table); entry = &table->search<MaybeAdding::NotAdding>(shape->propid(), keep); shape = entry->shape(); @@ -1004,21 +1002,21 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) * the object or table, so the remaining removal is infallible. */ RootedShape spare(cx); - if (self->inDictionaryMode()) { + if (obj->inDictionaryMode()) { /* For simplicity, always allocate an accessor shape for now. */ spare = Allocate<AccessorShape>(cx); if (!spare) return false; new (spare) Shape(shape->base()->unowned(), 0); - if (shape == self->lastProperty()) { + if (shape == obj->lastProperty()) { /* * Get an up to date unowned base shape for the new last property * when removing the dictionary's last property. Information in * base shapes for non-last properties may be out of sync with the * object's state. */ - RootedShape previous(cx, self->lastProperty()->parent); - StackBaseShape base(self->lastProperty()->base()); + RootedShape previous(cx, obj->lastProperty()->parent); + StackBaseShape base(obj->lastProperty()->base()); BaseShape* nbase = BaseShape::getUnowned(cx, base); if (!nbase) return false; @@ -1028,7 +1026,7 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) /* If shape has a slot, free its slot number. */ if (shape->hasSlot()) { - self->freeSlot(cx, shape->slot()); + obj->freeSlot(cx, shape->slot()); if (cx->isJSContext()) ++cx->asJSContext()->runtime()->propertyRemovals; } @@ -1038,8 +1036,8 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) * doubly linked list, hashed by lastProperty()->table. So we can edit the * list and hash in place. */ - if (self->inDictionaryMode()) { - ShapeTable* table = self->lastProperty()->maybeTable(keep); + if (obj->inDictionaryMode()) { + ShapeTable* table = obj->lastProperty()->maybeTable(keep); MOZ_ASSERT(table); if (entry->hadCollision()) { @@ -1056,23 +1054,23 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) * checks not to alter significantly the complexity of the * delete in debug builds, see bug 534493. */ - Shape* aprop = self->lastProperty(); + Shape* aprop = obj->lastProperty(); for (int n = 50; --n >= 0 && aprop->parent; aprop = aprop->parent) - MOZ_ASSERT_IF(aprop != shape, self->contains(cx, aprop)); + MOZ_ASSERT_IF(aprop != shape, obj->contains(cx, aprop)); #endif } { /* Remove shape from its non-circular doubly linked list. */ - Shape* oldLastProp = self->lastProperty(); - shape->removeFromDictionary(self); + Shape* oldLastProp = obj->lastProperty(); + shape->removeFromDictionary(obj); /* Hand off table from the old to new last property. */ - oldLastProp->handoffTableTo(self->lastProperty()); + oldLastProp->handoffTableTo(obj->lastProperty()); } /* Generate a new shape for the object, infallibly. */ - JS_ALWAYS_TRUE(self->generateOwnShape(cx, spare)); + JS_ALWAYS_TRUE(NativeObject::generateOwnShape(cx, obj, spare)); /* Consider shrinking table if its load factor is <= .25. */ uint32_t size = table->capacity(); @@ -1085,11 +1083,11 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) * lazily make via a later hashify the exact table for the new property * lineage. */ - MOZ_ASSERT(shape == self->lastProperty()); - self->removeLastProperty(cx); + MOZ_ASSERT(shape == obj->lastProperty()); + obj->removeLastProperty(cx); } - self->checkShapeConsistency(); + obj->checkShapeConsistency(); return true; } @@ -1133,35 +1131,30 @@ NativeObject::rollbackProperties(ExclusiveContext* cx, HandleNativeObject obj, u if (slot < slotSpan) break; } - if (!obj->removeProperty(cx, obj->lastProperty()->propid())) + if (!NativeObject::removeProperty(cx, obj, obj->lastProperty()->propid())) return false; } return true; } -Shape* -NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, Shape* oldShape, Shape* newShape, - bool accessorShape) +/* static */ Shape* +NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, HandleNativeObject obj, + Shape* oldShape, Shape* newShape, bool accessorShape) { MOZ_ASSERT(cx->isInsideCurrentZone(oldShape)); - MOZ_ASSERT_IF(oldShape != lastProperty(), - inDictionaryMode() && lookup(cx, oldShape->propidRef()) == oldShape); - - NativeObject* self = this; + MOZ_ASSERT_IF(oldShape != obj->lastProperty(), + obj->inDictionaryMode() && obj->lookup(cx, oldShape->propidRef()) == oldShape); - if (!inDictionaryMode()) { - RootedNativeObject selfRoot(cx, self); + if (!obj->inDictionaryMode()) { RootedShape newRoot(cx, newShape); - if (!toDictionaryMode(cx)) + if (!toDictionaryMode(cx, obj)) return nullptr; - oldShape = selfRoot->lastProperty(); - self = selfRoot; + oldShape = obj->lastProperty(); newShape = newRoot; } if (!newShape) { - RootedNativeObject selfRoot(cx, self); RootedShape oldRoot(cx, oldShape); newShape = (oldShape->isAccessorShape() || accessorShape) ? Allocate<AccessorShape>(cx) @@ -1169,12 +1162,11 @@ NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, Shape* oldShap if (!newShape) return nullptr; new (newShape) Shape(oldRoot->base()->unowned(), 0); - self = selfRoot; oldShape = oldRoot; } AutoCheckCannotGC nogc; - ShapeTable* table = self->lastProperty()->ensureTableForDictionary(cx, nogc); + ShapeTable* table = obj->lastProperty()->ensureTableForDictionary(cx, nogc); if (!table) return nullptr; @@ -1187,12 +1179,12 @@ NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, Shape* oldShap * enumeration order (see bug 601399). */ StackShape nshape(oldShape); - newShape->initDictionaryShape(nshape, self->numFixedSlots(), oldShape->listp); + newShape->initDictionaryShape(nshape, obj->numFixedSlots(), oldShape->listp); MOZ_ASSERT(newShape->parent == oldShape); - oldShape->removeFromDictionary(self); + oldShape->removeFromDictionary(obj); - if (newShape == self->lastProperty()) + if (newShape == obj->lastProperty()) oldShape->handoffTableTo(newShape); if (entry) @@ -1200,63 +1192,63 @@ NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, Shape* oldShap return newShape; } -bool -NativeObject::shadowingShapeChange(ExclusiveContext* cx, const Shape& shape) +/* static */ bool +NativeObject::shadowingShapeChange(ExclusiveContext* cx, HandleNativeObject obj, const Shape& shape) { - return generateOwnShape(cx); + return generateOwnShape(cx, obj); } -bool -JSObject::setFlags(ExclusiveContext* cx, BaseShape::Flag flags, GenerateShape generateShape) +/* static */ bool +JSObject::setFlags(ExclusiveContext* cx, HandleObject obj, BaseShape::Flag flags, + GenerateShape generateShape) { - if (hasAllFlags(flags)) + if (obj->hasAllFlags(flags)) return true; - RootedObject self(cx, this); - - Shape* existingShape = self->ensureShape(cx); + Shape* existingShape = obj->ensureShape(cx); if (!existingShape) return false; - if (isNative() && as<NativeObject>().inDictionaryMode()) { - if (generateShape == GENERATE_SHAPE && !as<NativeObject>().generateOwnShape(cx)) - return false; - StackBaseShape base(self->as<NativeObject>().lastProperty()); + if (obj->isNative() && obj->as<NativeObject>().inDictionaryMode()) { + if (generateShape == GENERATE_SHAPE) { + if (!NativeObject::generateOwnShape(cx, obj.as<NativeObject>())) + return false; + } + StackBaseShape base(obj->as<NativeObject>().lastProperty()); base.flags |= flags; UnownedBaseShape* nbase = BaseShape::getUnowned(cx, base); if (!nbase) return false; - self->as<NativeObject>().lastProperty()->base()->adoptUnowned(nbase); + obj->as<NativeObject>().lastProperty()->base()->adoptUnowned(nbase); return true; } - Shape* newShape = Shape::setObjectFlags(cx, flags, self->taggedProto(), existingShape); + Shape* newShape = Shape::setObjectFlags(cx, flags, obj->taggedProto(), existingShape); if (!newShape) return false; - // The success of the |JSObject::ensureShape| call above means that |self| + // The success of the |JSObject::ensureShape| call above means that |obj| // can be assumed to have a shape. - self->as<ShapedObject>().setShape(newShape); + obj->as<ShapedObject>().setShape(newShape); return true; } -bool -NativeObject::clearFlag(ExclusiveContext* cx, BaseShape::Flag flag) +/* static */ bool +NativeObject::clearFlag(ExclusiveContext* cx, HandleNativeObject obj, BaseShape::Flag flag) { - MOZ_ASSERT(inDictionaryMode()); + MOZ_ASSERT(obj->inDictionaryMode()); - RootedNativeObject self(cx, &as<NativeObject>()); - MOZ_ASSERT(self->lastProperty()->getObjectFlags() & flag); + MOZ_ASSERT(obj->lastProperty()->getObjectFlags() & flag); - StackBaseShape base(self->lastProperty()); + StackBaseShape base(obj->lastProperty()); base.flags &= ~flag; UnownedBaseShape* nbase = BaseShape::getUnowned(cx, base); if (!nbase) return false; - self->lastProperty()->base()->adoptUnowned(nbase); + obj->lastProperty()->base()->adoptUnowned(nbase); return true; } diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 978798aaa..fd6d843e0 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -905,9 +905,6 @@ class Shape : public gc::TenuredCell setter() == rawSetter; } - bool set(JSContext* cx, HandleNativeObject obj, HandleObject receiver, MutableHandleValue vp, - ObjectOpResult& result); - BaseShape* base() const { return base_.get(); } bool hasSlot() const { diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp index c69306aac..0dff41201 100644 --- a/js/src/vm/SharedArrayObject.cpp +++ b/js/src/vm/SharedArrayObject.cpp @@ -366,7 +366,8 @@ static const Class SharedArrayBufferObjectProtoClass = { static JSObject* CreateSharedArrayBufferPrototype(JSContext* cx, JSProtoKey key) { - return cx->global()->createBlankPrototype(cx, &SharedArrayBufferObjectProtoClass); + return GlobalObject::createBlankPrototype(cx, cx->global(), + &SharedArrayBufferObjectProtoClass); } static const ClassOps SharedArrayBufferObjectClassOps = { diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index a51c0aa14..11a19d175 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -306,7 +306,7 @@ InterpreterStack::pushInlineFrame(JSContext* cx, InterpreterRegs& regs, const Ca MOZ_ASSERT(regs.sp == args.end()); MOZ_ASSERT(callee->nonLazyScript() == script); - script->ensureNonLazyCanonicalFunction(cx); + script->ensureNonLazyCanonicalFunction(); InterpreterFrame* prev = regs.fp(); jsbytecode* prevpc = regs.pc; @@ -336,13 +336,13 @@ InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs, HandleObject envChain) { MOZ_ASSERT(callee->isGenerator()); - RootedScript script(cx, callee->getOrCreateScript(cx)); + RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee)); InterpreterFrame* prev = regs.fp(); jsbytecode* prevpc = regs.pc; Value* prevsp = regs.sp; MOZ_ASSERT(prev); - script->ensureNonLazyCanonicalFunction(cx); + script->ensureNonLazyCanonicalFunction(); LifoAlloc::Mark mark = allocator_.mark(); diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index dc9306c99..23e621344 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1006,6 +1006,17 @@ class InvokeArgs : public detail::GenericArgsBase<NO_CONSTRUCT> explicit InvokeArgs(JSContext* cx) : Base(cx) {} }; +/** Function call args of statically-unknown count. */ +class InvokeArgsMaybeIgnoresReturnValue : public detail::GenericArgsBase<NO_CONSTRUCT> +{ + using Base = detail::GenericArgsBase<NO_CONSTRUCT>; + + public: + explicit InvokeArgsMaybeIgnoresReturnValue(JSContext* cx, bool ignoresReturnValue) : Base(cx) { + this->ignoresReturnValue_ = ignoresReturnValue; + } +}; + /** Function call args of statically-known count. */ template <size_t N> class FixedInvokeArgs : public detail::FixedArgsBase<NO_CONSTRUCT, N> diff --git a/js/src/vm/StringObject-inl.h b/js/src/vm/StringObject-inl.h index 5fc1656f6..38191fc7a 100644 --- a/js/src/vm/StringObject-inl.h +++ b/js/src/vm/StringObject-inl.h @@ -15,31 +15,29 @@ namespace js { -inline bool -StringObject::init(JSContext* cx, HandleString str) +/* static */ inline bool +StringObject::init(JSContext* cx, Handle<StringObject*> obj, HandleString str) { - MOZ_ASSERT(numFixedSlots() == 2); + MOZ_ASSERT(obj->numFixedSlots() == 2); - Rooted<StringObject*> self(cx, this); - - if (!EmptyShape::ensureInitialCustomShape<StringObject>(cx, self)) + if (!EmptyShape::ensureInitialCustomShape<StringObject>(cx, obj)) return false; - MOZ_ASSERT(self->lookup(cx, NameToId(cx->names().length))->slot() == LENGTH_SLOT); + MOZ_ASSERT(obj->lookup(cx, NameToId(cx->names().length))->slot() == LENGTH_SLOT); - self->setStringThis(str); + obj->setStringThis(str); return true; } -inline StringObject* +/* static */ inline StringObject* StringObject::create(JSContext* cx, HandleString str, HandleObject proto, NewObjectKind newKind) { JSObject* obj = NewObjectWithClassProto(cx, &class_, proto, newKind); if (!obj) return nullptr; Rooted<StringObject*> strobj(cx, &obj->as<StringObject>()); - if (!strobj->init(cx, str)) + if (!StringObject::init(cx, strobj, str)) return nullptr; return strobj; } diff --git a/js/src/vm/StringObject.h b/js/src/vm/StringObject.h index 119e3d9fa..561e0478a 100644 --- a/js/src/vm/StringObject.h +++ b/js/src/vm/StringObject.h @@ -56,7 +56,7 @@ class StringObject : public NativeObject } private: - inline bool init(JSContext* cx, HandleString str); + static inline bool init(JSContext* cx, Handle<StringObject*> obj, HandleString str); void setStringThis(JSString* str) { MOZ_ASSERT(getReservedSlot(PRIMITIVE_VALUE_SLOT).isUndefined()); diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index ba809fc4e..7c2c0194e 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -1319,7 +1319,8 @@ js::EnsureTrackPropertyTypes(JSContext* cx, JSObject* obj, jsid id) AutoEnterAnalysis enter(cx); if (obj->hasLazyGroup()) { AutoEnterOOMUnsafeRegion oomUnsafe; - if (!obj->getGroup(cx)) { + RootedObject objRoot(cx, obj); + if (!JSObject::getGroup(cx, objRoot)) { oomUnsafe.crash("Could not allocate ObjectGroup in EnsureTrackPropertyTypes"); return; } @@ -1338,9 +1339,12 @@ HeapTypeSetKey::instantiate(JSContext* cx) { if (maybeTypes()) return true; - if (object()->isSingleton() && !object()->singleton()->getGroup(cx)) { - cx->clearPendingException(); - return false; + if (object()->isSingleton()) { + RootedObject obj(cx, object()->singleton()); + if (!JSObject::getGroup(cx, obj)) { + cx->clearPendingException(); + return false; + } } JSObject* obj = object()->isSingleton() ? object()->singleton() : nullptr; maybeTypes_ = object()->maybeGroup()->getProperty(cx, obj, id()); @@ -2941,7 +2945,8 @@ ObjectGroup::clearNewScript(ExclusiveContext* cx, ObjectGroup* replacement /* = // Mark the constructing function as having its 'new' script cleared, so we // will not try to construct another one later. - if (!newScript->function()->setNewScriptCleared(cx)) + RootedFunction fun(cx, newScript->function()); + if (!JSObject::setNewScriptCleared(cx, fun)) cx->recoverFromOutOfMemory(); } @@ -3088,7 +3093,7 @@ js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* gr */ RootedObject proto(cx, group->proto().toObjectOrNull()); while (proto) { - ObjectGroup* protoGroup = proto->getGroup(cx); + ObjectGroup* protoGroup = JSObject::getGroup(cx, proto); if (!protoGroup) { cx->recoverFromOutOfMemory(); return false; @@ -3712,7 +3717,8 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, Vector<Initializer> initializerVector(cx); RootedPlainObject templateRoot(cx, templateObject()); - if (!jit::AnalyzeNewScriptDefiniteProperties(cx, function(), group, templateRoot, &initializerVector)) + RootedFunction fun(cx, function()); + if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, group, templateRoot, &initializerVector)) return false; if (!group->newScript()) diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index ae97be0de..8b0302917 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -361,7 +361,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject return nullptr; const Class* clasp = TypedArrayObject::protoClassForType(ArrayTypeID()); - return global->createBlankPrototypeInheriting(cx, clasp, typedArrayProto); + return GlobalObject::createBlankPrototypeInheriting(cx, global, clasp, typedArrayProto); } static JSObject* @@ -1892,7 +1892,7 @@ DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallA Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal()); if (!proto) { - proto = global->getOrCreateDataViewPrototype(cx); + proto = GlobalObject::getOrCreateDataViewPrototype(cx, global); if (!proto) return false; } @@ -2892,12 +2892,13 @@ DataViewObject::initClass(JSContext* cx) if (global->isStandardClassResolved(JSProto_DataView)) return true; - RootedNativeObject proto(cx, global->createBlankPrototype(cx, &DataViewObject::protoClass)); + RootedNativeObject proto(cx, GlobalObject::createBlankPrototype(cx, global, + &DataViewObject::protoClass)); if (!proto) return false; - RootedFunction ctor(cx, global->createConstructor(cx, DataViewObject::class_constructor, - cx->names().DataView, 3)); + RootedFunction ctor(cx, GlobalObject::createConstructor(cx, DataViewObject::class_constructor, + cx->names().DataView, 3)); if (!ctor) return false; diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index a318d67a9..52b8eeed1 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -34,6 +34,7 @@ #include "frontend/Parser.h" #include "gc/Policy.h" #include "js/MemoryMetrics.h" +#include "vm/SelfHosting.h" #include "vm/StringBuffer.h" #include "vm/Time.h" #include "vm/TypedArrayObject.h" @@ -318,7 +319,7 @@ struct js::AsmJSMetadata : Metadata, AsmJSMetadataCacheablePod // Function constructor, this will be the first character in the function // source. Otherwise, it will be the opening parenthesis of the arguments // list. - uint32_t preludeStart; + uint32_t toStringStart; uint32_t srcStart; uint32_t srcBodyStart; bool strict; @@ -1759,7 +1760,7 @@ class MOZ_STACK_CLASS ModuleValidator if (!asmJSMetadata_) return false; - asmJSMetadata_->preludeStart = moduleFunctionNode_->pn_funbox->preludeStart; + asmJSMetadata_->toStringStart = moduleFunctionNode_->pn_funbox->toStringStart; asmJSMetadata_->srcStart = moduleFunctionNode_->pn_body->pn_pos.begin; asmJSMetadata_->srcBodyStart = parser_.tokenStream.currentToken().pos.end; asmJSMetadata_->strict = parser_.pc->sc()->strict() && @@ -3250,10 +3251,9 @@ CheckModuleLevelName(ModuleValidator& m, ParseNode* usepn, PropertyName* name) static bool CheckFunctionHead(ModuleValidator& m, ParseNode* fn) { - JSFunction* fun = FunctionObject(fn); if (fn->pn_funbox->hasRest()) return m.fail(fn, "rest args not allowed"); - if (fun->isExprBody()) + if (fn->pn_funbox->isExprBody()) return m.fail(fn, "expression closures not allowed"); if (fn->pn_funbox->hasDestructuringArgs) return m.fail(fn, "destructuring args not allowed"); @@ -7051,13 +7051,13 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) TokenStream& tokenStream = m.tokenStream(); tokenStream.consumeKnownToken(TOK_FUNCTION, TokenStream::Operand); - uint32_t preludeStart = tokenStream.currentToken().pos.begin; + uint32_t toStringStart = tokenStream.currentToken().pos.begin; *line = tokenStream.srcCoords.lineNum(tokenStream.currentToken().pos.end); TokenKind tk; if (!tokenStream.getToken(&tk, TokenStream::Operand)) return false; - if (tk != TOK_NAME && tk != TOK_YIELD) + if (!TokenKindIsPossibleIdentifier(tk)) return false; // The regular parser will throw a SyntaxError, no need to m.fail. RootedPropertyName name(m.cx(), m.parser().bindingIdentifier(YieldIsName)); @@ -7074,7 +7074,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line) ParseContext* outerpc = m.parser().pc; Directives directives(outerpc); - FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, preludeStart, directives, NotGenerator, + FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, toStringStart, directives, NotGenerator, SyncFunction, /* tryAnnexB = */ false); if (!funbox) return false; @@ -7466,6 +7466,20 @@ GetDataProperty(JSContext* cx, HandleValue objVal, ImmutablePropertyNamePtr fiel } static bool +HasObjectValueOfMethodPure(JSObject* obj, JSContext* cx) +{ + Value v; + if (!GetPropertyPure(cx, obj, NameToId(cx->names().valueOf), &v)) + return false; + + JSFunction* fun; + if (!IsFunctionObject(v, &fun)) + return false; + + return IsSelfHostedFunctionWithName(fun, cx->names().Object_valueOf); +} + +static bool HasPureCoercion(JSContext* cx, HandleValue v) { // Unsigned SIMD types are not allowed in function signatures. @@ -7479,10 +7493,10 @@ HasPureCoercion(JSContext* cx, HandleValue v) // coercions are not observable and coercion via ToNumber/ToInt32 // definitely produces NaN/0. We should remove this special case later once // most apps have been built with newer Emscripten. - jsid toString = NameToId(cx->names().toString); if (v.toObject().is<JSFunction>() && - HasObjectValueOf(&v.toObject(), cx) && - ClassMethodIsNative(cx, &v.toObject().as<JSFunction>(), &JSFunction::class_, toString, fun_toString)) + HasNoToPrimitiveMethodPure(&v.toObject(), cx) && + HasObjectValueOfMethodPure(&v.toObject(), cx) && + HasNativeMethodPure(&v.toObject(), cx->names().toString, fun_toString, cx)) { return true; } @@ -8057,7 +8071,7 @@ HandleInstantiationFailure(JSContext* cx, CallArgs args, const AsmJSMetadata& me return false; } - uint32_t begin = metadata.preludeStart; + uint32_t begin = metadata.toStringStart; uint32_t end = metadata.srcEndAfterCurly(); Rooted<JSFlatString*> src(cx, source->substringDontDeflate(cx, begin, end)); if (!src) @@ -8540,7 +8554,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded return true; // See AsmJSMetadata comment as well as ModuleValidator::init(). - asmJSMetadata->preludeStart = parser.pc->functionBox()->preludeStart; + asmJSMetadata->toStringStart = parser.pc->functionBox()->toStringStart; asmJSMetadata->srcStart = parser.pc->functionBox()->functionNode->pn_body->pn_pos.begin; asmJSMetadata->srcBodyStart = parser.tokenStream.currentToken().pos.end; asmJSMetadata->strict = parser.pc->sc()->strict() && !parser.pc->sc()->hasExplicitUseStrict(); @@ -8838,7 +8852,7 @@ js::AsmJSModuleToString(JSContext* cx, HandleFunction fun, bool addParenToLambda MOZ_ASSERT(IsAsmJSModule(fun)); const AsmJSMetadata& metadata = AsmJSModuleFunctionToModule(fun).metadata().asAsmJS(); - uint32_t begin = metadata.preludeStart; + uint32_t begin = metadata.toStringStart; uint32_t end = metadata.srcEndAfterCurly(); ScriptSource* source = metadata.scriptSource.get(); diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index 0b030c844..8d4f575b2 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -1659,7 +1659,7 @@ Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle<Promise if (!cx->getPendingException(&rejectionValue)) return false; - return promise->reject(cx, rejectionValue); + return PromiseObject::reject(cx, promise, rejectionValue); } RootedObject stack(cx, promise->allocationSite()); @@ -1687,7 +1687,7 @@ Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle<Promise return false; RootedValue rejectionValue(cx, ObjectValue(*errorObj)); - return promise->reject(cx, rejectionValue); + return PromiseObject::reject(cx, promise, rejectionValue); } static bool @@ -1699,7 +1699,7 @@ ResolveCompilation(JSContext* cx, Module& module, Handle<PromiseObject*> promise return false; RootedValue resolutionValue(cx, ObjectValue(*moduleObj)); - return promise->resolve(cx, resolutionValue); + return PromiseObject::resolve(cx, promise, resolutionValue); } struct CompileTask : PromiseTask @@ -1734,7 +1734,7 @@ RejectWithPendingException(JSContext* cx, Handle<PromiseObject*> promise) if (!GetAndClearException(cx, &rejectionValue)) return false; - return promise->reject(cx, rejectionValue); + return PromiseObject::reject(cx, promise, rejectionValue); } static bool @@ -1822,7 +1822,7 @@ ResolveInstantiation(JSContext* cx, Module& module, HandleObject importObj, return false; val = ObjectValue(*resultObj); - return promise->resolve(cx, val); + return PromiseObject::resolve(cx, promise, val); } struct InstantiateTask : CompileTask @@ -1894,7 +1894,7 @@ WebAssembly_instantiate(JSContext* cx, unsigned argc, Value* vp) return RejectWithPendingException(cx, promise, callArgs); RootedValue resolutionValue(cx, ObjectValue(*instanceObj)); - if (!promise->resolve(cx, resolutionValue)) + if (!PromiseObject::resolve(cx, promise, resolutionValue)) return false; } else { auto task = cx->make_unique<InstantiateTask>(cx, promise, importObj); @@ -2018,7 +2018,7 @@ js::InitWebAssemblyClass(JSContext* cx, HandleObject obj) Handle<GlobalObject*> global = obj.as<GlobalObject>(); MOZ_ASSERT(!global->isStandardClassResolved(JSProto_WebAssembly)); - RootedObject proto(cx, global->getOrCreateObjectPrototype(cx)); + RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global)); if (!proto) return nullptr; diff --git a/js/xpconnect/idl/moz.build b/js/xpconnect/idl/moz.build index 2438b1a5a..0808d3450 100644 --- a/js/xpconnect/idl/moz.build +++ b/js/xpconnect/idl/moz.build @@ -7,7 +7,6 @@ XPIDL_SOURCES += [ 'mozIJSSubScriptLoader.idl', 'nsIAddonInterposition.idl', - 'nsIScriptError.idl', 'nsIXPConnect.idl', 'nsIXPCScriptable.idl', 'xpccomponents.idl', diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index dbb63092e..07ce7460b 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -34,9 +34,11 @@ #include "nsDOMClassInfo.h" #include "ShimInterfaceInfo.h" #include "nsIAddonInterposition.h" +#include "nsIScriptError.h" #include "nsISimpleEnumerator.h" #include "nsPIDOMWindow.h" #include "nsGlobalWindow.h" +#include "nsScriptError.h" using namespace mozilla; using namespace JS; diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index 37932b452..77f09f4a5 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -11,9 +11,11 @@ #include "xpcprivate.h" #include "nsIAtom.h" +#include "nsIScriptError.h" #include "nsWrapperCache.h" #include "nsJSUtils.h" #include "nsQueryObject.h" +#include "nsScriptError.h" #include "WrapperFactory.h" #include "nsWrapperCacheInlines.h" diff --git a/js/xpconnect/src/XPCModule.h b/js/xpconnect/src/XPCModule.h index d62764625..506e8945a 100644 --- a/js/xpconnect/src/XPCModule.h +++ b/js/xpconnect/src/XPCModule.h @@ -23,7 +23,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsJSID) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIXPConnect, nsXPConnect::GetSingleton) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptError) NS_GENERIC_FACTORY_CONSTRUCTOR(mozJSComponentLoader) NS_GENERIC_FACTORY_CONSTRUCTOR(mozJSSubScriptLoader) @@ -31,14 +30,12 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(mozJSSubScriptLoader) NS_DEFINE_NAMED_CID(NS_JS_ID_CID); NS_DEFINE_NAMED_CID(NS_XPCONNECT_CID); NS_DEFINE_NAMED_CID(NS_XPCEXCEPTION_CID); -NS_DEFINE_NAMED_CID(NS_SCRIPTERROR_CID); NS_DEFINE_NAMED_CID(MOZJSCOMPONENTLOADER_CID); NS_DEFINE_NAMED_CID(MOZ_JSSUBSCRIPTLOADER_CID); #define XPCONNECT_CIDENTRIES \ { &kNS_JS_ID_CID, false, nullptr, nsJSIDConstructor }, \ { &kNS_XPCONNECT_CID, false, nullptr, nsIXPConnectConstructor }, \ - { &kNS_SCRIPTERROR_CID, false, nullptr, nsScriptErrorConstructor }, \ { &kMOZJSCOMPONENTLOADER_CID, false, nullptr, mozJSComponentLoaderConstructor },\ { &kMOZ_JSSUBSCRIPTLOADER_CID, false, nullptr, mozJSSubScriptLoaderConstructor }, @@ -46,7 +43,6 @@ NS_DEFINE_NAMED_CID(MOZ_JSSUBSCRIPTLOADER_CID); { XPC_ID_CONTRACTID, &kNS_JS_ID_CID }, \ { XPC_XPCONNECT_CONTRACTID, &kNS_XPCONNECT_CID }, \ { XPC_CONTEXT_STACK_CONTRACTID, &kNS_XPCONNECT_CID }, \ - { NS_SCRIPTERROR_CONTRACTID, &kNS_SCRIPTERROR_CID }, \ { MOZJSCOMPONENTLOADER_CONTRACTID, &kMOZJSCOMPONENTLOADER_CID }, \ { MOZJSSUBSCRIPTLOADER_CONTRACTID, &kMOZ_JSSUBSCRIPTLOADER_CID }, diff --git a/js/xpconnect/src/XPCWrappedJSClass.cpp b/js/xpconnect/src/XPCWrappedJSClass.cpp index 2c9fd66bc..e90373e3d 100644 --- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -10,6 +10,7 @@ #include "jsprf.h" #include "nsArrayEnumerator.h" #include "nsContentUtils.h" +#include "nsIScriptError.h" #include "nsWrapperCache.h" #include "AccessCheck.h" #include "nsJSUtils.h" diff --git a/js/xpconnect/src/XPCWrappedNativeInfo.cpp b/js/xpconnect/src/XPCWrappedNativeInfo.cpp index 302454fb5..4b0330af6 100644 --- a/js/xpconnect/src/XPCWrappedNativeInfo.cpp +++ b/js/xpconnect/src/XPCWrappedNativeInfo.cpp @@ -11,6 +11,7 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/XPTInterfaceInfoManager.h" +#include "nsIScriptError.h" #include "nsPrintfCString.h" using namespace JS; diff --git a/js/xpconnect/src/moz.build b/js/xpconnect/src/moz.build index 7e787bb56..7d9cd5b37 100644 --- a/js/xpconnect/src/moz.build +++ b/js/xpconnect/src/moz.build @@ -14,8 +14,6 @@ EXPORTS += [ UNIFIED_SOURCES += [ 'ExportHelpers.cpp', - 'nsScriptError.cpp', - 'nsScriptErrorWithStack.cpp', 'nsXPConnect.cpp', 'Sandbox.cpp', 'XPCCallContext.cpp', @@ -58,6 +56,7 @@ LOCAL_INCLUDES += [ '../wrappers', '/caps', '/dom/base', + '/dom/bindings', '/dom/html', '/dom/svg', '/dom/workers', diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 0466175b1..0d1a6be0a 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -33,7 +33,9 @@ #include "nsIObjectOutputStream.h" #include "nsScriptSecurityManager.h" #include "nsIPermissionManager.h" +#include "nsIScriptError.h" #include "nsContentUtils.h" +#include "nsScriptError.h" #include "jsfriendapi.h" using namespace mozilla; @@ -170,9 +172,31 @@ nsXPConnect::IsISupportsDescendant(nsIInterfaceInfo* info) } void +xpc::ErrorBase::Init(JSErrorBase* aReport) +{ + if (!aReport->filename) { + mFileName.SetIsVoid(true); + } else { + mFileName.AssignWithConversion(aReport->filename); + } + + mLineNumber = aReport->lineno; + mColumn = aReport->column; +} + +void +xpc::ErrorNote::Init(JSErrorNotes::Note* aNote) +{ + xpc::ErrorBase::Init(aNote); + + ErrorNoteToMessageString(aNote, mErrorMsg); +} + +void xpc::ErrorReport::Init(JSErrorReport* aReport, const char* aToStringResult, bool aIsChrome, uint64_t aWindowID) { + xpc::ErrorBase::Init(aReport); mCategory = aIsChrome ? NS_LITERAL_CSTRING("chrome javascript") : NS_LITERAL_CSTRING("content javascript"); mWindowID = aWindowID; @@ -182,12 +206,6 @@ xpc::ErrorReport::Init(JSErrorReport* aReport, const char* aToStringResult, AppendUTF8toUTF16(aToStringResult, mErrorMsg); } - if (!aReport->filename) { - mFileName.SetIsVoid(true); - } else { - mFileName.AssignWithConversion(aReport->filename); - } - mSourceLine.Assign(aReport->linebuf(), aReport->linebufLength()); const JSErrorFormatString* efs = js::GetErrorMessage(nullptr, aReport->errorNumber); @@ -197,10 +215,20 @@ xpc::ErrorReport::Init(JSErrorReport* aReport, const char* aToStringResult, mErrorMsgName.AssignASCII(efs->name); } - mLineNumber = aReport->lineno; - mColumn = aReport->column; mFlags = aReport->flags; mIsMuted = aReport->isMuted; + + if (aReport->notes) { + if (!mNotes.SetLength(aReport->notes->length(), fallible)) { + return; + } + + size_t i = 0; + for (auto&& note : *aReport->notes) { + mNotes.ElementAt(i).Init(note.get()); + i++; + } + } } void @@ -226,6 +254,59 @@ xpc::ErrorReport::Init(JSContext* aCx, mozilla::dom::Exception* aException, static LazyLogModule gJSDiagnostics("JSDiagnostics"); void +xpc::ErrorBase::AppendErrorDetailsTo(nsCString& error) +{ + error.Append(NS_LossyConvertUTF16toASCII(mFileName)); + error.AppendLiteral(", line "); + error.AppendInt(mLineNumber, 10); + error.AppendLiteral(": "); + error.Append(NS_LossyConvertUTF16toASCII(mErrorMsg)); +} + +void +xpc::ErrorNote::LogToStderr() +{ + if (!nsContentUtils::DOMWindowDumpEnabled()) { + return; + } + + nsAutoCString error; + error.AssignLiteral("JavaScript note: "); + AppendErrorDetailsTo(error); + + fprintf(stderr, "%s\n", error.get()); + fflush(stderr); +} + +void +xpc::ErrorReport::LogToStderr() +{ + if (!nsContentUtils::DOMWindowDumpEnabled()) { + return; + } + + nsAutoCString error; + error.AssignLiteral("JavaScript "); + if (JSREPORT_IS_STRICT(mFlags)) { + error.AppendLiteral("strict "); + } + if (JSREPORT_IS_WARNING(mFlags)) { + error.AppendLiteral("warning: "); + } else { + error.AppendLiteral("error: "); + } + AppendErrorDetailsTo(error); + + fprintf(stderr, "%s\n", error.get()); + fflush(stderr); + + for (size_t i = 0, len = mNotes.Length(); i < len; i++) { + ErrorNote& note = mNotes[i]; + note.LogToStderr(); + } +} + +void xpc::ErrorReport::LogToConsole() { LogToConsoleWithStack(nullptr); @@ -233,25 +314,7 @@ xpc::ErrorReport::LogToConsole() void xpc::ErrorReport::LogToConsoleWithStack(JS::HandleObject aStack) { - // Log to stdout. - if (nsContentUtils::DOMWindowDumpEnabled()) { - nsAutoCString error; - error.AssignLiteral("JavaScript "); - if (JSREPORT_IS_STRICT(mFlags)) - error.AppendLiteral("strict "); - if (JSREPORT_IS_WARNING(mFlags)) - error.AppendLiteral("warning: "); - else - error.AppendLiteral("error: "); - error.Append(NS_LossyConvertUTF16toASCII(mFileName)); - error.AppendLiteral(", line "); - error.AppendInt(mLineNumber, 10); - error.AppendLiteral(": "); - error.Append(NS_LossyConvertUTF16toASCII(mErrorMsg)); - - fprintf(stderr, "%s\n", error.get()); - fflush(stderr); - } + LogToStderr(); MOZ_LOG(gJSDiagnostics, JSREPORT_IS_WARNING(mFlags) ? LogLevel::Warning : LogLevel::Error, @@ -263,8 +326,9 @@ xpc::ErrorReport::LogToConsoleWithStack(JS::HandleObject aStack) // mechanisms. nsCOMPtr<nsIConsoleService> consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + NS_ENSURE_TRUE_VOID(consoleService); - nsCOMPtr<nsIScriptError> errorObject; + RefPtr<nsScriptErrorBase> errorObject; if (mWindowID && aStack) { // Only set stack on messages related to a document // As we cache messages in the console service, @@ -275,18 +339,38 @@ xpc::ErrorReport::LogToConsoleWithStack(JS::HandleObject aStack) errorObject = new nsScriptError(); } errorObject->SetErrorMessageName(mErrorMsgName); - NS_ENSURE_TRUE_VOID(consoleService); nsresult rv = errorObject->InitWithWindowID(mErrorMsg, mFileName, mSourceLine, mLineNumber, mColumn, mFlags, mCategory, mWindowID); NS_ENSURE_SUCCESS_VOID(rv); + + for (size_t i = 0, len = mNotes.Length(); i < len; i++) { + ErrorNote& note = mNotes[i]; + + nsScriptErrorNote* noteObject = new nsScriptErrorNote(); + noteObject->Init(note.mErrorMsg, note.mFileName, + note.mLineNumber, note.mColumn); + errorObject->AddNote(noteObject); + } + consoleService->LogMessage(errorObject); } /* static */ void +xpc::ErrorNote::ErrorNoteToMessageString(JSErrorNotes::Note* aNote, + nsAString& aString) +{ + aString.Truncate(); + if (aNote->message()) { + aString.Append(NS_ConvertUTF8toUTF16(aNote->message().c_str())); + } +} + +/* static */ +void xpc::ErrorReport::ErrorReportToMessageString(JSErrorReport* aReport, nsAString& aString) { diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 347b406eb..e55cc06e0 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -128,7 +128,6 @@ #include "MainThreadUtils.h" #include "nsIConsoleService.h" -#include "nsIScriptError.h" #include "nsIException.h" #include "nsVariant.h" @@ -2552,77 +2551,6 @@ extern char* xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals, bool showThisProps); -/***************************************************************************/ - -// Definition of nsScriptError, defined here because we lack a place to put -// XPCOM objects associated with the JavaScript engine. -class nsScriptErrorBase : public nsIScriptError { -public: - nsScriptErrorBase(); - - // TODO - do something reasonable on getting null from these babies. - - NS_DECL_NSICONSOLEMESSAGE - NS_DECL_NSISCRIPTERROR - -protected: - virtual ~nsScriptErrorBase(); - - void - InitializeOnMainThread(); - - nsString mMessage; - nsString mMessageName; - nsString mSourceName; - uint32_t mLineNumber; - nsString mSourceLine; - uint32_t mColumnNumber; - uint32_t mFlags; - nsCString mCategory; - // mOuterWindowID is set on the main thread from InitializeOnMainThread(). - uint64_t mOuterWindowID; - uint64_t mInnerWindowID; - int64_t mTimeStamp; - // mInitializedOnMainThread and mIsFromPrivateWindow are set on the main - // thread from InitializeOnMainThread(). - mozilla::Atomic<bool> mInitializedOnMainThread; - bool mIsFromPrivateWindow; -}; - -class nsScriptError final : public nsScriptErrorBase { -public: - nsScriptError() {} - NS_DECL_THREADSAFE_ISUPPORTS - -private: - virtual ~nsScriptError() {} -}; - -class nsScriptErrorWithStack : public nsScriptErrorBase { -public: - explicit nsScriptErrorWithStack(JS::HandleObject); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsScriptErrorWithStack) - - NS_IMETHOD Init(const nsAString& message, - const nsAString& sourceName, - const nsAString& sourceLine, - uint32_t lineNumber, - uint32_t columnNumber, - uint32_t flags, - const char* category) override; - - NS_IMETHOD GetStack(JS::MutableHandleValue) override; - NS_IMETHOD ToString(nsACString& aResult) override; - -private: - virtual ~nsScriptErrorWithStack(); - // Complete stackframe where the error happened. - // Must be SavedFrame object. - JS::Heap<JSObject*> mStack; -}; - /****************************************************************************** * Handles pre/post script processing. */ diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index fc8670d46..399cd2181 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -515,13 +515,50 @@ AllowCPOWsInAddon(const nsACString& addonId, bool allow); bool ExtraWarningsForSystemJS(); -class ErrorReport { +class ErrorBase { + public: + nsString mErrorMsg; + nsString mFileName; + uint32_t mLineNumber; + uint32_t mColumn; + + ErrorBase() : mLineNumber(0) + , mColumn(0) + {} + + void Init(JSErrorBase* aReport); + + void AppendErrorDetailsTo(nsCString& error); +}; + +class ErrorNote : public ErrorBase { + public: + void Init(JSErrorNotes::Note* aNote); + + // Produce an error event message string from the given JSErrorNotes::Note. + // This may produce an empty string if aNote doesn't have a message + // attached. + static void ErrorNoteToMessageString(JSErrorNotes::Note* aNote, + nsAString& aString); + + // Log the error note to the stderr. + void LogToStderr(); +}; + +class ErrorReport : public ErrorBase { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ErrorReport); + nsTArray<ErrorNote> mNotes; + + nsCString mCategory; + nsString mSourceLine; + nsString mErrorMsgName; + uint64_t mWindowID; + uint32_t mFlags; + bool mIsMuted; + ErrorReport() : mWindowID(0) - , mLineNumber(0) - , mColumn(0) , mFlags(0) , mIsMuted(false) {} @@ -530,6 +567,7 @@ class ErrorReport { bool aIsChrome, uint64_t aWindowID); void Init(JSContext* aCx, mozilla::dom::Exception* aException, bool aIsChrome, uint64_t aWindowID); + // Log the error report to the console. Which console will depend on the // window id it was initialized with. void LogToConsole(); @@ -544,18 +582,8 @@ class ErrorReport { static void ErrorReportToMessageString(JSErrorReport* aReport, nsAString& aString); - public: - - nsCString mCategory; - nsString mErrorMsgName; - nsString mErrorMsg; - nsString mFileName; - nsString mSourceLine; - uint64_t mWindowID; - uint32_t mLineNumber; - uint32_t mColumn; - uint32_t mFlags; - bool mIsMuted; + // Log the error report to the stderr. + void LogToStderr(); private: ~ErrorReport() {} diff --git a/js/xpconnect/tests/chrome/test_bug1041626.xul b/js/xpconnect/tests/chrome/test_bug1041626.xul index c7c7b7024..11529fbe4 100644 --- a/js/xpconnect/tests/chrome/test_bug1041626.xul +++ b/js/xpconnect/tests/chrome/test_bug1041626.xul @@ -28,9 +28,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1041626 ok(Cu.isXrayWrapper(window[0].location), "Location is Xrayed"); let xrayOwnProperties = Object.getOwnPropertyNames(window[0].location); - todo(xrayOwnProperties.indexOf('toJSON') != -1, - "dummy toJSON on Location should show up in Xrayable properties"); - xrayOwnProperties.push('toJSON'); let realOwnProperties = Object.getOwnPropertyNames(window[0].wrappedJSObject.location); ok(realOwnProperties.length > 2); diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index 0031fb127..8c9d38788 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -536,7 +536,7 @@ WrapperFactory::Rewrap(JSContext* cx, HandleObject existing, HandleObject obj) DEBUG_CheckUnwrapSafety(obj, wrapper, origin, target); if (existing) - return Wrapper::Renew(cx, existing, obj, wrapper); + return Wrapper::Renew(existing, obj, wrapper); return Wrapper::New(cx, obj, wrapper); } diff --git a/layout/base/ActiveLayerTracker.cpp b/layout/base/ActiveLayerTracker.cpp index 4f60f82d7..ecee4897a 100644 --- a/layout/base/ActiveLayerTracker.cpp +++ b/layout/base/ActiveLayerTracker.cpp @@ -178,7 +178,7 @@ LayerActivityTracker::NotifyExpired(LayerActivity* aObject) f->SchedulePaint(); } f->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY); - f->Properties().Delete(LayerActivityProperty()); + f->DeleteProperty(LayerActivityProperty()); } else { c->DeleteProperty(nsGkAtoms::LayerActivity); } @@ -190,15 +190,13 @@ GetLayerActivity(nsIFrame* aFrame) if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) { return nullptr; } - FrameProperties properties = aFrame->Properties(); - return properties.Get(LayerActivityProperty()); + return aFrame->GetProperty(LayerActivityProperty()); } static LayerActivity* GetLayerActivityForUpdate(nsIFrame* aFrame) { - FrameProperties properties = aFrame->Properties(); - LayerActivity* layerActivity = properties.Get(LayerActivityProperty()); + LayerActivity* layerActivity = aFrame->GetProperty(LayerActivityProperty()); if (layerActivity) { gLayerActivityTracker->MarkUsed(layerActivity); } else { @@ -208,7 +206,7 @@ GetLayerActivityForUpdate(nsIFrame* aFrame) layerActivity = new LayerActivity(aFrame); gLayerActivityTracker->AddObject(layerActivity); aFrame->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY); - properties.Set(LayerActivityProperty(), layerActivity); + aFrame->SetProperty(LayerActivityProperty(), layerActivity); } return layerActivity; } @@ -225,8 +223,7 @@ ActiveLayerTracker::TransferActivityToContent(nsIFrame* aFrame, nsIContent* aCon if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) { return; } - FrameProperties properties = aFrame->Properties(); - LayerActivity* layerActivity = properties.Remove(LayerActivityProperty()); + LayerActivity* layerActivity = aFrame->RemoveProperty(LayerActivityProperty()); aFrame->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY); if (!layerActivity) { return; @@ -248,7 +245,7 @@ ActiveLayerTracker::TransferActivityToFrame(nsIContent* aContent, nsIFrame* aFra layerActivity->mContent = nullptr; layerActivity->mFrame = aFrame; aFrame->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY); - aFrame->Properties().Set(LayerActivityProperty(), layerActivity); + aFrame->SetProperty(LayerActivityProperty(), layerActivity); } static void diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 9aaa28fb5..934d108e0 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -165,10 +165,10 @@ FrameLayerBuilder::DisplayItemData::AddFrame(nsIFrame* aFrame) mFrameList.AppendElement(aFrame); nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty()); + aFrame->GetProperty(FrameLayerBuilder::LayerManagerDataProperty()); if (!array) { array = new nsTArray<DisplayItemData*>(); - aFrame->Properties().Set(FrameLayerBuilder::LayerManagerDataProperty(), array); + aFrame->SetProperty(FrameLayerBuilder::LayerManagerDataProperty(), array); } array->AppendElement(this); } @@ -181,7 +181,7 @@ FrameLayerBuilder::DisplayItemData::RemoveFrame(nsIFrame* aFrame) MOZ_RELEASE_ASSERT(result, "Can't remove a frame that wasn't added!"); nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(FrameLayerBuilder::LayerManagerDataProperty()); + aFrame->GetProperty(FrameLayerBuilder::LayerManagerDataProperty()); MOZ_RELEASE_ASSERT(array, "Must be already stored on the frame!"); array->RemoveElement(this); } @@ -268,12 +268,17 @@ FrameLayerBuilder::DisplayItemData::~DisplayItemData() continue; } nsTArray<DisplayItemData*> *array = - reinterpret_cast<nsTArray<DisplayItemData*>*>(frame->Properties().Get(LayerManagerDataProperty())); + reinterpret_cast<nsTArray<DisplayItemData*>*>(frame->GetProperty(LayerManagerDataProperty())); array->RemoveElement(this); } - MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas && sAliveDisplayItemDatas->Contains(this)); - sAliveDisplayItemDatas->RemoveEntry(this); + MOZ_RELEASE_ASSERT(sAliveDisplayItemDatas); + nsPtrHashKey<mozilla::FrameLayerBuilder::DisplayItemData>* entry + = sAliveDisplayItemDatas->GetEntry(this); + MOZ_RELEASE_ASSERT(entry); + + sAliveDisplayItemDatas->RemoveEntry(entry); + if (sAliveDisplayItemDatas->Count() == 0) { delete sAliveDisplayItemDatas; sAliveDisplayItemDatas = nullptr; @@ -390,8 +395,7 @@ public: /* static */ void FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame) { - FrameProperties props = aFrame->Properties(); - props.Delete(LayerManagerDataProperty()); + aFrame->DeleteProperty(LayerManagerDataProperty()); } struct AssignedDisplayItem @@ -1823,7 +1827,7 @@ FrameLayerBuilder::DisplayItemData* FrameLayerBuilder::GetDisplayItemData(nsIFrame* aFrame, uint32_t aKey) { const nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (array) { for (uint32_t i = 0; i < array->Length(); i++) { DisplayItemData* item = AssertDisplayItemData(array->ElementAt(i)); @@ -2052,7 +2056,7 @@ FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem, LayerManager* aManager) { const nsTArray<DisplayItemData*>* array = - aItem->Frame()->Properties().Get(LayerManagerDataProperty()); + aItem->Frame()->GetProperty(LayerManagerDataProperty()); if (array) { for (uint32_t i = 0; i < array->Length(); i++) { DisplayItemData* item = AssertDisplayItemData(array->ElementAt(i)); @@ -2069,7 +2073,7 @@ bool FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) { const nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (array) { for (uint32_t i = 0; i < array->Length(); i++) { if (AssertDisplayItemData(array->ElementAt(i))->mDisplayItemKey == aDisplayItemKey) { @@ -2084,7 +2088,7 @@ void FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback) { const nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (!array) { return; } @@ -2151,7 +2155,7 @@ FrameLayerBuilder::ClearCachedGeometry(nsDisplayItem* aItem) FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) { const nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (!array) { return nullptr; @@ -2171,7 +2175,7 @@ FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKe FrameLayerBuilder::GetDebugSingleOldPaintedLayerForFrame(nsIFrame* aFrame) { const nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (!array) { return nullptr; @@ -5656,7 +5660,7 @@ FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager) FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame) { const nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (array) { for (uint32_t i = 0; i < array->Length(); i++) { AssertDisplayItemData(array->ElementAt(i))->mParent->mInvalidateAllLayers = true; @@ -5673,7 +5677,7 @@ FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey) // in the secondary manager const nsTArray<DisplayItemData*>* array = - aFrame->Properties().Get(LayerManagerDataProperty()); + aFrame->GetProperty(LayerManagerDataProperty()); if (array) { for (uint32_t i = 0; i < array->Length(); i++) { DisplayItemData *element = AssertDisplayItemData(array->ElementAt(i)); @@ -5729,7 +5733,7 @@ FrameLayerBuilder::GetPaintedLayerScaleForFrame(nsIFrame* aFrame) } const nsTArray<DisplayItemData*>* array = - f->Properties().Get(LayerManagerDataProperty()); + f->GetProperty(LayerManagerDataProperty()); if (!array) { continue; } @@ -6165,9 +6169,8 @@ FrameLayerBuilder::GetMostRecentGeometry(nsDisplayItem* aItem) typedef nsTArray<DisplayItemData*> DataArray; // Retrieve the array of DisplayItemData associated with our frame. - FrameProperties properties = aItem->Frame()->Properties(); const DataArray* dataArray = - properties.Get(LayerManagerDataProperty()); + aItem->Frame()->GetProperty(LayerManagerDataProperty()); if (!dataArray) { return nullptr; } diff --git a/layout/base/FramePropertyTable.h b/layout/base/FrameProperties.h index e9847efbf..3884b07bd 100644 --- a/layout/base/FramePropertyTable.h +++ b/layout/base/FrameProperties.h @@ -3,15 +3,15 @@ * 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 FRAMEPROPERTYTABLE_H_ -#define FRAMEPROPERTYTABLE_H_ +#ifndef FRAMEPROPERTIES_H_ +#define FRAMEPROPERTIES_H_ +#include "mozilla/DebugOnly.h" #include "mozilla/MemoryReporting.h" #include "mozilla/TypeTraits.h" #include "mozilla/Unused.h" #include "nsTArray.h" -#include "nsTHashtable.h" -#include "nsHashKeys.h" +#include "nsThreadUtils.h" class nsIFrame; @@ -62,7 +62,7 @@ protected: * * To use this class, declare a global (i.e., file, class or function-scope * static member) FramePropertyDescriptor and pass its address as - * aProperty in the FramePropertyTable methods. + * aProperty in the FrameProperties methods. */ template<typename T> struct FramePropertyDescriptor : public FramePropertyDescriptorUntyped @@ -131,7 +131,7 @@ struct FramePropertyTypeHelper<SmallValueHolder<T>> } /** - * The FramePropertyTable is optimized for storing 0 or 1 properties on + * The FrameProperties class is optimized for storing 0 or 1 properties on * a given frame. Storing very large numbers of properties on a single * frame will not be efficient. * @@ -141,7 +141,8 @@ struct FramePropertyTypeHelper<SmallValueHolder<T>> * Of course, the destructor function (if any) must handle such values * correctly. */ -class FramePropertyTable { +class FrameProperties +{ public: template<typename T> using Descriptor = const FramePropertyDescriptor<T>*; @@ -150,32 +151,36 @@ public: template<typename T> using PropertyType = typename detail::FramePropertyTypeHelper<T>::Type; - FramePropertyTable() : mLastFrame(nullptr), mLastEntry(nullptr) + explicit FrameProperties() { } - ~FramePropertyTable() + + ~FrameProperties() { - DeleteAll(); + MOZ_ASSERT(mProperties.Length() == 0, "forgot to delete properties"); } /** - * Set a property value on a frame. This requires one hashtable - * lookup (using the frame as the key) and a linear search through - * the properties of that frame. Any existing value for the property + * Return true if we have no properties, otherwise return false. + */ + bool IsEmpty() const { return mProperties.IsEmpty(); } + + /** + * Set a property value. This requires a linear search through + * the properties of the frame. Any existing value for the property * is destroyed. */ template<typename T> - void Set(const nsIFrame* aFrame, Descriptor<T> aProperty, - PropertyType<T> aValue) + void Set(Descriptor<T> aProperty, PropertyType<T> aValue, + const nsIFrame* aFrame) { void* ptr = ReinterpretHelper<T>::ToPointer(aValue); - SetInternal(aFrame, aProperty, ptr); + SetInternal(aProperty, ptr, aFrame); } /** - * @return true if @aProperty is set for @aFrame. This requires one hashtable - * lookup (using the frame as the key) and a linear search through the - * properties of that frame. + * @return true if @aProperty is set. This requires a linear search through the + * properties of the frame. * * In most cases, this shouldn't be used outside of assertions, because if * you're doing a lookup anyway it would be far more efficient to call Get() @@ -190,17 +195,14 @@ public: * an existing value for the frame property. */ template<typename T> - bool Has(const nsIFrame* aFrame, Descriptor<T> aProperty) + bool Has(Descriptor<T> aProperty) const { - bool foundResult = false; - mozilla::Unused << GetInternal(aFrame, aProperty, &foundResult); - return foundResult; + return mProperties.IndexOf(aProperty, 0, PropertyComparator()) != nsTArray<PropertyValue>::NoIndex; } /** - * Get a property value for a frame. This requires one hashtable - * lookup (using the frame as the key) and a linear search through - * the properties of that frame. If the frame has no such property, + * Get a property value. This requires a linear search through + * the properties of the frame. If the frame has no such property, * returns zero-filled result, which means null for pointers and * zero for integers and floating point types. * @param aFoundResult if non-null, receives a value 'true' iff @@ -209,16 +211,15 @@ public: * 'property value is null'. */ template<typename T> - PropertyType<T> Get(const nsIFrame* aFrame, Descriptor<T> aProperty, - bool* aFoundResult = nullptr) + PropertyType<T> Get(Descriptor<T> aProperty, + bool* aFoundResult = nullptr) const { - void* ptr = GetInternal(aFrame, aProperty, aFoundResult); + void* ptr = GetInternal(aProperty, aFoundResult); return ReinterpretHelper<T>::FromPointer(ptr); } /** - * Remove a property value for a frame. This requires one hashtable - * lookup (using the frame as the key) and a linear search through - * the properties of that frame. The old property value is returned + * Remove a property value. This requires a linear search through + * the properties of the frame. The old property value is returned * (and not destroyed). If the frame has no such property, * returns zero-filled result, which means null for pointers and * zero for integers and floating point types. @@ -228,46 +229,85 @@ public: * 'property value is null'. */ template<typename T> - PropertyType<T> Remove(const nsIFrame* aFrame, Descriptor<T> aProperty, + PropertyType<T> Remove(Descriptor<T> aProperty, bool* aFoundResult = nullptr) { - void* ptr = RemoveInternal(aFrame, aProperty, aFoundResult); + void* ptr = RemoveInternal(aProperty, aFoundResult); return ReinterpretHelper<T>::FromPointer(ptr); } /** - * Remove and destroy a property value for a frame. This requires one - * hashtable lookup (using the frame as the key) and a linear search - * through the properties of that frame. If the frame has no such + * Remove and destroy a property value. This requires a linear search + * through the properties of the frame. If the frame has no such * property, nothing happens. */ template<typename T> - void Delete(const nsIFrame* aFrame, Descriptor<T> aProperty) + void Delete(Descriptor<T> aProperty, const nsIFrame* aFrame) { - DeleteInternal(aFrame, aProperty); + DeleteInternal(aProperty, aFrame); } + /** - * Remove and destroy all property values for a frame. This requires one - * hashtable lookup (using the frame as the key). + * Call @aFunction for each property or until @aFunction returns false. */ - void DeleteAllFor(const nsIFrame* aFrame); + template<class F> + void ForEach(F aFunction) const + { +#ifdef DEBUG + size_t len = mProperties.Length(); +#endif + for (const auto& prop : mProperties) { + bool shouldContinue = aFunction(prop.mProperty, prop.mValue); +#ifdef DEBUG + MOZ_ASSERT(len == mProperties.Length(), + "frame property list was modified by ForEach callback!"); +#endif + if (!shouldContinue) { + return; + } + } + } + /** - * Remove and destroy all property values for all frames. + * Remove and destroy all property values for the frame. */ - void DeleteAll(); + void DeleteAll(const nsIFrame* aFrame) { + mozilla::DebugOnly<size_t> len = mProperties.Length(); + for (auto& prop : mProperties) { + prop.DestroyValueFor(aFrame); + MOZ_ASSERT(mProperties.Length() == len); + } + mProperties.Clear(); + } - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { + // We currently report only the shallow size of the mProperties array. + // As for the PropertyValue entries: we don't need to measure the mProperty + // field of because it always points to static memory, and we can't measure + // mValue because the type is opaque. + // XXX Can we do better, e.g. with a method on the descriptor? + return mProperties.ShallowSizeOfExcludingThis(aMallocSizeOf); + } -protected: - void SetInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty, - void* aValue); +private: + friend class ::nsIFrame; - void* GetInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty, - bool* aFoundResult); + // Prevent copying of FrameProperties; we should always return/pass around + // references to it, not copies! + FrameProperties(const FrameProperties&) = delete; + FrameProperties& operator=(const FrameProperties&) = delete; - void* RemoveInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty, - bool* aFoundResult); + inline void + SetInternal(UntypedDescriptor aProperty, void* aValue, + const nsIFrame* aFrame); - void DeleteInternal(const nsIFrame* aFrame, UntypedDescriptor aProperty); + inline void* + GetInternal(UntypedDescriptor aProperty, bool* aFoundResult) const; + + inline void* + RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult); + + inline void + DeleteInternal(UntypedDescriptor aProperty, const nsIFrame* aFrame); template<typename T> struct ReinterpretHelper @@ -305,21 +345,13 @@ protected: }; /** - * Stores a property descriptor/value pair. It can also be used to - * store an nsTArray of PropertyValues. + * Stores a property descriptor/value pair. */ struct PropertyValue { PropertyValue() : mProperty(nullptr), mValue(nullptr) {} PropertyValue(UntypedDescriptor aProperty, void* aValue) : mProperty(aProperty), mValue(aValue) {} - bool IsArray() { return !mProperty && mValue; } - nsTArray<PropertyValue>* ToArray() - { - NS_ASSERTION(IsArray(), "Must be array"); - return reinterpret_cast<nsTArray<PropertyValue>*>(&mValue); - } - void DestroyValueFor(const nsIFrame* aFrame) { if (mProperty->mDestructor) { mProperty->mDestructor(mValue); @@ -328,20 +360,6 @@ protected: } } - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) { - size_t n = 0; - // We don't need to measure mProperty because it always points to static - // memory. As for mValue: if it's a single value we can't measure it, - // because the type is opaque; if it's an array, we measure the array - // storage, but we can't measure the individual values, again because - // their types are opaque. - if (IsArray()) { - nsTArray<PropertyValue>* array = ToArray(); - n += array->ShallowSizeOfExcludingThis(aMallocSizeOf); - } - return n; - } - UntypedDescriptor mProperty; void* mValue; }; @@ -363,80 +381,86 @@ protected: } }; - /** - * Our hashtable entry. The key is an nsIFrame*, the value is a - * PropertyValue representing one or more property/value pairs. - */ - class Entry : public nsPtrHashKey<const nsIFrame> - { - public: - explicit Entry(KeyTypePointer aKey) : nsPtrHashKey<const nsIFrame>(aKey) {} - Entry(const Entry &toCopy) : - nsPtrHashKey<const nsIFrame>(toCopy), mProp(toCopy.mProp) {} - - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) { - return mProp.SizeOfExcludingThis(aMallocSizeOf); - } - - PropertyValue mProp; - }; - - static void DeleteAllForEntry(Entry* aEntry); - - // Note that mLastEntry points into mEntries, so we need to be careful about - // not triggering a resize of mEntries, e.g. use RawRemoveEntry() instead of - // RemoveEntry() in some places. - nsTHashtable<Entry> mEntries; - const nsIFrame* mLastFrame; - Entry* mLastEntry; + nsTArray<PropertyValue> mProperties; }; /** * This class encapsulates the properties of a frame. */ -class FrameProperties { -public: - template<typename T> using Descriptor = FramePropertyTable::Descriptor<T>; - template<typename T> using PropertyType = FramePropertyTable::PropertyType<T>; - - FrameProperties(FramePropertyTable* aTable, const nsIFrame* aFrame) - : mTable(aTable), mFrame(aFrame) {} +inline void* +FrameProperties::GetInternal(UntypedDescriptor aProperty, + bool* aFoundResult) const +{ + MOZ_ASSERT(aProperty, "Null property?"); - template<typename T> - void Set(Descriptor<T> aProperty, PropertyType<T> aValue) const - { - mTable->Set(mFrame, aProperty, aValue); + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index == nsTArray<PropertyValue>::NoIndex) { + if (aFoundResult) { + *aFoundResult = false; + } + return nullptr; } - template<typename T> - bool Has(Descriptor<T> aProperty) const - { - return mTable->Has(mFrame, aProperty); + if (aFoundResult) { + *aFoundResult = true; } - template<typename T> - PropertyType<T> Get(Descriptor<T> aProperty, - bool* aFoundResult = nullptr) const - { - return mTable->Get(mFrame, aProperty, aFoundResult); - } - template<typename T> - PropertyType<T> Remove(Descriptor<T> aProperty, - bool* aFoundResult = nullptr) const - { - return mTable->Remove(mFrame, aProperty, aFoundResult); +return mProperties.ElementAt(index).mValue; +} + +inline void +FrameProperties::SetInternal(UntypedDescriptor aProperty, void* aValue, + const nsIFrame* aFrame) +{ + MOZ_ASSERT(aProperty, "Null property?"); + + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index != nsTArray<PropertyValue>::NoIndex) { + PropertyValue* pv = &mProperties.ElementAt(index); + pv->DestroyValueFor(aFrame); + pv->mValue = aValue; + return; } - template<typename T> - void Delete(Descriptor<T> aProperty) - { - mTable->Delete(mFrame, aProperty); + + mProperties.AppendElement(PropertyValue(aProperty, aValue)); +} + +inline void* +FrameProperties::RemoveInternal(UntypedDescriptor aProperty, bool* aFoundResult) +{ + MOZ_ASSERT(aProperty, "Null property?"); + + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index == nsTArray<PropertyValue>::NoIndex) { + if (aFoundResult) { + *aFoundResult = false; + } + return nullptr; } -private: - FramePropertyTable* mTable; - const nsIFrame* mFrame; -}; +if (aFoundResult) { + *aFoundResult = true; +} + +void* result = mProperties.ElementAt(index).mValue; +mProperties.RemoveElementAt(index); + +return result; +} + +inline void +FrameProperties::DeleteInternal(UntypedDescriptor aProperty, + const nsIFrame* aFrame) +{ + MOZ_ASSERT(aProperty, "Null property?"); + + auto index = mProperties.IndexOf(aProperty, 0, PropertyComparator()); + if (index != nsTArray<PropertyValue>::NoIndex) { + mProperties.ElementAt(index).DestroyValueFor(aFrame); + mProperties.RemoveElementAt(index); + } +} } // namespace mozilla -#endif /* FRAMEPROPERTYTABLE_H_ */ +#endif /* FRAMEPROPERTIES_H_ */ diff --git a/layout/base/FramePropertyTable.cpp b/layout/base/FramePropertyTable.cpp deleted file mode 100644 index 0fd9b1c37..000000000 --- a/layout/base/FramePropertyTable.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "FramePropertyTable.h" - -#include "mozilla/MemoryReporting.h" - -namespace mozilla { - -void -FramePropertyTable::SetInternal( - const nsIFrame* aFrame, UntypedDescriptor aProperty, void* aValue) -{ - NS_ASSERTION(aFrame, "Null frame?"); - NS_ASSERTION(aProperty, "Null property?"); - - if (mLastFrame != aFrame || !mLastEntry) { - mLastFrame = aFrame; - mLastEntry = mEntries.PutEntry(aFrame); - } - Entry* entry = mLastEntry; - - if (!entry->mProp.IsArray()) { - if (!entry->mProp.mProperty) { - // Empty entry, so we can just store our property in the empty slot - entry->mProp.mProperty = aProperty; - entry->mProp.mValue = aValue; - return; - } - if (entry->mProp.mProperty == aProperty) { - // Just overwrite the current value - entry->mProp.DestroyValueFor(aFrame); - entry->mProp.mValue = aValue; - return; - } - - // We need to expand the single current entry to an array - PropertyValue current = entry->mProp; - entry->mProp.mProperty = nullptr; - static_assert(sizeof(nsTArray<PropertyValue>) <= sizeof(void *), - "Property array must fit entirely within entry->mProp.mValue"); - new (&entry->mProp.mValue) nsTArray<PropertyValue>(4); - entry->mProp.ToArray()->AppendElement(current); - } - - nsTArray<PropertyValue>* array = entry->mProp.ToArray(); - nsTArray<PropertyValue>::index_type index = - array->IndexOf(aProperty, 0, PropertyComparator()); - if (index != nsTArray<PropertyValue>::NoIndex) { - PropertyValue* pv = &array->ElementAt(index); - pv->DestroyValueFor(aFrame); - pv->mValue = aValue; - return; - } - - array->AppendElement(PropertyValue(aProperty, aValue)); -} - -void* -FramePropertyTable::GetInternal( - const nsIFrame* aFrame, UntypedDescriptor aProperty, bool* aFoundResult) -{ - NS_ASSERTION(aFrame, "Null frame?"); - NS_ASSERTION(aProperty, "Null property?"); - - if (aFoundResult) { - *aFoundResult = false; - } - - if (mLastFrame != aFrame) { - mLastFrame = aFrame; - mLastEntry = mEntries.GetEntry(mLastFrame); - } - Entry* entry = mLastEntry; - if (!entry) - return nullptr; - - if (entry->mProp.mProperty == aProperty) { - if (aFoundResult) { - *aFoundResult = true; - } - return entry->mProp.mValue; - } - if (!entry->mProp.IsArray()) { - // There's just one property and it's not the one we want, bail - return nullptr; - } - - nsTArray<PropertyValue>* array = entry->mProp.ToArray(); - nsTArray<PropertyValue>::index_type index = - array->IndexOf(aProperty, 0, PropertyComparator()); - if (index == nsTArray<PropertyValue>::NoIndex) - return nullptr; - - if (aFoundResult) { - *aFoundResult = true; - } - - return array->ElementAt(index).mValue; -} - -void* -FramePropertyTable::RemoveInternal( - const nsIFrame* aFrame, UntypedDescriptor aProperty, bool* aFoundResult) -{ - NS_ASSERTION(aFrame, "Null frame?"); - NS_ASSERTION(aProperty, "Null property?"); - - if (aFoundResult) { - *aFoundResult = false; - } - - if (mLastFrame != aFrame) { - mLastFrame = aFrame; - mLastEntry = mEntries.GetEntry(aFrame); - } - Entry* entry = mLastEntry; - if (!entry) - return nullptr; - - if (entry->mProp.mProperty == aProperty) { - // There's only one entry and it's the one we want - void* value = entry->mProp.mValue; - - // Here it's ok to use RemoveEntry() -- which may resize mEntries -- - // because we null mLastEntry at the same time. - mEntries.RemoveEntry(entry); - mLastEntry = nullptr; - if (aFoundResult) { - *aFoundResult = true; - } - return value; - } - if (!entry->mProp.IsArray()) { - // There's just one property and it's not the one we want, bail - return nullptr; - } - - nsTArray<PropertyValue>* array = entry->mProp.ToArray(); - nsTArray<PropertyValue>::index_type index = - array->IndexOf(aProperty, 0, PropertyComparator()); - if (index == nsTArray<PropertyValue>::NoIndex) { - // No such property, bail - return nullptr; - } - - if (aFoundResult) { - *aFoundResult = true; - } - - void* result = array->ElementAt(index).mValue; - - uint32_t last = array->Length() - 1; - array->ElementAt(index) = array->ElementAt(last); - array->RemoveElementAt(last); - - if (last == 1) { - PropertyValue pv = array->ElementAt(0); - array->~nsTArray<PropertyValue>(); - entry->mProp = pv; - } - - return result; -} - -void -FramePropertyTable::DeleteInternal( - const nsIFrame* aFrame, UntypedDescriptor aProperty) -{ - NS_ASSERTION(aFrame, "Null frame?"); - NS_ASSERTION(aProperty, "Null property?"); - - bool found; - void* v = RemoveInternal(aFrame, aProperty, &found); - if (found) { - PropertyValue pv(aProperty, v); - pv.DestroyValueFor(aFrame); - } -} - -/* static */ void -FramePropertyTable::DeleteAllForEntry(Entry* aEntry) -{ - if (!aEntry->mProp.IsArray()) { - aEntry->mProp.DestroyValueFor(aEntry->GetKey()); - return; - } - - nsTArray<PropertyValue>* array = aEntry->mProp.ToArray(); - for (uint32_t i = 0; i < array->Length(); ++i) { - array->ElementAt(i).DestroyValueFor(aEntry->GetKey()); - } - array->~nsTArray<PropertyValue>(); -} - -void -FramePropertyTable::DeleteAllFor(const nsIFrame* aFrame) -{ - NS_ASSERTION(aFrame, "Null frame?"); - - Entry* entry = mEntries.GetEntry(aFrame); - if (!entry) - return; - - if (mLastFrame == aFrame) { - // Flush cache. We assume DeleteAllForEntry will be called before - // a frame is destroyed. - mLastFrame = nullptr; - mLastEntry = nullptr; - } - - DeleteAllForEntry(entry); - - // mLastEntry points into mEntries, so we use RawRemoveEntry() which will not - // resize mEntries. - mEntries.RawRemoveEntry(entry); -} - -void -FramePropertyTable::DeleteAll() -{ - mLastFrame = nullptr; - mLastEntry = nullptr; - - for (auto iter = mEntries.Iter(); !iter.Done(); iter.Next()) { - DeleteAllForEntry(iter.Get()); - } - mEntries.Clear(); -} - -size_t -FramePropertyTable::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const -{ - return mEntries.SizeOfExcludingThis(aMallocSizeOf); -} - -} // namespace mozilla diff --git a/layout/base/OverflowChangedTracker.h b/layout/base/OverflowChangedTracker.h index a18d64b46..40145c65c 100644 --- a/layout/base/OverflowChangedTracker.h +++ b/layout/base/OverflowChangedTracker.h @@ -112,12 +112,12 @@ public: // Take a faster path that doesn't require unioning the overflow areas // of our children. - NS_ASSERTION(frame->Properties().Get( + NS_ASSERTION(frame->GetProperty( nsIFrame::DebugInitialOverflowPropertyApplied()), "InitialOverflowProperty must be set first."); nsOverflowAreas* overflow = - frame->Properties().Get(nsIFrame::InitialOverflowProperty()); + frame->GetProperty(nsIFrame::InitialOverflowProperty()); if (overflow) { // FinishAndStoreOverflow will change the overflow areas passed in, // so make a copy. diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index de8f10224..124b5535e 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -1122,10 +1122,10 @@ GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame) // We're the first continuation, so we can just get the frame // property directly prevContinuation = - aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling()); + aFrame->GetProperty(nsIFrame::IBSplitPrevSibling()); if (prevContinuation) { prevContinuation = - prevContinuation->Properties().Get(nsIFrame::IBSplitPrevSibling()); + prevContinuation->GetProperty(nsIFrame::IBSplitPrevSibling()); } } @@ -1313,8 +1313,7 @@ RestyleManager::ReparentStyleContext(nsIFrame* aFrame) // oldContext)" check will prevent us from redoing work. if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) && !aFrame->GetPrevContinuation()) { - nsIFrame* sib = - aFrame->Properties().Get(nsIFrame::IBSplitSibling()); + nsIFrame* sib = aFrame->GetProperty(nsIFrame::IBSplitSibling()); if (sib) { ReparentStyleContext(sib); } @@ -3349,7 +3348,6 @@ ElementRestyler::ComputeStyleChangeFor(nsIFrame* aFrame, // line), we might restyle more than that. nsPresContext* presContext = aFrame->PresContext(); - FramePropertyTable* propTable = presContext->PropertyTable(); TreeMatchContext treeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited, @@ -3363,7 +3361,7 @@ ElementRestyler::ComputeStyleChangeFor(nsIFrame* aFrame, nsTArray<nsIContent*> visibleKidsOfHiddenElement; nsIFrame* nextIBSibling; for (nsIFrame* ibSibling = aFrame; ibSibling; ibSibling = nextIBSibling) { - nextIBSibling = RestyleManager::GetNextBlockInInlineSibling(propTable, ibSibling); + nextIBSibling = RestyleManager::GetNextBlockInInlineSibling(ibSibling); if (nextIBSibling) { // Don't allow some ib-split siblings to be processed with diff --git a/layout/base/RestyleManagerBase.cpp b/layout/base/RestyleManagerBase.cpp index d96d9dbbb..6770f9464 100644 --- a/layout/base/RestyleManagerBase.cpp +++ b/layout/base/RestyleManagerBase.cpp @@ -385,8 +385,6 @@ RestyleManagerBase::DebugVerifyStyleTree(nsIFrame* aFrame) #endif // DEBUG -NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ChangeListProperty, bool) - /** * Sync views on aFrame and all of aFrame's descendants (following placeholders), * if aChange has nsChangeHint_SyncFrameView. @@ -521,10 +519,9 @@ RecomputePosition(nsIFrame* aFrame) // normal position, go ahead and add the offsets directly. // First, we need to ensure that the normal position is stored though. nsPoint normalPosition = cont->GetNormalPosition(); - auto props = cont->Properties(); - const auto& prop = nsIFrame::NormalPositionProperty(); - if (!props.Get(prop)) { - props.Set(prop, new nsPoint(normalPosition)); + if (!cont->GetProperty(nsIFrame::NormalPositionProperty())) { + cont->SetProperty(nsIFrame::NormalPositionProperty(), + new nsPoint(normalPosition)); } cont->SetPosition(normalPosition + nsPoint(newOffsets.left, newOffsets.top)); @@ -739,8 +736,7 @@ RestyleManagerBase::GetNearestAncestorFrame(nsIContent* aContent) } /* static */ nsIFrame* -RestyleManagerBase::GetNextBlockInInlineSibling(FramePropertyTable* aPropTable, - nsIFrame* aFrame) +RestyleManagerBase::GetNextBlockInInlineSibling(nsIFrame* aFrame) { NS_ASSERTION(!aFrame->GetPrevContinuation(), "must start with the first continuation"); @@ -750,8 +746,7 @@ RestyleManagerBase::GetNextBlockInInlineSibling(FramePropertyTable* aPropTable, return nullptr; } - return static_cast<nsIFrame*> - (aPropTable->Get(aFrame, nsIFrame::IBSplitSibling())); + return aFrame->GetProperty(nsIFrame::IBSplitSibling()); } static void @@ -1028,10 +1023,10 @@ RestyleManagerBase::GetNextContinuationWithSameStyle( // We're the last continuation, so we have to hop back to the first // before getting the frame property nextContinuation = - aFrame->FirstContinuation()->Properties().Get(nsIFrame::IBSplitSibling()); + aFrame->FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling()); if (nextContinuation) { nextContinuation = - nextContinuation->Properties().Get(nsIFrame::IBSplitSibling()); + nextContinuation->GetProperty(nsIFrame::IBSplitSibling()); } } @@ -1060,14 +1055,52 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) { NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), "Someone forgot a script blocker"); - if (aChangeList.IsEmpty()) - return NS_OK; + +// See bug 1378219 comment 9: +// Recursive calls here are a bit worrying, but apparently do happen in the +// wild (although not currently in any of our automated tests). Try to get a +// stack from Nightly/Dev channel to figure out what's going on and whether +// it's OK. +MOZ_DIAGNOSTIC_ASSERT(!mDestroyedFrames, "ProcessRestyledFrames recursion"); + +if (aChangeList.IsEmpty()) + return NS_OK; + +// If mDestroyedFrames is null, we want to create a new hashtable here +// and destroy it on exit; but if it is already non-null (because we're in +// a recursive call), we will continue to use the existing table to +// accumulate destroyed frames, and NOT clear mDestroyedFrames on exit. +// We use a MaybeClearDestroyedFrames helper to conditionally reset the +// mDestroyedFrames pointer when this method returns. +typedef decltype(mDestroyedFrames) DestroyedFramesT; +class MOZ_RAII MaybeClearDestroyedFrames +{ +private: + DestroyedFramesT& mDestroyedFramesRef; // ref to caller's mDestroyedFrames + const bool mResetOnDestruction; +public: + explicit MaybeClearDestroyedFrames(DestroyedFramesT& aTarget) + : mDestroyedFramesRef(aTarget) + , mResetOnDestruction(!aTarget) // reset only if target starts out null + { + } + ~MaybeClearDestroyedFrames() + { + if (mResetOnDestruction) { + mDestroyedFramesRef.reset(nullptr); + } + } +}; + +MaybeClearDestroyedFrames maybeClear(mDestroyedFrames); +if (!mDestroyedFrames) { + mDestroyedFrames = MakeUnique<nsTHashtable<nsPtrHashKey<const nsIFrame>>>(); +} PROFILER_LABEL("RestyleManager", "ProcessRestyledFrames", js::ProfileEntry::Category::CSS); nsPresContext* presContext = PresContext(); - FramePropertyTable* propTable = presContext->PropertyTable(); nsCSSFrameConstructor* frameConstructor = presContext->FrameConstructor(); // Handle nsChangeHint_CSSOverflowChange, by either updating the @@ -1135,15 +1168,6 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) // processing restyles frameConstructor->BeginUpdate(); - // Mark frames so that we skip frames that die along the way, bug 123049. - // A frame can be in the list multiple times with different hints. Further - // optmization is possible if nsStyleChangeList::AppendChange could coalesce - for (const nsStyleChangeData& data : aChangeList) { - if (data.mFrame) { - propTable->Set(data.mFrame, ChangeListProperty(), true); - } - } - bool didUpdateCursor = false; for (const nsStyleChangeData& data : aChangeList) { @@ -1157,7 +1181,7 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) "Reflow hint bits set without actually asking for a reflow"); // skip any frame that has been destroyed due to a ripple effect - if (frame && !propTable->Get(frame, ChangeListProperty())) { + if (frame && mDestroyedFrames->Contains(frame)) { continue; } @@ -1409,15 +1433,11 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) frameConstructor->EndUpdate(); - // cleanup references and verify the style tree. Note that the latter needs - // to happen once we've processed the whole list, since until then the tree - // is not in fact in a consistent state. - for (const nsStyleChangeData& data : aChangeList) { - if (data.mFrame) { - propTable->Delete(data.mFrame, ChangeListProperty()); - } - #ifdef DEBUG + // Verify the style tree. Note that this needs to happen once we've + // processed the whole list, since until then the tree is not in fact in a + // consistent state. + for (const nsStyleChangeData& data : aChangeList) { // reget frame from content since it may have been regenerated... if (data.mContent) { nsIFrame* frame = data.mContent->GetPrimaryFrame(); @@ -1429,8 +1449,8 @@ RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList& aChangeList) NS_WARNING("Unable to test style tree integrity -- no content node " "(and not a viewport frame)"); } -#endif } +#endif aChangeList.Clear(); return NS_OK; diff --git a/layout/base/RestyleManagerBase.h b/layout/base/RestyleManagerBase.h index f81f5e73f..d92c3d1f7 100644 --- a/layout/base/RestyleManagerBase.h +++ b/layout/base/RestyleManagerBase.h @@ -72,6 +72,11 @@ public: // WillDestroyFrameTree hasn't been called yet. void NotifyDestroyingFrame(nsIFrame* aFrame) { mOverflowChangedTracker.RemoveFrame(aFrame); + // If ProcessRestyledFrames is tracking frames which have been + // destroyed (to avoid re-visiting them), add this one to its set. + if (mDestroyedFrames) { + mDestroyedFrames->PutEntry(aFrame); + } } // Note: It's the caller's responsibility to make sure to wrap a @@ -127,6 +132,12 @@ private: nsPresContext* mPresContext; // weak, can be null after Disconnect(). uint32_t mRestyleGeneration; uint32_t mHoverGeneration; + + // Used to keep track of frames that have been destroyed during + // ProcessRestyledFrames, so we don't try to touch them again even if + // they're referenced again later in the changelist. + mozilla::UniquePtr<nsTHashtable<nsPtrHashKey<const nsIFrame>>> mDestroyedFrames; + // True if we're already waiting for a refresh notification. bool mObservingRefreshDriver; @@ -146,7 +157,7 @@ protected: GetNearestAncestorFrame(nsIContent* aContent); static nsIFrame* - GetNextBlockInInlineSibling(FramePropertyTable* aPropTable, nsIFrame* aFrame); + GetNextBlockInInlineSibling(nsIFrame* aFrame); /** * Get the next continuation or similar ib-split sibling (assuming diff --git a/layout/base/moz.build b/layout/base/moz.build index d3e417f16..4308a6e4d 100644 --- a/layout/base/moz.build +++ b/layout/base/moz.build @@ -61,7 +61,7 @@ EXPORTS += [ 'DisplayItemScrollClip.h', 'DisplayListClipState.h', 'FrameLayerBuilder.h', - 'FramePropertyTable.h', + 'FrameProperties.h', 'LayerState.h', 'LayoutLogging.h', 'nsArenaMemoryStats.h', @@ -126,7 +126,6 @@ UNIFIED_SOURCES += [ 'DisplayListClipState.cpp', 'DottedCornerFinder.cpp', 'FrameLayerBuilder.cpp', - 'FramePropertyTable.cpp', 'GeometryUtils.cpp', 'LayoutLogging.cpp', 'MaskLayerImageCache.cpp', diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index b3c20aabb..887563504 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -753,7 +753,6 @@ nsBidiPresUtils::ResolveParagraph(BidiParagraphData* aBpd) nsIContent* content = nullptr; int32_t contentTextLength = 0; - FramePropertyTable* propTable = aBpd->mPresContext->PropertyTable(); nsLineBox* currentLine = nullptr; #ifdef DEBUG @@ -809,7 +808,7 @@ nsBidiPresUtils::ResolveParagraph(BidiParagraphData* aBpd) } precedingControl = kBidiLevelNone; lastEmbedingLevel = embeddingLevel; - propTable->Set(frame, nsIFrame::BidiDataProperty(), bidiData); + frame->SetProperty(nsIFrame::BidiDataProperty(), bidiData); }; for (; ;) { @@ -1787,7 +1786,7 @@ nsBidiPresUtils::RemoveBidiContinuation(BidiParagraphData *aBpd, if (frame != NS_BIDI_CONTROL_FRAME) { // Make the frame and its continuation ancestors fluid, // so they can be reused or deleted by normal reflow code - frame->Properties().Set(nsIFrame::BidiDataProperty(), bidiData); + frame->SetProperty(nsIFrame::BidiDataProperty(), bidiData); frame->AddStateBits(NS_FRAME_IS_BIDI); while (frame) { nsIFrame* prev = frame->GetPrevContinuation(); diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 07a5b80e7..ec676ca92 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -492,9 +492,8 @@ static nsContainerFrame* GetIBSplitSibling(nsIFrame* aFrame) // We only store the "ib-split sibling" annotation with the first // frame in the continuation chain. Walk back to find that frame now. - return static_cast<nsContainerFrame*> - (aFrame->FirstContinuation()-> - Properties().Get(nsIFrame::IBSplitSibling())); + return aFrame->FirstContinuation()-> + GetProperty(nsIFrame::IBSplitSibling()); } static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame) @@ -503,9 +502,8 @@ static nsContainerFrame* GetIBSplitPrevSibling(nsIFrame* aFrame) // We only store the ib-split sibling annotation with the first // frame in the continuation chain. Walk back to find that frame now. - return static_cast<nsContainerFrame*> - (aFrame->FirstContinuation()-> - Properties().Get(nsIFrame::IBSplitPrevSibling())); + return aFrame->FirstContinuation()-> + GetProperty(nsIFrame::IBSplitPrevSibling()); } static nsContainerFrame* @@ -526,7 +524,7 @@ GetLastIBSplitSibling(nsIFrame* aFrame, bool aReturnEmptyTrailingInline) } static void -SetFrameIsIBSplit(nsContainerFrame* aFrame, nsIFrame* aIBSplitSibling) +SetFrameIsIBSplit(nsContainerFrame* aFrame, nsContainerFrame* aIBSplitSibling) { NS_PRECONDITION(aFrame, "bad args!"); @@ -547,9 +545,8 @@ SetFrameIsIBSplit(nsContainerFrame* aFrame, nsIFrame* aIBSplitSibling) // Store the ib-split sibling (if we were given one) with the // first frame in the flow. - FramePropertyTable* props = aFrame->PresContext()->PropertyTable(); - props->Set(aFrame, nsIFrame::IBSplitSibling(), aIBSplitSibling); - props->Set(aIBSplitSibling, nsIFrame::IBSplitPrevSibling(), aFrame); + aFrame->SetProperty(nsIFrame::IBSplitSibling(), aIBSplitSibling); + aIBSplitSibling->SetProperty(nsIFrame::IBSplitPrevSibling(), aFrame); } } @@ -6075,11 +6072,11 @@ AddGenConPseudoToFrame(nsIFrame* aOwnerFrame, nsIContent* aContent) NS_ASSERTION(nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aOwnerFrame), "property should only be set on first continuation/ib-sibling"); - FrameProperties props = aOwnerFrame->Properties(); - nsIFrame::ContentArray* value = props.Get(nsIFrame::GenConProperty()); + nsIFrame::ContentArray* value = + aOwnerFrame->GetProperty(nsIFrame::GenConProperty()); if (!value) { value = new nsIFrame::ContentArray; - props.Set(nsIFrame::GenConProperty(), value); + aOwnerFrame->SetProperty(nsIFrame::GenConProperty(), value); } value->AppendElement(aContent); } diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index ff9edf742..119c6c8a2 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -293,13 +293,13 @@ protected: if (!prevCont && (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) { nsIFrame* block = - aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling()); + aFrame->GetProperty(nsIFrame::IBSplitPrevSibling()); if (block) { // The {ib} properties are only stored on first continuations NS_ASSERTION(!block->GetPrevContinuation(), "Incorrect value for IBSplitPrevSibling"); prevCont = - block->Properties().Get(nsIFrame::IBSplitPrevSibling()); + block->GetProperty(nsIFrame::IBSplitPrevSibling()); NS_ASSERTION(prevCont, "How did that happen?"); } } @@ -313,9 +313,9 @@ protected: (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) { // The {ib} properties are only stored on first continuations aFrame = aFrame->FirstContinuation(); - nsIFrame* block = aFrame->Properties().Get(nsIFrame::IBSplitSibling()); + nsIFrame* block = aFrame->GetProperty(nsIFrame::IBSplitSibling()); if (block) { - nextCont = block->Properties().Get(nsIFrame::IBSplitSibling()); + nextCont = block->GetProperty(nsIFrame::IBSplitSibling()); NS_ASSERTION(nextCont, "How did that happen?"); } } @@ -842,7 +842,7 @@ static nsRect GetOutlineInnerRect(nsIFrame* aFrame) { nsRect* savedOutlineInnerRect = - aFrame->Properties().Get(nsIFrame::OutlineInnerRectProperty()); + aFrame->GetProperty(nsIFrame::OutlineInnerRectProperty()); if (savedOutlineInnerRect) return *savedOutlineInnerRect; NS_NOTREACHED("we should have saved a frame property"); diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index a55ec1e39..e22230b41 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -666,7 +666,7 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer, // EffectCompositor needs to know that we refused to run this animation // asynchronously so that it will not throttle the main thread // animation. - aFrame->Properties().Set(nsIFrame::RefusedAsyncAnimationProperty(), true); + aFrame->SetProperty(nsIFrame::RefusedAsyncAnimationProperty(), true); // We need to schedule another refresh driver run so that EffectCompositor // gets a chance to unthrottle the animation. @@ -902,15 +902,13 @@ void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, const DisplayItemClip* oldClip = mClipState.GetClipForContainingBlockDescendants(); const DisplayItemScrollClip* sc = mClipState.GetCurrentInnermostScrollClip(); OutOfFlowDisplayData* data = new OutOfFlowDisplayData(oldClip, sc, dirty); - aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data); + aFrame->SetProperty(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data); MarkFrameForDisplay(aFrame, aDirtyFrame); } static void UnmarkFrameForDisplay(nsIFrame* aFrame) { - nsPresContext* presContext = aFrame->PresContext(); - presContext->PropertyTable()-> - Delete(aFrame, nsDisplayListBuilder::OutOfFlowDisplayDataProperty()); + aFrame->DeleteProperty(nsDisplayListBuilder::OutOfFlowDisplayDataProperty()); for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) { @@ -5710,7 +5708,7 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame, } /* Allows us to access dimension getters by index. */ - float coords[2]; + float transformOrigin[2]; TransformReferenceBox::DimensionGetter dimensionGetter[] = { &TransformReferenceBox::Width, &TransformReferenceBox::Height }; TransformReferenceBox::DimensionGetter offsetGetter[] = @@ -5720,33 +5718,33 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame, /* If the transform-origin specifies a percentage, take the percentage * of the size of the box. */ - const nsStyleCoord &coord = display->mTransformOrigin[index]; - if (coord.GetUnit() == eStyleUnit_Calc) { - const nsStyleCoord::Calc *calc = coord.GetCalcValue(); - coords[index] = + const nsStyleCoord &originValue = display->mTransformOrigin[index]; + if (originValue.GetUnit() == eStyleUnit_Calc) { + const nsStyleCoord::Calc *calc = originValue.GetCalcValue(); + transformOrigin[index] = NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) * calc->mPercent + NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel); - } else if (coord.GetUnit() == eStyleUnit_Percent) { - coords[index] = + } else if (originValue.GetUnit() == eStyleUnit_Percent) { + transformOrigin[index] = NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) * - coord.GetPercentValue(); + originValue.GetPercentValue(); } else { - MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit"); - coords[index] = - NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel); + MOZ_ASSERT(originValue.GetUnit() == eStyleUnit_Coord, "unexpected unit"); + transformOrigin[index] = + NSAppUnitsToFloatPixels(originValue.GetCoordValue(), aAppUnitsPerPixel); } if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) { // SVG frames (unlike other frames) have a reference box that can be (and // typically is) offset from the TopLeft() of the frame. We need to // account for that here. - coords[index] += + transformOrigin[index] += NSAppUnitsToFloatPixels((refBox.*offsetGetter[index])(), aAppUnitsPerPixel); } } - return Point3D(coords[0], coords[1], + return Point3D(transformOrigin[0], transformOrigin[1], NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(), aAppUnitsPerPixel)); } @@ -5919,6 +5917,17 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp frame && frame->IsSVGTransformed(&svgTransform, &transformFromSVGParent); bool hasTransformFromSVGParent = hasSVGTransforms && !transformFromSVGParent.IsIdentity(); + + bool shouldRound = true; + + // An SVG frame should not have its translation rounded. + // Note it's possible that the SVG frame doesn't have an SVG + // transform but only has a CSS transform. + if (frame && frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) && + !(frame->GetType() == nsGkAtoms::svgOuterSVGAnonChildFrame)) { + shouldRound = false; + } + /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */ if (aProperties.mTransformList) { result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead, @@ -5996,7 +6005,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp // Otherwise we need to manually translate into our parent's coordinate // space. if (frame->IsTransformed()) { - nsLayoutUtils::PostTranslate(result, frame->GetPosition(), aAppUnitsPerPixel, !hasSVGTransforms); + nsLayoutUtils::PostTranslate(result, frame->GetPosition(), aAppUnitsPerPixel, shouldRound); } Matrix4x4 parent = GetResultingTransformMatrixInternal(props, @@ -6007,7 +6016,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp } if (aFlags & OFFSET_BY_ORIGIN) { - nsLayoutUtils::PostTranslate(result, aOrigin, aAppUnitsPerPixel, !hasSVGTransforms); + nsLayoutUtils::PostTranslate(result, aOrigin, aAppUnitsPerPixel, shouldRound); } return result; diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index fcdc9e4fc..c81d34fac 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -1003,7 +1003,7 @@ public: static OutOfFlowDisplayData* GetOutOfFlowData(nsIFrame* aFrame) { - return aFrame->Properties().Get(OutOfFlowDisplayDataProperty()); + return aFrame->GetProperty(OutOfFlowDisplayDataProperty()); } nsPresContext* CurrentPresContext() { diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 4016cc0a9..865f5534c 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -1533,11 +1533,12 @@ public: bool aFlushOnHoverChange) = 0; virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, - nsArenaMemoryStats *aArenaObjectsSize, - size_t *aPresShellSize, - size_t *aStyleSetsSize, - size_t *aTextRunsSize, - size_t *aPresContextSize) = 0; + nsArenaMemoryStats* aArenaObjectsSize, + size_t* aPresShellSize, + size_t* aStyleSetsSize, + size_t* aTextRunsSize, + size_t* aPresContextSize, + size_t* aFramePropertiesSize) = 0; /** * Methods that retrieve the cached font inflation preferences. diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 07befdc81..06690b208 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -2057,13 +2057,13 @@ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ScrollbarThumbLayerized, bool) /* static */ void nsLayoutUtils::SetScrollbarThumbLayerization(nsIFrame* aThumbFrame, bool aLayerize) { - aThumbFrame->Properties().Set(ScrollbarThumbLayerized(), aLayerize); + aThumbFrame->SetProperty(ScrollbarThumbLayerized(), aLayerize); } bool nsLayoutUtils::IsScrollbarThumbLayerized(nsIFrame* aThumbFrame) { - return aThumbFrame->Properties().Get(ScrollbarThumbLayerized()); + return aThumbFrame->GetProperty(ScrollbarThumbLayerized()); } // static @@ -4427,7 +4427,7 @@ nsLayoutUtils::GetNextContinuationOrIBSplitSibling(nsIFrame *aFrame) // frame in the continuation chain. Walk back to find that frame now. aFrame = aFrame->FirstContinuation(); - return aFrame->Properties().Get(nsIFrame::IBSplitSibling()); + return aFrame->GetProperty(nsIFrame::IBSplitSibling()); } return nullptr; @@ -4440,7 +4440,7 @@ nsLayoutUtils::FirstContinuationOrIBSplitSibling(nsIFrame *aFrame) if (result->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) { while (true) { nsIFrame* f = - result->Properties().Get(nsIFrame::IBSplitPrevSibling()); + result->GetProperty(nsIFrame::IBSplitPrevSibling()); if (!f) break; result = f; @@ -4456,10 +4456,10 @@ nsLayoutUtils::LastContinuationOrIBSplitSibling(nsIFrame *aFrame) nsIFrame *result = aFrame->FirstContinuation(); if (result->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) { while (true) { - nsIFrame* f = - result->Properties().Get(nsIFrame::IBSplitSibling()); - if (!f) + nsIFrame* f = result->GetProperty(nsIFrame::IBSplitSibling()); + if (!f) { break; + } result = f; } } @@ -4476,7 +4476,7 @@ nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(nsIFrame *aFrame) return false; } if ((aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) && - aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling())) { + aFrame->GetProperty(nsIFrame::IBSplitPrevSibling())) { return false; } diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 3106ff386..befb5deb2 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2741,8 +2741,7 @@ nsPresContext::GetPrimaryFrameFor(nsIContent* aContent) size_t nsPresContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { - return mPropertyTable.SizeOfExcludingThis(aMallocSizeOf) + - mLangGroupFontPrefs.SizeOfExcludingThis(aMallocSizeOf); + return mLangGroupFontPrefs.SizeOfExcludingThis(aMallocSizeOf); // Measurement of other members may be added later if DMD finds it is // worthwhile. diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index d8f876291..a2b9bb533 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -22,7 +22,6 @@ #include "nsITimer.h" #include "nsCRT.h" #include "nsIWidgetListener.h" -#include "FramePropertyTable.h" #include "nsGkAtoms.h" #include "nsCycleCollectionParticipant.h" #include "nsChangeHint.h" @@ -140,7 +139,6 @@ class nsRootPresContext; class nsPresContext : public nsIObserver, public mozilla::SupportsWeakPtr<nsPresContext> { public: - typedef mozilla::FramePropertyTable FramePropertyTable; typedef mozilla::LangGroupFontPrefs LangGroupFontPrefs; typedef mozilla::ScrollbarStyles ScrollbarStyles; typedef mozilla::StaticPresData StaticPresData; @@ -867,9 +865,6 @@ public: nsIPrintSettings* GetPrintSettings() { return mPrintSettings; } - /* Accessor for table of frame properties */ - FramePropertyTable* PropertyTable() { return &mPropertyTable; } - /* Helper function that ensures that this prescontext is shown in its docshell if it's the most recent prescontext for the docshell. Returns whether the prescontext is now being shown. @@ -1064,11 +1059,6 @@ public: */ nsIFrame* GetPrimaryFrameFor(nsIContent* aContent); - void NotifyDestroyingFrame(nsIFrame* aFrame) - { - PropertyTable()->DeleteAllFor(aFrame); - } - virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); @@ -1294,7 +1284,6 @@ protected: nsCOMPtr<nsIPrintSettings> mPrintSettings; nsCOMPtr<nsITimer> mPrefChangedTimer; - FramePropertyTable mPropertyTable; nsInvalidateRequestList mInvalidateRequestsSinceLastPaint; nsInvalidateRequestList mUndeliveredInvalidateRequestsBeforeLastPaint; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 5dfbb8dba..264b52b18 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1306,19 +1306,6 @@ PresShell::Destroy() // Destroy the frame manager. This will destroy the frame hierarchy mFrameConstructor->WillDestroyFrameTree(); - // Destroy all frame properties (whose destruction was suppressed - // while destroying the frame tree, but which might contain more - // frames within the properties. - if (mPresContext) { - // Clear out the prescontext's property table -- since our frame tree is - // now dead, we shouldn't be looking up any more properties in that table. - // We want to do this before we call DetachShell() on the prescontext, so - // property destructors can usefully call GetPresShell() on the - // prescontext. - mPresContext->PropertyTable()->DeleteAll(); - } - - NS_WARNING_ASSERTION(!mWeakFrames, "Weak frames alive after destroying FrameManager"); while (mWeakFrames) { @@ -2047,7 +2034,7 @@ PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) } // Remove frame properties - mPresContext->NotifyDestroyingFrame(aFrame); + aFrame->DeleteAllProperties(); if (aFrame == mCurrentEventFrame) { mCurrentEventContent = aFrame->GetContent(); @@ -2076,8 +2063,7 @@ PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) // frame from FrameLayerBuilder::DisplayItemData::mFrameList -- otherwise // the DisplayItemData destructor will use the destroyed frame when it // tries to remove it from the (array) value of this property. - mPresContext->PropertyTable()-> - Delete(aFrame, FrameLayerBuilder::LayerManagerDataProperty()); + aFrame->DeleteProperty( FrameLayerBuilder::LayerManagerDataProperty()); } } @@ -10917,11 +10903,12 @@ PresShell::GetRootPresShell() void PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, - nsArenaMemoryStats *aArenaObjectsSize, - size_t *aPresShellSize, - size_t *aStyleSetsSize, - size_t *aTextRunsSize, - size_t *aPresContextSize) + nsArenaMemoryStats* aArenaObjectsSize, + size_t* aPresShellSize, + size_t* aStyleSetsSize, + size_t* aTextRunsSize, + size_t* aPresContextSize, + size_t* aFramePropertiesSize) { mFrameArena.AddSizeOfExcludingThis(aMallocSizeOf, aArenaObjectsSize); *aPresShellSize += aMallocSizeOf(this); @@ -10941,6 +10928,12 @@ PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, *aTextRunsSize += SizeOfTextRuns(aMallocSizeOf); *aPresContextSize += mPresContext->SizeOfIncludingThis(aMallocSizeOf); + + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); + if (rootFrame) { + *aFramePropertiesSize += + rootFrame->SizeOfFramePropertiesForTree(aMallocSizeOf); + } } size_t diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index 7a9056a38..f20370d73 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -384,11 +384,12 @@ public: virtual void LoadComplete() override; void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, - nsArenaMemoryStats *aArenaObjectsSize, - size_t *aPresShellSize, - size_t *aStyleSetsSize, - size_t *aTextRunsSize, - size_t *aPresContextSize) override; + nsArenaMemoryStats* aArenaObjectsSize, + size_t* aPresShellSize, + size_t* aStyleSetsSize, + size_t* aTextRunsSize, + size_t* aPresContextSize, + size_t* aFramePropertiesSize) override; size_t SizeOfTextRuns(mozilla::MallocSizeOf aMallocSizeOf) const; virtual void AddInvalidateHiddenPresShellObserver(nsRefreshDriver *aDriver) override; diff --git a/layout/build/moz.build b/layout/build/moz.build index 5b607c171..ecf180d78 100644 --- a/layout/build/moz.build +++ b/layout/build/moz.build @@ -31,6 +31,7 @@ LOCAL_INCLUDES += [ '/docshell/base', '/dom/audiochannel', '/dom/base', + '/dom/bindings', '/dom/canvas', '/dom/filesystem', '/dom/geolocation', diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 8bb70f85c..9313b8e45 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -35,6 +35,7 @@ #include "nsIObserver.h" #include "nsIObserverService.h" #include "nsIScriptNameSpaceManager.h" +#include "nsIScriptError.h" #include "nsISelection.h" #include "nsCaret.h" #include "nsPlainTextSerializer.h" @@ -192,6 +193,8 @@ static void Shutdown(); #include "mozilla/dom/PresentationDeviceManager.h" #include "mozilla/dom/PresentationTCPSessionTransport.h" +#include "nsScriptError.h" + #include "mozilla/TextInputProcessor.h" using namespace mozilla; @@ -560,6 +563,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(UDPSocketChild) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(GeckoMediaPluginService, GeckoMediaPluginService::GetGeckoMediaPluginService) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptError) + #ifdef ACCESSIBILITY #include "xpcAccessibilityService.h" @@ -720,6 +725,8 @@ NS_DEFINE_NAMED_CID(PRESENTATION_TCP_SESSION_TRANSPORT_CID); NS_DEFINE_NAMED_CID(TEXT_INPUT_PROCESSOR_CID); +NS_DEFINE_NAMED_CID(NS_SCRIPTERROR_CID); + static nsresult CreateWindowCommandTableConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) @@ -978,6 +985,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kPRESENTATION_DEVICE_MANAGER_CID, false, nullptr, PresentationDeviceManagerConstructor }, { &kPRESENTATION_TCP_SESSION_TRANSPORT_CID, false, nullptr, PresentationTCPSessionTransportConstructor }, { &kTEXT_INPUT_PROCESSOR_CID, false, nullptr, TextInputProcessorConstructor }, + { &kNS_SCRIPTERROR_CID, false, nullptr, nsScriptErrorConstructor }, { nullptr } }; @@ -1109,6 +1117,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = { { PRESENTATION_DEVICE_MANAGER_CONTRACTID, &kPRESENTATION_DEVICE_MANAGER_CID }, { PRESENTATION_TCP_SESSION_TRANSPORT_CONTRACTID, &kPRESENTATION_TCP_SESSION_TRANSPORT_CID }, { "@mozilla.org/text-input-processor;1", &kTEXT_INPUT_PROCESSOR_CID }, + { NS_SCRIPTERROR_CONTRACTID, &kNS_SCRIPTERROR_CID }, { nullptr } }; diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp index a7f7d40a8..f8fdf3420 100644 --- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -124,10 +124,10 @@ nsTextControlFrame::DestroyFrom(nsIFrame* aDestructRoot) { mScrollEvent.Revoke(); - EditorInitializer* initializer = Properties().Get(TextControlInitializer()); + EditorInitializer* initializer = GetProperty(TextControlInitializer()); if (initializer) { initializer->Revoke(); - Properties().Delete(TextControlInitializer()); + DeleteProperty(TextControlInitializer()); } // Unbind the text editor state object from the frame. The editor will live @@ -410,12 +410,12 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements) if (initEagerly) { NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), "Someone forgot a script blocker?"); - EditorInitializer* initializer = Properties().Get(TextControlInitializer()); + EditorInitializer* initializer = GetProperty(TextControlInitializer()); if (initializer) { initializer->Revoke(); } initializer = new EditorInitializer(this); - Properties().Set(TextControlInitializer(),initializer); + SetProperty(TextControlInitializer(),initializer); nsContentUtils::AddScriptRunner(initializer); } @@ -1262,7 +1262,7 @@ nsTextControlFrame::SetInitialChildList(ChildListID aListID, NS_ASSERTION(txtCtrl, "Content not a text control element"); txtCtrl->InitializeKeyboardEventListeners(); - nsPoint* contentScrollPos = Properties().Get(ContentScrollPos()); + nsPoint* contentScrollPos = GetProperty(ContentScrollPos()); if (contentScrollPos) { // If we have a scroll pos stored to be passed to our anonymous // div, do it here! @@ -1271,7 +1271,7 @@ nsTextControlFrame::SetInitialChildList(ChildListID aListID, nsPresState fakePresState; fakePresState.SetScrollState(*contentScrollPos); statefulFrame->RestoreState(&fakePresState); - Properties().Remove(ContentScrollPos()); + RemoveProperty(ContentScrollPos()); delete contentScrollPos; } } @@ -1421,7 +1421,7 @@ nsTextControlFrame::RestoreState(nsPresState* aState) // Most likely, we don't have our anonymous content constructed yet, which // would cause us to end up here. In this case, we'll just store the scroll // pos ourselves, and forward it to the scroll frame later when it's created. - Properties().Set(ContentScrollPos(), new nsPoint(aState->GetScrollPosition())); + SetProperty(ContentScrollPos(), new nsPoint(aState->GetScrollPosition())); return NS_OK; } diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h index 9d4d0b77c..7fa39c5fb 100644 --- a/layout/forms/nsTextControlFrame.h +++ b/layout/forms/nsTextControlFrame.h @@ -327,7 +327,7 @@ private: nsresult GetRootNodeAndInitializeEditor(nsIDOMElement **aRootElement); void FinishedInitializer() { - Properties().Delete(TextControlInitializer()); + DeleteProperty(TextControlInitializer()); } private: diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp index bbff77ad4..78eca8c6c 100644 --- a/layout/generic/ReflowInput.cpp +++ b/layout/generic/ReflowInput.cpp @@ -999,13 +999,13 @@ ReflowInput::ComputeRelativeOffsets(WritingMode aWM, // Convert the offsets to physical coordinates and store them on the frame aComputedOffsets = offsets.GetPhysicalMargin(aWM); - FrameProperties props = aFrame->Properties(); - nsMargin* physicalOffsets = props.Get(nsIFrame::ComputedOffsetProperty()); + nsMargin* physicalOffsets = + aFrame->GetProperty(nsIFrame::ComputedOffsetProperty()); if (physicalOffsets) { *physicalOffsets = aComputedOffsets; } else { - props.Set(nsIFrame::ComputedOffsetProperty(), - new nsMargin(aComputedOffsets)); + aFrame->SetProperty(nsIFrame::ComputedOffsetProperty(), + new nsMargin(aComputedOffsets)); } } @@ -1015,21 +1015,22 @@ ReflowInput::ApplyRelativePositioning(nsIFrame* aFrame, nsPoint* aPosition) { if (!aFrame->IsRelativelyPositioned()) { - NS_ASSERTION(!aFrame->Properties().Get(nsIFrame::NormalPositionProperty()), + NS_ASSERTION(!aFrame->GetProperty(nsIFrame::NormalPositionProperty()), "We assume that changing the 'position' property causes " "frame reconstruction. If that ever changes, this code " "should call " - "props.Delete(nsIFrame::NormalPositionProperty())"); + "aFrame->DeleteProperty(nsIFrame::NormalPositionProperty())"); return; } // Store the normal position - FrameProperties props = aFrame->Properties(); - nsPoint* normalPosition = props.Get(nsIFrame::NormalPositionProperty()); + nsPoint* normalPosition = + aFrame->GetProperty(nsIFrame::NormalPositionProperty()); if (normalPosition) { *normalPosition = *aPosition; } else { - props.Set(nsIFrame::NormalPositionProperty(), new nsPoint(*aPosition)); + aFrame->SetProperty(nsIFrame::NormalPositionProperty(), + new nsPoint(*aPosition)); } const nsStyleDisplay* display = aFrame->StyleDisplay(); @@ -2452,20 +2453,20 @@ ReflowInput::InitConstraints(nsPresContext* aPresContext, } static void -UpdateProp(FrameProperties& aProps, +UpdateProp(nsIFrame* aFrame, const FramePropertyDescriptor<nsMargin>* aProperty, bool aNeeded, nsMargin& aNewValue) { if (aNeeded) { - nsMargin* propValue = aProps.Get(aProperty); + nsMargin* propValue = aFrame->GetProperty(aProperty); if (propValue) { *propValue = aNewValue; } else { - aProps.Set(aProperty, new nsMargin(aNewValue)); + aFrame->SetProperty(aProperty, new nsMargin(aNewValue)); } } else { - aProps.Delete(aProperty); + aFrame->DeleteProperty(aProperty); } } @@ -2482,8 +2483,7 @@ SizeComputationInput::InitOffsets(WritingMode aWM, // Since we are in reflow, we don't need to store these properties anymore // unless they are dependent on width, in which case we store the new value. nsPresContext *presContext = mFrame->PresContext(); - FrameProperties props(presContext->PropertyTable(), mFrame); - props.Delete(nsIFrame::UsedBorderProperty()); + mFrame->DeleteProperty(nsIFrame::UsedBorderProperty()); // Compute margins from the specified margin style information. These // become the default computed values, and may be adjusted below @@ -2494,7 +2494,7 @@ SizeComputationInput::InitOffsets(WritingMode aWM, // ... but if we did that, we'd need to fix nsFrame::GetUsedMargin // to use it even when the margins are all zero (since sometimes // they get treated as auto) - ::UpdateProp(props, nsIFrame::UsedMarginProperty(), needMarginProp, + ::UpdateProp(mFrame, nsIFrame::UsedMarginProperty(), needMarginProp, ComputedPhysicalMargin()); @@ -2530,7 +2530,7 @@ SizeComputationInput::InitOffsets(WritingMode aWM, auto ApplyBaselinePadding = [this, &needPaddingProp] (LogicalAxis aAxis, Prop aProp) { bool found; - nscoord val = mFrame->Properties().Get(aProp, &found); + nscoord val = mFrame->GetProperty(aProp, &found); if (found) { NS_ASSERTION(val != nscoord(0), "zero in this property is useless"); WritingMode wm = GetWritingMode(); @@ -2603,7 +2603,7 @@ SizeComputationInput::InitOffsets(WritingMode aWM, ComputedPhysicalBorderPadding().SizeTo(0,0,0,0); } } - ::UpdateProp(props, nsIFrame::UsedPaddingProperty(), needPaddingProp, + ::UpdateProp(mFrame, nsIFrame::UsedPaddingProperty(), needPaddingProp, ComputedPhysicalPadding()); } diff --git a/layout/generic/RubyUtils.cpp b/layout/generic/RubyUtils.cpp index f340663bc..05dd25413 100644 --- a/layout/generic/RubyUtils.cpp +++ b/layout/generic/RubyUtils.cpp @@ -19,21 +19,21 @@ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ReservedISize, nscoord) RubyUtils::SetReservedISize(nsIFrame* aFrame, nscoord aISize) { MOZ_ASSERT(IsExpandableRubyBox(aFrame)); - aFrame->Properties().Set(ReservedISize(), aISize); + aFrame->SetProperty(ReservedISize(), aISize); } /* static */ void RubyUtils::ClearReservedISize(nsIFrame* aFrame) { MOZ_ASSERT(IsExpandableRubyBox(aFrame)); - aFrame->Properties().Remove(ReservedISize()); + aFrame->RemoveProperty(ReservedISize()); } /* static */ nscoord RubyUtils::GetReservedISize(nsIFrame* aFrame) { MOZ_ASSERT(IsExpandableRubyBox(aFrame)); - return aFrame->Properties().Get(ReservedISize()); + return aFrame->GetProperty(ReservedISize()); } AutoRubyTextContainerArray::AutoRubyTextContainerArray( diff --git a/layout/generic/StickyScrollContainer.cpp b/layout/generic/StickyScrollContainer.cpp index d61a7e042..ca68992c3 100644 --- a/layout/generic/StickyScrollContainer.cpp +++ b/layout/generic/StickyScrollContainer.cpp @@ -45,12 +45,12 @@ StickyScrollContainer::GetStickyScrollContainerForFrame(nsIFrame* aFrame) // <html style="position: fixed"> return nullptr; } - FrameProperties props = static_cast<nsIFrame*>(do_QueryFrame(scrollFrame))-> - Properties(); - StickyScrollContainer* s = props.Get(StickyScrollContainerProperty()); + auto frame = static_cast<nsIFrame*>(do_QueryFrame(scrollFrame)); + StickyScrollContainer* s = + frame->GetProperty(StickyScrollContainerProperty()); if (!s) { s = new StickyScrollContainer(scrollFrame); - props.Set(StickyScrollContainerProperty(), s); + frame->SetProperty(StickyScrollContainerProperty(), s); } return s; } @@ -69,9 +69,9 @@ StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary(nsIFrame* // we aren't going to handle that. return; } - FrameProperties props = static_cast<nsIFrame*>(do_QueryFrame(oldScrollFrame))-> - Properties(); - StickyScrollContainer* oldSSC = props.Get(StickyScrollContainerProperty()); + StickyScrollContainer* oldSSC = + static_cast<nsIFrame*>(do_QueryFrame(oldScrollFrame))-> + GetProperty(StickyScrollContainerProperty()); if (!oldSSC) { // aOldParent had no sticky descendants, so aFrame doesn't have any sticky // descendants, and we're done here. @@ -95,8 +95,7 @@ StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary(nsIFrame* StickyScrollContainer* StickyScrollContainer::GetStickyScrollContainerForScrollFrame(nsIFrame* aFrame) { - FrameProperties props = aFrame->Properties(); - return props.Get(StickyScrollContainerProperty()); + return aFrame->GetProperty(StickyScrollContainerProperty()); } static nscoord @@ -141,13 +140,12 @@ StickyScrollContainer::ComputeStickyOffsets(nsIFrame* aFrame) scrollContainerSize.height); // Store the offset - FrameProperties props = aFrame->Properties(); - nsMargin* offsets = props.Get(nsIFrame::ComputedOffsetProperty()); + nsMargin* offsets = aFrame->GetProperty(nsIFrame::ComputedOffsetProperty()); if (offsets) { *offsets = computedOffsets; } else { - props.Set(nsIFrame::ComputedOffsetProperty(), - new nsMargin(computedOffsets)); + aFrame->SetProperty(nsIFrame::ComputedOffsetProperty(), + new nsMargin(computedOffsets)); } } @@ -162,7 +160,7 @@ StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame, nsRect* aStick, aContain->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX); const nsMargin* computedOffsets = - aFrame->Properties().Get(nsIFrame::ComputedOffsetProperty()); + aFrame->GetProperty(nsIFrame::ComputedOffsetProperty()); if (!computedOffsets) { // We haven't reflowed the scroll frame yet, so offsets haven't been // computed. Bail. diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 851e3406c..a37bfc06b 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -326,10 +326,8 @@ nsBlockFrame::DestroyFrom(nsIFrame* aDestructRoot) nsLineBox::DeleteLineList(presContext, mLines, aDestructRoot, &mFrames); - FramePropertyTable* props = presContext->PropertyTable(); - if (HasPushedFloats()) { - SafelyDestroyFrameListProp(aDestructRoot, shell, props, + SafelyDestroyFrameListProp(aDestructRoot, shell, PushedFloatProperty()); RemoveStateBits(NS_BLOCK_HAS_PUSHED_FLOATS); } @@ -343,13 +341,13 @@ nsBlockFrame::DestroyFrom(nsIFrame* aDestructRoot) } if (GetStateBits() & NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS) { - SafelyDestroyFrameListProp(aDestructRoot, shell, props, + SafelyDestroyFrameListProp(aDestructRoot, shell, OverflowOutOfFlowsProperty()); RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS); } if (HasOutsideBullet()) { - SafelyDestroyFrameListProp(aDestructRoot, shell, props, + SafelyDestroyFrameListProp(aDestructRoot, shell, OutsideBulletProperty()); RemoveStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET); } @@ -1669,7 +1667,7 @@ nsBlockFrame::ComputeFinalSize(const ReflowInput& aReflowInput, // our computed size due to overflowing their containing block. (E.g. this // ensures we fill the last row when a multi-row grid item is fragmented). bool found; - nscoord bSize = Properties().Get(FragStretchBSizeProperty(), &found); + nscoord bSize = GetProperty(FragStretchBSizeProperty(), &found); if (found) { finalSize.BSize(wm) = std::max(bSize, finalSize.BSize(wm)); } @@ -1679,7 +1677,7 @@ nsBlockFrame::ComputeFinalSize(const ReflowInput& aReflowInput, if (MOZ_UNLIKELY(aReflowInput.mFlags.mBClampMarginBoxMinSize) && NS_FRAME_IS_COMPLETE(aState.mReflowStatus)) { bool found; - nscoord cbSize = Properties().Get(BClampMarginBoxMinSizeProperty(), &found); + nscoord cbSize = GetProperty(BClampMarginBoxMinSizeProperty(), &found); if (found) { auto marginBoxBSize = finalSize.BSize(wm) + aReflowInput.ComputedLogicalMargin().BStartEnd(wm); @@ -1697,11 +1695,10 @@ nsBlockFrame::ComputeFinalSize(const ReflowInput& aReflowInput, finalSize.BSize(wm) = std::max(0, finalSize.BSize(wm)); *aBEndEdgeOfChildren = blockEndEdgeOfChildren; - FrameProperties properties = Properties(); if (blockEndEdgeOfChildren != finalSize.BSize(wm) - borderPadding.BEnd(wm)) { - properties.Set(BlockEndEdgeOfChildrenProperty(), blockEndEdgeOfChildren); + SetProperty(BlockEndEdgeOfChildrenProperty(), blockEndEdgeOfChildren); } else { - properties.Delete(BlockEndEdgeOfChildrenProperty()); + DeleteProperty(BlockEndEdgeOfChildrenProperty()); } aMetrics.SetSize(wm, finalSize); @@ -1834,7 +1831,7 @@ nsBlockFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) { bool found; nscoord blockEndEdgeOfChildren = - Properties().Get(BlockEndEdgeOfChildrenProperty(), &found); + GetProperty(BlockEndEdgeOfChildrenProperty(), &found); if (found) { ConsiderBlockEndEdgeOfChildren(GetWritingMode(), blockEndEdgeOfChildren, aOverflowAreas); @@ -4985,7 +4982,7 @@ nsBlockFrame::GetOverflowLines() const if (!HasOverflowLines()) { return nullptr; } - FrameLines* prop = Properties().Get(OverflowLinesProperty()); + FrameLines* prop = GetProperty(OverflowLinesProperty()); NS_ASSERTION(prop && !prop->mLines.empty() && prop->mLines.front()->GetChildCount() == 0 ? prop->mFrames.IsEmpty() : prop->mLines.front()->mFirstChild == prop->mFrames.FirstChild(), @@ -4999,7 +4996,7 @@ nsBlockFrame::RemoveOverflowLines() if (!HasOverflowLines()) { return nullptr; } - FrameLines* prop = Properties().Remove(OverflowLinesProperty()); + FrameLines* prop = RemoveProperty(OverflowLinesProperty()); NS_ASSERTION(prop && !prop->mLines.empty() && prop->mLines.front()->GetChildCount() == 0 ? prop->mFrames.IsEmpty() : prop->mLines.front()->mFirstChild == prop->mFrames.FirstChild(), @@ -5012,7 +5009,7 @@ void nsBlockFrame::DestroyOverflowLines() { NS_ASSERTION(HasOverflowLines(), "huh?"); - FrameLines* prop = Properties().Remove(OverflowLinesProperty()); + FrameLines* prop = RemoveProperty(OverflowLinesProperty()); NS_ASSERTION(prop && prop->mLines.empty(), "value should always be stored but empty when destroying"); RemoveStateBits(NS_BLOCK_HAS_OVERFLOW_LINES); @@ -5032,10 +5029,9 @@ nsBlockFrame::SetOverflowLines(FrameLines* aOverflowLines) NS_ASSERTION(!(GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES), "Overwriting existing overflow lines"); - FrameProperties props = Properties(); // Verify that we won't overwrite an existing overflow list - NS_ASSERTION(!props.Get(OverflowLinesProperty()), "existing overflow list"); - props.Set(OverflowLinesProperty(), aOverflowLines); + NS_ASSERTION(!GetProperty(OverflowLinesProperty()), "existing overflow list"); + SetProperty(OverflowLinesProperty(), aOverflowLines); AddStateBits(NS_BLOCK_HAS_OVERFLOW_LINES); } @@ -5088,7 +5084,7 @@ nsBlockFrame::GetInsideBullet() const return nullptr; } NS_ASSERTION(!HasOutsideBullet(), "invalid bullet state"); - nsBulletFrame* frame = Properties().Get(InsideBulletProperty()); + nsBulletFrame* frame = GetProperty(InsideBulletProperty()); NS_ASSERTION(frame && frame->GetType() == nsGkAtoms::bulletFrame, "bogus inside bullet frame"); return frame; @@ -5109,8 +5105,7 @@ nsBlockFrame::GetOutsideBulletList() const return nullptr; } NS_ASSERTION(!HasInsideBullet(), "invalid bullet state"); - nsFrameList* list = - Properties().Get(OutsideBulletProperty()); + nsFrameList* list = GetProperty(OutsideBulletProperty()); NS_ASSERTION(list && list->GetLength() == 1 && list->FirstChild()->GetType() == nsGkAtoms::bulletFrame, "bogus outside bullet list"); @@ -5123,8 +5118,7 @@ nsBlockFrame::GetPushedFloats() const if (!HasPushedFloats()) { return nullptr; } - nsFrameList* result = - Properties().Get(PushedFloatProperty()); + nsFrameList* result = GetProperty(PushedFloatProperty()); NS_ASSERTION(result, "value should always be non-empty when state set"); return result; } @@ -5137,7 +5131,7 @@ nsBlockFrame::EnsurePushedFloats() return result; result = new (PresContext()->PresShell()) nsFrameList; - Properties().Set(PushedFloatProperty(), result); + SetProperty(PushedFloatProperty(), result); AddStateBits(NS_BLOCK_HAS_PUSHED_FLOATS); return result; @@ -5149,7 +5143,7 @@ nsBlockFrame::RemovePushedFloats() if (!HasPushedFloats()) { return nullptr; } - nsFrameList *result = Properties().Remove(PushedFloatProperty()); + nsFrameList *result = RemoveProperty(PushedFloatProperty()); RemoveStateBits(NS_BLOCK_HAS_PUSHED_FLOATS); NS_ASSERTION(result, "value should always be non-empty when state set"); return result; @@ -5619,7 +5613,7 @@ nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame, if (mLine != line_end) { *aFoundValidLine = true; if (mLine != cursor) { - aFrame->Properties().Set(nsBlockFrame::LineCursorProperty(), mLine); + aFrame->SetProperty(nsBlockFrame::LineCursorProperty(), mLine); } return; } @@ -6769,7 +6763,7 @@ void nsBlockFrame::ClearLineCursor() return; } - Properties().Delete(LineCursorProperty()); + DeleteProperty(LineCursorProperty()); RemoveStateBits(NS_BLOCK_HAS_LINE_CURSOR); } @@ -6780,7 +6774,7 @@ void nsBlockFrame::SetupLineCursor() return; } - Properties().Set(LineCursorProperty(), mLines.front()); + SetProperty(LineCursorProperty(), mLines.front()); AddStateBits(NS_BLOCK_HAS_LINE_CURSOR); } @@ -6790,9 +6784,7 @@ nsLineBox* nsBlockFrame::GetFirstLineContaining(nscoord y) return nullptr; } - FrameProperties props = Properties(); - - nsLineBox* property = props.Get(LineCursorProperty()); + nsLineBox* property = GetProperty(LineCursorProperty()); LineIterator cursor = mLines.begin(property); nsRect cursorArea = cursor->GetVisualOverflowArea(); @@ -6808,7 +6800,7 @@ nsLineBox* nsBlockFrame::GetFirstLineContaining(nscoord y) } if (cursor.get() != property) { - props.Set(LineCursorProperty(), cursor.get()); + SetProperty(LineCursorProperty(), cursor.get()); } return cursor.get(); @@ -7021,11 +7013,11 @@ nsBlockFrame::CreateBulletFrameForListItem(bool aCreateBulletList, if (aListStylePositionInside) { nsFrameList bulletList(bullet, bullet); AddFrames(bulletList, nullptr); - Properties().Set(InsideBulletProperty(), bullet); + SetProperty(InsideBulletProperty(), bullet); AddStateBits(NS_BLOCK_FRAME_HAS_INSIDE_BULLET); } else { nsFrameList* bulletList = new (shell) nsFrameList(bullet, bullet); - Properties().Set(OutsideBulletProperty(), bulletList); + SetProperty(OutsideBulletProperty(), bulletList); AddStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET); } } diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index bb41a6e99..f515cc26f 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -215,7 +215,7 @@ public: ~AutoLineCursorSetup() { if (mOrigCursor) { - mFrame->Properties().Set(LineCursorProperty(), mOrigCursor); + mFrame->SetProperty(LineCursorProperty(), mOrigCursor); } else { mFrame->ClearLineCursor(); } @@ -416,7 +416,7 @@ protected: NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(LineCursorProperty, nsLineBox) bool HasLineCursor() { return GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR; } nsLineBox* GetLineCursor() { - return HasLineCursor() ? Properties().Get(LineCursorProperty()) : nullptr; + return HasLineCursor() ? GetProperty(LineCursorProperty()) : nullptr; } nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) { diff --git a/layout/generic/nsBulletFrame.cpp b/layout/generic/nsBulletFrame.cpp index aa8794321..f6595e8f6 100644 --- a/layout/generic/nsBulletFrame.cpp +++ b/layout/generic/nsBulletFrame.cpp @@ -903,7 +903,7 @@ nsBulletFrame::GetFontSizeInflation() const if (!HasFontSizeInflation()) { return 1.0f; } - return Properties().Get(FontSizeInflationProperty()); + return GetProperty(FontSizeInflationProperty()); } void @@ -912,13 +912,13 @@ nsBulletFrame::SetFontSizeInflation(float aInflation) if (aInflation == 1.0f) { if (HasFontSizeInflation()) { RemoveStateBits(BULLET_FRAME_HAS_FONT_INFLATION); - Properties().Delete(FontSizeInflationProperty()); + DeleteProperty(FontSizeInflationProperty()); } return; } AddStateBits(BULLET_FRAME_HAS_FONT_INFLATION); - Properties().Set(FontSizeInflationProperty(), aInflation); + SetProperty(FontSizeInflationProperty(), aInflation); } already_AddRefed<imgIContainer> diff --git a/layout/generic/nsCanvasFrame.cpp b/layout/generic/nsCanvasFrame.cpp index 70a2117cf..1a8812fb7 100644 --- a/layout/generic/nsCanvasFrame.cpp +++ b/layout/generic/nsCanvasFrame.cpp @@ -300,7 +300,7 @@ nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder, // above. destRect.Round(); RefPtr<DrawTarget> dt = - Frame()->Properties().Get(nsIFrame::CachedBackgroundImageDT()); + Frame()->GetProperty(nsIFrame::CachedBackgroundImageDT()); DrawTarget* destDT = dest->GetDrawTarget(); if (dt) { BlitSurface(destDT, destRect, dt); @@ -317,7 +317,7 @@ nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext context(ctx); PaintInternal(aBuilder, &context, bgClipRect, &bgClipRect); BlitSurface(dest->GetDrawTarget(), destRect, dt); - frame->Properties().Set(nsIFrame::CachedBackgroundImageDT(), + frame->SetProperty(nsIFrame::CachedBackgroundImageDT(), dt.forget().take()); return; } diff --git a/layout/generic/nsCanvasFrame.h b/layout/generic/nsCanvasFrame.h index 236ffb9c7..8bd9dbf79 100644 --- a/layout/generic/nsCanvasFrame.h +++ b/layout/generic/nsCanvasFrame.h @@ -201,7 +201,7 @@ public: virtual void NotifyRenderingChanged() override { - mFrame->Properties().Delete(nsIFrame::CachedBackgroundImageDT()); + mFrame->DeleteProperty(nsIFrame::CachedBackgroundImageDT()); } virtual bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) override diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 813d19dfe..abf687c9b 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -78,7 +78,7 @@ nsContainerFrame::SetInitialChildList(ChildListID aListID, "Only top layer frames should have backdrop"); MOZ_ASSERT(GetStateBits() & NS_FRAME_OUT_OF_FLOW, "Top layer frames should be out-of-flow"); - MOZ_ASSERT(!Properties().Get(BackdropProperty()), + MOZ_ASSERT(!GetProperty(BackdropProperty()), "We shouldn't have setup backdrop frame list before"); #ifdef DEBUG { @@ -93,7 +93,7 @@ nsContainerFrame::SetInitialChildList(ChildListID aListID, #endif nsFrameList* list = new (PresContext()->PresShell()) nsFrameList(aChildList); - Properties().Set(BackdropProperty(), list); + SetProperty(BackdropProperty(), list); } else { MOZ_ASSERT_UNREACHABLE("Unexpected child list"); } @@ -189,18 +189,17 @@ nsContainerFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot) void nsContainerFrame::SafelyDestroyFrameListProp(nsIFrame* aDestructRoot, nsIPresShell* aPresShell, - FramePropertyTable* aPropTable, FrameListPropertyDescriptor aProp) { // Note that the last frame can be removed through another route and thus // delete the property -- that's why we fetch the property again before // removing each frame rather than fetching it once and iterating the list. - while (nsFrameList* frameList = aPropTable->Get(this, aProp)) { + while (nsFrameList* frameList = GetProperty(aProp)) { nsIFrame* frame = frameList->RemoveFirstChild(); if (MOZ_LIKELY(frame)) { frame->DestroyFrom(aDestructRoot); } else { - aPropTable->Remove(this, aProp); + RemoveProperty(aProp); frameList->Delete(aPresShell); return; } @@ -220,25 +219,49 @@ nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot) // Destroy frames on the principal child list. mFrames.DestroyFramesFrom(aDestructRoot); + + if (MOZ_UNLIKELY(!mProperties.IsEmpty())) { + using T = mozilla::FrameProperties::UntypedDescriptor; + bool hasO = false, hasOC = false, hasEOC = false, hasBackdrop = false; + mProperties.ForEach([&] (const T& aProp, void*) { + if (aProp == OverflowProperty()) { + hasO = true; + } else if (aProp == OverflowContainersProperty()) { + hasOC = true; + } else if (aProp == ExcessOverflowContainersProperty()) { + hasEOC = true; + } else if (aProp == BackdropProperty()) { + hasBackdrop = true; + } + return true; + }); + // Destroy frames on the auxiliary frame lists and delete the lists. nsPresContext* pc = PresContext(); nsIPresShell* shell = pc->PresShell(); - FramePropertyTable* props = pc->PropertyTable(); - SafelyDestroyFrameListProp(aDestructRoot, shell, props, OverflowProperty()); - - MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers) || - !(props->Get(this, nsContainerFrame::OverflowContainersProperty()) || - props->Get(this, nsContainerFrame::ExcessOverflowContainersProperty())), - "this type of frame should't have overflow containers"); - SafelyDestroyFrameListProp(aDestructRoot, shell, props, - OverflowContainersProperty()); - SafelyDestroyFrameListProp(aDestructRoot, shell, props, - ExcessOverflowContainersProperty()); - - MOZ_ASSERT(!props->Get(this, BackdropProperty()) || + if (hasO) { + SafelyDestroyFrameListProp(aDestructRoot, shell, OverflowProperty()); + } + + MOZ_ASSERT(IsFrameOfType(eCanContainOverflowContainers) || + !(hasOC || hasEOC), + "this type of frame shouldn't have overflow containers"); + if (hasOC) { + SafelyDestroyFrameListProp(aDestructRoot, shell, + OverflowContainersProperty()); + } + if (hasEOC) { + SafelyDestroyFrameListProp(aDestructRoot, shell, + ExcessOverflowContainersProperty()); + } + + MOZ_ASSERT(!GetProperty(BackdropProperty()) || StyleDisplay()->mTopLayer != NS_STYLE_TOP_LAYER_NONE, "only top layer frame may have backdrop"); - SafelyDestroyFrameListProp(aDestructRoot, shell, props, BackdropProperty()); + if (hasBackdrop) { + SafelyDestroyFrameListProp(aDestructRoot, shell, BackdropProperty()); + } +} nsSplittableFrame::DestroyFrom(aDestructRoot); } @@ -276,38 +299,28 @@ nsContainerFrame::GetChildList(ChildListID aListID) const } } -static void -AppendIfNonempty(const nsIFrame* aFrame, - FramePropertyTable* aPropTable, - nsContainerFrame::FrameListPropertyDescriptor aProperty, - nsTArray<nsIFrame::ChildList>* aLists, - nsIFrame::ChildListID aListID) -{ - if (nsFrameList* list = aPropTable->Get(aFrame, aProperty)) { - list->AppendIfNonempty(aLists, aListID); - } -} - void nsContainerFrame::GetChildLists(nsTArray<ChildList>* aLists) const { mFrames.AppendIfNonempty(aLists, kPrincipalList); - FramePropertyTable* propTable = PresContext()->PropertyTable(); - ::AppendIfNonempty(this, propTable, OverflowProperty(), - aLists, kOverflowList); - if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) { - ::AppendIfNonempty(this, propTable, OverflowContainersProperty(), - aLists, kOverflowContainersList); - ::AppendIfNonempty(this, propTable, ExcessOverflowContainersProperty(), - aLists, kExcessOverflowContainersList); - } - // Bypass BackdropProperty hashtable lookup for any in-flow frames - // since frames in the top layer (only which can have backdrop) are - // definitely out-of-flow. - if (GetStateBits() & NS_FRAME_OUT_OF_FLOW) { - ::AppendIfNonempty(this, propTable, BackdropProperty(), - aLists, kBackdropList); - } + using T = mozilla::FrameProperties::UntypedDescriptor; + mProperties.ForEach([this, aLists] (const T& aProp, void* aValue) { + typedef const nsFrameList* L; + if (aProp == OverflowProperty()) { + L(aValue)->AppendIfNonempty(aLists, kOverflowList); + } else if (aProp == OverflowContainersProperty()) { + MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers), + "found unexpected OverflowContainersProperty"); + L(aValue)->AppendIfNonempty(aLists, kOverflowContainersList); + } else if (aProp == ExcessOverflowContainersProperty()) { + MOZ_ASSERT(IsFrameOfType(nsIFrame::eCanContainOverflowContainers), + "found unexpected ExcessOverflowContainersProperty"); + L(aValue)->AppendIfNonempty(aLists, kExcessOverflowContainersList); + } else if (aProp == BackdropProperty()) { + L(aValue)->AppendIfNonempty(aLists, kBackdropList); + } + return true; + }); nsSplittableFrame::GetChildLists(aLists); } @@ -1335,15 +1348,15 @@ nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder* aBuilder, } static bool -TryRemoveFrame(nsIFrame* aFrame, FramePropertyTable* aPropTable, +TryRemoveFrame(nsIFrame* aFrame, nsContainerFrame::FrameListPropertyDescriptor aProp, nsIFrame* aChildToRemove) { - nsFrameList* list = aPropTable->Get(aFrame, aProp); + nsFrameList* list = aFrame->GetProperty(aProp); if (list && list->StartRemoveFrame(aChildToRemove)) { // aChildToRemove *may* have been removed from this list. if (list->IsEmpty()) { - aPropTable->Remove(aFrame, aProp); + aFrame->RemoveProperty(aProp); list->Delete(aFrame->PresContext()->PresShell()); } return true; @@ -1356,13 +1369,12 @@ nsContainerFrame::MaybeStealOverflowContainerFrame(nsIFrame* aChild) { bool removed = false; if (MOZ_UNLIKELY(aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) { - FramePropertyTable* propTable = PresContext()->PropertyTable(); // Try removing from the overflow container list. - removed = ::TryRemoveFrame(this, propTable, OverflowContainersProperty(), + removed = ::TryRemoveFrame(this, OverflowContainersProperty(), aChild); if (!removed) { // It might be in the excess overflow container list. - removed = ::TryRemoveFrame(this, propTable, + removed = ::TryRemoveFrame(this, ExcessOverflowContainersProperty(), aChild); } @@ -1377,10 +1389,9 @@ nsContainerFrame::StealFrame(nsIFrame* aChild) if (!mFrames.ContainsFrame(aChild)) { nsFrameList* list = GetOverflowFrames(); if (!list || !list->ContainsFrame(aChild)) { - FramePropertyTable* propTable = PresContext()->PropertyTable(); - list = propTable->Get(this, OverflowContainersProperty()); + list = GetProperty(OverflowContainersProperty()); if (!list || !list->ContainsFrame(aChild)) { - list = propTable->Get(this, ExcessOverflowContainersProperty()); + list = GetProperty(ExcessOverflowContainersProperty()); MOZ_ASSERT(list && list->ContainsFrame(aChild), "aChild isn't our child" " or on a frame list not supported by StealFrame"); } @@ -1536,20 +1547,20 @@ nsContainerFrame::SetOverflowFrames(const nsFrameList& aOverflowFrames) nsPresContext* pc = PresContext(); nsFrameList* newList = new (pc->PresShell()) nsFrameList(aOverflowFrames); - pc->PropertyTable()->Set(this, OverflowProperty(), newList); + SetProperty(OverflowProperty(), newList); } nsFrameList* nsContainerFrame::GetPropTableFrames( FrameListPropertyDescriptor aProperty) const { - return PresContext()->PropertyTable()->Get(this, aProperty); + return GetProperty(aProperty); } nsFrameList* nsContainerFrame::RemovePropTableFrames(FrameListPropertyDescriptor aProperty) { - return PresContext()->PropertyTable()->Remove(this, aProperty); + return RemoveProperty(aProperty); } void @@ -1563,7 +1574,7 @@ nsContainerFrame::SetPropTableFrames(nsFrameList* aFrameList, IsFrameOfType(nsIFrame::eCanContainOverflowContainers), "this type of frame can't have overflow containers"); MOZ_ASSERT(!GetPropTableFrames(aProperty)); - PresContext()->PropertyTable()->Set(this, aProperty, aFrameList); + SetProperty(aProperty, aFrameList); } /** @@ -2253,13 +2264,11 @@ nsOverflowContinuationTracker::EndFinish(nsIFrame* aChild) return; } // Forget mOverflowContList if it was deleted. - nsPresContext* pc = aChild->PresContext(); - FramePropertyTable* propTable = pc->PropertyTable(); - nsFrameList* eoc = propTable->Get( - mParent, nsContainerFrame::ExcessOverflowContainersProperty()); + nsFrameList* eoc = mParent->GetProperty + (nsContainerFrame::ExcessOverflowContainersProperty()); if (eoc != mOverflowContList) { - nsFrameList* oc = static_cast<nsFrameList*>(propTable->Get(mParent, - nsContainerFrame::OverflowContainersProperty())); + nsFrameList* oc = static_cast<nsFrameList*>(mParent->GetProperty + (nsContainerFrame::OverflowContainersProperty())); if (oc != mOverflowContList) { // mOverflowContList was deleted mPrevOverflowCont = nullptr; diff --git a/layout/generic/nsContainerFrame.h b/layout/generic/nsContainerFrame.h index a9f6d52df..ddf993d91 100644 --- a/layout/generic/nsContainerFrame.h +++ b/layout/generic/nsContainerFrame.h @@ -24,9 +24,6 @@ #define NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD 0x0010 class nsOverflowContinuationTracker; -namespace mozilla { -class FramePropertyTable; -} // namespace mozilla // Some macros for container classes to do sanity checking on // width/height/x/y values computed during reflow. @@ -548,7 +545,7 @@ public: // Use this to suppress the CRAZY_SIZE assertions. NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(DebugReflowingWithInfiniteISize, bool) bool IsCrazySizeAssertSuppressed() const { - return Properties().Get(DebugReflowingWithInfiniteISize()); + return GetProperty(DebugReflowingWithInfiniteISize()); } #endif @@ -716,7 +713,6 @@ protected: */ void SafelyDestroyFrameListProp(nsIFrame* aDestructRoot, nsIPresShell* aPresShell, - mozilla::FramePropertyTable* aPropTable, FrameListPropertyDescriptor aProp); // ========================================================================== @@ -898,7 +894,7 @@ inline nsFrameList* nsContainerFrame::GetOverflowFrames() const { - nsFrameList* list = Properties().Get(OverflowProperty()); + nsFrameList* list = GetProperty(OverflowProperty()); NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list"); return list; } @@ -907,7 +903,7 @@ inline nsFrameList* nsContainerFrame::StealOverflowFrames() { - nsFrameList* list = Properties().Remove(OverflowProperty()); + nsFrameList* list = RemoveProperty(OverflowProperty()); NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list"); return list; } diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index 3818d3cb7..94bce1e7a 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -1816,8 +1816,8 @@ nsFlexContainerFrame::MeasureAscentAndHeightForFlexItem( nsPresContext* aPresContext, ReflowInput& aChildReflowInput) { - const FrameProperties props = aItem.Frame()->Properties(); - if (const auto* cachedResult = props.Get(CachedFlexMeasuringReflow())) { + if (const auto* cachedResult = + aItem.Frame()->GetProperty(CachedFlexMeasuringReflow())) { if (cachedResult->IsValidFor(aChildReflowInput)) { return *cachedResult; } @@ -1847,7 +1847,7 @@ nsFlexContainerFrame::MeasureAscentAndHeightForFlexItem( auto result = new CachedMeasuringReflowResult(aChildReflowInput, childDesiredSize); - props.Set(CachedFlexMeasuringReflow(), result); + aItem.Frame()->SetProperty(CachedFlexMeasuringReflow(), result); return *result; } @@ -1855,7 +1855,7 @@ nsFlexContainerFrame::MeasureAscentAndHeightForFlexItem( nsFlexContainerFrame::MarkIntrinsicISizesDirty() { for (nsIFrame* childFrame : mFrames) { - childFrame->Properties().Delete(CachedFlexMeasuringReflow()); + childFrame->DeleteProperty(CachedFlexMeasuringReflow()); } nsContainerFrame::MarkIntrinsicISizesDirty(); } @@ -4236,25 +4236,26 @@ class MOZ_RAII AutoFlexItemMainSizeOverride final public: explicit AutoFlexItemMainSizeOverride(FlexItem& aItem MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mItemProps(aItem.Frame()->Properties()) + : mItemFrame(aItem.Frame()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; - MOZ_ASSERT(!mItemProps.Has(nsIFrame::FlexItemMainSizeOverride()), + MOZ_ASSERT(!mItemFrame->HasProperty(nsIFrame::FlexItemMainSizeOverride()), "FlexItemMainSizeOverride prop shouldn't be set already; " "it should only be set temporarily (& not recursively)"); NS_ASSERTION(aItem.HasIntrinsicRatio(), "This should only be needed for items with an aspect ratio"); - mItemProps.Set(nsIFrame::FlexItemMainSizeOverride(), aItem.GetMainSize()); + mItemFrame->SetProperty(nsIFrame::FlexItemMainSizeOverride(), + aItem.GetMainSize()); } ~AutoFlexItemMainSizeOverride() { - mItemProps.Remove(nsIFrame::FlexItemMainSizeOverride()); + mItemFrame->RemoveProperty(nsIFrame::FlexItemMainSizeOverride()); } private: - const FrameProperties mItemProps; + nsIFrame* mItemFrame; MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; @@ -4668,8 +4669,7 @@ nsFlexContainerFrame::MoveFlexItemToFinalPosition( // If item is relpos, look up its offsets (cached from prev reflow) LogicalMargin logicalOffsets(outerWM); if (NS_STYLE_POSITION_RELATIVE == aItem.Frame()->StyleDisplay()->mPosition) { - FrameProperties props = aItem.Frame()->Properties(); - nsMargin* cachedOffsets = props.Get(nsIFrame::ComputedOffsetProperty()); + nsMargin* cachedOffsets = aItem.Frame()->GetProperty(nsIFrame::ComputedOffsetProperty()); MOZ_ASSERT(cachedOffsets, "relpos previously-reflowed frame should've cached its offsets"); logicalOffsets = LogicalMargin(outerWM, *cachedOffsets); diff --git a/layout/generic/nsFloatManager.cpp b/layout/generic/nsFloatManager.cpp index 2c0ff1f38..4e7e7ff91 100644 --- a/layout/generic/nsFloatManager.cpp +++ b/layout/generic/nsFloatManager.cpp @@ -331,7 +331,7 @@ nsFloatManager::GetRegionFor(WritingMode aWM, nsIFrame* aFloat, const nsSize& aContainerSize) { LogicalRect region = aFloat->GetLogicalRect(aWM, aContainerSize); - void* storedRegion = aFloat->Properties().Get(FloatRegionProperty()); + void* storedRegion = aFloat->GetProperty(FloatRegionProperty()); if (storedRegion) { nsMargin margin = *static_cast<nsMargin*>(storedRegion); region.Inflate(aWM, LogicalMargin(aWM, margin)); @@ -346,15 +346,14 @@ nsFloatManager::StoreRegionFor(WritingMode aWM, nsIFrame* aFloat, { nsRect region = aRegion.GetPhysicalRect(aWM, aContainerSize); nsRect rect = aFloat->GetRect(); - FrameProperties props = aFloat->Properties(); if (region.IsEqualEdges(rect)) { - props.Delete(FloatRegionProperty()); + aFloat->DeleteProperty(FloatRegionProperty()); } else { - nsMargin* storedMargin = props.Get(FloatRegionProperty()); + nsMargin* storedMargin = aFloat->GetProperty(FloatRegionProperty()); if (!storedMargin) { storedMargin = new nsMargin(); - props.Set(FloatRegionProperty(), storedMargin); + aFloat->SetProperty(FloatRegionProperty(), storedMargin); } *storedMargin = region - rect; } diff --git a/layout/generic/nsFontInflationData.cpp b/layout/generic/nsFontInflationData.cpp index 9e9a51999..831658c9e 100644 --- a/layout/generic/nsFontInflationData.cpp +++ b/layout/generic/nsFontInflationData.cpp @@ -6,7 +6,7 @@ /* Per-block-formatting-context manager of font size inflation for pan and zoom UI. */ #include "nsFontInflationData.h" -#include "FramePropertyTable.h" +#include "FrameProperties.h" #include "nsTextControlFrame.h" #include "nsListControlFrame.h" #include "nsComboboxControlFrame.h" @@ -27,7 +27,7 @@ nsFontInflationData::FindFontInflationDataFor(const nsIFrame *aFrame) NS_ASSERTION(bfc->GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT, "should have found a flow root"); - return bfc->Properties().Get(FontInflationDataProperty()); + return bfc->GetProperty(FontInflationDataProperty()); } /* static */ bool @@ -36,8 +36,7 @@ nsFontInflationData::UpdateFontInflationDataISizeFor(const ReflowInput& aReflowI nsIFrame *bfc = aReflowInput.mFrame; NS_ASSERTION(bfc->GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT, "should have been given a flow root"); - FrameProperties bfcProps(bfc->Properties()); - nsFontInflationData *data = bfcProps.Get(FontInflationDataProperty()); + nsFontInflationData *data = bfc->GetProperty(FontInflationDataProperty()); bool oldInflationEnabled; nscoord oldNCAISize; if (data) { @@ -45,7 +44,7 @@ nsFontInflationData::UpdateFontInflationDataISizeFor(const ReflowInput& aReflowI oldInflationEnabled = data->mInflationEnabled; } else { data = new nsFontInflationData(bfc); - bfcProps.Set(FontInflationDataProperty(), data); + bfc->SetProperty(FontInflationDataProperty(), data); oldNCAISize = -1; oldInflationEnabled = true; /* not relevant */ } @@ -65,8 +64,7 @@ nsFontInflationData::MarkFontInflationDataTextDirty(nsIFrame *aBFCFrame) NS_ASSERTION(aBFCFrame->GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT, "should have been given a flow root"); - FrameProperties bfcProps(aBFCFrame->Properties()); - nsFontInflationData *data = bfcProps.Get(FontInflationDataProperty()); + nsFontInflationData *data = aBFCFrame->GetProperty(FontInflationDataProperty()); if (data) { data->MarkTextDirty(); } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index fa5b24d40..bd96f213b 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -168,13 +168,12 @@ NS_DECLARE_FRAME_PROPERTY_DELETABLE(BoxMetricsProperty, nsBoxLayoutMetrics) static void InitBoxMetrics(nsIFrame* aFrame, bool aClear) { - FrameProperties props = aFrame->Properties(); if (aClear) { - props.Delete(BoxMetricsProperty()); + aFrame->DeleteProperty(BoxMetricsProperty()); } nsBoxLayoutMetrics* metrics = new nsBoxLayoutMetrics(); - props.Set(BoxMetricsProperty(), metrics); + aFrame->SetProperty(BoxMetricsProperty(), metrics); static_cast<nsFrame*>(aFrame)->nsFrame::MarkIntrinsicISizesDirty(); metrics->mBlockAscent = 0; @@ -254,7 +253,7 @@ nsIFrame::HasAbsolutelyPositionedChildren() const { nsAbsoluteContainingBlock* nsIFrame::GetAbsoluteContainingBlock() const { NS_ASSERTION(IsAbsoluteContainer(), "The frame is not marked as an abspos container correctly"); - nsAbsoluteContainingBlock* absCB = Properties().Get(AbsoluteContainingBlockProperty()); + nsAbsoluteContainingBlock* absCB = GetProperty(AbsoluteContainingBlockProperty()); NS_ASSERTION(absCB, "The frame is marked as an abspos container but doesn't have the property"); return absCB; } @@ -263,25 +262,25 @@ void nsIFrame::MarkAsAbsoluteContainingBlock() { MOZ_ASSERT(GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN); - NS_ASSERTION(!Properties().Get(AbsoluteContainingBlockProperty()), + NS_ASSERTION(!GetProperty(AbsoluteContainingBlockProperty()), "Already has an abs-pos containing block property?"); NS_ASSERTION(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN), "Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?"); AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN); - Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID())); + SetProperty(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID())); } void nsIFrame::MarkAsNotAbsoluteContainingBlock() { NS_ASSERTION(!HasAbsolutelyPositionedChildren(), "Think of the children!"); - NS_ASSERTION(Properties().Get(AbsoluteContainingBlockProperty()), + NS_ASSERTION(GetProperty(AbsoluteContainingBlockProperty()), "Should have an abs-pos containing block property"); NS_ASSERTION(HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN), "Should have NS_FRAME_HAS_ABSPOS_CHILDREN state bit"); MOZ_ASSERT(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)); RemoveStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN); - Properties().Delete(AbsoluteContainingBlockProperty()); + DeleteProperty(AbsoluteContainingBlockProperty()); } bool @@ -652,32 +651,30 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot) } // If we have any IB split siblings, clear their references to us. - // (Note: This has to happen before we call shell->NotifyDestroyingFrame, - // because that clears our Properties() table.) + // (Note: This has to happen before we clear our Properties() table.) if (mState & NS_FRAME_PART_OF_IBSPLIT) { // Delete previous sibling's reference to me. - nsIFrame* prevSib = Properties().Get(nsIFrame::IBSplitPrevSibling()); + nsIFrame* prevSib = GetProperty(nsIFrame::IBSplitPrevSibling()); if (prevSib) { NS_WARNING_ASSERTION( - this == prevSib->Properties().Get(nsIFrame::IBSplitSibling()), + this == prevSib->GetProperty(nsIFrame::IBSplitSibling()), "IB sibling chain is inconsistent"); - prevSib->Properties().Delete(nsIFrame::IBSplitSibling()); + prevSib->DeleteProperty(nsIFrame::IBSplitSibling()); } // Delete next sibling's reference to me. - nsIFrame* nextSib = Properties().Get(nsIFrame::IBSplitSibling()); + nsIFrame* nextSib = GetProperty(nsIFrame::IBSplitSibling()); if (nextSib) { NS_WARNING_ASSERTION( - this == nextSib->Properties().Get(nsIFrame::IBSplitPrevSibling()), + this == nextSib->GetProperty(nsIFrame::IBSplitPrevSibling()), "IB sibling chain is inconsistent"); - nextSib->Properties().Delete(nsIFrame::IBSplitPrevSibling()); + nextSib->DeleteProperty(nsIFrame::IBSplitPrevSibling()); } } bool isPrimaryFrame = (mContent && mContent->GetPrimaryFrame() == this); if (isPrimaryFrame) { - // This needs to happen before shell->NotifyDestroyingFrame because - // that clears our Properties() table. + // This needs to happen before we clear our Properties() table. ActiveLayerTracker::TransferActivityToContent(this, mContent); // Unfortunately, we need to do this for all frames being reframed @@ -712,9 +709,8 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot) } } - // Disable visibility tracking. Note that we have to do this before calling - // NotifyDestroyingFrame(), which will clear frame properties and make us lose - // track of whether we were previously visible or not. + // Disable visibility tracking. Note that we have to do this before we clear + // frame properties and lose track of whether we were previously visible. // XXX(seth): It'd be ideal to assert that we're already marked nonvisible // here, but it's unfortunately tricky to guarantee in the face of things like // frame reconstruction induced by style changes. @@ -742,6 +738,10 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot) mContent->SetPrimaryFrame(nullptr); } + // Delete all properties attached to the frame, to ensure any property + // destructors that need the frame pointer are handled properly. + DeleteAllProperties(); + // Must retrieve the object ID before calling destructors, so the // vtable is still valid. // @@ -860,22 +860,21 @@ nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) // calls GetUsed(Margin|Border|Padding)() before the next reflow, we // can give an accurate answer. // We don't want to set the property if one already exists. - FrameProperties props = Properties(); nsMargin oldValue(0, 0, 0, 0); nsMargin newValue(0, 0, 0, 0); const nsStyleMargin* oldMargin = aOldStyleContext->PeekStyleMargin(); if (oldMargin && oldMargin->GetMargin(oldValue)) { if ((!StyleMargin()->GetMargin(newValue) || oldValue != newValue) && - !props.Get(UsedMarginProperty())) { - props.Set(UsedMarginProperty(), new nsMargin(oldValue)); + !GetProperty(UsedMarginProperty())) { + SetProperty(UsedMarginProperty(), new nsMargin(oldValue)); } } const nsStylePadding* oldPadding = aOldStyleContext->PeekStylePadding(); if (oldPadding && oldPadding->GetPadding(oldValue)) { if ((!StylePadding()->GetPadding(newValue) || oldValue != newValue) && - !props.Get(UsedPaddingProperty())) { - props.Set(UsedPaddingProperty(), new nsMargin(oldValue)); + !GetProperty(UsedPaddingProperty())) { + SetProperty(UsedPaddingProperty(), new nsMargin(oldValue)); } } @@ -884,8 +883,8 @@ nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) oldValue = oldBorder->GetComputedBorder(); newValue = StyleBorder()->GetComputedBorder(); if (oldValue != newValue && - !props.Get(UsedBorderProperty())) { - props.Set(UsedBorderProperty(), new nsMargin(oldValue)); + !GetProperty(UsedBorderProperty())) { + SetProperty(UsedBorderProperty(), new nsMargin(oldValue)); } } } @@ -961,7 +960,7 @@ nsIFrame::GetUsedMargin() const IsSVGText()) return margin; - nsMargin *m = Properties().Get(UsedMarginProperty()); + nsMargin *m = GetProperty(UsedMarginProperty()); if (m) { margin = *m; } else { @@ -1000,7 +999,7 @@ nsIFrame::GetUsedBorder() const return border; } - nsMargin *b = Properties().Get(UsedBorderProperty()); + nsMargin *b = GetProperty(UsedBorderProperty()); if (b) { border = *b; } else { @@ -1037,7 +1036,7 @@ nsIFrame::GetUsedPadding() const } } - nsMargin *p = Properties().Get(UsedPaddingProperty()); + nsMargin *p = GetProperty(UsedPaddingProperty()); if (p) { padding = *p; } else { @@ -1478,8 +1477,7 @@ nsIFrame::GetVisibility() const } bool isSet = false; - FrameProperties props = Properties(); - uint32_t visibleCount = props.Get(VisibilityStateProperty(), &isSet); + uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet); MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"); @@ -1552,15 +1550,14 @@ nsIFrame::EnableVisibilityTracking() return; // Nothing to do. } - FrameProperties props = Properties(); - MOZ_ASSERT(!props.Has(VisibilityStateProperty()), + MOZ_ASSERT(!HasProperty(VisibilityStateProperty()), "Shouldn't have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is not set"); // Add the state bit so we know to track visibility for this frame, and // initialize the frame property. AddStateBits(NS_FRAME_VISIBILITY_IS_TRACKED); - props.Set(VisibilityStateProperty(), 0); + SetProperty(VisibilityStateProperty(), 0); nsIPresShell* presShell = PresContext()->PresShell(); if (!presShell) { @@ -1582,8 +1579,7 @@ nsIFrame::DisableVisibilityTracking() } bool isSet = false; - FrameProperties props = Properties(); - uint32_t visibleCount = props.Remove(VisibilityStateProperty(), &isSet); + uint32_t visibleCount = RemoveProperty(VisibilityStateProperty(), &isSet); MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"); @@ -1605,8 +1601,7 @@ nsIFrame::DecApproximateVisibleCount(Maybe<OnNonvisible> aNonvisibleAction MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED); bool isSet = false; - FrameProperties props = Properties(); - uint32_t visibleCount = props.Get(VisibilityStateProperty(), &isSet); + uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet); MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"); @@ -1614,7 +1609,7 @@ nsIFrame::DecApproximateVisibleCount(Maybe<OnNonvisible> aNonvisibleAction "decrementing its visible count?"); visibleCount--; - props.Set(VisibilityStateProperty(), visibleCount); + SetProperty(VisibilityStateProperty(), visibleCount); if (visibleCount > 0) { return; } @@ -1629,14 +1624,13 @@ nsIFrame::IncApproximateVisibleCount() MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED); bool isSet = false; - FrameProperties props = Properties(); - uint32_t visibleCount = props.Get(VisibilityStateProperty(), &isSet); + uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet); MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"); visibleCount++; - props.Set(VisibilityStateProperty(), visibleCount); + SetProperty(VisibilityStateProperty(), visibleCount); if (visibleCount > 1) { return; } @@ -4943,10 +4937,9 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte // If FlexItemMainSizeOverride frame-property is set, then that means the // flex container is imposing a main-size on this flex item for it to use // as its size in the container's main axis. - FrameProperties props = Properties(); bool didImposeMainSize; nscoord imposedMainSize = - props.Get(nsIFrame::FlexItemMainSizeOverride(), &didImposeMainSize); + GetProperty(nsIFrame::FlexItemMainSizeOverride(), &didImposeMainSize); if (didImposeMainSize) { imposedMainSizeStyleCoord.emplace(imposedMainSize, nsStyleCoord::CoordConstructor); @@ -5686,7 +5679,7 @@ nsIFrame::GetView() const return nullptr; // Check for a property on the frame - nsView* value = Properties().Get(ViewProperty()); + nsView* value = GetProperty(ViewProperty()); NS_ASSERTION(value, "frame state bit was set but frame has no view"); return value; } @@ -5709,7 +5702,7 @@ nsIFrame::SetView(nsView* aView) #endif // Set a property on the frame - Properties().Set(ViewProperty(), aView); + SetProperty(ViewProperty(), aView); // Set the frame state bit that says the frame has a view AddStateBits(NS_FRAME_HAS_VIEW); @@ -6098,7 +6091,7 @@ static void InvalidateFrameInternal(nsIFrame *aFrame, bool aHasDisplayItem = tru SchedulePaintInternal(aFrame); } if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) { - aFrame->Properties().Delete(nsIFrame::InvalidationRect()); + aFrame->DeleteProperty(nsIFrame::InvalidationRect()); aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT); } } @@ -6173,13 +6166,13 @@ nsIFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) return; } - nsRect* rect = Properties().Get(InvalidationRect()); + nsRect* rect = GetProperty(InvalidationRect()); if (!rect) { if (alreadyInvalid) { return; } rect = new nsRect(); - Properties().Set(InvalidationRect(), rect); + SetProperty(InvalidationRect(), rect); AddStateBits(NS_FRAME_HAS_INVALID_RECT); } @@ -6280,7 +6273,7 @@ nsIFrame::IsInvalid(nsRect& aRect) } if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) { - nsRect* rect = Properties().Get(InvalidationRect()); + nsRect* rect = GetProperty(InvalidationRect()); NS_ASSERTION(rect, "Must have an invalid rect if NS_FRAME_HAS_INVALID_RECT is set!"); aRect = *rect; } else { @@ -6368,8 +6361,8 @@ ComputeEffectsRect(nsIFrame* aFrame, const nsRect& aOverflowRect, // TODO: We could also take account of clipPath and mask to reduce the // visual overflow, but that's not essential. if (aFrame->StyleEffects()->HasFilters()) { - aFrame->Properties(). - Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r)); + aFrame->SetProperty + (nsIFrame::PreEffectsBBoxProperty(), new nsRect(r)); r = nsSVGUtils::GetPostFilterVisualOverflowRect(aFrame, aOverflowRect); } return r; @@ -6407,8 +6400,8 @@ ComputeEffectsRect(nsIFrame* aFrame, const nsRect& aOverflowRect, // the frame dies. if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) { - aFrame->Properties(). - Set(nsIFrame::PreEffectsBBoxProperty(), new nsRect(r)); + aFrame->SetProperty + (nsIFrame::PreEffectsBBoxProperty(), new nsRect(r)); r = nsSVGIntegrationUtils::ComputePostEffectsVisualOverflowRect(aFrame, r); } @@ -6422,7 +6415,7 @@ nsIFrame::MovePositionBy(const nsPoint& aTranslation) const nsMargin* computedOffsets = nullptr; if (IsRelativelyPositioned()) { - computedOffsets = Properties().Get(nsIFrame::ComputedOffsetProperty()); + computedOffsets = GetProperty(nsIFrame::ComputedOffsetProperty()); } ReflowInput::ApplyRelativePositioning(this, computedOffsets ? *computedOffsets : nsMargin(), @@ -6435,7 +6428,7 @@ nsIFrame::GetNormalRect() const { // It might be faster to first check // StyleDisplay()->IsRelativelyPositionedStyle(). - nsPoint* normalPosition = Properties().Get(NormalPositionProperty()); + nsPoint* normalPosition = GetProperty(NormalPositionProperty()); if (normalPosition) { return nsRect(*normalPosition, GetSize()); } @@ -6447,7 +6440,7 @@ nsIFrame::GetNormalPosition() const { // It might be faster to first check // StyleDisplay()->IsRelativelyPositionedStyle(). - nsPoint* normalPosition = Properties().Get(NormalPositionProperty()); + nsPoint* normalPosition = GetProperty(NormalPositionProperty()); if (normalPosition) { return *normalPosition; } @@ -6506,7 +6499,7 @@ nsIFrame::GetOverflowAreasRelativeToSelf() const { if (IsTransformed()) { nsOverflowAreas* preTransformOverflows = - Properties().Get(PreTransformOverflowAreasProperty()); + GetProperty(PreTransformOverflowAreasProperty()); if (preTransformOverflows) { return nsOverflowAreas(preTransformOverflows->VisualOverflow(), preTransformOverflows->ScrollableOverflow()); @@ -6533,7 +6526,7 @@ nsIFrame::GetScrollableOverflowRectRelativeToSelf() const { if (IsTransformed()) { nsOverflowAreas* preTransformOverflows = - Properties().Get(PreTransformOverflowAreasProperty()); + GetProperty(PreTransformOverflowAreasProperty()); if (preTransformOverflows) return preTransformOverflows->ScrollableOverflow(); } @@ -6545,7 +6538,7 @@ nsIFrame::GetVisualOverflowRectRelativeToSelf() const { if (IsTransformed()) { nsOverflowAreas* preTransformOverflows = - Properties().Get(PreTransformOverflowAreasProperty()); + GetProperty(PreTransformOverflowAreasProperty()); if (preTransformOverflows) return preTransformOverflows->VisualOverflow(); } @@ -6555,7 +6548,7 @@ nsIFrame::GetVisualOverflowRectRelativeToSelf() const nsRect nsIFrame::GetPreEffectsVisualOverflowRect() const { - nsRect* r = Properties().Get(nsIFrame::PreEffectsBBoxProperty()); + nsRect* r = GetProperty(nsIFrame::PreEffectsBBoxProperty()); return r ? *r : GetVisualOverflowRectRelativeToSelf(); } @@ -6758,11 +6751,11 @@ nsIFrame::ListGeneric(nsACString& aTo, const char* aPrefix, uint32_t aFlags) con aTo += nsPrintfCString(" next-%s=%p", fluid?"in-flow":"continuation", static_cast<void*>(GetNextContinuation())); } - void* IBsibling = Properties().Get(IBSplitSibling()); + void* IBsibling = GetProperty(IBSplitSibling()); if (IBsibling) { aTo += nsPrintfCString(" IBSplitSibling=%p", IBsibling); } - void* IBprevsibling = Properties().Get(IBSplitPrevSibling()); + void* IBprevsibling = GetProperty(IBSplitPrevSibling()); if (IBprevsibling) { aTo += nsPrintfCString(" IBSplitPrevSibling=%p", IBprevsibling); } @@ -7164,8 +7157,7 @@ nsFrame::GetPointFromOffset(int32_t inOffset, nsPoint* outPoint) // If the embedding level isn't set, just use the CSS direction // property. bool hasBidiData; - FrameBidiData bidiData = - Properties().Get(BidiDataProperty(), &hasBidiData); + FrameBidiData bidiData = GetProperty(BidiDataProperty(), &hasBidiData); bool isRTL = hasBidiData ? IS_LEVEL_RTL(bidiData.embeddingLevel) : StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL; @@ -8315,7 +8307,7 @@ nsIFrame::ClearOverflowRects() return false; } if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) { - Properties().Delete(OverflowAreasProperty()); + DeleteProperty(OverflowAreasProperty()); } mOverflow.mType = NS_FRAME_OVERFLOW_NONE; return true; @@ -8328,8 +8320,7 @@ nsIFrame::ClearOverflowRects() nsOverflowAreas* nsIFrame::GetOverflowAreasProperty() { - FrameProperties props = Properties(); - nsOverflowAreas* overflow = props.Get(OverflowAreasProperty()); + nsOverflowAreas* overflow = GetProperty(OverflowAreasProperty()); if (overflow) { return overflow; // the property already exists @@ -8338,7 +8329,7 @@ nsIFrame::GetOverflowAreasProperty() // The property isn't set yet, so allocate a new rect, set the property, // and return the newly allocated rect overflow = new nsOverflowAreas; - props.Set(OverflowAreasProperty(), overflow); + SetProperty(OverflowAreasProperty(), overflow); return overflow; } @@ -8349,7 +8340,7 @@ bool nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas) { if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) { - nsOverflowAreas* overflow = Properties().Get(OverflowAreasProperty()); + nsOverflowAreas* overflow = GetProperty(OverflowAreasProperty()); bool changed = *overflow != aOverflowAreas; *overflow = aOverflowAreas; @@ -8593,7 +8584,7 @@ ComputeAndIncludeOutlineArea(nsIFrame* aFrame, nsOverflowAreas& aOverflowAreas, } // Keep this code in sync with GetOutlineInnerRect in nsCSSRendering.cpp. - aFrame->Properties().Set(nsIFrame::OutlineInnerRectProperty(), + aFrame->SetProperty(nsIFrame::OutlineInnerRectProperty(), new nsRect(innerRect)); const nscoord offset = outline->mOutlineOffset; nsRect outerRect(innerRect); @@ -8635,22 +8626,22 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, if (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) || !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) { nsOverflowAreas* initial = - Properties().Get(nsIFrame::InitialOverflowProperty()); + GetProperty(nsIFrame::InitialOverflowProperty()); if (!initial) { - Properties().Set(nsIFrame::InitialOverflowProperty(), + SetProperty(nsIFrame::InitialOverflowProperty(), new nsOverflowAreas(aOverflowAreas)); } else if (initial != &aOverflowAreas) { *initial = aOverflowAreas; } } else { - Properties().Delete(nsIFrame::InitialOverflowProperty()); + DeleteProperty(nsIFrame::InitialOverflowProperty()); } #ifdef DEBUG - Properties().Set(nsIFrame::DebugInitialOverflowPropertyApplied(), true); + SetProperty(nsIFrame::DebugInitialOverflowPropertyApplied(), true); #endif } else { #ifdef DEBUG - Properties().Delete(nsIFrame::DebugInitialOverflowPropertyApplied()); + DeleteProperty(nsIFrame::DebugInitialOverflowPropertyApplied()); #endif } @@ -8745,8 +8736,8 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, } if (hasTransform) { - Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(), - new nsOverflowAreas(aOverflowAreas)); + SetProperty(nsIFrame::PreTransformOverflowAreasProperty(), + new nsOverflowAreas(aOverflowAreas)); if (Combines3DTransformWithAncestors()) { /* If we're a preserve-3d leaf frame, then our pre-transform overflow should be correct. Our @@ -8771,7 +8762,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, } } } else { - Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty()); + DeleteProperty(nsIFrame::PreTransformOverflowAreasProperty()); } /* Revert the size change in case some caller is depending on this. */ @@ -8803,7 +8794,7 @@ nsIFrame::RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame) } if (child->HasPerspective()) { nsOverflowAreas* overflow = - child->Properties().Get(nsIFrame::InitialOverflowProperty()); + child->GetProperty(nsIFrame::InitialOverflowProperty()); nsRect bounds(nsPoint(0, 0), child->GetSize()); if (overflow) { nsOverflowAreas overflowCopy = *overflow; @@ -8915,7 +8906,7 @@ GetIBSplitSiblingForAnonymousBlock(const nsIFrame* aFrame) * property. */ nsIFrame *ibSplitSibling = - aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling()); + aFrame->GetProperty(nsIFrame::IBSplitPrevSibling()); NS_ASSERTION(ibSplitSibling, "Broken frame tree?"); return ibSplitSibling; } @@ -9825,7 +9816,7 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState, nsBoxLayoutMetrics* nsFrame::BoxMetrics() const { - nsBoxLayoutMetrics* metrics = Properties().Get(BoxMetricsProperty()); + nsBoxLayoutMetrics* metrics = GetProperty(BoxMetricsProperty()); NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called"); return metrics; } @@ -10069,6 +10060,24 @@ nsFrame::HasCSSTransitions() return collection && collection->mAnimations.Length() > 0; } +size_t +nsIFrame::SizeOfFramePropertiesForTree(MallocSizeOf aMallocSizeOf) const +{ + size_t result = 0; + + result += mProperties.SizeOfExcludingThis(aMallocSizeOf); + + FrameChildListIterator iter(this); + while (!iter.IsDone()) { + for (const nsIFrame* f : iter.CurrentList()) { + result += f->SizeOfFramePropertiesForTree(aMallocSizeOf); + } + iter.Next(); + } + + return result; +} + // Box layout debugging #ifdef DEBUG_REFLOW int32_t gIndent2 = 0; diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index fbd61f783..3a2d5ad1d 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -2000,7 +2000,7 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput ++fragment; firstInFlow = pif; } - mSharedGridData = firstInFlow->Properties().Get(SharedGridData::Prop()); + mSharedGridData = firstInFlow->GetProperty(SharedGridData::Prop()); MOZ_ASSERT(mSharedGridData, "first-in-flow must have SharedGridData"); // Find the start row for this fragment and undo breaks after that row @@ -2809,7 +2809,7 @@ nsGridContainerFrame::GridItemCB(nsIFrame* aChild) { MOZ_ASSERT((aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && aChild->IsAbsolutelyPositioned()); - nsRect* cb = aChild->Properties().Get(GridItemContainingBlockRect()); + nsRect* cb = aChild->GetProperty(GridItemContainingBlockRect()); MOZ_ASSERT(cb, "this method must only be called on grid items, and the grid " "container should've reflowed this item by now and set up cb"); return *cb; @@ -2836,7 +2836,7 @@ nsGridContainerFrame::AddImplicitNamedAreas( // Lazily create the ImplicitNamedAreas. if (!areas) { areas = new ImplicitNamedAreas; - Properties().Set(ImplicitNamedAreasProperty(), areas); + SetProperty(ImplicitNamedAreasProperty(), areas); } mozilla::css::GridNamedArea area; @@ -2868,7 +2868,7 @@ nsGridContainerFrame::InitImplicitNamedAreas(const nsStylePosition* aStyle) AddImplicitNamedAreas(aStyle->mGridTemplateColumns.mLineNameLists); AddImplicitNamedAreas(aStyle->mGridTemplateRows.mLineNameLists); if (areas && areas->Count() == 0) { - Properties().Delete(ImplicitNamedAreasProperty()); + DeleteProperty(ImplicitNamedAreasProperty()); } } @@ -3711,7 +3711,7 @@ MeasuringReflow(nsIFrame* aChild, } #ifdef DEBUG // This will suppress various CRAZY_SIZE warnings for this reflow. - parent->Properties().Set( + parent->SetProperty( nsContainerFrame::DebugReflowingWithInfiniteISize(), true); #endif auto wm = aChild->GetWritingMode(); @@ -3724,10 +3724,10 @@ MeasuringReflow(nsIFrame* aChild, } if (aBMinSizeClamp != NS_MAXSIZE) { riFlags |= ReflowInput::B_CLAMP_MARGIN_BOX_MIN_SIZE; - aChild->Properties().Set(nsIFrame::BClampMarginBoxMinSizeProperty(), + aChild->SetProperty(nsIFrame::BClampMarginBoxMinSizeProperty(), aBMinSizeClamp); } else { - aChild->Properties().Delete(nsIFrame::BClampMarginBoxMinSizeProperty()); + aChild->DeleteProperty(nsIFrame::BClampMarginBoxMinSizeProperty()); } ReflowInput childRI(pc, *rs, aChild, aAvailableSize, &aCBSize, riFlags); ReflowOutput childSize(childRI); @@ -3738,7 +3738,7 @@ MeasuringReflow(nsIFrame* aChild, parent->FinishReflowChild(aChild, pc, childSize, &childRI, wm, LogicalPoint(wm), nsSize(), flags); #ifdef DEBUG - parent->Properties().Delete(nsContainerFrame::DebugReflowingWithInfiniteISize()); + parent->DeleteProperty(nsContainerFrame::DebugReflowingWithInfiniteISize()); #endif return childSize.BSize(wm); } @@ -5253,9 +5253,9 @@ nsGridContainerFrame::ReflowInFlowChild(nsIFrame* aChild, baselineAdjust = -baselineAdjust; } if (baselineAdjust != nscoord(0)) { - aChild->Properties().Set(aProp, baselineAdjust); + aChild->SetProperty(aProp, baselineAdjust); } else { - aChild->Properties().Delete(aProp); + aChild->DeleteProperty(aProp); } }; SetProp(eLogicalAxisBlock, isOrthogonal ? IBaselinePadProperty() : @@ -5292,10 +5292,10 @@ nsGridContainerFrame::ReflowInFlowChild(nsIFrame* aChild, auto childBAxis = GetOrthogonalAxis(childIAxis); if (aGridItemInfo->mState[childBAxis] & ItemState::eClampMarginBoxMinSize) { flags |= ReflowInput::B_CLAMP_MARGIN_BOX_MIN_SIZE; - aChild->Properties().Set(BClampMarginBoxMinSizeProperty(), - childCBSize.BSize(childWM)); + aChild->SetProperty(BClampMarginBoxMinSizeProperty(), + childCBSize.BSize(childWM)); } else { - aChild->Properties().Delete(BClampMarginBoxMinSizeProperty()); + aChild->DeleteProperty(BClampMarginBoxMinSizeProperty()); } if ((aGridItemInfo->mState[childIAxis] & ItemState::eApplyAutoMinSize)) { flags |= ReflowInput::I_APPLY_AUTO_MIN_SIZE; @@ -5313,11 +5313,11 @@ nsGridContainerFrame::ReflowInFlowChild(nsIFrame* aChild, // A table-wrapper needs to propagate the CB size we give it to its // inner table frame later. @see nsTableWrapperFrame::InitChildReflowInput. if (childType == nsGkAtoms::tableWrapperFrame) { - const auto& props = aChild->Properties(); - LogicalSize* cb = props.Get(nsTableWrapperFrame::GridItemCBSizeProperty()); + LogicalSize* cb = + aChild->GetProperty(nsTableWrapperFrame::GridItemCBSizeProperty()); if (!cb) { cb = new LogicalSize(childWM); - props.Set(nsTableWrapperFrame::GridItemCBSizeProperty(), cb); + aChild->SetProperty(nsTableWrapperFrame::GridItemCBSizeProperty(), cb); } *cb = percentBasis; } @@ -5337,9 +5337,9 @@ nsGridContainerFrame::ReflowInFlowChild(nsIFrame* aChild, } } if (stretch) { - aChild->Properties().Set(FragStretchBSizeProperty(), *aStretchBSize); + aChild->SetProperty(FragStretchBSizeProperty(), *aStretchBSize); } else { - aChild->Properties().Delete(FragStretchBSizeProperty()); + aChild->DeleteProperty(FragStretchBSizeProperty()); } } @@ -5951,10 +5951,10 @@ nsGridContainerFrame::ReflowChildren(GridReflowInput& aState, LogicalRect itemCB = aState.ContainingBlockForAbsPos(area, gridOrigin, gridCB); // nsAbsoluteContainingBlock::Reflow uses physical coordinates. - nsRect* cb = child->Properties().Get(GridItemContainingBlockRect()); + nsRect* cb = child->GetProperty(GridItemContainingBlockRect()); if (!cb) { cb = new nsRect; - child->Properties().Set(GridItemContainingBlockRect(), cb); + child->SetProperty(GridItemContainingBlockRect(), cb); } *cb = itemCB.GetPhysicalRect(wm, gridCBPhysicalSize); } @@ -6044,7 +6044,7 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, f = next; } if (overflowContainers->IsEmpty()) { - Properties().Delete(OverflowContainersProperty()); + DeleteProperty(OverflowContainersProperty()); } MergeSortedExcessOverflowContainers(moveToEOC); } @@ -6355,7 +6355,7 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, Move(colTrackStates), Move(colRemovedRepeatTracks), gridReflowInput.mColFunctions.mRepeatAutoStart); - Properties().Set(GridColTrackInfo(), colInfo); + SetProperty(GridColTrackInfo(), colInfo); uint32_t rowTrackCount = gridReflowInput.mRows.mSizes.Length(); nsTArray<nscoord> rowTrackPositions(rowTrackCount); @@ -6390,7 +6390,7 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, Move(rowTrackStates), Move(rowRemovedRepeatTracks), gridReflowInput.mRowFunctions.mRepeatAutoStart); - Properties().Set(GridRowTrackInfo(), rowInfo); + SetProperty(GridRowTrackInfo(), rowInfo); if (prevInFlow) { // This frame is fragmenting rows from a previous frame, so patch up @@ -6399,7 +6399,7 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, // FIXME: This can be streamlined and/or removed when bug 1151204 lands. ComputedGridTrackInfo* priorRowInfo = - prevInFlow->Properties().Get(GridRowTrackInfo()); + prevInFlow->GetProperty(GridRowTrackInfo()); // Adjust track positions based on the first track in this fragment. if (priorRowInfo->mPositions.Length() > @@ -6421,7 +6421,7 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, Move(priorRowInfo->mStates), Move(priorRowInfo->mRemovedRepeatTracks), priorRowInfo->mRepeatFirstTrack); - prevInFlow->Properties().Set(GridRowTrackInfo(), revisedPriorRowInfo); + prevInFlow->SetProperty(GridRowTrackInfo(), revisedPriorRowInfo); } // Generate the line info properties. We need to provide the number of @@ -6448,7 +6448,7 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, Move(columnLineNames), gridColTemplate.mRepeatAutoLineNameListBefore, gridColTemplate.mRepeatAutoLineNameListAfter); - Properties().Set(GridColumnLineInfo(), columnLineInfo); + SetProperty(GridColumnLineInfo(), columnLineInfo); // Generate row lines next. capacity = gridReflowInput.mRows.mSizes.Length(); @@ -6469,25 +6469,25 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, Move(rowLineNames), gridRowTemplate.mRepeatAutoLineNameListBefore, gridRowTemplate.mRepeatAutoLineNameListAfter); - Properties().Set(GridRowLineInfo(), rowLineInfo); + SetProperty(GridRowLineInfo(), rowLineInfo); // Generate area info for explicit areas. Implicit areas are handled // elsewhere. if (gridReflowInput.mGridStyle->mGridTemplateAreas) { nsTArray<css::GridNamedArea>* areas = new nsTArray<css::GridNamedArea>( gridReflowInput.mGridStyle->mGridTemplateAreas->mNamedAreas); - Properties().Set(ExplicitNamedAreasProperty(), areas); + SetProperty(ExplicitNamedAreasProperty(), areas); } else { - Properties().Delete(ExplicitNamedAreasProperty()); + DeleteProperty(ExplicitNamedAreasProperty()); } } if (!prevInFlow) { - SharedGridData* sharedGridData = Properties().Get(SharedGridData::Prop()); + SharedGridData* sharedGridData = GetProperty(SharedGridData::Prop()); if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) { if (!sharedGridData) { sharedGridData = new SharedGridData; - Properties().Set(SharedGridData::Prop(), sharedGridData); + SetProperty(SharedGridData::Prop(), sharedGridData); } sharedGridData->mCols.mSizes.Clear(); sharedGridData->mCols.mSizes.SwapElements(gridReflowInput.mCols.mSizes); @@ -6522,7 +6522,7 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext, sharedGridData->mGenerateComputedGridInfo = HasAnyStateBits(NS_STATE_GRID_GENERATE_COMPUTED_VALUES); } else if (sharedGridData && !GetNextInFlow()) { - Properties().Delete(SharedGridData::Prop()); + DeleteProperty(SharedGridData::Prop()); } } @@ -7142,10 +7142,10 @@ nsGridContainerFrame::GetGridFrameWithComputedInfo(nsIFrame* aFrame) nsGridContainerFrame* gridFrame = GetGridContainerFrame(aFrame); if (gridFrame) { // if any of our properties are missing, generate them - bool reflowNeeded = (!gridFrame->Properties().Has(GridColTrackInfo()) || - !gridFrame->Properties().Has(GridRowTrackInfo()) || - !gridFrame->Properties().Has(GridColumnLineInfo()) || - !gridFrame->Properties().Has(GridRowLineInfo())); + bool reflowNeeded = (!gridFrame->HasProperty(GridColTrackInfo()) || + !gridFrame->HasProperty(GridRowTrackInfo()) || + !gridFrame->HasProperty(GridColumnLineInfo()) || + !gridFrame->HasProperty(GridRowLineInfo())); if (reflowNeeded) { // Trigger a reflow that generates additional grid property data. @@ -7161,13 +7161,13 @@ nsGridContainerFrame::GetGridFrameWithComputedInfo(nsIFrame* aFrame) // Assert the grid properties are present MOZ_ASSERT(!gridFrame || - gridFrame->Properties().Has(GridColTrackInfo())); + gridFrame->HasProperty(GridColTrackInfo())); MOZ_ASSERT(!gridFrame || - gridFrame->Properties().Has(GridRowTrackInfo())); + gridFrame->HasProperty(GridRowTrackInfo())); MOZ_ASSERT(!gridFrame || - gridFrame->Properties().Has(GridColumnLineInfo())); + gridFrame->HasProperty(GridColumnLineInfo())); MOZ_ASSERT(!gridFrame || - gridFrame->Properties().Has(GridRowLineInfo())); + gridFrame->HasProperty(GridRowLineInfo())); } } diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h index e610dfa0b..960558421 100644 --- a/layout/generic/nsGridContainerFrame.h +++ b/layout/generic/nsGridContainerFrame.h @@ -164,7 +164,7 @@ public: NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridColTrackInfo, ComputedGridTrackInfo) const ComputedGridTrackInfo* GetComputedTemplateColumns() { - const ComputedGridTrackInfo* info = Properties().Get(GridColTrackInfo()); + const ComputedGridTrackInfo* info = GetProperty(GridColTrackInfo()); MOZ_ASSERT(info, "Property generation wasn't requested."); return info; } @@ -172,7 +172,7 @@ public: NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowTrackInfo, ComputedGridTrackInfo) const ComputedGridTrackInfo* GetComputedTemplateRows() { - const ComputedGridTrackInfo* info = Properties().Get(GridRowTrackInfo()); + const ComputedGridTrackInfo* info = GetProperty(GridRowTrackInfo()); MOZ_ASSERT(info, "Property generation wasn't requested."); return info; } @@ -180,7 +180,7 @@ public: NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridColumnLineInfo, ComputedGridLineInfo) const ComputedGridLineInfo* GetComputedTemplateColumnLines() { - const ComputedGridLineInfo* info = Properties().Get(GridColumnLineInfo()); + const ComputedGridLineInfo* info = GetProperty(GridColumnLineInfo()); MOZ_ASSERT(info, "Property generation wasn't requested."); return info; } @@ -188,7 +188,7 @@ public: NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowLineInfo, ComputedGridLineInfo) const ComputedGridLineInfo* GetComputedTemplateRowLines() { - const ComputedGridLineInfo* info = Properties().Get(GridRowLineInfo()); + const ComputedGridLineInfo* info = GetProperty(GridRowLineInfo()); MOZ_ASSERT(info, "Property generation wasn't requested."); return info; } @@ -199,14 +199,14 @@ public: NS_DECLARE_FRAME_PROPERTY_DELETABLE(ImplicitNamedAreasProperty, ImplicitNamedAreas) ImplicitNamedAreas* GetImplicitNamedAreas() const { - return Properties().Get(ImplicitNamedAreasProperty()); + return GetProperty(ImplicitNamedAreasProperty()); } typedef nsTArray<mozilla::css::GridNamedArea> ExplicitNamedAreas; NS_DECLARE_FRAME_PROPERTY_DELETABLE(ExplicitNamedAreasProperty, ExplicitNamedAreas) ExplicitNamedAreas* GetExplicitNamedAreas() const { - return Properties().Get(ExplicitNamedAreasProperty()); + return GetProperty(ExplicitNamedAreasProperty()); } /** diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 2acafa882..ec3568483 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -24,7 +24,7 @@ #include <stdio.h> #include "CaretAssociationHint.h" -#include "FramePropertyTable.h" +#include "FrameProperties.h" #include "mozilla/layout/FrameChildList.h" #include "mozilla/Maybe.h" #include "mozilla/WritingModes.h" @@ -997,7 +997,7 @@ public: #define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(prop, type) \ static void AssertOnDestroyingProperty##prop(type*) { \ MOZ_ASSERT_UNREACHABLE("Frame property " #prop " should never " \ - "be destroyed by the FramePropertyTable"); \ + "be destroyed by the FrameProperties class"); \ } \ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, \ AssertOnDestroyingProperty##prop) @@ -1005,8 +1005,8 @@ public: #define NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(prop, type) \ NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(prop, mozilla::SmallValueHolder<type>) - NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitSibling, nsIFrame) - NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitPrevSibling, nsIFrame) + NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitSibling, nsContainerFrame) + NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(IBSplitPrevSibling, nsContainerFrame) NS_DECLARE_FRAME_PROPERTY_DELETABLE(NormalPositionProperty, nsPoint) NS_DECLARE_FRAME_PROPERTY_DELETABLE(ComputedOffsetProperty, nsMargin) @@ -1059,7 +1059,7 @@ public: mozilla::FrameBidiData GetBidiData() { - return Properties().Get(BidiDataProperty()); + return GetProperty(BidiDataProperty()); } nsBidiLevel GetBaseLevel() @@ -1073,7 +1073,7 @@ public: } nsTArray<nsIContent*>* GetGenConPseudos() { - return Properties().Get(GenConProperty()); + return GetProperty(GenConProperty()); } /** @@ -1534,7 +1534,7 @@ public: bool RefusedAsyncAnimation() const { - return Properties().Get(RefusedAsyncAnimationProperty()); + return GetProperty(RefusedAsyncAnimationProperty()); } /** @@ -3061,9 +3061,53 @@ public: return mContent == aParentContent; } - FrameProperties Properties() const { - return FrameProperties(PresContext()->PropertyTable(), this); - } +/** + * Support for reading and writing properties on the frame. + * These call through to the frame's FrameProperties object, if it + * exists, but avoid creating it if no property is ever set. + */ +template<typename T> +FrameProperties::PropertyType<T> +GetProperty(FrameProperties::Descriptor<T> aProperty, + bool* aFoundResult = nullptr) const +{ + return mProperties.Get(aProperty, aFoundResult); +} + +template<typename T> +bool HasProperty(FrameProperties::Descriptor<T> aProperty) const +{ + return mProperties.Has(aProperty); +} + +template<typename T> +void SetProperty(FrameProperties::Descriptor<T> aProperty, + FrameProperties::PropertyType<T> aValue) +{ + mProperties.Set(aProperty, aValue, this); +} + +template<typename T> +FrameProperties::PropertyType<T> +RemoveProperty(FrameProperties::Descriptor<T> aProperty, + bool* aFoundResult = nullptr) +{ + return mProperties.Remove(aProperty, aFoundResult); +} + +template<typename T> +void DeleteProperty(FrameProperties::Descriptor<T> aProperty) +{ + mProperties.Delete(aProperty, this); +} + +void DeleteAllProperties() +{ + mProperties.DeleteAll(this); +} + +// Reports size of the FrameProperties for this frame and its descendants +size_t SizeOfFramePropertiesForTree(mozilla::MallocSizeOf aMallocSizeOf) const; /** * Return true if and only if this frame obeys visibility:hidden. @@ -3423,7 +3467,7 @@ public: */ bool FrameIsNonFirstInIBSplit() const { return (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) && - FirstContinuation()->Properties().Get(nsIFrame::IBSplitPrevSibling()); + FirstContinuation()->GetProperty(nsIFrame::IBSplitPrevSibling()); } /** @@ -3432,7 +3476,7 @@ public: */ bool FrameIsNonLastInIBSplit() const { return (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) && - FirstContinuation()->Properties().Get(nsIFrame::IBSplitSibling()); + FirstContinuation()->GetProperty(nsIFrame::IBSplitSibling()); } /** @@ -3514,11 +3558,11 @@ private: DestroyPaintedPresShellList) nsTArray<nsWeakPtr>* PaintedPresShellList() { - nsTArray<nsWeakPtr>* list = Properties().Get(PaintedPresShellsProperty()); + nsTArray<nsWeakPtr>* list = GetProperty(PaintedPresShellsProperty()); if (!list) { list = new nsTArray<nsWeakPtr>(); - Properties().Set(PaintedPresShellsProperty(), list); + SetProperty(PaintedPresShellsProperty(), list); } return list; @@ -3535,6 +3579,11 @@ protected: nsFrameState mState; + /** + * List of properties attached to the frame. + */ + FrameProperties mProperties; + // When there is an overflow area only slightly larger than mRect, // we store a set of four 1-byte deltas from the edges of mRect // rather than allocating a whole separate rectangle property. diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index 138d0b871..6a15a9cfa 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -819,11 +819,11 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, #endif if (mCurrentSpan == mRootSpan) { - pfd->mFrame->Properties().Remove(nsIFrame::LineBaselineOffset()); + pfd->mFrame->RemoveProperty(nsIFrame::LineBaselineOffset()); } else { #ifdef DEBUG bool hasLineOffset; - pfd->mFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &hasLineOffset); + pfd->mFrame->GetProperty(nsIFrame::LineBaselineOffset(), &hasLineOffset); NS_ASSERTION(!hasLineOffset, "LineBaselineOffset was set but was not expected"); #endif } diff --git a/layout/generic/nsPlaceholderFrame.cpp b/layout/generic/nsPlaceholderFrame.cpp index 2b6799f48..bd380a2d9 100644 --- a/layout/generic/nsPlaceholderFrame.cpp +++ b/layout/generic/nsPlaceholderFrame.cpp @@ -128,7 +128,7 @@ nsPlaceholderFrame::Reflow(nsPresContext* aPresContext, nsIFrame* ancestor = this; while ((ancestor = ancestor->GetParent())) { if (ancestor->GetPrevContinuation() || - ancestor->Properties().Get(IBSplitPrevSibling())) { + ancestor->GetProperty(IBSplitPrevSibling())) { isInContinuationOrIBSplit = true; break; } diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 3288d3f2e..0641c7439 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -2838,9 +2838,9 @@ nsTextFrame::EnsureTextRun(TextRunType aWhichTextRun, return gfxSkipCharsIterator(gfxPlatform:: GetPlatform()->EmptySkipChars(), 0); } - TabWidthStore* tabWidths = Properties().Get(TabWidthProperty()); + TabWidthStore* tabWidths = GetProperty(TabWidthProperty()); if (tabWidths && tabWidths->mValidForContentOffset != GetContentOffset()) { - Properties().Delete(TabWidthProperty()); + DeleteProperty(TabWidthProperty()); } } @@ -3478,7 +3478,7 @@ PropertyProvider::CalcTabWidths(Range aRange) return; } if (!mReflowing) { - mTabWidths = mFrame->Properties().Get(TabWidthProperty()); + mTabWidths = mFrame->GetProperty(TabWidthProperty()); #ifdef DEBUG // If we're not reflowing, we should have already computed the // tab widths; check that they're available as far as the last @@ -3524,7 +3524,7 @@ PropertyProvider::CalcTabWidths(Range aRange) } else { if (!mTabWidths) { mTabWidths = new TabWidthStore(mFrame->GetContentOffset()); - mFrame->Properties().Set(TabWidthProperty(), mTabWidths); + mFrame->SetProperty(TabWidthProperty(), mTabWidths); } double nextTab = AdvanceToNextTab(mOffsetFromBlockOriginForTabs, mFrame, mTextRun, &tabWidth); @@ -3543,7 +3543,7 @@ PropertyProvider::CalcTabWidths(Range aRange) if (!mTabWidths) { // Delete any stale property that may be left on the frame - mFrame->Properties().Delete(TabWidthProperty()); + mFrame->DeleteProperty(TabWidthProperty()); mTabWidthsAnalyzedLimit = std::max(mTabWidthsAnalyzedLimit, aRange.end - startOffset); } @@ -4249,7 +4249,7 @@ nsTextFrame::ClearFrameOffsetCache() // just destroys the frames in order, which means that the primary frame is already // dead if we're a continuing text frame, in which case, all of its properties are // gone, and we don't need to worry about deleting this property here. - primaryFrame->Properties().Delete(OffsetToFrameProperty()); + primaryFrame->DeleteProperty(OffsetToFrameProperty()); } RemoveStateBits(TEXT_IN_OFFSET_CACHE); } @@ -4358,7 +4358,7 @@ nsContinuingTextFrame::Init(nsIContent* aContent, if (aPrevInFlow->GetStateBits() & NS_FRAME_IS_BIDI) { FrameBidiData bidiData = aPrevInFlow->GetBidiData(); bidiData.precedingControl = kBidiLevelNone; - Properties().Set(BidiDataProperty(), bidiData); + SetProperty(BidiDataProperty(), bidiData); if (nextContinuation) { SetNextContinuation(nextContinuation); @@ -4622,7 +4622,7 @@ nsTextFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemK gfxTextRun* nsTextFrame::GetUninflatedTextRun() { - return Properties().Get(UninflatedTextRunProperty()); + return GetProperty(UninflatedTextRunProperty()); } void @@ -4648,7 +4648,7 @@ nsTextFrame::SetTextRun(gfxTextRun* aTextRun, TextRunType aWhichTextRun, // Setting the property will not automatically increment the textrun's // reference count, so we need to do it here. aTextRun->AddRef(); - Properties().Set(UninflatedTextRunProperty(), aTextRun); + SetProperty(UninflatedTextRunProperty(), aTextRun); return; } // fall through to setting mTextRun @@ -4668,10 +4668,9 @@ nsTextFrame::RemoveTextRun(gfxTextRun* aTextRun) mTextRun = nullptr; return true; } - FrameProperties props = Properties(); if ((GetStateBits() & TEXT_HAS_FONT_INFLATION) && - props.Get(UninflatedTextRunProperty()) == aTextRun) { - props.Delete(UninflatedTextRunProperty()); + GetProperty(UninflatedTextRunProperty()) == aTextRun) { + DeleteProperty(UninflatedTextRunProperty()); return true; } return false; @@ -4689,7 +4688,7 @@ nsTextFrame::ClearTextRun(nsTextFrame* aStartContinuation, DebugOnly<bool> checkmTextrun = textRun == mTextRun; UnhookTextRunFromFrames(textRun, aStartContinuation); MOZ_ASSERT(checkmTextrun ? !mTextRun - : !Properties().Get(UninflatedTextRunProperty())); + : !GetProperty(UninflatedTextRunProperty())); } void @@ -4699,7 +4698,7 @@ nsTextFrame::DisconnectTextRuns() "Textrun mentions this frame in its user data so we can't just disconnect"); mTextRun = nullptr; if ((GetStateBits() & TEXT_HAS_FONT_INFLATION)) { - Properties().Delete(UninflatedTextRunProperty()); + DeleteProperty(UninflatedTextRunProperty()); } } @@ -4929,7 +4928,7 @@ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(TextCombineScaleFactorProperty, float) static float GetTextCombineScaleFactor(nsTextFrame* aFrame) { - float factor = aFrame->Properties().Get(TextCombineScaleFactorProperty()); + float factor = aFrame->GetProperty(TextCombineScaleFactorProperty()); return factor ? factor : 1.0f; } @@ -5105,7 +5104,7 @@ static nscoord LazyGetLineBaselineOffset(nsIFrame* aChildFrame, nsBlockFrame* aBlockFrame) { bool offsetFound; - nscoord offset = aChildFrame->Properties().Get( + nscoord offset = aChildFrame->GetProperty( nsIFrame::LineBaselineOffset(), &offsetFound); if (!offsetFound) { @@ -5118,11 +5117,11 @@ LazyGetLineBaselineOffset(nsIFrame* aChildFrame, nsBlockFrame* aBlockFrame) for (nsIFrame* lineFrame = line->mFirstChild; n > 0; lineFrame = lineFrame->GetNextSibling(), --n) { offset = lineBaseline - lineFrame->GetNormalPosition().y; - lineFrame->Properties().Set(nsIFrame::LineBaselineOffset(), offset); + lineFrame->SetProperty(nsIFrame::LineBaselineOffset(), offset); } } } - return aChildFrame->Properties().Get( + return aChildFrame->GetProperty( nsIFrame::LineBaselineOffset(), &offsetFound); } else { return offset; @@ -5367,7 +5366,7 @@ nsTextFrame::UpdateTextEmphasis(WritingMode aWM, PropertyProvider& aProvider) { const nsStyleText* styleText = StyleText(); if (!styleText->HasTextEmphasis()) { - Properties().Delete(EmphasisMarkProperty()); + DeleteProperty(EmphasisMarkProperty()); return nsRect(); } @@ -5419,7 +5418,7 @@ nsTextFrame::UpdateTextEmphasis(WritingMode aWM, PropertyProvider& aProvider) overflowRect.BStart(aWM) += gap * (side == eLogicalSideBStart ? -1 : 1); } - Properties().Set(EmphasisMarkProperty(), info); + SetProperty(EmphasisMarkProperty(), info); return overflowRect.GetPhysicalRect(aWM, frameSize.GetPhysicalSize(aWM)); } @@ -6432,7 +6431,7 @@ nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM, const nscolor* aDecorationOverrideColor, PropertyProvider* aProvider) { - const EmphasisMarkInfo* info = Properties().Get(EmphasisMarkProperty()); + const EmphasisMarkInfo* info = GetProperty(EmphasisMarkProperty()); if (!info) { return; } @@ -7584,7 +7583,7 @@ nsTextFrame::GetChildFrameContainingOffset(int32_t aContentOffset, int32_t offset = mContentOffset; // Try to look up the offset to frame property - nsTextFrame* cachedFrame = Properties().Get(OffsetToFrameProperty()); + nsTextFrame* cachedFrame = GetProperty(OffsetToFrameProperty()); if (cachedFrame) { f = cachedFrame; @@ -7632,7 +7631,7 @@ nsTextFrame::GetChildFrameContainingOffset(int32_t aContentOffset, *aOutFrame = f; // cache the frame we found - Properties().Set(OffsetToFrameProperty(), f); + SetProperty(OffsetToFrameProperty(), f); f->AddStateBits(TEXT_IN_OFFSET_CACHE); return NS_OK; @@ -8169,7 +8168,7 @@ nsTextFrame::GetFontSizeInflation() const if (!HasFontSizeInflation()) { return 1.0f; } - return Properties().Get(FontSizeInflationProperty()); + return GetProperty(FontSizeInflationProperty()); } void @@ -8178,13 +8177,13 @@ nsTextFrame::SetFontSizeInflation(float aInflation) if (aInflation == 1.0f) { if (HasFontSizeInflation()) { RemoveStateBits(TEXT_HAS_FONT_INFLATION); - Properties().Delete(FontSizeInflationProperty()); + DeleteProperty(FontSizeInflationProperty()); } return; } AddStateBits(TEXT_HAS_FONT_INFLATION); - Properties().Set(FontSizeInflationProperty(), aInflation); + SetProperty(FontSizeInflationProperty(), aInflation); } /* virtual */ @@ -9319,9 +9318,9 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, gfxFloat em = fm->EmHeight(); // Compress the characters in horizontal axis if necessary. if (width <= em) { - Properties().Remove(TextCombineScaleFactorProperty()); + RemoveProperty(TextCombineScaleFactorProperty()); } else { - Properties().Set(TextCombineScaleFactorProperty(), em / width); + SetProperty(TextCombineScaleFactorProperty(), em / width); finalSize.ISize(wm) = em; } // Make the characters be in an 1em square. @@ -10049,13 +10048,13 @@ nsTextFrame::AssignJustificationGaps( static_assert(sizeof(aAssign) == 1, "The encoding might be broken if JustificationAssignment " "is larger than 1 byte"); - Properties().Set(JustificationAssignmentProperty(), encoded); + SetProperty(JustificationAssignmentProperty(), encoded); } mozilla::JustificationAssignment nsTextFrame::GetJustificationAssignment() const { - int32_t encoded = Properties().Get(JustificationAssignmentProperty()); + int32_t encoded = GetProperty(JustificationAssignmentProperty()); mozilla::JustificationAssignment result; result.mGapsAtStart = encoded >> 8; result.mGapsAtEnd = encoded & 0xFF; diff --git a/layout/mathml/nsMathMLContainerFrame.cpp b/layout/mathml/nsMathMLContainerFrame.cpp index ad1b13efd..93b631c9d 100644 --- a/layout/mathml/nsMathMLContainerFrame.cpp +++ b/layout/mathml/nsMathMLContainerFrame.cpp @@ -134,7 +134,7 @@ nsMathMLContainerFrame::SaveReflowAndBoundingMetricsFor(nsIFrame* { ReflowOutput* reflowOutput = new ReflowOutput(aReflowOutput); reflowOutput->mBoundingMetrics = aBoundingMetrics; - aFrame->Properties().Set(HTMLReflowOutputProperty(), reflowOutput); + aFrame->SetProperty(HTMLReflowOutputProperty(), reflowOutput); } // helper method to facilitate getting the reflow and bounding metrics @@ -147,7 +147,7 @@ nsMathMLContainerFrame::GetReflowAndBoundingMetricsFor(nsIFrame* aFra NS_PRECONDITION(aFrame, "null arg"); ReflowOutput* reflowOutput = - aFrame->Properties().Get(HTMLReflowOutputProperty()); + aFrame->GetProperty(HTMLReflowOutputProperty()); // IMPORTANT: This function is only meant to be called in Place() methods // where it is assumed that SaveReflowAndBoundingMetricsFor has recorded the @@ -175,9 +175,8 @@ void nsMathMLContainerFrame::ClearSavedChildMetrics() { nsIFrame* childFrame = mFrames.FirstChild(); - FramePropertyTable* props = PresContext()->PropertyTable(); while (childFrame) { - props->Delete(childFrame, HTMLReflowOutputProperty()); + childFrame->DeleteProperty(HTMLReflowOutputProperty()); childFrame = childFrame->GetNextSibling(); } } diff --git a/layout/mathml/nsMathMLmtableFrame.cpp b/layout/mathml/nsMathMLmtableFrame.cpp index a706fb483..fd184e637 100644 --- a/layout/mathml/nsMathMLmtableFrame.cpp +++ b/layout/mathml/nsMathMLmtableFrame.cpp @@ -167,8 +167,7 @@ FindCellProperty(const nsIFrame* aCellFrame, nsTArray<int8_t>* propertyData = nullptr; while (currentFrame) { - FrameProperties props = currentFrame->Properties(); - propertyData = props.Get(aFrameProperty); + propertyData = currentFrame->GetProperty(aFrameProperty); bool frameIsTable = (currentFrame->GetType() == nsGkAtoms::tableFrame); if (propertyData || frameIsTable) @@ -361,8 +360,7 @@ ParseFrameAttribute(nsIFrame* aFrame, if (valueList) { // The code reading the property assumes that this list is nonempty. NS_ASSERTION(valueList->Length() >= 1, "valueList should not be empty!"); - FrameProperties props = aFrame->Properties(); - props.Set(AttributeToProperty(aAttribute), valueList); + aFrame->SetProperty(AttributeToProperty(aAttribute), valueList); } else { ReportParseError(aFrame, aAttribute->GetUTF16String(), attrValue.get()); } @@ -769,8 +767,7 @@ nsMathMLmtableWrapperFrame::AttributeChanged(int32_t aNameSpaceID, aAttribute == nsGkAtoms::columnalign_ || aAttribute == nsGkAtoms::columnlines_) { // clear any cached property list for this table - presContext->PropertyTable()-> - Delete(tableFrame, AttributeToProperty(aAttribute)); + tableFrame->DeleteProperty(AttributeToProperty(aAttribute)); // Reparse the new attribute on the table. ParseFrameAttribute(tableFrame, aAttribute, true); } else { @@ -1120,7 +1117,7 @@ nsMathMLmtrFrame::AttributeChanged(int32_t aNameSpaceID, return NS_OK; } - presContext->PropertyTable()->Delete(this, AttributeToProperty(aAttribute)); + DeleteProperty(AttributeToProperty(aAttribute)); bool allowMultiValues = (aAttribute == nsGkAtoms::columnalign_); @@ -1219,8 +1216,7 @@ nsMathMLmtdFrame::AttributeChanged(int32_t aNameSpaceID, if (aAttribute == nsGkAtoms::rowalign_ || aAttribute == nsGkAtoms::columnalign_) { - nsPresContext* presContext = PresContext(); - presContext->PropertyTable()->Delete(this, AttributeToProperty(aAttribute)); + DeleteProperty(AttributeToProperty(aAttribute)); // Reparse the attribute. ParseFrameAttribute(this, aAttribute, false); diff --git a/layout/reftests/svg/css-transform-svg-ref.html b/layout/reftests/svg/css-transform-svg-ref.html new file mode 100644 index 000000000..6167442e7 --- /dev/null +++ b/layout/reftests/svg/css-transform-svg-ref.html @@ -0,0 +1,10 @@ +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<style> +</style> +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> + <rect id="a" x="0.49" y="0.51" width="2.5" height="2.5"/> + <rect id="b" x="3.5" y="3.5" width="2.5" height="2.5"/> +</svg> diff --git a/layout/reftests/svg/css-transform-svg.html b/layout/reftests/svg/css-transform-svg.html new file mode 100644 index 000000000..c1c63a839 --- /dev/null +++ b/layout/reftests/svg/css-transform-svg.html @@ -0,0 +1,13 @@ +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<style> +#a { + transform: scaleY(1); +} +</style> +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> + <rect id="a" x="0.49" y="0.51" width="2.5" height="2.5"/> + <rect id="b" x="3.5" y="3.5" width="2.5" height="2.5"/> +</svg> diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index 096628681..21e1c68a1 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -140,6 +140,7 @@ random == dynamic-use-nested-01b.svg dynamic-use-nested-01-ref.svg == fragmentIdentifier-01.xhtml pass.svg == linked-filter-01.svg pass.svg == linked-pattern-01.svg pass.svg +pref(layout.css.devPixelsPerPx,"1.0") == svg-blurry-with-subpixel-position.html svg-blurry-with-subpixel-position-ref.html == use-01.svg pass.svg == use-01-extref.svg pass.svg == use-02-extref.svg use-02-extref-ref.svg @@ -371,6 +372,7 @@ fuzzy-if(skiaContent,1,610) == textPath-03.svg pass.svg == text-white-space-01.svg text-white-space-01-ref.svg == thin-stroke-01.svg pass.svg == zero-stroke-01.svg pass.svg +== css-transform-svg.html css-transform-svg-ref.html == tspan-dxdy-01.svg tspan-dxdy-ref.svg == tspan-dxdy-02.svg tspan-dxdy-ref.svg == tspan-dxdy-03.svg tspan-dxdy-ref.svg diff --git a/layout/reftests/svg/svg-blurry-with-subpixel-position-ref.html b/layout/reftests/svg/svg-blurry-with-subpixel-position-ref.html new file mode 100644 index 000000000..c315509d7 --- /dev/null +++ b/layout/reftests/svg/svg-blurry-with-subpixel-position-ref.html @@ -0,0 +1,13 @@ +<!doctype html> +<style> + svg { + width:750px; + height:750px; + margin:3px; + } +</style> + +<svg viewBox="0.5 0.5 750 750"> + <path d="M3,6L277,6M3,12L277,12M3,18L277,18M3,24L277,24M3,30L277,30M3,36L277,36M3,42L277,42M3,48L277,48M3,54L277,54M3,60L277,60M3,66L277,66M3,72L277,72M3,78L277,78M3,84L277,84M3,90L277,90M3,96L277,96M3,102L277,102M3,108L277,108M3,114L277,114" style="stroke-width:1; stroke:black;" /> + <path d="M6,3L6,277M12,3L12,277M18,3L18,277M24,3L24,277M30,3L30,277M36,3L36,277M42,3L42,277M48,3L48,277M54,3L54,277M60,3L60,277M66,3L66,277M72,3L72,277M78,3L78,277M84,3L84,277M90,3L90,277M96,3L96,277M102,3L102,277M108,3L108,277M114,3L114,277" style="stroke-width:1; stroke:black;" /> +</svg> diff --git a/layout/reftests/svg/svg-blurry-with-subpixel-position.html b/layout/reftests/svg/svg-blurry-with-subpixel-position.html new file mode 100644 index 000000000..20bca7174 --- /dev/null +++ b/layout/reftests/svg/svg-blurry-with-subpixel-position.html @@ -0,0 +1,13 @@ +<!doctype html> +<style> + svg { + width:750px; + height:750px; + margin:2.5px; + } +</style> + +<svg viewBox="0.5 0.5 750 750"> + <path d="M3,6L277,6M3,12L277,12M3,18L277,18M3,24L277,24M3,30L277,30M3,36L277,36M3,42L277,42M3,48L277,48M3,54L277,54M3,60L277,60M3,66L277,66M3,72L277,72M3,78L277,78M3,84L277,84M3,90L277,90M3,96L277,96M3,102L277,102M3,108L277,108M3,114L277,114" style="stroke-width:1; stroke:black;" /> + <path d="M6,3L6,277M12,3L12,277M18,3L18,277M24,3L24,277M30,3L30,277M36,3L36,277M42,3L42,277M48,3L48,277M54,3L54,277M60,3L60,277M66,3L66,277M72,3L72,277M78,3L78,277M84,3L84,277M90,3L90,277M96,3L96,277M102,3L102,277M108,3L108,277M114,3L114,277" style="stroke-width:1; stroke:black;" /> +</svg> diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index 1645adfef..81c5ede0e 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -583,6 +583,19 @@ FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry, nsCOMPtr<nsIStreamLoader> streamLoader; nsCOMPtr<nsILoadGroup> loadGroup(mDocument->GetDocumentLoadGroup()); + // We're determining the security flags for font loading here based on + // scheme, because we want to allow fonts to be loaded using file: + // even if unique origins for file: access is enforced (allow CORS + // bypass in this case). + uint32_t securityFlags = 0; + bool isFile = false; + if (NS_SUCCEEDED(aFontFaceSrc->mURI->SchemeIs("file", &isFile)) && + isFile) { + securityFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS; + } else { + securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS; + } + nsCOMPtr<nsIChannel> channel; // Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a // node and a principal. This is because the document where the font is @@ -592,7 +605,7 @@ FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry, aFontFaceSrc->mURI, mDocument, aUserFontEntry->GetPrincipal(), - nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, + securityFlags, nsIContentPolicy::TYPE_FONT, loadGroup); NS_ENSURE_SUCCESS(rv, rv); diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp index e5a03333f..6ba267ee8 100644 --- a/layout/svg/SVGTextFrame.cpp +++ b/layout/svg/SVGTextFrame.cpp @@ -1328,7 +1328,7 @@ NS_DECLARE_FRAME_PROPERTY_DELETABLE(TextNodeCorrespondenceProperty, static uint32_t GetUndisplayedCharactersBeforeFrame(nsTextFrame* aFrame) { - void* value = aFrame->Properties().Get(TextNodeCorrespondenceProperty()); + void* value = aFrame->GetProperty(TextNodeCorrespondenceProperty()); TextNodeCorrespondence* correspondence = static_cast<TextNodeCorrespondence*>(value); if (!correspondence) { @@ -1517,8 +1517,8 @@ TextNodeCorrespondenceRecorder::TraverseAndRecord(nsIFrame* aFrame) } // Set the frame property. - frame->Properties().Set(TextNodeCorrespondenceProperty(), - new TextNodeCorrespondence(undisplayed)); + frame->SetProperty(TextNodeCorrespondenceProperty(), + new TextNodeCorrespondence(undisplayed)); // Remember how far into the current nsTextNode we are. mNodeCharIndex = frame->GetContentEnd(); @@ -3391,7 +3391,7 @@ SVGTextFrame::HandleAttributeChangeInDescendant(Element* aElement, // Blow away our reference, if any nsIFrame* childElementFrame = aElement->GetPrimaryFrame(); if (childElementFrame) { - childElementFrame->Properties().Delete( + childElementFrame->DeleteProperty( nsSVGEffects::HrefAsTextPathProperty()); NotifyGlyphMetricsChange(); } @@ -4817,7 +4817,7 @@ SVGPathElement* SVGTextFrame::GetTextPathPathElement(nsIFrame* aTextPathFrame) { nsSVGTextPathProperty *property = - aTextPathFrame->Properties().Get(nsSVGEffects::HrefAsTextPathProperty()); + aTextPathFrame->GetProperty(nsSVGEffects::HrefAsTextPathProperty()); if (!property) { nsIContent* content = aTextPathFrame->GetContent(); diff --git a/layout/svg/nsSVGEffects.cpp b/layout/svg/nsSVGEffects.cpp index e75c973c8..ca4c5778c 100644 --- a/layout/svg/nsSVGEffects.cpp +++ b/layout/svg/nsSVGEffects.cpp @@ -480,27 +480,26 @@ GetOrCreateFilterProperty(nsIFrame* aFrame) if (!effects->HasFilters()) return nullptr; - FrameProperties props = aFrame->Properties(); - nsSVGFilterProperty *prop = props.Get(nsSVGEffects::FilterProperty()); + nsSVGFilterProperty *prop = + aFrame->GetProperty(nsSVGEffects::FilterProperty()); if (prop) return prop; prop = new nsSVGFilterProperty(effects->mFilters, aFrame); NS_ADDREF(prop); - props.Set(nsSVGEffects::FilterProperty(), prop); + aFrame->SetProperty(nsSVGEffects::FilterProperty(), prop); return prop; } static nsSVGMaskProperty* GetOrCreateMaskProperty(nsIFrame* aFrame) { - FrameProperties props = aFrame->Properties(); - nsSVGMaskProperty *prop = props.Get(nsSVGEffects::MaskProperty()); + nsSVGMaskProperty *prop = aFrame->GetProperty(nsSVGEffects::MaskProperty()); if (prop) return prop; prop = new nsSVGMaskProperty(aFrame); NS_ADDREF(prop); - props.Set(nsSVGEffects::MaskProperty(), prop); + aFrame->SetProperty(nsSVGEffects::MaskProperty(), prop); return prop; } @@ -512,13 +511,12 @@ GetEffectProperty(nsIURI* aURI, nsIFrame* aFrame, if (!aURI) return nullptr; - FrameProperties props = aFrame->Properties(); - T* prop = props.Get(aProperty); + T* prop = aFrame->GetProperty(aProperty); if (prop) return prop; prop = new T(aURI, aFrame, false); NS_ADDREF(prop); - props.Set(aProperty, prop); + aFrame->SetProperty(aProperty, prop); return prop; } @@ -553,11 +551,11 @@ nsSVGEffects::GetPaintingPropertyForURI(nsIURI* aURI, nsIFrame* aFrame, if (!aURI) return nullptr; - FrameProperties props = aFrame->Properties(); - nsSVGEffects::URIObserverHashtable *hashtable = props.Get(aProperty); + nsSVGEffects::URIObserverHashtable *hashtable = + aFrame->GetProperty(aProperty); if (!hashtable) { hashtable = new nsSVGEffects::URIObserverHashtable(); - props.Set(aProperty, hashtable); + aFrame->SetProperty(aProperty, hashtable); } nsSVGPaintingProperty* prop = static_cast<nsSVGPaintingProperty*>(hashtable->GetWeak(aURI)); @@ -689,16 +687,15 @@ nsSVGEffects::UpdateEffects(nsIFrame* aFrame) NS_ASSERTION(aFrame->GetContent()->IsElement(), "aFrame's content should be an element"); - FrameProperties props = aFrame->Properties(); - props.Delete(FilterProperty()); - props.Delete(MaskProperty()); - props.Delete(ClipPathProperty()); - props.Delete(MarkerBeginProperty()); - props.Delete(MarkerMiddleProperty()); - props.Delete(MarkerEndProperty()); - props.Delete(FillProperty()); - props.Delete(StrokeProperty()); - props.Delete(BackgroundImageProperty()); + aFrame->DeleteProperty(FilterProperty()); + aFrame->DeleteProperty(MaskProperty()); + aFrame->DeleteProperty(ClipPathProperty()); + aFrame->DeleteProperty(MarkerBeginProperty()); + aFrame->DeleteProperty(MarkerMiddleProperty()); + aFrame->DeleteProperty(MarkerEndProperty()); + aFrame->DeleteProperty(FillProperty()); + aFrame->DeleteProperty(StrokeProperty()); + aFrame->DeleteProperty(BackgroundImageProperty()); // Ensure that the filter is repainted correctly // We can't do that in DoUpdate as the referenced frame may not be valid @@ -725,7 +722,7 @@ nsSVGEffects::GetFilterProperty(nsIFrame* aFrame) if (!aFrame->StyleEffects()->HasFilters()) return nullptr; - return aFrame->Properties().Get(FilterProperty()); + return aFrame->GetProperty(FilterProperty()); } void @@ -835,7 +832,7 @@ nsSVGEffects::InvalidateRenderingObservers(nsIFrame* aFrame) return; // If the rendering has changed, the bounds may well have changed too: - aFrame->Properties().Delete(nsSVGUtils::ObjectBoundingBoxProperty()); + aFrame->DeleteProperty(nsSVGUtils::ObjectBoundingBoxProperty()); nsSVGRenderingObserverList *observerList = GetObserverList(content->AsElement()); @@ -864,7 +861,7 @@ nsSVGEffects::InvalidateDirectRenderingObservers(Element* aElement, uint32_t aFl nsIFrame* frame = aElement->GetPrimaryFrame(); if (frame) { // If the rendering has changed, the bounds may well have changed too: - frame->Properties().Delete(nsSVGUtils::ObjectBoundingBoxProperty()); + frame->DeleteProperty(nsSVGUtils::ObjectBoundingBoxProperty()); } if (aElement->HasRenderingObservers()) { diff --git a/layout/svg/nsSVGEffects.h b/layout/svg/nsSVGEffects.h index 0cf9b1500..b8b2e53c1 100644 --- a/layout/svg/nsSVGEffects.h +++ b/layout/svg/nsSVGEffects.h @@ -7,7 +7,7 @@ #define NSSVGEFFECTS_H_ #include "mozilla/Attributes.h" -#include "FramePropertyTable.h" +#include "FrameProperties.h" #include "mozilla/dom/Element.h" #include "nsHashKeys.h" #include "nsID.h" diff --git a/layout/svg/nsSVGFilterFrame.cpp b/layout/svg/nsSVGFilterFrame.cpp index 13ce16993..3b99f413e 100644 --- a/layout/svg/nsSVGFilterFrame.cpp +++ b/layout/svg/nsSVGFilterFrame.cpp @@ -107,7 +107,7 @@ nsSVGFilterFrame::GetReferencedFilter() return nullptr; nsSVGPaintingProperty *property = - Properties().Get(nsSVGEffects::HrefAsPaintingProperty()); + GetProperty(nsSVGEffects::HrefAsPaintingProperty()); if (!property) { // Fetch our Filter element's href or xlink:href attribute @@ -183,7 +183,7 @@ nsSVGFilterFrame::AttributeChanged(int32_t aNameSpaceID, aNameSpaceID == kNameSpaceID_None) && aAttribute == nsGkAtoms::href) { // Blow away our reference, if any - Properties().Delete(nsSVGEffects::HrefAsPaintingProperty()); + DeleteProperty(nsSVGEffects::HrefAsPaintingProperty()); mNoHRefURI = false; // And update whoever references us nsSVGEffects::InvalidateDirectRenderingObservers(this); diff --git a/layout/svg/nsSVGGradientFrame.cpp b/layout/svg/nsSVGGradientFrame.cpp index 2d7684f5a..340cfa881 100644 --- a/layout/svg/nsSVGGradientFrame.cpp +++ b/layout/svg/nsSVGGradientFrame.cpp @@ -72,7 +72,7 @@ nsSVGGradientFrame::AttributeChanged(int32_t aNameSpaceID, aNameSpaceID == kNameSpaceID_None) && aAttribute == nsGkAtoms::href) { // Blow away our reference, if any - Properties().Delete(nsSVGEffects::HrefAsPaintingProperty()); + DeleteProperty(nsSVGEffects::HrefAsPaintingProperty()); mNoHRefURI = false; // And update whoever references us nsSVGEffects::InvalidateDirectRenderingObservers(this); @@ -316,7 +316,7 @@ nsSVGGradientFrame::GetReferencedGradient() return nullptr; nsSVGPaintingProperty *property = - Properties().Get(nsSVGEffects::HrefAsPaintingProperty()); + GetProperty(nsSVGEffects::HrefAsPaintingProperty()); if (!property) { // Fetch our gradient element's href or xlink:href attribute diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index 0003e1a73..4ce2941d4 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -75,7 +75,7 @@ public: private: static nsRect GetPreEffectsVisualOverflowRect(nsIFrame* aFrame) { - nsRect* r = aFrame->Properties().Get(nsIFrame::PreEffectsBBoxProperty()); + nsRect* r = aFrame->GetProperty(nsIFrame::PreEffectsBBoxProperty()); if (r) { return *r; } @@ -113,8 +113,7 @@ private: NS_ASSERTION(aFrame->GetParent()->StyleContext()->GetPseudo() == nsCSSAnonBoxes::mozAnonymousBlock, "How did we getting here, then?"); - NS_ASSERTION(!aFrame->Properties().Get( - aFrame->PreTransformOverflowAreasProperty()), + NS_ASSERTION(!aFrame->GetProperty(aFrame->PreTransformOverflowAreasProperty()), "GetVisualOverflowRect() won't return the pre-effects rect!"); return aFrame->GetVisualOverflowRect(); } diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp index e1b97bb40..b1ee54eb9 100644 --- a/layout/svg/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/nsSVGOuterSVGFrame.cpp @@ -979,43 +979,56 @@ nsSVGOuterSVGAnonChildFrame::GetType() const return nsGkAtoms::svgOuterSVGAnonChildFrame; } -bool -nsSVGOuterSVGAnonChildFrame::IsSVGTransformed(Matrix* aOwnTransform, - Matrix* aFromParentTransform) const +static Matrix +ComputeOuterSVGAnonChildFrameTransform(const nsSVGOuterSVGAnonChildFrame* aFrame) { // Our elements 'transform' attribute is applied to our nsSVGOuterSVGFrame // parent, and the element's children-only transforms are applied to us, the // anonymous child frame. Since we are the child frame, we apply the // children-only transforms as if they are our own transform. - SVGSVGElement* content = static_cast<SVGSVGElement*>(mContent); + SVGSVGElement* content = static_cast<SVGSVGElement*>(aFrame->GetContent()); if (!content->HasChildrenOnlyTransform()) { - return false; + return Matrix(); } // Outer-<svg> doesn't use x/y, so we can pass eChildToUserSpace here. gfxMatrix ownMatrix = content->PrependLocalTransformsTo(gfxMatrix(), eChildToUserSpace); - if (ownMatrix.IsIdentity()) { - return false; + if (ownMatrix.HasNonTranslation()) { + // viewBox, currentScale and currentTranslate should only produce a + // rectilinear transform. + MOZ_ASSERT(ownMatrix.IsRectilinear(), + "Non-rectilinear transform will break the following logic"); + + // The nsDisplayTransform code will apply this transform to our frame, + // including to our frame position. We don't want our frame position to + // be scaled though, so we need to correct for that in the transform. + CSSPoint pos = CSSPixel::FromAppUnits(aFrame->GetPosition()); + CSSPoint scaledPos = CSSPoint(ownMatrix._11 * pos.x, ownMatrix._22 * pos.y); + CSSPoint deltaPos = scaledPos - pos; + ownMatrix *= gfxMatrix::Translation(-deltaPos.x, -deltaPos.y); } - if (aOwnTransform) { - if (ownMatrix.HasNonTranslation()) { - // Note: viewBox, currentScale and currentTranslate should only - // produce a rectilinear transform. - // The nsDisplayTransform code will apply this transform to our frame, - // including to our frame position. We don't want our frame position to - // be scaled though, so we need to correct for that in the transform. - CSSPoint pos = CSSPixel::FromAppUnits(GetPosition()); - CSSPoint scaledPos = CSSPoint(ownMatrix._11 * pos.x, ownMatrix._22 * pos.y); - CSSPoint deltaPos = scaledPos - pos; - ownMatrix *= gfxMatrix::Translation(-deltaPos.x, -deltaPos.y); - } + return gfx::ToMatrix(ownMatrix); +} - *aOwnTransform = gfx::ToMatrix(ownMatrix); +// We want this frame to be a reference frame. An easy way to achieve that is +// to always return true from this method, even for identity transforms. +// This frame being a reference frame ensures that the offset between this +// <svg> element and the parent reference frame is completely absorbed by the +// nsDisplayTransform that's created for this frame, and that this offset does +// not affect our descendants' transforms. Consequently, if the <svg> element +// moves, e.g. during scrolling, the transform matrices of our contents are +// unaffected. This simplifies invalidation. +bool +nsSVGOuterSVGAnonChildFrame::IsSVGTransformed(Matrix* aOwnTransform, + Matrix* aFromParentTransform) const +{ + if (aOwnTransform) { + *aOwnTransform = ComputeOuterSVGAnonChildFrameTransform(this); } return true; diff --git a/layout/svg/nsSVGPatternFrame.cpp b/layout/svg/nsSVGPatternFrame.cpp index 198163d7f..2cd7eeaad 100644 --- a/layout/svg/nsSVGPatternFrame.cpp +++ b/layout/svg/nsSVGPatternFrame.cpp @@ -89,7 +89,7 @@ nsSVGPatternFrame::AttributeChanged(int32_t aNameSpaceID, aNameSpaceID == kNameSpaceID_None) && aAttribute == nsGkAtoms::href) { // Blow away our reference, if any - Properties().Delete(nsSVGEffects::HrefAsPaintingProperty()); + DeleteProperty(nsSVGEffects::HrefAsPaintingProperty()); mNoHRefURI = false; // And update whoever references us nsSVGEffects::InvalidateDirectRenderingObservers(this); @@ -548,7 +548,7 @@ nsSVGPatternFrame::GetReferencedPattern() return nullptr; nsSVGPaintingProperty *property = - Properties().Get(nsSVGEffects::HrefAsPaintingProperty()); + GetProperty(nsSVGEffects::HrefAsPaintingProperty()); if (!property) { // Fetch our pattern element's href or xlink:href attribute diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index 98e5f9b5f..c3394e292 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -1060,10 +1060,9 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags) return bbox; } - FrameProperties props = aFrame->Properties(); if (aFlags == eBBoxIncludeFillGeometry) { - gfxRect* prop = props.Get(ObjectBoundingBoxProperty()); + gfxRect* prop = aFrame->GetProperty(ObjectBoundingBoxProperty()); if (prop) { return *prop; } @@ -1139,7 +1138,7 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags) if (aFlags == eBBoxIncludeFillGeometry) { // Obtaining the bbox for objectBoundingBox calculations is common so we // cache the result for future calls, since calculation can be expensive: - props.Set(ObjectBoundingBoxProperty(), new gfxRect(bbox)); + aFrame->SetProperty(ObjectBoundingBoxProperty(), new gfxRect(bbox)); } return bbox; diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 4c11d2704..b9b6ca5fe 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -272,13 +272,12 @@ nsTableFrame::RegisterPositionedTablePart(nsIFrame* aFrame) tableFrame = static_cast<nsTableFrame*>(tableFrame->FirstContinuation()); // Retrieve the positioned parts array for this table. - FrameProperties props = tableFrame->Properties(); - FrameTArray* positionedParts = props.Get(PositionedTablePartArray()); + FrameTArray* positionedParts = tableFrame->GetProperty(PositionedTablePartArray()); // Lazily create the array if it doesn't exist yet. if (!positionedParts) { positionedParts = new FrameTArray; - props.Set(PositionedTablePartArray(), positionedParts); + tableFrame->SetProperty(PositionedTablePartArray(), positionedParts); } // Add this frame to the list. @@ -302,8 +301,7 @@ nsTableFrame::UnregisterPositionedTablePart(nsIFrame* aFrame, tableFrame = static_cast<nsTableFrame*>(tableFrame->FirstContinuation()); // Retrieve the positioned parts array for this table. - FrameProperties props = tableFrame->Properties(); - FrameTArray* positionedParts = props.Get(PositionedTablePartArray()); + FrameTArray* positionedParts = tableFrame->GetProperty(PositionedTablePartArray()); // Remove the frame. MOZ_ASSERT(positionedParts && positionedParts->Contains(aFrame), @@ -1992,7 +1990,7 @@ nsTableFrame::FixupPositionedTableParts(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput) { - FrameTArray* positionedParts = Properties().Get(PositionedTablePartArray()); + FrameTArray* positionedParts = GetProperty(PositionedTablePartArray()); if (!positionedParts) { return; } @@ -2653,13 +2651,18 @@ nsTableFrame::GetUsedMargin() const NS_DECLARE_FRAME_PROPERTY_DELETABLE(TableBCProperty, BCPropertyData) BCPropertyData* -nsTableFrame::GetBCProperty(bool aCreateIfNecessary) const +nsTableFrame::GetBCProperty() const { - FrameProperties props = Properties(); - BCPropertyData* value = props.Get(TableBCProperty()); - if (!value && aCreateIfNecessary) { + return GetProperty(TableBCProperty()); +} + +BCPropertyData* +nsTableFrame::GetOrCreateBCProperty() +{ + BCPropertyData* value = GetProperty(TableBCProperty()); + if (!value) { value = new BCPropertyData(); - props.Set(TableBCProperty(), value); + SetProperty(TableBCProperty(), value); } return value; @@ -4103,7 +4106,7 @@ nsTableFrame::AddBCDamageArea(const TableArea& aValue) SetNeedToCalcBCBorders(true); // Get the property - BCPropertyData* value = GetBCProperty(true); + BCPropertyData* value = GetOrCreateBCProperty(); if (value) { #ifdef DEBUG VerifyNonNegativeDamageRect(value->mDamageArea); @@ -4143,7 +4146,7 @@ nsTableFrame::SetFullBCDamageArea() SetNeedToCalcBCBorders(true); - BCPropertyData* value = GetBCProperty(true); + BCPropertyData* value = GetOrCreateBCProperty(); if (value) { value->mDamageArea = TableArea(0, 0, GetColCount(), GetRowCount()); } @@ -4310,7 +4313,7 @@ BCMapCellInfo::BCMapCellInfo(nsTableFrame* aTableFrame) : mTableFrame(aTableFrame) , mNumTableRows(aTableFrame->GetRowCount()) , mNumTableCols(aTableFrame->GetColCount()) - , mTableBCData(mTableFrame->Properties().Get(TableBCProperty())) + , mTableBCData(mTableFrame->GetProperty(TableBCProperty())) , mTableWM(aTableFrame->StyleContext()) { ResetCellInfo(); diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index a78625339..7e56c28c1 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -809,7 +809,8 @@ protected: void SetBorderCollapse(bool aValue); - BCPropertyData* GetBCProperty(bool aCreateIfNecessary = false) const; + BCPropertyData* GetBCProperty() const; + BCPropertyData* GetOrCreateBCProperty(); void SetFullBCDamageArea(); void CalcBCBorders(); diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index 81b5d6699..1b6051ef2 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -978,7 +978,7 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, // MovePositionBy does internally. (This codepath should really // be merged into the else below if we can.) nsMargin* computedOffsetProp = - kidFrame->Properties().Get(nsIFrame::ComputedOffsetProperty()); + kidFrame->GetProperty(nsIFrame::ComputedOffsetProperty()); // Bug 975644: a position:sticky kid can end up with a null // property value here. LogicalMargin computedOffsets(wm, computedOffsetProp ? @@ -1417,16 +1417,14 @@ nsTableRowFrame::SetUnpaginatedBSize(nsPresContext* aPresContext, nscoord aValue) { NS_ASSERTION(!GetPrevInFlow(), "program error"); - // Get the property - aPresContext->PropertyTable()-> - Set(this, RowUnpaginatedHeightProperty(), aValue); + // Set the property + SetProperty(RowUnpaginatedHeightProperty(), aValue); } nscoord nsTableRowFrame::GetUnpaginatedBSize() { - FrameProperties props = FirstInFlow()->Properties(); - return props.Get(RowUnpaginatedHeightProperty()); + return GetProperty(RowUnpaginatedHeightProperty()); } void nsTableRowFrame::SetContinuousBCBorderWidth(LogicalSide aForSide, diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 60596f12b..8f014b204 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -1910,7 +1910,7 @@ nsTableRowGroupFrame::ClearRowCursor() } RemoveStateBits(NS_ROWGROUP_HAS_ROW_CURSOR); - Properties().Delete(RowCursorProperty()); + DeleteProperty(RowCursorProperty()); } nsTableRowGroupFrame::FrameCursorData* @@ -1934,7 +1934,7 @@ nsTableRowGroupFrame::SetupRowCursor() FrameCursorData* data = new FrameCursorData(); if (!data) return nullptr; - Properties().Set(RowCursorProperty(), data); + SetProperty(RowCursorProperty(), data); AddStateBits(NS_ROWGROUP_HAS_ROW_CURSOR); return data; } @@ -1946,7 +1946,7 @@ nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove) return nullptr; } - FrameCursorData* property = Properties().Get(RowCursorProperty()); + FrameCursorData* property = GetProperty(RowCursorProperty()); uint32_t cursorIndex = property->mCursorIndex; uint32_t frameCount = property->mFrames.Length(); if (cursorIndex >= frameCount) diff --git a/layout/tables/nsTableWrapperFrame.cpp b/layout/tables/nsTableWrapperFrame.cpp index e44652a73..f0b6d1512 100644 --- a/layout/tables/nsTableWrapperFrame.cpp +++ b/layout/tables/nsTableWrapperFrame.cpp @@ -246,7 +246,7 @@ nsTableWrapperFrame::InitChildReflowInput(nsPresContext& aPresContext, } // Propagate our stored CB size if present, minus any margins. if (!HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) { - LogicalSize* cb = Properties().Get(GridItemCBSizeProperty()); + LogicalSize* cb = GetProperty(GridItemCBSizeProperty()); if (cb) { cbSize.emplace(*cb); *cbSize -= aReflowInput.ComputedLogicalMargin().Size(wm); @@ -953,7 +953,7 @@ nsTableWrapperFrame::Reflow(nsPresContext* aPresContext, // for the table frame if we are bsize constrained and the caption is above // or below the inner table. Also reduce the CB size that we store for // our children in case we're a grid item, by the same amount. - LogicalSize* cbSize = Properties().Get(GridItemCBSizeProperty()); + LogicalSize* cbSize = GetProperty(GridItemCBSizeProperty()); if (NS_UNCONSTRAINEDSIZE != aOuterRI.AvailableBSize() || cbSize) { nscoord captionBSize = 0; nscoord captionISize = 0; diff --git a/layout/xul/nsBox.cpp b/layout/xul/nsBox.cpp index f7ec5fead..787758b15 100644 --- a/layout/xul/nsBox.cpp +++ b/layout/xul/nsBox.cpp @@ -144,10 +144,9 @@ nsBox::BeginXULLayout(nsBoxLayoutState& aState) // Another copy-over from ReflowInput. // Since we are in reflow, we don't need to store these properties anymore. - FrameProperties props = Properties(); - props.Delete(UsedBorderProperty()); - props.Delete(UsedPaddingProperty()); - props.Delete(UsedMarginProperty()); + DeleteProperty(UsedBorderProperty()); + DeleteProperty(UsedPaddingProperty()); + DeleteProperty(UsedMarginProperty()); #ifdef DEBUG_LAYOUT PropagateDebug(aState); diff --git a/layout/xul/nsMenuFrame.cpp b/layout/xul/nsMenuFrame.cpp index ea968fab5..67fcdbe43 100644 --- a/layout/xul/nsMenuFrame.cpp +++ b/layout/xul/nsMenuFrame.cpp @@ -273,7 +273,7 @@ nsMenuFrame::GetPopupList() const if (!HasPopup()) { return nullptr; } - nsFrameList* prop = Properties().Get(PopupListProperty()); + nsFrameList* prop = GetProperty(PopupListProperty()); NS_ASSERTION(prop && prop->GetLength() == 1 && prop->FirstChild()->GetType() == nsGkAtoms::menuPopupFrame, "popup list should have exactly one nsMenuPopupFrame"); @@ -284,7 +284,7 @@ void nsMenuFrame::DestroyPopupList() { NS_ASSERTION(HasPopup(), "huh?"); - nsFrameList* prop = Properties().Remove(PopupListProperty()); + nsFrameList* prop = RemoveProperty(PopupListProperty()); NS_ASSERTION(prop && prop->IsEmpty(), "popup list must exist and be empty when destroying"); RemoveStateBits(NS_STATE_MENU_HAS_POPUP_LIST); @@ -300,7 +300,7 @@ nsMenuFrame::SetPopupFrame(nsFrameList& aFrameList) // Remove the frame from the list and store it in a nsFrameList* property. aFrameList.RemoveFrame(popupFrame); nsFrameList* popupList = new (PresContext()->PresShell()) nsFrameList(popupFrame, popupFrame); - Properties().Set(PopupListProperty(), popupList); + SetProperty(PopupListProperty(), popupList); AddStateBits(NS_STATE_MENU_HAS_POPUP_LIST); break; } diff --git a/media/libnestegg/include/nestegg.h b/media/libnestegg/include/nestegg.h index 2baa50bc5..2a9f08f5d 100644 --- a/media/libnestegg/include/nestegg.h +++ b/media/libnestegg/include/nestegg.h @@ -72,6 +72,8 @@ extern "C" { #define NESTEGG_CODEC_VP9 2 /**< Track uses Google On2 VP9 codec. */ #define NESTEGG_CODEC_OPUS 3 /**< Track uses Xiph Opus codec. */ #define NESTEGG_CODEC_AV1 4 /**< Track uses AOMedia AV1 codec. */ +#define NESTEGG_CODEC_AVC1 5 /**< Track uses AVC1 'h264' */ +#define NESTEGG_CODEC_AAC 6 /**< Track uses AAC 'mp4a' */ #define NESTEGG_CODEC_UNKNOWN INT_MAX /**< Track uses unknown codec. */ #define NESTEGG_VIDEO_MONO 0 /**< Track is mono video. */ diff --git a/media/libnestegg/src/nestegg.c b/media/libnestegg/src/nestegg.c index 61c30ec6b..051bc50fa 100644 --- a/media/libnestegg/src/nestegg.c +++ b/media/libnestegg/src/nestegg.c @@ -157,6 +157,8 @@ enum ebml_type_enum { #define TRACK_ID_AV1 "V_AV1" #define TRACK_ID_VORBIS "A_VORBIS" #define TRACK_ID_OPUS "A_OPUS" +#define TRACK_ID_AVC1 "V_MPEG4/ISO/AVC" +#define TRACK_ID_AAC "A_AAC" /* Track Encryption */ #define CONTENT_ENC_ALGO_AES 5 @@ -2401,6 +2403,12 @@ nestegg_track_codec_id(nestegg * ctx, unsigned int track) if (strcmp(codec_id, TRACK_ID_OPUS) == 0) return NESTEGG_CODEC_OPUS; + if (strcmp(codec_id, TRACK_ID_AVC1) == 0) + return NESTEGG_CODEC_AVC1; + + if (strcmp(codec_id, TRACK_ID_AAC) == 0) + return NESTEGG_CODEC_AAC; + return NESTEGG_CODEC_UNKNOWN; } @@ -2421,7 +2429,8 @@ nestegg_track_codec_data_count(nestegg * ctx, unsigned int track, codec_id = nestegg_track_codec_id(ctx, track); - if (codec_id == NESTEGG_CODEC_OPUS) { + if (codec_id == NESTEGG_CODEC_OPUS || + codec_id == NESTEGG_CODEC_AAC) { *count = 1; return 0; } @@ -2459,7 +2468,9 @@ nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item, return -1; if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS && - nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS) + nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS && + nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_AVC1 && + nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_AAC) return -1; if (ne_get_binary(entry->codec_private, &codec_private) != 0) @@ -2772,6 +2783,19 @@ nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt) if (r != 1) return r; + /* Some files have a crc32 element, since it also has to be first it + conflicts with the timecode spec. Just ignore it */ + if (id == ID_CRC32) { + ctx->log(ctx, NESTEGG_LOG_DEBUG, + "read_packet: skipping crc element in a cluster"); + r = ne_io_read_skip(ctx->io, size); + if (r != 1) + return r; + r = ne_read_element(ctx, &id, &size); + if (r != 1) + return r; + } + /* Timecode must be the first element in a Cluster, per spec. */ if (id != ID_TIMECODE) return -1; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index cd4284a9e..e69a985ce 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4012,6 +4012,12 @@ pref("autocomplete.ungrab_during_mode_switch", true); // toggling to use the XUL filepicker pref("ui.allow_platform_file_picker", true); +// Allow for using the native GTK file picker. If the application is not run +// with GTK_USE_PORTAL=1 this pref has no effect. +#ifdef MOZ_WIDGET_GTK +pref("widget.allow-gtk-native-file-chooser", false); +#endif + pref("helpers.global_mime_types_file", "/etc/mime.types"); pref("helpers.global_mailcap_file", "/etc/mailcap"); pref("helpers.private_mime_types_file", "~/.mime.types"); diff --git a/netwerk/base/nsIBrowserSearchService.idl b/netwerk/base/nsIBrowserSearchService.idl index 045973e0c..4ca052e91 100644 --- a/netwerk/base/nsIBrowserSearchService.idl +++ b/netwerk/base/nsIBrowserSearchService.idl @@ -7,7 +7,7 @@ interface nsIURI; interface nsIInputStream; -[scriptable, uuid(5799251f-5b55-4df7-a9e7-0c27812c469a)] +[scriptable, uuid(72599f7a-3712-4b93-90e9-86127006cd68)] interface nsISearchSubmission : nsISupports { /** @@ -20,6 +20,12 @@ interface nsISearchSubmission : nsISupports * The URI to submit a search to. */ readonly attribute nsIURI uri; + + /** + * The POST data associated with a search submission as an + * application/x-www-form-urlencoded string. May be null. + */ + readonly attribute AString postDataString; }; [scriptable, uuid(620bd920-0491-48c8-99a8-d6047e64802d)] diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index b9355c82b..70035be28 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -907,6 +907,9 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, NS_ENSURE_SUCCESS(rv, rv); } + // TODO: Bug 1353683 + // consider calling SetBlockedRequest in nsCORSListenerProxy::UpdateChannel + // // Check that the uri is ok to load rv = nsContentUtils::GetSecurityManager()-> CheckLoadURIWithPrincipal(mRequestingPrincipal, uri, diff --git a/old-configure.in b/old-configure.in index 3895128ae..1525ecc9b 100644 --- a/old-configure.in +++ b/old-configure.in @@ -5099,13 +5099,13 @@ MOZ_ARG_WITH_STRING(macbundlename-prefix, Prefix for MOZ_MACBUNDLE_NAME], [ MOZ_MACBUNDLE_NAME_PREFIX="$withval"]) -MOZ_MACBUNDLE_NAME=`echo $MOZ_APP_DISPLAYNAME | tr -d ' '` +MOZ_MACBUNDLE_NAME=$MOZ_APP_DISPLAYNAME if test "$MOZ_MACBUNDLE_NAME_PREFIX"; then - MOZ_MACBUNDLE_NAME="${MOZ_MACBUNDLE_NAME_PREFIX}${MOZ_MACBUNDLE_NAME}" + MOZ_MACBUNDLE_NAME="${MOZ_MACBUNDLE_NAME_PREFIX} ${MOZ_MACBUNDLE_NAME}" fi if test "$MOZ_DEBUG"; then - MOZ_MACBUNDLE_NAME=${MOZ_MACBUNDLE_NAME}Debug.app + MOZ_MACBUNDLE_NAME="${MOZ_MACBUNDLE_NAME}Debug.app" else MOZ_MACBUNDLE_NAME=${MOZ_MACBUNDLE_NAME}.app fi @@ -5483,10 +5483,6 @@ if test "$ACCESSIBILITY" -a "$MOZ_ENABLE_GTK" ; then AC_DEFINE_UNQUOTED(ATK_REV_VERSION, $ATK_REV_VERSION) fi -if test -n "$MOZ_DEV_EDITION"; then - AC_DEFINE(MOZ_DEV_EDITION) -fi - if test "$MOZ_DEBUG"; then A11Y_LOG=1 fi diff --git a/parser/html/moz.build b/parser/html/moz.build index 4a2da8a79..cd6031abe 100644 --- a/parser/html/moz.build +++ b/parser/html/moz.build @@ -39,6 +39,7 @@ EXPORTS += [ 'nsHtml5SpeculativeLoad.h', 'nsHtml5StreamListener.h', 'nsHtml5StreamParser.h', + 'nsHtml5String.h', 'nsHtml5StringParser.h', 'nsHtml5SVGLoadDispatcher.h', 'nsHtml5TreeOperation.h', @@ -78,6 +79,7 @@ UNIFIED_SOURCES += [ 'nsHtml5StateSnapshot.cpp', 'nsHtml5StreamListener.cpp', 'nsHtml5StreamParser.cpp', + 'nsHtml5String.cpp', 'nsHtml5StringParser.cpp', 'nsHtml5SVGLoadDispatcher.cpp', 'nsHtml5Tokenizer.cpp', diff --git a/parser/html/nsHtml5ArrayCopy.h b/parser/html/nsHtml5ArrayCopy.h index 78ed65568..594a801ab 100644 --- a/parser/html/nsHtml5ArrayCopy.h +++ b/parser/html/nsHtml5ArrayCopy.h @@ -51,10 +51,11 @@ class nsHtml5ArrayCopy { memcpy(target, source, size_t(length) * sizeof(int32_t)); } - static inline void - arraycopy(nsString** source, nsString** target, int32_t length) + static inline void arraycopy(nsHtml5String* source, + nsHtml5String* target, + int32_t length) { - memcpy(target, source, size_t(length) * sizeof(nsString*)); + memcpy(target, source, size_t(length) * sizeof(nsHtml5String)); } static inline void diff --git a/parser/html/nsHtml5AttributeName.cpp b/parser/html/nsHtml5AttributeName.cpp index fc7745adc..dc546c111 100644 --- a/parser/html/nsHtml5AttributeName.cpp +++ b/parser/html/nsHtml5AttributeName.cpp @@ -29,7 +29,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" diff --git a/parser/html/nsHtml5AttributeName.h b/parser/html/nsHtml5AttributeName.h index 748dcf3c9..d0b93341b 100644 --- a/parser/html/nsHtml5AttributeName.h +++ b/parser/html/nsHtml5AttributeName.h @@ -30,7 +30,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" diff --git a/parser/html/nsHtml5ElementName.cpp b/parser/html/nsHtml5ElementName.cpp index 1aa6f11ce..fb523e7ef 100644 --- a/parser/html/nsHtml5ElementName.cpp +++ b/parser/html/nsHtml5ElementName.cpp @@ -29,7 +29,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" diff --git a/parser/html/nsHtml5ElementName.h b/parser/html/nsHtml5ElementName.h index b4df323a6..b5f0e4b9b 100644 --- a/parser/html/nsHtml5ElementName.h +++ b/parser/html/nsHtml5ElementName.h @@ -30,7 +30,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" diff --git a/parser/html/nsHtml5Highlighter.cpp b/parser/html/nsHtml5Highlighter.cpp index 259803ee1..23cdf7d84 100644 --- a/parser/html/nsHtml5Highlighter.cpp +++ b/parser/html/nsHtml5Highlighter.cpp @@ -91,7 +91,7 @@ nsHtml5Highlighter::Start(const nsAutoString& aTitle) if (length > INT32_MAX) { length = INT32_MAX; } - AppendCharacters(aTitle.get(), 0, (int32_t)length); + AppendCharacters(aTitle.BeginReading(), 0, (int32_t)length); Pop(); // title Push(nsGkAtoms::link, nsHtml5ViewSourceUtils::NewLinkAttributes()); @@ -105,7 +105,7 @@ nsHtml5Highlighter::Start(const nsAutoString& aTitle) Push(nsGkAtoms::body, nsHtml5ViewSourceUtils::NewBodyAttributes()); nsHtml5HtmlAttributes* preAttrs = new nsHtml5HtmlAttributes(0); - nsString* preId = new nsString(NS_LITERAL_STRING("line1")); + nsHtml5String preId = nsHtml5Portability::newStringFromLiteral("line1"); preAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, preId, -1); Push(nsGkAtoms::pre, preAttrs); @@ -618,7 +618,7 @@ nsHtml5Highlighter::FlushOps() void nsHtml5Highlighter::MaybeLinkifyAttributeValue(nsHtml5AttributeName* aName, - nsString* aValue) + nsHtml5String aValue) { if (!(nsHtml5AttributeName::ATTR_HREF == aName || nsHtml5AttributeName::ATTR_SRC == aName || @@ -630,7 +630,7 @@ nsHtml5Highlighter::MaybeLinkifyAttributeValue(nsHtml5AttributeName* aName, nsHtml5AttributeName::ATTR_DEFINITIONURL == aName)) { return; } - AddViewSourceHref(*aValue); + AddViewSourceHref(aValue); } void @@ -717,10 +717,10 @@ nsHtml5Highlighter::AddClass(const char16_t* aClass) } void -nsHtml5Highlighter::AddViewSourceHref(const nsString& aValue) +nsHtml5Highlighter::AddViewSourceHref(nsHtml5String aValue) { char16_t* bufferCopy = new char16_t[aValue.Length() + 1]; - memcpy(bufferCopy, aValue.get(), aValue.Length() * sizeof(char16_t)); + aValue.CopyToBuffer(bufferCopy); bufferCopy[aValue.Length()] = 0; mOpQueue.AppendElement()->Init(eTreeOpAddViewSourceHref, @@ -730,14 +730,14 @@ nsHtml5Highlighter::AddViewSourceHref(const nsString& aValue) } void -nsHtml5Highlighter::AddBase(const nsString& aValue) +nsHtml5Highlighter::AddBase(nsHtml5String aValue) { if(mSeenBase) { return; } mSeenBase = true; char16_t* bufferCopy = new char16_t[aValue.Length() + 1]; - memcpy(bufferCopy, aValue.get(), aValue.Length() * sizeof(char16_t)); + aValue.CopyToBuffer(bufferCopy); bufferCopy[aValue.Length()] = 0; mOpQueue.AppendElement()->Init(eTreeOpAddViewSourceBase, diff --git a/parser/html/nsHtml5Highlighter.h b/parser/html/nsHtml5Highlighter.h index e9474869e..366f11582 100644 --- a/parser/html/nsHtml5Highlighter.h +++ b/parser/html/nsHtml5Highlighter.h @@ -78,7 +78,7 @@ class nsHtml5Highlighter * @param aValue the value of the attribute */ void MaybeLinkifyAttributeValue(nsHtml5AttributeName* aName, - nsString* aValue); + nsHtml5String aValue); /** * Inform the highlighter that the tokenizer successfully completed a @@ -147,7 +147,7 @@ class nsHtml5Highlighter * * @param aValue the base URL to add */ - void AddBase(const nsString& aValue); + void AddBase(nsHtml5String aValue); private: @@ -272,7 +272,7 @@ class nsHtml5Highlighter * * @param aValue the (potentially relative) URL to link to */ - void AddViewSourceHref(const nsString& aValue); + void AddViewSourceHref(nsHtml5String aValue); /** * The state we are transitioning away from. diff --git a/parser/html/nsHtml5HtmlAttributes.cpp b/parser/html/nsHtml5HtmlAttributes.cpp index d515f381d..62b9ae2b2 100644 --- a/parser/html/nsHtml5HtmlAttributes.cpp +++ b/parser/html/nsHtml5HtmlAttributes.cpp @@ -30,7 +30,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" @@ -58,11 +58,11 @@ nsHtml5HtmlAttributes* nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES = nullptr; nsHtml5HtmlAttributes::nsHtml5HtmlAttributes(int32_t mode) - : mode(mode), - length(0), - names(jArray<nsHtml5AttributeName*,int32_t>::newJArray(8)), - values(jArray<nsString*,int32_t>::newJArray(8)), - lines(jArray<int32_t,int32_t>::newJArray(8)) + : mode(mode) + , length(0) + , names(jArray<nsHtml5AttributeName*, int32_t>::newJArray(8)) + , values(jArray<nsHtml5String, int32_t>::newJArray(8)) + , lines(jArray<int32_t, int32_t>::newJArray(8)) { MOZ_COUNT_CTOR(nsHtml5HtmlAttributes); } @@ -85,7 +85,7 @@ nsHtml5HtmlAttributes::getIndex(nsHtml5AttributeName* name) return -1; } -nsString* +nsHtml5String nsHtml5HtmlAttributes::getValue(nsHtml5AttributeName* name) { int32_t index = getIndex(name); @@ -123,7 +123,7 @@ nsHtml5HtmlAttributes::getPrefixNoBoundsCheck(int32_t index) return names[index]->getPrefix(mode); } -nsString* +nsHtml5String nsHtml5HtmlAttributes::getValueNoBoundsCheck(int32_t index) { MOZ_ASSERT(index < length && index >= 0, "Index out of bounds"); @@ -145,14 +145,17 @@ nsHtml5HtmlAttributes::getLineNoBoundsCheck(int32_t index) } void -nsHtml5HtmlAttributes::addAttribute(nsHtml5AttributeName* name, nsString* value, int32_t line) +nsHtml5HtmlAttributes::addAttribute(nsHtml5AttributeName* name, + nsHtml5String value, + int32_t line) { if (names.length == length) { int32_t newLen = length << 1; jArray<nsHtml5AttributeName*,int32_t> newNames = jArray<nsHtml5AttributeName*,int32_t>::newJArray(newLen); nsHtml5ArrayCopy::arraycopy(names, newNames, names.length); names = newNames; - jArray<nsString*,int32_t> newValues = jArray<nsString*,int32_t>::newJArray(newLen); + jArray<nsHtml5String, int32_t> newValues = + jArray<nsHtml5String, int32_t>::newJArray(newLen); nsHtml5ArrayCopy::arraycopy(values, newValues, values.length); values = newValues; jArray<int32_t,int32_t> newLines = jArray<int32_t,int32_t>::newJArray(newLen); @@ -171,7 +174,7 @@ nsHtml5HtmlAttributes::clear(int32_t m) for (int32_t i = 0; i < length; i++) { names[i]->release(); names[i] = nullptr; - nsHtml5Portability::releaseString(values[i]); + values[i].Release(); values[i] = nullptr; } length = 0; @@ -181,7 +184,7 @@ nsHtml5HtmlAttributes::clear(int32_t m) void nsHtml5HtmlAttributes::releaseValue(int32_t i) { - nsHtml5Portability::releaseString(values[i]); + values[i].Release(); } void diff --git a/parser/html/nsHtml5HtmlAttributes.h b/parser/html/nsHtml5HtmlAttributes.h index c02d0a08c..12149a0b5 100644 --- a/parser/html/nsHtml5HtmlAttributes.h +++ b/parser/html/nsHtml5HtmlAttributes.h @@ -31,7 +31,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" @@ -64,21 +64,23 @@ class nsHtml5HtmlAttributes int32_t mode; int32_t length; autoJArray<nsHtml5AttributeName*,int32_t> names; - autoJArray<nsString*,int32_t> values; + autoJArray<nsHtml5String, int32_t> values; autoJArray<int32_t,int32_t> lines; public: explicit nsHtml5HtmlAttributes(int32_t mode); ~nsHtml5HtmlAttributes(); int32_t getIndex(nsHtml5AttributeName* name); - nsString* getValue(nsHtml5AttributeName* name); + nsHtml5String getValue(nsHtml5AttributeName* name); int32_t getLength(); nsIAtom* getLocalNameNoBoundsCheck(int32_t index); int32_t getURINoBoundsCheck(int32_t index); nsIAtom* getPrefixNoBoundsCheck(int32_t index); - nsString* getValueNoBoundsCheck(int32_t index); + nsHtml5String getValueNoBoundsCheck(int32_t index); nsHtml5AttributeName* getAttributeNameNoBoundsCheck(int32_t index); int32_t getLineNoBoundsCheck(int32_t index); - void addAttribute(nsHtml5AttributeName* name, nsString* value, int32_t line); + void addAttribute(nsHtml5AttributeName* name, + nsHtml5String value, + int32_t line); void clear(int32_t m); void releaseValue(int32_t i); void clearWithoutReleasingContents(); diff --git a/parser/html/nsHtml5MetaScanner.cpp b/parser/html/nsHtml5MetaScanner.cpp index d39eacd9b..24f17b02b 100644 --- a/parser/html/nsHtml5MetaScanner.cpp +++ b/parser/html/nsHtml5MetaScanner.cpp @@ -30,7 +30,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" @@ -86,8 +86,8 @@ nsHtml5MetaScanner::nsHtml5MetaScanner(nsHtml5TreeBuilder* tb) nsHtml5MetaScanner::~nsHtml5MetaScanner() { MOZ_COUNT_DTOR(nsHtml5MetaScanner); - nsHtml5Portability::releaseString(content); - nsHtml5Portability::releaseString(charset); + content.Release(); + charset.Release(); } void @@ -771,9 +771,9 @@ bool nsHtml5MetaScanner::handleTag() { bool stop = handleTagInner(); - nsHtml5Portability::releaseString(content); + content.Release(); content = nullptr; - nsHtml5Portability::releaseString(charset); + charset.Release(); charset = nullptr; httpEquivState = NS_HTML5META_SCANNER_HTTP_EQUIV_NOT_SEEN; return stop; @@ -786,12 +786,13 @@ nsHtml5MetaScanner::handleTagInner() return true; } if (!!content && httpEquivState == NS_HTML5META_SCANNER_HTTP_EQUIV_CONTENT_TYPE) { - nsString* extract = nsHtml5TreeBuilder::extractCharsetFromContent(content, treeBuilder); + nsHtml5String extract = + nsHtml5TreeBuilder::extractCharsetFromContent(content, treeBuilder); if (!extract) { return false; } bool success = tryCharset(extract); - nsHtml5Portability::releaseString(extract); + extract.Release(); return success; } return false; diff --git a/parser/html/nsHtml5MetaScanner.h b/parser/html/nsHtml5MetaScanner.h index 4e0ad7647..a4d308147 100644 --- a/parser/html/nsHtml5MetaScanner.h +++ b/parser/html/nsHtml5MetaScanner.h @@ -31,7 +31,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" @@ -76,8 +76,8 @@ class nsHtml5MetaScanner private: int32_t strBufLen; autoJArray<char16_t,int32_t> strBuf; - nsString* content; - nsString* charset; + nsHtml5String content; + nsHtml5String charset; int32_t httpEquivState; nsHtml5TreeBuilder* treeBuilder; public: @@ -100,7 +100,7 @@ class nsHtml5MetaScanner bool handleTag(); bool handleTagInner(); protected: - bool tryCharset(nsString* encoding); + bool tryCharset(nsHtml5String encoding); public: static void initializeStatics(); static void releaseStatics(); diff --git a/parser/html/nsHtml5MetaScannerCppSupplement.h b/parser/html/nsHtml5MetaScannerCppSupplement.h index 5e7033777..9d2496361 100644 --- a/parser/html/nsHtml5MetaScannerCppSupplement.h +++ b/parser/html/nsHtml5MetaScannerCppSupplement.h @@ -19,13 +19,15 @@ nsHtml5MetaScanner::sniff(nsHtml5ByteReadable* bytes, nsACString& charset) } bool -nsHtml5MetaScanner::tryCharset(nsString* charset) +nsHtml5MetaScanner::tryCharset(nsHtml5String charset) { // This code needs to stay in sync with // nsHtml5StreamParser::internalEncodingDeclaration. Unfortunately, the // trickery with member fields here leads to some copy-paste reuse. :-( nsAutoCString label; - CopyUTF16toUTF8(*charset, label); + nsString charset16; // Not Auto, because using it to hold nsStringBuffer* + charset.ToString(charset16); + CopyUTF16toUTF8(charset16, label); nsAutoCString encoding; if (!EncodingUtils::FindEncodingForLabel(label, encoding)) { return false; diff --git a/parser/html/nsHtml5PlainTextUtils.cpp b/parser/html/nsHtml5PlainTextUtils.cpp index 4f0eab81b..0d2933150 100644 --- a/parser/html/nsHtml5PlainTextUtils.cpp +++ b/parser/html/nsHtml5PlainTextUtils.cpp @@ -5,21 +5,24 @@ #include "nsHtml5PlainTextUtils.h" #include "nsHtml5AttributeName.h" +#include "nsHtml5Portability.h" #include "nsIServiceManager.h" #include "nsIStringBundle.h" #include "mozilla/Preferences.h" +#include "nsHtml5String.h" // static nsHtml5HtmlAttributes* nsHtml5PlainTextUtils::NewLinkAttributes() { nsHtml5HtmlAttributes* linkAttrs = new nsHtml5HtmlAttributes(0); - nsString* rel = new nsString(NS_LITERAL_STRING("alternate stylesheet")); + nsHtml5String rel = + nsHtml5Portability::newStringFromLiteral("alternate stylesheet"); linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_REL, rel, -1); - nsString* type = new nsString(NS_LITERAL_STRING("text/css")); + nsHtml5String type = nsHtml5Portability::newStringFromLiteral("text/css"); linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_TYPE, type, -1); - nsString* href = new nsString( - NS_LITERAL_STRING("resource://gre-resources/plaintext.css")); + nsHtml5String href = nsHtml5Portability::newStringFromLiteral( + "resource://gre-resources/plaintext.css"); linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_HREF, href, -1); nsresult rv; @@ -34,7 +37,7 @@ nsHtml5PlainTextUtils::NewLinkAttributes() bundle->GetStringFromName(u"plainText.wordWrap", getter_Copies(title)); } - nsString* titleCopy = new nsString(title); - linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_TITLE, titleCopy, -1); + linkAttrs->addAttribute( + nsHtml5AttributeName::ATTR_TITLE, nsHtml5String::FromString(title), -1); return linkAttrs; } diff --git a/parser/html/nsHtml5Portability.cpp b/parser/html/nsHtml5Portability.cpp index 0a7c6f845..5a76b3c56 100644 --- a/parser/html/nsHtml5Portability.cpp +++ b/parser/html/nsHtml5Portability.cpp @@ -16,37 +16,31 @@ nsHtml5Portability::newLocalNameFromBuffer(char16_t* buf, int32_t offset, int32_ return interner->GetAtom(nsDependentSubstring(buf, buf + length)); } -nsString* -nsHtml5Portability::newStringFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5TreeBuilder* treeBuilder) +nsHtml5String +nsHtml5Portability::newStringFromBuffer(char16_t* buf, + int32_t offset, + int32_t length, + nsHtml5TreeBuilder* treeBuilder) { - nsString* str = new nsString(); - bool succeeded = str->Append(buf + offset, length, mozilla::fallible); - if (!succeeded) { - str->Assign(char16_t(0xFFFD)); - treeBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY); - } - return str; + return nsHtml5String::FromBuffer(buf + offset, length, treeBuilder); } -nsString* +nsHtml5String nsHtml5Portability::newEmptyString() { - return new nsString(); + return nsHtml5String::EmptyString(); } -nsString* +nsHtml5String nsHtml5Portability::newStringFromLiteral(const char* literal) { - nsString* str = new nsString(); - str->AssignASCII(literal); - return str; + return nsHtml5String::FromLiteral(literal); } -nsString* -nsHtml5Portability::newStringFromString(nsString* string) { - nsString* newStr = new nsString(); - newStr->Assign(*string); - return newStr; +nsHtml5String +nsHtml5Portability::newStringFromString(nsHtml5String string) +{ + return string.Clone(); } jArray<char16_t,int32_t> @@ -60,12 +54,14 @@ nsHtml5Portability::newCharArrayFromLocal(nsIAtom* local) return arr; } -jArray<char16_t,int32_t> -nsHtml5Portability::newCharArrayFromString(nsString* string) +jArray<char16_t, int32_t> +nsHtml5Portability::newCharArrayFromString(nsHtml5String string) { - int32_t len = string->Length(); + MOZ_RELEASE_ASSERT(string); + uint32_t len = string.Length(); + MOZ_RELEASE_ASSERT(len < INT32_MAX); jArray<char16_t,int32_t> arr = jArray<char16_t,int32_t>::newJArray(len); - memcpy(arr, string->BeginReading(), len * sizeof(char16_t)); + string.CopyToBuffer(arr); return arr; } @@ -82,12 +78,6 @@ nsHtml5Portability::newLocalFromLocal(nsIAtom* local, nsHtml5AtomTable* interner return local; } -void -nsHtml5Portability::releaseString(nsString* str) -{ - delete str; -} - bool nsHtml5Portability::localEqualsBuffer(nsIAtom* local, char16_t* buf, int32_t offset, int32_t length) { @@ -95,55 +85,32 @@ nsHtml5Portability::localEqualsBuffer(nsIAtom* local, char16_t* buf, int32_t off } bool -nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(const char* lowerCaseLiteral, nsString* string) +nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString( + const char* lowerCaseLiteral, + nsHtml5String string) { - if (!string) { - return false; - } - const char* litPtr = lowerCaseLiteral; - const char16_t* strPtr = string->BeginReading(); - const char16_t* end = string->EndReading(); - char16_t litChar; - while ((litChar = *litPtr)) { - NS_ASSERTION(!(litChar >= 'A' && litChar <= 'Z'), "Literal isn't in lower case."); - if (strPtr == end) { - return false; - } - char16_t strChar = *strPtr; - if (strChar >= 'A' && strChar <= 'Z') { - strChar += 0x20; - } - if (litChar != strChar) { - return false; - } - ++litPtr; - ++strPtr; - } - return true; + return string.LowerCaseStartsWithASCII(lowerCaseLiteral); } bool -nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(const char* lowerCaseLiteral, nsString* string) +nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString( + const char* lowerCaseLiteral, + nsHtml5String string) { - if (!string) { - return false; - } - return string->LowerCaseEqualsASCII(lowerCaseLiteral); + return string.LowerCaseEqualsASCII(lowerCaseLiteral); } bool -nsHtml5Portability::literalEqualsString(const char* literal, nsString* string) +nsHtml5Portability::literalEqualsString(const char* literal, + nsHtml5String string) { - if (!string) { - return false; - } - return string->EqualsASCII(literal); + return string.EqualsASCII(literal); } bool -nsHtml5Portability::stringEqualsString(nsString* one, nsString* other) +nsHtml5Portability::stringEqualsString(nsHtml5String one, nsHtml5String other) { - return one->Equals(*other); + return one.Equals(other); } void diff --git a/parser/html/nsHtml5Portability.h b/parser/html/nsHtml5Portability.h index bd85ccbdb..a3214dd2f 100644 --- a/parser/html/nsHtml5Portability.h +++ b/parser/html/nsHtml5Portability.h @@ -30,7 +30,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" @@ -59,19 +59,26 @@ class nsHtml5Portability { public: static nsIAtom* newLocalNameFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5AtomTable* interner); - static nsString* newStringFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5TreeBuilder* treeBuilder); - static nsString* newEmptyString(); - static nsString* newStringFromLiteral(const char* literal); - static nsString* newStringFromString(nsString* string); + static nsHtml5String newStringFromBuffer(char16_t* buf, + int32_t offset, + int32_t length, + nsHtml5TreeBuilder* treeBuilder); + static nsHtml5String newEmptyString(); + static nsHtml5String newStringFromLiteral(const char* literal); + static nsHtml5String newStringFromString(nsHtml5String string); static jArray<char16_t,int32_t> newCharArrayFromLocal(nsIAtom* local); - static jArray<char16_t,int32_t> newCharArrayFromString(nsString* string); + static jArray<char16_t, int32_t> newCharArrayFromString( + nsHtml5String string); static nsIAtom* newLocalFromLocal(nsIAtom* local, nsHtml5AtomTable* interner); - static void releaseString(nsString* str); static bool localEqualsBuffer(nsIAtom* local, char16_t* buf, int32_t offset, int32_t length); - static bool lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(const char* lowerCaseLiteral, nsString* string); - static bool lowerCaseLiteralEqualsIgnoreAsciiCaseString(const char* lowerCaseLiteral, nsString* string); - static bool literalEqualsString(const char* literal, nsString* string); - static bool stringEqualsString(nsString* one, nsString* other); + static bool lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString( + const char* lowerCaseLiteral, + nsHtml5String string); + static bool lowerCaseLiteralEqualsIgnoreAsciiCaseString( + const char* lowerCaseLiteral, + nsHtml5String string); + static bool literalEqualsString(const char* literal, nsHtml5String string); + static bool stringEqualsString(nsHtml5String one, nsHtml5String other); static void initializeStatics(); static void releaseStatics(); }; diff --git a/parser/html/nsHtml5SpeculativeLoad.h b/parser/html/nsHtml5SpeculativeLoad.h index 575f6186d..6f1365bcf 100644 --- a/parser/html/nsHtml5SpeculativeLoad.h +++ b/parser/html/nsHtml5SpeculativeLoad.h @@ -35,45 +35,57 @@ class nsHtml5SpeculativeLoad { nsHtml5SpeculativeLoad(); ~nsHtml5SpeculativeLoad(); - inline void InitBase(const nsAString& aUrl) + inline void InitBase(nsHtml5String aUrl) { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadBase; - mUrl.Assign(aUrl); + aUrl.ToString(mUrl); } - inline void InitMetaCSP(const nsAString& aCSP) { + inline void InitMetaCSP(nsHtml5String aCSP) + { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadCSP; + nsString csp; // Not Auto, because using it to hold nsStringBuffer* + aCSP.ToString(csp); mMetaCSP.Assign( - nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aCSP)); + nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(csp)); } - inline void InitMetaReferrerPolicy(const nsAString& aReferrerPolicy) { + inline void InitMetaReferrerPolicy(nsHtml5String aReferrerPolicy) + { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadMetaReferrer; + nsString + referrerPolicy; // Not Auto, because using it to hold nsStringBuffer* + aReferrerPolicy.ToString(referrerPolicy); mReferrerPolicy.Assign( - nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aReferrerPolicy)); + nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>( + referrerPolicy)); } - inline void InitImage(const nsAString& aUrl, - const nsAString& aCrossOrigin, - const nsAString& aReferrerPolicy, - const nsAString& aSrcset, - const nsAString& aSizes) + inline void InitImage(nsHtml5String aUrl, + nsHtml5String aCrossOrigin, + nsHtml5String aReferrerPolicy, + nsHtml5String aSrcset, + nsHtml5String aSizes) { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadImage; - mUrl.Assign(aUrl); - mCrossOrigin.Assign(aCrossOrigin); + aUrl.ToString(mUrl); + aCrossOrigin.ToString(mCrossOrigin); + nsString + referrerPolicy; // Not Auto, because using it to hold nsStringBuffer* + aReferrerPolicy.ToString(referrerPolicy); mReferrerPolicy.Assign( - nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aReferrerPolicy)); - mSrcset.Assign(aSrcset); - mSizes.Assign(aSizes); + nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>( + referrerPolicy)); + aSrcset.ToString(mSrcset); + aSizes.ToString(mSizes); } // <picture> elements have multiple <source> nodes followed by an <img>, @@ -97,49 +109,50 @@ class nsHtml5SpeculativeLoad { mOpCode = eSpeculativeLoadEndPicture; } - inline void InitPictureSource(const nsAString& aSrcset, - const nsAString& aSizes, - const nsAString& aType, - const nsAString& aMedia) + inline void InitPictureSource(nsHtml5String aSrcset, + nsHtml5String aSizes, + nsHtml5String aType, + nsHtml5String aMedia) { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadPictureSource; - mSrcset.Assign(aSrcset); - mSizes.Assign(aSizes); - mTypeOrCharsetSourceOrDocumentMode.Assign(aType); - mMedia.Assign(aMedia); + aSrcset.ToString(mSrcset); + aSizes.ToString(mSizes); + aType.ToString(mTypeOrCharsetSourceOrDocumentMode); + aMedia.ToString(mMedia); } - inline void InitScript(const nsAString& aUrl, - const nsAString& aCharset, - const nsAString& aType, - const nsAString& aCrossOrigin, - const nsAString& aIntegrity, + inline void InitScript(nsHtml5String aUrl, + nsHtml5String aCharset, + nsHtml5String aType, + nsHtml5String aCrossOrigin, + nsHtml5String aIntegrity, bool aParserInHead) { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = aParserInHead ? eSpeculativeLoadScriptFromHead : eSpeculativeLoadScript; - mUrl.Assign(aUrl); - mCharset.Assign(aCharset); - mTypeOrCharsetSourceOrDocumentMode.Assign(aType); - mCrossOrigin.Assign(aCrossOrigin); - mIntegrity.Assign(aIntegrity); + aUrl.ToString(mUrl); + aCharset.ToString(mCharset); + aType.ToString(mTypeOrCharsetSourceOrDocumentMode); + aCrossOrigin.ToString(mCrossOrigin); + aIntegrity.ToString(mIntegrity); } - inline void InitStyle(const nsAString& aUrl, const nsAString& aCharset, - const nsAString& aCrossOrigin, - const nsAString& aIntegrity) + inline void InitStyle(nsHtml5String aUrl, + nsHtml5String aCharset, + nsHtml5String aCrossOrigin, + nsHtml5String aIntegrity) { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadStyle; - mUrl.Assign(aUrl); - mCharset.Assign(aCharset); - mCrossOrigin.Assign(aCrossOrigin); - mIntegrity.Assign(aIntegrity); + aUrl.ToString(mUrl); + aCharset.ToString(mCharset); + aCrossOrigin.ToString(mCrossOrigin); + aIntegrity.ToString(mIntegrity); } /** @@ -153,12 +166,12 @@ class nsHtml5SpeculativeLoad { * manifests seen by the parser thread have to maintain the queue order * relative to true speculative loads. See bug 541079. */ - inline void InitManifest(const nsAString& aUrl) + inline void InitManifest(nsHtml5String aUrl) { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadManifest; - mUrl.Assign(aUrl); + aUrl.ToString(mUrl); } /** @@ -195,14 +208,13 @@ class nsHtml5SpeculativeLoad { mTypeOrCharsetSourceOrDocumentMode.Assign((char16_t)aMode); } - inline void InitPreconnect(const nsAString& aUrl, - const nsAString& aCrossOrigin) + inline void InitPreconnect(nsHtml5String aUrl, nsHtml5String aCrossOrigin) { NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized, "Trying to reinitialize a speculative load!"); mOpCode = eSpeculativeLoadPreconnect; - mUrl.Assign(aUrl); - mCrossOrigin.Assign(aCrossOrigin); + aUrl.ToString(mUrl); + aCrossOrigin.ToString(mCrossOrigin); } void Perform(nsHtml5TreeOpExecutor* aExecutor); diff --git a/parser/html/nsHtml5StackNode.cpp b/parser/html/nsHtml5StackNode.cpp index ac5f0b2a3..41163ae40 100644 --- a/parser/html/nsHtml5StackNode.cpp +++ b/parser/html/nsHtml5StackNode.cpp @@ -30,7 +30,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" diff --git a/parser/html/nsHtml5StackNode.h b/parser/html/nsHtml5StackNode.h index 57909ca9c..1677ec571 100644 --- a/parser/html/nsHtml5StackNode.h +++ b/parser/html/nsHtml5StackNode.h @@ -31,7 +31,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" diff --git a/parser/html/nsHtml5StateSnapshot.cpp b/parser/html/nsHtml5StateSnapshot.cpp index e8e3debf0..90780738b 100644 --- a/parser/html/nsHtml5StateSnapshot.cpp +++ b/parser/html/nsHtml5StateSnapshot.cpp @@ -29,7 +29,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" diff --git a/parser/html/nsHtml5StateSnapshot.h b/parser/html/nsHtml5StateSnapshot.h index 141b34340..119570499 100644 --- a/parser/html/nsHtml5StateSnapshot.h +++ b/parser/html/nsHtml5StateSnapshot.h @@ -30,7 +30,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" diff --git a/parser/html/nsHtml5StreamParser.cpp b/parser/html/nsHtml5StreamParser.cpp index 83bf4d8b6..ab4548125 100644 --- a/parser/html/nsHtml5StreamParser.cpp +++ b/parser/html/nsHtml5StreamParser.cpp @@ -1261,7 +1261,7 @@ nsHtml5StreamParser::PreferredForInternalEncodingDecl(nsACString& aEncoding) } bool -nsHtml5StreamParser::internalEncodingDeclaration(nsString* aEncoding) +nsHtml5StreamParser::internalEncodingDeclaration(nsHtml5String aEncoding) { // This code needs to stay in sync with // nsHtml5MetaScanner::tryCharset. Unfortunately, the @@ -1270,9 +1270,10 @@ nsHtml5StreamParser::internalEncodingDeclaration(nsString* aEncoding) if (mCharsetSource >= kCharsetFromMetaTag) { // this threshold corresponds to "confident" in the HTML5 spec return false; } - + nsString newEncoding16; // Not Auto, because using it to hold nsStringBuffer* + aEncoding.ToString(newEncoding16); nsAutoCString newEncoding; - CopyUTF16toUTF8(*aEncoding, newEncoding); + CopyUTF16toUTF8(newEncoding16, newEncoding); if (!PreferredForInternalEncodingDecl(newEncoding)) { return false; diff --git a/parser/html/nsHtml5StreamParser.h b/parser/html/nsHtml5StreamParser.h index 9a38ba067..2560f84ab 100644 --- a/parser/html/nsHtml5StreamParser.h +++ b/parser/html/nsHtml5StreamParser.h @@ -145,7 +145,7 @@ class nsHtml5StreamParser : public nsICharsetDetectionObserver { /** * Tree builder uses this to report a late <meta charset> */ - bool internalEncodingDeclaration(nsString* aEncoding); + bool internalEncodingDeclaration(nsHtml5String aEncoding); // Not from an external interface diff --git a/parser/html/nsHtml5String.cpp b/parser/html/nsHtml5String.cpp new file mode 100644 index 000000000..d26eeaede --- /dev/null +++ b/parser/html/nsHtml5String.cpp @@ -0,0 +1,226 @@ +/* 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 "nsHtml5String.h" +#include "nsCharTraits.h" +#include "nsUTF8Utils.h" +#include "nsHtml5TreeBuilder.h" + +nsHtml5String::nsHtml5String(already_AddRefed<nsStringBuffer> aBuffer, + uint32_t aLength) + : mBuffer(aBuffer.take()) + , mLength(aLength) +{ + if (mBuffer) { + MOZ_ASSERT(aLength); + } else { + MOZ_ASSERT(!aLength || aLength == UINT32_MAX); + } +} + +void +nsHtml5String::ToString(nsAString& aString) +{ + if (mBuffer) { + mBuffer->ToString(mLength, aString); + } else { + aString.Truncate(); + if (mLength) { + aString.SetIsVoid(true); + } + } +} + +void +nsHtml5String::CopyToBuffer(char16_t* aBuffer) +{ + if (mBuffer) { + memcpy(aBuffer, mBuffer->Data(), mLength * sizeof(char16_t)); + } +} + +bool +nsHtml5String::LowerCaseEqualsASCII(const char* aLowerCaseLiteral) +{ + if (!mBuffer) { + if (mLength) { + // This string is null + return false; + } + // this string is empty + return !(*aLowerCaseLiteral); + } + return !nsCharTraits<char16_t>::compareLowerCaseToASCIINullTerminated( + reinterpret_cast<char16_t*>(mBuffer->Data()), Length(), aLowerCaseLiteral); +} + +bool +nsHtml5String::EqualsASCII(const char* aLiteral) +{ + if (!mBuffer) { + if (mLength) { + // This string is null + return false; + } + // this string is empty + return !(*aLiteral); + } + return !nsCharTraits<char16_t>::compareASCIINullTerminated( + reinterpret_cast<char16_t*>(mBuffer->Data()), Length(), aLiteral); +} + +bool +nsHtml5String::LowerCaseStartsWithASCII(const char* aLowerCaseLiteral) +{ + if (!mBuffer) { + if (mLength) { + // This string is null + return false; + } + // this string is empty + return !(*aLowerCaseLiteral); + } + const char* litPtr = aLowerCaseLiteral; + const char16_t* strPtr = reinterpret_cast<char16_t*>(mBuffer->Data()); + const char16_t* end = strPtr + Length(); + char16_t litChar; + while ((litChar = *litPtr) && (strPtr != end)) { + MOZ_ASSERT(!(litChar >= 'A' && litChar <= 'Z'), + "Literal isn't in lower case."); + char16_t strChar = *strPtr; + if (strChar >= 'A' && strChar <= 'Z') { + strChar += 0x20; + } + if (litChar != strChar) { + return false; + } + ++litPtr; + ++strPtr; + } + return true; +} + +bool +nsHtml5String::Equals(nsHtml5String aOther) +{ + MOZ_ASSERT(operator bool()); + MOZ_ASSERT(aOther); + if (mLength != aOther.mLength) { + return false; + } + if (!mBuffer) { + return true; + } + MOZ_ASSERT(aOther.mBuffer); + return !memcmp( + mBuffer->Data(), aOther.mBuffer->Data(), Length() * sizeof(char16_t)); +} + +nsHtml5String +nsHtml5String::Clone() +{ + MOZ_ASSERT(operator bool()); + RefPtr<nsStringBuffer> ref(mBuffer); + return nsHtml5String(ref.forget(), mLength); +} + +void +nsHtml5String::Release() +{ + if (mBuffer) { + mBuffer->Release(); + mBuffer = nullptr; + } + mLength = UINT32_MAX; +} + +// static +nsHtml5String +nsHtml5String::FromBuffer(char16_t* aBuffer, + int32_t aLength, + nsHtml5TreeBuilder* aTreeBuilder) +{ + if (!aLength) { + return nsHtml5String(nullptr, 0U); + } + // Work with nsStringBuffer directly to make sure that storage is actually + // nsStringBuffer and to make sure the allocation strategy matches + // nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and + // copy. + RefPtr<nsStringBuffer> buffer( + nsStringBuffer::Alloc((aLength + 1) * sizeof(char16_t))); + if (!buffer) { + if (!aTreeBuilder) { + MOZ_CRASH("Out of memory."); + } + aTreeBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY); + buffer = nsStringBuffer::Alloc(2 * sizeof(char16_t)); + if (!buffer) { + MOZ_CRASH( + "Out of memory so badly that couldn't even allocate placeholder."); + } + char16_t* data = reinterpret_cast<char16_t*>(buffer->Data()); + data[0] = 0xFFFD; + data[1] = 0; + return nsHtml5String(buffer.forget(), 1); + } + char16_t* data = reinterpret_cast<char16_t*>(buffer->Data()); + memcpy(data, aBuffer, aLength * sizeof(char16_t)); + data[aLength] = 0; + return nsHtml5String(buffer.forget(), aLength); +} + +// static +nsHtml5String +nsHtml5String::FromLiteral(const char* aLiteral) +{ + size_t length = std::strlen(aLiteral); + if (!length) { + return nsHtml5String(nullptr, 0U); + } + // Work with nsStringBuffer directly to make sure that storage is actually + // nsStringBuffer and to make sure the allocation strategy matches + // nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and + // copy. + RefPtr<nsStringBuffer> buffer( + nsStringBuffer::Alloc((length + 1) * sizeof(char16_t))); + if (!buffer) { + MOZ_CRASH("Out of memory."); + } + char16_t* data = reinterpret_cast<char16_t*>(buffer->Data()); + LossyConvertEncoding8to16 converter(data); + converter.write(aLiteral, length); + data[length] = 0; + return nsHtml5String(buffer.forget(), length); +} + +// static +nsHtml5String +nsHtml5String::FromString(const nsAString& aString) +{ + auto length = aString.Length(); + if (!length) { + return nsHtml5String(nullptr, 0U); + } + RefPtr<nsStringBuffer> buffer = nsStringBuffer::FromString(aString); + if (buffer) { + return nsHtml5String(buffer.forget(), length); + } + buffer = nsStringBuffer::Alloc((length + 1) * sizeof(char16_t)); + if (!buffer) { + MOZ_CRASH("Out of memory."); + } + char16_t* data = reinterpret_cast<char16_t*>(buffer->Data()); + memcpy(data, aString.BeginReading(), length * sizeof(char16_t)); + data[length] = 0; + return nsHtml5String(buffer.forget(), length); +} + +// static +nsHtml5String +nsHtml5String::EmptyString() +{ + return nsHtml5String(nullptr, 0U); + +}
\ No newline at end of file diff --git a/parser/html/nsHtml5String.h b/parser/html/nsHtml5String.h new file mode 100644 index 000000000..191bf6be8 --- /dev/null +++ b/parser/html/nsHtml5String.h @@ -0,0 +1,95 @@ +/* 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 nsHtml5String_h +#define nsHtml5String_h + +#include "nsString.h" + +class nsHtml5TreeBuilder; + +/** + * A pass-by-value type that combines an unsafe `nsStringBuffer*` with its + * logical length (`uint32_t`). (`nsStringBuffer` knows its capacity but not + * its logical length, i.e. how much of the capacity is in use.) + * + * Holding or passing this type is as unsafe as holding or passing + * `nsStringBuffer*`. + * + * Empty strings and null strings are distinct. Since an empty nsString does + * not have a an `nsStringBuffer`, both empty and null `nsHtml5String` have + * `nullptr` as `mBuffer`. If `mBuffer` is `nullptr`, the empty case is marked + * with `mLength` being zero and the null case with `mLength` being non-zero. + */ +class nsHtml5String final +{ +public: + /** + * Default constructor. + */ + inline nsHtml5String() + : nsHtml5String(nullptr) + { + } + + /** + * Constructor from nullptr. + */ + inline MOZ_IMPLICIT nsHtml5String(decltype(nullptr)) + : mBuffer(nullptr) + , mLength(UINT32_MAX) + { + } + + inline uint32_t Length() const { return mBuffer ? mLength : 0; } + + /** + * False iff the string is logically null + */ + inline MOZ_IMPLICIT operator bool() const { return !(!mBuffer && mLength); } + + void ToString(nsAString& aString); + + void CopyToBuffer(char16_t* aBuffer); + + bool LowerCaseEqualsASCII(const char* aLowerCaseLiteral); + + bool EqualsASCII(const char* aLiteral); + + bool LowerCaseStartsWithASCII(const char* aLowerCaseLiteral); + + bool Equals(nsHtml5String aOther); + + nsHtml5String Clone(); + + void Release(); + + static nsHtml5String FromBuffer(char16_t* aBuffer, + int32_t aLength, + nsHtml5TreeBuilder* aTreeBuilder); + + static nsHtml5String FromLiteral(const char* aLiteral); + + static nsHtml5String FromString(const nsAString& aString); + + static nsHtml5String EmptyString(); + +private: + /** + * Constructor from raw parts. + */ + nsHtml5String(already_AddRefed<nsStringBuffer> aBuffer, uint32_t aLength); + + /** + * nullptr if the string is logically null or logically empty + */ + nsStringBuffer* mBuffer; + + /** + * The length of the string. non-zero if the string is logically null. + */ + uint32_t mLength; +}; + +#endif // nsHtml5String_h
\ No newline at end of file diff --git a/parser/html/nsHtml5Tokenizer.cpp b/parser/html/nsHtml5Tokenizer.cpp index c469fe683..e70c081bf 100644 --- a/parser/html/nsHtml5Tokenizer.cpp +++ b/parser/html/nsHtml5Tokenizer.cpp @@ -32,7 +32,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" #include "jArray.h" @@ -113,7 +113,8 @@ nsHtml5Tokenizer::setInterner(nsHtml5AtomTable* interner) } void -nsHtml5Tokenizer::initLocation(nsString* newPublicId, nsString* newSystemId) +nsHtml5Tokenizer::initLocation(nsHtml5String newPublicId, + nsHtml5String newSystemId) { this->systemId = newSystemId; this->publicId = newPublicId; @@ -222,10 +223,11 @@ nsHtml5Tokenizer::emitOrAppendCharRefBuf(int32_t returnState) } } -nsString* +nsHtml5String nsHtml5Tokenizer::strBufToString() { - nsString* str = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, tokenHandler); + nsHtml5String str = + nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, tokenHandler); clearStrBufAfterUse(); return str; } @@ -350,7 +352,7 @@ void nsHtml5Tokenizer::addAttributeWithValue() { if (attributeName) { - nsString* val = strBufToString(); + nsHtml5String val = strBufToString(); if (mViewSource) { mViewSource->MaybeLinkifyAttributeValue(attributeName, val); } @@ -3493,11 +3495,11 @@ nsHtml5Tokenizer::initDoctypeFields() clearStrBufAfterUse(); doctypeName = nsHtml5Atoms::emptystring; if (systemIdentifier) { - nsHtml5Portability::releaseString(systemIdentifier); + systemIdentifier.Release(); systemIdentifier = nullptr; } if (publicIdentifier) { - nsHtml5Portability::releaseString(publicIdentifier); + publicIdentifier.Release(); publicIdentifier = nullptr; } forceQuirks = false; @@ -3659,11 +3661,11 @@ nsHtml5Tokenizer::eof() errEofInDoctype(); doctypeName = nsHtml5Atoms::emptystring; if (systemIdentifier) { - nsHtml5Portability::releaseString(systemIdentifier); + systemIdentifier.Release(); systemIdentifier = nullptr; } if (publicIdentifier) { - nsHtml5Portability::releaseString(publicIdentifier); + publicIdentifier.Release(); publicIdentifier = nullptr; } forceQuirks = true; @@ -3893,14 +3895,14 @@ nsHtml5Tokenizer::emitDoctypeToken(int32_t pos) cstart = pos + 1; tokenHandler->doctype(doctypeName, publicIdentifier, systemIdentifier, forceQuirks); doctypeName = nullptr; - nsHtml5Portability::releaseString(publicIdentifier); + publicIdentifier.Release(); publicIdentifier = nullptr; - nsHtml5Portability::releaseString(systemIdentifier); + systemIdentifier.Release(); systemIdentifier = nullptr; } bool -nsHtml5Tokenizer::internalEncodingDeclaration(nsString* internalCharset) +nsHtml5Tokenizer::internalEncodingDeclaration(nsHtml5String internalCharset) { if (encodingDeclarationHandler) { return encodingDeclarationHandler->internalEncodingDeclaration(internalCharset); @@ -3935,11 +3937,11 @@ nsHtml5Tokenizer::end() strBuf = nullptr; doctypeName = nullptr; if (systemIdentifier) { - nsHtml5Portability::releaseString(systemIdentifier); + systemIdentifier.Release(); systemIdentifier = nullptr; } if (publicIdentifier) { - nsHtml5Portability::releaseString(publicIdentifier); + publicIdentifier.Release(); publicIdentifier = nullptr; } if (tagName) { @@ -4038,13 +4040,13 @@ nsHtml5Tokenizer::loadState(nsHtml5Tokenizer* other) } else { doctypeName = nsHtml5Portability::newLocalFromLocal(other->doctypeName, interner); } - nsHtml5Portability::releaseString(systemIdentifier); + systemIdentifier.Release(); if (!other->systemIdentifier) { systemIdentifier = nullptr; } else { systemIdentifier = nsHtml5Portability::newStringFromString(other->systemIdentifier); } - nsHtml5Portability::releaseString(publicIdentifier); + publicIdentifier.Release(); if (!other->publicIdentifier) { publicIdentifier = nullptr; } else { diff --git a/parser/html/nsHtml5Tokenizer.h b/parser/html/nsHtml5Tokenizer.h index da509b69b..00cca9a9c 100644 --- a/parser/html/nsHtml5Tokenizer.h +++ b/parser/html/nsHtml5Tokenizer.h @@ -33,7 +33,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" #include "jArray.h" @@ -106,8 +106,8 @@ class nsHtml5Tokenizer protected: int32_t cstart; private: - nsString* publicId; - nsString* systemId; + nsHtml5String publicId; + nsHtml5String systemId; autoJArray<char16_t,int32_t> strBuf; int32_t strBufLen; autoJArray<char16_t,int32_t> charRefBuf; @@ -126,8 +126,8 @@ class nsHtml5Tokenizer nsHtml5AttributeName* attributeName; private: nsIAtom* doctypeName; - nsString* publicIdentifier; - nsString* systemIdentifier; + nsHtml5String publicIdentifier; + nsHtml5String systemIdentifier; nsHtml5HtmlAttributes* attributes; bool newAttributesEachTime; bool shouldSuspend; @@ -141,7 +141,7 @@ class nsHtml5Tokenizer public: nsHtml5Tokenizer(nsHtml5TreeBuilder* tokenHandler, bool viewingXmlSource); void setInterner(nsHtml5AtomTable* interner); - void initLocation(nsString* newPublicId, nsString* newSystemId); + void initLocation(nsHtml5String newPublicId, nsHtml5String newSystemId); bool isViewingXmlSource(); void setStateAndEndTagExpectation(int32_t specialTokenizerState, nsIAtom* endTagExpectation); void setStateAndEndTagExpectation(int32_t specialTokenizerState, nsHtml5ElementName* endTagExpectation); @@ -193,7 +193,7 @@ class nsHtml5Tokenizer } protected: - nsString* strBufToString(); + nsHtml5String strBufToString(); private: void strBufToDoctypeName(); void emitStrBuf(); @@ -285,7 +285,7 @@ class nsHtml5Tokenizer } public: - bool internalEncodingDeclaration(nsString* internalCharset); + bool internalEncodingDeclaration(nsHtml5String internalCharset); private: void emitOrAppendTwo(const char16_t* val, int32_t returnState); void emitOrAppendOne(const char16_t* val, int32_t returnState); diff --git a/parser/html/nsHtml5TreeBuilder.cpp b/parser/html/nsHtml5TreeBuilder.cpp index f694116ba..457c7deb1 100644 --- a/parser/html/nsHtml5TreeBuilder.cpp +++ b/parser/html/nsHtml5TreeBuilder.cpp @@ -34,7 +34,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" #include "nsITimer.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" @@ -154,13 +154,16 @@ nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) } void -nsHtml5TreeBuilder::doctype(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks) +nsHtml5TreeBuilder::doctype(nsIAtom* name, + nsHtml5String publicIdentifier, + nsHtml5String systemIdentifier, + bool forceQuirks) { needToDropLF = false; if (!isInForeign() && mode == NS_HTML5TREE_BUILDER_INITIAL) { - nsString* emptyString = nsHtml5Portability::newEmptyString(); + nsHtml5String emptyString = nsHtml5Portability::newEmptyString(); appendDoctypeToDocument(!name ? nsHtml5Atoms::emptystring : name, !publicIdentifier ? emptyString : publicIdentifier, !systemIdentifier ? emptyString : systemIdentifier); - nsHtml5Portability::releaseString(emptyString); + emptyString.Release(); if (isQuirky(name, publicIdentifier, systemIdentifier, forceQuirks)) { errQuirkyDoctype(); documentModeInternal(QUIRKS_MODE, publicIdentifier, systemIdentifier, false); @@ -1990,8 +1993,9 @@ nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode) return (kNameSpaceID_XHTML == ns) || (stackNode->isHtmlIntegrationPoint()) || ((kNameSpaceID_MathML == ns) && (stackNode->getGroup() == NS_HTML5TREE_BUILDER_MI_MO_MN_MS_MTEXT)); } -nsString* -nsHtml5TreeBuilder::extractCharsetFromContent(nsString* attributeValue, nsHtml5TreeBuilder* tb) +nsHtml5String +nsHtml5TreeBuilder::extractCharsetFromContent(nsHtml5String attributeValue, + nsHtml5TreeBuilder* tb) { int32_t charsetState = NS_HTML5TREE_BUILDER_CHARSET_INITIAL; int32_t start = -1; @@ -2175,12 +2179,13 @@ nsHtml5TreeBuilder::extractCharsetFromContent(nsString* attributeValue, nsHtml5T } } charsetloop_end: ; - nsString* charset = nullptr; + nsHtml5String charset = nullptr; if (start != -1) { if (end == -1) { end = buffer.length; } - charset = nsHtml5Portability::newStringFromBuffer(buffer, start, end - start, tb); + charset = + nsHtml5Portability::newStringFromBuffer(buffer, start, end - start, tb); } return charset; } @@ -2188,7 +2193,8 @@ nsHtml5TreeBuilder::extractCharsetFromContent(nsString* attributeValue, nsHtml5T void nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes) { - nsString* charset = attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); + nsHtml5String charset = + attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); if (charset) { if (tokenizer->internalEncodingDeclaration(charset)) { requestSuspension(); @@ -2199,15 +2205,17 @@ nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes) if (!nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("content-type", attributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) { return; } - nsString* content = attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); + nsHtml5String content = + attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); if (content) { - nsString* extract = nsHtml5TreeBuilder::extractCharsetFromContent(content, this); + nsHtml5String extract = + nsHtml5TreeBuilder::extractCharsetFromContent(content, this); if (extract) { if (tokenizer->internalEncodingDeclaration(extract)) { requestSuspension(); } } - nsHtml5Portability::releaseString(extract); + extract.Release(); } } @@ -3208,7 +3216,11 @@ nsHtml5TreeBuilder::isSecondOnStackBody() } void -nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m, nsString* publicIdentifier, nsString* systemIdentifier, bool html4SpecificAdditionalErrorChecks) +nsHtml5TreeBuilder::documentModeInternal( + nsHtml5DocumentMode m, + nsHtml5String publicIdentifier, + nsHtml5String systemIdentifier, + bool html4SpecificAdditionalErrorChecks) { if (isSrcdocDocument) { quirks = false; @@ -3220,7 +3232,8 @@ nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m, nsString* public } bool -nsHtml5TreeBuilder::isAlmostStandards(nsString* publicIdentifier, nsString* systemIdentifier) +nsHtml5TreeBuilder::isAlmostStandards(nsHtml5String publicIdentifier, + nsHtml5String systemIdentifier) { if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd xhtml 1.0 transitional//en", publicIdentifier)) { return true; @@ -3240,7 +3253,10 @@ nsHtml5TreeBuilder::isAlmostStandards(nsString* publicIdentifier, nsString* syst } bool -nsHtml5TreeBuilder::isQuirky(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks) +nsHtml5TreeBuilder::isQuirky(nsIAtom* name, + nsHtml5String publicIdentifier, + nsHtml5String systemIdentifier, + bool forceQuirks) { if (forceQuirks) { return true; @@ -4051,7 +4067,8 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterMathML(nsHtml5Elem bool nsHtml5TreeBuilder::annotationXmlEncodingPermitsHtml(nsHtml5HtmlAttributes* attributes) { - nsString* encoding = attributes->getValue(nsHtml5AttributeName::ATTR_ENCODING); + nsHtml5String encoding = + attributes->getValue(nsHtml5AttributeName::ATTR_ENCODING); if (!encoding) { return false; } diff --git a/parser/html/nsHtml5TreeBuilder.h b/parser/html/nsHtml5TreeBuilder.h index a66b168be..67f5010c5 100644 --- a/parser/html/nsHtml5TreeBuilder.h +++ b/parser/html/nsHtml5TreeBuilder.h @@ -35,7 +35,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" #include "nsITimer.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" @@ -103,7 +103,10 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState bool isSrcdocDocument; public: void startTokenization(nsHtml5Tokenizer* self); - void doctype(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks); + void doctype(nsIAtom* name, + nsHtml5String publicIdentifier, + nsHtml5String systemIdentifier, + bool forceQuirks); void comment(char16_t* buf, int32_t start, int32_t length); void characters(const char16_t* buf, int32_t start, int32_t length); void zeroOriginatingReplacementCharacter(); @@ -119,7 +122,8 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState bool isTemplateModeStackEmpty(); bool isSpecialParentInForeign(nsHtml5StackNode* stackNode); public: - static nsString* extractCharsetFromContent(nsString* attributeValue, nsHtml5TreeBuilder* tb); + static nsHtml5String extractCharsetFromContent(nsHtml5String attributeValue, + nsHtml5TreeBuilder* tb); private: void checkMetaCharset(nsHtml5HtmlAttributes* attributes); public: @@ -136,9 +140,16 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState void generateImpliedEndTagsExceptFor(nsIAtom* name); void generateImpliedEndTags(); bool isSecondOnStackBody(); - void documentModeInternal(nsHtml5DocumentMode m, nsString* publicIdentifier, nsString* systemIdentifier, bool html4SpecificAdditionalErrorChecks); - bool isAlmostStandards(nsString* publicIdentifier, nsString* systemIdentifier); - bool isQuirky(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks); + void documentModeInternal(nsHtml5DocumentMode m, + nsHtml5String publicIdentifier, + nsHtml5String systemIdentifier, + bool html4SpecificAdditionalErrorChecks); + bool isAlmostStandards(nsHtml5String publicIdentifier, + nsHtml5String systemIdentifier); + bool isQuirky(nsIAtom* name, + nsHtml5String publicIdentifier, + nsHtml5String systemIdentifier, + bool forceQuirks); void closeTheCell(int32_t eltPos); int32_t findLastInTableScopeTdTh(); void clearStackBackTo(int32_t eltPos); @@ -224,7 +235,9 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState void markMalformedIfScript(nsIContentHandle* elt); void start(bool fragmentMode); void end(); - void appendDoctypeToDocument(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier); + void appendDoctypeToDocument(nsIAtom* name, + nsHtml5String publicIdentifier, + nsHtml5String systemIdentifier); void elementPushed(int32_t ns, nsIAtom* name, nsIContentHandle* node); void elementPopped(int32_t ns, nsIAtom* name, nsIContentHandle* node); public: diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h index ff17c326e..aacc5a3e0 100644 --- a/parser/html/nsHtml5TreeBuilderCppSupplement.h +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h @@ -123,181 +123,178 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName, switch (aNamespace) { case kNameSpaceID_XHTML: if (nsHtml5Atoms::img == aName) { - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); - nsString* srcset = + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); + nsHtml5String srcset = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET); - nsString* crossOrigin = + nsHtml5String crossOrigin = aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); - nsString* referrerPolicy = + nsHtml5String referrerPolicy = aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY); - nsString* sizes = + nsHtml5String sizes = aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES); - mSpeculativeLoadQueue.AppendElement()-> - InitImage(url ? *url : NullString(), - crossOrigin ? *crossOrigin : NullString(), - referrerPolicy ? *referrerPolicy : NullString(), - srcset ? *srcset : NullString(), - sizes ? *sizes : NullString()); + mSpeculativeLoadQueue.AppendElement()->InitImage( + url, crossOrigin, referrerPolicy, srcset, sizes); } else if (nsHtml5Atoms::source == aName) { - nsString* srcset = + nsHtml5String srcset = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET); // Sources without srcset cannot be selected. The source could also be // for a media element, but in that context doesn't use srcset. See // comments in nsHtml5SpeculativeLoad.h about <picture> preloading if (srcset) { - nsString* sizes = + nsHtml5String sizes = aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES); - nsString* type = + nsHtml5String type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); - nsString* media = + nsHtml5String media = aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA); - mSpeculativeLoadQueue.AppendElement()-> - InitPictureSource(*srcset, - sizes ? *sizes : NullString(), - type ? *type : NullString(), - media ? *media : NullString()); + mSpeculativeLoadQueue.AppendElement()->InitPictureSource( + srcset, sizes, type, media); } } else if (nsHtml5Atoms::script == aName) { nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); NS_ASSERTION(treeOp, "Tree op allocation failed."); treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber()); - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); if (url) { - nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); - nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); - nsString* crossOrigin = + nsHtml5String charset = + aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); + nsHtml5String type = + aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); + nsHtml5String crossOrigin = aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); - nsString* integrity = + nsHtml5String integrity = aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); - mSpeculativeLoadQueue.AppendElement()-> - InitScript(*url, - (charset) ? *charset : EmptyString(), - (type) ? *type : EmptyString(), - (crossOrigin) ? *crossOrigin : NullString(), - (integrity) ? *integrity : NullString(), - mode == NS_HTML5TREE_BUILDER_IN_HEAD); + mSpeculativeLoadQueue.AppendElement()->InitScript( + url, + charset, + type, + crossOrigin, + integrity, + mode == NS_HTML5TREE_BUILDER_IN_HEAD); mCurrentHtmlScriptIsAsyncOrDefer = aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) || aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER); } } else if (nsHtml5Atoms::link == aName) { - nsString* rel = aAttributes->getValue(nsHtml5AttributeName::ATTR_REL); + nsHtml5String rel = + aAttributes->getValue(nsHtml5AttributeName::ATTR_REL); // Not splitting on space here is bogus but the old parser didn't even // do a case-insensitive check. if (rel) { - if (rel->LowerCaseEqualsASCII("stylesheet")) { - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); + if (rel.LowerCaseEqualsASCII("stylesheet")) { + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); if (url) { - nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); - nsString* crossOrigin = + nsHtml5String charset = + aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); + nsHtml5String crossOrigin = aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); - nsString* integrity = + nsHtml5String integrity = aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); - mSpeculativeLoadQueue.AppendElement()-> - InitStyle(*url, - (charset) ? *charset : EmptyString(), - (crossOrigin) ? *crossOrigin : NullString(), - (integrity) ? *integrity : NullString()); + mSpeculativeLoadQueue.AppendElement()->InitStyle( + url, charset, crossOrigin, integrity); } - } else if (rel->LowerCaseEqualsASCII("preconnect")) { - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); + } else if (rel.LowerCaseEqualsASCII("preconnect")) { + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); if (url) { - nsString* crossOrigin = + nsHtml5String crossOrigin = aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); - mSpeculativeLoadQueue.AppendElement()-> - InitPreconnect(*url, (crossOrigin) ? *crossOrigin : NullString()); + mSpeculativeLoadQueue.AppendElement()->InitPreconnect( + url, crossOrigin); } } } } else if (nsHtml5Atoms::video == aName) { - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER); + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER); if (url) { - mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(), - NullString(), - NullString(), - NullString()); + mSpeculativeLoadQueue.AppendElement()->InitImage( + url, nullptr, nullptr, nullptr, nullptr); } } else if (nsHtml5Atoms::style == aName) { nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); NS_ASSERTION(treeOp, "Tree op allocation failed."); treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); } else if (nsHtml5Atoms::html == aName) { - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); - if (url) { - mSpeculativeLoadQueue.AppendElement()->InitManifest(*url); - } else { - mSpeculativeLoadQueue.AppendElement()->InitManifest(EmptyString()); - } + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); + mSpeculativeLoadQueue.AppendElement()->InitManifest(url); } else if (nsHtml5Atoms::base == aName) { - nsString* url = - aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); if (url) { - mSpeculativeLoadQueue.AppendElement()->InitBase(*url); + mSpeculativeLoadQueue.AppendElement()->InitBase(url); } } else if (nsHtml5Atoms::meta == aName) { if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString( "content-security-policy", aAttributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) { - nsString* csp = aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); + nsHtml5String csp = + aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); if (csp) { - mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(*csp); + mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(csp); } } else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString( "referrer", aAttributes->getValue(nsHtml5AttributeName::ATTR_NAME))) { - nsString* referrerPolicy = aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); + nsHtml5String referrerPolicy = + aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); if (referrerPolicy) { - mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy(*referrerPolicy); + mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy( + referrerPolicy); } } } break; case kNameSpaceID_SVG: if (nsHtml5Atoms::image == aName) { - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); if (url) { - mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(), - NullString(), - NullString(), - NullString()); + mSpeculativeLoadQueue.AppendElement()->InitImage( + url, nullptr, nullptr, nullptr, nullptr); } } else if (nsHtml5Atoms::script == aName) { nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); NS_ASSERTION(treeOp, "Tree op allocation failed."); treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber()); - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); if (url) { - nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); - nsString* crossOrigin = + nsHtml5String type = + aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); + nsHtml5String crossOrigin = aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); - nsString* integrity = + nsHtml5String integrity = aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); - mSpeculativeLoadQueue.AppendElement()-> - InitScript(*url, - EmptyString(), - (type) ? *type : EmptyString(), - (crossOrigin) ? *crossOrigin : NullString(), - (integrity) ? *integrity : NullString(), - mode == NS_HTML5TREE_BUILDER_IN_HEAD); + mSpeculativeLoadQueue.AppendElement()->InitScript( + url, + nullptr, + type, + crossOrigin, + integrity, + mode == NS_HTML5TREE_BUILDER_IN_HEAD); } } else if (nsHtml5Atoms::style == aName) { nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); NS_ASSERTION(treeOp, "Tree op allocation failed."); treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); if (url) { - nsString* crossOrigin = + nsHtml5String crossOrigin = aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); - nsString* integrity = + nsHtml5String integrity = aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); - mSpeculativeLoadQueue.AppendElement()-> - InitStyle(*url, EmptyString(), - (crossOrigin) ? *crossOrigin : NullString(), - (integrity) ? *integrity : NullString()); + mSpeculativeLoadQueue.AppendElement()->InitStyle( + url, nullptr, crossOrigin, integrity); } } break; @@ -320,18 +317,23 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName, } } else if (aNamespace == kNameSpaceID_XHTML) { if (nsHtml5Atoms::html == aName) { - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); NS_ASSERTION(treeOp, "Tree op allocation failed."); if (url) { - treeOp->Init(eTreeOpProcessOfflineManifest, *url); + nsString + urlString; // Not Auto, because using it to hold nsStringBuffer* + url.ToString(urlString); + treeOp->Init(eTreeOpProcessOfflineManifest, urlString); } else { treeOp->Init(eTreeOpProcessOfflineManifest, EmptyString()); } } else if (nsHtml5Atoms::base == aName && mViewSource) { - nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); + nsHtml5String url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); if (url) { - mViewSource->AddBase(*url); + mViewSource->AddBase(url); } } } @@ -743,17 +745,19 @@ nsHtml5TreeBuilder::end() } void -nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, nsString* aSystemId) +nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, + nsHtml5String aPublicId, + nsHtml5String aSystemId) { NS_PRECONDITION(aName, "Null name"); - + nsString publicId; // Not Auto, because using it to hold nsStringBuffer* + nsString systemId; // Not Auto, because using it to hold nsStringBuffer* + aPublicId.ToString(publicId); + aSystemId.ToString(systemId); if (mBuilder) { nsCOMPtr<nsIAtom> name = nsHtml5TreeOperation::Reget(aName); - nsresult rv = - nsHtml5TreeOperation::AppendDoctypeToDocument(name, - *aPublicId, - *aSystemId, - mBuilder); + nsresult rv = nsHtml5TreeOperation::AppendDoctypeToDocument( + name, publicId, systemId, mBuilder); if (NS_FAILED(rv)) { MarkAsBrokenAndRequestSuspension(rv); } @@ -762,7 +766,7 @@ nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); NS_ASSERTION(treeOp, "Tree op allocation failed."); - treeOp->Init(aName, *aPublicId, *aSystemId); + treeOp->Init(aName, publicId, systemId); // nsXMLContentSink can flush here, but what's the point? // It can also interrupt here, but we can't. } diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index 5c3f32d6f..95f177376 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -954,8 +954,9 @@ nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL, const nsAString& aImageReferrerPolicy) { nsCOMPtr<nsIURI> baseURI = BaseURIForPreload(); + bool isImgSet = false; nsCOMPtr<nsIURI> uri = mDocument->ResolvePreloadImage(baseURI, aURL, aSrcset, - aSizes); + aSizes, &isImgSet); if (uri && ShouldPreloadURI(uri)) { // use document wide referrer policy mozilla::net::ReferrerPolicy referrerPolicy = mSpeculationReferrerPolicy; @@ -969,7 +970,7 @@ nsHtml5TreeOpExecutor::PreloadImage(const nsAString& aURL, } } - mDocument->MaybePreLoadImage(uri, aCrossOrigin, referrerPolicy); + mDocument->MaybePreLoadImage(uri, aCrossOrigin, referrerPolicy, isImgSet); } } diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp index af246a253..3877e01b8 100644 --- a/parser/html/nsHtml5TreeOperation.cpp +++ b/parser/html/nsHtml5TreeOperation.cpp @@ -319,11 +319,10 @@ nsHtml5TreeOperation::AddAttributes(nsIContent* aNode, if (!node->HasAttr(nsuri, localName)) { // prefix doesn't need regetting. it is always null or a static atom // local name is never null - node->SetAttr(nsuri, - localName, - aAttributes->getPrefixNoBoundsCheck(i), - *(aAttributes->getValueNoBoundsCheck(i)), - true); + nsString value; // Not Auto, because using it to hold nsStringBuffer* + aAttributes->getValueNoBoundsCheck(i).ToString(value); + node->SetAttr( + nsuri, localName, aAttributes->getPrefixNoBoundsCheck(i), value, true); // XXX what to do with nsresult? } } @@ -418,12 +417,14 @@ nsHtml5TreeOperation::CreateElement(int32_t aNs, nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i); int32_t nsuri = aAttributes->getURINoBoundsCheck(i); + nsString value; // Not Auto, because using it to hold nsStringBuffer* + aAttributes->getValueNoBoundsCheck(i).ToString(value); if (aNs == kNameSpaceID_XHTML && nsHtml5Atoms::a == aName && nsHtml5Atoms::name == localName) { // This is an HTML5-incompliant Geckoism. // Remove when fixing bug 582361 - NS_ConvertUTF16toUTF8 cname(*(aAttributes->getValueNoBoundsCheck(i))); + NS_ConvertUTF16toUTF8 cname(value); NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting())); newContent->SetAttr(nsuri, localName, @@ -431,7 +432,6 @@ nsHtml5TreeOperation::CreateElement(int32_t aNs, uv, false); } else { - nsString& value = *(aAttributes->getValueNoBoundsCheck(i)); newContent->SetAttr(nsuri, localName, prefix, diff --git a/parser/html/nsHtml5UTF16Buffer.cpp b/parser/html/nsHtml5UTF16Buffer.cpp index f70365ce4..0d6870bc4 100644 --- a/parser/html/nsHtml5UTF16Buffer.cpp +++ b/parser/html/nsHtml5UTF16Buffer.cpp @@ -29,7 +29,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" diff --git a/parser/html/nsHtml5UTF16Buffer.h b/parser/html/nsHtml5UTF16Buffer.h index cf810e124..c94245f74 100644 --- a/parser/html/nsHtml5UTF16Buffer.h +++ b/parser/html/nsHtml5UTF16Buffer.h @@ -30,7 +30,7 @@ #include "nsIAtom.h" #include "nsHtml5AtomTable.h" -#include "nsString.h" +#include "nsHtml5String.h" #include "nsNameSpaceManager.h" #include "nsIContent.h" #include "nsTraceRefcnt.h" diff --git a/parser/html/nsHtml5ViewSourceUtils.cpp b/parser/html/nsHtml5ViewSourceUtils.cpp index 4dd33fc05..b2f635bff 100644 --- a/parser/html/nsHtml5ViewSourceUtils.cpp +++ b/parser/html/nsHtml5ViewSourceUtils.cpp @@ -6,32 +6,35 @@ #include "nsHtml5ViewSourceUtils.h" #include "nsHtml5AttributeName.h" #include "mozilla/Preferences.h" -#include "mozilla/UniquePtr.h" +#include "nsHtml5String.h" // static nsHtml5HtmlAttributes* nsHtml5ViewSourceUtils::NewBodyAttributes() { nsHtml5HtmlAttributes* bodyAttrs = new nsHtml5HtmlAttributes(0); - auto id = MakeUnique<nsString>(NS_LITERAL_STRING("viewsource")); - bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, id.release(), -1); + nsHtml5String id = nsHtml5Portability::newStringFromLiteral("viewsource"); + bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, id, -1); - auto klass = MakeUnique<nsString>(); + nsString klass; if (mozilla::Preferences::GetBool("view_source.wrap_long_lines", true)) { - klass->Append(NS_LITERAL_STRING("wrap ")); + klass.Append(NS_LITERAL_STRING("wrap ")); } if (mozilla::Preferences::GetBool("view_source.syntax_highlight", true)) { - klass->Append(NS_LITERAL_STRING("highlight")); + klass.Append(NS_LITERAL_STRING("highlight")); } - if (!klass->IsEmpty()) { - bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_CLASS, klass.release(), -1); + if (!klass.IsEmpty()) { + bodyAttrs->addAttribute( + nsHtml5AttributeName::ATTR_CLASS, nsHtml5String::FromString(klass), -1); } int32_t tabSize = mozilla::Preferences::GetInt("view_source.tab_size", 4); if (tabSize > 0) { - auto style = MakeUnique<nsString>(NS_LITERAL_STRING("-moz-tab-size: ")); - style->AppendInt(tabSize); - bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_STYLE, style.release(), -1); + nsString style; + style.AssignASCII("-moz-tab-size: "); + style.AppendInt(tabSize); + bodyAttrs->addAttribute( + nsHtml5AttributeName::ATTR_STYLE, nsHtml5String::FromString(style), -1); } return bodyAttrs; @@ -42,12 +45,12 @@ nsHtml5HtmlAttributes* nsHtml5ViewSourceUtils::NewLinkAttributes() { nsHtml5HtmlAttributes* linkAttrs = new nsHtml5HtmlAttributes(0); - nsString* rel = new nsString(NS_LITERAL_STRING("stylesheet")); + nsHtml5String rel = nsHtml5Portability::newStringFromLiteral("stylesheet"); linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_REL, rel, -1); - nsString* type = new nsString(NS_LITERAL_STRING("text/css")); + nsHtml5String type = nsHtml5Portability::newStringFromLiteral("text/css"); linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_TYPE, type, -1); - nsString* href = new nsString( - NS_LITERAL_STRING("resource://gre-resources/viewsource.css")); + nsHtml5String href = nsHtml5Portability::newStringFromLiteral( + "resource://gre-resources/viewsource.css"); linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_HREF, href, -1); return linkAttrs; } diff --git a/services/sync/modules/policies.js b/services/sync/modules/policies.js index 2d85b1428..48acbe2e6 100644 --- a/services/sync/modules/policies.js +++ b/services/sync/modules/policies.js @@ -60,20 +60,60 @@ SyncScheduler.prototype = { }, // nextSync is in milliseconds, but prefs can't hold that much - get nextSync() Svc.Prefs.get("nextSync", 0) * 1000, - set nextSync(value) Svc.Prefs.set("nextSync", Math.floor(value / 1000)), + get nextSync() { + if (Svc.Prefs) { + return Svc.Prefs.get("nextSync", 0) * 1000 + } + }, + set nextSync(value) { + if (Svc.Prefs) { + Svc.Prefs.set("nextSync", Math.floor(value / 1000)) + } + }, - get syncInterval() Svc.Prefs.get("syncInterval", this.singleDeviceInterval), - set syncInterval(value) Svc.Prefs.set("syncInterval", value), + get syncInterval() { + if (Svc.Prefs) { + return Svc.Prefs.get("syncInterval", this.singleDeviceInterval) + } + }, + set syncInterval(value) { + if (Svc.Prefs) { + Svc.Prefs.set("syncInterval", value) + } + }, - get syncThreshold() Svc.Prefs.get("syncThreshold", SINGLE_USER_THRESHOLD), - set syncThreshold(value) Svc.Prefs.set("syncThreshold", value), + get syncThreshold() { + if (Svc.Prefs) { + return Svc.Prefs.get("syncThreshold", SINGLE_USER_THRESHOLD) + } + }, + set syncThreshold(value) { + if (Svc.Prefs) { + Svc.Prefs.set("syncThreshold", value) + } + }, - get globalScore() Svc.Prefs.get("globalScore", 0), - set globalScore(value) Svc.Prefs.set("globalScore", value), + get globalScore() { + if (Svc.Prefs) { + return Svc.Prefs.get("globalScore", 0) + } + }, + set globalScore(value) { + if (Svc.Prefs) { + Svc.Prefs.set("globalScore", value) + } + }, - get numClients() Svc.Prefs.get("numClients", 0), - set numClients(value) Svc.Prefs.set("numClients", value), + get numClients() { + if (Svc.Prefs) { + return Svc.Prefs.get("numClients", 0) + } + }, + set numClients(value) { + if (Svc.Prefs) { + Svc.Prefs.set("numClients", value) + } + }, init: function init() { this._log.level = Log.Level[Svc.Prefs.get("log.logger.service.main")]; @@ -523,7 +563,7 @@ SyncScheduler.prototype = { }, get isBlocked() { - let until = Svc.Prefs.get("scheduler.blocked-until"); + let until = Svc.Prefs ? Svc.Prefs.get("scheduler.blocked-until") : undefined; if (until === undefined) { return false; } @@ -770,19 +810,19 @@ ErrorHandler.prototype = { }, get currentAlertMode() { - return Svc.Prefs.get("errorhandler.alert.mode"); + return Svc.Prefs ? Svc.Prefs.get("errorhandler.alert.mode") : undefined; }, set currentAlertMode(str) { - return Svc.Prefs.set("errorhandler.alert.mode", str); + return Svc.Prefs ? Svc.Prefs.set("errorhandler.alert.mode", str) : undefined; }, get earliestNextAlert() { - return Svc.Prefs.get("errorhandler.alert.earliestNext", 0) * 1000; + return Svc.Prefs ? Svc.Prefs.get("errorhandler.alert.earliestNext", 0) * 1000 : undefined; }, set earliestNextAlert(msec) { - return Svc.Prefs.set("errorhandler.alert.earliestNext", msec / 1000); + return Svc.Prefs ? Svc.Prefs.set("errorhandler.alert.earliestNext", msec / 1000) : undefined; }, clearServerAlerts: function () { diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index 15884aca0..804eb20cd 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -296,21 +296,6 @@ Sync11Service.prototype = { return false; }, - // The global "enabled" state comes from prefs, and will be set to false - // whenever the UI that exposes what to sync finds all Sync engines disabled. - get enabled() { - return Svc.Prefs.get("enabled"); - }, - set enabled(val) { - // There's no real reason to impose this other than to catch someone doing - // something we don't expect with bad consequences - all setting of this - // pref are in the UI code and external to this module. - if (val) { - throw new Error("Only disabling via this setter is supported"); - } - Svc.Prefs.set("enabled", val); - }, - /** * Prepare to initialize the rest of Weave after waiting a little bit */ @@ -340,6 +325,8 @@ Sync11Service.prototype = { this._clusterManager = this.identity.createClusterManager(this); this.recordManager = new RecordManager(this); + this.enabled = true; + this._registerEngines(); let ua = Cc["@mozilla.org/network/protocol;1?name=http"]. @@ -1236,10 +1223,6 @@ Sync11Service.prototype = { }, sync: function sync() { - if (!this.enabled) { - this._log.debug("Not syncing as Sync is disabled."); - return; - } let dateStr = new Date().toLocaleFormat(LOG_DATE_FORMAT); this._log.debug("User-Agent: " + SyncStorageRequest.prototype.userAgent); this._log.info("Starting sync at " + dateStr); diff --git a/services/sync/modules/util.js b/services/sync/modules/util.js index 7fd5a7971..73f4d8a80 100644 --- a/services/sync/modules/util.js +++ b/services/sync/modules/util.js @@ -321,10 +321,17 @@ this.Utils = { * could not be loaded, the first argument will be undefined. */ jsonLoad: Task.async(function*(filePath, that, callback) { - let path = OS.Path.join(OS.Constants.Path.profileDir, "weave", filePath + ".json"); + let path; + try { + path = OS.Path.normalize(OS.Path.join(OS.Constants.Path.profileDir, "weave", filePath + ".json")); + } catch (e) { + if (that._log) { + that._log.debug("Path join error: " + e); + } + } if (that._log) { - that._log.trace("Loading json from disk: " + filePath); + that._log.trace("Loading json from disk: " + path); } let json; @@ -341,8 +348,9 @@ this.Utils = { } } } - - callback.call(that, json); + if (callback) { + callback.call(that, json); + } }), /** diff --git a/services/sync/services-sync.js b/services/sync/services-sync.js index 640fb4abc..dfce84767 100644 --- a/services/sync/services-sync.js +++ b/services/sync/services-sync.js @@ -24,10 +24,6 @@ pref("services.sync.scheduler.sync11.singleDeviceInterval", 86400); // 1 day pref("services.sync.errorhandler.networkFailureReportTimeout", 1209600); // 2 weeks -// A "master" pref for Sync being enabled. Will be set to false if the sync -// customization UI finds all our builtin engines disabled (and addons are -// free to force this to true if they have their own engine) -pref("services.sync.enabled", true); // Our engines. pref("services.sync.engine.addons", false); pref("services.sync.engine.bookmarks", true); diff --git a/services/sync/tests/unit/test_service_login.js b/services/sync/tests/unit/test_service_login.js index 52ee5e63a..2ecb0a377 100644 --- a/services/sync/tests/unit/test_service_login.js +++ b/services/sync/tests/unit/test_service_login.js @@ -183,7 +183,7 @@ add_test(function test_login_on_sync() { // This test exercises these two branches. _("We're ready to sync if locked."); - Svc.Prefs.set("enabled", true); + Service.enabled = true; Services.io.offline = false; Service.scheduler.checkSyncStatus(); do_check_true(scheduleCalled); diff --git a/testing/profiles/prefs_general.js b/testing/profiles/prefs_general.js index 35680ca43..3ec41b385 100644 --- a/testing/profiles/prefs_general.js +++ b/testing/profiles/prefs_general.js @@ -108,7 +108,6 @@ user_pref("extensions.update.background.url", "http://%(server)s/extensions-dumm user_pref("extensions.blocklist.detailsURL", "http://%(server)s/extensions-dummy/blocklistDetailsURL"); user_pref("extensions.blocklist.itemURL", "http://%(server)s/extensions-dummy/blocklistItemURL"); user_pref("extensions.blocklist.url", "http://%(server)s/extensions-dummy/blocklistURL"); -user_pref("extensions.hotfix.url", "http://%(server)s/extensions-dummy/hotfixURL"); user_pref("extensions.systemAddon.update.url", "http://%(server)s/dummy-system-addons.xml"); // Turn off extension updates so they don't bother tests user_pref("extensions.update.enabled", false); diff --git a/testing/talos/talos/config.py b/testing/talos/talos/config.py index 828e68a15..872bb3543 100644 --- a/testing/talos/talos/config.py +++ b/testing/talos/talos/config.py @@ -123,8 +123,6 @@ DEFAULTS = dict( 'extensions.blocklist.enabled': False, 'extensions.blocklist.url': 'http://127.0.0.1/extensions-dummy/blocklistURL', - 'extensions.hotfix.url': - 'http://127.0.0.1/extensions-dummy/hotfixURL', 'extensions.update.enabled': False, 'extensions.webservice.discoverURL': 'http://127.0.0.1/extensions-dummy/discoveryURL', diff --git a/testing/talos/tests/test_talosconfig_browser_config.json b/testing/talos/tests/test_talosconfig_browser_config.json index 7e7226c9f..b0ba17ad7 100644 --- a/testing/talos/tests/test_talosconfig_browser_config.json +++ b/testing/talos/tests/test_talosconfig_browser_config.json @@ -1 +1 @@ -{'deviceroot': '', 'dirs': {}, 'repository': 'http://hg.mozilla.org/releases/mozilla-release', 'buildid': '20131205075310', 'results_log': 'pathtoresults_log', 'symbols_path': None, 'bcontroller_config': 'pathtobcontroller', 'host': '', 'browser_name': 'Firefox', 'sourcestamp': '39faf812aaec', 'remote': False, 'child_process': 'plugin-container', 'branch_name': '', 'browser_version': '26.0', 'extra_args': '', 'develop': True, 'preferences': {'browser.display.overlaynavbuttons': False, 'extensions.getAddons.get.url': 'http://127.0.0.1/extensions-dummy/repositoryGetURL', 'dom.max_chrome_script_run_time': 0, 'network.proxy.type': 1, 'extensions.update.background.url': 'http://127.0.0.1/extensions-dummy/updateBackgroundURL', 'network.proxy.http': 'localhost', 'plugins.update.url': 'http://127.0.0.1/plugins-dummy/updateCheckURL', 'dom.max_script_run_time': 0, 'extensions.update.enabled': False, 'browser.safebrowsing.keyURL': 'http://127.0.0.1/safebrowsing-dummy/newkey', 'media.navigator.permission.disabled': True, 'app.update.enabled': False, 'extensions.blocklist.url': 'http://127.0.0.1/extensions-dummy/blocklistURL', 'browser.EULA.override': True, 'extensions.checkCompatibility': False, 'talos.logfile': 'pathtofile', 'browser.safebrowsing.gethashURL': 'http://127.0.0.1/safebrowsing-dummy/gethash', 'extensions.hotfix.url': 'http://127.0.0.1/extensions-dummy/hotfixURL', 'dom.disable_window_move_resize': True, 'network.proxy.http_port': 80, 'browser.dom.window.dump.enabled': True, 'extensions.update.url': 'http://127.0.0.1/extensions-dummy/updateURL', 'browser.chrome.dynamictoolbar': False, 'browser.link.open_newwindow': 2, 'extensions.getAddons.search.url': 'http://127.0.0.1/extensions-dummy/repositorySearchURL', 'browser.cache.disk.smart_size.first_run': False, 'security.turn_off_all_security_so_that_viruses_can_take_over_this_computer': True, 'dom.disable_open_during_load': False, 'extensions.getAddons.search.browseURL': 'http://127.0.0.1/extensions-dummy/repositoryBrowseURL', 'browser.cache.disk.smart_size.enabled': False, 'extensions.getAddons.getWithPerformance.url': 'http://127.0.0.1/extensions-dummy/repositoryGetWithPerformanceURL', 'hangmonitor.timeout': 0, 'extensions.getAddons.maxResults': 0, 'dom.send_after_paint_to_content': True, 'security.fileuri.strict_origin_policy': False, 'media.capturestream_hints.enabled': True, 'extensions.update.notifyUser': False, 'extensions.blocklist.enabled': False, 'browser.bookmarks.max_backups': 0, 'browser.shell.checkDefaultBrowser': False, 'media.peerconnection.enabled': True, 'dom.disable_window_flip': True, 'security.enable_java': False, 'browser.warnOnQuit': False, 'media.navigator.enabled': True, 'browser.safebrowsing.updateURL': 'http://127.0.0.1/safebrowsing-dummy/update', 'dom.allow_scripts_to_close_windows': True, 'extensions.webservice.discoverURL': 'http://127.0.0.1/extensions-dummy/discoveryURL'}, 'test_timeout': 1200, 'title': 'qm-pxp01', 'error_filename': 'pathtoerrorfile', 'webserver': 'localhost:15707', 'browser_path':ffox_path, 'port': 20701, 'browser_log': 'browser_output.txt', 'process': 'firefox.exe', 'xperf_path': 'C:/Program Files/Microsoft Windows Performance Toolkit/xperf.exe', 'extensions': ['pathtopageloader'], 'fennecIDs': '', 'env': {'NO_EM_RESTART': '1'}, 'init_url': 'http://localhost:15707/getInfo.html', 'browser_wait': 5}
\ No newline at end of file +{'deviceroot': '', 'dirs': {}, 'repository': 'http://hg.mozilla.org/releases/mozilla-release', 'buildid': '20131205075310', 'results_log': 'pathtoresults_log', 'symbols_path': None, 'bcontroller_config': 'pathtobcontroller', 'host': '', 'browser_name': 'Firefox', 'sourcestamp': '39faf812aaec', 'remote': False, 'child_process': 'plugin-container', 'branch_name': '', 'browser_version': '26.0', 'extra_args': '', 'develop': True, 'preferences': {'browser.display.overlaynavbuttons': False, 'extensions.getAddons.get.url': 'http://127.0.0.1/extensions-dummy/repositoryGetURL', 'dom.max_chrome_script_run_time': 0, 'network.proxy.type': 1, 'extensions.update.background.url': 'http://127.0.0.1/extensions-dummy/updateBackgroundURL', 'network.proxy.http': 'localhost', 'plugins.update.url': 'http://127.0.0.1/plugins-dummy/updateCheckURL', 'dom.max_script_run_time': 0, 'extensions.update.enabled': False, 'browser.safebrowsing.keyURL': 'http://127.0.0.1/safebrowsing-dummy/newkey', 'media.navigator.permission.disabled': True, 'app.update.enabled': False, 'extensions.blocklist.url': 'http://127.0.0.1/extensions-dummy/blocklistURL', 'browser.EULA.override': True, 'extensions.checkCompatibility': False, 'talos.logfile': 'pathtofile', 'browser.safebrowsing.gethashURL': 'http://127.0.0.1/safebrowsing-dummy/gethash', 'dom.disable_window_move_resize': True, 'network.proxy.http_port': 80, 'browser.dom.window.dump.enabled': True, 'extensions.update.url': 'http://127.0.0.1/extensions-dummy/updateURL', 'browser.chrome.dynamictoolbar': False, 'browser.link.open_newwindow': 2, 'extensions.getAddons.search.url': 'http://127.0.0.1/extensions-dummy/repositorySearchURL', 'browser.cache.disk.smart_size.first_run': False, 'security.turn_off_all_security_so_that_viruses_can_take_over_this_computer': True, 'dom.disable_open_during_load': False, 'extensions.getAddons.search.browseURL': 'http://127.0.0.1/extensions-dummy/repositoryBrowseURL', 'browser.cache.disk.smart_size.enabled': False, 'extensions.getAddons.getWithPerformance.url': 'http://127.0.0.1/extensions-dummy/repositoryGetWithPerformanceURL', 'hangmonitor.timeout': 0, 'extensions.getAddons.maxResults': 0, 'dom.send_after_paint_to_content': True, 'security.fileuri.strict_origin_policy': False, 'media.capturestream_hints.enabled': True, 'extensions.update.notifyUser': False, 'extensions.blocklist.enabled': False, 'browser.bookmarks.max_backups': 0, 'browser.shell.checkDefaultBrowser': False, 'media.peerconnection.enabled': True, 'dom.disable_window_flip': True, 'security.enable_java': False, 'browser.warnOnQuit': False, 'media.navigator.enabled': True, 'browser.safebrowsing.updateURL': 'http://127.0.0.1/safebrowsing-dummy/update', 'dom.allow_scripts_to_close_windows': True, 'extensions.webservice.discoverURL': 'http://127.0.0.1/extensions-dummy/discoveryURL'}, 'test_timeout': 1200, 'title': 'qm-pxp01', 'error_filename': 'pathtoerrorfile', 'webserver': 'localhost:15707', 'browser_path':ffox_path, 'port': 20701, 'browser_log': 'browser_output.txt', 'process': 'firefox.exe', 'xperf_path': 'C:/Program Files/Microsoft Windows Performance Toolkit/xperf.exe', 'extensions': ['pathtopageloader'], 'fennecIDs': '', 'env': {'NO_EM_RESTART': '1'}, 'init_url': 'http://localhost:15707/getInfo.html', 'browser_wait': 5} diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 7edded5dc..03dda4a1f 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -18166,6 +18166,18 @@ "url": "/html/browsers/history/the-location-interface/location-stringifier.html" }, { + "path": "html/browsers/history/the-location-interface/location-symbol-toprimitive.html", + "url": "/html/browsers/history/the-location-interface/location-symbol-toprimitive.html" + }, + { + "path": "html/browsers/history/the-location-interface/location-tojson.html", + "url": "/html/browsers/history/the-location-interface/location-tojson.html" + }, + { + "path": "html/browsers/history/the-location-interface/location-valueof.html", + "url": "/html/browsers/history/the-location-interface/location-valueof.html" + }, + { "path": "html/browsers/history/the-location-interface/location_assign.html", "url": "/html/browsers/history/the-location-interface/location_assign.html" }, diff --git a/testing/web-platform/tests/html/browsers/history/the-location-interface/location-stringifier.html b/testing/web-platform/tests/html/browsers/history/the-location-interface/location-stringifier.html index d23323b37..bde54b266 100644 --- a/testing/web-platform/tests/html/browsers/history/the-location-interface/location-stringifier.html +++ b/testing/web-platform/tests/html/browsers/history/the-location-interface/location-stringifier.html @@ -8,4 +8,17 @@ <div id=log></div> <script> test_stringifier_attribute(location, "href", true); + +test(function() { + const prop1 = Object.getOwnPropertyDescriptor(location, "toString"), + prop2 = Object.getOwnPropertyDescriptor(location, "href") + + assert_true(prop1.enumerable) + assert_false(prop1.writable) + assert_false(prop1.configurable) + + assert_true(prop2.enumerable) + assert_false(prop2.configurable) + assert_equals(typeof prop2.get, "function") +}) </script> diff --git a/testing/web-platform/tests/html/browsers/history/the-location-interface/location-symbol-toprimitive.html b/testing/web-platform/tests/html/browsers/history/the-location-interface/location-symbol-toprimitive.html new file mode 100644 index 000000000..e666a3e70 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-location-interface/location-symbol-toprimitive.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<title>Location Symbol.toPrimitive</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(() => { + assert_equals(location[Symbol.toPrimitive], undefined) + const prop = Object.getOwnPropertyDescriptor(location, Symbol.toPrimitive) + assert_false(prop.enumerable) + assert_false(prop.writable) + assert_false(prop.configurable) +}) +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-location-interface/location-tojson.html b/testing/web-platform/tests/html/browsers/history/the-location-interface/location-tojson.html new file mode 100644 index 000000000..5f20a6e15 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-location-interface/location-tojson.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<title>Location has no toJSON</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(() => { + assert_equals(location.toJSON, undefined) + assert_equals(Object.getOwnPropertyDescriptor(location, "toJSON"), undefined) + assert_false(location.hasOwnProperty("toJSON")) +}) +</script> +<!-- See https://github.com/whatwg/html/pull/2294 for context. (And the HTML Standard of course.) --> diff --git a/testing/web-platform/tests/html/browsers/history/the-location-interface/location-valueof.html b/testing/web-platform/tests/html/browsers/history/the-location-interface/location-valueof.html new file mode 100644 index 000000000..978bbb63a --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-location-interface/location-valueof.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>Location valueOf</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(() => { + assert_equals(location.valueOf, Object.prototype.valueOf) + assert_equals(typeof location.valueOf.call(5), "object") + const prop = Object.getOwnPropertyDescriptor(location, "valueOf") + assert_false(prop.enumerable) + assert_false(prop.writable) + assert_false(prop.configurable) +}) +</script> diff --git a/toolkit/components/places/PlacesUtils.jsm b/toolkit/components/places/PlacesUtils.jsm index 323fa41a1..5f6e81f18 100644 --- a/toolkit/components/places/PlacesUtils.jsm +++ b/toolkit/components/places/PlacesUtils.jsm @@ -1341,7 +1341,7 @@ this.PlacesUtils = { * The container node to search through. * @returns true if the node contains uri nodes, false otherwise. */ - hasChildURIs: function PU_hasChildURIs(aNode) { + hasChildURIs: function PU_hasChildURIs(aNode, aMultiple=false) { if (!this.nodeIsContainer(aNode)) return false; @@ -1357,11 +1357,14 @@ this.PlacesUtils = { root.containerOpen = true; } + let foundFirst = !aMultiple; let found = false; for (let i = 0; i < root.childCount && !found; i++) { let child = root.getChild(i); - if (this.nodeIsURI(child)) - found = true; + if (this.nodeIsURI(child)) { + found = foundFirst; + foundFirst = true; + } } if (!wasOpen) { diff --git a/toolkit/components/places/tests/unit/test_utils_getURLsForContainerNode.js b/toolkit/components/places/tests/unit/test_utils_getURLsForContainerNode.js index ecebce94a..3e2f88c21 100644 --- a/toolkit/components/places/tests/unit/test_utils_getURLsForContainerNode.js +++ b/toolkit/components/places/tests/unit/test_utils_getURLsForContainerNode.js @@ -165,6 +165,7 @@ function check_uri_nodes(aQuery, aOptions, aExpectedURINodes) { root.containerOpen = true; var node = root.getChild(0); do_check_eq(PU.hasChildURIs(node), aExpectedURINodes > 0); + do_check_eq(PU.hasChildURIs(node, true), aExpectedURINodes > 1); do_check_eq(PU.getURLsForContainerNode(node).length, aExpectedURINodes); root.containerOpen = false; } diff --git a/toolkit/components/search/nsSearchService.js b/toolkit/components/search/nsSearchService.js index 19f4048b4..f6303bca1 100644 --- a/toolkit/components/search/nsSearchService.js +++ b/toolkit/components/search/nsSearchService.js @@ -780,6 +780,7 @@ EngineURL.prototype = { } var postData = null; + let postDataString = null; if (this.method == "GET") { // GET method requests have no post data, and append the encoded // query string to the url... @@ -787,6 +788,7 @@ EngineURL.prototype = { url += "?"; url += dataString; } else if (this.method == "POST") { + postDataString = dataString; // POST method requests must wrap the encoded text in a MIME // stream and supply that as POSTDATA. var stringStream = Cc["@mozilla.org/io/string-input-stream;1"]. @@ -800,7 +802,7 @@ EngineURL.prototype = { postData.setData(stringStream); } - return new Submission(makeURI(url), postData); + return new Submission(makeURI(url), postData, postDataString); }, _getTermsParameterName: function SRCH_EURL__getTermsParameterName() { @@ -2409,9 +2411,10 @@ Engine.prototype = { }; // nsISearchSubmission -function Submission(aURI, aPostData = null) { +function Submission(aURI, aPostData = null, aPostDataString = null) { this._uri = aURI; this._postData = aPostData; + this._postDataString = aPostDataString; } Submission.prototype = { get uri() { @@ -2420,6 +2423,9 @@ Submission.prototype = { get postData() { return this._postData; }, + get postDataString() { + return this._postDataString; + }, QueryInterface: function SRCH_SUBM_QI(aIID) { if (aIID.equals(Ci.nsISearchSubmission) || aIID.equals(Ci.nsISupports)) diff --git a/toolkit/components/telemetry/TelemetryEnvironment.jsm b/toolkit/components/telemetry/TelemetryEnvironment.jsm index 295679ca4..391ea4bb4 100644 --- a/toolkit/components/telemetry/TelemetryEnvironment.jsm +++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm @@ -196,7 +196,6 @@ const PREF_DISTRIBUTION_ID = "distribution.id"; const PREF_DISTRIBUTION_VERSION = "distribution.version"; const PREF_DISTRIBUTOR = "app.distributor"; const PREF_DISTRIBUTOR_CHANNEL = "app.distributor.channel"; -const PREF_HOTFIX_LASTVERSION = "extensions.hotfix.lastVersion"; const PREF_APP_PARTNER_BRANCH = "app.partner."; const PREF_PARTNER_ID = "mozilla.partner.id"; const PREF_UPDATE_ENABLED = "app.update.enabled"; @@ -1050,7 +1049,6 @@ EnvironmentCache.prototype = { vendor: Services.appinfo.vendor || null, platformVersion: Services.appinfo.platformVersion || null, xpcomAbi: Services.appinfo.XPCOMABI, - hotfixVersion: Preferences.get(PREF_HOTFIX_LASTVERSION, null), }; // Add |architecturesInBinary| only for Mac Universal builds. diff --git a/toolkit/components/telemetry/docs/data/environment.rst b/toolkit/components/telemetry/docs/data/environment.rst index ff0d204a4..0c259fa85 100644 --- a/toolkit/components/telemetry/docs/data/environment.rst +++ b/toolkit/components/telemetry/docs/data/environment.rst @@ -31,7 +31,6 @@ Structure: vendor: <string>, // e.g. "Mozilla" platformVersion: <string>, // e.g. "35.0" xpcomAbi: <string>, // e.g. "x86-msvc" - hotfixVersion: <string>, // e.g. "20141211.01" }, settings: { addonCompatibilityCheckEnabled: <bool>, // Whether application compatibility is respected for add-ons diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js index 35181272a..2518a80ba 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js @@ -33,7 +33,6 @@ const PLATFORM_VERSION = "1.9.2"; const APP_VERSION = "1"; const APP_ID = "xpcshell@tests.mozilla.org"; const APP_NAME = "XPCShell"; -const APP_HOTFIX_VERSION = "2.3.4a"; const DISTRIBUTION_ID = "distributor-id"; const DISTRIBUTION_VERSION = "4.5.6b"; @@ -385,10 +384,8 @@ function checkBuildSection(data) { Assert.equal(data.build[f], expectedInfo[f], f + " must have the correct value."); } - // Make sure architecture and hotfixVersion are in the environment. + // Make sure architecture is in the environment. Assert.ok(checkString(data.build.architecture)); - Assert.ok(checkString(data.build.hotfixVersion)); - Assert.equal(data.build.hotfixVersion, APP_HOTFIX_VERSION); if (gIsMac) { let macUtils = Cc["@mozilla.org/xpcom/mac-utils;1"].getService(Ci.nsIMacUtils); @@ -830,9 +827,6 @@ add_task(function* setup() { gHttpServer.registerDirectory("/data/", do_get_cwd()); do_register_cleanup(() => gHttpServer.stop(() => {})); - // Spoof the the hotfixVersion - Preferences.set("extensions.hotfix.lastVersion", APP_HOTFIX_VERSION); - // Create the attribution data file, so that settings.attribution will exist. // The attribution functionality only exists in Firefox. if (AppConstants.MOZ_BUILD_APP == "browser") { diff --git a/toolkit/content/aboutSupport.js b/toolkit/content/aboutSupport.js index 8908a0f80..06470f966 100644 --- a/toolkit/content/aboutSupport.js +++ b/toolkit/content/aboutSupport.js @@ -53,28 +53,6 @@ var snapshotFormatters = { if (data.updateChannel) $("updatechannel-box").textContent = data.updateChannel; - let statusText = stringBundle().GetStringFromName("multiProcessStatus.unknown"); - - // Whitelist of known values with string descriptions: - switch (data.autoStartStatus) { - case 0: - case 1: - case 2: - case 4: - case 6: - case 7: - case 8: - statusText = stringBundle().GetStringFromName("multiProcessStatus." + data.autoStartStatus); - break; - - case 10: - statusText = (Services.appinfo.OS == "Darwin" ? "OS X 10.6 - 10.8" : "Windows XP"); - break; - } - - $("multiprocess-box").textContent = stringBundle().formatStringFromName("multiProcessWindows", - [data.numRemoteWindows, data.numTotalWindows, statusText], 3); - $("safemode-box").textContent = data.safeMode; }, diff --git a/toolkit/content/aboutSupport.xhtml b/toolkit/content/aboutSupport.xhtml index 5e6319182..fff86dff6 100644 --- a/toolkit/content/aboutSupport.xhtml +++ b/toolkit/content/aboutSupport.xhtml @@ -236,15 +236,6 @@ <tr> <th class="column"> - &aboutSupport.appBasicsMultiProcessSupport; - </th> - - <td id="multiprocess-box"> - </td> - </tr> - - <tr> - <th class="column"> &aboutSupport.appBasicsSafeMode; </th> diff --git a/toolkit/locales/en-US/chrome/global/aboutSupport.dtd b/toolkit/locales/en-US/chrome/global/aboutSupport.dtd index a2477fb2e..34db4e4c4 100644 --- a/toolkit/locales/en-US/chrome/global/aboutSupport.dtd +++ b/toolkit/locales/en-US/chrome/global/aboutSupport.dtd @@ -64,8 +64,6 @@ Windows/Mac use the term "Folder" instead of "Directory" --> <!ENTITY aboutSupport.appBasicsProfiles "Profiles"> -<!ENTITY aboutSupport.appBasicsMultiProcessSupport "Multiprocess Windows"> - <!ENTITY aboutSupport.appBasicsSafeMode "Safe Mode"> <!ENTITY aboutSupport.showDir.label "Open Directory"> diff --git a/toolkit/locales/en-US/chrome/global/aboutSupport.properties b/toolkit/locales/en-US/chrome/global/aboutSupport.properties index 564292e3d..be9ce5f33 100644 --- a/toolkit/locales/en-US/chrome/global/aboutSupport.properties +++ b/toolkit/locales/en-US/chrome/global/aboutSupport.properties @@ -99,23 +99,6 @@ gpuProcessKillButton = Terminate GPU Process minLibVersions = Expected minimum version loadedLibVersions = Version in use -# LOCALIZATION NOTE %1$S and %2$S will be replaced with the number of remote and the total number -# of windows, respectively, while %3$S will be replaced with one of the status strings below, -# which contains a description of the multi-process preference and status. -# Note: multiProcessStatus.3 doesn't exist because status=3 was deprecated. -multiProcessWindows = %1$S/%2$S (%3$S) -multiProcessStatus.0 = Enabled by user -multiProcessStatus.1 = Enabled by default -multiProcessStatus.2 = Disabled -multiProcessStatus.4 = Disabled by accessibility tools -multiProcessStatus.5 = Disabled by lack of graphics hardware acceleration on Mac OS X -multiProcessStatus.6 = Disabled by unsupported text input -multiProcessStatus.7 = Disabled by add-ons -multiProcessStatus.8 = Disabled forcibly -# No longer in use (bug 1296353) but we might bring this back. -multiProcessStatus.9 = Disabled by graphics hardware acceleration on Windows XP -multiProcessStatus.unknown = Unknown status - asyncPanZoom = Asynchronous Pan/Zoom apzNone = none wheelEnabled = wheel input enabled diff --git a/toolkit/locales/l10n.mk b/toolkit/locales/l10n.mk index 05bda0b56..f1825438d 100644 --- a/toolkit/locales/l10n.mk +++ b/toolkit/locales/l10n.mk @@ -112,13 +112,13 @@ repackage-zip: UNPACKAGE='$(ZIP_IN)' repackage-zip: libs-$(AB_CD) # call a hook for apps to put their uninstall helper.exe into the package $(UNINSTALLER_PACKAGE_HOOK) - $(PYTHON) $(MOZILLA_DIR)/toolkit/mozapps/installer/l10n-repack.py $(STAGEDIST) $(DIST)/xpi-stage/locale-$(AB_CD) \ + $(PYTHON) $(MOZILLA_DIR)/toolkit/mozapps/installer/l10n-repack.py '$(STAGEDIST)' $(DIST)/xpi-stage/locale-$(AB_CD) \ $(MOZ_PKG_EXTRAL10N) \ $(if $(filter omni,$(MOZ_PACKAGER_FORMAT)),$(if $(NON_OMNIJAR_FILES),--non-resource $(NON_OMNIJAR_FILES))) ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) ifneq (en,$(LPROJ_ROOT)) - mv $(STAGEDIST)/en.lproj $(STAGEDIST)/$(LPROJ_ROOT).lproj + mv '$(STAGEDIST)'/en.lproj '$(STAGEDIST)'/$(LPROJ_ROOT).lproj endif endif @@ -133,7 +133,7 @@ endif # packaging done, undo l10n stuff ifneq (en,$(LPROJ_ROOT)) ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) - mv $(STAGEDIST)/$(LPROJ_ROOT).lproj $(STAGEDIST)/en.lproj + mv '$(STAGEDIST)'/$(LPROJ_ROOT).lproj '$(STAGEDIST)'/en.lproj endif endif $(NSINSTALL) -D $(DIST)/$(PKG_PATH) @@ -197,7 +197,7 @@ endif generate-snippet-%: $(PYTHON) $(MOZILLA_DIR)/tools/update-packaging/generatesnippet.py \ --mar-path=$(ABS_DIST)/update \ - --application-ini-file=$(STAGEDIST)/application.ini \ + --application-ini-file='$(STAGEDIST)'/application.ini \ --locale=$* \ --product=$(MOZ_PKG_APPNAME) \ --platform=$(MOZ_PKG_PLATFORM) \ diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index ae0eea1c4..40ceb15ba 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -60,13 +60,6 @@ this.AppConstants = Object.freeze({ false, #endif - MOZ_DEV_EDITION: -#ifdef MOZ_DEV_EDITION - true, -#else - false, -#endif - MOZ_SERVICES_HEALTHREPORT: #ifdef MOZ_SERVICES_HEALTHREPORT true, diff --git a/toolkit/modules/Troubleshoot.jsm b/toolkit/modules/Troubleshoot.jsm index 8d84eec8c..6ee6cb54e 100644 --- a/toolkit/modules/Troubleshoot.jsm +++ b/toolkit/modules/Troubleshoot.jsm @@ -220,18 +220,6 @@ var dataProviders = { } } - data.remoteAutoStart = Services.appinfo.browserTabsRemoteAutostart; - - try { - let e10sStatus = Cc["@mozilla.org/supports-PRUint64;1"] - .createInstance(Ci.nsISupportsPRUint64); - let appinfo = Services.appinfo.QueryInterface(Ci.nsIObserver); - appinfo.observe(e10sStatus, "getE10SBlocked", ""); - data.autoStartStatus = e10sStatus.data; - } catch (e) { - data.autoStartStatus = -1; - } - done(data); }, diff --git a/toolkit/modules/tests/browser/browser_Troubleshoot.js b/toolkit/modules/tests/browser/browser_Troubleshoot.js index 4124be1fb..ebc4de1f9 100644 --- a/toolkit/modules/tests/browser/browser_Troubleshoot.js +++ b/toolkit/modules/tests/browser/browser_Troubleshoot.js @@ -126,13 +126,6 @@ const SNAPSHOT_SCHEMA = { supportURL: { type: "string", }, - remoteAutoStart: { - type: "boolean", - required: true, - }, - autoStartStatus: { - type: "number", - }, numTotalWindows: { type: "number", }, diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index 1e185f879..9576e9a3b 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -2153,7 +2153,7 @@ var gDiscoverView = { Ci.nsIWebProgressListener.STATE_IS_REQUEST | Ci.nsIWebProgressListener.STATE_TRANSFERRING; // Once transferring begins show the content - if (aStateFlags & transferStart) + if ((aStateFlags & transferStart) === transferStart) this.node.selectedPanel = this._browser; // Only care about the network events diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index 71a956aa4..dc9324597 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -52,7 +52,7 @@ stage-package: $(MOZ_PKG_MANIFEST) $(MOZ_PKG_MANIFEST_DEPS) $(if $(OPTIMIZEJARS),--optimizejars) \ $(if $(DISABLE_JAR_COMPRESSION),--disable-compression) \ $(addprefix --unify ,$(UNIFY_DIST)) \ - $(MOZ_PKG_MANIFEST) $(DIST) $(DIST)/$(STAGEPATH)$(MOZ_PKG_DIR)$(if $(MOZ_PKG_MANIFEST),,$(_BINPATH)) \ + $(MOZ_PKG_MANIFEST) '$(DIST)' '$(DIST)'/$(STAGEPATH)$(MOZ_PKG_DIR)$(if $(MOZ_PKG_MANIFEST),,$(_BINPATH)) \ $(if $(filter omni,$(MOZ_PACKAGER_FORMAT)),$(if $(NON_OMNIJAR_FILES),--non-resource $(NON_OMNIJAR_FILES))) $(PYTHON) $(MOZILLA_DIR)/toolkit/mozapps/installer/find-dupes.py $(DIST)/$(STAGEPATH)$(MOZ_PKG_DIR) ifdef MOZ_PACKAGE_JSSHELL diff --git a/toolkit/mozapps/installer/upload-files.mk b/toolkit/mozapps/installer/upload-files.mk index 25103ff37..40af34a59 100644 --- a/toolkit/mozapps/installer/upload-files.mk +++ b/toolkit/mozapps/installer/upload-files.mk @@ -286,18 +286,18 @@ endif ifdef MOZ_SIGN_PREPARED_PACKAGE_CMD ifeq (Darwin, $(OS_ARCH)) MAKE_PACKAGE = $(or $(call MAKE_SIGN_EME_VOUCHER,$(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/$(MOZ_CHILD_PROCESS_NAME).app/Contents/MacOS,$(STAGEPATH)$(MOZ_PKG_DIR)$(_RESPATH)),true) \ - && (cd $(STAGEPATH)$(MOZ_PKG_DIR)$(_RESPATH) && $(CREATE_PRECOMPLETE_CMD)) \ - && cd ./$(PKG_DMG_SOURCE) && $(MOZ_SIGN_PREPARED_PACKAGE_CMD) $(MOZ_MACBUNDLE_NAME) \ + && (cd '$(STAGEPATH)$(MOZ_PKG_DIR)$(_RESPATH)' && $(CREATE_PRECOMPLETE_CMD)) \ + && cd ./$(PKG_DMG_SOURCE) && $(MOZ_SIGN_PREPARED_PACKAGE_CMD) '$(MOZ_MACBUNDLE_NAME)' \ && cd $(PACKAGE_BASE_DIR) && $(INNER_MAKE_PACKAGE) else MAKE_PACKAGE = $(MOZ_SIGN_PREPARED_PACKAGE_CMD) $(MOZ_PKG_DIR) \ && $(or $(call MAKE_SIGN_EME_VOUCHER,$(STAGEPATH)$(MOZ_PKG_DIR)),true) \ - && (cd $(STAGEPATH)$(MOZ_PKG_DIR)$(_RESPATH) && $(CREATE_PRECOMPLETE_CMD)) \ + && (cd '$(STAGEPATH)$(MOZ_PKG_DIR)$(_RESPATH)' && $(CREATE_PRECOMPLETE_CMD)) \ && $(INNER_MAKE_PACKAGE) endif #Darwin else - MAKE_PACKAGE = (cd $(STAGEPATH)$(MOZ_PKG_DIR)$(_RESPATH) && $(CREATE_PRECOMPLETE_CMD)) && $(INNER_MAKE_PACKAGE) + MAKE_PACKAGE = (cd '$(STAGEPATH)$(MOZ_PKG_DIR)$(_RESPATH)' && $(CREATE_PRECOMPLETE_CMD)) && $(INNER_MAKE_PACKAGE) endif ifdef MOZ_SIGN_PACKAGE_CMD diff --git a/toolkit/profile/nsToolkitProfileService.cpp b/toolkit/profile/nsToolkitProfileService.cpp index 38b3a37f1..e818d27e6 100644 --- a/toolkit/profile/nsToolkitProfileService.cpp +++ b/toolkit/profile/nsToolkitProfileService.cpp @@ -425,22 +425,6 @@ nsToolkitProfileService::Init() nsToolkitProfile* currentProfile = nullptr; -#ifdef MOZ_DEV_EDITION - nsCOMPtr<nsIFile> ignoreSeparateProfile; - rv = mAppData->Clone(getter_AddRefs(ignoreSeparateProfile)); - if (NS_FAILED(rv)) - return rv; - - rv = ignoreSeparateProfile->AppendNative(NS_LITERAL_CSTRING("ignore-dev-edition-profile")); - if (NS_FAILED(rv)) - return rv; - - bool shouldIgnoreSeparateProfile; - rv = ignoreSeparateProfile->Exists(&shouldIgnoreSeparateProfile); - if (NS_FAILED(rv)) - return rv; -#endif - unsigned int c = 0; bool foundAuroraDefault = false; for (c = 0; true; ++c) { @@ -501,35 +485,8 @@ nsToolkitProfileService::Init() mChosen = currentProfile; this->SetDefaultProfile(currentProfile); } -#ifdef MOZ_DEV_EDITION - // Use the dev-edition-default profile if this is an Aurora build and - // ignore-dev-edition-profile is not present. - if (name.EqualsLiteral("dev-edition-default") && !shouldIgnoreSeparateProfile) { - mChosen = currentProfile; - foundAuroraDefault = true; - } -#endif } -#ifdef MOZ_DEV_EDITION - if (!foundAuroraDefault && !shouldIgnoreSeparateProfile) { - // If a single profile exists, it may not be already marked as default. - // Do it now to avoid problems when we create the dev-edition-default profile. - if (!mChosen && mFirst && !mFirst->mNext) - this->SetDefaultProfile(mFirst); - - // Create a default profile for aurora, if none was found. - nsCOMPtr<nsIToolkitProfile> profile; - rv = CreateProfile(nullptr, - NS_LITERAL_CSTRING("dev-edition-default"), - getter_AddRefs(profile)); - if (NS_FAILED(rv)) return rv; - mChosen = profile; - rv = Flush(); - if (NS_FAILED(rv)) return rv; - } -#endif - if (!mChosen && mFirst && !mFirst->mNext) // only one profile mChosen = mFirst; return NS_OK; diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 5a51fd3e7..035d35a9d 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -2173,9 +2173,9 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n return ShowProfileManager(aProfileSvc, aNative); } -#ifndef MOZ_DEV_EDITION - // If the only existing profile is the dev-edition-profile and this is not - // Developer Edition, then no valid profiles were found. + // Dev edition leftovers: + // If the only existing profile is the dev-edition-profile, + // then no valid profiles were found. if (count == 1) { nsCOMPtr<nsIToolkitProfile> deProfile; // GetSelectedProfile will auto-select the only profile if there's just one @@ -2186,7 +2186,6 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n count = 0; } } -#endif if (!count) { gDoMigration = true; @@ -2195,25 +2194,15 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n // create a default profile nsCOMPtr<nsIToolkitProfile> profile; nsresult rv = aProfileSvc->CreateProfile(nullptr, // choose a default dir for us -#ifdef MOZ_DEV_EDITION - NS_LITERAL_CSTRING("dev-edition-default"), -#else NS_LITERAL_CSTRING("default"), -#endif getter_AddRefs(profile)); if (NS_SUCCEEDED(rv)) { -#ifndef MOZ_DEV_EDITION aProfileSvc->SetDefaultProfile(profile); -#endif aProfileSvc->Flush(); rv = profile->Lock(nullptr, aResult); if (NS_SUCCEEDED(rv)) { if (aProfileName) -#ifdef MOZ_DEV_EDITION - aProfileName->AssignLiteral("dev-edition-default"); -#else aProfileName->AssignLiteral("default"); -#endif return NS_OK; } } diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js index 00a48f359..e449931bd 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/import-browserjs-globals.js @@ -32,7 +32,6 @@ const SCRIPTS = [ "browser/base/content/browser-addons.js", "browser/base/content/browser-ctrlTab.js", "browser/base/content/browser-customization.js", - "browser/base/content/browser-devedition.js", "browser/base/content/browser-feeds.js", "browser/base/content/browser-fullScreenAndPointerLock.js", "browser/base/content/browser-fullZoom.js", diff --git a/tools/update-packaging/common.sh b/tools/update-packaging/common.sh index ec9478035..24f1ca6eb 100755 --- a/tools/update-packaging/common.sh +++ b/tools/update-packaging/common.sh @@ -60,15 +60,15 @@ make_add_instruction() { # before performing this add instruction. testdir=$(echo "$f" | sed 's/\(.*distribution\/extensions\/[^\/]*\)\/.*/\1/') notice " add-if \"$testdir\" \"$f\"" - echo "add-if \"$testdir\" \"$f\"" >> $filev2 + echo "add-if \"$testdir\" \"$f\"" >> "$filev2" if [ ! $filev3 = "" ]; then - echo "add-if \"$testdir\" \"$f\"" >> $filev3 + echo "add-if \"$testdir\" \"$f\"" >> "$filev3" fi else notice " add \"$f\"$forced" - echo "add \"$f\"" >> $filev2 - if [ ! $filev3 = "" ]; then - echo "add \"$f\"" >> $filev3 + echo "add \"$f\"" >> "$filev2" + if [ ! "$filev3" = "" ]; then + echo "add \"$f\"" >> "$filev3" fi fi } @@ -100,7 +100,7 @@ make_add_if_not_instruction() { filev3="$2" notice " add-if-not \"$f\" \"$f\"" - echo "add-if-not \"$f\" \"$f\"" >> $filev3 + echo "add-if-not \"$f\" \"$f\"" >> "$filev3" } make_patch_instruction() { @@ -114,12 +114,12 @@ make_patch_instruction() { # before performing this add instruction. testdir=$(echo "$f" | sed 's/\(.*distribution\/extensions\/[^\/]*\)\/.*/\1/') notice " patch-if \"$testdir\" \"$f.patch\" \"$f\"" - echo "patch-if \"$testdir\" \"$f.patch\" \"$f\"" >> $filev2 - echo "patch-if \"$testdir\" \"$f.patch\" \"$f\"" >> $filev3 + echo "patch-if \"$testdir\" \"$f.patch\" \"$f\"" >> "$filev2" + echo "patch-if \"$testdir\" \"$f.patch\" \"$f\"" >> "$filev3" else notice " patch \"$f.patch\" \"$f\"" - echo "patch \"$f.patch\" \"$f\"" >> $filev2 - echo "patch \"$f.patch\" \"$f\"" >> $filev3 + echo "patch \"$f.patch\" \"$f\"" >> "$filev2" + echo "patch \"$f.patch\" \"$f\"" >> "$filev3" fi } @@ -148,18 +148,18 @@ append_remove_instructions() { if [ ! $(echo "$f" | grep -c '^#') = 1 ]; then if [ $(echo "$f" | grep -c '\/$') = 1 ]; then notice " rmdir \"$f\"" - echo "rmdir \"$f\"" >> $filev2 - echo "rmdir \"$f\"" >> $filev3 + echo "rmdir \"$f\"" >> "$filev2" + echo "rmdir \"$f\"" >> "$filev3" elif [ $(echo "$f" | grep -c '\/\*$') = 1 ]; then # Remove the * f=$(echo "$f" | sed -e 's:\*$::') notice " rmrfdir \"$f\"" - echo "rmrfdir \"$f\"" >> $filev2 - echo "rmrfdir \"$f\"" >> $filev3 + echo "rmrfdir \"$f\"" >> "$filev2" + echo "rmrfdir \"$f\"" >> "$filev3" else notice " remove \"$f\"" - echo "remove \"$f\"" >> $filev2 - echo "remove \"$f\"" >> $filev3 + echo "remove \"$f\"" >> "$filev2" + echo "remove \"$f\"" >> "$filev3" fi fi fi diff --git a/tools/update-packaging/make_full_update.sh b/tools/update-packaging/make_full_update.sh index f0466144d..ba1404474 100755 --- a/tools/update-packaging/make_full_update.sh +++ b/tools/update-packaging/make_full_update.sh @@ -67,13 +67,13 @@ list_files files popd # Add the type of update to the beginning of the update manifests. -> $updatemanifestv2 -> $updatemanifestv3 +> "$updatemanifestv2" +> "$updatemanifestv3" notice "" notice "Adding type instruction to update manifests" notice " type complete" -echo "type \"complete\"" >> $updatemanifestv2 -echo "type \"complete\"" >> $updatemanifestv3 +echo "type \"complete\"" >> "$updatemanifestv2" +echo "type \"complete\"" >> "$updatemanifestv3" notice "" notice "Adding file add instructions to update manifests" diff --git a/widget/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp index 172cb4444..05d8bb0f0 100644 --- a/widget/gtk/nsFilePicker.cpp +++ b/widget/gtk/nsFilePicker.cpp @@ -23,6 +23,7 @@ #include "nsNetUtil.h" #include "nsReadableUtils.h" #include "mozcontainer.h" +#include "mozilla/Preferences.h" #include "nsFilePicker.h" @@ -175,6 +176,7 @@ nsFilePicker::nsFilePicker() , mFileChooserDelegate(nullptr) #endif { + mUseNativeFileChooser = Preferences::GetBool("widget.allow-gtk-native-file-chooser", false); } nsFilePicker::~nsFilePicker() @@ -197,7 +199,7 @@ ReadMultipleFiles(gpointer filename, gpointer array) } void -nsFilePicker::ReadValuesFromFileChooser(GtkWidget *file_chooser) +nsFilePicker::ReadValuesFromFileChooser(void *file_chooser) { mFiles.Clear(); @@ -389,19 +391,10 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback) if (!mOkButtonLabel.IsEmpty()) { accept_button = buttonLabel.get(); } else { - accept_button = (action == GTK_FILE_CHOOSER_ACTION_SAVE) ? - GTK_STOCK_SAVE : GTK_STOCK_OPEN; + accept_button = nullptr; } - GtkWidget *file_chooser = - gtk_file_chooser_dialog_new(title, parent_widget, action, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - accept_button, GTK_RESPONSE_ACCEPT, - nullptr); - gtk_dialog_set_alternative_button_order(GTK_DIALOG(file_chooser), - GTK_RESPONSE_ACCEPT, - GTK_RESPONSE_CANCEL, - -1); + void *file_chooser = GtkFileChooserNew(title.get(), parent_widget, action, accept_button); if (mAllowURLs) { gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), FALSE); } @@ -412,11 +405,7 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback) g_signal_connect(file_chooser, "update-preview", G_CALLBACK(UpdateFilePreviewWidget), img_preview); } - GtkWindow *window = GTK_WINDOW(file_chooser); - gtk_window_set_modal(window, TRUE); - if (parent_widget) { - gtk_window_set_destroy_with_parent(window, TRUE); - } + GtkFileChooserSetModal(file_chooser, parent_widget, TRUE); NS_ConvertUTF16toUTF8 defaultName(mDefault); switch (mMode) { @@ -454,18 +443,21 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback) // Otherwise, if our dialog gets destroyed, we'll lose the dialog's // delegate by the time this gets processed in the event loop. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1166741 - GtkDialog *dialog = GTK_DIALOG(file_chooser); - GtkContainer *area = GTK_CONTAINER(gtk_dialog_get_content_area(dialog)); - gtk_container_forall(area, [](GtkWidget *widget, - gpointer data) { - if (GTK_IS_FILE_CHOOSER_WIDGET(widget)) { - auto result = static_cast<GtkFileChooserWidget**>(data); - *result = GTK_FILE_CHOOSER_WIDGET(widget); - } - }, &mFileChooserDelegate); - - if (mFileChooserDelegate) - g_object_ref(mFileChooserDelegate); + if (GTK_IS_DIALOG(file_chooser)) { + GtkDialog *dialog = GTK_DIALOG(file_chooser); + GtkContainer *area = GTK_CONTAINER(gtk_dialog_get_content_area(dialog)); + gtk_container_forall(area, [](GtkWidget *widget, + gpointer data) { + if (GTK_IS_FILE_CHOOSER_WIDGET(widget)) { + auto result = static_cast<GtkFileChooserWidget**>(data); + *result = GTK_FILE_CHOOSER_WIDGET(widget); + } + }, &mFileChooserDelegate); + + if (mFileChooserDelegate) { + g_object_ref(mFileChooserDelegate); + } + } #endif gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), @@ -473,7 +465,9 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback) } } - gtk_dialog_set_default_response(GTK_DIALOG(file_chooser), GTK_RESPONSE_ACCEPT); + if (GTK_IS_DIALOG(file_chooser)) { + gtk_dialog_set_default_response(GTK_DIALOG(file_chooser), GTK_RESPONSE_ACCEPT); + } int32_t count = mFilters.Length(); for (int32_t i = 0; i < count; ++i) { @@ -517,14 +511,13 @@ nsFilePicker::Open(nsIFilePickerShownCallback *aCallback) mCallback = aCallback; NS_ADDREF_THIS(); g_signal_connect(file_chooser, "response", G_CALLBACK(OnResponse), this); - g_signal_connect(file_chooser, "destroy", G_CALLBACK(OnDestroy), this); - gtk_widget_show(file_chooser); + GtkFileChooserShow(file_chooser); return NS_OK; } /* static */ void -nsFilePicker::OnResponse(GtkWidget* file_chooser, gint response_id, +nsFilePicker::OnResponse(void* file_chooser, gint response_id, gpointer user_data) { static_cast<nsFilePicker*>(user_data)-> @@ -539,7 +532,7 @@ nsFilePicker::OnDestroy(GtkWidget* file_chooser, gpointer user_data) } void -nsFilePicker::Done(GtkWidget* file_chooser, gint response) +nsFilePicker::Done(void* file_chooser, gint response) { mRunning = false; @@ -583,7 +576,7 @@ nsFilePicker::Done(GtkWidget* file_chooser, gint response) // requests that any remaining references be released, but the reference // count will not be decremented again if GtkWindow's reference has already // been released. - gtk_widget_destroy(file_chooser); + GtkFileChooserDestroy(file_chooser); #if (MOZ_WIDGET_GTK == 3) if (mFileChooserDelegate) { @@ -608,3 +601,73 @@ nsFilePicker::Done(GtkWidget* file_chooser, gint response) } NS_RELEASE_THIS(); } + +// All below functions available as of GTK 3.20+ + +void * +nsFilePicker::GtkFileChooserNew( + const gchar *title, GtkWindow *parent, + GtkFileChooserAction action, + const gchar *accept_label) +{ + static auto sGtkFileChooserNativeNewPtr = (void * (*)( + const gchar *, GtkWindow *, + GtkFileChooserAction, + const gchar *, const gchar *)) + dlsym(RTLD_DEFAULT, "gtk_file_chooser_native_new"); + if (mUseNativeFileChooser && sGtkFileChooserNativeNewPtr != nullptr) { + return (*sGtkFileChooserNativeNewPtr)(title, parent, action, accept_label, nullptr); + } + if (accept_label == nullptr) { + accept_label = (action == GTK_FILE_CHOOSER_ACTION_SAVE) + ? GTK_STOCK_SAVE : GTK_STOCK_OPEN; + } + GtkWidget *file_chooser = gtk_file_chooser_dialog_new(title, parent, action, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + accept_label, GTK_RESPONSE_ACCEPT, nullptr); + gtk_dialog_set_alternative_button_order(GTK_DIALOG(file_chooser), + GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1); + return file_chooser; +} + +void +nsFilePicker::GtkFileChooserShow(void *file_chooser) +{ + static auto sGtkNativeDialogShowPtr = (void (*)(void *)) + dlsym(RTLD_DEFAULT, "gtk_native_dialog_show"); + if (mUseNativeFileChooser && sGtkNativeDialogShowPtr != nullptr) { + (*sGtkNativeDialogShowPtr)(file_chooser); + } else { + g_signal_connect(file_chooser, "destroy", G_CALLBACK(OnDestroy), this); + gtk_widget_show(GTK_WIDGET(file_chooser)); + } +} + +void +nsFilePicker::GtkFileChooserDestroy(void *file_chooser) +{ + static auto sGtkNativeDialogDestroyPtr = (void (*)(void *)) + dlsym(RTLD_DEFAULT, "gtk_native_dialog_destroy"); + if (mUseNativeFileChooser && sGtkNativeDialogDestroyPtr != nullptr) { + (*sGtkNativeDialogDestroyPtr)(file_chooser); + } else { + gtk_widget_destroy(GTK_WIDGET(file_chooser)); + } +} + +void +nsFilePicker::GtkFileChooserSetModal(void *file_chooser, + GtkWindow *parent_widget, gboolean modal) +{ + static auto sGtkNativeDialogSetModalPtr = (void (*)(void *, gboolean)) + dlsym(RTLD_DEFAULT, "gtk_native_dialog_set_modal"); + if (mUseNativeFileChooser && sGtkNativeDialogSetModalPtr != nullptr) { + (*sGtkNativeDialogSetModalPtr)(file_chooser, modal); + } else { + GtkWindow *window = GTK_WINDOW(file_chooser); + gtk_window_set_modal(window, modal); + if (parent_widget != nullptr) { + gtk_window_set_destroy_with_parent(window, modal); + } + } +} diff --git a/widget/gtk/nsFilePicker.h b/widget/gtk/nsFilePicker.h index 2b5042098..e0a1d541d 100644 --- a/widget/gtk/nsFilePicker.h +++ b/widget/gtk/nsFilePicker.h @@ -48,12 +48,12 @@ public: protected: virtual ~nsFilePicker(); - void ReadValuesFromFileChooser(GtkWidget *file_chooser); + void ReadValuesFromFileChooser(void *file_chooser); - static void OnResponse(GtkWidget* dialog, gint response_id, + static void OnResponse(void* dialog, gint response_id, gpointer user_data); - static void OnDestroy(GtkWidget* dialog, gpointer user_data); - void Done(GtkWidget* dialog, gint response_id); + static void OnDestroy(GtkWidget* file_chooser, gpointer user_data); + void Done(void* file_chooser, gint response_id); nsCOMPtr<nsIWidget> mParentWidget; nsCOMPtr<nsIFilePickerShownCallback> mCallback; @@ -74,9 +74,19 @@ protected: private: static nsIFile *mPrevDisplayDirectory; + void *GtkFileChooserNew( + const gchar *title, GtkWindow *parent, + GtkFileChooserAction action, + const gchar *accept_label); + void GtkFileChooserShow(void *file_chooser); + void GtkFileChooserDestroy(void *file_chooser); + void GtkFileChooserSetModal(void *file_chooser, GtkWindow* parent_widget, + gboolean modal); + #if (MOZ_WIDGET_GTK == 3) GtkFileChooserWidget *mFileChooserDelegate; #endif + bool mUseNativeFileChooser; }; #endif |