diff --git a/CLOBBER b/CLOBBER index 68d7e52fb0ea..f37a76e82ae7 100644 --- a/CLOBBER +++ b/CLOBBER @@ -18,3 +18,4 @@ # Modifying this file will now automatically clobber the buildbot machines \o/ # Bug 879831 needed to clobber for the removal of jsprobes.cpp +bug 882904: move LIBS to moz.build (logic). diff --git a/accessible/src/generic/HyperTextAccessible.cpp b/accessible/src/generic/HyperTextAccessible.cpp index 94d55192526e..28b0c91dd652 100644 --- a/accessible/src/generic/HyperTextAccessible.cpp +++ b/accessible/src/generic/HyperTextAccessible.cpp @@ -2112,6 +2112,14 @@ HyperTextAccessible::ScrollSubstringToPoint(int32_t aStartIndex, ENameValueFlag HyperTextAccessible::NativeName(nsString& aName) { + // Check @alt attribute for invalid img elements. + bool hasImgAlt = false; + if (mContent->IsHTML(nsGkAtoms::img)) { + hasImgAlt = mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName); + if (!aName.IsEmpty()) + return eNameOK; + } + ENameValueFlag nameFlag = AccessibleWrap::NativeName(aName); if (!aName.IsEmpty()) return nameFlag; @@ -2123,7 +2131,7 @@ HyperTextAccessible::NativeName(nsString& aName) mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) aName.CompressWhitespace(); - return eNameOK; + return hasImgAlt ? eNoNameOnPurpose : eNameOK; } void diff --git a/accessible/src/jsat/content-script.js b/accessible/src/jsat/content-script.js index 92c36b40383a..f9eecbe4fc0c 100644 --- a/accessible/src/jsat/content-script.js +++ b/accessible/src/jsat/content-script.js @@ -16,6 +16,8 @@ XPCOMUtils.defineLazyModuleGetter(this, 'Utils', 'resource://gre/modules/accessibility/Utils.jsm'); XPCOMUtils.defineLazyModuleGetter(this, 'EventManager', 'resource://gre/modules/accessibility/EventManager.jsm'); +XPCOMUtils.defineLazyModuleGetter(this, 'ObjectWrapper', + 'resource://gre/modules/ObjectWrapper.jsm'); Logger.debug('content-script.js'); @@ -182,6 +184,21 @@ function scroll(aMessage) { while (acc) { let elem = acc.DOMNode; + // This is inspired by IndieUI events. Once they are + // implemented, it should be easy to transition to them. + // https://dvcs.w3.org/hg/IndieUI/raw-file/tip/src/indie-ui-events.html#scrollrequest + let uiactions = elem.getAttribute ? elem.getAttribute('uiactions') : ''; + if (uiactions && uiactions.split(' ').indexOf('scroll') >= 0) { + let evt = elem.ownerDocument.createEvent('CustomEvent'); + let details = horiz ? { deltaX: page * elem.clientWidth } : + { deltaY: page * elem.clientHeight }; + evt.initCustomEvent( + 'scrollrequest', true, true, + ObjectWrapper.wrap(details, elem.ownerDocument.defaultView)); + if (!elem.dispatchEvent(evt)) + return; + } + // We will do window scrolling next. if (elem == content.document) break; @@ -202,25 +219,6 @@ function scroll(aMessage) { return true; } } - - let controllers = acc. - getRelationByType( - Ci.nsIAccessibleRelation.RELATION_CONTROLLED_BY); - for (let i = 0; controllers.targetsCount > i; i++) { - let controller = controllers.getTarget(i); - // If the section has a controlling slider, it should be considered - // the page-turner. - if (controller.role == Ci.nsIAccessibleRole.ROLE_SLIDER) { - // Sliders are controlled with ctrl+right/left. I just decided :) - let evt = content.document.createEvent('KeyboardEvent'); - evt.initKeyEvent( - 'keypress', true, true, null, - true, false, false, false, - (page > 0) ? evt.DOM_VK_RIGHT : evt.DOM_VK_LEFT, 0); - controller.DOMNode.dispatchEvent(evt); - return true; - } - } } acc = acc.parent; } diff --git a/accessible/tests/mochitest/name/test_general.html b/accessible/tests/mochitest/name/test_general.html index d28626ae3214..737e523bb6b7 100644 --- a/accessible/tests/mochitest/name/test_general.html +++ b/accessible/tests/mochitest/name/test_general.html @@ -208,6 +208,7 @@ // Test equation image testName("img_eq", "x^2 + y^2 + z^2") + testName("input_img_eq", "x^2 + y^2 + z^2") testName("txt_eq", "x^2 + y^2 + z^2") //////////////////////////////////////////////////////////////////////// @@ -606,6 +607,7 @@

Image: x^2 + y^2 + z^2 +

Text: diff --git a/accessible/tests/mochitest/tree/Makefile.in b/accessible/tests/mochitest/tree/Makefile.in index 9631b3db8f94..900615a966d2 100644 --- a/accessible/tests/mochitest/tree/Makefile.in +++ b/accessible/tests/mochitest/tree/Makefile.in @@ -34,6 +34,7 @@ MOCHITEST_A11Y_FILES =\ test_groupbox.xul \ test_iframe.html \ test_img.html \ + test_invalid_img.xhtml \ test_invalidationlist.html \ test_list.html \ test_map.html \ diff --git a/accessible/tests/mochitest/tree/test_invalid_img.xhtml b/accessible/tests/mochitest/tree/test_invalid_img.xhtml new file mode 100644 index 000000000000..14ada63224ea --- /dev/null +++ b/accessible/tests/mochitest/tree/test_invalid_img.xhtml @@ -0,0 +1,50 @@ + + + invalid html img + + + + + + + + + + + + + + Mozilla Bug 852129 + + +

+ +
+  
+ + 1 + + diff --git a/b2g/app/Makefile.in b/b2g/app/Makefile.in index 0a71a0a17643..3bfbe1df17c5 100644 --- a/b2g/app/Makefile.in +++ b/b2g/app/Makefile.in @@ -51,7 +51,6 @@ STL_FLAGS= LIBS += $(JEMALLOC_LIBS) LIBS += \ - $(EXTRA_DSO_LIBS) \ $(XPCOM_STANDALONE_GLUE_LDOPTS) \ $(NULL) diff --git a/b2g/components/Makefile.in b/b2g/components/Makefile.in index 46c41604d1d5..da26cc6d791d 100644 --- a/b2g/components/Makefile.in +++ b/b2g/components/Makefile.in @@ -9,7 +9,7 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -EXTRA_PP_COMPONENTS = \ +DISABLED_EXTRA_PP_COMPONENTS = \ ActivitiesGlue.js \ AlertsService.js \ B2GAboutRedirector.js \ @@ -36,7 +36,7 @@ EXTRA_JS_MODULES = \ $(NULL) ifdef MOZ_UPDATER -EXTRA_PP_COMPONENTS += UpdatePrompt.js +DISABLED_EXTRA_PP_COMPONENTS += UpdatePrompt.js endif include $(topsrcdir)/config/rules.mk diff --git a/b2g/components/moz.build b/b2g/components/moz.build index 12242bdbdbc6..5b36cdfbada8 100644 --- a/b2g/components/moz.build +++ b/b2g/components/moz.build @@ -12,3 +12,26 @@ XPIDL_SOURCES += [ MODULE = 'B2GComponents' +EXTRA_PP_COMPONENTS += [ + 'ActivitiesGlue.js', + 'AlertsService.js', + 'B2GAboutRedirector.js', + 'B2GComponents.manifest', + 'ContentHandler.js', + 'ContentPermissionPrompt.js', + 'DirectoryProvider.js', + 'FilePicker.js', + 'MailtoProtocolHandler.js', + 'MozKeyboard.js', + 'PaymentGlue.js', + 'ProcessGlobal.js', + 'RecoveryService.js', + 'SmsProtocolHandler.js', + 'TelProtocolHandler.js', + 'YoutubeProtocolHandler.js', +] + +if CONFIG['MOZ_UPDATER']: + EXTRA_PP_COMPONENTS += [ + 'UpdatePrompt.js', + ] diff --git a/browser/app/Makefile.in b/browser/app/Makefile.in index a705fdbd4aa0..c4a5de582de0 100644 --- a/browser/app/Makefile.in +++ b/browser/app/Makefile.in @@ -54,7 +54,6 @@ DEFINES += -DXPCOM_GLUE STL_FLAGS= LIBS += \ - $(EXTRA_DSO_LIBS) \ $(XPCOM_STANDALONE_GLUE_LDOPTS) \ $(NULL) diff --git a/browser/base/content/test/browser_datareporting_notification.js b/browser/base/content/test/browser_datareporting_notification.js index 51c3bdeb7535..b892bd00922f 100644 --- a/browser/base/content/test/browser_datareporting_notification.js +++ b/browser/base/content/test/browser_datareporting_notification.js @@ -23,7 +23,6 @@ function sendNotifyRequest(name) { service.healthReporter.onInit().then(function onInit() { is(policy.ensureNotifyResponse(new Date()), false, "User has not responded to policy."); - is(policy.notifyState, policy.STATE_NOTIFY_WAIT, "Policy is waiting for notification response."); }); return policy; diff --git a/browser/base/content/test/browser_urlbar_search_healthreport.js b/browser/base/content/test/browser_urlbar_search_healthreport.js index 215aa63141bc..4315a98649ed 100644 --- a/browser/base/content/test/browser_urlbar_search_healthreport.js +++ b/browser/base/content/test/browser_urlbar_search_healthreport.js @@ -45,7 +45,7 @@ function test() { gURLBar.value = "firefox health report"; gURLBar.handleCommand(); - executeSoon(function afterSearch() { + executeSoon(() => executeSoon(() => { gBrowser.removeTab(tab); m.getValues().then(function onData(data) { @@ -58,7 +58,7 @@ function test() { is(newCount, oldCount + 1, "Exactly one search has been recorded."); finish(); }); - }); + })); }); }); } diff --git a/browser/components/Makefile.in b/browser/components/Makefile.in index dc685b3f9e5f..a70f997846c2 100644 --- a/browser/components/Makefile.in +++ b/browser/components/Makefile.in @@ -13,7 +13,7 @@ DISABLED_EXTRA_COMPONENTS = \ BrowserComponents.manifest \ $(NULL) -EXTRA_PP_COMPONENTS = \ +DISABLED_EXTRA_PP_COMPONENTS = \ nsBrowserContentHandler.js \ nsBrowserGlue.js \ $(NULL) diff --git a/browser/components/feeds/src/Makefile.in b/browser/components/feeds/src/Makefile.in index 904a5d79920d..afd42cf6f0ef 100644 --- a/browser/components/feeds/src/Makefile.in +++ b/browser/components/feeds/src/Makefile.in @@ -25,7 +25,7 @@ DISABLED_EXTRA_COMPONENTS = \ WebContentConverter.js \ $(NULL) -EXTRA_PP_COMPONENTS = \ +DISABLED_EXTRA_PP_COMPONENTS = \ FeedWriter.js \ $(NULL) diff --git a/browser/components/feeds/src/moz.build b/browser/components/feeds/src/moz.build index e97a4f0ab691..f79e0f956b33 100644 --- a/browser/components/feeds/src/moz.build +++ b/browser/components/feeds/src/moz.build @@ -15,3 +15,7 @@ EXTRA_COMPONENTS += [ 'FeedConverter.js', 'WebContentConverter.js', ] + +EXTRA_PP_COMPONENTS += [ + 'FeedWriter.js', +] diff --git a/browser/components/migration/src/Makefile.in b/browser/components/migration/src/Makefile.in index 017d5f6fc8d2..ab7afa2202d6 100644 --- a/browser/components/migration/src/Makefile.in +++ b/browser/components/migration/src/Makefile.in @@ -19,7 +19,7 @@ DISABLED_EXTRA_COMPONENTS = \ FirefoxProfileMigrator.js \ $(NULL) -EXTRA_PP_COMPONENTS = \ +DISABLED_EXTRA_PP_COMPONENTS = \ ChromeProfileMigrator.js \ $(NULL) @@ -27,19 +27,19 @@ ifeq ($(OS_ARCH),WINNT) DISABLED_EXTRA_COMPONENTS += IEProfileMigrator.js \ $(NULL) -EXTRA_PP_COMPONENTS += SafariProfileMigrator.js \ +DISABLED_EXTRA_PP_COMPONENTS += SafariProfileMigrator.js \ $(NULL) DEFINES += -DHAS_IE_MIGRATOR -DHAS_SAFARI_MIGRATOR endif ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) -EXTRA_PP_COMPONENTS += SafariProfileMigrator.js \ +DISABLED_EXTRA_PP_COMPONENTS += SafariProfileMigrator.js \ $(NULL) DEFINES += -DHAS_SAFARI_MIGRATOR endif -EXTRA_PP_COMPONENTS += \ +DISABLED_EXTRA_PP_COMPONENTS += \ BrowserProfileMigrators.manifest \ $(NULL) diff --git a/browser/components/migration/src/moz.build b/browser/components/migration/src/moz.build index e98f9e082ea0..211f79e22e1e 100644 --- a/browser/components/migration/src/moz.build +++ b/browser/components/migration/src/moz.build @@ -20,3 +20,18 @@ if CONFIG['OS_ARCH'] == 'WINNT': EXTRA_COMPONENTS += [ 'IEProfileMigrator.js', ] + +EXTRA_PP_COMPONENTS += [ + 'BrowserProfileMigrators.manifest', + 'ChromeProfileMigrator.js', +] + +if CONFIG['OS_ARCH'] == 'WINNT': + EXTRA_PP_COMPONENTS += [ + 'SafariProfileMigrator.js', + ] + +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + EXTRA_PP_COMPONENTS += [ + 'SafariProfileMigrator.js', + ] diff --git a/browser/components/moz.build b/browser/components/moz.build index dc73374babdb..1e2aa74ac939 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -39,3 +39,7 @@ MODULE = 'browsercomps' EXTRA_COMPONENTS += [ 'BrowserComponents.manifest', ] +EXTRA_PP_COMPONENTS += [ + 'nsBrowserContentHandler.js', + 'nsBrowserGlue.js', +] diff --git a/browser/components/search/test/browser_healthreport.js b/browser/components/search/test/browser_healthreport.js index d70191560df0..58dc9d881ab5 100644 --- a/browser/components/search/test/browser_healthreport.js +++ b/browser/components/search/test/browser_healthreport.js @@ -66,7 +66,7 @@ function test() { } EventUtils.synthesizeKey("VK_RETURN", {}); - executeSoon(afterSearch); + executeSoon(() => executeSoon(afterSearch)); }); }); } diff --git a/browser/devtools/styleeditor/StyleEditorPanel.jsm b/browser/devtools/styleeditor/StyleEditorPanel.jsm index 0cfa54b4e360..783dfe84d9e9 100644 --- a/browser/devtools/styleeditor/StyleEditorPanel.jsm +++ b/browser/devtools/styleeditor/StyleEditorPanel.jsm @@ -91,16 +91,16 @@ StyleEditorPanel.prototype = { * @param {string} href * Url of stylesheet to find and select in editor * @param {number} line - * Line number to jump to after selecting + * Line number to jump to after selecting. One-indexed * @param {number} col - * Column number to jump to after selecting + * Column number to jump to after selecting. One-indexed */ selectStyleSheet: function(href, line, col) { if (!this._debuggee || !this.UI) { return; } let stylesheet = this._debuggee.styleSheetFromHref(href); - this.UI.selectStyleSheet(href, line, col); + this.UI.selectStyleSheet(href, line - 1, col - 1); }, /** diff --git a/browser/devtools/styleeditor/StyleEditorUI.jsm b/browser/devtools/styleeditor/StyleEditorUI.jsm index d89e3c6e7668..3ddca7022cd7 100644 --- a/browser/devtools/styleeditor/StyleEditorUI.jsm +++ b/browser/devtools/styleeditor/StyleEditorUI.jsm @@ -48,7 +48,7 @@ function StyleEditorUI(debuggee, panelDoc) { this._root = this._panelDoc.getElementById("style-editor-chrome"); this.editors = []; - this.selectedStyleSheetIndex = -1; + this.selectedEditor = null; this._onStyleSheetCreated = this._onStyleSheetCreated.bind(this); this._onStyleSheetsCleared = this._onStyleSheetsCleared.bind(this); @@ -84,6 +84,14 @@ StyleEditorUI.prototype = { this._markedDirty = value; }, + /* + * Index of selected stylesheet in document.styleSheets + */ + get selectedStyleSheetIndex() { + return this.selectedEditor ? + this.selectedEditor.styleSheet.styleSheetIndex : -1; + }, + /** * Build the initial UI and wire buttons with event handlers. */ @@ -140,10 +148,17 @@ StyleEditorUI.prototype = { * Handler for debuggee's 'stylesheets-cleared' event. Remove all editors. */ _onStyleSheetsCleared: function() { - this._clearStyleSheetEditors(); + // remember selected sheet and line number for next load + if (this.selectedEditor) { + let href = this.selectedEditor.styleSheet.href; + let {line, col} = this.selectedEditor.sourceEditor.getCaretPosition(); + this.selectStyleSheet(href, line, col); + } + this._clearStyleSheetEditors(); this._view.removeAll(); - this.selectedStyleSheetIndex = -1; + + this.selectedEditor = null; this._root.classList.add("loading"); }, @@ -166,11 +181,22 @@ StyleEditorUI.prototype = { * StyleSheet object for new sheet */ _onDocumentLoad: function(event, styleSheets) { + if (this._styleSheetToSelect) { + // if selected stylesheet from previous load isn't here, + // just set first stylesheet to be selected instead + let selectedExists = styleSheets.some((sheet) => { + return this._styleSheetToSelect.href == sheet.href; + }) + if (!selectedExists) { + this._styleSheetToSelect = null; + } + } for (let sheet of styleSheets) { this._addStyleSheetEditor(sheet); } - // this might be the first stylesheet, so remove loading indicator + this._root.classList.remove("loading"); + this.emit("document-load"); }, @@ -295,13 +321,18 @@ StyleEditorUI.prototype = { onShow: function(summary, details, data) { let editor = data.editor; + this.selectedEditor = editor; + this._styleSheetToSelect = null; + if (!editor.sourceEditor) { // only initialize source editor when we switch to this view let inputElement = details.querySelector(".stylesheet-editor-input"); editor.load(inputElement); } editor.onShow(); - } + + this.emit("editor-selected", editor); + }.bind(this) }); }, @@ -314,7 +345,6 @@ StyleEditorUI.prototype = { for each (let editor in this.editors) { if (editor.styleSheet.href == sheet.href) { this._selectEditor(editor, sheet.line, sheet.col); - this._styleSheetToSelect = null; break; } } @@ -331,18 +361,14 @@ StyleEditorUI.prototype = { * Column number to jump to */ _selectEditor: function(editor, line, col) { - line = line || 1; - col = col || 1; - - this.selectedStyleSheetIndex = editor.styleSheet.styleSheetIndex; + line = line || 0; + col = col || 0; editor.getSourceEditor().then(() => { - editor.sourceEditor.setCaretPosition(line - 1, col - 1); + editor.sourceEditor.setCaretPosition(line, col); }); this._view.activeSummary = editor.summary; - - this.emit("editor-selected", editor); }, /** @@ -354,9 +380,9 @@ StyleEditorUI.prototype = { * a stylesheet is not passed and the editor is initialized we ignore * the call. * @param {Number} [line] - * Line to which the caret should be moved (one-indexed). + * Line to which the caret should be moved (zero-indexed). * @param {Number} [col] - * Column to which the caret should be moved (one-indexed). + * Column to which the caret should be moved (zero-indexed). */ selectStyleSheet: function(href, line, col) { diff --git a/browser/devtools/styleeditor/test/Makefile.in b/browser/devtools/styleeditor/test/Makefile.in index f80625eadb43..c43c941e6409 100644 --- a/browser/devtools/styleeditor/test/Makefile.in +++ b/browser/devtools/styleeditor/test/Makefile.in @@ -28,6 +28,7 @@ _BROWSER_TEST_FILES = \ browser_styleeditor_bug_740541_iframes.js \ browser_styleeditor_bug_851132_middle_click.js \ browser_styleeditor_nostyle.js \ + browser_styleeditor_reload.js \ head.js \ four.html \ head.js \ diff --git a/browser/devtools/styleeditor/test/browser_styleeditor_reload.js b/browser/devtools/styleeditor/test/browser_styleeditor_reload.js new file mode 100644 index 000000000000..267fbcffeb08 --- /dev/null +++ b/browser/devtools/styleeditor/test/browser_styleeditor_reload.js @@ -0,0 +1,99 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const TESTCASE_URI = TEST_BASE_HTTPS + "simple.html"; +const NEW_URI = TEST_BASE_HTTPS + "media.html"; + +const LINE_NO = 5; +const COL_NO = 3; + +let gContentWin; +let gUI; + +function test() +{ + waitForExplicitFinish(); + + addTabAndOpenStyleEditor(function(panel) { + gContentWin = gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject; + gUI = panel.UI; + + let count = 0; + gUI.on("editor-added", function editorAdded(event, editor) { + if (++count == 2) { + gUI.off("editor-added", editorAdded); + gUI.editors[0].getSourceEditor().then(runTests); + } + }) + }); + + content.location = TESTCASE_URI; +} + +function runTests() +{ + let count = 0; + gUI.once("editor-selected", (event, editor) => { + editor.getSourceEditor().then(() => { + info("selected second editor, about to reload page"); + reloadPage(); + + gUI.on("editor-added", function editorAdded(event, editor) { + if (++count == 2) { + gUI.off("editor-added", editorAdded); + gUI.editors[1].getSourceEditor().then(testRemembered); + } + }) + }); + }); + gUI.selectStyleSheet(gUI.editors[1].styleSheet.href, LINE_NO, COL_NO); +} + +function testRemembered() +{ + is(gUI.selectedEditor, gUI.editors[1], "second editor is selected"); + + let {line, col} = gUI.selectedEditor.sourceEditor.getCaretPosition(); + is(line, LINE_NO, "correct line selected"); + is(col, COL_NO, "correct column selected"); + + testNewPage(); +} + +function testNewPage() +{ + let count = 0; + gUI.on("editor-added", function editorAdded(event, editor) { + info("editor added here") + if (++count == 2) { + gUI.off("editor-added", editorAdded); + gUI.editors[0].getSourceEditor().then(testNotRemembered); + } + }) + + info("navigating to a different page"); + navigatePage(); +} + +function testNotRemembered() +{ + is(gUI.selectedEditor, gUI.editors[0], "first editor is selected"); + + let {line, col} = gUI.selectedEditor.sourceEditor.getCaretPosition(); + is(line, 0, "first line is selected"); + is(col, 0, "first column is selected"); + + gUI = null; + finish(); +} + +function reloadPage() +{ + gContentWin.location.reload(); +} + +function navigatePage() +{ + gContentWin.location = NEW_URI; +} \ No newline at end of file diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js index 42524a7c1909..893401be63a3 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_770099_violation.js @@ -8,7 +8,7 @@ // Tests that the Web Console CSP messages are displayed const TEST_VIOLATION = "https://example.com/browser/browser/devtools/webconsole/test/test_bug_770099_violation.html"; -const CSP_VIOLATION_MSG = "CSP WARN: Directive default-src https://example.com:443 violated by http://some.example.com/test.png" +const CSP_VIOLATION_MSG = "Content Security Policy: Directive default-src https://example.com:443 violated by http://some.example.com/test.png" let hud = undefined; diff --git a/browser/fuel/src/Makefile.in b/browser/fuel/src/Makefile.in index 8166aedd9f31..79b5c91a1e7f 100644 --- a/browser/fuel/src/Makefile.in +++ b/browser/fuel/src/Makefile.in @@ -10,6 +10,6 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk DISABLED_EXTRA_COMPONENTS = fuelApplication.manifest -EXTRA_PP_COMPONENTS = fuelApplication.js +DISABLED_EXTRA_PP_COMPONENTS = fuelApplication.js include $(topsrcdir)/config/rules.mk diff --git a/browser/fuel/src/moz.build b/browser/fuel/src/moz.build index d7f2cd6af472..1fc5a0135ddc 100644 --- a/browser/fuel/src/moz.build +++ b/browser/fuel/src/moz.build @@ -9,3 +9,7 @@ MODULE = 'fuel' EXTRA_COMPONENTS += [ 'fuelApplication.manifest', ] + +EXTRA_PP_COMPONENTS += [ + 'fuelApplication.js', +] diff --git a/browser/metro/base/content/contenthandlers/Content.js b/browser/metro/base/content/contenthandlers/Content.js index e7948ba921c2..53c63d184379 100644 --- a/browser/metro/base/content/contenthandlers/Content.js +++ b/browser/metro/base/content/contenthandlers/Content.js @@ -143,7 +143,7 @@ let Content = { // pages have any privilege themselves. addEventListener("click", this, false); - docShell.QueryInterface(Ci.nsIDocShellHistory).useGlobalHistory = true; + docShell.useGlobalHistory = true; }, /******************************************* diff --git a/browser/metro/components/Makefile.in b/browser/metro/components/Makefile.in index 4e89f862bdf1..667adf897778 100644 --- a/browser/metro/components/Makefile.in +++ b/browser/metro/components/Makefile.in @@ -11,7 +11,7 @@ include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/config.mk # metro/components.manifest -EXTRA_PP_COMPONENTS = \ +DISABLED_EXTRA_PP_COMPONENTS = \ components.manifest \ AboutRedirector.js \ BrowserCLH.js \ diff --git a/browser/metro/components/moz.build b/browser/metro/components/moz.build index 26492f18f30a..f83a3d104da4 100644 --- a/browser/metro/components/moz.build +++ b/browser/metro/components/moz.build @@ -10,3 +10,14 @@ XPIDL_SOURCES += [ MODULE = 'components' +# metro/components.manifest +EXTRA_PP_COMPONENTS += [ + 'AboutRedirector.js', + 'BrowserCLH.js', + 'BrowserStartup.js', + 'DirectoryProvider.js', + 'HelperAppDialog.js', + 'SessionStore.js', + 'Sidebar.js', + 'components.manifest', +] diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index 92a7f03c8737..9e7d704cf472 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -2090,7 +2090,7 @@ nsScriptSecurityManager::old_doGetObjectPrincipal(JS::Handle aObj, // Note: jsClass is set before this loop, and also at the // *end* of this loop. - if (IS_WRAPPER_CLASS(jsClass)) { + if (IS_WN_CLASS(jsClass)) { result = nsXPConnect::XPConnect()->GetPrincipal(obj, aAllowShortCircuit); if (result) { diff --git a/config/makefiles/debugmake.mk b/config/makefiles/debugmake.mk index dd21734003e7..6e193947e4da 100644 --- a/config/makefiles/debugmake.mk +++ b/config/makefiles/debugmake.mk @@ -50,7 +50,6 @@ ifneq (,$(filter $(PROGRAM) $(HOST_PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $ @echo "IMPORT_LIBRARY = $(IMPORT_LIBRARY)" @echo "STATIC_LIBS = $(STATIC_LIBS)" @echo "SHARED_LIBS = $(SHARED_LIBS)" - @echo "EXTRA_DSO_LIBS = $(EXTRA_DSO_LIBS)" @echo "EXTRA_DSO_LDOPTS = $(EXTRA_DSO_LDOPTS)" @echo "DEPENDENT_LIBS = $(DEPENDENT_LIBS)" @echo -------------------------------------------------------------------------------- diff --git a/config/rules.mk b/config/rules.mk index 42ecc25f2ee7..ec293c3cc8fc 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -110,10 +110,6 @@ endif # ifndef .PYMAKE _VPATH_SRCS = $(abspath $<) -ifdef EXTRA_DSO_LIBS -EXTRA_DSO_LIBS := $(call EXPAND_MOZLIBNAME,$(EXTRA_DSO_LIBS)) -endif - ################################################################################ # Testing frameworks support ################################################################################ diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 710c0ba465ec..3b130e2ffb60 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -766,7 +766,9 @@ public: * Get this document's inline style sheet. May return null if there * isn't one */ - virtual nsHTMLCSSStyleSheet* GetInlineStyleSheet() const = 0; + nsHTMLCSSStyleSheet* GetInlineStyleSheet() const { + return mStyleAttrStyleSheet; + } /** * Get/set the object from which a document can get a script context @@ -2178,6 +2180,7 @@ protected: nsRefPtr mCSSLoader; nsRefPtr mStyleImageLoader; nsRefPtr mAttrStyleSheet; + nsRefPtr mStyleAttrStyleSheet; // The set of all object, embed, applet, video and audio elements for // which this is the owner document. (They might not be in the document.) diff --git a/content/base/src/CSPUtils.jsm b/content/base/src/CSPUtils.jsm index dcc3afb5c112..9d17d5de7bdb 100644 --- a/content/base/src/CSPUtils.jsm +++ b/content/base/src/CSPUtils.jsm @@ -13,6 +13,9 @@ const Cu = Components.utils; const Ci = Components.interfaces; +const WARN_FLAG = Ci.nsIScriptError.warningFlag; +const ERROR_FLAG = Ci.nsIScriptError.ERROR_FLAG; + Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); @@ -842,7 +845,7 @@ CSPRep.prototype = { // However, our original CSP implementation required a default src // or an allow directive. if (!defaultSrcDir && !this._specCompliant) { - this.warn(CSPLocalizer.getStr("allowOrDefaultSrcRequired")); + this.log(WARN_FLAG, CSPLocalizer.getStr("allowOrDefaultSrcRequired")); return false; } @@ -888,7 +891,9 @@ CSPRep.prototype = { }, /** - * Sends a warning message to the error console and web developer console. + * Sends a message to the error console and web developer console. + * @param aFlag + * The nsIScriptError flag constant indicating severity * @param aMsg * The message to send * @param aSource (optional) @@ -898,50 +903,25 @@ CSPRep.prototype = { * @param aLineNum (optional) * The number of the line where the error occurred */ - warn: - function cspd_warn(aMsg, aSource, aScriptLine, aLineNum) { - var textMessage = 'CSP WARN: ' + aMsg + "\n"; - + log: + function cspd_log(aFlag, aMsg, aSource, aScriptLine, aLineNum) { + var textMessage = "Content Security Policy: " + aMsg; var consoleMsg = Components.classes["@mozilla.org/scripterror;1"] .createInstance(Ci.nsIScriptError); if (this._innerWindowID) { consoleMsg.initWithWindowID(textMessage, aSource, aScriptLine, aLineNum, - 0, Ci.nsIScriptError.warningFlag, - "Content Security Policy", + 0, aFlag, + "CSP", this._innerWindowID); } else { consoleMsg.init(textMessage, aSource, aScriptLine, aLineNum, 0, - Ci.nsIScriptError.warningFlag, - "Content Security Policy"); + aFlag, + "CSP"); } Components.classes["@mozilla.org/consoleservice;1"] .getService(Ci.nsIConsoleService).logMessage(consoleMsg); }, - /** - * Sends an error message to the error console and web developer console. - * @param aMsg - * The message to send - */ - error: - function cspsd_error(aMsg) { - var textMessage = 'CSP ERROR: ' + aMsg + "\n"; - - var consoleMsg = Components.classes["@mozilla.org/scripterror;1"] - .createInstance(Ci.nsIScriptError); - if (this._innerWindowID) { - consoleMsg.initWithWindowID(textMessage, null, null, 0, 0, - Ci.nsIScriptError.errorFlag, - "Content Security Policy", - this._innerWindowID); - } - else { - consoleMsg.init(textMessage, null, null, 0, 0, - Ci.nsIScriptError.errorFlag, "Content Security Policy"); - } - Components.classes["@mozilla.org/consoleservice;1"] - .getService(Ci.nsIConsoleService).logMessage(consoleMsg); - }, }; ////////////////////////////////////////////////////////////////////// @@ -1967,17 +1947,17 @@ function innerWindowFromRequest(docRequest) { function cspError(aCSPRep, aMessage) { if (aCSPRep) { - aCSPRep.error(aMessage); + aCSPRep.log(ERROR_FLAG, aMessage); } else { - (new CSPRep()).error(aMessage); + (new CSPRep()).log(ERROR_FLAG, aMessage); } } function cspWarn(aCSPRep, aMessage) { if (aCSPRep) { - aCSPRep.warn(aMessage); + aCSPRep.log(WARN_FLAG, aMessage); } else { - (new CSPRep()).warn(aMessage); + (new CSPRep()).log(WARN_FLAG, aMessage); } } diff --git a/content/base/src/Makefile.in b/content/base/src/Makefile.in index eb061b5b48e2..7ddedb42f8ce 100644 --- a/content/base/src/Makefile.in +++ b/content/base/src/Makefile.in @@ -34,7 +34,7 @@ EXTRA_COMPONENTS = \ messageWakeupService.manifest \ $(NULL) -EXTRA_PP_COMPONENTS = \ +DISABLED_EXTRA_PP_COMPONENTS = \ contentSecurityPolicy.js \ $(NULL) diff --git a/content/base/src/contentSecurityPolicy.js b/content/base/src/contentSecurityPolicy.js index f3054742edc1..400d408aeabc 100644 --- a/content/base/src/contentSecurityPolicy.js +++ b/content/base/src/contentSecurityPolicy.js @@ -25,6 +25,9 @@ const CSP_VIOLATION_TOPIC = "csp-on-violate-policy"; const CSP_TYPE_XMLHTTPREQUEST_SPEC_COMPLIANT = "csp_type_xmlhttprequest_spec_compliant"; const CSP_TYPE_WEBSOCKET_SPEC_COMPLIANT = "csp_type_websocket_spec_compliant"; +const WARN_FLAG = Ci.nsIScriptError.warningFlag; +const ERROR_FLAG = Ci.nsIScriptError.ERROR_FLAG; + Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/CSPUtils.jsm"); @@ -180,13 +183,13 @@ ContentSecurityPolicy.prototype = { break; case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_INLINE_SCRIPT: if (!this._policy.allowsInlineScripts) - this._asyncReportViolation('self',null,'inline script base restriction', + this._asyncReportViolation('self', null, 'inline script base restriction', 'violated base restriction: Inline Scripts will not execute', aSourceFile, aScriptSample, aLineNum); break; case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_EVAL: if (!this._policy.allowsEvalInScripts) - this._asyncReportViolation('self',null,'eval script base restriction', + this._asyncReportViolation('self', null, 'eval script base restriction', 'violated base restriction: Code will not be created from strings', aSourceFile, aScriptSample, aLineNum); break; @@ -360,7 +363,7 @@ ContentSecurityPolicy.prototype = { } else { violationMessage = CSPLocalizer.getFormatStr("directiveViolated", [violatedDirective]); } - this._policy.warn(violationMessage, + this._policy.log(WARN_FLAG, violationMessage, (aSourceFile) ? aSourceFile : null, (aScriptSample) ? decodeURIComponent(aScriptSample) : null, (aLineNum) ? aLineNum : null); @@ -425,8 +428,8 @@ ContentSecurityPolicy.prototype = { } catch(e) { // it's possible that the URI was invalid, just log a // warning and skip over that. - this._policy.warn(CSPLocalizer.getFormatStr("triedToSendReport", [uris[i]])); - this._policy.warn(CSPLocalizer.getFormatStr("errorWas", [e.toString()])); + this._policy.log(WARN_FLAG, CSPLocalizer.getFormatStr("triedToSendReport", [uris[i]])); + this._policy.log(WARN_FLAG, CSPLocalizer.getFormatStr("errorWas", [e.toString()])); } } } @@ -663,7 +666,7 @@ CSPReportRedirectSink.prototype = { // nsIChannelEventSink asyncOnChannelRedirect: function channel_redirect(oldChannel, newChannel, flags, callback) { - this._policy.warn(CSPLocalizer.getFormatStr("reportPostRedirect", [oldChannel.URI.asciiSpec])); + this._policy.log(WARN_FLAG, CSPLocalizer.getFormatStr("reportPostRedirect", [oldChannel.URI.asciiSpec])); // cancel the old channel so XHR failure callback happens oldChannel.cancel(Cr.NS_ERROR_ABORT); diff --git a/content/base/src/moz.build b/content/base/src/moz.build index 383955bcde61..277a6e2203d8 100644 --- a/content/base/src/moz.build +++ b/content/base/src/moz.build @@ -153,3 +153,6 @@ CPP_SOURCES += [ 'nsXMLNameSpaceMap.cpp', ] +EXTRA_PP_COMPONENTS += [ + 'contentSecurityPolicy.js', +] diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 4184ba13ba47..713bd60cbaa5 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1478,8 +1478,6 @@ nsDocument::~nsDocument() if (mAttrStyleSheet) { mAttrStyleSheet->SetOwningDocument(nullptr); } - if (mStyleAttrStyleSheet) - mStyleAttrStyleSheet->SetOwningDocument(nullptr); if (mListenerManager) { mListenerManager->Disconnect(); @@ -1539,7 +1537,6 @@ NS_INTERFACE_TABLE_HEAD(nsDocument) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentTouch) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsITouchEventReceiver) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIInlineEventHandlers) - NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocumentRegister) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver) NS_INTERFACE_TABLE_END NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument) @@ -2234,37 +2231,16 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) // Now reset our inline style and attribute sheets. if (mAttrStyleSheet) { - // Remove this sheet from all style sets - nsCOMPtr shell = GetShell(); - if (shell) { - shell->StyleSet()->RemoveStyleSheet(nsStyleSet::ePresHintSheet, - mAttrStyleSheet); - } - mAttrStyleSheet->Reset(aURI); + mAttrStyleSheet->Reset(); + mAttrStyleSheet->SetOwningDocument(this); } else { - mAttrStyleSheet = new nsHTMLStyleSheet(aURI, this); + mAttrStyleSheet = new nsHTMLStyleSheet(this); } - // Don't use AddStyleSheet, since it'll put the sheet into style - // sets in the document level, which is not desirable here. - mAttrStyleSheet->SetOwningDocument(this); - - if (mStyleAttrStyleSheet) { - // Remove this sheet from all style sets - nsCOMPtr shell = GetShell(); - if (shell) { - shell->StyleSet()-> - RemoveStyleSheet(nsStyleSet::eStyleAttrSheet, mStyleAttrStyleSheet); - } - mStyleAttrStyleSheet->Reset(aURI); - } else { - mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet(aURI, this); + if (!mStyleAttrStyleSheet) { + mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet(); } - // The loop over style sets below will handle putting this sheet - // into style sets as needed. - mStyleAttrStyleSheet->SetOwningDocument(this); - // Now set up our style sets nsCOMPtr shell = GetShell(); if (shell) { @@ -2295,19 +2271,13 @@ void nsDocument::FillStyleSet(nsStyleSet* aStyleSet) { NS_PRECONDITION(aStyleSet, "Must have a style set"); - NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::ePresHintSheet) == 0, - "Style set already has a preshint sheet?"); NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eDocSheet) == 0, "Style set already has document sheets?"); - NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eStyleAttrSheet) == 0, - "Style set already has style attr sheets?"); - NS_PRECONDITION(mStyleAttrStyleSheet, "No style attr stylesheet?"); - NS_PRECONDITION(mAttrStyleSheet, "No attr stylesheet?"); - aStyleSet->AppendStyleSheet(nsStyleSet::ePresHintSheet, mAttrStyleSheet); - - aStyleSet->AppendStyleSheet(nsStyleSet::eStyleAttrSheet, - mStyleAttrStyleSheet); + // We could consider moving this to nsStyleSet::Init, to match its + // handling of the eAnimationSheet and eTransitionSheet levels. + aStyleSet->DirtyRuleProcessors(nsStyleSet::ePresHintSheet); + aStyleSet->DirtyRuleProcessors(nsStyleSet::eStyleAttrSheet); int32_t i; for (i = mStyleSheets.Count() - 1; i >= 0; --i) { @@ -5104,32 +5074,6 @@ nsDocument::RegisterEnabled() return sPrefValue; } -NS_IMETHODIMP -nsDocument::Register(const nsAString& aName, const JS::Value& aOptions, - JSContext* aCx, uint8_t aOptionalArgc, - jsval* aConstructor /* out param */) -{ - RootedDictionary options(aCx); - if (aOptionalArgc > 0) { - JSAutoCompartment ac(aCx, GetWrapper()); - JS::Rooted opts(aCx, aOptions); - NS_ENSURE_TRUE(JS_WrapValue(aCx, opts.address()), - NS_ERROR_UNEXPECTED); - NS_ENSURE_TRUE(options.Init(aCx, opts), - NS_ERROR_UNEXPECTED); - } - - ErrorResult rv; - JSObject* object = Register(aCx, aName, options, rv); - if (rv.Failed()) { - return rv.ErrorCode(); - } - NS_ENSURE_TRUE(object, NS_ERROR_UNEXPECTED); - - *aConstructor = OBJECT_TO_JSVAL(object); - return NS_OK; -} - JSObject* nsDocument::Register(JSContext* aCx, const nsAString& aName, const ElementRegistrationOptions& aOptions, diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index b7e36e35eab2..293abb01254a 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -60,7 +60,6 @@ #include "nsIProgressEventSink.h" #include "nsISecurityEventSink.h" #include "nsIChannelEventSink.h" -#include "nsIDocumentRegister.h" #include "imgIRequest.h" #include "mozilla/dom/DOMImplementation.h" #include "nsIDOMTouchEvent.h" @@ -505,7 +504,6 @@ class nsDocument : public nsIDocument, public nsStubMutationObserver, public nsIDOMDocumentTouch, public nsIInlineEventHandlers, - public nsIDocumentRegister, public nsIObserver { public: @@ -641,14 +639,6 @@ public: return mChannel; } - /** - * Get this document's inline style sheet. May return null if there - * isn't one - */ - virtual nsHTMLCSSStyleSheet* GetInlineStyleSheet() const MOZ_OVERRIDE { - return mStyleAttrStyleSheet; - } - /** * Set the object from which a document can get a script context. * This is the context within which all scripts (during document @@ -804,9 +794,6 @@ public: // nsIInlineEventHandlers NS_DECL_NSIINLINEEVENTHANDLERS - // nsIDocumentRegister - NS_DECL_NSIDOCUMENTREGISTER - // nsIObserver NS_DECL_NSIOBSERVER @@ -1308,7 +1295,6 @@ protected: // The channel that got passed to StartDocumentLoad(), if any nsCOMPtr mChannel; - nsRefPtr mStyleAttrStyleSheet; // A document "without a browsing context" that owns the content of // HTMLTemplateElement. diff --git a/content/base/src/nsNodeUtils.cpp b/content/base/src/nsNodeUtils.cpp index ba7bcd514406..15d926a034d4 100644 --- a/content/base/src/nsNodeUtils.cpp +++ b/content/base/src/nsNodeUtils.cpp @@ -401,13 +401,6 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, AutoJSContext cx; nsresult rv; - JS::RootedObject wrapper(cx); - bool isDOMBinding; - if (aReparentScope && (wrapper = aNode->GetWrapper()) && - !(isDOMBinding = IsDOMObject(wrapper))) { - rv = xpc_MorphSlimWrapper(cx, aNode); - NS_ENSURE_SUCCESS(rv, rv); - } nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager; @@ -523,19 +516,22 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, elem->RecompileScriptEventListeners(); } - if (aReparentScope && wrapper) { - if (isDOMBinding) { - rv = ReparentWrapper(cx, wrapper); - } else { - nsIXPConnect *xpc = nsContentUtils::XPConnect(); - if (xpc) { - rv = xpc->ReparentWrappedNativeIfFound(cx, wrapper, aReparentScope, aNode); + if (aReparentScope) { + JS::Rooted wrapper(cx); + if ((wrapper = aNode->GetWrapper())) { + if (IsDOMObject(wrapper)) { + rv = ReparentWrapper(cx, wrapper); + } else { + nsIXPConnect *xpc = nsContentUtils::XPConnect(); + if (xpc) { + rv = xpc->ReparentWrappedNativeIfFound(cx, wrapper, aReparentScope, aNode); + } } - } - if (NS_FAILED(rv)) { - aNode->mNodeInfo.swap(nodeInfo); + if (NS_FAILED(rv)) { + aNode->mNodeInfo.swap(nodeInfo); - return rv; + return rv; + } } } } diff --git a/content/events/public/nsIEventListenerService.idl b/content/events/public/nsIEventListenerService.idl index 744f509040c8..f9277b030aa6 100644 --- a/content/events/public/nsIEventListenerService.idl +++ b/content/events/public/nsIEventListenerService.idl @@ -16,6 +16,7 @@ interface nsIEventListenerInfo : nsISupports { /** * The type of the event for which the listener was added. + * Null if the listener is for all the events. */ readonly attribute AString type; readonly attribute boolean capturing; diff --git a/content/events/src/nsEventListenerManager.cpp b/content/events/src/nsEventListenerManager.cpp index 06b7febebd92..b0dbfa13ec60 100644 --- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -1167,8 +1167,12 @@ nsEventListenerManager::GetListenerInfo(nsCOMArray* aList) CompileEventHandlerInternal(const_cast(&ls), true, nullptr); } - const nsDependentSubstring& eventType = - Substring(nsDependentAtomString(ls.mTypeAtom), 2); + nsAutoString eventType; + if (ls.mAllEvents) { + eventType.SetIsVoid(true); + } else { + eventType.Assign(Substring(nsDependentAtomString(ls.mTypeAtom), 2)); + } // EventListenerInfo is defined in XPCOM, so we have to go ahead // and convert to an XPCOM callback here... nsRefPtr info = diff --git a/content/events/test/test_bug448602.html b/content/events/test/test_bug448602.html index 2878a92a8c88..9b4e2560782c 100644 --- a/content/events/test/test_bug448602.html +++ b/content/events/test/test_bug448602.html @@ -184,6 +184,15 @@ function testAllListener() { } els.addListenerForAllEvents(root, allListener, false, true); + var infos = els.getListenerInfoFor(root); + var nullTypes = 0; + for (var i = 0; i < infos.length; ++i) { + if (infos[i].type == null) { + ++nullTypes; + } + } + is(nullTypes, 1, "Should have one all-event-listener!"); + els.addListenerForAllEvents(root, allListener, false, true, true); els.addListenerForAllEvents(root, allListenerTrustedOnly, false, false, true); l3.dispatchEvent(new Event("testevent", { bubbles: true })); diff --git a/content/html/content/src/HTMLTrackElement.cpp b/content/html/content/src/HTMLTrackElement.cpp index f848ae4e75ed..580b36f82ad5 100644 --- a/content/html/content/src/HTMLTrackElement.cpp +++ b/content/html/content/src/HTMLTrackElement.cpp @@ -94,7 +94,8 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED_4(HTMLTrackElement, nsGenericHTMLElement, NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLTrackElement) NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLElement) -NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement) + NS_HTML_CONTENT_INTERFACES(nsGenericHTMLElement) +NS_ELEMENT_INTERFACE_MAP_END void HTMLTrackElement::OnChannelRedirect(nsIChannel* aChannel, diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h index 364e4173db43..f88b6a5e8e49 100644 --- a/content/html/document/src/nsHTMLDocument.h +++ b/content/html/document/src/nsHTMLDocument.h @@ -44,7 +44,7 @@ public: ~nsHTMLDocument(); virtual nsresult Init() MOZ_OVERRIDE; - NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsHTMLDocument, nsDocument) diff --git a/content/media/AudioSegment.cpp b/content/media/AudioSegment.cpp index 7ccce0d8138d..03e6d5691b5e 100644 --- a/content/media/AudioSegment.cpp +++ b/content/media/AudioSegment.cpp @@ -171,7 +171,7 @@ AudioSegment::WriteTo(AudioStream* aOutput) if (channelData.Length() > outputChannels) { // Down-mix. DownmixAndInterleave(channelData, c.mBufferFormat, duration, - c.mVolume, channelData.Length(), buf.Elements()); + c.mVolume, outputChannels, buf.Elements()); } else { InterleaveAndConvertBuffer(channelData.Elements(), c.mBufferFormat, duration, c.mVolume, diff --git a/content/media/AudioSegment.h b/content/media/AudioSegment.h index 3ff5b70f326c..7000dc82f2bb 100644 --- a/content/media/AudioSegment.h +++ b/content/media/AudioSegment.h @@ -30,9 +30,11 @@ void InterleaveAndConvertBuffer(const void** aSourceChannels, int32_t aLength, float aVolume, int32_t aChannels, AudioDataValue* aOutput); + /** - * Down-mix audio channels, and interleave the channel data. A total of - * aOutputChannels*aDuration interleaved samples will be stored into aOutput. + * Given an array of input channels (aChannelData), downmix to aOutputChannels, + * interleave the channel data. A total of aOutputChannels*aDuration + * interleaved samples will be copied to a channel buffer in aOutput. */ void DownmixAndInterleave(const nsTArray& aChannelData, AudioSampleFormat aSourceFormat, int32_t aDuration, diff --git a/content/media/WebVTTLoadListener.cpp b/content/media/WebVTTLoadListener.cpp index 7d652092b88e..a754b1b079a1 100644 --- a/content/media/WebVTTLoadListener.cpp +++ b/content/media/WebVTTLoadListener.cpp @@ -73,6 +73,7 @@ WebVTTLoadListener::LoadResource() mParser.own(parser); NS_ENSURE_TRUE(mParser != nullptr, NS_ERROR_FAILURE); + mElement->mReadyState = HTMLTrackElement::LOADING; return NS_OK; } @@ -89,6 +90,9 @@ WebVTTLoadListener::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) { webvtt_finish_parsing(mParser); + if(mElement->mReadyState != HTMLTrackElement::ERROR) { + mElement->mReadyState = HTMLTrackElement::LOADED; + } return NS_OK; } @@ -227,6 +231,11 @@ WebVTTLoadListener::OnReportError(uint32_t aLine, uint32_t aCol, #endif switch(aError) { + // Non-recoverable errors require us to abort parsing: + case WEBVTT_MALFORMED_TAG: + mElement->mReadyState = HTMLTrackElement::ERROR; + return -1; + // Errors which should result in dropped cues // if the return value is negative: case WEBVTT_MALFORMED_TIMESTAMP: diff --git a/content/media/test/crashtests/882956.html b/content/media/test/crashtests/882956.html new file mode 100644 index 000000000000..ae7b441f9993 --- /dev/null +++ b/content/media/test/crashtests/882956.html @@ -0,0 +1,15 @@ + diff --git a/content/media/test/crashtests/crashtests.list b/content/media/test/crashtests/crashtests.list index 95a9a9350263..3ea3632778c4 100644 --- a/content/media/test/crashtests/crashtests.list +++ b/content/media/test/crashtests/crashtests.list @@ -46,3 +46,4 @@ load 880384.html load 880404.html load 880724.html load 881775.html +load 882956.html diff --git a/dom/apps/src/Makefile.in b/dom/apps/src/Makefile.in index 39932ebd73c6..7f2b9d5f2a12 100644 --- a/dom/apps/src/Makefile.in +++ b/dom/apps/src/Makefile.in @@ -15,7 +15,7 @@ DISABLED_EXTRA_COMPONENTS = \ Webapps.manifest \ $(NULL) -EXTRA_PP_COMPONENTS = \ +DISABLED_EXTRA_PP_COMPONENTS = \ Webapps.js \ $(NULL) diff --git a/dom/apps/src/moz.build b/dom/apps/src/moz.build index 735d90b1705f..c8b90539372e 100644 --- a/dom/apps/src/moz.build +++ b/dom/apps/src/moz.build @@ -10,6 +10,10 @@ EXTRA_COMPONENTS += [ 'Webapps.manifest', ] +EXTRA_PP_COMPONENTS += [ + 'Webapps.js', +] + EXTRA_JS_MODULES += [ 'AppDownloadManager.jsm', 'AppsServiceChild.jsm', diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index dca001c3c7f3..d6cc34708dd5 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -4259,7 +4259,7 @@ LocationSetterGuts(JSContext *cx, JSObject *obj, jsval *vp) { // This function duplicates some of the logic in XPC_WN_HelperSetProperty obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); - if (!IS_WN_WRAPPER(obj)) + if (!IS_WN_REFLECTOR(obj)) return NS_ERROR_XPC_BAD_CONVERT_JS; XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); @@ -5099,8 +5099,7 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *aGlobalObj, nsresult rv = WrapNativeParent(cx, globalObj, native_parent, parentObj); NS_ENSURE_SUCCESS(rv, rv); - return node->ChromeOnlyAccess() ? - NS_SUCCESS_CHROME_ACCESS_ONLY : NS_SUCCESS_ALLOW_SLIM_WRAPPERS; + return node->ChromeOnlyAccess() ? NS_SUCCESS_CHROME_ACCESS_ONLY : NS_OK; } NS_IMETHODIMP @@ -5261,8 +5260,7 @@ nsElementSH::PreCreate(nsISupports *nativeObj, JSContext *cx, if (element->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) && doc->BindingManager()->GetBinding(element)) { - // Don't allow slim wrappers. - return rv == NS_SUCCESS_ALLOW_SLIM_WRAPPERS ? NS_OK : rv; + return rv; } mozilla::css::URLValue *bindingURL; @@ -5276,7 +5274,7 @@ nsElementSH::PreCreate(nsISupports *nativeObj, JSContext *cx, element->SetFlags(NODE_ATTACH_BINDING_ON_POSTCREATE); - return rv == NS_SUCCESS_ALLOW_SLIM_WRAPPERS ? NS_OK : rv; + return rv; } NS_IMETHODIMP diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 25fa820284ef..aab790d2a780 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -535,29 +535,24 @@ MaybeWrapValue(JSContext* cx, JS::MutableHandle rval) return true; } - if (rval.isObject()) { - JSObject* obj = &rval.toObject(); - if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) { - return JS_WrapValue(cx, rval.address()); - } - - // We're same-compartment, but even then we might need to wrap - // objects specially. Check for that. - if (GetSameCompartmentWrapperForDOMBinding(obj)) { - // We're a new-binding object, and "obj" now points to the right thing - rval.set(JS::ObjectValue(*obj)); - return true; - } - - if (!IS_SLIM_WRAPPER(obj)) { - // We might need a SOW - return JS_WrapValue(cx, rval.address()); - } - - // Fall through to returning true + if (!rval.isObject()) { + return true; } - return true; + JSObject* obj = &rval.toObject(); + if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) { + return JS_WrapValue(cx, rval.address()); + } + + // We're same-compartment, but even then we might need to wrap + // objects specially. Check for that. + if (GetSameCompartmentWrapperForDOMBinding(obj)) { + // We're a new-binding object, and "obj" now points to the right thing + rval.set(JS::ObjectValue(*obj)); + return true; + } + + return JS_WrapValue(cx, rval.address()); } static inline void @@ -642,7 +637,7 @@ WrapNewBindingObject(JSContext* cx, JS::Handle scope, T* value, } rval.set(JS::ObjectValue(*obj)); - return (sameCompartment && IS_SLIM_WRAPPER(obj)) || JS_WrapValue(cx, rval.address()); + return JS_WrapValue(cx, rval.address()); } // Create a JSObject wrapping "value", for cases when "value" is a diff --git a/dom/interfaces/core/moz.build b/dom/interfaces/core/moz.build index 1c185e57de13..10f6ed014322 100644 --- a/dom/interfaces/core/moz.build +++ b/dom/interfaces/core/moz.build @@ -25,7 +25,6 @@ XPIDL_SOURCES += [ 'nsIDOMText.idl', 'nsIDOMUserDataHandler.idl', 'nsIDOMXMLDocument.idl', - 'nsIDocumentRegister.idl', 'nsIInlineEventHandlers.idl', ] diff --git a/dom/interfaces/core/nsIDocumentRegister.idl b/dom/interfaces/core/nsIDocumentRegister.idl deleted file mode 100644 index 701eb9936ba5..000000000000 --- a/dom/interfaces/core/nsIDocumentRegister.idl +++ /dev/null @@ -1,16 +0,0 @@ -/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(e35935bd-ebae-4e0d-93bf-efa93ab14c05)] -interface nsIDocumentRegister : nsISupports -{ - [optional_argc, - implicit_jscontext] jsval register(in DOMString name, - [optional] in jsval options) - raises(DOMException); -}; - diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 6baf9d331860..da3d31c9a897 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -348,11 +348,10 @@ TabChild::Observe(nsISupports *aSubject, // the top-left of the page. mLastMetrics.mZoom = gfxSize(1.0, 1.0); mLastMetrics.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize); - // I don't know what units mInnerSize is in, hence FromUnknownRect - mLastMetrics.mCompositionBounds = LayerIntRect::FromUnknownRect( - gfx::IntRect(0, 0, mInnerSize.width, mInnerSize.height)); - mLastMetrics.mResolution = + mLastMetrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize); + CSSToScreenScale resolution = AsyncPanZoomController::CalculateResolution(mLastMetrics); + mLastMetrics.mResolution = gfxSize(resolution.scale, resolution.scale); mLastMetrics.mScrollOffset = CSSPoint(0, 0); utils->SetResolution(mLastMetrics.mResolution.width, mLastMetrics.mResolution.height); @@ -590,9 +589,7 @@ TabChild::HandlePossibleViewportChange() FrameMetrics metrics(mLastMetrics); metrics.mViewport = CSSRect(CSSPoint(), viewport); metrics.mScrollableRect = CSSRect(CSSPoint(), pageSize); - // I don't know what units mInnerSize is in, hence FromUnknownRect - metrics.mCompositionBounds = LayerIntRect::FromUnknownRect( - gfx::IntRect(0, 0, mInnerSize.width, mInnerSize.height)); + metrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize); // Changing the zoom when we're not doing a first paint will get ignored // by AsyncPanZoomController and causes a blurry flash. @@ -623,14 +620,13 @@ TabChild::HandlePossibleViewportChange() // new CSS viewport, so we know that there's no velocity, acceleration, and // we have no idea how long painting will take. metrics, gfx::Point(0.0f, 0.0f), gfx::Point(0.0f, 0.0f), 0.0); - gfxSize resolution = AsyncPanZoomController::CalculateResolution(metrics); + CSSToScreenScale resolution = AsyncPanZoomController::CalculateResolution(metrics); // XXX is this actually hysteresis? This calculation is not well // understood. It's taken from the previous JS implementation. gfxFloat hysteresis/*?*/ = gfxFloat(oldBrowserWidth) / gfxFloat(oldScreenWidth); - resolution.width *= hysteresis; - resolution.height *= hysteresis; - metrics.mResolution = resolution; + metrics.mResolution = gfxSize(resolution.scale * hysteresis, + resolution.scale * hysteresis); utils->SetResolution(metrics.mResolution.width, metrics.mResolution.height); // Force a repaint with these metrics. This, among other things, sets the @@ -1413,7 +1409,8 @@ TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size, const mOuterRect.height = rect.height; mOrientation = orientation; - mInnerSize = size; + mInnerSize = ScreenIntSize::FromUnknownSize( + gfx::IntSize(size.width, size.height)); mWidget->Resize(0, 0, size.width, size.height, true); @@ -1530,9 +1527,9 @@ TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics) utils->SetScrollPositionClampingScrollPortSize( cssCompositedRect.width, cssCompositedRect.height); ScrollWindowTo(window, aFrameMetrics.mScrollOffset); - gfxSize resolution = AsyncPanZoomController::CalculateResolution( + CSSToScreenScale resolution = AsyncPanZoomController::CalculateResolution( aFrameMetrics); - utils->SetResolution(resolution.width, resolution.height); + utils->SetResolution(resolution.scale, resolution.scale); nsCOMPtr domDoc; nsCOMPtr docElement; diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 6f300e5429cb..5b50a5fdc7b1 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -441,7 +441,7 @@ private: nsRefPtr mTabChildGlobal; uint32_t mChromeFlags; nsIntRect mOuterRect; - nsIntSize mInnerSize; + ScreenIntSize mInnerSize; // When we're tracking a possible tap gesture, this is the "down" // point of the touchstart. nsIntPoint mGestureDownPoint; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index c36e7f22ee89..d9e6dc992bee 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -464,7 +464,8 @@ TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size) unused << SendUpdateDimensions(mRect, mDimensions, mOrientation); if (RenderFrameParent* rfp = GetRenderFrame()) { - rfp->NotifyDimensionsChanged(mDimensions.width, mDimensions.height); + rfp->NotifyDimensionsChanged(ScreenIntSize::FromUnknownSize( + gfx::IntSize(mDimensions.width, mDimensions.height))); } } } @@ -1464,7 +1465,8 @@ TabParent::RecvPRenderFrameConstructor(PRenderFrameParent* actor, { RenderFrameParent* rfp = GetRenderFrame(); if (mDimensions != nsIntSize() && rfp) { - rfp->NotifyDimensionsChanged(mDimensions.width, mDimensions.height); + rfp->NotifyDimensionsChanged(ScreenIntSize::FromUnknownSize( + gfx::IntSize(mDimensions.width, mDimensions.height))); } return true; diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.cpp b/extensions/spellcheck/src/mozInlineSpellChecker.cpp index daf0237b381a..ba83a2fa99bc 100644 --- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp +++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp @@ -1976,18 +1976,23 @@ NS_IMPL_ISUPPORTS1(UpdateCurrentDictionaryCallback, nsIEditorSpellCheckCallback) NS_IMETHODIMP mozInlineSpellChecker::UpdateCurrentDictionary() { - if (!mSpellCheck) { + // mSpellCheck is null and mPendingSpellCheck is nonnull while the spell + // checker is being initialized. Calling UpdateCurrentDictionary on + // mPendingSpellCheck simply queues the dictionary update after the init. + nsCOMPtr spellCheck = mSpellCheck ? mSpellCheck : + mPendingSpellCheck; + if (!spellCheck) { return NS_OK; } - if (NS_FAILED(mSpellCheck->GetCurrentDictionary(mPreviousDictionary))) { + if (NS_FAILED(spellCheck->GetCurrentDictionary(mPreviousDictionary))) { mPreviousDictionary.Truncate(); } nsRefPtr cb = new UpdateCurrentDictionaryCallback(this, mDisabledAsyncToken); NS_ENSURE_STATE(cb); - nsresult rv = mSpellCheck->UpdateCurrentDictionary(cb); + nsresult rv = spellCheck->UpdateCurrentDictionary(cb); if (NS_FAILED(rv)) { cb = nullptr; NS_ENSURE_SUCCESS(rv, rv); diff --git a/gfx/2d/Point.h b/gfx/2d/Point.h index ed7f6be5963e..026b44604c49 100644 --- a/gfx/2d/Point.h +++ b/gfx/2d/Point.h @@ -61,6 +61,12 @@ struct PointTyped : }; typedef PointTyped Point; +template +IntPointTyped RoundedToInt(const PointTyped& aPoint) { + return IntPointTyped(NS_lround(aPoint.x), + NS_lround(aPoint.y)); +} + template struct IntSizeTyped : public BaseSize< int32_t, IntSizeTyped >, diff --git a/gfx/2d/Rect.h b/gfx/2d/Rect.h index eb1b01c1219d..2084b394e546 100644 --- a/gfx/2d/Rect.h +++ b/gfx/2d/Rect.h @@ -100,6 +100,26 @@ struct RectTyped : }; typedef RectTyped Rect; +template +IntRectTyped RoundedToInt(const RectTyped& aRect) +{ + return IntRectTyped(NS_lround(aRect.x), + NS_lround(aRect.y), + NS_lround(aRect.width), + NS_lround(aRect.height)); +} + +template +IntRectTyped RoundedIn(const RectTyped& aRect) +{ + RectTyped copy(aRect); + copy.RoundIn(); + return IntRectTyped(int32_t(copy.x), + int32_t(copy.y), + int32_t(copy.width), + int32_t(copy.height)); +} + } } diff --git a/gfx/2d/ScaleFactor.h b/gfx/2d/ScaleFactor.h new file mode 100644 index 000000000000..ceef86f51d05 --- /dev/null +++ b/gfx/2d/ScaleFactor.h @@ -0,0 +1,67 @@ +/* -*- 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/. */ + +#ifndef MOZILLA_GFX_SCALEFACTOR_H_ +#define MOZILLA_GFX_SCALEFACTOR_H_ + +#include "gfxPoint.h" + +namespace mozilla { +namespace gfx { + +/* + * This class represents a scaling factor between two different pixel unit + * systems. This is effectively a type-safe float, intended to be used in + * combination with the known-type instances of gfx::Point, gfx::Rect, etc. + * + * Note that some parts of the code that pre-date this class used separate + * scaling factors for the x and y axes. However, at runtime these values + * were always expected to be the same, so this class uses only one scale + * factor for both axes. The two constructors that take two-axis scaling + * factors check to ensure that this assertion holds. + */ +template +struct ScaleFactor { + float scale; + + ScaleFactor() : scale(1.0) {} + ScaleFactor(const ScaleFactor& aCopy) : scale(aCopy.scale) {} + explicit ScaleFactor(float aScale) : scale(aScale) {} + + explicit ScaleFactor(float aX, float aY) : scale(aX) { + MOZ_ASSERT(fabs(aX - aY) < 1e-6); + } + + explicit ScaleFactor(gfxSize aScale) : scale(aScale.width) { + MOZ_ASSERT(fabs(aScale.width - aScale.height) < 1e-6); + } + + ScaleFactor Inverse() { + return ScaleFactor(1 / scale); + } + + bool operator==(const ScaleFactor& aOther) const { + return scale == aOther.scale; + } + + bool operator!=(const ScaleFactor& aOther) const { + return !(*this == aOther); + } + + template + ScaleFactor operator/(const ScaleFactor& aOther) const { + return ScaleFactor(scale / aOther.scale); + } + + template + ScaleFactor operator*(const ScaleFactor& aOther) const { + return ScaleFactor(scale * aOther.scale); + } +}; + +} +} + +#endif /* MOZILLA_GFX_SCALEFACTOR_H_ */ diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index 619b738f90fd..35c43ca3774e 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -20,6 +20,7 @@ EXPORTS.mozilla.gfx += [ 'Point.h', 'Rect.h', 'Scale.h', + 'ScaleFactor.h', 'Tools.h', 'Types.h', 'UserData.h', diff --git a/gfx/graphite2/README.mozilla b/gfx/graphite2/README.mozilla index 525ba23ab56b..33b1ceee35be 100644 --- a/gfx/graphite2/README.mozilla +++ b/gfx/graphite2/README.mozilla @@ -1,6 +1,6 @@ This directory contains the Graphite2 library from http://hg.palaso.org/graphitedev -Current version derived from upstream changeset 09707dd22634 +Current version derived from upstream changeset 6b8ddb7d599f See gfx/graphite2/moz-gr-update.sh for update procedure. diff --git a/gfx/graphite2/include/graphite2/Font.h b/gfx/graphite2/include/graphite2/Font.h index 4c9451eb2679..85ee73d91264 100644 --- a/gfx/graphite2/include/graphite2/Font.h +++ b/gfx/graphite2/include/graphite2/Font.h @@ -30,7 +30,7 @@ #define GR2_VERSION_MAJOR 1 #define GR2_VERSION_MINOR 2 -#define GR2_VERSION_BUGFIX 2 +#define GR2_VERSION_BUGFIX 3 #ifdef __cplusplus extern "C" diff --git a/gfx/graphite2/src/Pass.cpp b/gfx/graphite2/src/Pass.cpp index 743e260d6111..4c139e64f6a5 100644 --- a/gfx/graphite2/src/Pass.cpp +++ b/gfx/graphite2/src/Pass.cpp @@ -199,7 +199,8 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries, if (r->sort > 63 || r->preContext >= r->sort || r->preContext > m_maxPreCtxt || r->preContext < m_minPreCtxt) return false; ac_begin = ac_data + be::peek(--o_action); - rc_begin = *--o_constraint ? rc_data + be::peek(o_constraint) : rc_end; + --o_constraint; + rc_begin = be::peek(o_constraint) ? rc_data + be::peek(o_constraint) : rc_end; if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end || rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end) diff --git a/gfx/graphite2/src/Slot.cpp b/gfx/graphite2/src/Slot.cpp index 21618f7e7df3..c6fc2b5679a0 100644 --- a/gfx/graphite2/src/Slot.cpp +++ b/gfx/graphite2/src/Slot.cpp @@ -147,7 +147,7 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel) { Position base; - Rect bbox = seg->theGlyphBBoxTemporary(gid()); + Rect bbox = seg->theGlyphBBoxTemporary(glyph()); float clusterMin = 0.; Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin); @@ -389,12 +389,13 @@ void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph) } } m_realglyphid = theGlyph->attrs()[seg->silf()->aPseudo()]; + const GlyphFace *aGlyph = theGlyph; if (m_realglyphid) { - const GlyphFace *aGlyph = seg->getFace()->glyphs().glyphSafe(m_realglyphid); - if (aGlyph) theGlyph = aGlyph; + aGlyph = seg->getFace()->glyphs().glyphSafe(m_realglyphid); + if (!aGlyph) aGlyph = theGlyph; } - m_advance = Position(theGlyph->theAdvance().x, 0.); + m_advance = Position(aGlyph->theAdvance().x, 0.); if (seg->silf()->aPassBits()) seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()]); } diff --git a/gfx/graphite2/src/TtfUtil.cpp b/gfx/graphite2/src/TtfUtil.cpp index 9ede99e91455..ba26946dcc10 100644 --- a/gfx/graphite2/src/TtfUtil.cpp +++ b/gfx/graphite2/src/TtfUtil.cpp @@ -954,11 +954,11 @@ gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, return (uint16)(idDelta + nUnicodeId); // must use modulus 2^16 // Look up value in glyphIdArray - size_t offset = (nUnicodeId - chStart) + (idRangeOffset >> 1) + - (reinterpret_cast(pMid) - reinterpret_cast(pTable)); - if (offset * 2 >= pTable->length) + const ptrdiff_t offset = (nUnicodeId - chStart) + (idRangeOffset >> 1) + + (pMid - reinterpret_cast(pTable)); + if (offset * 2 >= be::swap(pTable->length)) return 0; - gid16 nGlyphId = be::peek(pMid + (nUnicodeId - chStart) + (idRangeOffset >> 1)); + gid16 nGlyphId = be::peek(reinterpret_cast(pTable)+offset); // If this value is 0, return 0. Else add the idDelta return nGlyphId ? nGlyphId + idDelta : 0; } diff --git a/gfx/graphite2/src/inc/Sparse.h b/gfx/graphite2/src/inc/Sparse.h index bbe6bcfb95ca..cd685bdcba7b 100644 --- a/gfx/graphite2/src/inc/Sparse.h +++ b/gfx/graphite2/src/inc/Sparse.h @@ -106,9 +106,9 @@ sparse::sparse(I attr, const I last) } if (m_nchunks == 0) return; - m_array.values = grzeroalloc((m_nchunks*sizeof(chunk) + sizeof(mapped_type)/2) + m_array.values = grzeroalloc((m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1) / sizeof(mapped_type) - + n_values*sizeof(mapped_type)); + + n_values); if (m_array.values == 0) { diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index cb7342ad85b1..24b9e5e6b71c 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -89,9 +89,9 @@ public: return mResolution * mDevPixelsPerCSSPixel; } - gfxPoint GetScrollOffsetInLayerPixels() const + gfx::Point GetScrollOffsetInLayerPixels() const { - return gfxPoint( + return gfx::Point( static_cast( mScrollOffset.x * LayersPixelsPerCSSPixel().width), static_cast( @@ -118,7 +118,7 @@ public: // // This is only valid on the root layer. Nested iframes do not need this // metric as they do not have a displayport set. See bug 775452. - LayerIntRect mCompositionBounds; + ScreenIntRect mCompositionBounds; // --------------------------------------------------------------------------- // The following metrics are all in CSS pixels. They are not in any uniform diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index 1986033c1cca..0ceb44f9d14c 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -395,16 +395,15 @@ ClientLayerManager::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, // This is derived from the code in // gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree. const gfx3DMatrix& rootTransform = GetRoot()->GetTransform(); - float devPixelRatioX = 1 / rootTransform.GetXScale(); - float devPixelRatioY = 1 / rootTransform.GetYScale(); + CSSToLayerScale paintScale = LayerToCSSScale(rootTransform.GetXScale(), + rootTransform.GetYScale()).Inverse(); const CSSRect& metricsDisplayPort = (aDrawingCritical && !metrics.mCriticalDisplayPort.IsEmpty()) ? metrics.mCriticalDisplayPort : metrics.mDisplayPort; - LayerRect displayPort = LayerRect::FromCSSRect(metricsDisplayPort + metrics.mScrollOffset, - devPixelRatioX, devPixelRatioY); + LayerRect displayPort = (metricsDisplayPort + metrics.mScrollOffset) * paintScale; return AndroidBridge::Bridge()->ProgressiveUpdateCallback( - aHasPendingNewThebesContent, displayPort, devPixelRatioX, aDrawingCritical, + aHasPendingNewThebesContent, displayPort, paintScale.scale, aDrawingCritical, aViewport, aScaleX, aScaleY); } #endif diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index a74af05b66d6..a85bab189d78 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -342,7 +342,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram LayerComposite* layerComposite = aLayer->AsLayerComposite(); ViewTransform treeTransform; - gfx::Point scrollOffset; + ScreenPoint scrollOffset; *aWantNextFrame |= controller->SampleContentTransformForFrame(aCurrentFrame, container, @@ -355,7 +355,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram metrics.mDisplayPort : metrics.mCriticalDisplayPort); gfx::Margin fixedLayerMargins(0, 0, 0, 0); ScreenPoint offset(0, 0); - SyncFrameMetrics(scrollOffset, treeTransform.mScale.width, metrics.mScrollableRect, + SyncFrameMetrics(scrollOffset, treeTransform.mScale.scale, metrics.mScrollableRect, mLayersUpdated, displayPort, 1 / rootTransform.GetXScale(), mIsFirstPaint, fixedLayerMargins, offset); @@ -381,8 +381,8 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram TransformFixedLayers( aLayer, - -treeTransform.mTranslation / treeTransform.mScale, - treeTransform.mScale, + gfxPoint(-treeTransform.mTranslation.x, -treeTransform.mTranslation.y), + gfxSize(treeTransform.mScale.scale, treeTransform.mScale.scale), fixedLayerMargins); appliedTransform = true; @@ -404,16 +404,15 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const gfx3DMatr gfx3DMatrix treeTransform; - float layerPixelRatioX = 1 / aRootTransform.GetXScale(), - layerPixelRatioY = 1 / aRootTransform.GetYScale(); + CSSToLayerScale geckoZoom = LayerToCSSScale(aRootTransform.GetXScale(), + aRootTransform.GetYScale()).Inverse(); - LayerIntPoint scrollOffsetLayerPixels = LayerIntPoint::FromCSSPointRounded( - metrics.mScrollOffset, layerPixelRatioX, layerPixelRatioY); + LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.mScrollOffset * geckoZoom); if (mIsFirstPaint) { mContentRect = metrics.mScrollableRect; SetFirstPaintViewport(scrollOffsetLayerPixels, - layerPixelRatioX, + geckoZoom.scale, mContentRect); mIsFirstPaint = false; } else if (!metrics.mScrollableRect.IsEqualEdges(mContentRect)) { @@ -424,20 +423,19 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const gfx3DMatr // We synchronise the viewport information with Java after sending the above // notifications, so that Java can take these into account in its response. // Calculate the absolute display port to send to Java - LayerIntRect displayPort = - LayerIntRect::FromCSSRectRounded(metrics.mCriticalDisplayPort.IsEmpty() - ? metrics.mDisplayPort - : metrics.mCriticalDisplayPort, - layerPixelRatioX, layerPixelRatioY); + LayerIntRect displayPort = RoundedToInt( + (metrics.mCriticalDisplayPort.IsEmpty() + ? metrics.mDisplayPort + : metrics.mCriticalDisplayPort + ) * geckoZoom); displayPort += scrollOffsetLayerPixels; gfx::Margin fixedLayerMargins(0, 0, 0, 0); ScreenPoint offset(0, 0); - ScreenPoint scrollOffset(0, 0); - float scaleX = 1.0, - scaleY = 1.0; - SyncViewportInfo(displayPort, layerPixelRatioX, mLayersUpdated, - scrollOffset, scaleX, scaleY, fixedLayerMargins, + ScreenPoint userScroll(0, 0); + CSSToScreenScale userZoom; + SyncViewportInfo(displayPort, geckoZoom.scale, mLayersUpdated, + userScroll, userZoom.scale, userZoom.scale, fixedLayerMargins, offset); mLayersUpdated = false; @@ -447,50 +445,44 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const gfx3DMatr // Handle transformations for asynchronous panning and zooming. We determine the // zoom used by Gecko from the transformation set on the root layer, and we // determine the scroll offset used by Gecko from the frame metrics of the - // primary scrollable layer. We compare this to the desired zoom and scroll + // primary scrollable layer. We compare this to the user zoom and scroll // offset in the view transform we obtained from Java in order to compute the // transformation we need to apply. - float tempScaleDiffX = aRootTransform.GetXScale() * scaleX; - float tempScaleDiffY = aRootTransform.GetYScale() * scaleY; + LayerToScreenScale zoomAdjust = userZoom / geckoZoom; - LayerIntPoint metricsScrollOffset(0, 0); + LayerIntPoint geckoScroll(0, 0); if (metrics.IsScrollable()) { - metricsScrollOffset = scrollOffsetLayerPixels; + geckoScroll = scrollOffsetLayerPixels; } - nsIntPoint scrollCompensation( - (scrollOffset.x / tempScaleDiffX - metricsScrollOffset.x) * scaleX, - (scrollOffset.y / tempScaleDiffY - metricsScrollOffset.y) * scaleY); - treeTransform = gfx3DMatrix(ViewTransform(-scrollCompensation, - gfxSize(scaleX, scaleY))); + LayerPoint translation = (userScroll / zoomAdjust) - geckoScroll; + treeTransform = gfx3DMatrix(ViewTransform(-translation, userZoom)); // Translate fixed position layers so that they stay in the correct position - // when scrollOffset and metricsScrollOffset differ. + // when userScroll and geckoScroll differ. gfxPoint fixedOffset; gfxSize scaleDiff; - LayerRect content = LayerRect::FromCSSRect(mContentRect, - 1 / aRootTransform.GetXScale(), - 1 / aRootTransform.GetYScale()); + LayerRect content = mContentRect * geckoZoom; // If the contents can fit entirely within the widget area on a particular // dimension, we need to translate and scale so that the fixed layers remain // within the page boundaries. - if (mContentRect.width * scaleX < metrics.mCompositionBounds.width) { - fixedOffset.x = -metricsScrollOffset.x; + if (mContentRect.width * userZoom.scale < metrics.mCompositionBounds.width) { + fixedOffset.x = -geckoScroll.x; scaleDiff.width = std::min(1.0f, metrics.mCompositionBounds.width / content.width); } else { - fixedOffset.x = clamped(scrollOffset.x / tempScaleDiffX, content.x, - content.XMost() - metrics.mCompositionBounds.width / tempScaleDiffX) - metricsScrollOffset.x; - scaleDiff.width = tempScaleDiffX; + fixedOffset.x = clamped(userScroll.x / zoomAdjust.scale, content.x, + content.XMost() - metrics.mCompositionBounds.width / zoomAdjust.scale) - geckoScroll.x; + scaleDiff.width = zoomAdjust.scale; } - if (mContentRect.height * scaleY < metrics.mCompositionBounds.height) { - fixedOffset.y = -metricsScrollOffset.y; + if (mContentRect.height * userZoom.scale < metrics.mCompositionBounds.height) { + fixedOffset.y = -geckoScroll.y; scaleDiff.height = std::min(1.0f, metrics.mCompositionBounds.height / content.height); } else { - fixedOffset.y = clamped(scrollOffset.y / tempScaleDiffY, content.y, - content.YMost() - metrics.mCompositionBounds.height / tempScaleDiffY) - metricsScrollOffset.y; - scaleDiff.height = tempScaleDiffY; + fixedOffset.y = clamped(userScroll.y / zoomAdjust.scale, content.y, + content.YMost() - metrics.mCompositionBounds.height / zoomAdjust.scale) - geckoScroll.y; + scaleDiff.height = zoomAdjust.scale; } // The transform already takes the resolution scale into account. Since we @@ -588,7 +580,7 @@ AsyncCompositionManager::SyncViewportInfo(const LayerIntRect& aDisplayPort, } void -AsyncCompositionManager::SyncFrameMetrics(const gfx::Point& aScrollOffset, +AsyncCompositionManager::SyncFrameMetrics(const ScreenPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect, bool aLayersUpdated, diff --git a/gfx/layers/composite/AsyncCompositionManager.h b/gfx/layers/composite/AsyncCompositionManager.h index 38889bacc79b..99ec81989a4f 100644 --- a/gfx/layers/composite/AsyncCompositionManager.h +++ b/gfx/layers/composite/AsyncCompositionManager.h @@ -27,8 +27,8 @@ class AutoResolveRefLayers; // Represents (affine) transforms that are calculated from a content view. struct ViewTransform { - ViewTransform(gfxPoint aTranslation = gfxPoint(), - gfxSize aScale = gfxSize(1, 1)) + ViewTransform(LayerPoint aTranslation = LayerPoint(), + CSSToScreenScale aScale = CSSToScreenScale()) : mTranslation(aTranslation) , mScale(aScale) {} @@ -36,12 +36,12 @@ struct ViewTransform { operator gfx3DMatrix() const { return - gfx3DMatrix::ScalingMatrix(mScale.width, mScale.height, 1) * - gfx3DMatrix::Translation(mTranslation.x, mTranslation.y, 0); + gfx3DMatrix::Translation(mTranslation.x, mTranslation.y, 0) * + gfx3DMatrix::ScalingMatrix(mScale.scale, mScale.scale, 1); } - gfxPoint mTranslation; - gfxSize mScale; + LayerPoint mTranslation; + CSSToScreenScale mScale; }; /** @@ -125,7 +125,7 @@ private: float& aScaleX, float& aScaleY, gfx::Margin& aFixedLayerMargins, ScreenPoint& aOffset); - void SyncFrameMetrics(const gfx::Point& aScrollOffset, + void SyncFrameMetrics(const ScreenPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect, bool aLayersUpdated, diff --git a/gfx/layers/composite/ThebesLayerComposite.cpp b/gfx/layers/composite/ThebesLayerComposite.cpp index 2c46046510ef..f91861933b66 100644 --- a/gfx/layers/composite/ThebesLayerComposite.cpp +++ b/gfx/layers/composite/ThebesLayerComposite.cpp @@ -246,17 +246,15 @@ ThebesLayerComposite::GetCompositionBounds() // the content resolution. Layer* rootLayer = Manager()->GetRoot(); const gfx3DMatrix& rootTransform = rootLayer->GetTransform(); - float scaleX = rootTransform.GetXScale(); - float scaleY = rootTransform.GetYScale(); + LayerToCSSScale scale(rootTransform.GetXScale(), + rootTransform.GetYScale()); // Get the content document bounds, in screen-space. const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics(); - const LayerIntRect content = LayerIntRect::FromCSSRectRounded(metrics.mScrollableRect, - 1 / scaleX, - 1 / scaleY); + const LayerIntRect content = RoundedToInt(metrics.mScrollableRect / scale); gfx::Point scrollOffset = - gfx::Point((metrics.mScrollOffset.x * metrics.LayersPixelsPerCSSPixel().width) / scaleX, - (metrics.mScrollOffset.y * metrics.LayersPixelsPerCSSPixel().height) / scaleY); + gfx::Point((metrics.mScrollOffset.x * metrics.LayersPixelsPerCSSPixel().width) / scale.scale, + (metrics.mScrollOffset.y * metrics.LayersPixelsPerCSSPixel().height) / scale.scale); const nsIntPoint contentOrigin( content.x - NS_lround(scrollOffset.x), content.y - NS_lround(scrollOffset.y)); diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index 8b8ae99c0e6b..78082d383739 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -208,37 +208,29 @@ AsyncPanZoomController::GetTouchStartTolerance() return gTouchStartTolerance; } -static gfx::Point -WidgetSpaceToCompensatedViewportSpace(const gfx::Point& aPoint, - gfxFloat aCurrentZoom) +static CSSPoint +WidgetSpaceToCompensatedViewportSpace(const ScreenPoint& aPoint, + const CSSToScreenScale& aCurrentZoom) { // Transform the input point from local widget space to the content document // space that the user is seeing, from last composite. - gfx::Point pt(aPoint); - pt = pt / aCurrentZoom; - // FIXME/bug 775451: this doesn't attempt to compensate for content transforms // in effect on the compositor. The problem is that it's very hard for us to // know what content CSS pixel is at widget point 0,0 based on information // available here. So we use this hacky implementation for now, which works // in quiescent states. - return pt; + return aPoint / aCurrentZoom; } nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent, nsInputEvent* aOutEvent) { - gfxFloat currentResolution; - gfx::Point currentScrollOffset, lastScrollOffset; + CSSToScreenScale currentResolution; { MonitorAutoLock monitor(mMonitor); - currentResolution = CalculateResolution(mFrameMetrics).width; - currentScrollOffset = gfx::Point(mFrameMetrics.mScrollOffset.x, - mFrameMetrics.mScrollOffset.y); - lastScrollOffset = gfx::Point(mLastContentPaintMetrics.mScrollOffset.x, - mLastContentPaintMetrics.mScrollOffset.y); + currentResolution = CalculateResolution(mFrameMetrics); } nsEventStatus status; @@ -265,8 +257,9 @@ AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent, for (uint32_t i = 0; i < touches.Length(); ++i) { nsIDOMTouch* touch = touches[i]; if (touch) { - gfx::Point refPoint = WidgetSpaceToCompensatedViewportSpace( - gfx::Point(touch->mRefPoint.x, touch->mRefPoint.y), + CSSPoint refPoint = WidgetSpaceToCompensatedViewportSpace( + ScreenPoint::FromUnknownPoint(gfx::Point( + touch->mRefPoint.x, touch->mRefPoint.y)), currentResolution); touch->mRefPoint = nsIntPoint(refPoint.x, refPoint.y); } @@ -274,8 +267,9 @@ AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent, break; } default: { - gfx::Point refPoint = WidgetSpaceToCompensatedViewportSpace( - gfx::Point(aOutEvent->refPoint.x, aOutEvent->refPoint.y), + CSSPoint refPoint = WidgetSpaceToCompensatedViewportSpace( + ScreenPoint::FromUnknownPoint(gfx::Point( + aOutEvent->refPoint.x, aOutEvent->refPoint.y)), currentResolution); aOutEvent->refPoint = nsIntPoint(refPoint.x, refPoint.y); break; @@ -550,13 +544,11 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) { { MonitorAutoLock monitor(mMonitor); - gfxFloat resolution = CalculateResolution(mFrameMetrics).width; + CSSToScreenScale resolution = CalculateResolution(mFrameMetrics); gfxFloat userZoom = mFrameMetrics.mZoom.width; ScreenPoint focusPoint = aEvent.mFocusPoint; - CSSPoint focusChange = ScreenPoint::ToCSSPoint(mLastZoomFocus - focusPoint, - 1.0 / resolution, - 1.0 / resolution); + CSSPoint focusChange = (mLastZoomFocus - focusPoint) / resolution; // If displacing by the change in focus point will take us off page bounds, // then reduce the displacement such that it doesn't. if (mX.DisplacementWillOverscroll(focusChange.x) != Axis::OVERSCROLL_NONE) { @@ -653,12 +645,12 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent) if (mGeckoContentController) { MonitorAutoLock monitor(mMonitor); - gfxFloat resolution = CalculateResolution(mFrameMetrics).width; - CSSPoint point = CSSPoint::FromUnknownPoint( - WidgetSpaceToCompensatedViewportSpace( - gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y), - resolution)); - mGeckoContentController->HandleLongTap(CSSIntPoint::RoundToInt(point)); + CSSToScreenScale resolution = CalculateResolution(mFrameMetrics); + CSSPoint point = WidgetSpaceToCompensatedViewportSpace( + ScreenPoint::FromUnknownPoint(gfx::Point( + aEvent.mPoint.x, aEvent.mPoint.y)), + resolution); + mGeckoContentController->HandleLongTap(gfx::RoundedToInt(point)); return nsEventStatus_eConsumeNoDefault; } return nsEventStatus_eIgnore; @@ -672,12 +664,12 @@ nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput if (mGeckoContentController) { MonitorAutoLock monitor(mMonitor); - gfxFloat resolution = CalculateResolution(mFrameMetrics).width; - CSSPoint point = CSSPoint::FromUnknownPoint( - WidgetSpaceToCompensatedViewportSpace( - gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y), - resolution)); - mGeckoContentController->HandleSingleTap(CSSIntPoint::RoundToInt(point)); + CSSToScreenScale resolution = CalculateResolution(mFrameMetrics); + CSSPoint point = WidgetSpaceToCompensatedViewportSpace( + ScreenPoint::FromUnknownPoint(gfx::Point( + aEvent.mPoint.x, aEvent.mPoint.y)), + resolution); + mGeckoContentController->HandleSingleTap(gfx::RoundedToInt(point)); return nsEventStatus_eConsumeNoDefault; } return nsEventStatus_eIgnore; @@ -688,12 +680,12 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) MonitorAutoLock monitor(mMonitor); if (mAllowZoom) { - gfxFloat resolution = CalculateResolution(mFrameMetrics).width; - CSSPoint point = CSSPoint::FromUnknownPoint( - WidgetSpaceToCompensatedViewportSpace( - gfx::Point(aEvent.mPoint.x, aEvent.mPoint.y), - resolution)); - mGeckoContentController->HandleDoubleTap(CSSIntPoint::RoundToInt(point)); + CSSToScreenScale resolution = CalculateResolution(mFrameMetrics); + CSSPoint point = WidgetSpaceToCompensatedViewportSpace( + ScreenPoint::FromUnknownPoint(gfx::Point( + aEvent.mPoint.x, aEvent.mPoint.y)), + resolution); + mGeckoContentController->HandleDoubleTap(gfx::RoundedToInt(point)); } return nsEventStatus_eConsumeNoDefault; @@ -758,11 +750,11 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) { // We want to inversely scale it because when you're zoomed further in, a // larger swipe should move you a shorter distance. - gfxFloat inverseResolution = 1 / CalculateResolution(mFrameMetrics).width; + ScreenToCSSScale inverseResolution = CalculateResolution(mFrameMetrics).Inverse(); - gfx::Point displacement(mX.GetDisplacementForDuration(inverseResolution, + gfx::Point displacement(mX.GetDisplacementForDuration(inverseResolution.scale, timeDelta), - mY.GetDisplacementForDuration(inverseResolution, + mY.GetDisplacementForDuration(inverseResolution.scale, timeDelta)); if (fabs(displacement.x) <= EPSILON && fabs(displacement.y) <= EPSILON) { return; @@ -802,11 +794,11 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) { // We want to inversely scale it because when you're zoomed further in, a // larger swipe should move you a shorter distance. - gfxFloat inverseResolution = 1 / CalculateResolution(mFrameMetrics).width; + ScreenToCSSScale inverseResolution = CalculateResolution(mFrameMetrics).Inverse(); ScrollBy(CSSPoint::FromUnknownPoint(gfx::Point( - mX.GetDisplacementForDuration(inverseResolution, aDelta), - mY.GetDisplacementForDuration(inverseResolution, aDelta) + mX.GetDisplacementForDuration(inverseResolution.scale, aDelta), + mY.GetDisplacementForDuration(inverseResolution.scale, aDelta) ))); TimeDuration timePaintDelta = TimeStamp::Now() - mPreviousPaintStartTime; if (timePaintDelta.ToMilliseconds() > gFlingRepaintInterval) { @@ -834,17 +826,17 @@ void AsyncPanZoomController::ScrollBy(const CSSPoint& aOffset) { void AsyncPanZoomController::ScaleWithFocus(float aZoom, const ScreenPoint& aFocus) { float zoomFactor = aZoom / mFrameMetrics.mZoom.width; - gfxFloat resolution = CalculateResolution(mFrameMetrics).width; + CSSToScreenScale resolution = CalculateResolution(mFrameMetrics); SetZoomAndResolution(aZoom); // If the new scale is very small, we risk multiplying in huge rounding // errors, so don't bother adjusting the scroll offset. - if (resolution >= 0.01f) { + if (resolution.scale >= 0.01f) { mFrameMetrics.mScrollOffset.x += - aFocus.x * (zoomFactor - 1.0) / resolution; + aFocus.x * (zoomFactor - 1.0) / resolution.scale; mFrameMetrics.mScrollOffset.y += - aFocus.y * (zoomFactor - 1.0) / resolution; + aFocus.y * (zoomFactor - 1.0) / resolution.scale; } } @@ -896,9 +888,8 @@ const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort( double estimatedPaintDuration = aEstimatedPaintDuration > EPSILON ? aEstimatedPaintDuration : 1.0; - gfxSize resolution = CalculateResolution(aFrameMetrics); - CSSIntRect compositionBounds = LayerIntRect::ToCSSIntRectRoundIn( - aFrameMetrics.mCompositionBounds, resolution.width, resolution.height); + CSSToScreenScale resolution = CalculateResolution(aFrameMetrics); + CSSIntRect compositionBounds = gfx::RoundedIn(aFrameMetrics.mCompositionBounds / resolution); CSSRect scrollableRect = aFrameMetrics.mScrollableRect; // Ensure the scrollableRect is at least as big as the compositionBounds @@ -975,21 +966,20 @@ AsyncPanZoomController::CalculateIntrinsicScale(const FrameMetrics& aMetrics) return gfxSize(intrinsicScale, intrinsicScale); } -/*static*/ gfxSize +/*static*/ CSSToScreenScale AsyncPanZoomController::CalculateResolution(const FrameMetrics& aMetrics) { gfxSize intrinsicScale = CalculateIntrinsicScale(aMetrics); gfxSize userZoom = aMetrics.mZoom; - return gfxSize(intrinsicScale.width * userZoom.width, - intrinsicScale.height * userZoom.height); + return CSSToScreenScale(intrinsicScale.width * userZoom.width, + intrinsicScale.height * userZoom.height); } /*static*/ CSSRect AsyncPanZoomController::CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics) { - gfxSize resolution = CalculateResolution(aMetrics); - CSSIntRect rect = LayerIntRect::ToCSSIntRectRoundIn( - aMetrics.mCompositionBounds, resolution.width, resolution.height); + CSSToScreenScale resolution = CalculateResolution(aMetrics); + CSSIntRect rect = gfx::RoundedIn(aMetrics.mCompositionBounds / resolution); return CSSRect(rect); } @@ -1087,7 +1077,7 @@ AsyncPanZoomController::FireAsyncScrollOnTimeout() bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime, ContainerLayer* aLayer, ViewTransform* aNewTransform, - gfx::Point& aScrollOffset) { + ScreenPoint& aScrollOffset) { // The eventual return value of this function. The compositor needs to know // whether or not to advance by a frame as soon as it can. For example, if a // fling is happening, it has to keep compositing so that the animation is @@ -1098,12 +1088,12 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa const gfx3DMatrix& currentTransform = aLayer->GetTransform(); // Scales on the root layer, on what's currently painted. - gfxSize rootScale(currentTransform.GetXScale(), - currentTransform.GetYScale()); + LayerToCSSScale rootScale(currentTransform.GetXScale(), + currentTransform.GetYScale()); - gfxPoint metricsScrollOffset(0, 0); - gfxPoint scrollOffset; - gfxSize localScale; + LayerPoint metricsScrollOffset; + CSSPoint scrollOffset; + CSSToScreenScale localScale; const FrameMetrics& frame = aLayer->GetFrameMetrics(); { MonitorAutoLock mon(mMonitor); @@ -1159,10 +1149,11 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa localScale = CalculateResolution(mFrameMetrics); if (frame.IsScrollable()) { - metricsScrollOffset = frame.GetScrollOffsetInLayerPixels(); + metricsScrollOffset = LayerPoint::FromUnknownPoint( + frame.GetScrollOffsetInLayerPixels()); } - scrollOffset = gfxPoint(mFrameMetrics.mScrollOffset.x, mFrameMetrics.mScrollOffset.y); + scrollOffset = mFrameMetrics.mScrollOffset; mCurrentAsyncScrollOffset = mFrameMetrics.mScrollOffset; } @@ -1193,11 +1184,9 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa mAsyncScrollTimeout); } - gfxPoint scrollCompensation( - (scrollOffset / rootScale - metricsScrollOffset) * localScale); - *aNewTransform = ViewTransform(-scrollCompensation, localScale); - aScrollOffset.x = scrollOffset.x * localScale.width; - aScrollOffset.y = scrollOffset.y * localScale.height; + LayerPoint translation = (scrollOffset / rootScale) - metricsScrollOffset; + *aNewTransform = ViewTransform(-translation, localScale); + aScrollOffset = scrollOffset * localScale; mLastSampleTime = aSampleTime; @@ -1245,9 +1234,9 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr aViewportFrame.mCompositionBounds.height == mFrameMetrics.mCompositionBounds.height) { // Remote content has sync'd up to the composition geometry // change, so we can accept the viewport it's calculated. - gfxSize previousResolution = CalculateResolution(mFrameMetrics); + CSSToScreenScale previousResolution = CalculateResolution(mFrameMetrics); mFrameMetrics.mViewport = aViewportFrame.mViewport; - gfxSize newResolution = CalculateResolution(mFrameMetrics); + CSSToScreenScale newResolution = CalculateResolution(mFrameMetrics); needContentRepaint |= (previousResolution != newResolution); } @@ -1274,10 +1263,10 @@ const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() { return mFrameMetrics; } -void AsyncPanZoomController::UpdateCompositionBounds(const LayerIntRect& aCompositionBounds) { +void AsyncPanZoomController::UpdateCompositionBounds(const ScreenIntRect& aCompositionBounds) { MonitorAutoLock mon(mMonitor); - LayerIntRect oldCompositionBounds = mFrameMetrics.mCompositionBounds; + ScreenIntRect oldCompositionBounds = mFrameMetrics.mCompositionBounds; mFrameMetrics.mCompositionBounds = aCompositionBounds; // If the window had 0 dimensions before, or does now, we don't want to @@ -1312,10 +1301,10 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) { { MonitorAutoLock mon(mMonitor); - LayerIntRect compositionBounds = mFrameMetrics.mCompositionBounds; + ScreenIntRect compositionBounds = mFrameMetrics.mCompositionBounds; CSSRect cssPageRect = mFrameMetrics.mScrollableRect; CSSPoint scrollOffset = mFrameMetrics.mScrollOffset; - gfxSize resolution = CalculateResolution(mFrameMetrics); + CSSToScreenScale resolution = CalculateResolution(mFrameMetrics); gfxSize currentZoom = mFrameMetrics.mZoom; float targetZoom; gfxFloat targetResolution; @@ -1338,7 +1327,7 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) { targetResolution = std::min(compositionBounds.width / zoomToRect.width, compositionBounds.height / zoomToRect.height); - targetZoom = float(targetResolution / resolution.width) * currentZoom.width; + targetZoom = float(targetResolution / resolution.scale) * currentZoom.width; } // 1. If the rect is empty, request received from browserElementScrolling.js // 2. currentZoom is equal to mMaxZoom and user still double-tapping it @@ -1347,8 +1336,7 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) { if (zoomToRect.IsEmpty() || (currentZoom.width == mMaxZoom && targetZoom >= mMaxZoom) || (currentZoom.width == localMinZoom && targetZoom <= localMinZoom)) { - CSSIntRect cssCompositionBounds = LayerIntRect::ToCSSIntRectRoundIn( - compositionBounds, resolution.width, resolution.height); + CSSIntRect cssCompositionBounds = gfx::RoundedIn(compositionBounds / resolution); float y = scrollOffset.y; float newHeight = @@ -1363,7 +1351,7 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) { targetResolution = std::min(compositionBounds.width / zoomToRect.width, compositionBounds.height / zoomToRect.height); - targetZoom = float(targetResolution / resolution.width) * currentZoom.width; + targetZoom = float(targetResolution / resolution.scale) * currentZoom.width; } targetZoom = clamped(targetZoom, localMinZoom, mMaxZoom); @@ -1453,7 +1441,8 @@ void AsyncPanZoomController::TimeoutTouchListeners() { void AsyncPanZoomController::SetZoomAndResolution(float aZoom) { mMonitor.AssertCurrentThreadOwns(); mFrameMetrics.mZoom = gfxSize(aZoom, aZoom); - mFrameMetrics.mResolution = CalculateResolution(mFrameMetrics); + CSSToScreenScale resolution = CalculateResolution(mFrameMetrics); + mFrameMetrics.mResolution = gfxSize(resolution.scale, resolution.scale); } void AsyncPanZoomController::UpdateZoomConstraints(bool aAllowZoom, diff --git a/gfx/layers/ipc/AsyncPanZoomController.h b/gfx/layers/ipc/AsyncPanZoomController.h index 615efba2c58a..246a7037d0e6 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.h +++ b/gfx/layers/ipc/AsyncPanZoomController.h @@ -111,7 +111,7 @@ public: * { x = 0, y = 0, width = surface.width, height = surface.height }, however * there is no hard requirement for this. */ - void UpdateCompositionBounds(const LayerIntRect& aCompositionBounds); + void UpdateCompositionBounds(const ScreenIntRect& aCompositionBounds); /** * We are scrolling a subframe, so disable our machinery until we hit @@ -178,7 +178,7 @@ public: bool SampleContentTransformForFrame(const TimeStamp& aSampleTime, ContainerLayer* aLayer, ViewTransform* aNewTransform, - gfx::Point& aScrollOffset); + ScreenPoint& aScrollOffset); /** * A shadow layer update has arrived. |aViewportFrame| is the new FrameMetrics @@ -235,7 +235,7 @@ public: * factor, etc. (The mResolution member of aFrameMetrics is * ignored.) */ - static gfxSize CalculateResolution(const FrameMetrics& aMetrics); + static CSSToScreenScale CalculateResolution(const FrameMetrics& aMetrics); static CSSRect CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics); diff --git a/gfx/layers/ipc/Axis.cpp b/gfx/layers/ipc/Axis.cpp index 1134681bda5a..4e8686e8ef27 100644 --- a/gfx/layers/ipc/Axis.cpp +++ b/gfx/layers/ipc/Axis.cpp @@ -318,9 +318,8 @@ bool Axis::ScaleWillOverscrollBothSides(float aScale) { CSSRect cssContentRect = metrics.mScrollableRect; - float scale = metrics.mZoom.width * aScale; - CSSIntRect cssCompositionBounds = LayerIntRect::ToCSSIntRectRoundIn( - metrics.mCompositionBounds, scale, scale); + CSSToScreenScale scale(metrics.mZoom.width * aScale); + CSSIntRect cssCompositionBounds = RoundedIn(metrics.mCompositionBounds / scale); return GetRectLength(cssContentRect) < GetRectLength(CSSRect(cssCompositionBounds)); } diff --git a/gfx/tests/gtest/TestTiledLayerBuffer.cpp b/gfx/tests/gtest/TestTiledLayerBuffer.cpp index 2909fd7d3724..339558c7dddc 100644 --- a/gfx/tests/gtest/TestTiledLayerBuffer.cpp +++ b/gfx/tests/gtest/TestTiledLayerBuffer.cpp @@ -68,7 +68,6 @@ TEST(TiledLayerBuffer, TileStart) { TEST(TiledLayerBuffer, EmptyUpdate) { TestTiledLayerBuffer buffer; - nsRegion::InitStatic(); nsIntRegion validRegion(nsIntRect(0, 0, 10, 10)); buffer.TestUpdate(validRegion, validRegion); diff --git a/image/decoders/icon/qt/Makefile.in b/image/decoders/icon/qt/Makefile.in index 9868c78f94ea..b76677b183d3 100644 --- a/image/decoders/icon/qt/Makefile.in +++ b/image/decoders/icon/qt/Makefile.in @@ -19,7 +19,7 @@ LOCAL_INCLUDES += $(MOZ_QT_CFLAGS) FORCE_STATIC_LIB = 1 EXTRA_COMPONENTS = gtkqticonsconverter.manifest -EXTRA_PP_COMPONENTS = gtkqticonsconverter.js +DISABLED_EXTRA_PP_COMPONENTS = gtkqticonsconverter.js include $(topsrcdir)/config/rules.mk diff --git a/image/decoders/icon/qt/moz.build b/image/decoders/icon/qt/moz.build index efbd2f3da73d..b9ef4a0e3581 100644 --- a/image/decoders/icon/qt/moz.build +++ b/image/decoders/icon/qt/moz.build @@ -12,3 +12,6 @@ CPP_SOURCES += [ 'nsIconChannel.cpp', ] +EXTRA_PP_COMPONENTS += [ + 'gtkqticonsconverter.js', +] diff --git a/js/src/builtin/Iterator-inl.h b/js/src/builtin/Iterator-inl.h index e6c838cdeb98..bb1d7e74c632 100644 --- a/js/src/builtin/Iterator-inl.h +++ b/js/src/builtin/Iterator-inl.h @@ -8,7 +8,6 @@ #define Iterator_inl_h_ #include "jsiter.h" -#include "jsobjinlines.h" inline bool JSObject::isPropertyIterator() const diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 09159b560dd8..d26a0f24b58a 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -13,10 +13,13 @@ #include "gc/Marking.h" #include "js/Utility.h" #include "vm/GlobalObject.h" +#include "vm/Interpreter.h" #include "vm/Stack.h" #include "jsobjinlines.h" +#include "gc/Barrier-inl.h" + using namespace js; using mozilla::DoubleIsInt32; diff --git a/js/src/builtin/Module.cpp b/js/src/builtin/Module.cpp index 0897cd459298..f5386d705970 100644 --- a/js/src/builtin/Module.cpp +++ b/js/src/builtin/Module.cpp @@ -4,9 +4,10 @@ * 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 "jsobjinlines.h" #include "builtin/Module.h" +#include "jsobjinlines.h" + using namespace js; Class js::ModuleClass = { diff --git a/js/src/builtin/ParallelArray.cpp b/js/src/builtin/ParallelArray.cpp index ae7d4d1dea24..fb0dab4b58f8 100644 --- a/js/src/builtin/ParallelArray.cpp +++ b/js/src/builtin/ParallelArray.cpp @@ -15,8 +15,6 @@ #include "vm/String.h" #include "vm/ThreadPool.h" -#include "jsobjinlines.h" - #include "vm/Interpreter-inl.h" using namespace js; diff --git a/js/src/builtin/ParallelArray.js b/js/src/builtin/ParallelArray.js index 98213378053a..0a2db707446f 100644 --- a/js/src/builtin/ParallelArray.js +++ b/js/src/builtin/ParallelArray.js @@ -377,7 +377,7 @@ function ParallelArrayMap(func, mode) { // FIXME(bug 844887): Check |IsCallable(func)| var self = this; - var length = self.shape[0]; + var length = UnsafeGetImmutableElement(self.shape, 0); var buffer = NewDenseArray(length); parallel: for (;;) { // see ParallelArrayBuild() to explain why for(;;) etc @@ -432,7 +432,7 @@ function ParallelArrayReduce(func, mode) { // FIXME(bug 844887): Check |IsCallable(func)| var self = this; - var length = self.shape[0]; + var length = UnsafeGetImmutableElement(self.shape, 0); if (length === 0) ThrowError(JSMSG_PAR_ARRAY_REDUCE_EMPTY); @@ -519,7 +519,7 @@ function ParallelArrayScan(func, mode) { // FIXME(bug 844887): Check |IsCallable(func)| var self = this; - var length = self.shape[0]; + var length = UnsafeGetImmutableElement(self.shape, 0); if (length === 0) ThrowError(JSMSG_PAR_ARRAY_REDUCE_EMPTY); @@ -726,7 +726,7 @@ function ParallelArrayScatter(targets, defaultValue, conflictFunc, length, mode) var self = this; if (length === undefined) - length = self.shape[0]; + length = UnsafeGetImmutableElement(self.shape, 0); // The Divide-Scatter-Vector strategy: // 1. Slice |targets| array of indices ("scatter-vector") into N @@ -977,7 +977,7 @@ function ParallelArrayFilter(func, mode) { // FIXME(bug 844887): Check |IsCallable(func)| var self = this; - var length = self.shape[0]; + var length = UnsafeGetImmutableElement(self.shape, 0); parallel: for (;;) { // see ParallelArrayBuild() to explain why for(;;) etc if (ShouldForceSequential()) @@ -1151,6 +1151,11 @@ function ParallelArrayFlatten() { function ParallelArrayGet1(i) { if (i === undefined) return undefined; + + // We could use UnsafeGetImmutableElement here, but I am not doing + // so (for the moment) since using the default path enables + // bounds-check hoisting, which is (currently) not possible + // otherwise. return this.buffer[this.offset + i]; } @@ -1158,27 +1163,25 @@ function ParallelArrayGet1(i) { * Specialized variant of get() for two-dimensional case */ function ParallelArrayGet2(x, y) { - var xDimension = this.shape[0]; - var yDimension = this.shape[1]; - if (x === undefined) - return undefined; - if (x >= xDimension) + var xDimension = UnsafeGetImmutableElement(this.shape, 0); + var yDimension = UnsafeGetImmutableElement(this.shape, 1); + if (x === undefined || TO_INT32(x) !== x || x >= xDimension) return undefined; if (y === undefined) return NewParallelArray(ParallelArrayView, [yDimension], this.buffer, this.offset + x * yDimension); - if (y >= yDimension) + if (TO_INT32(y) !== y || y >= yDimension) return undefined; var offset = y + x * yDimension; - return this.buffer[this.offset + offset]; + return UnsafeGetImmutableElement(this.buffer, this.offset + offset); } /** * Specialized variant of get() for three-dimensional case */ function ParallelArrayGet3(x, y, z) { - var xDimension = this.shape[0]; - var yDimension = this.shape[1]; - var zDimension = this.shape[2]; + var xDimension = UnsafeGetImmutableElement(this.shape, 0); + var yDimension = UnsafeGetImmutableElement(this.shape, 1); + var zDimension = UnsafeGetImmutableElement(this.shape, 2); if (x === undefined) return undefined; if (x >= xDimension) @@ -1194,7 +1197,7 @@ function ParallelArrayGet3(x, y, z) { if (z >= zDimension) return undefined; var offset = z + y*zDimension + x * yDimension * zDimension; - return this.buffer[this.offset + offset]; + return UnsafeGetImmutableElement(this.buffer, this.offset + offset); } /** @@ -1228,7 +1231,7 @@ function ParallelArrayGetN(...coords) { /** The length property yields the outermost dimension */ function ParallelArrayLength() { - return this.shape[0]; + return UnsafeGetImmutableElement(this.shape, 0); } function ParallelArrayToString() { diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 335666be8845..28b32290fb98 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -10,6 +10,8 @@ #include "builtin/RegExp.h" +#include "jsobjinlines.h" + #include "vm/RegExpObject-inl.h" #include "vm/RegExpStatics-inl.h" diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 1d28985f7a2f..1dbd5eef2292 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -11,13 +11,14 @@ #include "jsfriendapi.h" #include "jsgc.h" #include "jsobj.h" -#include "jsobjinlines.h" #include "jsprf.h" #include "jswrapper.h" #include "builtin/TestingFunctions.h" #include "vm/ForkJoin.h" +#include "jsobjinlines.h" + #include "vm/Stack-inl.h" using namespace js; diff --git a/js/src/config/makefiles/debugmake.mk b/js/src/config/makefiles/debugmake.mk index dd21734003e7..6e193947e4da 100644 --- a/js/src/config/makefiles/debugmake.mk +++ b/js/src/config/makefiles/debugmake.mk @@ -50,7 +50,6 @@ ifneq (,$(filter $(PROGRAM) $(HOST_PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $ @echo "IMPORT_LIBRARY = $(IMPORT_LIBRARY)" @echo "STATIC_LIBS = $(STATIC_LIBS)" @echo "SHARED_LIBS = $(SHARED_LIBS)" - @echo "EXTRA_DSO_LIBS = $(EXTRA_DSO_LIBS)" @echo "EXTRA_DSO_LDOPTS = $(EXTRA_DSO_LDOPTS)" @echo "DEPENDENT_LIBS = $(DEPENDENT_LIBS)" @echo -------------------------------------------------------------------------------- diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk index 42ecc25f2ee7..ec293c3cc8fc 100644 --- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -110,10 +110,6 @@ endif # ifndef .PYMAKE _VPATH_SRCS = $(abspath $<) -ifdef EXTRA_DSO_LIBS -EXTRA_DSO_LIBS := $(call EXPAND_MOZLIBNAME,$(EXTRA_DSO_LIBS)) -endif - ################################################################################ # Testing frameworks support ################################################################################ diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 6032d3944244..57b6823449a3 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -4,16 +4,14 @@ * 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 "ctypes/CTypes.h" + #include "mozilla/FloatingPoint.h" +#include "mozilla/StandardInteger.h" -#include "CTypes.h" -#include "Library.h" -#include "jsnum.h" -#include "jscompartment.h" -#include "jsobjinlines.h" #include - #include + #if defined(XP_WIN) || defined(XP_OS2) #include #endif @@ -32,7 +30,12 @@ #include #endif -#include "mozilla/StandardInteger.h" +#include "jscompartment.h" +#include "jsnum.h" +#include "jsprf.h" +#include "jstypedarray.h" + +#include "ctypes/Library.h" using namespace std; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 862fb8f8a7d3..9a3789d4b1fc 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -14,6 +14,8 @@ #include "vm/GlobalObject.h" #include "jsinferinlines.h" +#include "jsobjinlines.h" + #include "frontend/ParseMaps-inl.h" #include "frontend/ParseNode-inl.h" #include "frontend/Parser-inl.h" @@ -74,6 +76,15 @@ CheckArgumentsWithinEval(JSContext *cx, Parser &parser, Handle return true; } +inline bool +CanLazilyParse(JSContext *cx, const CompileOptions &options) +{ + return options.canLazilyParse && + options.compileAndGo && + options.sourcePolicy == CompileOptions::SAVE_SOURCE && + !cx->compartment()->debugMode(); +} + JSScript * frontend::CompileScript(JSContext *cx, HandleObject scopeChain, HandleScript evalCaller, @@ -102,7 +113,7 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, return NULL; if (options.filename && !ss->setFilename(cx, options.filename)) return NULL; - + JS::RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss)); if (!sourceObject) return NULL; @@ -120,28 +131,21 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, break; } + bool canLazilyParse = CanLazilyParse(cx, options); + Maybe > syntaxParser; - if (options.canLazilyParse) { + if (canLazilyParse) { syntaxParser.construct(cx, options, chars, length, /* foldConstants = */ false, (Parser *) NULL, (LazyScript *) NULL); } Parser parser(cx, options, chars, length, /* foldConstants = */ true, - options.canLazilyParse ? &syntaxParser.ref() : NULL, NULL); + canLazilyParse ? &syntaxParser.ref() : NULL, NULL); parser.sct = sct; GlobalSharedContext globalsc(cx, scopeChain, StrictModeFromContext(cx)); - // Syntax parsing may cause us to restart processing of top level - // statements in the script. Use Maybe<> so that the parse context can be - // reset when this occurs. - Maybe > pc; - - pc.construct(&parser, (GenericParseContext *) NULL, &globalsc, staticLevel, /* bodyid = */ 0); - if (!pc.ref().init()) - return NULL; - bool savedCallerFun = options.compileAndGo && evalCaller && @@ -169,6 +173,15 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, if (!bce.init()) return NULL; + // Syntax parsing may cause us to restart processing of top level + // statements in the script. Use Maybe<> so that the parse context can be + // reset when this occurs. + Maybe > pc; + + pc.construct(&parser, (GenericParseContext *) NULL, &globalsc, staticLevel, /* bodyid = */ 0); + if (!pc.ref().init()) + return NULL; + /* If this is a direct call to eval, inherit the caller's strictness. */ if (evalCaller && evalCaller->strict) globalsc.strict = true; @@ -313,32 +326,34 @@ bool frontend::CompileLazyFunction(JSContext *cx, HandleFunction fun, LazyScript *lazy, const jschar *chars, size_t length) { - CompileOptions options(cx); + JS_ASSERT(cx->compartment() == fun->compartment()); + + CompileOptions options(cx, lazy->version()); options.setPrincipals(cx->compartment()->principals) - .setOriginPrincipals(lazy->parent()->originPrincipals) - .setVersion(lazy->parent()->getVersion()) - .setFileAndLine(lazy->parent()->filename(), lazy->lineno()) + .setOriginPrincipals(lazy->originPrincipals()) + .setFileAndLine(lazy->source()->filename(), lazy->lineno()) .setColumn(lazy->column()) - .setCompileAndGo(lazy->parent()->compileAndGo) + .setCompileAndGo(true) .setNoScriptRval(false) .setSelfHostingMode(false); Parser parser(cx, options, chars, length, /* foldConstants = */ true, NULL, lazy); - RootedObject enclosingScope(cx, lazy->parent()->function()); + RootedObject enclosingScope(cx, lazy->parentFunction()); - ParseNode *pn = parser.standaloneLazyFunction(fun, lazy->parent()->staticLevel + 1, - lazy->strict()); + ParseNode *pn = parser.standaloneLazyFunction(fun, lazy->staticLevel(), lazy->strict()); if (!pn) return false; - JS::RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, lazy->source())); - if (!sourceObject) + if (!NameFunctions(cx, pn)) return false; + JS::RootedScriptSource sourceObject(cx, lazy->sourceObject()); + JS_ASSERT(sourceObject); + Rooted script(cx, JSScript::Create(cx, enclosingScope, false, - options, lazy->parent()->staticLevel + 1, + options, lazy->staticLevel(), sourceObject, lazy->begin(), lazy->end())); if (!script) return false; @@ -347,11 +362,11 @@ frontend::CompileLazyFunction(JSContext *cx, HandleFunction fun, LazyScript *laz if (lazy->directlyInsideEval()) script->directlyInsideEval = true; - - bool hasGlobalScope = lazy->parent()->compileAndGo; + if (lazy->usesArgumentsAndApply()) + script->usesArgumentsAndApply = true; BytecodeEmitter bce(/* parent = */ NULL, &parser, pn->pn_funbox, script, options.forEval, - /* evalCaller = */ NullPtr(), hasGlobalScope, + /* evalCaller = */ NullPtr(), /* hasGlobalScope = */ true, options.lineno, BytecodeEmitter::LazyFunction); if (!bce.init()) return false; @@ -385,8 +400,10 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO return false; } + bool canLazilyParse = CanLazilyParse(cx, options); + Maybe > syntaxParser; - if (options.canLazilyParse) { + if (canLazilyParse) { syntaxParser.construct(cx, options, chars, length, /* foldConstants = */ false, (Parser *) NULL, (LazyScript *) NULL); @@ -395,7 +412,7 @@ frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileO JS_ASSERT(!options.forEval); Parser parser(cx, options, chars, length, /* foldConstants = */ true, - options.canLazilyParse ? &syntaxParser.ref() : NULL, NULL); + canLazilyParse ? &syntaxParser.ref() : NULL, NULL); parser.sct = &sct; JS_ASSERT(fun); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 5a07cd3e21b8..8d6fbb7be16b 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -41,6 +41,7 @@ #include "vm/Shape.h" #include "jsatominlines.h" +#include "jsobjinlines.h" #include "jsscriptinlines.h" #include "frontend/ParseMaps-inl.h" @@ -1128,11 +1129,22 @@ TryConvertFreeName(BytecodeEmitter *bce, ParseNode *pn) * resolving upvar accesses within the inner function. */ if (bce->emitterMode == BytecodeEmitter::LazyFunction) { + // The only statements within a lazy function which can push lexical + // scopes are try/catch blocks. Use generic ops in this case. + for (StmtInfoBCE *stmt = bce->topStmt; stmt; stmt = stmt->down) { + switch (stmt->type) { + case STMT_TRY: + case STMT_FINALLY: + return true; + default:; + } + } + size_t hops = 0; FunctionBox *funbox = bce->sc->asFunctionBox(); if (funbox->hasExtensibleScope()) return false; - if (funbox->function()->atom() == pn->pn_atom) + if (funbox->function()->isNamedLambda() && funbox->function()->atom() == pn->pn_atom) return false; if (funbox->function()->isHeavyweight()) { hops++; @@ -2676,7 +2688,7 @@ EmitDestructuringDecls(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, Parse if (pn->isKind(PNK_ARRAY)) { for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { - if (pn2->isKind(PNK_COMMA)) + if (pn2->isKind(PNK_ELISION)) continue; emitter = (pn2->isKind(PNK_NAME)) ? EmitDestructuringDecl @@ -2896,8 +2908,8 @@ EmitDestructuringOpsHelper(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JS_ASSERT(bce->stackDepth >= stackDepth + 1); } - /* Nullary comma node makes a hole in the array destructurer. */ - if (pn3->isKind(PNK_COMMA) && pn3->isArity(PN_NULLARY)) { + /* Elision node makes a hole in the array destructurer. */ + if (pn3->isKind(PNK_ELISION)) { JS_ASSERT(pn->isKind(PNK_ARRAY)); JS_ASSERT(pn2 == pn3); if (Emit1(cx, bce, JSOP_POP) < 0) @@ -2972,7 +2984,7 @@ EmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, } /* MaybeEmitGroupAssignment won't call us if rhs is holey. */ - JS_ASSERT(!(pn->isKind(PNK_COMMA) && pn->isArity(PN_NULLARY))); + JS_ASSERT(!pn->isKind(PNK_ELISION)); if (!EmitTree(cx, bce, pn)) return false; ++limit; @@ -2989,7 +3001,7 @@ EmitGroupAssignment(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, if (!EmitUnaliasedVarOp(cx, JSOP_GETLOCAL, slot, bce)) return false; - if (pn->isKind(PNK_COMMA) && pn->isArity(PN_NULLARY)) { + if (pn->isKind(PNK_ELISION)) { if (Emit1(cx, bce, JSOP_POP) < 0) return false; } else { @@ -4491,8 +4503,10 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) return false; if (fun->isInterpretedLazy()) { - if (!fun->lazyScript()->parent()) - fun->lazyScript()->initParent(bce->script); + if (!fun->lazyScript()->sourceObject()) { + JSFunction *parent = bce->sc->isFunctionBox() ? bce->sc->asFunctionBox()->function() : NULL; + fun->lazyScript()->setParent(parent, bce->script->sourceObject(), bce->script->originPrincipals); + } } else { SharedContext *outersc = bce->sc; @@ -4557,6 +4571,9 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) /* We measured the max scope depth when we parsed the function. */ if (!EmitFunctionScript(cx, &bce2, pn->pn_body)) return false; + + if (funbox->usesArguments && funbox->usesApply) + script->usesArgumentsAndApply = true; } } @@ -5264,16 +5281,14 @@ EmitIncOrDec(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) * the comment on EmitSwitch. */ MOZ_NEVER_INLINE static bool -EmitLabel(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) +EmitLabeledStatement(JSContext *cx, BytecodeEmitter *bce, const LabeledStatement *pn) { /* * Emit a JSOP_LABEL instruction. The argument is the offset to the statement * following the labeled statement. */ - JSAtom *atom = pn->pn_atom; - jsatomid index; - if (!bce->makeAtomIndex(atom, &index)) + if (!bce->makeAtomIndex(pn->label(), &index)) return false; ptrdiff_t top = EmitJump(cx, bce, JSOP_LABEL, 0); @@ -5283,8 +5298,8 @@ EmitLabel(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) /* Emit code for the labeled statement. */ StmtInfoBCE stmtInfo(cx); PushStatementBCE(bce, &stmtInfo, STMT_LABEL, bce->offset()); - stmtInfo.label = atom; - if (!EmitTree(cx, bce, pn->expr())) + stmtInfo.label = pn->label(); + if (!EmitTree(cx, bce, pn->statement())) return false; if (!PopStatementBCE(cx, bce)) return false; @@ -5527,7 +5542,7 @@ EmitArray(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) if (nspread && !EmitNumberOp(cx, 0, bce)) return false; for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) { - if (pn2->isKind(PNK_COMMA) && pn2->isArity(PN_NULLARY)) { + if (pn2->isKind(PNK_ELISION)) { if (Emit1(cx, bce, JSOP_HOLE) < 0) return false; } else { @@ -5816,8 +5831,8 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn) ok = EmitStatement(cx, bce, pn); break; - case PNK_COLON: - ok = EmitLabel(cx, bce, pn); + case PNK_LABEL: + ok = EmitLabeledStatement(cx, bce, &pn->as()); break; case PNK_COMMA: diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 6588bd3e1997..d4f5c34b0e46 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -49,6 +49,10 @@ class FullParseHandler LazyScript * const lazyOuterFunction_; size_t lazyInnerFunctionIndex; + const TokenPos &pos() { + return tokenStream.currentToken().pos; + } + public: /* @@ -100,7 +104,7 @@ class FullParseHandler return dn; } ParseNode *newAtom(ParseNodeKind kind, JSAtom *atom, JSOp op = JSOP_NOP) { - ParseNode *pn = NullaryNode::create(kind, this); + ParseNode *pn = new_(kind, pos()); if (!pn) return NULL; pn->setOp(op); @@ -108,7 +112,7 @@ class FullParseHandler return pn; } ParseNode *newNumber(double value, DecimalPoint decimalPoint = NoDecimal) { - ParseNode *pn = NullaryNode::create(PNK_NUMBER, this); + ParseNode *pn = new_(PNK_NUMBER, pos()); if (!pn) return NULL; pn->initNumber(value, decimalPoint); @@ -130,8 +134,8 @@ class FullParseHandler return new_(cond, thenExpr, elseExpr); } - ParseNode *newNullary(ParseNodeKind kind) { - return NullaryNode::create(kind, this); + ParseNode *newElision() { + return new_(PNK_ELISION, pos()); } ParseNode *newUnary(ParseNodeKind kind, ParseNode *kid, JSOp op = JSOP_NOP) { @@ -162,11 +166,6 @@ class FullParseHandler ParseContext *pc, JSOp op = JSOP_NOP) { return ParseNode::newBinaryOrAppend(kind, op, left, right, this, pc, foldConstants); } - void setBinaryRHS(ParseNode *pn, ParseNode *rhs) { - JS_ASSERT(pn->isArity(PN_BINARY)); - pn->pn_right = rhs; - pn->pn_pos.end = rhs->pn_pos.end; - } ParseNode *newTernary(ParseNodeKind kind, ParseNode *first, ParseNode *second, ParseNode *third, @@ -174,12 +173,22 @@ class FullParseHandler return new_(kind, op, first, second, third); } + ParseNode *newLabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin) { + return new_(label, stmt, begin); + } + + ParseNode *newCaseOrDefault(uint32_t begin, ParseNode *expr, ParseNode *body) { + TokenPos pos = TokenPos::make(begin, body->pn_pos.end); + return new_(expr ? PNK_CASE : PNK_DEFAULT, JSOP_NOP, pos, expr, body); + } + ParseNode *newBreak(PropertyName *label, uint32_t begin, uint32_t end) { return new_(label, begin, end); } ParseNode *newContinue(PropertyName *label, uint32_t begin, uint32_t end) { return new_(label, begin, end); } + ParseNode *newDebuggerStatement(const TokenPos &pos) { return new_(pos); } @@ -193,8 +202,6 @@ class FullParseHandler inline bool addCatchBlock(ParseNode *catchList, ParseNode *letBlock, ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody); - inline void morphNameIntoLabel(ParseNode *name, ParseNode *statement); - inline void setLeaveBlockResult(ParseNode *block, ParseNode *kid, bool leaveBlockExpr); inline void setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *pn); @@ -213,7 +220,6 @@ class FullParseHandler return pn->isKind(kind) && !pn->isInParens(); } - inline void noteLValue(ParseNode *pn); inline bool finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op); void setBeginPosition(ParseNode *pn, ParseNode *oth) { @@ -292,9 +298,6 @@ class FullParseHandler } return NULL; } - bool isEmptySemicolon(ParseNode *pn) { - return pn->isKind(PNK_SEMI) && !pn->pn_kid; - } inline ParseNode *makeAssignment(ParseNode *pn, ParseNode *rhs); @@ -367,14 +370,6 @@ FullParseHandler::addCatchBlock(ParseNode *catchList, ParseNode *letBlock, return true; } -inline void -FullParseHandler::morphNameIntoLabel(ParseNode *name, ParseNode *statement) -{ - name->setKind(PNK_COLON); - name->pn_pos.end = statement->pn_pos.end; - name->pn_expr = statement; -} - inline void FullParseHandler::setLeaveBlockResult(ParseNode *block, ParseNode *kid, bool leaveBlockExpr) { @@ -419,15 +414,6 @@ FullParseHandler::newLexicalScope(ObjectBox *blockbox) return pn; } -inline void -FullParseHandler::noteLValue(ParseNode *pn) -{ - if (pn->isUsed()) - pn->pn_lexdef->pn_dflags |= PND_ASSIGNED; - - pn->pn_dflags |= PND_ASSIGNED; -} - inline bool FullParseHandler::finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op) { @@ -445,7 +431,7 @@ FullParseHandler::finishInitializerAssignment(ParseNode *pn, ParseNode *init, JS ? JSOP_SETCONST : JSOP_SETNAME); - noteLValue(pn); + pn->markAsAssigned(); /* The declarator's position must include the initializer. */ pn->pn_pos.end = init->pn_pos.end; diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index 109f22ce47c9..9f079059237b 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -8,10 +8,13 @@ #include "jsfun.h" #include "jsprf.h" + #include "frontend/BytecodeCompiler.h" #include "frontend/ParseNode.h" #include "frontend/SharedContext.h" +#include "jsfuninlines.h" + #include "vm/String-inl.h" #include "vm/StringBuffer.h" @@ -175,8 +178,6 @@ class NameResolver JSAtom *resolveFun(ParseNode *pn, HandleAtom prefix) { JS_ASSERT(pn != NULL && pn->isKind(PNK_FUNCTION)); RootedFunction fun(cx, pn->pn_funbox->function()); - if (nparents == 0) - return NULL; StringBuffer buf(cx); this->buf = &buf; @@ -184,7 +185,7 @@ class NameResolver /* If the function already has a name, use that */ if (fun->displayAtom() != NULL) { if (prefix == NULL) - return fun->atom(); + return fun->displayAtom(); if (!buf.append(prefix) || !buf.append("/") || !buf.append(fun->displayAtom())) diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index fe913db666d5..600d48260b56 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -530,7 +530,7 @@ Parser::cloneLeftHandSide(ParseNode *opn) pn2 = handler.new_(PNK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target); } else if (opn2->isArity(PN_NULLARY)) { - JS_ASSERT(opn2->isKind(PNK_COMMA)); + JS_ASSERT(opn2->isKind(PNK_ELISION)); pn2 = cloneParseTree(opn2); } else { pn2 = cloneLeftHandSide(opn2); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index c3e0b2b79b55..474f4a2a048e 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -75,7 +75,9 @@ class UpvarCookie F(DOT) \ F(ELEM) \ F(ARRAY) \ + F(ELISION) \ F(STATEMENTLIST) \ + F(LABEL) \ F(OBJECT) \ F(CALL) \ F(NAME) \ @@ -181,7 +183,8 @@ class UpvarCookie * * The long comment after this enum block describes the kinds in detail. */ -enum ParseNodeKind { +enum ParseNodeKind +{ #define EMIT_ENUM(name) PNK_##name, FOR_EACH_PARSE_NODE_KIND(EMIT_ENUM) #undef EMIT_ENUM @@ -284,7 +287,7 @@ enum ParseNodeKind { * pn_prologue: true if Directive Prologue member * in original source, not introduced via * constant folding or other tree rewriting - * PNK_COLON name pn_atom: label, pn_expr: labeled statement + * PNK_LABEL name pn_atom: label, pn_expr: labeled statement * * * All left-associated binary trees of the same type are optimized into lists @@ -357,7 +360,7 @@ enum ParseNodeKind { * PNK_GENEXP list Exactly like PNK_CALL, used for the implicit call * in the desugaring of a generator-expression. * PNK_ARRAY list pn_head: list of pn_count array element exprs - * [,,] holes are represented by PNK_COMMA nodes + * [,,] holes are represented by PNK_ELISION nodes * pn_xflags: PN_ENDCOMMA if extra comma at end * PNK_OBJECT list pn_head: list of pn_count binary PNK_COLON nodes * PNK_COLON binary key-value pair in object initializer or @@ -392,7 +395,8 @@ enum ParseNodeKind { * pn_kid: array comprehension expression * PNK_NOP nullary */ -enum ParseNodeArity { +enum ParseNodeArity +{ PN_NULLARY, /* 0 kids, only pn_atom/pn_dval/etc. */ PN_UNARY, /* one kid, plus a couple of scalars */ PN_BINARY, /* two kids, plus a couple of scalars */ @@ -404,6 +408,7 @@ enum ParseNodeArity { struct Definition; +class LabeledStatement; class LoopControlStatement; class BreakStatement; class ContinueStatement; @@ -411,7 +416,8 @@ class ConditionalExpression; class PropertyAccess; class ModuleBox; -struct ParseNode { +struct ParseNode +{ private: uint32_t pn_type : 16, /* PNK_* type */ pn_op : 8, /* see JSOp enum and jsopcode.tbl */ @@ -723,11 +729,6 @@ struct ParseNode { /* Return true if this node appears in a Directive Prologue. */ bool isDirectivePrologueMember() const { return pn_prologue; } -#ifdef JS_HAS_DESTRUCTURING - /* Return true if this represents a hole in an array literal. */ - bool isArrayHole() const { return isKind(PNK_COMMA) && isArity(PN_NULLARY); } -#endif - #ifdef JS_HAS_GENERATOR_EXPRS ParseNode *generatorExpr() const { JS_ASSERT(isKind(PNK_GENEXP)); @@ -738,6 +739,8 @@ struct ParseNode { } #endif + inline void markAsAssigned(); + /* * Compute a pointer to the last element in a singly-linked list. NB: list * must be non-empty for correct PN_LAST usage -- this is asserted! @@ -813,7 +816,11 @@ struct ParseNode { #endif }; -struct NullaryNode : public ParseNode { +struct NullaryNode : public ParseNode +{ + NullaryNode(ParseNodeKind kind, const TokenPos &pos) + : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos) {} + static inline NullaryNode *create(ParseNodeKind kind, FullParseHandler *handler) { return (NullaryNode *) ParseNode::create(kind, PN_NULLARY, handler); } @@ -827,7 +834,8 @@ struct NullaryNode : public ParseNode { #endif }; -struct UnaryNode : public ParseNode { +struct UnaryNode : public ParseNode +{ UnaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *kid) : ParseNode(kind, op, PN_UNARY, pos) { @@ -847,7 +855,8 @@ struct UnaryNode : public ParseNode { #endif }; -struct BinaryNode : public ParseNode { +struct BinaryNode : public ParseNode +{ BinaryNode(ParseNodeKind kind, JSOp op, const TokenPos &pos, ParseNode *left, ParseNode *right) : ParseNode(kind, op, PN_BINARY, pos) { @@ -875,7 +884,8 @@ struct BinaryNode : public ParseNode { #endif }; -struct TernaryNode : public ParseNode { +struct TernaryNode : public ParseNode +{ TernaryNode(ParseNodeKind kind, JSOp op, ParseNode *kid1, ParseNode *kid2, ParseNode *kid3) : ParseNode(kind, op, PN_TERNARY, TokenPos::make((kid1 ? kid1 : kid2 ? kid2 : kid3)->pn_pos.begin, @@ -921,7 +931,8 @@ struct ListNode : public ParseNode #endif }; -struct CodeNode : public ParseNode { +struct CodeNode : public ParseNode +{ static inline CodeNode *create(ParseNodeKind kind, FullParseHandler *handler) { return (CodeNode *) ParseNode::create(kind, PN_CODE, handler); } @@ -935,7 +946,8 @@ struct CodeNode : public ParseNode { #endif }; -struct NameNode : public ParseNode { +struct NameNode : public ParseNode +{ static NameNode *create(ParseNodeKind kind, JSAtom *atom, FullParseHandler *handler, ParseContext *pc); @@ -950,13 +962,41 @@ struct NameNode : public ParseNode { #endif }; -struct LexicalScopeNode : public ParseNode { +struct LexicalScopeNode : public ParseNode +{ static inline LexicalScopeNode *create(ParseNodeKind kind, FullParseHandler *handler) { return (LexicalScopeNode *) ParseNode::create(kind, PN_NAME, handler); } }; -class LoopControlStatement : public ParseNode { +class LabeledStatement : public ParseNode +{ + public: + LabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin) + : ParseNode(PNK_LABEL, JSOP_NOP, PN_NAME, TokenPos::make(begin, stmt->pn_pos.end)) + { + pn_atom = label; + pn_expr = stmt; + } + + PropertyName *label() const { + return pn_atom->asPropertyName(); + } + + ParseNode *statement() const { + return pn_expr; + } + + static bool test(const ParseNode &node) { + bool match = node.isKind(PNK_LABEL); + JS_ASSERT_IF(match, node.isArity(PN_NAME)); + JS_ASSERT_IF(match, node.isOp(JSOP_NOP)); + return match; + } +}; + +class LoopControlStatement : public ParseNode +{ protected: LoopControlStatement(ParseNodeKind kind, PropertyName *label, uint32_t begin, uint32_t end) : ParseNode(kind, JSOP_NOP, PN_NULLARY, TokenPos::make(begin, end)) @@ -979,7 +1019,8 @@ class LoopControlStatement : public ParseNode { } }; -class BreakStatement : public LoopControlStatement { +class BreakStatement : public LoopControlStatement +{ public: BreakStatement(PropertyName *label, uint32_t begin, uint32_t end) : LoopControlStatement(PNK_BREAK, label, begin, end) @@ -993,7 +1034,8 @@ class BreakStatement : public LoopControlStatement { } }; -class ContinueStatement : public LoopControlStatement { +class ContinueStatement : public LoopControlStatement +{ public: ContinueStatement(PropertyName *label, uint32_t begin, uint32_t end) : LoopControlStatement(PNK_CONTINUE, label, begin, end) @@ -1007,14 +1049,16 @@ class ContinueStatement : public LoopControlStatement { } }; -class DebuggerStatement : public ParseNode { +class DebuggerStatement : public ParseNode +{ public: DebuggerStatement(const TokenPos &pos) : ParseNode(PNK_DEBUGGER, JSOP_NOP, PN_NULLARY, pos) { } }; -class ConditionalExpression : public ParseNode { +class ConditionalExpression : public ParseNode +{ public: ConditionalExpression(ParseNode *condition, ParseNode *thenExpr, ParseNode *elseExpr) : ParseNode(PNK_CONDITIONAL, JSOP_NOP, PN_TERNARY, @@ -1048,24 +1092,28 @@ class ConditionalExpression : public ParseNode { } }; -class ThisLiteral : public ParseNode { +class ThisLiteral : public ParseNode +{ public: ThisLiteral(const TokenPos &pos) : ParseNode(PNK_THIS, JSOP_THIS, PN_NULLARY, pos) { } }; -class NullLiteral : public ParseNode { +class NullLiteral : public ParseNode +{ public: NullLiteral(const TokenPos &pos) : ParseNode(PNK_NULL, JSOP_NULL, PN_NULLARY, pos) { } }; -class BooleanLiteral : public ParseNode { +class BooleanLiteral : public ParseNode +{ public: BooleanLiteral(bool b, const TokenPos &pos) : ParseNode(b ? PNK_TRUE : PNK_FALSE, b ? JSOP_TRUE : JSOP_FALSE, PN_NULLARY, pos) { } }; -class PropertyAccess : public ParseNode { +class PropertyAccess : public ParseNode +{ public: PropertyAccess(ParseNode *lhs, PropertyName *name, uint32_t begin, uint32_t end) : ParseNode(PNK_DOT, JSOP_GETPROP, PN_NAME, TokenPos::make(begin, end)) @@ -1091,7 +1139,8 @@ class PropertyAccess : public ParseNode { } }; -class PropertyByValue : public ParseNode { +class PropertyByValue : public ParseNode +{ public: PropertyByValue(ParseNode *lhs, ParseNode *propExpr, uint32_t begin, uint32_t end) : ParseNode(PNK_ELEM, JSOP_GETELEM, PN_BINARY, TokenPos::make(begin, end)) @@ -1239,7 +1288,8 @@ struct Definition : public ParseNode } }; -class ParseNodeAllocator { +class ParseNodeAllocator +{ public: explicit ParseNodeAllocator(JSContext *cx) : cx(cx), freelist(NULL) {} @@ -1268,6 +1318,15 @@ ParseNode::test(unsigned flag) const return !!(pn_dflags & flag); } +inline void +ParseNode::markAsAssigned() +{ + JS_ASSERT(js_CodeSpec[pn_op].format & JOF_NAME); + if (isUsed()) + pn_lexdef->pn_dflags |= PND_ASSIGNED; + pn_dflags |= PND_ASSIGNED; +} + inline Definition * ParseNode::resolve() { @@ -1295,7 +1354,8 @@ ParseNode::isConstant() } } -class ObjectBox { +class ObjectBox +{ public: JSObject *object; @@ -1316,7 +1376,8 @@ class ObjectBox { ObjectBox(Module *module, ObjectBox *traceLink); }; -enum ParseReportKind { +enum ParseReportKind +{ ParseError, ParseWarning, ParseExtraWarning, diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 97580b021f3f..fca697549035 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -48,6 +48,7 @@ #include "vm/Shape.h" #include "jsatominlines.h" +#include "jsobjinlines.h" #include "jsscriptinlines.h" #include "frontend/ParseMaps-inl.h" @@ -419,9 +420,6 @@ Parser::Parser(JSContext *cx, const CompileOptions &options, abortedSyntaxParse(false), handler(cx, tokenStream, foldConstants, syntaxParser, lazyOuterFunction) { - // XXX bug 678037 always disable syntax parsing for now. - handler.disableSyntaxParser(); - cx->runtime()->activeCompilations++; // The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings @@ -487,6 +485,8 @@ FunctionBox::FunctionBox(JSContext *cx, ObjectBox* traceListHead, JSFunction *fu inGenexpLambda(false), useAsm(false), insideUseAsm(outerpc && outerpc->useAsmOrInsideUseAsm()), + usesArguments(false), + usesApply(false), funCxFlags() { JS_ASSERT(fun->isTenured()); @@ -925,6 +925,7 @@ Parser::checkFunctionArguments() dn->pn_dflags |= PND_IMPLICITARGUMENTS; if (!pc->define(context, arguments, dn, Definition::VAR)) return false; + pc->sc->asFunctionBox()->usesArguments = true; break; } } @@ -1014,11 +1015,15 @@ template <> bool Parser::checkFunctionArguments() { - if (pc->sc->asFunctionBox()->function()->hasRest()) { - if (pc->lexdeps->lookup(context->names().arguments)) { + bool hasRest = pc->sc->asFunctionBox()->function()->hasRest(); + + if (pc->lexdeps->lookup(context->names().arguments)) { + pc->sc->asFunctionBox()->usesArguments = true; + if (hasRest) { report(ParseError, false, null(), JSMSG_ARGUMENTS_AND_REST); return false; } + } else if (hasRest) { DefinitionNode maybeArgDef = pc->decls().lookupFirst(context->names().arguments); if (maybeArgDef && handler.getDefinitionKind(maybeArgDef) != Definition::ARG) { report(ParseError, false, null(), JSMSG_ARGUMENTS_AND_REST); @@ -1074,27 +1079,6 @@ Parser::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ return pn; } -static void -ForgetUse(ParseNode *pn) -{ - if (!pn->isUsed()) { - JS_ASSERT(!pn->isDefn()); - return; - } - - ParseNode **pnup = &pn->lexdef()->dn_uses; - ParseNode *pnu; - while ((pnu = *pnup) != pn) - pnup = &pnu->pn_link; - *pnup = pn->pn_link; - pn->setUsed(false); -} - -static void -ForgetUse(SyntaxParseHandler::Node pn) -{ -} - /* See comment for use in Parser::functionDef. */ template <> bool @@ -1341,14 +1325,6 @@ Parser::leaveFunction(ParseNode *fn, HandlePropertyName funNam continue; } - /* - * If there are no uses of this placeholder (e.g., it was created - * for an identifierName that turned out to be a label), there is - * nothing left to do. - */ - if (!dn->dn_uses) - continue; - Definition *outer_dn = outerpc->decls().lookupFirst(atom); /* @@ -2046,7 +2022,7 @@ Parser::finishFunctionDefinition(Node pn, FunctionBox *funbo size_t numFreeVariables = pc->lexdeps->count(); size_t numInnerFunctions = pc->innerFunctions.length(); - LazyScript *lazy = LazyScript::Create(context, numFreeVariables, numInnerFunctions, + LazyScript *lazy = LazyScript::Create(context, numFreeVariables, numInnerFunctions, versionNumber(), funbox->bufStart, funbox->bufEnd, funbox->startLine, funbox->startColumn); if (!lazy) @@ -2064,6 +2040,8 @@ Parser::finishFunctionDefinition(Node pn, FunctionBox *funbo if (pc->sc->strict) lazy->setStrict(); + if (funbox->usesArguments && funbox->usesApply) + lazy->setUsesArgumentsAndApply(); PropagateTransitiveParseFlags(funbox, lazy); funbox->object->toFunction()->initLazyScript(lazy); @@ -2173,6 +2151,11 @@ Parser::functionArgsAndBody(Node pn, HandleFunction fun, *becameStrict = false; ParseContext *outerpc = pc; + // As from a full parse handler, abort if functions are defined within + // lexical scopes. + if (pc->topScopeStmt) + return abortIfSyntaxParser(); + // Create box for fun->object early to protect against last-ditch GC. FunctionBox *funbox = newFunctionBox(fun, pc, strict); if (!funbox) @@ -2503,7 +2486,7 @@ Parser::maybeParseDirective(Node pn, bool *cont) template <> void -Parser::addStatementToList(ParseNode *pn, ParseNode *kid, bool *hasFunctionStmt) +Parser::addStatementToList(ParseNode *pn, ParseNode *kid) { JS_ASSERT(pn->isKind(PNK_STATEMENTLIST)); @@ -2512,21 +2495,12 @@ Parser::addStatementToList(ParseNode *pn, ParseNode *kid, bool * PNX_FUNCDEFS notifies the emitter that the block contains body- * level function definitions that should be processed before the * rest of nodes. - * - * |hasFunctionStmt| is for the TOK_LC case in Statement. It - * is relevant only for function definitions not at body-level, - * which we call function statements. */ if (pc->atBodyLevel()) { pn->pn_xflags |= PNX_FUNCDEFS; } else { - /* - * General deoptimization was done in functionDef, here we just - * need to tell TOK_LC in Parser::statement to add braces. - */ + /* General deoptimization was done in functionDef. */ JS_ASSERT_IF(pc->sc->isFunctionBox(), pc->sc->asFunctionBox()->hasExtensibleScope()); - if (hasFunctionStmt) - *hasFunctionStmt = true; } } @@ -2536,7 +2510,7 @@ Parser::addStatementToList(ParseNode *pn, ParseNode *kid, bool template <> void -Parser::addStatementToList(Node pn, Node kid, bool *hasFunctionStmt) +Parser::addStatementToList(Node pn, Node kid) { } @@ -2547,11 +2521,9 @@ Parser::addStatementToList(Node pn, Node kid, bool *hasFunct */ template typename ParseHandler::Node -Parser::statements(bool *hasFunctionStmt) +Parser::statements() { JS_CHECK_RECURSION(context, return null()); - if (hasFunctionStmt) - *hasFunctionStmt = false; Node pn = handler.newList(PNK_STATEMENTLIST); if (!pn) @@ -2584,7 +2556,7 @@ Parser::statements(bool *hasFunctionStmt) return null(); } - addStatementToList(pn, next, hasFunctionStmt); + addStatementToList(pn, next); } /* @@ -2993,7 +2965,7 @@ Parser::bindDestructuringVar(BindData *data, if (data->op == JSOP_DEFCONST) pn->pn_dflags |= PND_CONST; - handler.noteLValue(pn); + pn->markAsAssigned(); return true; } @@ -3021,7 +2993,7 @@ Parser::bindDestructuringLHS(ParseNode *pn) { switch (pn->getKind()) { case PNK_NAME: - handler.noteLValue(pn); + pn->markAsAssigned(); /* FALL THROUGH */ case PNK_DOT: @@ -3105,8 +3077,7 @@ Parser::checkDestructuring(BindData *data, if (left->isKind(PNK_ARRAY)) { for (ParseNode *pn = left->pn_head; pn; pn = pn->pn_next) { - /* Nullary comma is an elision; binary comma is an expression.*/ - if (!pn->isArrayHole()) { + if (!pn->isKind(PNK_ELISION)) { if (pn->isKind(PNK_ARRAY) || pn->isKind(PNK_OBJECT)) { ok = checkDestructuring(data, pn, false); } else { @@ -3542,7 +3513,10 @@ Parser::switchStatement() bool seenDefault = false; TokenKind tt; while ((tt = tokenStream.getToken()) != TOK_RC) { - Node casepn; + uint32_t caseBegin = tokenStream.currentToken().pos.begin; + + ParseNodeKind caseKind; + Node caseExpr; switch (tt) { case TOK_DEFAULT: if (seenDefault) { @@ -3550,21 +3524,16 @@ Parser::switchStatement() return null(); } seenDefault = true; - casepn = handler.newBinary(PNK_DEFAULT); - if (!casepn) - return null(); + caseKind = PNK_DEFAULT; + caseExpr = null(); break; case TOK_CASE: - { - Node left = expr(); - if (!left) - return null(); - casepn = handler.newBinary(PNK_CASE, left); - if (!casepn) + caseKind = PNK_CASE; + caseExpr = expr(); + if (!caseExpr) return null(); break; - } case TOK_ERROR: return null(); @@ -3574,8 +3543,6 @@ Parser::switchStatement() return null(); } - handler.addList(caseList, casepn); - MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); Node body = handler.newList(PNK_STATEMENTLIST); @@ -3593,7 +3560,10 @@ Parser::switchStatement() handler.addList(body, stmt); } - handler.setBinaryRHS(casepn, body); + Node casepn = handler.newCaseOrDefault(caseBegin, caseExpr, body); + if (!casepn) + return null(); + handler.addList(caseList, casepn); } /* @@ -3916,7 +3886,7 @@ Parser::forStatement() switch (pn2->getKind()) { case PNK_NAME: /* Beware 'for (arguments in ...)' with or without a 'var'. */ - handler.noteLValue(pn2); + pn2->markAsAssigned(); break; #if JS_HAS_DESTRUCTURING @@ -4099,6 +4069,7 @@ Parser::forStatement() /* Check that the left side of the 'in' or 'of' is valid. */ if (!forDecl && lhsNode != SyntaxParseHandler::NodeName && + lhsNode != SyntaxParseHandler::NodeGetProp && lhsNode != SyntaxParseHandler::NodeLValue) { JS_ALWAYS_FALSE(abortIfSyntaxParser()); @@ -4311,12 +4282,15 @@ Parser::tryStatement() return pn; } -template -typename ParseHandler::Node -Parser::withStatement() +template <> +ParseNode * +Parser::withStatement() { - if (!abortIfSyntaxParser()) + if (handler.syntaxParser) { + handler.disableSyntaxParser(); + abortedSyntaxParse = true; return null(); + } JS_ASSERT(tokenStream.isCurrentTokenType(TOK_WITH)); uint32_t begin = tokenStream.currentToken().pos.begin; @@ -4354,7 +4328,7 @@ Parser::withStatement() * to safely optimize binding globals (see bug 561923). */ for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) { - DefinitionNode defn = r.front().value().get(); + DefinitionNode defn = r.front().value().get(); DefinitionNode lexdep = handler.resolve(defn); handler.deoptimizeUsesWithin(lexdep, TokenPos::make(begin, tokenStream.currentToken().pos.begin)); @@ -4369,6 +4343,14 @@ Parser::withStatement() return pn; } +template <> +SyntaxParseHandler::Node +Parser::withStatement() +{ + JS_ALWAYS_FALSE(abortIfSyntaxParser()); + return null(); +} + #if JS_HAS_BLOCK_SCOPE template <> ParseNode * @@ -4499,6 +4481,35 @@ Parser::letStatement() #endif // JS_HAS_BLOCK_SCOPE +template +typename ParseHandler::Node +Parser::labeledStatement() +{ + uint32_t begin = tokenStream.currentToken().pos.begin; + RootedPropertyName label(context, tokenStream.currentToken().name()); + for (StmtInfoPC *stmt = pc->topStmt; stmt; stmt = stmt->down) { + if (stmt->type == STMT_LABEL && stmt->label == label) { + report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL); + return null(); + } + } + + tokenStream.consumeKnownToken(TOK_COLON); + + /* Push a label struct and parse the statement. */ + StmtInfoPC stmtInfo(context); + PushStatementPC(pc, &stmtInfo, STMT_LABEL); + stmtInfo.label = label; + Node pn = statement(); + if (!pn) + return null(); + + /* Pop the label, set pn_expr, and return early. */ + PopStatementPC(context, pc); + + return handler.newLabeledStatement(label, pn, begin); +} + template typename ParseHandler::Node Parser::expressionStatement() @@ -4508,37 +4519,6 @@ Parser::expressionStatement() if (!pn2) return null(); - if (tokenStream.peekToken() == TOK_COLON) { - RootedAtom label(context, handler.isName(pn2)); - if (!label) { - report(ParseError, false, null(), JSMSG_BAD_LABEL); - return null(); - } - for (StmtInfoPC *stmt = pc->topStmt; stmt; stmt = stmt->down) { - if (stmt->type == STMT_LABEL && stmt->label == label) { - report(ParseError, false, null(), JSMSG_DUPLICATE_LABEL); - return null(); - } - } - ForgetUse(pn2); - - (void) tokenStream.getToken(); - - /* Push a label struct and parse the statement. */ - StmtInfoPC stmtInfo(context); - PushStatementPC(pc, &stmtInfo, STMT_LABEL); - stmtInfo.label = label; - Node pn = statement(); - if (!pn) - return null(); - - /* Pop the label, set pn_expr, and return early. */ - PopStatementPC(context, pc); - - handler.morphNameIntoLabel(pn2, pn); - return pn2; - } - Node pn = handler.newUnary(PNK_SEMI, pn2); /* Check termination of this primitive statement. */ @@ -4566,18 +4546,18 @@ Parser::statement() if (!cond) return null(); + if (tokenStream.peekToken() == TOK_SEMI && + !report(ParseExtraWarning, false, null(), JSMSG_EMPTY_CONSEQUENT)) + { + return null(); + } + StmtInfoPC stmtInfo(context); PushStatementPC(pc, &stmtInfo, STMT_IF); Node thenBranch = statement(); if (!thenBranch) return null(); - if (handler.isEmptySemicolon(thenBranch) && - !report(ParseExtraWarning, false, null(), JSMSG_EMPTY_CONSEQUENT)) - { - return null(); - } - Node elseBranch; if (tokenStream.matchToken(TOK_ELSE, TSF_OPERAND)) { stmtInfo.type = STMT_ELSE; @@ -4803,8 +4783,8 @@ Parser::statement() StmtInfoPC stmtInfo(context); if (!PushBlocklikeStatement(&stmtInfo, STMT_BLOCK, pc)) return null(); - bool hasFunctionStmt; - pn = statements(&hasFunctionStmt); + + pn = statements(); if (!pn) return null(); @@ -4827,12 +4807,16 @@ Parser::statement() case TOK_ERROR: return null(); - case TOK_NAME: - if (tokenStream.currentToken().name() == context->names().module && - tokenStream.peekTokenSameLine(TSF_OPERAND) == TOK_STRING) + case TOK_NAME: { + if (tokenStream.peekToken() == TOK_COLON) + return labeledStatement(); + if (tokenStream.currentToken().name() == context->names().module + && tokenStream.peekTokenSameLine() == TOK_STRING) { return moduleDecl(); } + } + /* FALL THROUGH */ default: return expressionStatement(); @@ -5200,7 +5184,7 @@ Parser::setAssignmentLhsOps(ParseNode *pn, JSOp op) if (!checkStrictAssignment(pn)) return false; pn->setOp(pn->isOp(JSOP_GETLOCAL) ? JSOP_SETLOCAL : JSOP_SETNAME); - handler.noteLValue(pn); + pn->markAsAssigned(); break; case PNK_DOT: pn->setOp(JSOP_SETPROP); @@ -5235,8 +5219,12 @@ bool Parser::setAssignmentLhsOps(Node pn, JSOp op) { /* Full syntax checking of valid assignment LHS terms requires a parse tree. */ - if (pn != SyntaxParseHandler::NodeName && pn != SyntaxParseHandler::NodeLValue) + if (pn != SyntaxParseHandler::NodeName && + pn != SyntaxParseHandler::NodeGetProp && + pn != SyntaxParseHandler::NodeLValue) + { return abortIfSyntaxParser(); + } return checkStrictAssignment(pn); } @@ -5337,7 +5325,7 @@ Parser::setIncOpKid(ParseNode *pn, ParseNode *kid, TokenKind t switch (kid->getKind()) { case PNK_NAME: - handler.noteLValue(kid); + kid->markAsAssigned(); break; case PNK_CALL: @@ -5419,8 +5407,12 @@ Parser::checkDeleteExpression(Node *pn) // Treat deletion of non-lvalues as ambiguous, so that any error associated // with deleting a call expression is reported. - if (*pn != SyntaxParseHandler::NodeLValue && strictMode()) + if (*pn != SyntaxParseHandler::NodeGetProp && + *pn != SyntaxParseHandler::NodeLValue && + strictMode()) + { return abortIfSyntaxParser(); + } return true; } @@ -6444,10 +6436,13 @@ Parser::memberExpr(TokenKind tt, bool allowCallSyntax) } } else if (JSAtom *atom = handler.isGetProp(lhs)) { /* Select JSOP_FUNAPPLY given foo.apply(...). */ - if (atom == context->names().apply) + if (atom == context->names().apply) { handler.setOp(nextMember, JSOP_FUNAPPLY); - else if (atom == context->names().call) + if (pc->sc->isFunctionBox()) + pc->sc->asFunctionBox()->usesApply = true; + } else if (atom == context->names().call) { handler.setOp(nextMember, JSOP_FUNCALL); + } } handler.setBeginPosition(nextMember, lhs); @@ -6551,7 +6546,17 @@ template <> SyntaxParseHandler::Node Parser::newRegExp(const jschar *buf, size_t length, RegExpFlag flags) { - return SyntaxParseHandler::NodeGeneric; + // Create the regexp even when doing a syntax parse, to check the regexp's syntax. + const StableCharPtr chars(buf, length); + RegExpStatics *res = context->regExpStatics(); + + RegExpObject *reobj; + if (context->hasfp()) + reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream); + else + reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream); + + return reobj ? SyntaxParseHandler::NodeGeneric : SyntaxParseHandler::NodeFailure; } template @@ -6601,9 +6606,8 @@ Parser::primaryExpr(TokenKind tt) break; if (tt == TOK_COMMA) { - /* So CURRENT_TOKEN gets TOK_COMMA and not TOK_LB. */ tokenStream.matchToken(TOK_COMMA); - pn2 = handler.newNullary(PNK_COMMA); + pn2 = handler.newElision(); if (!pn2) return null(); handler.setListFlag(pn, PNX_SPECIALARRAYINIT | PNX_NONCONST); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 4a041f553c47..4f7f361984c2 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -421,10 +421,11 @@ struct Parser : private AutoGCRooter, public StrictModeGetter Node moduleDecl(); Node functionStmt(); Node functionExpr(); - Node statements(bool *hasFunctionStmt = NULL); + Node statements(); Node switchStatement(); Node forStatement(); + Node labeledStatement(); Node tryStatement(); Node withStatement(); #if JS_HAS_BLOCK_SCOPE @@ -482,7 +483,7 @@ struct Parser : private AutoGCRooter, public StrictModeGetter bool setAssignmentLhsOps(Node pn, JSOp op); bool matchInOrOf(bool *isForOfp); - void addStatementToList(Node pn, Node kid, bool *hasFunctionStmt); + void addStatementToList(Node pn, Node kid); bool checkFunctionArguments(); bool makeDefIntoUse(Definition *dn, Node pn, JSAtom *atom); bool checkFunctionDefinition(HandlePropertyName funName, Node *pn, FunctionSyntaxKind kind, diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index ae17cf1e3a2e..0585971a12b5 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -184,9 +184,9 @@ class GlobalSharedContext : public SharedContext JSObject *scopeChain() const { return scopeChain_; } }; - -class ModuleBox : public ObjectBox, public SharedContext { -public: +class ModuleBox : public ObjectBox, public SharedContext +{ + public: Bindings bindings; ModuleBox(JSContext *cx, ObjectBox *traceListHead, Module *module, @@ -210,6 +210,10 @@ class FunctionBox : public ObjectBox, public SharedContext bool useAsm:1; /* function contains "use asm" directive */ bool insideUseAsm:1; /* nested function of function of "use asm" directive */ + // Fields for use in heuristics. + bool usesArguments:1; /* contains a free use of 'arguments' */ + bool usesApply:1; /* contains an f.apply() call */ + FunctionContextFlags funCxFlags; template diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 19f411f5becc..3a6d17d5aff4 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -32,6 +32,7 @@ class SyntaxParseHandler NodeFailure = 0, NodeGeneric, NodeName, + NodeGetProp, NodeString, NodeStringExprStatement, NodeLValue @@ -70,7 +71,7 @@ class SyntaxParseHandler Node newNullLiteral(const TokenPos &pos) { return NodeGeneric; } Node newConditional(Node cond, Node thenExpr, Node elseExpr) { return NodeGeneric; } - Node newNullary(ParseNodeKind kind) { return NodeGeneric; } + Node newElision() { return NodeGeneric; } Node newUnary(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) { if (kind == PNK_SEMI && kid == NodeString) @@ -89,12 +90,17 @@ class SyntaxParseHandler ParseContext *pc, JSOp op = JSOP_NOP) { return NodeGeneric; } - void setBinaryRHS(Node pn, Node rhs) {} Node newTernary(ParseNodeKind kind, Node first, Node second, Node third, JSOp op = JSOP_NOP) { return NodeGeneric; } + Node newLabeledStatement(PropertyName *label, Node stmt, uint32_t begin) { + return NodeGeneric; + } + Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { + return NodeGeneric; + } Node newBreak(PropertyName *label, uint32_t begin, uint32_t end) { return NodeGeneric; } @@ -102,13 +108,16 @@ class SyntaxParseHandler return NodeGeneric; } Node newDebuggerStatement(const TokenPos &pos) { return NodeGeneric; } - Node newPropertyAccess(Node pn, PropertyName *name, uint32_t end) { return NodeLValue; } + Node newPropertyAccess(Node pn, PropertyName *name, uint32_t end) + { + lastAtom = name; + return NodeGetProp; + } Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeLValue; } bool addCatchBlock(Node catchList, Node letBlock, Node catchName, Node catchGuard, Node catchBody) { return true; } - void morphNameIntoLabel(Node name, Node statement) {} void setLeaveBlockResult(Node block, Node kid, bool leaveBlockExpr) {} void setLastFunctionArgumentDefault(Node funcpn, Node pn) {} @@ -124,7 +133,6 @@ class SyntaxParseHandler return false; } - void noteLValue(Node pn) {} bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; } void setBeginPosition(Node pn, Node oth) {} @@ -159,7 +167,9 @@ class SyntaxParseHandler PropertyName *isName(Node pn) { return (pn == NodeName) ? lastAtom->asPropertyName() : NULL; } - PropertyName *isGetProp(Node pn) { return NULL; } + PropertyName *isGetProp(Node pn) { + return (pn == NodeGetProp) ? lastAtom->asPropertyName() : NULL; + } JSAtom *isStringExprStatement(Node pn, TokenPos *pos) { if (pn == NodeStringExprStatement) { *pos = lastStringPos; @@ -167,7 +177,6 @@ class SyntaxParseHandler } return NULL; } - bool isEmptySemicolon(Node pn) { return false; } Node makeAssignment(Node pn, Node rhs) { return NodeGeneric; } diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index e658b8bbef78..6c83d6434afa 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -557,7 +557,7 @@ TokenStream::advance(size_t position) void TokenStream::tell(Position *pos) { - pos->buf = userbuf.addressOfNextRawChar(); + pos->buf = userbuf.addressOfNextRawChar(/* allowPoisoned = */ true); pos->flags = flags; pos->lineno = lineno; pos->linebase = linebase; @@ -571,7 +571,7 @@ TokenStream::tell(Position *pos) void TokenStream::seek(const Position &pos) { - userbuf.setAddressOfNextRawChar(pos.buf); + userbuf.setAddressOfNextRawChar(pos.buf, /* allowPoisoned = */ true); flags = pos.flags; lineno = pos.lineno; linebase = pos.linebase; @@ -587,6 +587,7 @@ void TokenStream::seek(const Position &pos, const TokenStream &other) { srcCoords.fill(other.srcCoords); + lastFunctionKeyword = other.lastFunctionKeyword; seek(pos); } diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 941b6401dbe3..278a2360cc3e 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -832,14 +832,14 @@ class MOZ_STACK_CLASS TokenStream ptr--; } - const jschar *addressOfNextRawChar() const { - JS_ASSERT(ptr); /* make sure haven't been poisoned */ + const jschar *addressOfNextRawChar(bool allowPoisoned = false) const { + JS_ASSERT_IF(!allowPoisoned, ptr); /* make sure haven't been poisoned */ return ptr; } /* Use this with caution! */ - void setAddressOfNextRawChar(const jschar *a) { - JS_ASSERT(a); + void setAddressOfNextRawChar(const jschar *a, bool allowPoisoned = false) { + JS_ASSERT_IF(!allowPoisoned, a); ptr = a; } diff --git a/js/src/gc/Iteration.cpp b/js/src/gc/Iteration.cpp index 76693e5fecff..9421fd9f8882 100644 --- a/js/src/gc/Iteration.cpp +++ b/js/src/gc/Iteration.cpp @@ -12,7 +12,6 @@ #include "js/HashTable.h" #include "gc/GCInternals.h" -#include "jsobjinlines.h" #include "jsgcinlines.h" using namespace js; diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 05748691f39f..de6ba90068aa 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -10,12 +10,12 @@ #include "jsstr.h" #include "gc/Marking.h" -#include "gc/Nursery-inl.h" +#include "ion/IonCode.h" #include "vm/Shape.h" -#include "jsobjinlines.h" +#include "jscompartmentinlines.h" -#include "ion/IonCode.h" +#include "gc/Nursery-inl.h" #include "vm/Shape-inl.h" #include "vm/String-inl.h" diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 1666fcd640f4..f16c685710f8 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -19,6 +19,7 @@ #include "frontend/BytecodeCompiler.h" #include "gc/GCInternals.h" #include "gc/Marking.h" +#include "ion/IonCode.h" #ifdef JS_ION # include "ion/IonMacroAssembler.h" # include "ion/IonFrameIterator.h" @@ -28,7 +29,6 @@ #include "jsgcinlines.h" #include "jsobjinlines.h" -#include "ion/IonCode.h" #ifdef MOZ_VALGRIND # include diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp index 6273f3e56fe2..bb15dddbdde3 100644 --- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -16,7 +16,6 @@ #include "js/HashTable.h" #include "gc/GCInternals.h" -#include "jsobjinlines.h" #include "jsgcinlines.h" #ifdef MOZ_VALGRIND diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 28fcb0602fc4..ff75dac9846f 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -19,7 +19,6 @@ #include "ion/Ion.h" #endif -#include "jsobjinlines.h" #include "jsgcinlines.h" using namespace js; diff --git a/js/src/ion/AsmJS.cpp b/js/src/ion/AsmJS.cpp index 378ae3f3c412..c54d503f36fc 100644 --- a/js/src/ion/AsmJS.cpp +++ b/js/src/ion/AsmJS.cpp @@ -11,7 +11,6 @@ #include "ion/AsmJS.h" #include "ion/AsmJSModule.h" -#include "jsobjinlines.h" #include "frontend/ParseNode-inl.h" using namespace js; @@ -168,15 +167,13 @@ LoopControlMaybeLabel(ParseNode *pn) static inline PropertyName * LabeledStatementLabel(ParseNode *pn) { - JS_ASSERT(pn->isKind(PNK_COLON)); - return pn->pn_atom->asPropertyName(); + return pn->as().label(); } static inline ParseNode * LabeledStatementStatement(ParseNode *pn) { - JS_ASSERT(pn->isKind(PNK_COLON)); - return pn->expr(); + return pn->as().statement(); } static double @@ -1501,9 +1498,8 @@ class MOZ_STACK_CLASS ModuleCompiler JSAutoByteString name; if (!js_AtomToPrintableString(cx_, func.name, &name)) return; - slowFuns.reset(JS_smprintf("%s%s:%u:%u (%ums, %g%%)%s", slowFuns.get(), + slowFuns.reset(JS_smprintf("%s%s:%u:%u (%ums)%s", slowFuns.get(), name.ptr(), func.line, func.column, func.ms, - double(func.ms)/double(msTotal), i+1 < slowFunctions_.length() ? ", " : "")); if (!slowFuns) return; @@ -4353,7 +4349,7 @@ CheckDoWhile(FunctionCompiler &f, ParseNode *whileStmt, const LabelVector *maybe static bool CheckLabel(FunctionCompiler &f, ParseNode *labeledStmt, LabelVector *maybeLabels) { - JS_ASSERT(labeledStmt->isKind(PNK_COLON)); + JS_ASSERT(labeledStmt->isKind(PNK_LABEL)); PropertyName *label = LabeledStatementLabel(labeledStmt); ParseNode *stmt = LabeledStatementStatement(labeledStmt); @@ -4624,7 +4620,7 @@ CheckStatement(FunctionCompiler &f, ParseNode *stmt, LabelVector *maybeLabels) case PNK_WHILE: return CheckWhile(f, stmt, maybeLabels); case PNK_FOR: return CheckFor(f, stmt, maybeLabels); case PNK_DOWHILE: return CheckDoWhile(f, stmt, maybeLabels); - case PNK_COLON: return CheckLabel(f, stmt, maybeLabels); + case PNK_LABEL: return CheckLabel(f, stmt, maybeLabels); case PNK_IF: return CheckIf(f, stmt); case PNK_SWITCH: return CheckSwitch(f, stmt); case PNK_RETURN: return CheckReturn(f, stmt); @@ -6264,7 +6260,7 @@ AsmJSModule::~AsmJSModule() if (!exitDatum.fun) continue; - if (!exitDatum.fun->isInterpreted()) + if (!exitDatum.fun->hasScript()) continue; JSScript *script = exitDatum.fun->nonLazyScript(); diff --git a/js/src/ion/BaselineIC.cpp b/js/src/ion/BaselineIC.cpp index 871d92018b37..6a5fcb9f188c 100644 --- a/js/src/ion/BaselineIC.cpp +++ b/js/src/ion/BaselineIC.cpp @@ -1324,6 +1324,9 @@ ICUpdatedStub::addUpdateStubForValue(JSContext *cx, HandleScript script, HandleO return true; } + if (!obj->getType(cx)) + return false; + types::EnsureTrackPropertyTypes(cx, obj, id); if (val.isPrimitive()) { diff --git a/js/src/ion/BaselineIC.h b/js/src/ion/BaselineIC.h index 8f61016075cb..128283c48601 100644 --- a/js/src/ion/BaselineIC.h +++ b/js/src/ion/BaselineIC.h @@ -2717,7 +2717,7 @@ class ICUnaryArith_Double : public ICStub friend class ICStubSpace; ICUnaryArith_Double(IonCode *stubCode) - : ICStub(UnaryArith_Int32, stubCode) + : ICStub(UnaryArith_Double, stubCode) {} public: @@ -2733,7 +2733,7 @@ class ICUnaryArith_Double : public ICStub public: Compiler(JSContext *cx, JSOp op) - : ICMultiStubCompiler(cx, ICStub::UnaryArith_Int32, op) + : ICMultiStubCompiler(cx, ICStub::UnaryArith_Double, op) {} ICStub *getStub(ICStubSpace *space) { diff --git a/js/src/ion/BytecodeAnalysis.cpp b/js/src/ion/BytecodeAnalysis.cpp index 4a9a1be05596..c2f978fc8f53 100644 --- a/js/src/ion/BytecodeAnalysis.cpp +++ b/js/src/ion/BytecodeAnalysis.cpp @@ -7,7 +7,6 @@ #include "ion/BytecodeAnalysis.h" #include "jsopcode.h" #include "jsopcodeinlines.h" -#include "jsobjinlines.h" using namespace js; using namespace js::ion; diff --git a/js/src/ion/CodeGenerator.cpp b/js/src/ion/CodeGenerator.cpp index 53e18ba9d6c7..a8b5b8df7eb4 100644 --- a/js/src/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -1694,6 +1694,10 @@ CodeGenerator::visitCallKnown(LCallKnown *call) return true; } + // The calleereg is known to be a non-native function, but might point to + // a LazyScript instead of a JSScript. + masm.branchIfFunctionHasNoScript(calleereg, &uncompiled); + // Knowing that calleereg is a non-native function, load the JSScript. masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg); diff --git a/js/src/ion/Ion.cpp b/js/src/ion/Ion.cpp index 4e829bb4a2df..1990a4fb89dc 100644 --- a/js/src/ion/Ion.cpp +++ b/js/src/ion/Ion.cpp @@ -40,9 +40,12 @@ # include "arm/Lowering-arm.h" #endif #include "gc/Marking.h" + +#include "jscompartmentinlines.h" #include "jsgcinlines.h" #include "jsinferinlines.h" -#include "jsobjinlines.h" + +#include "gc/Barrier-inl.h" #include "vm/Stack-inl.h" #include "ion/IonFrames-inl.h" #include "ion/CompilerRoot.h" diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp index 4d8786b3b11a..defa2286ded3 100644 --- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -200,6 +200,8 @@ IonBuilder::getPolyCallTargets(types::StackTypeSet *calleeTypes, targets.clear(); return true; } + if (!typeObj->interpretedFunction->getOrCreateScript(cx)) + return false; DebugOnly appendOk = targets.append(typeObj->interpretedFunction); JS_ASSERT(appendOk); @@ -6264,8 +6266,11 @@ IonBuilder::jsop_getelem() if (ElementAccessIsDenseNative(obj, index)) { // Don't generate a fast path if there have been bounds check failures // and this access might be on a sparse property. - if (!ElementAccessHasExtraIndexedProperty(cx, obj) || !failedBoundsCheck_) - return jsop_getelem_dense(); + if (!ElementAccessHasExtraIndexedProperty(cx, obj) || !failedBoundsCheck_) { + MDefinition *id = current->pop(); + MDefinition *obj = current->pop(); + return jsop_getelem_dense(GetElem_Normal, obj, id); + } } int arrayType = TypedArray::TYPE_MAX; @@ -6330,11 +6335,8 @@ IonBuilder::jsop_getelem() } bool -IonBuilder::jsop_getelem_dense() +IonBuilder::jsop_getelem_dense(GetElemSafety safety, MDefinition *obj, MDefinition *id) { - MDefinition *id = current->pop(); - MDefinition *obj = current->pop(); - types::StackTypeSet *types = types::TypeScript::BytecodeTypes(script(), pc); if (JSOp(*pc) == JSOP_CALLELEM && !id->mightBeType(MIRType_String) && types->noConstraints()) { @@ -6351,6 +6353,7 @@ IonBuilder::jsop_getelem_dense() // undefined values have been observed at this access site and the access // cannot hit another indexed property on the object or its prototypes. bool readOutOfBounds = + safety == GetElem_Normal && types->hasType(types::Type::UndefinedType()) && !ElementAccessHasExtraIndexedProperty(cx, obj); @@ -6387,9 +6390,6 @@ IonBuilder::jsop_getelem_dense() if (loadDouble) elements = addConvertElementsToDoubles(elements); - MInitializedLength *initLength = MInitializedLength::New(elements); - current->add(initLength); - MInstruction *load; if (!readOutOfBounds) { @@ -6397,14 +6397,28 @@ IonBuilder::jsop_getelem_dense() // in-bounds elements, and the array is packed or its holes are not // read. This is the best case: we can separate the bounds check for // hoisting. - id = addBoundsCheck(id, initLength); + switch (safety) { + case GetElem_Normal: { + MInitializedLength *initLength = MInitializedLength::New(elements); + current->add(initLength); + id = addBoundsCheck(id, initLength); + break; + } - load = MLoadElement::New(elements, id, needsHoleCheck, loadDouble); + case GetElem_Unsafe: break; + case GetElem_UnsafeImmutable: break; + } + + bool knownImmutable = (safety == GetElem_UnsafeImmutable); + load = MLoadElement::New(elements, id, needsHoleCheck, loadDouble, + knownImmutable); current->add(load); } else { // This load may return undefined, so assume that we *can* read holes, // or that we can read out-of-bounds accesses. In this case, the bounds // check is part of the opcode. + MInitializedLength *initLength = MInitializedLength::New(elements); + current->add(initLength); load = MLoadElementHole::New(elements, id, initLength, needsHoleCheck); current->add(load); diff --git a/js/src/ion/IonBuilder.h b/js/src/ion/IonBuilder.h index e1a47e2c01da..d918f84eca56 100644 --- a/js/src/ion/IonBuilder.h +++ b/js/src/ion/IonBuilder.h @@ -41,6 +41,20 @@ class IonBuilder : public MIRGenerator SetElem_Unsafe, }; + enum GetElemSafety { + // Normal read like a[b] + GetElem_Normal, + + // Read due to UnsafeGetElement: + // - assumed to be in bounds, + GetElem_Unsafe, + + // Read due to UnsafeGetImmutableElement: + // - assumed to be in bounds, + // - assumed not to alias any stores + GetElem_UnsafeImmutable, + }; + struct DeferredEdge : public TempObject { MBasicBlock *block; @@ -391,7 +405,7 @@ class IonBuilder : public MIRGenerator bool jsop_intrinsic(HandlePropertyName name); bool jsop_bindname(PropertyName *name); bool jsop_getelem(); - bool jsop_getelem_dense(); + bool jsop_getelem_dense(GetElemSafety safety, MDefinition *object, MDefinition *index); bool jsop_getelem_typed(int arrayType); bool jsop_getelem_typed_static(bool *psucceeded); bool jsop_getelem_string(); @@ -486,6 +500,8 @@ class IonBuilder : public MIRGenerator InliningStatus inlineUnsafeSetElement(CallInfo &callInfo); bool inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base); bool inlineUnsafeSetTypedArrayElement(CallInfo &callInfo, uint32_t base, int arrayType); + InliningStatus inlineUnsafeGetElement(CallInfo &callInfo, + GetElemSafety safety); InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo); InliningStatus inlineNewDenseArray(CallInfo &callInfo); InliningStatus inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo); diff --git a/js/src/ion/Lowering.cpp b/js/src/ion/Lowering.cpp index 6b66a4abdebd..d5ef296fe055 100644 --- a/js/src/ion/Lowering.cpp +++ b/js/src/ion/Lowering.cpp @@ -13,7 +13,6 @@ #include "jsanalyze.h" #include "jsbool.h" #include "jsnum.h" -#include "jsobjinlines.h" #include "shared/Lowering-shared-inl.h" #include "mozilla/DebugOnly.h" diff --git a/js/src/ion/MCallOptimize.cpp b/js/src/ion/MCallOptimize.cpp index e2691532e577..06cb9a79297f 100644 --- a/js/src/ion/MCallOptimize.cpp +++ b/js/src/ion/MCallOptimize.cpp @@ -90,6 +90,10 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native) // Array intrinsics. if (native == intrinsic_UnsafeSetElement) return inlineUnsafeSetElement(callInfo); + if (native == intrinsic_UnsafeGetElement) + return inlineUnsafeGetElement(callInfo, GetElem_Unsafe); + if (native == intrinsic_UnsafeGetImmutableElement) + return inlineUnsafeGetElement(callInfo, GetElem_UnsafeImmutable); if (native == intrinsic_NewDenseArray) return inlineNewDenseArray(callInfo); @@ -952,9 +956,10 @@ IonBuilder::inlineUnsafeSetElement(CallInfo &callInfo) /* Important: * * Here we inline each of the stores resulting from a call to - * %UnsafeSetElement(). It is essential that these stores occur + * UnsafeSetElement(). It is essential that these stores occur * atomically and cannot be interrupted by a stack or recursion * check. If this is not true, race conditions can occur. + * See definition of UnsafeSetElement() for more details. */ for (uint32_t base = 0; base < argc; base += 3) { @@ -1053,6 +1058,30 @@ IonBuilder::inlineUnsafeSetTypedArrayElement(CallInfo &callInfo, return true; } +IonBuilder::InliningStatus +IonBuilder::inlineUnsafeGetElement(CallInfo &callInfo, + GetElemSafety safety) +{ + JS_ASSERT(safety != GetElem_Normal); + + uint32_t argc = callInfo.argc(); + if (argc < 2 || callInfo.constructing()) + return InliningStatus_NotInlined; + const uint32_t obj = 0; + const uint32_t index = 1; + if (!ElementAccessIsDenseNative(callInfo.getArg(obj), + callInfo.getArg(index))) + return InliningStatus_NotInlined; + if (ElementAccessHasExtraIndexedProperty(cx, callInfo.getArg(obj))) + return InliningStatus_NotInlined; + callInfo.unwrapArgs(); + if (!jsop_getelem_dense(safety, + callInfo.getArg(obj), + callInfo.getArg(index))) + return InliningStatus_Error; + return InliningStatus_Inlined; +} + IonBuilder::InliningStatus IonBuilder::inlineForceSequentialOrInParallelSection(CallInfo &callInfo) { diff --git a/js/src/ion/MIR.h b/js/src/ion/MIR.h index 4450915e2a9c..3a36021cb223 100644 --- a/js/src/ion/MIR.h +++ b/js/src/ion/MIR.h @@ -4510,11 +4510,13 @@ class MLoadElement { bool needsHoleCheck_; bool loadDoubles_; + bool knownImmutable_; // load of data that is known to be immutable - MLoadElement(MDefinition *elements, MDefinition *index, bool needsHoleCheck, bool loadDoubles) + MLoadElement(MDefinition *elements, MDefinition *index, bool needsHoleCheck, bool loadDoubles, bool knownImmutable) : MBinaryInstruction(elements, index), needsHoleCheck_(needsHoleCheck), - loadDoubles_(loadDoubles) + loadDoubles_(loadDoubles), + knownImmutable_(knownImmutable) { setResultType(MIRType_Value); setMovable(); @@ -4526,8 +4528,10 @@ class MLoadElement INSTRUCTION_HEADER(LoadElement) static MLoadElement *New(MDefinition *elements, MDefinition *index, - bool needsHoleCheck, bool loadDoubles) { - return new MLoadElement(elements, index, needsHoleCheck, loadDoubles); + bool needsHoleCheck, bool loadDoubles, + bool knownImmutable) { + return new MLoadElement(elements, index, needsHoleCheck, loadDoubles, + knownImmutable); } TypePolicy *typePolicy() { @@ -4549,6 +4553,9 @@ class MLoadElement return needsHoleCheck(); } AliasSet getAliasSet() const { + if (knownImmutable_) + return AliasSet::None(); + return AliasSet::Load(AliasSet::Element); } }; diff --git a/js/src/ion/ParallelArrayAnalysis.cpp b/js/src/ion/ParallelArrayAnalysis.cpp index 3a34014bda1c..84b40624a1f2 100644 --- a/js/src/ion/ParallelArrayAnalysis.cpp +++ b/js/src/ion/ParallelArrayAnalysis.cpp @@ -856,14 +856,18 @@ GetPossibleCallees(JSContext *cx, if (!rootedFun->isInterpreted()) continue; - if (rootedFun->nonLazyScript()->shouldCloneAtCallsite) { + rootedScript = rootedFun->getOrCreateScript(cx); + if (!rootedScript) + return false; + + if (rootedScript->shouldCloneAtCallsite) { rootedFun = CloneFunctionAtCallsite(cx, rootedFun, script, pc); if (!rootedFun) return false; + rootedScript = rootedFun->nonLazyScript(); } // check if this call target is already known - rootedScript = rootedFun->nonLazyScript(); if (!AddCallTarget(rootedScript, targets)) return false; } diff --git a/js/src/ion/ParallelFunctions.cpp b/js/src/ion/ParallelFunctions.cpp index c1572f07ce29..f05894ac1490 100644 --- a/js/src/ion/ParallelFunctions.cpp +++ b/js/src/ion/ParallelFunctions.cpp @@ -434,6 +434,8 @@ ion::ParCallToUncompiledScript(JSFunction *func) JSScript *script = func->nonLazyScript(); Spew(SpewBailouts, "Call to uncompiled script: %p:%s:%d", script, script->filename(), script->lineno); + } else if (func->isInterpretedLazy()) { + Spew(SpewBailouts, "Call to uncompiled lazy script"); } else if (func->isBoundFunction()) { int depth = 0; JSFunction *target = func->getBoundFunctionTarget()->toFunction(); diff --git a/js/src/ion/RangeAnalysis.cpp b/js/src/ion/RangeAnalysis.cpp index fb7db64a222a..e374b2cd69ee 100644 --- a/js/src/ion/RangeAnalysis.cpp +++ b/js/src/ion/RangeAnalysis.cpp @@ -85,11 +85,6 @@ using mozilla::IsNegative; // after range analysis is performed. The remaining compiler phases do not ever // encounter beta nodes. -RangeAnalysis::RangeAnalysis(MIRGraph &graph) - : graph_(graph) -{ -} - static bool IsDominatedUse(MBasicBlock *block, MUse *use) { @@ -749,7 +744,13 @@ void MTruncateToInt32::computeRange() { Range input(getOperand(0)); - setRange(new Range(input.lower(), input.upper())); + int32_t lower = input.lower(); + int32_t upper = input.upper(); + if (input.isLowerInfinite() || input.isUpperInfinite()) { + lower = JSVAL_INT_MIN; + upper = JSVAL_INT_MAX; + } + setRange(new Range(lower, upper)); } void diff --git a/js/src/ion/RangeAnalysis.h b/js/src/ion/RangeAnalysis.h index 93e0206ec079..0dc1206eb8ce 100644 --- a/js/src/ion/RangeAnalysis.h +++ b/js/src/ion/RangeAnalysis.h @@ -78,7 +78,8 @@ class RangeAnalysis MIRGraph &graph_; public: - RangeAnalysis(MIRGraph &graph); + MOZ_CONSTEXPR RangeAnalysis(MIRGraph &graph) : + graph_(graph) {} bool addBetaNobes(); bool analyze(); bool removeBetaNobes(); diff --git a/js/src/ion/RegisterAllocator.h b/js/src/ion/RegisterAllocator.h index fe76b3504ee9..751479175827 100644 --- a/js/src/ion/RegisterAllocator.h +++ b/js/src/ion/RegisterAllocator.h @@ -7,6 +7,8 @@ #ifndef js_ion_registerallocator_h__ #define js_ion_registerallocator_h__ +#include "mozilla/Attributes.h" + #include "Ion.h" #include "MIR.h" #include "MIRGraph.h" @@ -140,7 +142,7 @@ struct AllocationIntegrityState class CodePosition { private: - CodePosition(const uint32_t &bits) + MOZ_CONSTEXPR CodePosition(const uint32_t &bits) : bits_(bits) { } @@ -159,7 +161,7 @@ class CodePosition OUTPUT }; - CodePosition() : bits_(0) + MOZ_CONSTEXPR CodePosition() : bits_(0) { } CodePosition(uint32_t instruction, SubPosition where) { diff --git a/js/src/ion/RegisterSets.h b/js/src/ion/RegisterSets.h index dc15038b2c86..9bcf0823e4bd 100644 --- a/js/src/ion/RegisterSets.h +++ b/js/src/ion/RegisterSets.h @@ -92,7 +92,7 @@ class ValueOperand Register payload_; public: - ValueOperand(Register type, Register payload) + MOZ_CONSTEXPR ValueOperand(Register type, Register payload) : type_(type), payload_(payload) { } @@ -117,7 +117,7 @@ class ValueOperand Register value_; public: - explicit ValueOperand(Register value) + explicit MOZ_CONSTEXPR ValueOperand(Register value) : value_(value) { } @@ -297,13 +297,13 @@ class TypedRegisterSet uint32_t bits_; public: - explicit TypedRegisterSet(uint32_t bits) + explicit MOZ_CONSTEXPR TypedRegisterSet(uint32_t bits) : bits_(bits) { } - TypedRegisterSet() : bits_(0) + MOZ_CONSTEXPR TypedRegisterSet() : bits_(0) { } - TypedRegisterSet(const TypedRegisterSet &set) : bits_(set.bits_) + MOZ_CONSTEXPR TypedRegisterSet(const TypedRegisterSet &set) : bits_(set.bits_) { } static inline TypedRegisterSet All() { @@ -471,7 +471,7 @@ class RegisterSet { public: RegisterSet() { } - RegisterSet(const GeneralRegisterSet &gpr, const FloatRegisterSet &fpu) + MOZ_CONSTEXPR RegisterSet(const GeneralRegisterSet &gpr, const FloatRegisterSet &fpu) : gpr_(gpr), fpu_(fpu) { } @@ -579,10 +579,10 @@ class RegisterSet { gpr_.clear(); fpu_.clear(); } - GeneralRegisterSet gprs() const { + MOZ_CONSTEXPR GeneralRegisterSet gprs() const { return gpr_; } - FloatRegisterSet fpus() const { + MOZ_CONSTEXPR FloatRegisterSet fpus() const { return fpu_; } bool operator ==(const RegisterSet &other) const { diff --git a/js/src/ion/arm/Assembler-arm.cpp b/js/src/ion/arm/Assembler-arm.cpp index 42afb5a0a2f4..798933656f07 100644 --- a/js/src/ion/arm/Assembler-arm.cpp +++ b/js/src/ion/arm/Assembler-arm.cpp @@ -2791,5 +2791,12 @@ AutoFlushCache::flushAnyway() } used_ = false; } - +InstructionIterator::InstructionIterator(Instruction *i_) : i(i_) { + const PoolHeader *ph; + // If this is a guard, and the next instruction is a header, always work around the pool + // If it isn't a guard, then start looking ahead. + if (InstIsGuard(i, &ph)) { + i = i->next(); + } +} Assembler *Assembler::dummy = NULL; diff --git a/js/src/ion/arm/Assembler-arm.h b/js/src/ion/arm/Assembler-arm.h index 68acd6338f16..5e2dfe8d8f13 100644 --- a/js/src/ion/arm/Assembler-arm.h +++ b/js/src/ion/arm/Assembler-arm.h @@ -7,6 +7,7 @@ #ifndef jsion_cpu_arm_assembler_h__ #define jsion_cpu_arm_assembler_h__ +#include "mozilla/Attributes.h" #include "mozilla/MathAlgorithms.h" #include "mozilla/Util.h" @@ -26,44 +27,44 @@ namespace ion { // clearer than bl r14). HOWEVER, this register can // easily be a gpr when it is not busy holding the return // address. -static const Register r0 = { Registers::r0 }; -static const Register r1 = { Registers::r1 }; -static const Register r2 = { Registers::r2 }; -static const Register r3 = { Registers::r3 }; -static const Register r4 = { Registers::r4 }; -static const Register r5 = { Registers::r5 }; -static const Register r6 = { Registers::r6 }; -static const Register r7 = { Registers::r7 }; -static const Register r8 = { Registers::r8 }; -static const Register r9 = { Registers::r9 }; -static const Register r10 = { Registers::r10 }; -static const Register r11 = { Registers::r11 }; -static const Register r12 = { Registers::ip }; -static const Register ip = { Registers::ip }; -static const Register sp = { Registers::sp }; -static const Register r14 = { Registers::lr }; -static const Register lr = { Registers::lr }; -static const Register pc = { Registers::pc }; +static const MOZ_CONSTEXPR Register r0 = { Registers::r0 }; +static const MOZ_CONSTEXPR Register r1 = { Registers::r1 }; +static const MOZ_CONSTEXPR Register r2 = { Registers::r2 }; +static const MOZ_CONSTEXPR Register r3 = { Registers::r3 }; +static const MOZ_CONSTEXPR Register r4 = { Registers::r4 }; +static const MOZ_CONSTEXPR Register r5 = { Registers::r5 }; +static const MOZ_CONSTEXPR Register r6 = { Registers::r6 }; +static const MOZ_CONSTEXPR Register r7 = { Registers::r7 }; +static const MOZ_CONSTEXPR Register r8 = { Registers::r8 }; +static const MOZ_CONSTEXPR Register r9 = { Registers::r9 }; +static const MOZ_CONSTEXPR Register r10 = { Registers::r10 }; +static const MOZ_CONSTEXPR Register r11 = { Registers::r11 }; +static const MOZ_CONSTEXPR Register r12 = { Registers::ip }; +static const MOZ_CONSTEXPR Register ip = { Registers::ip }; +static const MOZ_CONSTEXPR Register sp = { Registers::sp }; +static const MOZ_CONSTEXPR Register r14 = { Registers::lr }; +static const MOZ_CONSTEXPR Register lr = { Registers::lr }; +static const MOZ_CONSTEXPR Register pc = { Registers::pc }; -static const Register ScratchRegister = {Registers::ip}; +static const MOZ_CONSTEXPR Register ScratchRegister = {Registers::ip}; -static const Register OsrFrameReg = r3; -static const Register ArgumentsRectifierReg = r8; -static const Register CallTempReg0 = r5; -static const Register CallTempReg1 = r6; -static const Register CallTempReg2 = r7; -static const Register CallTempReg3 = r8; -static const Register CallTempReg4 = r0; -static const Register CallTempReg5 = r1; -static const Register CallTempReg6 = r2; +static const MOZ_CONSTEXPR Register OsrFrameReg = r3; +static const MOZ_CONSTEXPR Register ArgumentsRectifierReg = r8; +static const MOZ_CONSTEXPR Register CallTempReg0 = r5; +static const MOZ_CONSTEXPR Register CallTempReg1 = r6; +static const MOZ_CONSTEXPR Register CallTempReg2 = r7; +static const MOZ_CONSTEXPR Register CallTempReg3 = r8; +static const MOZ_CONSTEXPR Register CallTempReg4 = r0; +static const MOZ_CONSTEXPR Register CallTempReg5 = r1; +static const MOZ_CONSTEXPR Register CallTempReg6 = r2; -static const Register IntArgReg0 = r0; -static const Register IntArgReg1 = r1; -static const Register IntArgReg2 = r2; -static const Register IntArgReg3 = r3; -static const Register GlobalReg = r10; -static const Register HeapReg = r11; -static const Register CallTempNonArgRegs[] = { r5, r6, r7, r8 }; +static const MOZ_CONSTEXPR Register IntArgReg0 = r0; +static const MOZ_CONSTEXPR Register IntArgReg1 = r1; +static const MOZ_CONSTEXPR Register IntArgReg2 = r2; +static const MOZ_CONSTEXPR Register IntArgReg3 = r3; +static const MOZ_CONSTEXPR Register GlobalReg = r10; +static const MOZ_CONSTEXPR Register HeapReg = r11; +static const MOZ_CONSTEXPR Register CallTempNonArgRegs[] = { r5, r6, r7, r8 }; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); class ABIArgGenerator @@ -87,37 +88,37 @@ class ABIArgGenerator }; -static const Register PreBarrierReg = r1; +static const MOZ_CONSTEXPR Register PreBarrierReg = r1; -static const Register InvalidReg = { Registers::invalid_reg }; -static const FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg }; +static const MOZ_CONSTEXPR Register InvalidReg = { Registers::invalid_reg }; +static const MOZ_CONSTEXPR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg }; -static const Register JSReturnReg_Type = r3; -static const Register JSReturnReg_Data = r2; -static const Register StackPointer = sp; -static const Register FramePointer = InvalidReg; -static const Register ReturnReg = r0; -static const FloatRegister ReturnFloatReg = { FloatRegisters::d0 }; -static const FloatRegister ScratchFloatReg = { FloatRegisters::d1 }; +static const MOZ_CONSTEXPR Register JSReturnReg_Type = r3; +static const MOZ_CONSTEXPR Register JSReturnReg_Data = r2; +static const MOZ_CONSTEXPR Register StackPointer = sp; +static const MOZ_CONSTEXPR Register FramePointer = InvalidReg; +static const MOZ_CONSTEXPR Register ReturnReg = r0; +static const MOZ_CONSTEXPR FloatRegister ReturnFloatReg = { FloatRegisters::d0 }; +static const MOZ_CONSTEXPR FloatRegister ScratchFloatReg = { FloatRegisters::d1 }; -static const FloatRegister NANReg = { FloatRegisters::d15 }; +static const MOZ_CONSTEXPR FloatRegister NANReg = { FloatRegisters::d15 }; -static const FloatRegister d0 = {FloatRegisters::d0}; -static const FloatRegister d1 = {FloatRegisters::d1}; -static const FloatRegister d2 = {FloatRegisters::d2}; -static const FloatRegister d3 = {FloatRegisters::d3}; -static const FloatRegister d4 = {FloatRegisters::d4}; -static const FloatRegister d5 = {FloatRegisters::d5}; -static const FloatRegister d6 = {FloatRegisters::d6}; -static const FloatRegister d7 = {FloatRegisters::d7}; -static const FloatRegister d8 = {FloatRegisters::d8}; -static const FloatRegister d9 = {FloatRegisters::d9}; -static const FloatRegister d10 = {FloatRegisters::d10}; -static const FloatRegister d11 = {FloatRegisters::d11}; -static const FloatRegister d12 = {FloatRegisters::d12}; -static const FloatRegister d13 = {FloatRegisters::d13}; -static const FloatRegister d14 = {FloatRegisters::d14}; -static const FloatRegister d15 = {FloatRegisters::d15}; +static const MOZ_CONSTEXPR FloatRegister d0 = {FloatRegisters::d0}; +static const MOZ_CONSTEXPR FloatRegister d1 = {FloatRegisters::d1}; +static const MOZ_CONSTEXPR FloatRegister d2 = {FloatRegisters::d2}; +static const MOZ_CONSTEXPR FloatRegister d3 = {FloatRegisters::d3}; +static const MOZ_CONSTEXPR FloatRegister d4 = {FloatRegisters::d4}; +static const MOZ_CONSTEXPR FloatRegister d5 = {FloatRegisters::d5}; +static const MOZ_CONSTEXPR FloatRegister d6 = {FloatRegisters::d6}; +static const MOZ_CONSTEXPR FloatRegister d7 = {FloatRegisters::d7}; +static const MOZ_CONSTEXPR FloatRegister d8 = {FloatRegisters::d8}; +static const MOZ_CONSTEXPR FloatRegister d9 = {FloatRegisters::d9}; +static const MOZ_CONSTEXPR FloatRegister d10 = {FloatRegisters::d10}; +static const MOZ_CONSTEXPR FloatRegister d11 = {FloatRegisters::d11}; +static const MOZ_CONSTEXPR FloatRegister d12 = {FloatRegisters::d12}; +static const MOZ_CONSTEXPR FloatRegister d13 = {FloatRegisters::d13}; +static const MOZ_CONSTEXPR FloatRegister d14 = {FloatRegisters::d14}; +static const MOZ_CONSTEXPR FloatRegister d15 = {FloatRegisters::d15}; // For maximal awesomeness, 8 should be sufficent. // ldrd/strd (dual-register load/store) operate in a single cycle @@ -2061,7 +2062,7 @@ class InstructionIterator { private: Instruction *i; public: - InstructionIterator(Instruction *i_) : i(i_) {} + InstructionIterator(Instruction *i_); Instruction *next() { i = i->next(); return cur(); diff --git a/js/src/ion/x64/Assembler-x64.h b/js/src/ion/x64/Assembler-x64.h index 909327bca425..82874703737b 100644 --- a/js/src/ion/x64/Assembler-x64.h +++ b/js/src/ion/x64/Assembler-x64.h @@ -15,39 +15,39 @@ namespace js { namespace ion { -static const Register rax = { JSC::X86Registers::eax }; -static const Register rbx = { JSC::X86Registers::ebx }; -static const Register rcx = { JSC::X86Registers::ecx }; -static const Register rdx = { JSC::X86Registers::edx }; -static const Register rsi = { JSC::X86Registers::esi }; -static const Register rdi = { JSC::X86Registers::edi }; -static const Register rbp = { JSC::X86Registers::ebp }; -static const Register r8 = { JSC::X86Registers::r8 }; -static const Register r9 = { JSC::X86Registers::r9 }; -static const Register r10 = { JSC::X86Registers::r10 }; -static const Register r11 = { JSC::X86Registers::r11 }; -static const Register r12 = { JSC::X86Registers::r12 }; -static const Register r13 = { JSC::X86Registers::r13 }; -static const Register r14 = { JSC::X86Registers::r14 }; -static const Register r15 = { JSC::X86Registers::r15 }; -static const Register rsp = { JSC::X86Registers::esp }; +static const MOZ_CONSTEXPR Register rax = { JSC::X86Registers::eax }; +static const MOZ_CONSTEXPR Register rbx = { JSC::X86Registers::ebx }; +static const MOZ_CONSTEXPR Register rcx = { JSC::X86Registers::ecx }; +static const MOZ_CONSTEXPR Register rdx = { JSC::X86Registers::edx }; +static const MOZ_CONSTEXPR Register rsi = { JSC::X86Registers::esi }; +static const MOZ_CONSTEXPR Register rdi = { JSC::X86Registers::edi }; +static const MOZ_CONSTEXPR Register rbp = { JSC::X86Registers::ebp }; +static const MOZ_CONSTEXPR Register r8 = { JSC::X86Registers::r8 }; +static const MOZ_CONSTEXPR Register r9 = { JSC::X86Registers::r9 }; +static const MOZ_CONSTEXPR Register r10 = { JSC::X86Registers::r10 }; +static const MOZ_CONSTEXPR Register r11 = { JSC::X86Registers::r11 }; +static const MOZ_CONSTEXPR Register r12 = { JSC::X86Registers::r12 }; +static const MOZ_CONSTEXPR Register r13 = { JSC::X86Registers::r13 }; +static const MOZ_CONSTEXPR Register r14 = { JSC::X86Registers::r14 }; +static const MOZ_CONSTEXPR Register r15 = { JSC::X86Registers::r15 }; +static const MOZ_CONSTEXPR Register rsp = { JSC::X86Registers::esp }; -static const FloatRegister xmm0 = { JSC::X86Registers::xmm0 }; -static const FloatRegister xmm1 = { JSC::X86Registers::xmm1 }; -static const FloatRegister xmm2 = { JSC::X86Registers::xmm2 }; -static const FloatRegister xmm3 = { JSC::X86Registers::xmm3 }; -static const FloatRegister xmm4 = { JSC::X86Registers::xmm4 }; -static const FloatRegister xmm5 = { JSC::X86Registers::xmm5 }; -static const FloatRegister xmm6 = { JSC::X86Registers::xmm6 }; -static const FloatRegister xmm7 = { JSC::X86Registers::xmm7 }; -static const FloatRegister xmm8 = { JSC::X86Registers::xmm8 }; -static const FloatRegister xmm9 = { JSC::X86Registers::xmm9 }; -static const FloatRegister xmm10 = { JSC::X86Registers::xmm10 }; -static const FloatRegister xmm11 = { JSC::X86Registers::xmm11 }; -static const FloatRegister xmm12 = { JSC::X86Registers::xmm12 }; -static const FloatRegister xmm13 = { JSC::X86Registers::xmm13 }; -static const FloatRegister xmm14 = { JSC::X86Registers::xmm14 }; -static const FloatRegister xmm15 = { JSC::X86Registers::xmm15 }; +static const MOZ_CONSTEXPR FloatRegister xmm0 = { JSC::X86Registers::xmm0 }; +static const MOZ_CONSTEXPR FloatRegister xmm1 = { JSC::X86Registers::xmm1 }; +static const MOZ_CONSTEXPR FloatRegister xmm2 = { JSC::X86Registers::xmm2 }; +static const MOZ_CONSTEXPR FloatRegister xmm3 = { JSC::X86Registers::xmm3 }; +static const MOZ_CONSTEXPR FloatRegister xmm4 = { JSC::X86Registers::xmm4 }; +static const MOZ_CONSTEXPR FloatRegister xmm5 = { JSC::X86Registers::xmm5 }; +static const MOZ_CONSTEXPR FloatRegister xmm6 = { JSC::X86Registers::xmm6 }; +static const MOZ_CONSTEXPR FloatRegister xmm7 = { JSC::X86Registers::xmm7 }; +static const MOZ_CONSTEXPR FloatRegister xmm8 = { JSC::X86Registers::xmm8 }; +static const MOZ_CONSTEXPR FloatRegister xmm9 = { JSC::X86Registers::xmm9 }; +static const MOZ_CONSTEXPR FloatRegister xmm10 = { JSC::X86Registers::xmm10 }; +static const MOZ_CONSTEXPR FloatRegister xmm11 = { JSC::X86Registers::xmm11 }; +static const MOZ_CONSTEXPR FloatRegister xmm12 = { JSC::X86Registers::xmm12 }; +static const MOZ_CONSTEXPR FloatRegister xmm13 = { JSC::X86Registers::xmm13 }; +static const MOZ_CONSTEXPR FloatRegister xmm14 = { JSC::X86Registers::xmm14 }; +static const MOZ_CONSTEXPR FloatRegister xmm15 = { JSC::X86Registers::xmm15 }; // X86-common synonyms. static const Register eax = rax; @@ -59,74 +59,74 @@ static const Register edi = rdi; static const Register ebp = rbp; static const Register esp = rsp; -static const Register InvalidReg = { JSC::X86Registers::invalid_reg }; -static const FloatRegister InvalidFloatReg = { JSC::X86Registers::invalid_xmm }; +static const MOZ_CONSTEXPR Register InvalidReg = { JSC::X86Registers::invalid_reg }; +static const MOZ_CONSTEXPR FloatRegister InvalidFloatReg = { JSC::X86Registers::invalid_xmm }; static const Register StackPointer = rsp; static const Register FramePointer = rbp; -static const Register JSReturnReg = rcx; +static const MOZ_CONSTEXPR Register JSReturnReg = rcx; // Avoid, except for assertions. -static const Register JSReturnReg_Type = JSReturnReg; -static const Register JSReturnReg_Data = JSReturnReg; +static const MOZ_CONSTEXPR Register JSReturnReg_Type = JSReturnReg; +static const MOZ_CONSTEXPR Register JSReturnReg_Data = JSReturnReg; -static const Register ReturnReg = rax; -static const Register ScratchReg = r11; -static const Register HeapReg = r15; -static const FloatRegister ReturnFloatReg = xmm0; -static const FloatRegister ScratchFloatReg = xmm15; +static const MOZ_CONSTEXPR Register ReturnReg = rax; +static const MOZ_CONSTEXPR Register ScratchReg = r11; +static const MOZ_CONSTEXPR Register HeapReg = r15; +static const MOZ_CONSTEXPR FloatRegister ReturnFloatReg = xmm0; +static const MOZ_CONSTEXPR FloatRegister ScratchFloatReg = xmm15; -static const Register ArgumentsRectifierReg = r8; -static const Register CallTempReg0 = rax; -static const Register CallTempReg1 = rdi; -static const Register CallTempReg2 = rbx; -static const Register CallTempReg3 = rcx; -static const Register CallTempReg4 = rsi; -static const Register CallTempReg5 = rdx; -static const Register CallTempReg6 = rbp; +static const MOZ_CONSTEXPR Register ArgumentsRectifierReg = r8; +static const MOZ_CONSTEXPR Register CallTempReg0 = rax; +static const MOZ_CONSTEXPR Register CallTempReg1 = rdi; +static const MOZ_CONSTEXPR Register CallTempReg2 = rbx; +static const MOZ_CONSTEXPR Register CallTempReg3 = rcx; +static const MOZ_CONSTEXPR Register CallTempReg4 = rsi; +static const MOZ_CONSTEXPR Register CallTempReg5 = rdx; +static const MOZ_CONSTEXPR Register CallTempReg6 = rbp; // Different argument registers for WIN64 #if defined(_WIN64) -static const Register IntArgReg0 = rcx; -static const Register IntArgReg1 = rdx; -static const Register IntArgReg2 = r8; -static const Register IntArgReg3 = r9; -static const uint32_t NumIntArgRegs = 4; -static const Register IntArgRegs[NumIntArgRegs] = { rcx, rdx, r8, r9 }; +static const MOZ_CONSTEXPR Register IntArgReg0 = rcx; +static constMOZ_CONSTEXPRconstexpr Register IntArgReg1 = rdx; +static const MOZ_CONSTEXPR Register IntArgReg2 = r8; +static const MOZ_CONSTEXPR Register IntArgReg3 = r9; +static constMOZ_CONSTEXPRuint32_t NumIntArgRegs = 4; +static const MOZ_CONSTEXPR Register IntArgRegs[NumIntArgRegs] = { rcx, rdx, r8, r9 }; -static const Register CallTempNonArgRegs[] = { rax, rdi, rbx, rsi }; +static const MOZ_CONSTEXPR Register CallTempNonArgRegs[] = { rax, rdi, rbx, rsi }; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); -static const FloatRegister FloatArgReg0 = xmm0; -static const FloatRegister FloatArgReg1 = xmm1; -static const FloatRegister FloatArgReg2 = xmm2; -static const FloatRegister FloatArgReg3 = xmm3; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg0 = xmm0; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg1 = xmm1; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg2 = xmm2; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg3 = xmm3; static const uint32_t NumFloatArgRegs = 4; static const FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3 }; #else -static const Register IntArgReg0 = rdi; -static const Register IntArgReg1 = rsi; -static const Register IntArgReg2 = rdx; -static const Register IntArgReg3 = rcx; -static const Register IntArgReg4 = r8; -static const Register IntArgReg5 = r9; -static const uint32_t NumIntArgRegs = 6; -static const Register IntArgRegs[NumIntArgRegs] = { rdi, rsi, rdx, rcx, r8, r9 }; +static const MOZ_CONSTEXPR Register IntArgReg0 = rdi; +static const MOZ_CONSTEXPR Register IntArgReg1 = rsi; +static const MOZ_CONSTEXPR Register IntArgReg2 = rdx; +static const MOZ_CONSTEXPR Register IntArgReg3 = rcx; +static const MOZ_CONSTEXPR Register IntArgReg4 = r8; +static const MOZ_CONSTEXPR Register IntArgReg5 = r9; +static const MOZ_CONSTEXPR uint32_t NumIntArgRegs = 6; +static const MOZ_CONSTEXPR Register IntArgRegs[NumIntArgRegs] = { rdi, rsi, rdx, rcx, r8, r9 }; -static const Register CallTempNonArgRegs[] = { rax, rbx }; +static const MOZ_CONSTEXPR Register CallTempNonArgRegs[] = { rax, rbx }; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); -static const FloatRegister FloatArgReg0 = xmm0; -static const FloatRegister FloatArgReg1 = xmm1; -static const FloatRegister FloatArgReg2 = xmm2; -static const FloatRegister FloatArgReg3 = xmm3; -static const FloatRegister FloatArgReg4 = xmm4; -static const FloatRegister FloatArgReg5 = xmm5; -static const FloatRegister FloatArgReg6 = xmm6; -static const FloatRegister FloatArgReg7 = xmm7; -static const uint32_t NumFloatArgRegs = 8; -static const FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 }; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg0 = xmm0; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg1 = xmm1; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg2 = xmm2; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg3 = xmm3; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg4 = xmm4; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg5 = xmm5; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg6 = xmm6; +static const MOZ_CONSTEXPR FloatRegister FloatArgReg7 = xmm7; +static const MOZ_CONSTEXPR uint32_t NumFloatArgRegs = 8; +static const MOZ_CONSTEXPR FloatRegister FloatArgRegs[NumFloatArgRegs] = { xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 }; #endif class ABIArgGenerator @@ -152,9 +152,9 @@ class ABIArgGenerator static const Register NonVolatileReg; }; -static const Register OsrFrameReg = IntArgReg3; +static const MOZ_CONSTEXPR Register OsrFrameReg = IntArgReg3; -static const Register PreBarrierReg = rdx; +static const MOZ_CONSTEXPR Register PreBarrierReg = rdx; // GCC stack is aligned on 16 bytes, but we don't maintain the invariant in // jitted code. @@ -265,7 +265,7 @@ namespace js { namespace ion { // Return operand from a JS -> JS call. -static const ValueOperand JSReturnOperand = ValueOperand(JSReturnReg); +static const MOZ_CONSTEXPR ValueOperand JSReturnOperand = ValueOperand(JSReturnReg); class Assembler : public AssemblerX86Shared { diff --git a/js/src/ion/x86/Assembler-x86.h b/js/src/ion/x86/Assembler-x86.h index 64cfcdccd80f..e9476db4a43e 100644 --- a/js/src/ion/x86/Assembler-x86.h +++ b/js/src/ion/x86/Assembler-x86.h @@ -18,46 +18,46 @@ namespace js { namespace ion { -static const Register eax = { JSC::X86Registers::eax }; -static const Register ecx = { JSC::X86Registers::ecx }; -static const Register edx = { JSC::X86Registers::edx }; -static const Register ebx = { JSC::X86Registers::ebx }; -static const Register esp = { JSC::X86Registers::esp }; -static const Register ebp = { JSC::X86Registers::ebp }; -static const Register esi = { JSC::X86Registers::esi }; -static const Register edi = { JSC::X86Registers::edi }; +static const MOZ_CONSTEXPR Register eax = { JSC::X86Registers::eax }; +static const MOZ_CONSTEXPR Register ecx = { JSC::X86Registers::ecx }; +static const MOZ_CONSTEXPR Register edx = { JSC::X86Registers::edx }; +static const MOZ_CONSTEXPR Register ebx = { JSC::X86Registers::ebx }; +static const MOZ_CONSTEXPR Register esp = { JSC::X86Registers::esp }; +static const MOZ_CONSTEXPR Register ebp = { JSC::X86Registers::ebp }; +static const MOZ_CONSTEXPR Register esi = { JSC::X86Registers::esi }; +static const MOZ_CONSTEXPR Register edi = { JSC::X86Registers::edi }; -static const FloatRegister xmm0 = { JSC::X86Registers::xmm0 }; -static const FloatRegister xmm1 = { JSC::X86Registers::xmm1 }; -static const FloatRegister xmm2 = { JSC::X86Registers::xmm2 }; -static const FloatRegister xmm3 = { JSC::X86Registers::xmm3 }; -static const FloatRegister xmm4 = { JSC::X86Registers::xmm4 }; -static const FloatRegister xmm5 = { JSC::X86Registers::xmm5 }; -static const FloatRegister xmm6 = { JSC::X86Registers::xmm6 }; -static const FloatRegister xmm7 = { JSC::X86Registers::xmm7 }; +static const MOZ_CONSTEXPR FloatRegister xmm0 = { JSC::X86Registers::xmm0 }; +static const MOZ_CONSTEXPR FloatRegister xmm1 = { JSC::X86Registers::xmm1 }; +static const MOZ_CONSTEXPR FloatRegister xmm2 = { JSC::X86Registers::xmm2 }; +static const MOZ_CONSTEXPR FloatRegister xmm3 = { JSC::X86Registers::xmm3 }; +static const MOZ_CONSTEXPR FloatRegister xmm4 = { JSC::X86Registers::xmm4 }; +static const MOZ_CONSTEXPR FloatRegister xmm5 = { JSC::X86Registers::xmm5 }; +static const MOZ_CONSTEXPR FloatRegister xmm6 = { JSC::X86Registers::xmm6 }; +static const MOZ_CONSTEXPR FloatRegister xmm7 = { JSC::X86Registers::xmm7 }; -static const Register InvalidReg = { JSC::X86Registers::invalid_reg }; -static const FloatRegister InvalidFloatReg = { JSC::X86Registers::invalid_xmm }; +static const MOZ_CONSTEXPR Register InvalidReg = { JSC::X86Registers::invalid_reg }; +static const MOZ_CONSTEXPR FloatRegister InvalidFloatReg = { JSC::X86Registers::invalid_xmm }; -static const Register JSReturnReg_Type = ecx; -static const Register JSReturnReg_Data = edx; -static const Register StackPointer = esp; -static const Register FramePointer = ebp; -static const Register ReturnReg = eax; -static const FloatRegister ReturnFloatReg = xmm0; -static const FloatRegister ScratchFloatReg = xmm7; +static const MOZ_CONSTEXPR Register JSReturnReg_Type = ecx; +static const MOZ_CONSTEXPR Register JSReturnReg_Data = edx; +static const MOZ_CONSTEXPR Register StackPointer = esp; +static const MOZ_CONSTEXPR Register FramePointer = ebp; +static const MOZ_CONSTEXPR Register ReturnReg = eax; +static const MOZ_CONSTEXPR FloatRegister ReturnFloatReg = xmm0; +static const MOZ_CONSTEXPR FloatRegister ScratchFloatReg = xmm7; -static const Register ArgumentsRectifierReg = esi; -static const Register CallTempReg0 = edi; -static const Register CallTempReg1 = eax; -static const Register CallTempReg2 = ebx; -static const Register CallTempReg3 = ecx; -static const Register CallTempReg4 = esi; -static const Register CallTempReg5 = edx; -static const Register CallTempReg6 = ebp; +static const MOZ_CONSTEXPR Register ArgumentsRectifierReg = esi; +static const MOZ_CONSTEXPR Register CallTempReg0 = edi; +static const MOZ_CONSTEXPR Register CallTempReg1 = eax; +static const MOZ_CONSTEXPR Register CallTempReg2 = ebx; +static const MOZ_CONSTEXPR Register CallTempReg3 = ecx; +static const MOZ_CONSTEXPR Register CallTempReg4 = esi; +static const MOZ_CONSTEXPR Register CallTempReg5 = edx; +static const MOZ_CONSTEXPR Register CallTempReg6 = ebp; // We have no arg regs, so our NonArgRegs are just our CallTempReg* -static const Register CallTempNonArgRegs[] = { edi, eax, ebx, ecx, esi, edx }; +static const MOZ_CONSTEXPR Register CallTempNonArgRegs[] = { edi, eax, ebx, ecx, esi, edx }; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); @@ -78,8 +78,8 @@ class ABIArgGenerator static const Register NonVolatileReg; }; -static const Register OsrFrameReg = edx; -static const Register PreBarrierReg = edx; +static const MOZ_CONSTEXPR Register OsrFrameReg = edx; +static const MOZ_CONSTEXPR Register PreBarrierReg = edx; // GCC stack is aligned on 16 bytes, but we don't maintain the invariant in // jitted code. diff --git a/js/src/jit-test/tests/auto-regress/bug827821.js b/js/src/jit-test/tests/auto-regress/bug827821.js deleted file mode 100644 index 1000e99219b9..000000000000 --- a/js/src/jit-test/tests/auto-regress/bug827821.js +++ /dev/null @@ -1,36 +0,0 @@ -// Binary: cache/js-dbg-32-795632f0e4fe-linux -// Flags: --ion-eager -// - -var lfcode = new Array(); -lfcode.push("3"); -lfcode.push("\ - gczeal(2);\ - for (let q = 0; q < 50; ++q) {\ - var w = \"r\".match(/r/);\ - }\ - let (eval) (function (a) {\ - Function = gczeal;\ - })();\ - // .js\ -"); -lfcode.push(" // .js"); -lfcode.push(" // .js"); -lfcode.push(" // .js"); -while (true) { - var file = lfcode.shift(); if (file == undefined) { break; } - loadFile(file) -} -function loadFile(lfVarx) { - try { - if (lfVarx.substr(-3) == ".js") { - uneval("foo"); - switch (lfRunTypeId) { - case 3: function newFunc(x) { new Function(x)(); }; newFunc(lfVarx); break; - case 4: eval("(function() { " + lfVarx + " })();"); break; - } - } else if (!isNaN(lfVarx)) { - lfRunTypeId = parseInt(lfVarx); - } - } catch (lfVare) {} -} diff --git a/js/src/jit-test/tests/basic/functionnames.js b/js/src/jit-test/tests/basic/functionnames.js index 1f89047143eb..92fbf258c634 100644 --- a/js/src/jit-test/tests/basic/functionnames.js +++ b/js/src/jit-test/tests/basic/functionnames.js @@ -36,7 +36,7 @@ var Foo = function (){ assertName(arguments.callee, 'Foo<') return function(){}; }(); -assertName(Foo, 'Foo'); +assertName(Foo, 'Foo:( + foo = evalcx("(function foo() { foo.bar() })"); + foo.bar = evalcx("(function bar() {})"); + + fatty(); +} diff --git a/js/src/jit-test/tests/modules/nonkeyword.js b/js/src/jit-test/tests/modules/nonkeyword.js index deab3bb8025c..40dae8e5328d 100644 --- a/js/src/jit-test/tests/modules/nonkeyword.js +++ b/js/src/jit-test/tests/modules/nonkeyword.js @@ -4,3 +4,5 @@ module = {}; module.p = 0; assertEq(this.module.p, 0); +assertEq(eval('module \n "hello"'), "hello"); +assertEq(eval('module \n "world" \n {}'), "world"); diff --git a/js/src/jsapi-tests/testBug604087.cpp b/js/src/jsapi-tests/testBug604087.cpp index 4bda71b5e0fd..436d79017512 100644 --- a/js/src/jsapi-tests/testBug604087.cpp +++ b/js/src/jsapi-tests/testBug604087.cpp @@ -7,7 +7,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - #include "tests.h" #include "jsobj.h" #include "jswrapper.h" diff --git a/js/src/jsapi-tests/testFuncCallback.cpp b/js/src/jsapi-tests/testFuncCallback.cpp index 924233598f41..fe7bd7e33921 100644 --- a/js/src/jsapi-tests/testFuncCallback.cpp +++ b/js/src/jsapi-tests/testFuncCallback.cpp @@ -6,8 +6,6 @@ #include "jsfun.h" #include "jscntxt.h" -#include "jsobjinlines.h" - #ifdef MOZ_TRACE_JSCALLS static int depth = 0; diff --git a/js/src/jsapi-tests/testGCFinalizeCallback.cpp b/js/src/jsapi-tests/testGCFinalizeCallback.cpp index b17182f988e6..e9328ac1c39e 100644 --- a/js/src/jsapi-tests/testGCFinalizeCallback.cpp +++ b/js/src/jsapi-tests/testGCFinalizeCallback.cpp @@ -9,6 +9,8 @@ #include "jsfriendapi.h" #include "jscntxt.h" +#include "vm/ObjectImpl-inl.h" + const unsigned BufferSize = 20; static unsigned FinalizeCalls = 0; static JSFinalizeStatus StatusBuffer[BufferSize]; diff --git a/js/src/jsapi-tests/testOriginPrincipals.cpp b/js/src/jsapi-tests/testOriginPrincipals.cpp index 4e0419e79d6a..0b03014bff1a 100644 --- a/js/src/jsapi-tests/testOriginPrincipals.cpp +++ b/js/src/jsapi-tests/testOriginPrincipals.cpp @@ -4,7 +4,6 @@ #include "tests.h" #include "jsdbgapi.h" -#include "jsobjinlines.h" JSPrincipals *sOriginPrincipalsInErrorReporter = NULL; diff --git a/js/src/jsapi-tests/testStringBuffer.cpp b/js/src/jsapi-tests/testStringBuffer.cpp index ebbd2dff1f61..5b0a219fedbc 100644 --- a/js/src/jsapi-tests/testStringBuffer.cpp +++ b/js/src/jsapi-tests/testStringBuffer.cpp @@ -12,8 +12,6 @@ #include "vm/StringBuffer.h" -#include "jsobjinlines.h" - BEGIN_TEST(testStringBuffer_finishString) { JSString *str = JS_NewStringCopyZ(cx, "foopy"); diff --git a/js/src/jsapi-tests/testVersion.cpp b/js/src/jsapi-tests/testVersion.cpp index ccbb7497321d..f2f972968a8a 100644 --- a/js/src/jsapi-tests/testVersion.cpp +++ b/js/src/jsapi-tests/testVersion.cpp @@ -7,7 +7,6 @@ #include "jscntxt.h" #include "jscntxtinlines.h" -#include "jsobjinlines.h" using namespace js; diff --git a/js/src/jsapi-tests/testXDR.cpp b/js/src/jsapi-tests/testXDR.cpp index 053f8f8c2e8f..2b5900b7365b 100644 --- a/js/src/jsapi-tests/testXDR.cpp +++ b/js/src/jsapi-tests/testXDR.cpp @@ -9,6 +9,8 @@ #include "jsstr.h" #include "jsfriendapi.h" +#include "jsscriptinlines.h" + static JSScript * CompileScriptForPrincipalsVersionOrigin(JSContext *cx, JS::HandleObject obj, JSPrincipals *principals, JSPrincipals *originPrincipals, diff --git a/js/src/jsapi-tests/tests.h b/js/src/jsapi-tests/tests.h index c3c7e4cb8265..03c8ea7fd403 100644 --- a/js/src/jsapi-tests/tests.h +++ b/js/src/jsapi-tests/tests.h @@ -12,7 +12,6 @@ // For js::gc::AutoSuppressGC #include "jsgc.h" -#include "jsobjinlines.h" #include "jsgcinlines.h" #include "js/Vector.h" diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 828bd264e51b..0c40486226f6 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -77,7 +77,6 @@ #include "jsatominlines.h" #include "jsinferinlines.h" -#include "jsobjinlines.h" #include "jsscriptinlines.h" #include "vm/Interpreter-inl.h" @@ -5289,10 +5288,10 @@ AutoFile::open(JSContext *cx, const char *filename) } -JS::CompileOptions::CompileOptions(JSContext *cx) +JS::CompileOptions::CompileOptions(JSContext *cx, JSVersion version) : principals(NULL), originPrincipals(NULL), - version(cx->findVersion()), + version(version != JSVERSION_UNKNOWN ? version : cx->findVersion()), versionSet(false), utf8(false), filename(NULL), diff --git a/js/src/jsapi.h b/js/src/jsapi.h index fb8790bdef0f..f3c62a1d825d 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3907,7 +3907,7 @@ struct JS_PUBLIC_API(CompileOptions) { SAVE_SOURCE } sourcePolicy; - explicit CompileOptions(JSContext *cx); + explicit CompileOptions(JSContext *cx, JSVersion version = JSVERSION_UNKNOWN); CompileOptions &setPrincipals(JSPrincipals *p) { principals = p; return *this; } CompileOptions &setOriginPrincipals(JSPrincipals *p) { originPrincipals = p; return *this; } CompileOptions &setVersion(JSVersion v) { version = v; versionSet = true; return *this; } diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 9079b6e495f9..803cda5df7ae 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -33,7 +33,6 @@ #include "jsatominlines.h" #include "jscntxtinlines.h" -#include "jsobjinlines.h" #include "jsstrinlines.h" #include "vm/ArgumentsObject-inl.h" diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index 46f20662493b..10c10b07457b 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -26,6 +26,7 @@ #include "vm/Xdr.h" #include "jsatominlines.h" +#include "jscompartmentinlines.h" #include "vm/String-inl.h" diff --git a/js/src/jsatominlines.h b/js/src/jsatominlines.h index c119f0c122fc..1a66b6930f5c 100644 --- a/js/src/jsatominlines.h +++ b/js/src/jsatominlines.h @@ -11,6 +11,7 @@ #include "mozilla/RangedPtr.h" #include "jsatom.h" +#include "jscntxt.h" #include "jsnum.h" #include "jsobj.h" #include "jsstr.h" diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index 8718c95a0b24..7569cc1794be 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -21,7 +21,6 @@ #include "vm/StringBuffer.h" #include "jsboolinlines.h" -#include "jsobjinlines.h" #include "vm/BooleanObject-inl.h" #include "vm/GlobalObject-inl.h" diff --git a/js/src/jsboolinlines.h b/js/src/jsboolinlines.h index bcf242b5c061..52d3d3f6aca1 100644 --- a/js/src/jsboolinlines.h +++ b/js/src/jsboolinlines.h @@ -12,8 +12,6 @@ #include "js/RootingAPI.h" -#include "jsobjinlines.h" - #include "vm/BooleanObject-inl.h" namespace js { diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 982f0222ca4a..03fff82cd175 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -27,6 +27,7 @@ #include "jstypes.h" #include "jsprf.h" #include "jsatom.h" +#include "jscompartment.h" #include "jsdbgapi.h" #include "jsexn.h" #include "jsfun.h" @@ -52,7 +53,6 @@ #include "yarr/BumpPointerAllocator.h" #include "jscntxtinlines.h" -#include "jscompartment.h" #include "jsobjinlines.h" using namespace js; @@ -1464,6 +1464,18 @@ JSContext::mark(JSTracer *trc) MarkValueRoot(trc, &iterValue, "iterValue"); } +JSVersion +JSContext::findVersion() const +{ + if (hasVersionOverride) + return versionOverride; + + if (JSScript *script = stack.currentScript(NULL, js::ContextStack::ALLOW_CROSS_COMPARTMENT)) + return script->getVersion(); + + return defaultVersion; +} + #if defined JS_THREADSAFE && defined DEBUG JS::AutoCheckRequestDepth::AutoCheckRequestDepth(JSContext *cx) @@ -1481,3 +1493,18 @@ JS::AutoCheckRequestDepth::~AutoCheckRequestDepth() } #endif + +#ifdef JS_CRASH_DIAGNOSTICS +void CompartmentChecker::check(StackFrame *fp) +{ + if (fp) + check(fp->scopeChain()); +} + +void CompartmentChecker::check(AbstractFramePtr frame) +{ + if (frame) + check(frame.scopeChain()); +} +#endif + diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 1a01b6cda11d..42a8b7bc6fee 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -357,7 +357,7 @@ class NewObjectCache inline JSObject *newObjectFromHit(JSContext *cx, EntryIndex entry, js::gc::InitialHeap heap); /* Fill an entry after a cache miss. */ - inline void fillProto(EntryIndex entry, Class *clasp, js::TaggedProto proto, gc::AllocKind kind, JSObject *obj); + void fillProto(EntryIndex entry, Class *clasp, js::TaggedProto proto, gc::AllocKind kind, JSObject *obj); inline void fillGlobal(EntryIndex entry, Class *clasp, js::GlobalObject *global, gc::AllocKind kind, JSObject *obj); inline void fillType(EntryIndex entry, Class *clasp, js::types::TypeObject *type, gc::AllocKind kind, JSObject *obj); @@ -1529,7 +1529,11 @@ struct JSContext : js::ContextFriendFields, JSRuntime *runtime() const { return runtime_; } JSCompartment *compartment() const { return compartment_; } - inline JS::Zone *zone() const; + inline JS::Zone *zone() const { + JS_ASSERT_IF(!compartment(), !zone_); + JS_ASSERT_IF(compartment(), js::GetCompartmentZone(compartment()) == zone_); + return zone_; + } js::PerThreadData &mainThread() { return runtime()->mainThread; } private: @@ -1695,7 +1699,7 @@ struct JSContext : js::ContextFriendFields, * * Note: if this ever shows up in a profile, just add caching! */ - inline JSVersion findVersion() const; + JSVersion findVersion() const; void setOptions(unsigned opts) { JS_ASSERT((opts & JSOPTION_MASK) == opts); @@ -1762,7 +1766,9 @@ struct JSContext : js::ContextFriendFields, void *onOutOfMemory(void *p, size_t nbytes) { return runtime()->onOutOfMemory(p, nbytes, this); } - void updateMallocCounter(size_t nbytes); + void updateMallocCounter(size_t nbytes) { + runtime()->updateMallocCounter(zone(), nbytes); + } void reportAllocationOverflow() { js_ReportAllocationOverflow(this); } @@ -2360,6 +2366,9 @@ JSBool intrinsic_IsCallable(JSContext *cx, unsigned argc, Value *vp); JSBool intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp); JSBool intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp); JSBool intrinsic_UnsafeSetElement(JSContext *cx, unsigned argc, Value *vp); +JSBool intrinsic_UnsafeGetElement(JSContext *cx, unsigned argc, Value *vp); +JSBool intrinsic_UnsafeGetImmutableElement(JSContext *cx, unsigned argc, + Value *vp); JSBool intrinsic_ShouldForceSequential(JSContext *cx, unsigned argc, Value *vp); JSBool intrinsic_NewParallelArray(JSContext *cx, unsigned argc, Value *vp); diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 103de78ad18a..6713e4464a57 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -20,6 +20,8 @@ #include "jsgcinlines.h" +#include "vm/ObjectImpl-inl.h" + namespace js { inline void @@ -85,14 +87,6 @@ NewObjectCache::fill(EntryIndex entry_, Class *clasp, gc::Cell *key, gc::AllocKi js_memcpy(&entry->templateObject, obj, entry->nbytes); } -inline void -NewObjectCache::fillProto(EntryIndex entry, Class *clasp, js::TaggedProto proto, gc::AllocKind kind, JSObject *obj) -{ - JS_ASSERT_IF(proto.isObject(), !proto.toObject()->isGlobal()); - JS_ASSERT(obj->getTaggedProto() == proto); - return fill(entry, clasp, proto.raw(), kind, obj); -} - inline void NewObjectCache::fillGlobal(EntryIndex entry, Class *clasp, js::GlobalObject *global, gc::AllocKind kind, JSObject *obj) { @@ -107,6 +101,16 @@ NewObjectCache::fillType(EntryIndex entry, Class *clasp, js::types::TypeObject * return fill(entry, clasp, type, kind, obj); } +inline void +NewObjectCache::copyCachedToObject(JSObject *dst, JSObject *src, gc::AllocKind kind) +{ + js_memcpy(dst, src, gc::Arena::thingSize(kind)); +#ifdef JSGC_GENERATIONAL + Shape::writeBarrierPost(dst->shape_, &dst->shape_); + types::TypeObject::writeBarrierPost(dst->type_, &dst->type_); +#endif +} + inline JSObject * NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::InitialHeap heap) { @@ -248,15 +252,8 @@ class CompartmentChecker check(script->compartment()); } - void check(StackFrame *fp) { - if (fp) - check(fp->scopeChain()); - } - - void check(AbstractFramePtr frame) { - if (frame) - check(frame.scopeChain()); - } + void check(StackFrame *fp); + void check(AbstractFramePtr frame); }; #endif /* JS_CRASH_DIAGNOSTICS */ @@ -465,18 +462,6 @@ CallSetter(JSContext *cx, HandleObject obj, HandleId id, StrictPropertyOp op, un } /* namespace js */ -inline JSVersion -JSContext::findVersion() const -{ - if (hasVersionOverride) - return versionOverride; - - if (JSScript *script = stack.currentScript(NULL, js::ContextStack::ALLOW_CROSS_COMPARTMENT)) - return script->getVersion(); - - return defaultVersion; -} - inline bool JSContext::canSetDefaultVersion() const { @@ -589,20 +574,6 @@ JSContext::leaveCompartment(JSCompartment *oldCompartment) wrapPendingException(); } -inline JS::Zone * -JSContext::zone() const -{ - JS_ASSERT_IF(!compartment(), !zone_); - JS_ASSERT_IF(compartment(), compartment()->zone() == zone_); - return zone_; -} - -inline void -JSContext::updateMallocCounter(size_t nbytes) -{ - runtime()->updateMallocCounter(zone(), nbytes); -} - inline void JSContext::setCompartment(JSCompartment *comp) { diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 48b8459d7890..065757c39b02 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -25,6 +25,8 @@ #include "jsgcinlines.h" #include "jsobjinlines.h" +#include "gc/Barrier-inl.h" + using namespace js; using namespace js::gc; @@ -603,6 +605,77 @@ JSCompartment::hasScriptsOnStack() return false; } +static bool +AddInnerLazyFunctionsFromScript(JSScript *script, AutoObjectVector &lazyFunctions) +{ + if (!script->hasObjects()) + return true; + ObjectArray *objects = script->objects(); + for (size_t i = script->innerObjectsStart(); i < objects->length; i++) { + JSObject *obj = objects->vector[i]; + if (obj->isFunction() && obj->toFunction()->isInterpretedLazy()) { + if (!lazyFunctions.append(obj)) + return false; + } + } + return true; +} + +static bool +CreateLazyScriptsForCompartment(JSContext *cx) +{ + AutoObjectVector lazyFunctions(cx); + + // Find all root lazy functions in the compartment: those which have not been + // compiled and which have a source object, indicating that their parent has + // been compiled. + for (gc::CellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) { + JSObject *obj = i.get(); + if (obj->compartment() == cx->compartment() && obj->isFunction()) { + JSFunction *fun = obj->toFunction(); + if (fun->isInterpretedLazy()) { + LazyScript *lazy = fun->lazyScript(); + if (lazy->sourceObject() && !lazy->maybeScript()) { + if (!lazyFunctions.append(fun)) + return false; + } + } + } + } + + // 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. + for (size_t i = 0; i < lazyFunctions.length(); i++) { + JSFunction *fun = lazyFunctions[i]->toFunction(); + + // lazyFunctions may have been populated with multiple functions for + // a lazy script. + if (!fun->isInterpretedLazy()) + continue; + + JSScript *script = fun->getOrCreateScript(cx); + if (!script) + return false; + if (!AddInnerLazyFunctionsFromScript(script, lazyFunctions)) + return false; + } + + // Repoint any clones of the original functions to their new script. + for (gc::CellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) { + JSObject *obj = i.get(); + if (obj->compartment() == cx->compartment() && obj->isFunction()) { + JSFunction *fun = obj->toFunction(); + if (fun->isInterpretedLazy()) { + JS_ASSERT(fun->lazyScript()->maybeScript()); + JS_ALWAYS_TRUE(fun->getOrCreateScript(cx)); + } + } + } + + return true; +} + bool JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeGC &dmgc) { @@ -626,6 +699,8 @@ JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeGC &dmgc) JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_NOT_IDLE); return false; } + if (enabledAfter && !CreateLazyScriptsForCompartment(cx)) + return false; } debugModeBits = (debugModeBits & ~unsigned(DebugFromC)) | (b ? DebugFromC : 0); @@ -677,10 +752,14 @@ JSCompartment::addDebuggee(JSContext *cx, js::GlobalObject *global) bool JSCompartment::addDebuggee(JSContext *cx, - js::GlobalObject *global, + GlobalObject *globalArg, AutoDebugModeGC &dmgc) { + Rooted global(cx, globalArg); + bool wasEnabled = debugMode(); + if (!wasEnabled && !CreateLazyScriptsForCompartment(cx)) + return false; if (!debuggees.put(global)) { js_ReportOutOfMemory(cx); return false; diff --git a/js/src/jscompartmentinlines.h b/js/src/jscompartmentinlines.h index 2925632dec25..0cd9475eab7c 100644 --- a/js/src/jscompartmentinlines.h +++ b/js/src/jscompartmentinlines.h @@ -9,6 +9,8 @@ #include "jscompartment.h" +#include "jscntxtinlines.h" + inline void JSCompartment::initGlobal(js::GlobalObject &global) { diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 2a603f26446a..44c434ca6730 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -38,6 +38,7 @@ #include "jsobj.h" #include "jsstr.h" +#include "js/Date.h" #include "vm/DateTime.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" @@ -47,8 +48,6 @@ #include "jsobjinlines.h" -#include "js/Date.h" - using namespace js; using namespace js::types; diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 5ee1c1a98e50..371fd74fb692 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -35,7 +35,6 @@ #include "jsatominlines.h" #include "jsinferinlines.h" -#include "jsobjinlines.h" #include "jsscriptinlines.h" #include "vm/Debugger-inl.h" diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 4e528f027ffd..413f5e7fea9b 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -13,6 +13,7 @@ #include "jscntxt.h" #include "jscompartment.h" #include "jsgc.h" +#include "jsobj.h" #include "jswrapper.h" #include "jsweakmap.h" #include "jswatchpoint.h" diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index aa763956641e..122db3f6d914 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -35,7 +35,6 @@ #include "jsfuninlines.h" #include "jsinferinlines.h" -#include "jsobjinlines.h" #include "jsscriptinlines.h" #include "vm/Interpreter-inl.h" @@ -350,9 +349,11 @@ js::XDRInterpretedFunction(XDRState *xdr, HandleObject enclosingScope, Han return false; } firstword = !!fun->atom(); - flagsword = (fun->nargs << 16) | fun->flags; + script = fun->getOrCreateScript(cx); + if (!script) + return false; atom = fun->atom(); - script = fun->nonLazyScript(); + flagsword = (fun->nargs << 16) | fun->flags; } else { fun = NewFunction(cx, NullPtr(), NULL, 0, JSFunction::INTERPRETED, NullPtr(), NullPtr(), JSFunction::FinalizeKind, TenuredObject); @@ -1057,9 +1058,10 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti if (cx->zone()->needsBarrier()) LazyScript::writeBarrierPre(lazy); + fun->flags &= ~INTERPRETED_LAZY; + fun->flags |= INTERPRETED; + if (JSScript *script = lazy->maybeScript()) { - fun->flags &= ~INTERPRETED_LAZY; - fun->flags |= INTERPRETED; fun->initScript(script); /* @@ -1072,10 +1074,9 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti return true; } - /* Lazily parsed script. */ - const jschar *chars = lazy->source()->chars(cx); - if (!chars) - return false; + fun->initScript(NULL); + + JS_ASSERT(lazy->source()->hasSourceData()); /* * GC must be suppressed for the remainder of the lazy parse, as any @@ -1083,9 +1084,10 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti */ AutoSuppressGC suppressGC(cx); - fun->flags &= ~INTERPRETED_LAZY; - fun->flags |= INTERPRETED; - fun->initScript(NULL); + /* Lazily parsed script. */ + const jschar *chars = lazy->source()->chars(cx); + if (!chars) + return false; const jschar *lazyStart = chars + lazy->begin(); size_t lazyLength = lazy->end() - lazy->begin(); diff --git a/js/src/jsfun.h b/js/src/jsfun.h index c93557a90ea8..e5d060a0e831 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -142,7 +142,6 @@ class JSFunction : public JSObject // Can be called multiple times by the parser. void setArgCount(uint16_t nargs) { - JS_ASSERT(this->nargs == 0 || this->nargs == nargs); this->nargs = nargs; } @@ -186,13 +185,6 @@ class JSFunction : public JSObject flags |= EXPR_CLOSURE; } - void markNotLazy() { - JS_ASSERT(isInterpretedLazy()); - JS_ASSERT(hasScript()); - flags |= INTERPRETED; - flags &= ~INTERPRETED_LAZY; - } - JSAtom *atom() const { return hasGuessedAtom() ? NULL : atom_.get(); } js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? NULL : atom_->asPropertyName(); } inline void initAtom(JSAtom *atom); @@ -221,7 +213,6 @@ class JSFunction : public JSObject JS_ASSERT(cx); if (isInterpretedLazy()) { JS::RootedFunction self(cx, this); - js::MaybeCheckStackRoots(cx); if (!createScriptForLazilyInterpretedFunction(cx, self)) return NULL; JS_ASSERT(self->hasScript()); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index bb92eedcd3df..3b1e1e6e6d08 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -168,7 +168,8 @@ static const AllocKind FinalizePhaseStrings[] = { }; static const AllocKind FinalizePhaseScripts[] = { - FINALIZE_SCRIPT + FINALIZE_SCRIPT, + FINALIZE_LAZY_SCRIPT }; static const AllocKind FinalizePhaseIonCode[] = { @@ -213,7 +214,6 @@ static const AllocKind BackgroundPhaseStrings[] = { }; static const AllocKind BackgroundPhaseShapes[] = { - FINALIZE_LAZY_SCRIPT, FINALIZE_SHAPE, FINALIZE_BASE_SHAPE, FINALIZE_TYPE_OBJECT @@ -1440,7 +1440,7 @@ ArenaLists::queueScriptsForSweep(FreeOp *fop) { gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_SCRIPT); queueForForegroundSweep(fop, FINALIZE_SCRIPT); - queueForBackgroundSweep(fop, FINALIZE_LAZY_SCRIPT); + queueForForegroundSweep(fop, FINALIZE_LAZY_SCRIPT); } void diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 4eec8386f750..8eb84af8de3f 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -204,7 +204,7 @@ IsBackgroundFinalized(AllocKind kind) false, /* FINALIZE_OBJECT16 */ true, /* FINALIZE_OBJECT16_BACKGROUND */ false, /* FINALIZE_SCRIPT */ - true, /* FINALIZE_LAZY_SCRIPT */ + false, /* FINALIZE_LAZY_SCRIPT */ true, /* FINALIZE_SHAPE */ true, /* FINALIZE_BASE_SHAPE */ true, /* FINALIZE_TYPE_OBJECT */ diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index d25c20b483bb..1f239121d9e7 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -32,8 +32,8 @@ #include "jsatominlines.h" #include "jsgcinlines.h" #include "jsinferinlines.h" -#include "jsobjinlines.h" #include "jsopcodeinlines.h" +#include "jsobjinlines.h" #include "jsscriptinlines.h" #include "vm/Stack-inl.h" diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index 80a74ecd756e..cae493ee3270 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -22,6 +22,8 @@ #include "vm/GlobalObject.h" #include "jsanalyzeinlines.h" + +#include "gc/Barrier-inl.h" #include "vm/Stack-inl.h" #ifndef jsinferinlines_h___ @@ -734,28 +736,20 @@ UseNewTypeForClone(JSFunction *fun) * instance a singleton type and clone the underlying script. */ - JSScript *script = fun->nonLazyScript(); - - if (script->length >= 50) - return false; - - if (script->hasConsts() || script->hasObjects() || script->hasRegexps() || fun->isHeavyweight()) - return false; - - bool hasArguments = false; - bool hasApply = false; - - for (jsbytecode *pc = script->code; - pc != script->code + script->length; - pc += GetBytecodeLength(pc)) - { - if (*pc == JSOP_ARGUMENTS) - hasArguments = true; - if (*pc == JSOP_FUNAPPLY) - hasApply = true; + uint32_t begin, end; + if (fun->hasScript()) { + if (!fun->nonLazyScript()->usesArgumentsAndApply) + return false; + begin = fun->nonLazyScript()->sourceStart; + end = fun->nonLazyScript()->sourceEnd; + } else { + if (!fun->lazyScript()->usesArgumentsAndApply()) + return false; + begin = fun->lazyScript()->begin(); + end = fun->lazyScript()->end(); } - return hasArguments && hasApply; + return end - begin <= 100; } ///////////////////////////////////////////////////////////////////// diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 3bd99e403d4d..2c8159b11b7f 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -42,7 +42,6 @@ #include "vm/StringBuffer.h" #include "jsatominlines.h" -#include "jsobjinlines.h" #include "jsstrinlines.h" #include "vm/NumberObject-inl.h" #include "vm/String-inl.h" diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index ae153ae604f5..6aaa1b01d461 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1222,6 +1222,8 @@ JSObject::isSealedOrFrozen(JSContext *cx, HandleObject obj, ImmutabilityType it, const char * JSObject::className(JSContext *cx, HandleObject obj) { + assertSameCompartment(cx, obj); + if (obj->isProxy()) return Proxy::className(cx, obj); @@ -1281,6 +1283,15 @@ NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *paren return obj; } +void +NewObjectCache::fillProto(EntryIndex entry, Class *clasp, js::TaggedProto proto, + gc::AllocKind kind, JSObject *obj) +{ + JS_ASSERT_IF(proto.isObject(), !proto.toObject()->isGlobal()); + JS_ASSERT(obj->getTaggedProto() == proto); + return fill(entry, clasp, proto.raw(), kind, obj); +} + JSObject * js::NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, js::TaggedProto proto_, JSObject *parent_, diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 33cdab295ced..b308dc285cce 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -463,7 +463,6 @@ class JSObject : public js::ObjectImpl * GC in order to compute the proto. Currently, it will not run JS code. */ inline JSObject *getProto() const; - using js::ObjectImpl::getTaggedProto; static inline bool getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject protop); @@ -539,7 +538,6 @@ class JSObject : public js::ObjectImpl static bool setMetadata(JSContext *cx, js::HandleObject obj, js::HandleObject newMetadata); inline js::GlobalObject &global() const; - using js::ObjectImpl::compartment; /* Remove the type (and prototype) or parent from a new object. */ static inline bool clearType(JSContext *cx, js::HandleObject obj); @@ -970,54 +968,53 @@ class JSObject : public js::ObjectImpl */ /* Direct subtypes of JSObject: */ - inline bool isArray() const; - inline bool isArguments() const; - inline bool isArrayBuffer() const; - inline bool isDataView() const; - inline bool isDate() const; - inline bool isElementIterator() const; - inline bool isError() const; - inline bool isFunction() const; - inline bool isGenerator() const; - inline bool isGlobal() const; - inline bool isMapIterator() const; - inline bool isModule() const; - inline bool isObject() const; - inline bool isPrimitive() const; + inline bool isArray() const { return hasClass(&js::ArrayClass); } + inline bool isArguments() const { return isNormalArguments() || isStrictArguments(); } + inline bool isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); } + inline bool isDataView() const { return hasClass(&js::DataViewClass); } + inline bool isDate() const { return hasClass(&js::DateClass); } + inline bool isElementIterator() const { return hasClass(&js::ElementIteratorClass); } + inline bool isError() const { return hasClass(&js::ErrorClass); } + inline bool isFunction() const { return hasClass(&js::FunctionClass); } + inline bool isGenerator() const { return hasClass(&js::GeneratorClass); } + inline bool isGlobal() const; + inline bool isMapIterator() const { return hasClass(&js::MapIteratorClass); } + inline bool isModule() const { return hasClass(&js::ModuleClass); } + inline bool isObject() const { return hasClass(&js::ObjectClass); } + inline bool isPrimitive() const { return isNumber() || isString() || isBoolean(); } inline bool isPropertyIterator() const; using js::ObjectImpl::isProxy; - inline bool isRegExp() const; - inline bool isRegExpStatics() const; - inline bool isScope() const; - inline bool isScript() const; - inline bool isScriptSource() const; - inline bool isSetIterator() const; - inline bool isStopIteration() const; - inline bool isTypedArray() const; - inline bool isWeakMap() const; + inline bool isRegExp() const { return hasClass(&js::RegExpClass); } + inline bool isRegExpStatics() const { return hasClass(&js::RegExpStaticsClass); } + inline bool isScope() const { return isCall() || isDeclEnv() || isNestedScope(); } + inline bool isScriptSource() const { return hasClass(&js::ScriptSourceClass); } + inline bool isSetIterator() const { return hasClass(&js::SetIteratorClass); } + inline bool isStopIteration() const { return hasClass(&js::StopIterationClass); } + inline bool isTypedArray() const; + inline bool isWeakMap() const { return hasClass(&js::WeakMapClass); } /* Subtypes of ScopeObject. */ - inline bool isBlock() const; - inline bool isCall() const; - inline bool isDeclEnv() const; - inline bool isNestedScope() const; - inline bool isWith() const; + inline bool isBlock() const { return hasClass(&js::BlockClass); } + inline bool isCall() const { return hasClass(&js::CallClass); } + inline bool isDeclEnv() const { return hasClass(&js::DeclEnvClass); } + inline bool isNestedScope() const { return isBlock() || isWith(); } + inline bool isWith() const { return hasClass(&js::WithClass); } inline bool isClonedBlock() const; inline bool isStaticBlock() const; /* Subtypes of PrimitiveObject. */ - inline bool isBoolean() const; - inline bool isNumber() const; - inline bool isString() const; + inline bool isBoolean() const { return hasClass(&js::BooleanClass); } + inline bool isNumber() const { return hasClass(&js::NumberClass); } + inline bool isString() const { return hasClass(&js::StringClass); } /* Subtypes of ArgumentsObject. */ - inline bool isNormalArguments() const; - inline bool isStrictArguments() const; + inline bool isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); } + inline bool isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); } /* Subtypes of Proxy. */ - inline bool isDebugScope() const; - inline bool isWrapper() const; - inline bool isFunctionProxy() const; + inline bool isDebugScope() const; + inline bool isWrapper() const; + inline bool isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); } inline bool isCrossCompartmentWrapper() const; inline js::ArgumentsObject &asArguments(); @@ -1033,7 +1030,10 @@ class JSObject : public js::ObjectImpl inline js::GlobalObject &asGlobal(); inline js::MapObject &asMap(); inline js::MapIteratorObject &asMapIterator(); - inline js::Module &asModule(); + js::Module &asModule() { + JS_ASSERT(isModule()); + return *reinterpret_cast(this); + } inline js::NestedScopeObject &asNestedScope(); inline js::NormalArgumentsObject &asNormalArguments(); inline js::NumberObject &asNumber(); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 404c26f06bd7..bd710547a77b 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -9,43 +9,16 @@ #include "jsobj.h" -#include "jsapi.h" -#include "jsarray.h" -#include "jsbool.h" -#include "jscntxt.h" -#include "jsfun.h" -#include "jsiter.h" -#include "jslock.h" -#include "jsnum.h" -#include "jspropertytree.h" -#include "jsproxy.h" -#include "jsstr.h" -#include "jstypedarray.h" #include "jswrapper.h" -#include "builtin/Module.h" -#include "gc/Barrier.h" -#include "gc/Marking.h" -#include "js/MemoryMetrics.h" -#include "js/RootingAPI.h" -#include "js/TemplateLib.h" -#include "vm/BooleanObject.h" -#include "vm/GlobalObject.h" -#include "vm/Shape.h" #include "vm/NumberObject.h" #include "vm/Probes.h" -#include "vm/RegExpStatics.h" #include "vm/StringObject.h" #include "jsatominlines.h" -#include "jscompartmentinlines.h" #include "jsfuninlines.h" -#include "jsgcinlines.h" -#include "jsinferinlines.h" -#include "gc/Barrier-inl.h" + #include "vm/ObjectImpl-inl.h" -#include "vm/Shape-inl.h" -#include "vm/String-inl.h" /* static */ inline bool JSObject::enumerate(JSContext *cx, JS::HandleObject obj, JSIterateOp iterop, @@ -872,40 +845,9 @@ inline bool JSObject::watched() const return lastProperty()->hasObjectFlag(js::BaseShape::WATCHED); } -inline bool JSObject::isArray() const { return hasClass(&js::ArrayClass); } -inline bool JSObject::isArguments() const { return isNormalArguments() || isStrictArguments(); } -inline bool JSObject::isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); } -inline bool JSObject::isBlock() const { return hasClass(&js::BlockClass); } -inline bool JSObject::isBoolean() const { return hasClass(&js::BooleanClass); } -inline bool JSObject::isCall() const { return hasClass(&js::CallClass); } inline bool JSObject::isClonedBlock() const { return isBlock() && !!getProto(); } -inline bool JSObject::isDataView() const { return hasClass(&js::DataViewClass); } -inline bool JSObject::isDate() const { return hasClass(&js::DateClass); } -inline bool JSObject::isDeclEnv() const { return hasClass(&js::DeclEnvClass); } -inline bool JSObject::isElementIterator() const { return hasClass(&js::ElementIteratorClass); } -inline bool JSObject::isError() const { return hasClass(&js::ErrorClass); } -inline bool JSObject::isFunction() const { return hasClass(&js::FunctionClass); } -inline bool JSObject::isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); } -inline bool JSObject::isGenerator() const { return hasClass(&js::GeneratorClass); } -inline bool JSObject::isMapIterator() const { return hasClass(&js::MapIteratorClass); } -inline bool JSObject::isModule() const { return hasClass(&js::ModuleClass); } -inline bool JSObject::isNestedScope() const { return isBlock() || isWith(); } -inline bool JSObject::isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); } -inline bool JSObject::isNumber() const { return hasClass(&js::NumberClass); } -inline bool JSObject::isObject() const { return hasClass(&js::ObjectClass); } -inline bool JSObject::isPrimitive() const { return isNumber() || isString() || isBoolean(); } -inline bool JSObject::isRegExp() const { return hasClass(&js::RegExpClass); } -inline bool JSObject::isRegExpStatics() const { return hasClass(&js::RegExpStaticsClass); } -inline bool JSObject::isScope() const { return isCall() || isDeclEnv() || isNestedScope(); } -inline bool JSObject::isScriptSource() const { return hasClass(&js::ScriptSourceClass); } -inline bool JSObject::isSetIterator() const { return hasClass(&js::SetIteratorClass); } inline bool JSObject::isStaticBlock() const { return isBlock() && !getProto(); } -inline bool JSObject::isStopIteration() const { return hasClass(&js::StopIterationClass); } -inline bool JSObject::isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); } -inline bool JSObject::isString() const { return hasClass(&js::StringClass); } inline bool JSObject::isTypedArray() const { return IsTypedArrayClass(getClass()); } -inline bool JSObject::isWeakMap() const { return hasClass(&js::WeakMapClass); } -inline bool JSObject::isWith() const { return hasClass(&js::WithClass); } inline js::NumberObject & JSObject::asNumber() @@ -928,13 +870,6 @@ JSObject::asScriptSource() return *static_cast(this); } -inline js::Module & -JSObject::asModule() -{ - JS_ASSERT(isModule()); - return *static_cast(this); -} - inline bool JSObject::isDebugScope() const { @@ -1532,16 +1467,6 @@ class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescri friend void AutoGCRooter::trace(JSTracer *trc); }; -inline void -NewObjectCache::copyCachedToObject(JSObject *dst, JSObject *src, gc::AllocKind kind) -{ - js_memcpy(dst, src, gc::Arena::thingSize(kind)); -#ifdef JSGC_GENERATIONAL - Shape::writeBarrierPost(dst->shape_, &dst->shape_); - types::TypeObject::writeBarrierPost(dst->type_, &dst->type_); -#endif -} - static inline bool CanBeFinalizedInBackground(gc::AllocKind kind, Class *clasp) { diff --git a/js/src/json.cpp b/js/src/json.cpp index b7944b6167ff..2f60a17827b3 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -25,7 +25,6 @@ #include "jsatominlines.h" #include "jsboolinlines.h" -#include "jsobjinlines.h" using namespace js; using namespace js::gc; diff --git a/js/src/jsonparser.cpp b/js/src/jsonparser.cpp index 3e0dc7ee7675..2aa2ad678874 100644 --- a/js/src/jsonparser.cpp +++ b/js/src/jsonparser.cpp @@ -9,6 +9,7 @@ #include "mozilla/RangedPtr.h" #include "jsarray.h" +#include "jscompartment.h" #include "jsnum.h" #include "vm/StringBuffer.h" diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index f3fe3cf445d0..9b81302ea067 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -19,9 +19,11 @@ #include "jstypes.h" #include "jsutil.h" #include "jsprf.h" +#include "jsanalyze.h" #include "jsapi.h" #include "jsatom.h" #include "jscntxt.h" +#include "jscompartment.h" #include "jsfun.h" #include "jsnum.h" #include "jsobj.h" @@ -36,11 +38,13 @@ #include "jscntxtinlines.h" #include "jsobjinlines.h" +#include "jscompartmentinlines.h" #include "jsopcodeinlines.h" #include "jsautooplen.h" #include "vm/RegExpObject-inl.h" +#include "vm/ScopeObject-inl.h" using namespace js; using namespace js::gc; diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index a76d8cc26cae..43fed35235ff 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -2147,12 +2147,12 @@ ASTSerializer::statement(ParseNode *pn, MutableHandleValue dst) : builder.continueStatement(label, &pn->pn_pos, dst)); } - case PNK_COLON: + case PNK_LABEL: { JS_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos)); RootedValue label(cx), stmt(cx); - RootedAtom pnAtom(cx, pn->pn_atom); + RootedAtom pnAtom(cx, pn->as().label()); return identifier(pnAtom, NULL, &label) && statement(pn->pn_expr, &stmt) && builder.labeledStatement(label, stmt, &pn->pn_pos, dst); @@ -2516,7 +2516,7 @@ ASTSerializer::expression(ParseNode *pn, MutableHandleValue dst) for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { JS_ASSERT(pn->pn_pos.encloses(next->pn_pos)); - if (next->isKind(PNK_COMMA) && next->pn_count == 0) { + if (next->isKind(PNK_ELISION)) { elts.infallibleAppend(NullValue()); } else { RootedValue expr(cx); @@ -2696,10 +2696,7 @@ ASTSerializer::arrayPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValu return false; for (ParseNode *next = pn->pn_head; next; next = next->pn_next) { - /* Comma expressions can't occur inside patterns, so no need to test pn_count. */ - JS_ASSERT_IF(next->isKind(PNK_COMMA), next->pn_count == 0); - - if (next->isKind(PNK_COMMA)) { + if (next->isKind(PNK_ELISION)) { elts.infallibleAppend(NullValue()); } else { RootedValue patt(cx); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index eb777511d0bb..047322749b61 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -34,7 +34,6 @@ #include "vm/Xdr.h" #include "jsinferinlines.h" -#include "jsobjinlines.h" #include "jsscriptinlines.h" #include "vm/Interpreter-inl.h" @@ -666,7 +665,10 @@ js::XDRScript(XDRState *xdr, HandleObject enclosingScope, HandleScript enc /* Code the nested function's enclosing scope. */ uint32_t funEnclosingScopeIndex = 0; if (mode == XDR_ENCODE) { - RootedObject staticScope(cx, (*objp)->toFunction()->nonLazyScript()->enclosingStaticScope()); + JSScript *innerScript = (*objp)->toFunction()->getOrCreateScript(cx); + if (!innerScript) + return false; + RootedObject staticScope(cx, innerScript->enclosingStaticScope()); StaticScopeIter ssi(cx, staticScope); if (ssi.done() || ssi.type() == StaticScopeIter::FUNCTION) { JS_ASSERT(ssi.done() == !fun); @@ -1226,16 +1228,13 @@ SourceDataCache::purge() const jschar * ScriptSource::chars(JSContext *cx) { -#ifdef USE_ZLIB - Rooted cached(cx, NULL); -#endif #ifdef JS_THREADSAFE if (!ready()) return cx->runtime()->sourceCompressorThread.currentChars(); #endif #ifdef USE_ZLIB if (compressed()) { - cached = cx->runtime()->sourceDataCache.lookup(this); + JSStableString *cached = cx->runtime()->sourceDataCache.lookup(this); if (!cached) { const size_t nbytes = sizeof(jschar) * (length_ + 1); jschar *decompressed = static_cast(cx->malloc_(nbytes)); @@ -1257,10 +1256,8 @@ ScriptSource::chars(JSContext *cx) } return cached->chars().get(); } - return data.source; -#else - return data.source; #endif + return data.source; } JSStableString * @@ -2324,8 +2321,11 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun, assertSameCompartment(cx, innerFun); clone = innerFun; } else { - if (!innerFun->getOrCreateScript(cx)) - return NULL; + if (innerFun->isInterpretedLazy()) { + AutoCompartment ac(cx, innerFun); + if (!innerFun->getOrCreateScript(cx)) + return NULL; + } RootedObject staticScope(cx, innerFun->nonLazyScript()->enclosingStaticScope()); StaticScopeIter ssi(cx, staticScope); RootedObject enclosingScope(cx); @@ -2771,11 +2771,14 @@ JSScript::markChildren(JSTracer *trc) void LazyScript::markChildren(JSTracer *trc) { - if (parent_) - MarkScriptUnbarriered(trc, &parent_, "lazyScriptParent"); + if (sourceObject_) + MarkObject(trc, &sourceObject_, "sourceObject"); + + if (parentFunction_) + MarkObject(trc, &parentFunction_, "parentFunction"); if (script_) - MarkScriptUnbarriered(trc, &script_, "lazyScript"); + MarkScript(trc, &script_, "realScript"); HeapPtrAtom *freeVariables = this->freeVariables(); for (size_t i = 0; i < numFreeVariables(); i++) @@ -2791,6 +2794,9 @@ LazyScript::finalize(FreeOp *fop) { if (table_) fop->free_(table_); + + if (originPrincipals_) + JS_DropPrincipals(fop->runtime(), originPrincipals_); } void @@ -2939,8 +2945,58 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot) return argsObjAliasesFormals() && !formalIsAliased(argSlot); } +LazyScript::LazyScript(void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions, + JSVersion version, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) + : script_(NULL), + parentFunction_(NULL), + sourceObject_(NULL), + table_(table), + originPrincipals_(NULL), + version_(version), + numFreeVariables_(numFreeVariables), + numInnerFunctions_(numInnerFunctions), + strict_(false), + bindingsAccessedDynamically_(false), + hasDebuggerStatement_(false), + directlyInsideEval_(false), + usesArgumentsAndApply_(false), + hasBeenCloned_(false), + begin_(begin), + end_(end), + lineno_(lineno), + column_(column) +{ + JS_ASSERT(this->version() == version); + JS_ASSERT(begin <= end); +} + +void +LazyScript::initScript(JSScript *script) +{ + JS_ASSERT(script && !script_); + script_ = script; +} + +void +LazyScript::setParent(JSFunction *parentFunction, ScriptSourceObject *sourceObject, + JSPrincipals *originPrincipals) +{ + JS_ASSERT(sourceObject && !sourceObject_ && !parentFunction_ && !originPrincipals_); + parentFunction_ = parentFunction; + sourceObject_ = sourceObject; + originPrincipals_ = originPrincipals; + if (originPrincipals) + JS_HoldPrincipals(originPrincipals); +} + +ScriptSourceObject * +LazyScript::sourceObject() const +{ + return sourceObject_ ? &sourceObject_->asScriptSource() : NULL; +} + /* static */ LazyScript * -LazyScript::Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFunctions, +LazyScript::Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) { JS_ASSERT(begin <= end); @@ -2959,7 +3015,13 @@ LazyScript::Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFu if (!res) return NULL; - return new (res) LazyScript(table, numFreeVariables, numInnerFunctions, begin, end, lineno, column); + return new (res) LazyScript(table, numFreeVariables, numInnerFunctions, version, + begin, end, lineno, column); +} + +uint32_t LazyScript::staticLevel() const +{ + return parentFunction() ? parentFunction()->nonLazyScript()->staticLevel + 1 : 1; } void diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 173ba4c93a93..82b3232fd2e8 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -538,9 +538,12 @@ class JSScript : public js::gc::Cell bool isActiveEval:1; /* script came from eval(), and is still active */ bool isCachedEval:1; /* script came from eval(), and is in eval cache */ - /* Set for functions defined at the top level within an 'eval' script. */ + // Set for functions defined at the top level within an 'eval' script. bool directlyInsideEval:1; + // Both 'arguments' and f.apply() are used. This is likely to be a wrapper. + bool usesArgumentsAndApply:1; + /* script is attempted to be cloned anew at each callsite. This is temporarily needed for ParallelArray selfhosted code until type information can be made context sensitive. See discussion in @@ -1099,19 +1102,20 @@ class AliasedFormalIter struct SourceCompressionToken; - // Information about a script which may be (or has been) lazily compiled to // bytecode from its source. class LazyScript : public js::gc::Cell { - // Immediate parent in which the script is nested, or NULL if the parent - // has not been compiled yet. Lazy scripts are always functions within a - // global or eval script so there will be a parent. - JSScript *parent_; - // If non-NULL, the script has been compiled and this is a forwarding // pointer to the result. - JSScript *script_; + HeapPtrScript script_; + + // Immediate parent in which the script is nested, or NULL. + HeapPtrFunction parentFunction_; + + // Source code object, or NULL if the script in which this is nested has + // not been compiled yet. + HeapPtrObject sourceObject_; // Heap allocated table with any free variables or inner functions. void *table_; @@ -1120,14 +1124,20 @@ class LazyScript : public js::gc::Cell uint32_t padding; #endif - uint32_t numFreeVariables_; + // Assorted bits that should really be in ScriptSourceObject. + JSPrincipals *originPrincipals_; + uint32_t version_ : 8; + + uint32_t numFreeVariables_ : 24; uint32_t numInnerFunctions_ : 26; - bool strict_ : 1; - bool bindingsAccessedDynamically_ : 1; - bool hasDebuggerStatement_ : 1; - bool directlyInsideEval_:1; - bool hasBeenCloned_:1; + // N.B. These are booleans but need to be uint32_t to pack correctly on MSVC. + uint32_t strict_ : 1; + uint32_t bindingsAccessedDynamically_ : 1; + uint32_t hasDebuggerStatement_ : 1; + uint32_t directlyInsideEval_:1; + uint32_t usesArgumentsAndApply_:1; + uint32_t hasBeenCloned_:1; // Source location for the script. uint32_t begin_; @@ -1135,46 +1145,33 @@ class LazyScript : public js::gc::Cell uint32_t lineno_; uint32_t column_; - LazyScript(void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column) - : parent_(NULL), - script_(NULL), - table_(table), - numFreeVariables_(numFreeVariables), - numInnerFunctions_(numInnerFunctions), - strict_(false), - bindingsAccessedDynamically_(false), - hasDebuggerStatement_(false), - directlyInsideEval_(false), - hasBeenCloned_(false), - begin_(begin), - end_(end), - lineno_(lineno), - column_(column) - { - JS_ASSERT(begin <= end); - } + LazyScript(void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version, + uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); public: static LazyScript *Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFunctions, - uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); + JSVersion version, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column); - void initParent(JSScript *parent) { - JS_ASSERT(parent && !parent_); - parent_ = parent; - } - JSScript *parent() const { - return parent_; - } - - void initScript(JSScript *script) { - JS_ASSERT(script && !script_); - script_ = script; - } + void initScript(JSScript *script); JSScript *maybeScript() { return script_; } + JSFunction *parentFunction() const { + return parentFunction_; + } + ScriptSourceObject *sourceObject() const; + JSPrincipals *originPrincipals() const { + return originPrincipals_; + } + JSVersion version() const { + JS_STATIC_ASSERT(JSVERSION_UNKNOWN == -1); + return (version_ == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(version_); + } + + void setParent(JSFunction *parentFunction, ScriptSourceObject *sourceObject, + JSPrincipals *originPrincipals); + uint32_t numFreeVariables() const { return numFreeVariables_; } @@ -1217,6 +1214,13 @@ class LazyScript : public js::gc::Cell directlyInsideEval_ = true; } + bool usesArgumentsAndApply() const { + return usesArgumentsAndApply_; + } + void setUsesArgumentsAndApply() { + usesArgumentsAndApply_ = true; + } + bool hasBeenCloned() const { return hasBeenCloned_; } @@ -1225,7 +1229,7 @@ class LazyScript : public js::gc::Cell } ScriptSource *source() const { - return parent()->scriptSource(); + return sourceObject()->source(); } uint32_t begin() const { return begin_; @@ -1240,6 +1244,8 @@ class LazyScript : public js::gc::Cell return column_; } + uint32_t staticLevel() const; + Zone *zone() const { return Cell::tenuredZone(); } diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index ff422e94ba98..dce41aae863f 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -18,6 +18,8 @@ #include "vm/RegExpObject.h" #include "vm/Shape.h" +#include "jscompartmentinlines.h" + #include "vm/Shape-inl.h" namespace js { diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 752b2a45a3fe..193a6ffb6265 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -47,7 +47,6 @@ #include "vm/StringBuffer.h" #include "jsinferinlines.h" -#include "jsobjinlines.h" #include "jsstrinlines.h" #include "jsautooplen.h" // generated headers last diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 8f9b6d2a715d..aece0b479aa7 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -30,7 +30,6 @@ #include "jsatominlines.h" #include "jsinferinlines.h" -#include "jsobjinlines.h" #include "jstypedarrayinlines.h" #include "vm/GlobalObject-inl.h" diff --git a/js/src/jswatchpoint.cpp b/js/src/jswatchpoint.cpp index 7e35298701d8..db9d8a198d35 100644 --- a/js/src/jswatchpoint.cpp +++ b/js/src/jswatchpoint.cpp @@ -7,9 +7,11 @@ #include "jswatchpoint.h" #include "jsatom.h" +#include "jscompartment.h" #include "gc/Marking.h" +#include "jsgcinlines.h" #include "jsobjinlines.h" using namespace js; diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index 86f70a84950d..1c70d9de41d0 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -17,6 +17,8 @@ #include "jsobjinlines.h" +#include "gc/Barrier-inl.h" + using namespace js; WeakMapBase::WeakMapBase(JSObject *memOf, JSCompartment *c) diff --git a/js/src/perf/jsperf.cpp b/js/src/perf/jsperf.cpp index 4940e9da8fd8..d1b36f54e124 100644 --- a/js/src/perf/jsperf.cpp +++ b/js/src/perf/jsperf.cpp @@ -8,7 +8,6 @@ #include "jscntxt.h" /* for error messages */ #include "jsobj.h" /* for unwrapping without a context */ -#include "jsobjinlines.h" #include "vm/ObjectImpl-inl.h" using JS::PerfMeasurement; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 55a0a1b3c89c..18a174ff95c6 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -52,7 +52,6 @@ #include "jsheaptools.h" #include "jsinferinlines.h" -#include "jsobjinlines.h" #include "jsscriptinlines.h" #include "ion/Ion.h" diff --git a/js/src/tests/ecma_2/Statements/label-003.js b/js/src/tests/ecma_2/Statements/label-003.js new file mode 100644 index 000000000000..d3ed464f5f8b --- /dev/null +++ b/js/src/tests/ecma_2/Statements/label-003.js @@ -0,0 +1,15 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// The colon for a labeled statement may be on a separate line. +var x; +label +: { + x = 1; + break label; + x = 2; +} +assertEq(x, 1); +reportCompare(0, 0, 'ok'); diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index 29c2a4378804..b9f9345dfb96 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -18,7 +18,7 @@ #include "vm/Stack-inl.h" #include "vm/ArgumentsObject-inl.h" -#if defined(JS_ION) +#if defined(JS_ION) #include "ion/IonFrames.h" #endif diff --git a/js/src/vm/BooleanObject-inl.h b/js/src/vm/BooleanObject-inl.h index b84171b8eb1d..688330031a3c 100644 --- a/js/src/vm/BooleanObject-inl.h +++ b/js/src/vm/BooleanObject-inl.h @@ -7,10 +7,10 @@ #ifndef BooleanObject_inl_h___ #define BooleanObject_inl_h___ -#include "jsobjinlines.h" - #include "vm/BooleanObject.h" +#include "jsobjinlines.h" + inline js::BooleanObject & JSObject::asBoolean() { diff --git a/js/src/vm/Debugger-inl.h b/js/src/vm/Debugger-inl.h index 61117ebde761..c05766ed9e52 100644 --- a/js/src/vm/Debugger-inl.h +++ b/js/src/vm/Debugger-inl.h @@ -11,7 +11,7 @@ #include "vm/Stack-inl.h" -bool +inline bool js::Debugger::onLeaveFrame(JSContext *cx, AbstractFramePtr frame, bool ok) { /* Traps must be cleared from eval frames, see slowPathOnLeaveFrame. */ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index fd14b3bba038..63a6413b8060 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -21,8 +21,8 @@ #include "js/Vector.h" #include "jsgcinlines.h" -#include "jsobjinlines.h" #include "jsopcodeinlines.h" + #include "gc/FindSCCs-inl.h" #include "vm/Interpreter-inl.h" #include "vm/Stack-inl.h" @@ -229,7 +229,6 @@ class Debugger::FrameRange } }; - /*** Breakpoints *********************************************************************************/ BreakpointSite::BreakpointSite(JSScript *script, jsbytecode *pc) @@ -686,7 +685,6 @@ Debugger::wrapDebuggeeValue(JSContext *cx, MutableHandleValue vp) assertSameCompartment(cx, object.get()); if (vp.isObject()) { - // Do we need this RootedObject? RootedObject obj(cx, &vp.toObject()); ObjectWeakMap::AddPtr p = objects.lookupForAdd(obj); @@ -2887,16 +2885,6 @@ DebuggerScript_getSourceMapUrl(JSContext *cx, unsigned argc, Value *vp) return true; } -static bool -EnsureFunctionHasScript(JSContext *cx, JSFunction *fun) -{ - if (fun->isInterpretedLazy()) { - AutoCompartment ac(cx, fun); - return fun->getOrCreateScript(cx); - } - return true; -} - static JSBool DebuggerScript_getChildScripts(JSContext *cx, unsigned argc, Value *vp) { @@ -2921,10 +2909,6 @@ DebuggerScript_getChildScripts(JSContext *cx, unsigned argc, Value *vp) obj = objects->vector[i]; if (obj->isFunction()) { fun = static_cast(obj.get()); - - if (!EnsureFunctionHasScript(cx, fun)) - return false; - funScript = fun->nonLazyScript(); s = dbg->wrapScript(cx, funScript); if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s))) @@ -4397,7 +4381,11 @@ static JSBool DebuggerObject_getClass(JSContext *cx, unsigned argc, Value *vp) { THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get class", args, refobj); - const char *className = JSObject::className(cx, refobj); + const char *className; + { + AutoCompartment ac(cx, refobj); + className = JSObject::className(cx, refobj); + } JSAtom *str = Atomize(cx, className, strlen(className)); if (!str) return false; @@ -4473,9 +4461,6 @@ DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp) result->ensureDenseInitializedLength(cx, 0, fun->nargs); if (fun->isInterpreted()) { - if (!EnsureFunctionHasScript(cx, fun)) - return false; - JS_ASSERT(fun->nargs == fun->nonLazyScript()->bindings.numArgs()); if (fun->nargs > 0) { @@ -4517,9 +4502,6 @@ DebuggerObject_getScript(JSContext *cx, unsigned argc, Value *vp) return true; } - if (!EnsureFunctionHasScript(cx, fun)) - return false; - RootedScript script(cx, fun->nonLazyScript()); RootedObject scriptObject(cx, dbg->wrapScript(cx, script)); if (!scriptObject) diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 7e77fc47ea13..dc63a22b6fa1 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -422,7 +422,7 @@ class Debugger : private mozilla::LinkedListElement inline bool observesNewScript() const; inline bool observesNewGlobalObject() const; inline bool observesGlobal(GlobalObject *global) const; - inline bool observesFrame(AbstractFramePtr frame) const; + bool observesFrame(AbstractFramePtr frame) const; bool observesScript(JSScript *script) const; /* diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index ed46bec8d4f1..e91e0ba1fa15 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -20,6 +20,7 @@ #include "builtin/Object.h" #include "builtin/RegExp.h" +#include "jscompartmentinlines.h" #include "jsobjinlines.h" #include "vm/GlobalObject-inl.h" diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index a9a224f43dec..c4332a21ff18 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -42,9 +42,9 @@ #include "jsatominlines.h" #include "jsboolinlines.h" #include "jsinferinlines.h" -#include "jsobjinlines.h" #include "jsopcodeinlines.h" #include "jsscriptinlines.h" + #include "builtin/Iterator-inl.h" #include "ion/IonFrames-inl.h" #include "vm/Interpreter-inl.h" @@ -280,6 +280,9 @@ js::ValueToCallable(JSContext *cx, const Value &v, int numToSkip, MaybeConstruct return NULL; } +static JS_NEVER_INLINE bool +Interpret(JSContext *cx, StackFrame *entryFrame); + bool js::RunScript(JSContext *cx, StackFrame *fp) { @@ -342,7 +345,7 @@ js::RunScript(JSContext *cx, StackFrame *fp) } #endif - return Interpret(cx, fp) != Interpret_Error; + return Interpret(cx, fp); } /* @@ -985,13 +988,12 @@ js::IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval) return js_IteratorNext(cx, iterobj, rval); } -JS_NEVER_INLINE InterpretStatus -js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool useNewType) +static JS_NEVER_INLINE bool +Interpret(JSContext *cx, StackFrame *entryFrame) { JSAutoResolveFlags rf(cx, RESOLVE_INFER); - if (interpMode == JSINTERP_NORMAL) - gc::MaybeVerifyBarriers(cx, true); + gc::MaybeVerifyBarriers(cx, true); JS_ASSERT(!cx->compartment()->activeAnalysis); @@ -1060,8 +1062,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool script = (s); \ if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts) \ interrupts.enable(); \ - JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP, \ - script->hasAnyBreakpointsOrStepMode()); \ JS_END_MACRO /* Repoint cx->regs to a local variable for faster access. */ @@ -1128,43 +1128,28 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool /* State communicated between non-local jumps: */ bool interpReturnOK; - /* Don't call the script prologue if executing between Method and Trace JIT. */ - if (interpMode == JSINTERP_NORMAL) { - StackFrame *fp = regs.fp(); - if (!fp->isGeneratorFrame()) { - if (!fp->prologue(cx)) - goto error; - } else { - Probes::enterScript(cx, script, script->function(), fp); - } - if (cx->compartment()->debugMode()) { - JSTrapStatus status = ScriptDebugPrologue(cx, fp); - switch (status) { - case JSTRAP_CONTINUE: - break; - case JSTRAP_RETURN: - interpReturnOK = true; - goto forced_return; - case JSTRAP_THROW: - case JSTRAP_ERROR: - goto error; - default: - JS_NOT_REACHED("bad ScriptDebugPrologue status"); - } + if (!entryFrame->isGeneratorFrame()) { + if (!entryFrame->prologue(cx)) + goto error; + } else { + Probes::enterScript(cx, script, script->function(), entryFrame); + } + if (cx->compartment()->debugMode()) { + JSTrapStatus status = ScriptDebugPrologue(cx, entryFrame); + switch (status) { + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + interpReturnOK = true; + goto forced_return; + case JSTRAP_THROW: + case JSTRAP_ERROR: + goto error; + default: + JS_NOT_REACHED("bad ScriptDebugPrologue status"); } } - /* The REJOIN mode acts like the normal mode, except the prologue is skipped. */ - if (interpMode == JSINTERP_REJOIN) - interpMode = JSINTERP_NORMAL; - - /* - * The RETHROW mode acts like a bailout mode, except that it resume an - * exception instead of resuming the script. - */ - if (interpMode == JSINTERP_RETHROW) - goto error; - /* * It is important that "op" be initialized before calling DO_OP because * it is possible for "op" to be specially assigned during the normal @@ -1240,7 +1225,7 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool if (script->hasAnyBreakpointsOrStepMode()) moreInterrupts = true; - if (script->hasBreakpointsAt(regs.pc) && interpMode != JSINTERP_SKIP_TRAP) { + if (script->hasBreakpointsAt(regs.pc)) { RootedValue rval(cx); JSTrapStatus status = Debugger::onTrap(cx, &rval); switch (status) { @@ -1260,8 +1245,6 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode, bool JS_ASSERT(rval.isInt32() && rval.toInt32() == op); } - interpMode = JSINTERP_NORMAL; - switchMask = moreInterrupts ? -1 : 0; switchOp = int(op); goto do_switch; @@ -3022,9 +3005,6 @@ END_CASE(JSOP_ARRAYPUSH) JS_ASSERT(&cx->regs() == ®s); JS_ASSERT(uint32_t(regs.pc - script->code) < script->length); - /* When rejoining, we must not err before finishing Interpret's prologue. */ - JS_ASSERT(interpMode != JSINTERP_REJOIN); - if (cx->isExceptionPending()) { /* Call debugger throw hooks. */ if (cx->compartment()->debugMode()) { @@ -3149,7 +3129,7 @@ END_CASE(JSOP_ARRAYPUSH) leave_on_safe_point: #endif - return interpReturnOK ? Interpret_Ok : Interpret_Error; + return interpReturnOK; } bool @@ -3259,7 +3239,7 @@ js::DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain, */ RootedFunction fun(cx, funArg); if (fun->isNative() || fun->environment() != scopeChain) { - fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain); + fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain, TenuredObject); if (!fun) return false; } else { diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 61605bb508dd..f46b63d048ac 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -164,31 +164,6 @@ ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChain, const Va extern bool Execute(JSContext *cx, HandleScript script, JSObject &scopeChain, Value *rval); -/* Flags to toggle js::Interpret() execution. */ -enum InterpMode -{ - JSINTERP_NORMAL = 0, /* interpreter is running normally */ - JSINTERP_REJOIN = 1, /* as normal, but the frame has already started */ - JSINTERP_SKIP_TRAP = 2, /* as REJOIN, but skip trap at first opcode */ - JSINTERP_BAILOUT = 3, /* interpreter is running from an Ion bailout */ - JSINTERP_RETHROW = 4 /* as BAILOUT, but unwind all frames */ -}; - -enum InterpretStatus -{ - Interpret_Error = 0, /* interpreter had an error */ - Interpret_Ok = 1, /* interpreter executed successfully */ - Interpret_OSR = 2 /* when mode=BAILOUT and we should OSR into Ion */ -}; - -/* - * Execute the caller-initialized frame for a user-defined script or function - * pointed to by cx->fp until completion or error. - */ -extern JS_NEVER_INLINE InterpretStatus -Interpret(JSContext *cx, StackFrame *stopFp, InterpMode mode = JSINTERP_NORMAL, - bool useNewType = false); - extern bool RunScript(JSContext *cx, StackFrame *fp); diff --git a/js/src/vm/NumberObject-inl.h b/js/src/vm/NumberObject-inl.h index 651cb93d6ddd..5e899d288791 100644 --- a/js/src/vm/NumberObject-inl.h +++ b/js/src/vm/NumberObject-inl.h @@ -9,6 +9,8 @@ #include "NumberObject.h" +#include "jsobjinlines.h" + namespace js { inline NumberObject * diff --git a/js/src/vm/ObjectImpl-inl.h b/js/src/vm/ObjectImpl-inl.h index e539041f5636..745d75116f52 100644 --- a/js/src/vm/ObjectImpl-inl.h +++ b/js/src/vm/ObjectImpl-inl.h @@ -204,24 +204,6 @@ js::ObjectImpl::invalidateSlotRange(uint32_t start, uint32_t length) #endif /* DEBUG */ } -inline void -js::ObjectImpl::initializeSlotRange(uint32_t start, uint32_t length) -{ - /* - * No bounds check, as this is used when the object's shape does not - * reflect its allocated slots (updateSlotsForSpan). - */ - HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; - getSlotRangeUnchecked(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd); - - JSRuntime *rt = runtime(); - uint32_t offset = start; - for (HeapSlot *sp = fixedStart; sp < fixedEnd; sp++) - sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue()); - for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++) - sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue()); -} - inline bool js::ObjectImpl::isNative() const { @@ -332,12 +314,6 @@ js::ObjectImpl::getJSClass() const return Jsvalify(getClass()); } -inline bool -js::ObjectImpl::hasClass(const Class *c) const -{ - return getClass() == c; -} - inline const js::ObjectOps * js::ObjectImpl::getOps() const { @@ -456,38 +432,6 @@ js::ObjectImpl::writeBarrierPost(ObjectImpl *obj, void *addr) #endif } -inline bool -js::ObjectImpl::hasPrivate() const -{ - return getClass()->hasPrivate(); -} - -inline void *& -js::ObjectImpl::privateRef(uint32_t nfixed) const -{ - /* - * The private pointer of an object can hold any word sized value. - * Private pointers are stored immediately after the last fixed slot of - * the object. - */ - MOZ_ASSERT(nfixed == numFixedSlots()); - MOZ_ASSERT(hasPrivate()); - HeapSlot *end = &fixedSlots()[nfixed]; - return *reinterpret_cast(end); -} - -inline void * -js::ObjectImpl::getPrivate() const -{ - return privateRef(numFixedSlots()); -} - -inline void * -js::ObjectImpl::getPrivate(uint32_t nfixed) const -{ - return privateRef(nfixed); -} - inline void js::ObjectImpl::setPrivate(void *data) { diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index 47614737b126..085d9f030d7c 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -13,6 +13,7 @@ #include "vm/ObjectImpl.h" #include "jsatominlines.h" +#include "jsobjinlines.h" #include "gc/Barrier-inl.h" #include "gc/Marking.h" @@ -247,6 +248,24 @@ js::ObjectImpl::checkShapeConsistency() } #endif +void +js::ObjectImpl::initializeSlotRange(uint32_t start, uint32_t length) +{ + /* + * No bounds check, as this is used when the object's shape does not + * reflect its allocated slots (updateSlotsForSpan). + */ + HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; + getSlotRangeUnchecked(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd); + + JSRuntime *rt = runtime(); + uint32_t offset = start; + for (HeapSlot *sp = fixedStart; sp < fixedEnd; sp++) + sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue()); + for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++) + sp->init(rt, this->asObjectPtr(), HeapSlot::Slot, offset++, UndefinedValue()); +} + void js::ObjectImpl::initSlotRange(uint32_t start, const Value *vector, uint32_t length) { diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index 1e8dd9b41256..7d58b3855d42 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -1251,7 +1251,7 @@ class ObjectImpl : public gc::Cell friend class NewObjectCache; inline void invalidateSlotRange(uint32_t start, uint32_t count); - inline void initializeSlotRange(uint32_t start, uint32_t count); + void initializeSlotRange(uint32_t start, uint32_t count); /* * Initialize a flat array of slots to this object at a start slot. The @@ -1372,7 +1372,9 @@ class ObjectImpl : public gc::Cell inline bool nativeContainsPure(Shape* shape); inline JSClass *getJSClass() const; - inline bool hasClass(const Class *c) const; + inline bool hasClass(const Class *c) const { + return getClass() == c; + } inline const ObjectOps *getOps() const; /* @@ -1509,17 +1511,33 @@ class ObjectImpl : public gc::Cell /* Private data accessors. */ - inline void *&privateRef(uint32_t nfixed) const; /* XXX should be private, not protected! */ + inline void *&privateRef(uint32_t nfixed) const { /* XXX should be private, not protected! */ + /* + * The private pointer of an object can hold any word sized value. + * Private pointers are stored immediately after the last fixed slot of + * the object. + */ + MOZ_ASSERT(nfixed == numFixedSlots()); + MOZ_ASSERT(hasPrivate()); + HeapSlot *end = &fixedSlots()[nfixed]; + return *reinterpret_cast(end); + } - inline bool hasPrivate() const; - inline void *getPrivate() const; + inline bool hasPrivate() const { + return getClass()->hasPrivate(); + } + inline void *getPrivate() const { + return privateRef(numFixedSlots()); + } inline void setPrivate(void *data); inline void setPrivateGCThing(gc::Cell *cell); inline void setPrivateUnbarriered(void *data); inline void initPrivate(void *data); /* Access private data for an object with a known number of fixed slots. */ - inline void *getPrivate(uint32_t nfixed) const; + inline void *getPrivate(uint32_t nfixed) const { + return privateRef(nfixed); + } /* JIT Accessors */ static size_t offsetOfShape() { return offsetof(ObjectImpl, shape_); } diff --git a/js/src/vm/RegExpObject-inl.h b/js/src/vm/RegExpObject-inl.h index dba31d91f694..7a9fbd8ba255 100644 --- a/js/src/vm/RegExpObject-inl.h +++ b/js/src/vm/RegExpObject-inl.h @@ -11,7 +11,6 @@ #include "RegExpObject.h" -#include "jsobjinlines.h" #include "jsstrinlines.h" #include "String-inl.h" diff --git a/js/src/vm/RegExpStatics-inl.h b/js/src/vm/RegExpStatics-inl.h index 56ad17d3efe0..c3311e825f18 100644 --- a/js/src/vm/RegExpStatics-inl.h +++ b/js/src/vm/RegExpStatics-inl.h @@ -7,9 +7,12 @@ #ifndef RegExpStatics_inl_h__ #define RegExpStatics_inl_h__ -#include "RegExpStatics.h" +#include "vm/RegExpStatics.h" #include "gc/Marking.h" + +#include "jsinferinlines.h" + #include "vm/String-inl.h" namespace js { diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 3ec25d429e9e..0e59b38d14b1 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -17,7 +17,8 @@ #include "jsatominlines.h" #include "jsobjinlines.h" -#include "ScopeObject-inl.h" +#include "gc/Barrier-inl.h" +#include "vm/ScopeObject-inl.h" using namespace js; using namespace js::types; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index a3f7798046d8..20addd06ae27 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -341,15 +341,26 @@ js::intrinsic_NewDenseArray(JSContext *cx, unsigned argc, Value *vp) /* * UnsafeSetElement(arr0, idx0, elem0, ..., arrN, idxN, elemN): For * each set of (arr, idx, elem) arguments that are passed, performs - * the assignment |arr[idx] = elem|. |arr| must be either a dense array + * the assignment `arr[idx] = elem`. `arr` must be either a dense array * or a typed array. * - * If |arr| is a dense array, the index must be an int32 less than the - * initialized length of |arr|. Use |%EnsureDenseResultArrayElements| - * to ensure that the initialized length is long enough. + * If `arr` is a dense array, the index must be an int32 less than the + * initialized length of `arr`. Use `NewDenseAllocatedArray` to ensure + * that the initialized length is long enough. * - * If |arr| is a typed array, the index must be an int32 less than the - * length of |arr|. + * If `arr` is a typed array, the index must be an int32 less than the + * length of `arr`. + * + * The reason that `UnsafeSetElement` takes multiple + * array/index/element triples is not for convenience but rather for + * semantic reasons: there are a few places in the parallel code where + * correctness relies on the fact that *all of the assignments occur + * or none of them*. This occurs in operations like reduce or fold + * which mutate the same data in place. That is, we do not want to + * bail out or interrupt in between the individual assignments. To + * convey this notion, we place all the assignments together into one + * `UnsafeSetElement` call. It is preferable to use multiple calls if + * it is not important that the assignments occur all-or-nothing. */ JSBool js::intrinsic_UnsafeSetElement(JSContext *cx, unsigned argc, Value *vp) @@ -380,7 +391,6 @@ js::intrinsic_UnsafeSetElement(JSContext *cx, unsigned argc, Value *vp) } else { JS_ASSERT(idx < TypedArray::length(arrobj)); RootedValue tmp(cx, args[elemi]); - // XXX: Always non-strict. if (!JSObject::setElement(cx, arrobj, arrobj, idx, &tmp, false)) return false; } @@ -390,6 +400,46 @@ js::intrinsic_UnsafeSetElement(JSContext *cx, unsigned argc, Value *vp) return true; } +/* + * UnsafeGetElement(arr, idx)=elem: + * + * Loads an element from an array. Requires that `arr` be a dense + * array and `idx` be in bounds. In ion compiled code, no bounds + * check will be emitted. + */ +JSBool +js::intrinsic_UnsafeGetElement(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + const uint32_t arri = 0; + const uint32_t idxi = 1; + + JS_ASSERT(args[arri].isObject()); + JS_ASSERT(args[idxi].isInt32()); + + RootedObject arrobj(cx, &args[arri].toObject()); + uint32_t idx = args[idxi].toInt32(); + + JS_ASSERT(args[arri].toObject().isNative()); + JS_ASSERT(idx < arrobj->getDenseInitializedLength()); + args.rval().set(arrobj->getDenseElement(idx)); + return true; +} + +/* + * UnsafeGetImmutableElement(arr, idx)=elem: + * + * Same as `UnsafeGetElement(arr, idx)`, except that the array is + * known by the self-hosting code to be immutable. Therefore, ion + * compilation can reorder this load freely with respect to stores. + */ +JSBool +js::intrinsic_UnsafeGetImmutableElement(JSContext *cx, unsigned argc, Value *vp) +{ + return intrinsic_UnsafeGetElement(cx, argc, vp); +} + /* * ParallelTestsShouldPass(): Returns false if we are running in a * mode (such as --ion-eager) that is known to cause additional @@ -468,6 +518,8 @@ const JSFunctionSpec intrinsic_functions[] = { JS_FN("NewParallelArray", intrinsic_NewParallelArray, 3,0), JS_FN("NewDenseArray", intrinsic_NewDenseArray, 1,0), JS_FN("UnsafeSetElement", intrinsic_UnsafeSetElement, 3,0), + JS_FN("UnsafeGetElement", intrinsic_UnsafeGetElement, 2,0), + JS_FN("UnsafeGetImmutableElement", intrinsic_UnsafeGetImmutableElement, 2,0), JS_FN("ShouldForceSequential", intrinsic_ShouldForceSequential, 0,0), JS_FN("ParallelTestsShouldPass", intrinsic_ParallelTestsShouldPass, 0,0), diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 8681fde27779..0d55fe13945a 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -22,9 +22,9 @@ #include "vm/ScopeObject.h" #include "vm/StringObject.h" +#include "jsatominlines.h" #include "jscntxtinlines.h" #include "jsgcinlines.h" -#include "jsobjinlines.h" #include "vm/ScopeObject-inl.h" diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 191f01328e6d..1e8562961e69 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -441,19 +441,6 @@ AbstractFramePtr::setReturnValue(const Value &rval) const #endif } -inline bool -AbstractFramePtr::hasPushedSPSFrame() const -{ - if (isStackFrame()) - return asStackFrame()->hasPushedSPSFrame(); -#ifdef JS_ION - return asBaselineFrame()->hasPushedSPSFrame(); -#else - JS_NOT_REACHED("Invalid frame"); - return false; -#endif -} - inline JSObject * AbstractFramePtr::scopeChain() const { diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index fc5c77484ee2..bffdaa8ae884 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -4,22 +4,24 @@ * 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/Stack.h" + #include "mozilla/DebugOnly.h" #include "mozilla/PodOperations.h" #include "jscntxt.h" #include "jsopcode.h" + #include "gc/Marking.h" #ifdef JS_ION #include "ion/BaselineFrame.h" #include "ion/IonFrames.h" #include "ion/IonCompartment.h" #endif -#include "vm/Stack.h" #include "vm/ForkJoin.h" #include "jsgcinlines.h" -#include "jsobjinlines.h" + #include "vm/Interpreter-inl.h" #include "vm/Stack-inl.h" #include "vm/Probes-inl.h" @@ -1826,6 +1828,19 @@ AbstractFramePtr::evalPrevScopeChain(JSContext *cx) const return iter.scopeChain(); } +bool +AbstractFramePtr::hasPushedSPSFrame() const +{ + if (isStackFrame()) + return asStackFrame()->hasPushedSPSFrame(); +#ifdef JS_ION + return asBaselineFrame()->hasPushedSPSFrame(); +#else + JS_NOT_REACHED("Invalid frame"); + return false; +#endif +} + #ifdef DEBUG void js::CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index cf2a06396df8..2acbc1b2fd8e 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -233,7 +233,7 @@ class AbstractFramePtr inline Value returnValue() const; inline void setReturnValue(const Value &rval) const; - inline bool hasPushedSPSFrame() const; + bool hasPushedSPSFrame() const; inline void popBlock(JSContext *cx) const; inline void popWith(JSContext *cx) const; diff --git a/js/src/vm/String-inl.h b/js/src/vm/String-inl.h index 3151bf8036e4..9feb52f18b36 100644 --- a/js/src/vm/String-inl.h +++ b/js/src/vm/String-inl.h @@ -15,7 +15,6 @@ #include "gc/Marking.h" #include "jsgcinlines.h" -#include "jsobjinlines.h" namespace js { diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp index fbb622588149..34de8b730a0e 100644 --- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -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/. */ +#include "vm/String.h" + #include "mozilla/PodOperations.h" #include "mozilla/RangedPtr.h" #include "gc/Marking.h" -#include "String.h" -#include "String-inl.h" +#include "jscompartmentinlines.h" -#include "jsobjinlines.h" +#include "String-inl.h" using namespace js; diff --git a/js/src/vm/StringObject-inl.h b/js/src/vm/StringObject-inl.h index 2dd4c70d9c47..852cdb76067b 100644 --- a/js/src/vm/StringObject-inl.h +++ b/js/src/vm/StringObject-inl.h @@ -9,6 +9,8 @@ #include "StringObject.h" +#include "jsobjinlines.h" + namespace js { inline bool diff --git a/js/src/vm/Xdr.cpp b/js/src/vm/Xdr.cpp index 73620f83ba9a..f32266d66b61 100644 --- a/js/src/vm/Xdr.cpp +++ b/js/src/vm/Xdr.cpp @@ -19,10 +19,10 @@ #include "jsscript.h" #include "jsstr.h" -#include "Xdr.h" -#include "Debugger.h" +#include "vm/Xdr.h" +#include "vm/Debugger.h" -#include "jsobjinlines.h" +#include "jsscriptinlines.h" using namespace js; @@ -139,6 +139,24 @@ XDRState::codeScript(MutableHandleScript scriptp) return true; } +template +void +XDRState::initScriptPrincipals(JSScript *script) +{ + JS_ASSERT(mode == XDR_DECODE); + + /* The origin principals must be normalized at this point. */ + JS_ASSERT_IF(principals, originPrincipals); + JS_ASSERT(!script->originPrincipals); + if (principals) + JS_ASSERT(script->principals() == principals); + + if (originPrincipals) { + script->originPrincipals = originPrincipals; + JS_HoldPrincipals(originPrincipals); + } +} + XDRDecoder::XDRDecoder(JSContext *cx, const void *data, uint32_t length, JSPrincipals *principals, JSPrincipals *originPrincipals) : XDRState(cx) diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 595d4146aa46..b34a66e9bad4 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -211,20 +211,7 @@ class XDRState { bool codeFunction(JS::MutableHandleObject objp); bool codeScript(MutableHandleScript scriptp); - void initScriptPrincipals(JSScript *script) { - JS_ASSERT(mode == XDR_DECODE); - - /* The origin principals must be normalized at this point. */ - JS_ASSERT_IF(principals, originPrincipals); - JS_ASSERT(!script->originPrincipals); - if (principals) - JS_ASSERT(script->principals() == principals); - - if (originPrincipals) { - script->originPrincipals = originPrincipals; - JS_HoldPrincipals(originPrincipals); - } - } + void initScriptPrincipals(JSScript *script); }; class XDREncoder : public XDRState { diff --git a/js/xpconnect/src/XPCCallContext.cpp b/js/xpconnect/src/XPCCallContext.cpp index ca20ff70711b..44b3d0c0a705 100644 --- a/js/xpconnect/src/XPCCallContext.cpp +++ b/js/xpconnect/src/XPCCallContext.cpp @@ -98,11 +98,8 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, } } else { js::Class *clasp = js::GetObjectClass(unwrapped); - if (IS_WRAPPER_CLASS(clasp)) { - if (IS_SLIM_WRAPPER_OBJECT(unwrapped)) - mFlattenedJSObject = unwrapped; - else - mWrapper = XPCWrappedNative::Get(unwrapped); + if (IS_WN_CLASS(clasp)) { + mWrapper = XPCWrappedNative::Get(unwrapped); } else if (IS_TEAROFF_CLASS(clasp)) { mTearOff = (XPCWrappedNativeTearOff*)js::GetObjectPrivate(unwrapped); mWrapper = XPCWrappedNative::Get(js::GetObjectParent(unwrapped)); @@ -116,8 +113,7 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, else mScriptableInfo = mWrapper->GetScriptableInfo(); } else { - NS_ABORT_IF_FALSE(!mFlattenedJSObject || IS_SLIM_WRAPPER(mFlattenedJSObject), - "should have a slim wrapper"); + NS_ABORT_IF_FALSE(!mFlattenedJSObject, "What object do we have?"); } if (!JSID_IS_VOID(name)) @@ -425,8 +421,7 @@ XPCCallContext::UnwrapThisIfAllowed(HandleObject obj, HandleObject fun, unsigned MOZ_ASSERT(unwrapped == JS_ObjectToInnerObject(mJSContext, js::Wrapper::wrappedObject(obj))); // Make sure we have an XPCWN, and grab it. - MOZ_ASSERT(!IS_SLIM_WRAPPER(unwrapped), "security wrapping morphs slim wrappers"); - if (!IS_WRAPPER_CLASS(js::GetObjectClass(unwrapped))) + if (!IS_WN_REFLECTOR(unwrapped)) return nullptr; XPCWrappedNative *wn = (XPCWrappedNative*)js::GetObjectPrivate(unwrapped); diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index c9c4b2b7525b..21a477a64624 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -2684,10 +2684,6 @@ nsXPCComponents_Utils::LookupMethod(const JS::Value& object, // Enter the target compartment. JSAutoCompartment ac(cx, obj); - // Morph slim wrappers. - if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) - return NS_ERROR_FAILURE; - // Now, try to create an Xray wrapper around the object. This won't work // if the object isn't Xray-able. In that case, we throw. JSObject *xray = WrapperFactory::WrapForSameCompartmentXray(cx, obj); @@ -3316,7 +3312,7 @@ xpc_CreateSandboxObject(JSContext *cx, jsval *vp, nsISupports *prinOrSop, Sandbo // Now check what sort of thing we've got in |proto| JSObject *unwrappedProto = js::UncheckedUnwrap(options.proto, false); js::Class *unwrappedClass = js::GetObjectClass(unwrappedProto); - if (IS_WRAPPER_CLASS(unwrappedClass) || + if (IS_WN_CLASS(unwrappedClass) || mozilla::dom::IsDOMClass(Jsvalify(unwrappedClass))) { // Wrap it up in a proxy that will do the right thing in terms // of this-binding for methods. diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index 4e90d835dd5c..f1ce4953544e 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -819,7 +819,6 @@ XPCConvert::NativeInterface2JSObject(jsval* d, // object will create (and fill the cache) from its WrapObject call. nsWrapperCache *cache = aHelper.GetWrapperCache(); - bool tryConstructSlimWrapper = false; RootedObject flat(cx); if (cache) { flat = cache->GetWrapper(); @@ -839,40 +838,10 @@ XPCConvert::NativeInterface2JSObject(jsval* d, return CreateHolderIfNeeded(flat, d, dest); } } - - if (!dest) { - if (!flat) { - tryConstructSlimWrapper = true; - } else if (IS_SLIM_WRAPPER_OBJECT(flat)) { - if (js::IsObjectInContextCompartment(flat, cx)) { - *d = OBJECT_TO_JSVAL(flat); - return true; - } - } - } } else { flat = nullptr; } - // If we're not handing this wrapper to an nsIXPConnectJSObjectHolder, and - // the object supports slim wrappers, try to create one here. - if (tryConstructSlimWrapper) { - RootedValue slim(cx); - if (ConstructSlimWrapper(aHelper, xpcscope, &slim)) { - *d = slim; - return true; - } - - if (JS_IsExceptionPending(cx)) - return false; - - // Even if ConstructSlimWrapper returns false it might have created a - // wrapper (while calling the PreCreate hook). In that case we need to - // fall through because we either have a slim wrapper that needs to be - // morphed or an XPCWrappedNative. - flat = cache->GetWrapper(); - } - // We can't simply construct a slim wrapper. Go ahead and create an // XPCWrappedNative for this object. At this point, |flat| could be // non-null, meaning that either we already have a wrapped native from @@ -893,8 +862,7 @@ XPCConvert::NativeInterface2JSObject(jsval* d, } } - NS_ASSERTION(!flat || IS_WRAPPER_CLASS(js::GetObjectClass(flat)), - "What kind of wrapper is this?"); + NS_ASSERTION(!flat || IS_WN_REFLECTOR(flat), "What kind of wrapper is this?"); nsresult rv; XPCWrappedNative* wrapper; @@ -904,7 +872,9 @@ XPCConvert::NativeInterface2JSObject(jsval* d, getter_AddRefs(strongWrapper)); wrapper = strongWrapper; - } else if (IS_WN_WRAPPER_OBJECT(flat)) { + } else { + MOZ_ASSERT(IS_WN_REFLECTOR(flat)); + wrapper = static_cast(xpc_GetJSPrivate(flat)); // If asked to return the wrapper we'll return a strong reference, @@ -916,17 +886,6 @@ XPCConvert::NativeInterface2JSObject(jsval* d, wrapper->FindTearOff(iface, false, &rv); else rv = NS_OK; - } else { - NS_ASSERTION(IS_SLIM_WRAPPER(flat), - "What kind of wrapper is this?"); - - SLIM_LOG(("***** morphing from XPCConvert::NativeInterface2JSObject" - "(%p)\n", - static_cast(xpc_GetJSPrivate(flat)))); - - rv = XPCWrappedNative::Morph(flat, iface, cache, - getter_AddRefs(strongWrapper)); - wrapper = strongWrapper; } if (NS_FAILED(rv) && pErr) @@ -1025,7 +984,7 @@ XPCConvert::JSObject2NativeInterface(void** dest, HandleObject src, // Is this really a native xpcom object with a wrapper? XPCWrappedNative* wrappedNative = nullptr; - if (IS_WN_WRAPPER(inner)) + if (IS_WN_REFLECTOR(inner)) wrappedNative = XPCWrappedNative::Get(inner); if (wrappedNative) { iface = wrappedNative->GetIdentityObject(); @@ -1156,8 +1115,8 @@ XPCConvert::JSValToXPCException(jsval sArg, JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); if (!unwrapped) return NS_ERROR_XPC_SECURITY_MANAGER_VETO; - XPCWrappedNative* wrapper = IS_WN_WRAPPER(unwrapped) ? XPCWrappedNative::Get(unwrapped) - : nullptr; + XPCWrappedNative* wrapper = IS_WN_REFLECTOR(unwrapped) ? XPCWrappedNative::Get(unwrapped) + : nullptr; if (wrapper) { nsISupports* supports = wrapper->GetIdentityObject(); nsCOMPtr iface = do_QueryInterface(supports); diff --git a/js/xpconnect/src/XPCInlines.h b/js/xpconnect/src/XPCInlines.h index c17dec24cf23..30a303b9aabb 100644 --- a/js/xpconnect/src/XPCInlines.h +++ b/js/xpconnect/src/XPCInlines.h @@ -121,9 +121,7 @@ inline XPCWrappedNativeProto* XPCCallContext::GetProto() const { CHECK_STATE(HAVE_OBJECT); - if (mWrapper) - return mWrapper->GetProto(); - return mFlattenedJSObject ? GetSlimWrapperProto(mFlattenedJSObject) : nullptr; + return mWrapper ? mWrapper->GetProto() : nullptr; } inline JSBool diff --git a/js/xpconnect/src/XPCJSID.cpp b/js/xpconnect/src/XPCJSID.cpp index 175731354f38..8c7d59807fda 100644 --- a/js/xpconnect/src/XPCJSID.cpp +++ b/js/xpconnect/src/XPCJSID.cpp @@ -470,14 +470,13 @@ nsJSIID::Enumerate(nsIXPConnectWrappedNative *wrapper, * there's chrome code that relies on this. * * This static method handles both complexities, returning either an XPCWN, a - * slim wrapper, a DOM object, or null. The object may well be cross-compartment - * from |cx|. + * DOM object, or null. The object may well be cross-compartment from |cx|. */ static JSObject * FindObjectForHasInstance(JSContext *cx, HandleObject objArg) { RootedObject obj(cx, objArg), proto(cx); - while (obj && !IS_WRAPPER_CLASS(js::GetObjectClass(obj)) && !IsDOMObject(obj)) { + while (obj && !IS_WN_REFLECTOR(obj) && !IsDOMObject(obj)) { if (js::IsWrapper(obj)) { obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); continue; @@ -505,7 +504,6 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper, NS_ASSERTION(obj, "when is an object not an object?"); - nsISupports *identity = nullptr; // is this really a native xpcom object with a wrapper? const nsIID* iid; mInfo->GetIIDShared(&iid); @@ -514,33 +512,19 @@ nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper, if (!obj) return NS_OK; - if (IS_SLIM_WRAPPER(obj)) { - XPCWrappedNativeProto* proto = GetSlimWrapperProto(obj); - if (proto->GetSet()->HasInterfaceWithAncestor(iid)) { - *bp = true; + if (IsDOMObject(obj)) { + // Not all DOM objects implement nsISupports. But if they don't, + // there's nothing to do in this HasInstance hook. + nsISupports *identity = UnwrapDOMObjectToISupports(obj); + if (!identity) return NS_OK; - } - -#ifdef DEBUG_slimwrappers - char foo[NSID_LENGTH]; - iid->ToProvidedString(foo); - SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, foo); -#endif - if (!MorphSlimWrapper(cx, obj)) - return NS_ERROR_FAILURE; - } else if (IsDOMObject(obj)) { - // Not all DOM objects implement nsISupports. But if they don't, - // there's nothing to do in this HasInstance hook. - identity = UnwrapDOMObjectToISupports(obj); - if (!identity) - return NS_OK; - nsCOMPtr supp; - identity->QueryInterface(*iid, getter_AddRefs(supp)); - *bp = supp; - return NS_OK; + nsCOMPtr supp; + identity->QueryInterface(*iid, getter_AddRefs(supp)); + *bp = supp; + return NS_OK; } - MOZ_ASSERT(IS_WN_WRAPPER(obj)); + MOZ_ASSERT(IS_WN_REFLECTOR(obj)); XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj); if (!other_wrapper) return NS_OK; @@ -857,11 +841,9 @@ nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper, // is this really a native xpcom object with a wrapper? nsIClassInfo* ci = nullptr; obj = FindObjectForHasInstance(cx, obj); - if (!obj || !IS_WRAPPER_CLASS(js::GetObjectClass(obj))) + if (!obj || !IS_WN_REFLECTOR(obj)) return rv; - if (IS_SLIM_WRAPPER_OBJECT(obj)) - ci = GetSlimWrapperProto(obj)->GetClassInfo(); - else if (XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj)) + if (XPCWrappedNative* other_wrapper = XPCWrappedNative::Get(obj)) ci = other_wrapper->GetClassInfo(); // We consider CID equality to be the thing that matters here. @@ -911,7 +893,7 @@ xpc_JSObjectToID(JSContext *cx, JSObject* obj) // NOTE: this call does NOT addref XPCWrappedNative* wrapper = nullptr; obj = js::CheckedUnwrap(obj); - if (obj && IS_WN_WRAPPER(obj)) + if (obj && IS_WN_REFLECTOR(obj)) wrapper = XPCWrappedNative::Get(obj); if (wrapper && (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) || @@ -929,7 +911,7 @@ xpc_JSObjectIsID(JSContext *cx, JSObject* obj) // NOTE: this call does NOT addref XPCWrappedNative* wrapper = nullptr; obj = js::CheckedUnwrap(obj); - if (obj && IS_WN_WRAPPER(obj)) + if (obj && IS_WN_REFLECTOR(obj)) wrapper = XPCWrappedNative::Get(obj); return wrapper && (wrapper->HasInterfaceNoQI(NS_GET_IID(nsIJSID)) || diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index cd3e312f7845..4b83e0fe56ed 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -2537,14 +2537,10 @@ PreserveWrapper(JSContext *cx, JSObject *objArg) if (!ccx.IsValid()) return false; - if (!IS_WRAPPER_CLASS(js::GetObjectClass(obj))) + if (!IS_WN_REFLECTOR(obj)) return mozilla::dom::TryPreserveWrapper(obj); - nsISupports *supports = nullptr; - if (IS_WN_WRAPPER_OBJECT(obj)) - supports = XPCWrappedNative::Get(obj)->Native(); - else - supports = static_cast(xpc_GetJSPrivate(obj)); + nsISupports *supports = XPCWrappedNative::Get(obj)->Native(); // For pre-Paris DOM bindings objects, we only support Node. if (nsCOMPtr node = do_QueryInterface(supports)) { diff --git a/js/xpconnect/src/XPCLog.cpp b/js/xpconnect/src/XPCLog.cpp index eebe50fb98c8..c659183dc9c0 100644 --- a/js/xpconnect/src/XPCLog.cpp +++ b/js/xpconnect/src/XPCLog.cpp @@ -90,36 +90,3 @@ XPC_Log_Clear_Indent() } #endif - -#ifdef DEBUG_slimwrappers -void -LogSlimWrapperWillMorph(JSContext *cx, JSObject *obj, const char *propname, - const char *functionName) -{ - if (obj && IS_SLIM_WRAPPER(obj)) { - XPCNativeScriptableInfo *si = - GetSlimWrapperProto(obj)->GetScriptableInfo(); - printf("***** morphing %s from %s", si->GetJSClass()->name, - functionName); - if (propname) - printf(" for %s", propname); - printf(" (%p, %p)\n", obj, - static_cast(xpc_GetJSPrivate(obj))); - xpc_DumpJSStack(cx, false, false, false); - } -} - -void -LogSlimWrapperNotCreated(JSContext *cx, nsISupports *obj, const char *reason) -{ - char* className = nullptr; - nsCOMPtr ci = do_QueryInterface(obj); - if (ci) - ci->GetClassDescription(&className); - printf("***** refusing to create slim wrapper%s%s, reason: %s (%p)\n", - className ? " for " : "", className ? className : "", reason, obj); - if (className) - PR_Free(className); - xpc_DumpJSStack(cx, false, false, false); -} -#endif diff --git a/js/xpconnect/src/XPCLog.h b/js/xpconnect/src/XPCLog.h index 42b8c08ec999..7bf52900ae58 100644 --- a/js/xpconnect/src/XPCLog.h +++ b/js/xpconnect/src/XPCLog.h @@ -64,58 +64,4 @@ JS_END_EXTERN_C #define XPC_LOG_FINISH() ((void)0) #endif - -#ifdef DEBUG_peterv -#define DEBUG_slimwrappers 1 -#endif - -#ifdef DEBUG_slimwrappers -extern void LogSlimWrapperWillMorph(JSContext *cx, JSObject *obj, - const char *propname, - const char *functionName); -extern void LogSlimWrapperNotCreated(JSContext *cx, nsISupports *obj, - const char *reason); - -#define SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, prop) \ - PR_BEGIN_MACRO \ - LogSlimWrapperWillMorph(cx, obj, (const char*)prop, __FUNCTION__); \ - PR_END_MACRO -#define SLIM_LOG_WILL_MORPH_FOR_ID(cx, obj, id) \ - PR_BEGIN_MACRO \ - JSString* strId = ::JS_ValueToString(cx, id); \ - if (strId) { \ - NS_ConvertUTF16toUTF8 name((PRUnichar*)::JS_GetStringChars(strId), \ - ::JS_GetStringLength(strId)); \ - LOG_WILL_MORPH_FOR_PROP(cx, obj, name.get()); \ - } \ - else \ - { \ - LOG_WILL_MORPH_FOR_PROP(cx, obj, nullptr); \ - } \ - PR_END_MACRO -#define SLIM_LOG_NOT_CREATED(cx, obj, reason) \ - PR_BEGIN_MACRO \ - LogSlimWrapperNotCreated(cx, obj, reason); \ - PR_END_MACRO -#define SLIM_LOG(_args) \ - PR_BEGIN_MACRO \ - printf _args; \ - PR_END_MACRO -#else -#define SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, prop) \ - PR_BEGIN_MACRO \ - PR_END_MACRO -#define SLIM_LOG_WILL_MORPH_FOR_ID(cx, obj) \ - PR_BEGIN_MACRO \ - PR_END_MACRO -#define SLIM_LOG_NOT_CREATED(cx, obj, reason) \ - PR_BEGIN_MACRO \ - PR_END_MACRO -#define SLIM_LOG(_args) \ - PR_BEGIN_MACRO \ - PR_END_MACRO -#endif -#define SLIM_LOG_WILL_MORPH(cx, obj) \ - SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, nullptr) - #endif /* xpclog_h___ */ diff --git a/js/xpconnect/src/XPCQuickStubs.cpp b/js/xpconnect/src/XPCQuickStubs.cpp index 924b95f33b6d..4599e9be9397 100644 --- a/js/xpconnect/src/XPCQuickStubs.cpp +++ b/js/xpconnect/src/XPCQuickStubs.cpp @@ -69,7 +69,7 @@ LookupInterfaceOrAncestor(uint32_t tableSize, const xpc_qsHashEntry *table, static MOZ_ALWAYS_INLINE bool HasBitInInterfacesBitmap(JSObject *obj, uint32_t interfaceBit) { - NS_ASSERTION(IS_WRAPPER_CLASS(js::GetObjectClass(obj)), "Not a wrapper?"); + NS_ASSERTION(IS_WN_REFLECTOR(obj), "Not a wrapper?"); XPCWrappedNativeJSClass *clasp = (XPCWrappedNativeJSClass*)js::GetObjectClass(obj); @@ -178,16 +178,10 @@ GetMemberInfo(JSObject *obj, jsid memberId, const char **ifaceName) // because it isn't worth the risk of something going wrong just to generate // an error message. Instead, only handle the simple case where we have the // reflector in hand. - if (IS_WRAPPER_CLASS(js::GetObjectClass(obj))) { - XPCWrappedNativeProto *proto; - if (IS_SLIM_WRAPPER_OBJECT(obj)) { - proto = GetSlimWrapperProto(obj); - } else { - MOZ_ASSERT(IS_WN_WRAPPER_OBJECT(obj)); - XPCWrappedNative *wrapper = - static_cast(js::GetObjectPrivate(obj)); - proto = wrapper->GetProto(); - } + if (IS_WN_REFLECTOR(obj)) { + XPCWrappedNative *wrapper = + static_cast(js::GetObjectPrivate(obj)); + XPCWrappedNativeProto *proto = wrapper->GetProto(); if (proto) { XPCNativeSet *set = proto->GetSet(); if (set) { @@ -565,14 +559,10 @@ getWrapper(JSContext *cx, obj = js::GetObjectParent(obj); } - // If we've got a WN or slim wrapper, store things the way callers expect. - // Otherwise, leave things null and return. - if (IS_WRAPPER_CLASS(clasp)) { - if (IS_WN_WRAPPER_OBJECT(obj)) - *wrapper = (XPCWrappedNative*) js::GetObjectPrivate(obj); - else - *cur = obj; - } + // If we've got a WN, store things the way callers expect. Otherwise, leave + // things null and return. + if (IS_WN_CLASS(clasp)) + *wrapper = XPCWrappedNative::Get(obj); return NS_OK; } @@ -597,12 +587,8 @@ castNative(JSContext *cx, } else if (cur) { nsISupports *native; if (!(native = mozilla::dom::UnwrapDOMObjectToISupports(cur))) { - if (IS_SLIM_WRAPPER(cur)) { - native = static_cast(xpc_GetJSPrivate(cur)); - } else { - *pThisRef = nullptr; - return NS_ERROR_ILLEGAL_VALUE; - } + *pThisRef = nullptr; + return NS_ERROR_ILLEGAL_VALUE; } if (NS_SUCCEEDED(getNative(native, cur, iid, ppThis, pThisRef, vp))) { @@ -628,11 +614,9 @@ castNativeFromWrapper(JSContext *cx, XPCWrappedNativeTearOff *tearoff; JSObject *cur; - if (IS_WRAPPER_CLASS(js::GetObjectClass(obj))) { + if (IS_WN_REFLECTOR(obj)) { cur = obj; - wrapper = IS_WN_WRAPPER_OBJECT(cur) ? - (XPCWrappedNative*)xpc_GetJSPrivate(obj) : - nullptr; + wrapper = (XPCWrappedNative*)xpc_GetJSPrivate(obj); tearoff = nullptr; } else { *rv = getWrapper(cx, obj, &wrapper, &cur, &tearoff); @@ -647,11 +631,6 @@ castNativeFromWrapper(JSContext *cx, if (!native || !HasBitInInterfacesBitmap(cur, interfaceBit)) { native = nullptr; } - } else if (cur && IS_SLIM_WRAPPER(cur)) { - native = static_cast(xpc_GetJSPrivate(cur)); - if (!native || !HasBitInInterfacesBitmap(cur, interfaceBit)) { - native = nullptr; - } } else if (cur && protoDepth >= 0) { const mozilla::dom::DOMClass* domClass = mozilla::dom::GetDOMClass(cur); diff --git a/js/xpconnect/src/XPCVariant.cpp b/js/xpconnect/src/XPCVariant.cpp index 25de5166df89..814aa52c80e3 100644 --- a/js/xpconnect/src/XPCVariant.cpp +++ b/js/xpconnect/src/XPCVariant.cpp @@ -45,7 +45,7 @@ XPCVariant::XPCVariant(JSContext* cx, jsval aJSVal) mJSVal = OBJECT_TO_JSVAL(obj); JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); - mReturnRawObject = !(unwrapped && IS_WN_WRAPPER(unwrapped)); + mReturnRawObject = !(unwrapped && IS_WN_REFLECTOR(unwrapped)); } else mReturnRawObject = false; } diff --git a/js/xpconnect/src/XPCWrappedJSClass.cpp b/js/xpconnect/src/XPCWrappedJSClass.cpp index 54f8afb19cbd..21588f80ce03 100644 --- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -699,8 +699,7 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self, bool isSystem; rv = secMan->IsSystemPrincipal(objPrin, &isSystem); - if ((NS_FAILED(rv) || !isSystem) && - !IS_WRAPPER_CLASS(js::GetObjectClass(selfObj))) { + if ((NS_FAILED(rv) || !isSystem) && !IS_WN_REFLECTOR(selfObj)) { // A content object. nsRefPtr checked = new SameOriginCheckedComponent(self); diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index cf62f09bec81..4b60dd7c8677 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -36,7 +36,7 @@ bool xpc_OkToHandOutWrapper(nsWrapperCache *cache) { NS_ABORT_IF_FALSE(cache->GetWrapper(), "Must have wrapper"); - NS_ABORT_IF_FALSE(IS_WN_WRAPPER(cache->GetWrapper()), + NS_ABORT_IF_FALSE(IS_WN_REFLECTOR(cache->GetWrapper()), "Must have XPCWrappedNative wrapper"); return !static_cast(xpc_GetJSPrivate(cache->GetWrapper()))-> @@ -532,15 +532,8 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper, if (cache) { RootedObject cached(cx, cache->GetWrapper()); - if (cached) { - if (IS_SLIM_WRAPPER_OBJECT(cached)) { - if (NS_FAILED(XPCWrappedNative::Morph(cached, - Interface, cache, getter_AddRefs(wrapper)))) - return NS_ERROR_FAILURE; - } else { - wrapper = static_cast(xpc_GetJSPrivate(cached)); - } - } + if (cached) + wrapper = static_cast(xpc_GetJSPrivate(cached)); } else { // scoped lock XPCAutoLock lock(mapLock); @@ -711,67 +704,6 @@ FinishCreate(XPCWrappedNativeScope* Scope, return NS_OK; } -// static -nsresult -XPCWrappedNative::Morph(HandleObject existingJSObject, - XPCNativeInterface* Interface, - nsWrapperCache *cache, - XPCWrappedNative** resultWrapper) -{ - AutoJSContext cx; - NS_ASSERTION(IS_SLIM_WRAPPER(existingJSObject), - "Trying to morph a JSObject that's not a slim wrapper?"); - - nsISupports *identity = - static_cast(xpc_GetJSPrivate(existingJSObject)); - XPCWrappedNativeProto *proto = GetSlimWrapperProto(existingJSObject); - -#if DEBUG - // FIXME Can't assert this until - // https://bugzilla.mozilla.org/show_bug.cgi?id=343141 is fixed. -#if 0 - if (proto->GetScriptableInfo()->GetFlags().WantPreCreate()) { - JSObject* parent = JS_GetParent(existingJSObject); - JSObject* plannedParent = parent; - nsresult rv = - proto->GetScriptableInfo()->GetCallback()->PreCreate(identity, ccx, - parent, - &parent); - if (NS_FAILED(rv)) - return rv; - - NS_ASSERTION(parent == plannedParent, - "PreCreate returned a different parent"); - } -#endif -#endif - - nsRefPtr wrapper = new XPCWrappedNative(dont_AddRef(identity), proto); - if (!wrapper) - return NS_ERROR_FAILURE; - - NS_ASSERTION(!xpc::WrapperFactory::IsXrayWrapper(js::GetObjectParent(existingJSObject)), - "Xray wrapper being used to parent XPCWrappedNative?"); - - // We use an AutoMarkingPtr here because it is possible for JS gc to happen - // after we have Init'd the wrapper but *before* we add it to the hashtable. - // This would cause the mSet to get collected and we'd later crash. I've - // *seen* this happen. - AutoMarkingWrappedNativePtr wrapperMarker(cx, wrapper); - - JSAutoCompartment ac(cx, existingJSObject); - if (!wrapper->Init(existingJSObject)) - return NS_ERROR_FAILURE; - - nsresult rv; - if (Interface && !wrapper->FindTearOff(Interface, false, &rv)) { - NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure"); - return rv; - } - - return FinishCreate(wrapper->GetScope(), Interface, cache, wrapper, resultWrapper); -} - // static nsresult XPCWrappedNative::GetUsedOnly(nsISupports* Object, @@ -787,17 +719,11 @@ XPCWrappedNative::GetUsedOnly(nsISupports* Object, CallQueryInterface(Object, &cache); if (cache) { RootedObject flat(cx, cache->GetWrapper()); - if (flat && IS_SLIM_WRAPPER_OBJECT(flat) && !MorphSlimWrapper(cx, flat)) - return NS_ERROR_FAILURE; - - wrapper = flat ? - static_cast(xpc_GetJSPrivate(flat)) : - nullptr; - - if (!wrapper) { + if (!flat) { *resultWrapper = nullptr; return NS_OK; } + wrapper = static_cast(xpc_GetJSPrivate(flat)); NS_ADDREF(wrapper); } else { nsCOMPtr identity = do_QueryInterface(Object); @@ -1067,10 +993,6 @@ XPCWrappedNative::GatherScriptableCreateInfo(nsISupports* obj, return sciProto; } -#ifdef DEBUG_slimwrappers -static uint32_t sMorphedSlimWrappers; -#endif - JSBool XPCWrappedNative::Init(HandleObject parent, const XPCNativeScriptableCreateInfo* sci) @@ -1129,34 +1051,14 @@ XPCWrappedNative::Init(HandleObject parent, return FinishInit(); } -JSBool -XPCWrappedNative::Init(JSObject *existingJSObject) -{ - // Set up the private to point to the WN. - JS_SetPrivate(existingJSObject, this); - - // Officially mark us as non-slim. - MorphMultiSlot(existingJSObject); - - mScriptableInfo = GetProto()->GetScriptableInfo(); - mFlatJSObject = existingJSObject; - - SLIM_LOG(("----- %i morphed slim wrapper (mFlatJSObject: %p, %p)\n", - ++sMorphedSlimWrappers, mFlatJSObject, - static_cast(xpc_GetJSPrivate(mFlatJSObject)))); - - return FinishInit(); -} - JSBool XPCWrappedNative::FinishInit() { AutoJSContext cx; - // For all WNs, we want to make sure that the multislot starts out as null. - // This happens explicitly when morphing a slim wrapper, but we need to - // make sure it happens in the other cases too. - JS_SetReservedSlot(mFlatJSObject, WRAPPER_MULTISLOT, JSVAL_NULL); + // For all WNs, we want to make sure that the expando chain slot starts out + // as null. + JS_SetReservedSlot(mFlatJSObject, WN_XRAYEXPANDOCHAIN_SLOT, JSVAL_NULL); // This reference will be released when mFlatJSObject is finalized. // Since this reference will push the refcount to 2 it will also root @@ -1419,7 +1321,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, CallQueryInterface(aCOMObj, &cache); if (cache) { flat = cache->GetWrapper(); - if (flat && !IS_SLIM_WRAPPER_OBJECT(flat)) { + if (flat) { wrapper = static_cast(xpc_GetJSPrivate(flat)); NS_ASSERTION(wrapper->GetScope() == aOldScope, "Incorrect scope passed"); @@ -1440,8 +1342,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, // ReparentWrapperIfFound is really only meant to be called from DOM code // which must happen only on the main thread. Bail if we're on some other // thread or have a non-main-thread-only wrapper. - if (wrapper && - wrapper->GetProto() && + if (wrapper->GetProto() && !wrapper->GetProto()->ClassIsMainThreadOnly()) { return NS_ERROR_FAILURE; } @@ -1457,14 +1358,9 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, MOZ_ASSERT(js::GetObjectCompartment(aOldScope->GetGlobalJSObject()) != js::GetObjectCompartment(aNewScope->GetGlobalJSObject())); NS_ASSERTION(aNewParent, "won't be able to find the new parent"); - NS_ASSERTION(wrapper, "can't transplant slim wrappers"); - if (!wrapper) - oldProto = GetSlimWrapperProto(flat); - else if (wrapper->HasProto()) + if (wrapper->HasProto()) { oldProto = wrapper->GetProto(); - - if (oldProto) { XPCNativeScriptableInfo *info = oldProto->GetScriptableInfo(); XPCNativeScriptableCreateInfo ci(*info); newProto = @@ -1476,137 +1372,130 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, } } - if (wrapper) { + // First, the clone of the reflector, get a copy of its + // properties and clone its expando chain. The only part that is + // dangerous here if we have to return early is that we must avoid + // ending up with two reflectors pointing to the same WN. Other than + // that, the objects we create will just go away if we return early. - // First, the clone of the reflector, get a copy of its - // properties and clone its expando chain. The only part that is - // dangerous here if we have to return early is that we must avoid - // ending up with two reflectors pointing to the same WN. Other than - // that, the objects we create will just go away if we return early. + RootedObject newobj(cx, JS_CloneObject(cx, flat, + newProto->GetJSProtoObject(), + aNewParent)); + if (!newobj) + return NS_ERROR_FAILURE; - RootedObject newobj(cx, JS_CloneObject(cx, flat, - newProto->GetJSProtoObject(), - aNewParent)); - if (!newobj) + // At this point, both |flat| and |newobj| point to the same wrapped + // native, which is bad, because one of them will end up finalizing + // a wrapped native it does not own. |cloneGuard| ensures that if we + // exit before calling clearing |flat|'s private the private of + // |newobj| will be set to NULL. |flat| will go away soon, because + // we swap it with another object during the transplant and let that + // object die. + RootedObject propertyHolder(cx); + { + AutoClonePrivateGuard cloneGuard(cx, flat, newobj); + + propertyHolder = JS_NewObjectWithGivenProto(cx, NULL, NULL, aNewParent); + if (!propertyHolder) + return NS_ERROR_OUT_OF_MEMORY; + if (!JS_CopyPropertiesFrom(cx, propertyHolder, flat)) return NS_ERROR_FAILURE; - // At this point, both |flat| and |newobj| point to the same wrapped - // native, which is bad, because one of them will end up finalizing - // a wrapped native it does not own. |cloneGuard| ensures that if we - // exit before calling clearing |flat|'s private the private of - // |newobj| will be set to NULL. |flat| will go away soon, because - // we swap it with another object during the transplant and let that - // object die. - RootedObject propertyHolder(cx); - { - AutoClonePrivateGuard cloneGuard(cx, flat, newobj); + // Expandos from other compartments are attached to the target JS object. + // Copy them over, and let the old ones die a natural death. + SetWNExpandoChain(newobj, nullptr); + if (!XrayUtils::CloneExpandoChain(cx, newobj, flat)) + return NS_ERROR_FAILURE; - propertyHolder = JS_NewObjectWithGivenProto(cx, NULL, NULL, aNewParent); - if (!propertyHolder) - return NS_ERROR_OUT_OF_MEMORY; - if (!JS_CopyPropertiesFrom(cx, propertyHolder, flat)) - return NS_ERROR_FAILURE; - - // Expandos from other compartments are attached to the target JS object. - // Copy them over, and let the old ones die a natural death. - SetWNExpandoChain(newobj, nullptr); - if (!XrayUtils::CloneExpandoChain(cx, newobj, flat)) - return NS_ERROR_FAILURE; - - // We've set up |newobj|, so we make it own the WN by nulling out - // the private of |flat|. - // - // NB: It's important to do this _after_ copying the properties to - // propertyHolder. Otherwise, an object with |foo.x === foo| will - // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x. - JS_SetPrivate(flat, nullptr); - } - - // Before proceeding, eagerly create any same-compartment security wrappers - // that the object might have. This forces us to take the 'WithWrapper' path - // while transplanting that handles this stuff correctly. - { - JSAutoCompartment innerAC(cx, aOldScope->GetGlobalJSObject()); - if (!wrapper->GetSameCompartmentSecurityWrapper(cx)) - return NS_ERROR_FAILURE; - } - - // Update scope maps. This section modifies global state, so from - // here on out we crash if anything fails. - { // scoped lock - Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap(); - Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap(); - XPCAutoLock lock(aOldScope->GetRuntime()->GetMapLock()); - - oldMap->Remove(wrapper); - - if (wrapper->HasProto()) - wrapper->SetProto(newProto); - - // If the wrapper has no scriptable or it has a non-shared - // scriptable, then we don't need to mess with it. - // Otherwise... - - if (wrapper->mScriptableInfo && - wrapper->mScriptableInfo == oldProto->GetScriptableInfo()) { - // The new proto had better have the same JSClass stuff as - // the old one! We maintain a runtime wide unique map of - // this stuff. So, if these don't match then the caller is - // doing something bad here. - - NS_ASSERTION(oldProto->GetScriptableInfo()->GetScriptableShared() == - newProto->GetScriptableInfo()->GetScriptableShared(), - "Changing proto is also changing JSObject Classname or " - "helper's nsIXPScriptable flags. This is not allowed!"); - - wrapper->UpdateScriptableInfo(newProto->GetScriptableInfo()); - } - - // Crash if the wrapper is already in the new scope. - if (newMap->Find(wrapper->GetIdentityObject())) - MOZ_CRASH(); - - if (!newMap->Add(wrapper)) - MOZ_CRASH(); - } - - JSObject *ww = wrapper->GetWrapper(); - if (ww) { - JSObject *newwrapper; - MOZ_ASSERT(wrapper->NeedsSOW(), "weird wrapper wrapper"); - newwrapper = xpc::WrapperFactory::WrapSOWObject(cx, newobj); - if (!newwrapper) - MOZ_CRASH(); - - // Ok, now we do the special object-plus-wrapper transplant. - ww = xpc::TransplantObjectWithWrapper(cx, flat, ww, newobj, - newwrapper); - if (!ww) - MOZ_CRASH(); - - flat = newobj; - wrapper->SetWrapper(ww); - } else { - flat = xpc::TransplantObject(cx, flat, newobj); - if (!flat) - MOZ_CRASH(); - } - - wrapper->mFlatJSObject = flat; - if (cache) { - bool preserving = cache->PreservingWrapper(); - cache->SetPreservingWrapper(false); - cache->SetWrapper(flat); - cache->SetPreservingWrapper(preserving); - } - if (!JS_CopyPropertiesFrom(cx, flat, propertyHolder)) - MOZ_CRASH(); - } else { - SetSlimWrapperProto(flat, newProto.get()); - if (!JS_SetPrototype(cx, flat, newProto->GetJSProtoObject())) - MOZ_CRASH(); // this is bad, very bad + // We've set up |newobj|, so we make it own the WN by nulling out + // the private of |flat|. + // + // NB: It's important to do this _after_ copying the properties to + // propertyHolder. Otherwise, an object with |foo.x === foo| will + // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x. + JS_SetPrivate(flat, nullptr); } + // Before proceeding, eagerly create any same-compartment security wrappers + // that the object might have. This forces us to take the 'WithWrapper' path + // while transplanting that handles this stuff correctly. + { + JSAutoCompartment innerAC(cx, aOldScope->GetGlobalJSObject()); + if (!wrapper->GetSameCompartmentSecurityWrapper(cx)) + return NS_ERROR_FAILURE; + } + + // Update scope maps. This section modifies global state, so from + // here on out we crash if anything fails. + { // scoped lock + Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap(); + Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap(); + XPCAutoLock lock(aOldScope->GetRuntime()->GetMapLock()); + + oldMap->Remove(wrapper); + + if (wrapper->HasProto()) + wrapper->SetProto(newProto); + + // If the wrapper has no scriptable or it has a non-shared + // scriptable, then we don't need to mess with it. + // Otherwise... + + if (wrapper->mScriptableInfo && + wrapper->mScriptableInfo == oldProto->GetScriptableInfo()) { + // The new proto had better have the same JSClass stuff as + // the old one! We maintain a runtime wide unique map of + // this stuff. So, if these don't match then the caller is + // doing something bad here. + + NS_ASSERTION(oldProto->GetScriptableInfo()->GetScriptableShared() == + newProto->GetScriptableInfo()->GetScriptableShared(), + "Changing proto is also changing JSObject Classname or " + "helper's nsIXPScriptable flags. This is not allowed!"); + + wrapper->UpdateScriptableInfo(newProto->GetScriptableInfo()); + } + + // Crash if the wrapper is already in the new scope. + if (newMap->Find(wrapper->GetIdentityObject())) + MOZ_CRASH(); + + if (!newMap->Add(wrapper)) + MOZ_CRASH(); + } + + JSObject *ww = wrapper->GetWrapper(); + if (ww) { + JSObject *newwrapper; + MOZ_ASSERT(wrapper->NeedsSOW(), "weird wrapper wrapper"); + newwrapper = xpc::WrapperFactory::WrapSOWObject(cx, newobj); + if (!newwrapper) + MOZ_CRASH(); + + // Ok, now we do the special object-plus-wrapper transplant. + ww = xpc::TransplantObjectWithWrapper(cx, flat, ww, newobj, + newwrapper); + if (!ww) + MOZ_CRASH(); + + flat = newobj; + wrapper->SetWrapper(ww); + } else { + flat = xpc::TransplantObject(cx, flat, newobj); + if (!flat) + MOZ_CRASH(); + } + + wrapper->mFlatJSObject = flat; + if (cache) { + bool preserving = cache->PreservingWrapper(); + cache->SetPreservingWrapper(false); + cache->SetWrapper(flat); + cache->SetPreservingWrapper(preserving); + } + if (!JS_CopyPropertiesFrom(cx, flat, propertyHolder)) + MOZ_CRASH(); + // Call the scriptable hook to indicate that we transplanted. XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); if (si->GetFlags().WantPostCreate()) @@ -1619,10 +1508,8 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, if (!JS_SetParent(cx, flat, aNewParent)) MOZ_CRASH(); - JSObject *nw; - if (wrapper && - (nw = wrapper->GetWrapper()) && - !JS_SetParent(cx, nw, JS_GetGlobalForObject(cx, aNewParent))) { + JSObject *nw = wrapper->GetWrapper(); + if (nw && !JS_SetParent(cx, nw, JS_GetGlobalForObject(cx, aNewParent))) { MOZ_CRASH(); } } @@ -1670,7 +1557,7 @@ RescueOrphans(HandleObject obj) // PreCreate may touch dead compartments. js::AutoMaybeTouchDeadZones agc(parentObj); - bool isWN = IS_WRAPPER_CLASS(js::GetObjectClass(obj)); + bool isWN = IS_WN_REFLECTOR(obj); // There's one little nasty twist here. For reasons described in bug 752764, // we nuke SOW-ed objects after transplanting them. This means that nodes @@ -1693,12 +1580,6 @@ RescueOrphans(HandleObject obj) } } - // Morph any slim wrappers, lest they confuse us. - if (IS_SLIM_WRAPPER(parentObj)) { - bool ok = MorphSlimWrapper(cx, parentObj); - NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); - } - // Recursively fix up orphans on the parent chain. rv = RescueOrphans(parentObj); NS_ENSURE_SUCCESS(rv, rv); @@ -3553,120 +3434,3 @@ XPCJSObjectHolder::newHolder(JSObject* obj) } return new XPCJSObjectHolder(obj); } - -JSBool -MorphSlimWrapper(JSContext *cx, HandleObject obj) -{ - SLIM_LOG(("***** morphing from MorphSlimToWrapper (%p, %p)\n", - obj, static_cast(xpc_GetJSPrivate(obj)))); - - nsISupports* object = static_cast(xpc_GetJSPrivate(obj)); - nsWrapperCache *cache = nullptr; - CallQueryInterface(object, &cache); - nsRefPtr wn; - nsresult rv = XPCWrappedNative::Morph(obj, nullptr, cache, - getter_AddRefs(wn)); - return NS_SUCCEEDED(rv); -} - -#ifdef DEBUG_slimwrappers -static uint32_t sSlimWrappers; -#endif - -JSBool -ConstructSlimWrapper(xpcObjectHelper &aHelper, - XPCWrappedNativeScope* xpcScope, MutableHandleValue rval) -{ - AutoJSContext cx; - nsISupports *identityObj = aHelper.GetCanonical(); - nsXPCClassInfo *classInfoHelper = aHelper.GetXPCClassInfo(); - - if (!classInfoHelper) { - SLIM_LOG_NOT_CREATED(cx, identityObj, "No classinfo helper"); - return false; - } - - XPCNativeScriptableFlags flags(classInfoHelper->GetScriptableFlags()); - - NS_ASSERTION(flags.DontAskInstanceForScriptable(), - "Not supported for cached wrappers!"); - - RootedObject parent(cx, xpcScope->GetGlobalJSObject()); - if (!flags.WantPreCreate()) { - SLIM_LOG_NOT_CREATED(cx, identityObj, - "scriptable helper has no PreCreate hook"); - - return false; - } - - // PreCreate may touch dead compartments. - js::AutoMaybeTouchDeadZones agc(parent); - - RootedObject plannedParent(cx, parent); - nsresult rv = classInfoHelper->PreCreate(identityObj, cx, parent, parent.address()); - if (rv != NS_SUCCESS_ALLOW_SLIM_WRAPPERS) { - SLIM_LOG_NOT_CREATED(cx, identityObj, "PreCreate hook refused"); - - return false; - } - - if (!js::IsObjectInContextCompartment(parent, cx)) { - SLIM_LOG_NOT_CREATED(cx, identityObj, "wrong compartment"); - - return false; - } - - JSAutoCompartment ac(cx, parent); - - if (parent != plannedParent) { - XPCWrappedNativeScope *newXpcScope = GetObjectScope(parent); - if (newXpcScope != xpcScope) { - SLIM_LOG_NOT_CREATED(cx, identityObj, "crossing origins"); - - return false; - } - } - - // The PreCreate hook could have forced the creation of a wrapper, need - // to check for that here and return early. - nsWrapperCache *cache = aHelper.GetWrapperCache(); - JSObject* wrapper = cache->GetWrapper(); - if (wrapper) { - rval.setObject(*wrapper); - - return true; - } - - uint32_t interfacesBitmap = classInfoHelper->GetInterfacesBitmap(); - XPCNativeScriptableCreateInfo - sciProto(aHelper.forgetXPCClassInfo(), flags, interfacesBitmap); - - AutoMarkingWrappedNativeProtoPtr xpcproto(cx); - xpcproto = XPCWrappedNativeProto::GetNewOrUsed(xpcScope, classInfoHelper, &sciProto); - if (!xpcproto) - return false; - - XPCNativeScriptableInfo* si = xpcproto->GetScriptableInfo(); - JSClass* jsclazz = si->GetSlimJSClass(); - if (!jsclazz) - return false; - - wrapper = JS_NewObject(cx, jsclazz, xpcproto->GetJSProtoObject(), parent); - if (!wrapper) - return false; - - JS_SetPrivate(wrapper, identityObj); - SetSlimWrapperProto(wrapper, xpcproto.get()); - - // Transfer ownership to the wrapper's private. - aHelper.forgetCanonical(); - - cache->SetWrapper(wrapper); - - SLIM_LOG(("+++++ %i created slim wrapper (%p, %p, %p)\n", ++sSlimWrappers, - wrapper, p, xpcScope)); - - rval.setObject(*wrapper); - - return true; -} diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 5ad652d65421..f038a9677ea9 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -30,13 +30,6 @@ static JSBool Throw(nsresult errNum, JSContext* cx) // Handy macro used in many callback stub below. -#define MORPH_SLIM_WRAPPER(cx, obj) \ - PR_BEGIN_MACRO \ - SLIM_LOG_WILL_MORPH(cx, obj); \ - if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) \ - return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \ - PR_END_MACRO - #define THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper) \ PR_BEGIN_MACRO \ if (!wrapper) \ @@ -81,32 +74,6 @@ XPC_WN_Shared_ToString(JSContext *cx, unsigned argc, jsval *vp) if (!obj) return false; - if (IS_SLIM_WRAPPER(obj)) { - XPCNativeScriptableInfo *si = - GetSlimWrapperProto(obj)->GetScriptableInfo(); -#ifdef DEBUG -# define FMT_ADDR " @ 0x%p" -# define FMT_STR(str) str -# define PARAM_ADDR(w) , w -#else -# define FMT_ADDR "" -# define FMT_STR(str) -# define PARAM_ADDR(w) -#endif - char *sz = JS_smprintf("[object %s" FMT_ADDR FMT_STR(" (native") FMT_ADDR FMT_STR(")") "]", si->GetJSClass()->name PARAM_ADDR(obj.get()) PARAM_ADDR(xpc_GetJSPrivate(obj))); - if (!sz) - return false; - - JSString* str = JS_NewStringCopyZ(cx, sz); - JS_smprintf_free(sz); - if (!str) - return false; - - *vp = STRING_TO_JSVAL(str); - - return true; - } - XPCCallContext ccx(JS_CALLER, cx, obj); if (!ccx.IsValid()) return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); @@ -173,7 +140,6 @@ XPC_WN_DoubleWrappedGetter(JSContext *cx, unsigned argc, jsval *vp) if (!obj) return false; - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -513,7 +479,6 @@ XPC_WN_Shared_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableH return true; } - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -566,7 +531,6 @@ XPC_WN_Shared_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableH static JSBool XPC_WN_Shared_Enumerate(JSContext *cx, JSHandleObject obj) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -603,10 +567,6 @@ XPC_WN_Shared_Enumerate(JSContext *cx, JSHandleObject obj) /***************************************************************************/ -#ifdef DEBUG_slimwrappers -static uint32_t sFinalizedSlimWrappers; -#endif - enum WNHelperType { WN_NOHELPER, WN_HELPER @@ -623,20 +583,6 @@ WrappedNativeFinalize(js::FreeOp *fop, JSObject *obj, WNHelperType helperType) if (!p) return; - if (IS_SLIM_WRAPPER_OBJECT(obj)) { - SLIM_LOG(("----- %i finalized slim wrapper (%p, %p)\n", - ++sFinalizedSlimWrappers, obj, p)); - - nsWrapperCache* cache; - CallQueryInterface(p, &cache); - cache->ClearWrapper(); - - XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance(); - MOZ_ASSERT(rt, "XPCJSRuntime should exist during a GC."); - rt->DeferredRelease(p); - return; - } - XPCWrappedNative* wrapper = static_cast(p); if (helperType == WN_HELPER) wrapper->GetScriptableCallback()->Finalize(wrapper, js::CastToJSFreeOp(fop), obj); @@ -649,12 +595,6 @@ XPC_WN_NoHelper_Finalize(js::FreeOp *fop, JSObject *obj) WrappedNativeFinalize(fop, obj, WN_NOHELPER); } -static void -TraceInsideSlimWrapper(JSTracer *trc, JSObject *obj) -{ - GetSlimWrapperProto(obj)->TraceSelf(trc); -} - /* * General comment about XPConnect tracing: Given a C++ object |wrapper| and its * corresponding JS object |obj|, calling |wrapper->TraceSelf| will ask the JS @@ -670,18 +610,11 @@ MarkWrappedNative(JSTracer *trc, JSObject *obj) if (clazz->flags & JSCLASS_DOM_GLOBAL) { mozilla::dom::TraceProtoAndIfaceCache(trc, obj); } - MOZ_ASSERT(IS_WRAPPER_CLASS(clazz)); + MOZ_ASSERT(IS_WN_CLASS(clazz)); - if (IS_WN_WRAPPER_OBJECT(obj)) { - XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); - if (wrapper) { - if (wrapper->IsValid()) - wrapper->TraceInside(trc); - } - } else { - MOZ_ASSERT(IS_SLIM_WRAPPER_OBJECT(obj)); - TraceInsideSlimWrapper(trc, obj); - } + XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); + if (wrapper && wrapper->IsValid()) + wrapper->TraceInside(trc); } static void @@ -693,7 +626,6 @@ XPC_WN_NoHelper_Trace(JSTracer *trc, JSObject *obj) static JSBool XPC_WN_NoHelper_Resolve(JSContext *cx, JSHandleObject obj, JSHandleId id) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -826,7 +758,6 @@ XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { static JSBool XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -846,7 +777,6 @@ XPC_WN_MaybeResolvingStrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHan static JSBool XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -859,36 +789,19 @@ XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHan } // macro fun! -#define PRE_HELPER_STUB_NO_SLIM \ - XPCWrappedNative* wrapper = \ - XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj); \ - THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \ - bool retval = true; \ - nsresult rv = wrapper->GetScriptableCallback()-> - #define PRE_HELPER_STUB \ - XPCWrappedNative* wrapper; \ - nsIXPCScriptable* si; \ - JSObject *unwrapped = js::CheckedUnwrap(obj, false); \ + JSObject *unwrapped = js::CheckedUnwrap(obj, false); \ if (!unwrapped) { \ JS_ReportError(cx, "Permission denied to operate on object."); \ return false; \ } \ - if (!IS_WRAPPER_CLASS(js::GetObjectClass(unwrapped))) { \ + if (!IS_WN_REFLECTOR(unwrapped)) { \ return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \ } \ - if (IS_SLIM_WRAPPER_OBJECT(unwrapped)) { \ - wrapper = nullptr; \ - si = GetSlimWrapperProto(unwrapped)->GetScriptableInfo() \ - ->GetCallback(); \ - } else { \ - MOZ_ASSERT(IS_WN_WRAPPER_OBJECT(unwrapped)); \ - wrapper = XPCWrappedNative::Get(unwrapped); \ - THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \ - si = wrapper->GetScriptableCallback(); \ - } \ + XPCWrappedNative *wrapper = XPCWrappedNative::Get(unwrapped); \ + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \ bool retval = true; \ - nsresult rv = si-> + nsresult rv = wrapper->GetScriptableCallback()-> #define POST_HELPER_STUB \ if (NS_FAILED(rv)) \ @@ -934,8 +847,7 @@ XPC_WN_Helper_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBo static JSBool XPC_WN_Helper_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp) { - SLIM_LOG_WILL_MORPH(cx, obj); - PRE_HELPER_STUB_NO_SLIM + PRE_HELPER_STUB Convert(wrapper, cx, obj, type, vp.address(), &retval); POST_HELPER_STUB } @@ -963,8 +875,7 @@ XPC_WN_Helper_Call(JSContext *cx, unsigned argc, jsval *vp) MOZ_ASSERT(obj == ccx.GetFlattenedJSObject()); - SLIM_LOG_WILL_MORPH(cx, obj); - PRE_HELPER_STUB_NO_SLIM + PRE_HELPER_STUB Call(wrapper, cx, obj, args, &retval); POST_HELPER_STUB } @@ -984,8 +895,7 @@ XPC_WN_Helper_Construct(JSContext *cx, unsigned argc, jsval *vp) MOZ_ASSERT(obj == ccx.GetFlattenedJSObject()); - SLIM_LOG_WILL_MORPH(cx, obj); - PRE_HELPER_STUB_NO_SLIM + PRE_HELPER_STUB Construct(wrapper, cx, obj, args, &retval); POST_HELPER_STUB } @@ -993,9 +903,8 @@ XPC_WN_Helper_Construct(JSContext *cx, unsigned argc, jsval *vp) static JSBool XPC_WN_Helper_HasInstance(JSContext *cx, JSHandleObject obj, JSMutableHandleValue valp, JSBool *bp) { - SLIM_LOG_WILL_MORPH(cx, obj); bool retval2; - PRE_HELPER_STUB_NO_SLIM + PRE_HELPER_STUB HasInstance(wrapper, cx, obj, valp, &retval2, &retval); *bp = retval2; POST_HELPER_STUB @@ -1014,27 +923,6 @@ XPC_WN_Helper_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsig nsresult rv = NS_OK; bool retval = true; RootedObject obj2FromScriptable(cx); - if (IS_SLIM_WRAPPER(obj)) { - XPCNativeScriptableInfo *si = - GetSlimWrapperProto(obj)->GetScriptableInfo(); - if (!si->GetFlags().WantNewResolve()) - return retval; - - NS_ASSERTION(si->GetFlags().AllowPropModsToPrototype() && - !si->GetFlags().AllowPropModsDuringResolve(), - "We don't support these flags for slim wrappers!"); - - rv = si->GetCallback()->NewResolve(nullptr, cx, obj, id, flags, - obj2FromScriptable.address(), &retval); - if (NS_FAILED(rv)) - return Throw(rv, cx); - - if (obj2FromScriptable) - objp.set(obj2FromScriptable); - - return retval; - } - XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -1150,7 +1038,7 @@ XPC_WN_JSOp_Enumerate(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, JSMutableHandleValue statep, MutableHandleId idp) { js::Class *clazz = js::GetObjectClass(obj); - if (!IS_WRAPPER_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base) { + if (!IS_WN_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base) { // obj must be a prototype object or a wrapper w/o a // helper. Short circuit this call to the default // implementation. @@ -1158,8 +1046,6 @@ XPC_WN_JSOp_Enumerate(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, return JS_EnumerateState(cx, obj, enum_op, statep, idp); } - MORPH_SLIM_WRAPPER(cx, obj); - XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -1397,9 +1283,6 @@ XPCNativeScriptableShared::PopulateJSClass() if (mFlags.WantOuterObject()) mJSClass.base.ext.outerObject = XPC_WN_OuterObject; - if (!(mFlags & nsIXPCScriptable::WANT_OUTER_OBJECT)) - mCanBeSlim = true; - mJSClass.base.ext.isWrappedNative = true; } @@ -1453,18 +1336,6 @@ XPC_WN_CallMethod(JSContext *cx, unsigned argc, jsval *vp) if (!obj) return false; -#ifdef DEBUG_slimwrappers - { - JSFunction* fun = funobj->getFunctionPrivate(); - JSString *funid = JS_GetFunctionDisplayId(fun); - JSAutoByteString bytes; - const char *funname = !funid ? "" : bytes.encodeLatin1(cx, funid) ? bytes.ptr() : ""; - SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, funname); - } -#endif - if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) - return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); - obj = FixUpThisIfBroken(obj, funobj); XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, argc, JS_ARGV(cx, vp), vp); @@ -1490,21 +1361,6 @@ XPC_WN_GetterSetter(JSContext *cx, unsigned argc, jsval *vp) if (!obj) return false; -#ifdef DEBUG_slimwrappers - { - const char* funname = nullptr; - JSAutoByteString bytes; - if (JS_TypeOfValue(cx, JS_CALLEE(cx, vp)) == JSTYPE_FUNCTION) { - JSString *funid = JS_GetFunctionDisplayId(funobj->getFunctionPrivate()); - funname = !funid ? "" : bytes.encodeLatin1(cx, funid) ? bytes.ptr() : ""; - } - SLIM_LOG_WILL_MORPH_FOR_PROP(cx, obj, funname); - } -#endif - if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) - return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); - - obj = FixUpThisIfBroken(obj, funobj); XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, argc, JS_ARGV(cx, vp), vp); @@ -1787,7 +1643,6 @@ js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = { static JSBool XPC_WN_TearOff_Enumerate(JSContext *cx, JSHandleObject obj) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -1810,7 +1665,6 @@ XPC_WN_TearOff_Enumerate(JSContext *cx, JSHandleObject obj) static JSBool XPC_WN_TearOff_Resolve(JSContext *cx, JSHandleObject obj, JSHandleId id) { - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index ecbf68b9185c..393f37c6bd45 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -1080,21 +1080,6 @@ nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext, return NS_OK; } -nsresult -xpc_MorphSlimWrapper(JSContext *cx, nsISupports *tomorph) -{ - nsWrapperCache *cache; - CallQueryInterface(tomorph, &cache); - if (!cache) - return NS_OK; - - RootedObject obj(cx, cache->GetWrapper()); - if (!obj || !IS_SLIM_WRAPPER(obj)) - return NS_OK; - NS_ENSURE_STATE(MorphSlimWrapper(cx, obj)); - return NS_OK; -} - static nsresult NativeInterface2JSObject(HandleObject aScope, nsISupports *aCOMObj, @@ -1236,12 +1221,9 @@ nsXPConnect::GetWrappedNativeOfJSObject(JSContext * aJSContext, NS_ASSERTION(_retval, "bad param"); RootedObject aJSObj(aJSContext, aJSObjArg); - SLIM_LOG_WILL_MORPH(aJSContext, aJSObj); - nsIXPConnectWrappedNative* wrapper = - XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(aJSContext, aJSObj); - if (wrapper) { - NS_ADDREF(wrapper); - *_retval = wrapper; + aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtOuter = */ false); + if (aJSObj && IS_WN_REFLECTOR(aJSObj)) { + NS_IF_ADDREF(*_retval = XPCWrappedNative::Get(aJSObj)); return NS_OK; } @@ -1263,10 +1245,8 @@ nsXPConnect::GetNativeOfWrapper(JSContext * aJSContext, JS_ReportError(aJSContext, "Permission denied to get native of security wrapper"); return nullptr; } - if (IS_WRAPPER_CLASS(js::GetObjectClass(aJSObj))) { - if (IS_SLIM_WRAPPER_OBJECT(aJSObj)) - return (nsISupports*)xpc_GetJSPrivate(aJSObj); - else if (XPCWrappedNative *wn = XPCWrappedNative::Get(aJSObj)) + if (IS_WN_REFLECTOR(aJSObj)) { + if (XPCWrappedNative *wn = XPCWrappedNative::Get(aJSObj)) return wn->Native(); return nullptr; } @@ -1938,41 +1918,21 @@ IsJSContextOnStack(JSContext *aCx) nsIPrincipal* nsXPConnect::GetPrincipal(JSObject* obj, bool allowShortCircuit) const { - NS_ASSERTION(IS_WRAPPER_CLASS(js::GetObjectClass(obj)), - "What kind of wrapper is this?"); + NS_ASSERTION(IS_WN_REFLECTOR(obj), "What kind of wrapper is this?"); - if (IS_WN_WRAPPER_OBJECT(obj)) { - XPCWrappedNative *xpcWrapper = - (XPCWrappedNative *)xpc_GetJSPrivate(obj); - if (xpcWrapper) { - if (allowShortCircuit) { - nsIPrincipal *result = xpcWrapper->GetObjectPrincipal(); - if (result) { - return result; - } - } - - // If not, check if it points to an nsIScriptObjectPrincipal - nsCOMPtr objPrin = - do_QueryInterface(xpcWrapper->Native()); - if (objPrin) { - nsIPrincipal *result = objPrin->GetPrincipal(); - if (result) { - return result; - } - } - } - } else { + XPCWrappedNative *xpcWrapper = + (XPCWrappedNative *)xpc_GetJSPrivate(obj); + if (xpcWrapper) { if (allowShortCircuit) { - nsIPrincipal *result = - GetSlimWrapperProto(obj)->GetScope()->GetPrincipal(); + nsIPrincipal *result = xpcWrapper->GetObjectPrincipal(); if (result) { return result; } } + // If not, check if it points to an nsIScriptObjectPrincipal nsCOMPtr objPrin = - do_QueryInterface((nsISupports*)xpc_GetJSPrivate(obj)); + do_QueryInterface(xpcWrapper->Native()); if (objPrin) { nsIPrincipal *result = objPrin->GetPrincipal(); if (result) { diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 0354be0b7840..8651cce43af5 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -15,13 +15,6 @@ * additional C++ object involved of type XPCWrappedNative. The XPCWrappedNative * holds pointers to the C++ object and the flat JS object. * - * As an optimization, some C++ objects don't have XPCWrappedNatives, although - * they still have a corresponding flattened JS object. These are called "slim - * wrappers": all the wrapping information is stored in extra fields of the C++ - * object and the JS object. Slim wrappers are only used for DOM objects. As a - * deoptimization, slim wrappers can be "morphed" into XPCWrappedNatives if the - * extra fields of the XPCWrappedNative become necessary. - * * All XPCWrappedNative objects belong to an XPCWrappedNativeScope. These scopes * are essentially in 1:1 correspondence with JS global objects. The * XPCWrappedNativeScope has a pointer to the JS global object. The parent of a @@ -49,10 +42,6 @@ * pointers are smooshed together in a tagged union.) Either way it can reach * its scope. * - * In the case of slim wrappers (where there is no XPCWrappedNative), the - * flattened JS object has a pointer to the XPCWrappedNativeProto stored in a - * reserved slot. - * * An XPCWrappedNativeProto keeps track of the set of interfaces implemented by * the C++ object in an XPCNativeSet. (The list of interfaces is obtained by * calling a method on the nsIClassInfo.) An XPCNativeSet is a collection of @@ -288,42 +277,24 @@ extern const char XPC_XPCONNECT_CONTRACTID[]; #define WRAPPER_SLOTS (JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | \ JSCLASS_HAS_RESERVED_SLOTS(1)) -// WRAPPER_MULTISLOT is defined in xpcpublic.h - #define INVALID_OBJECT ((JSObject *)1) -inline void SetSlimWrapperProto(JSObject *obj, XPCWrappedNativeProto *proto) -{ - JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, PRIVATE_TO_JSVAL(proto)); -} - -inline XPCWrappedNativeProto* GetSlimWrapperProto(JSObject *obj) -{ - MOZ_ASSERT(IS_SLIM_WRAPPER(obj)); - const JS::Value &v = js::GetReservedSlot(obj, WRAPPER_MULTISLOT); - return static_cast(v.toPrivate()); -} - -// A slim wrapper is identified by having a native pointer in its reserved slot. -// This function, therefore, does the official transition from a slim wrapper to -// a non-slim wrapper. -inline void MorphMultiSlot(JSObject *obj) -{ - MOZ_ASSERT(IS_SLIM_WRAPPER(obj)); - JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, JSVAL_NULL); - MOZ_ASSERT(!IS_SLIM_WRAPPER(obj)); -} +// NB: This slot isn't actually reserved for us on globals, because SpiderMonkey +// uses the first N slots on globals internally. The fact that we use it for +// wrapped global objects is totally broken. But due to a happy coincidence, the +// JS engine never uses that slot. This still needs fixing though. See bug 760095. +#define WN_XRAYEXPANDOCHAIN_SLOT 0 inline void SetWNExpandoChain(JSObject *obj, JSObject *chain) { - MOZ_ASSERT(IS_WN_WRAPPER(obj)); - JS_SetReservedSlot(obj, WRAPPER_MULTISLOT, JS::ObjectOrNullValue(chain)); + MOZ_ASSERT(IS_WN_REFLECTOR(obj)); + JS_SetReservedSlot(obj, WN_XRAYEXPANDOCHAIN_SLOT, JS::ObjectOrNullValue(chain)); } inline JSObject* GetWNExpandoChain(JSObject *obj) { - MOZ_ASSERT(IS_WN_WRAPPER(obj)); - return JS_GetReservedSlot(obj, WRAPPER_MULTISLOT).toObjectOrNull(); + MOZ_ASSERT(IS_WN_REFLECTOR(obj)); + return JS_GetReservedSlot(obj, WN_XRAYEXPANDOCHAIN_SLOT).toObjectOrNull(); } /***************************************************************************/ @@ -1966,13 +1937,10 @@ public: {return mJSClass.interfacesBitmap;} JSClass* GetJSClass() {return Jsvalify(&mJSClass.base);} - JSClass* GetSlimJSClass() - {if (mCanBeSlim) return GetJSClass(); return nullptr;} XPCNativeScriptableShared(uint32_t aFlags, char* aName, uint32_t interfacesBitmap) - : mFlags(aFlags), - mCanBeSlim(false) + : mFlags(aFlags) {memset(&mJSClass, 0, sizeof(mJSClass)); mJSClass.base.name = aName; // take ownership mJSClass.interfacesBitmap = interfacesBitmap; @@ -1995,7 +1963,6 @@ public: private: XPCNativeScriptableFlags mFlags; XPCWrappedNativeJSClass mJSClass; - JSBool mCanBeSlim; }; /***************************************************************************/ @@ -2020,9 +1987,6 @@ public: JSClass* GetJSClass() {return mShared->GetJSClass();} - JSClass* - GetSlimJSClass() {return mShared->GetSlimJSClass();} - XPCNativeScriptableShared* GetScriptableShared() {return mShared;} @@ -2241,12 +2205,6 @@ private: XPCNativeScriptableInfo* mScriptableInfo; }; -class xpcObjectHelper; -extern JSBool ConstructSlimWrapper(xpcObjectHelper &aHelper, - XPCWrappedNativeScope* xpcScope, - JS::MutableHandleValue rval); -extern JSBool MorphSlimWrapper(JSContext *cx, JS::HandleObject obj); - /***********************************************/ // XPCWrappedNativeTearOff represents the info needed to make calls to one // interface on the underlying native object of a XPCWrappedNative. @@ -2433,7 +2391,7 @@ public: SetSet(XPCNativeSet* set) {XPCAutoLock al(GetLock()); mSet = set;} static XPCWrappedNative* Get(JSObject *obj) { - MOZ_ASSERT(IS_WN_WRAPPER(obj)); + MOZ_ASSERT(IS_WN_REFLECTOR(obj)); return (XPCWrappedNative*)js::GetObjectPrivate(obj); } @@ -2493,22 +2451,6 @@ public: XPCNativeInterface* Interface, XPCWrappedNative** wrapper); - static XPCWrappedNative* - GetAndMorphWrappedNativeOfJSObject(JSContext* cx, JSObject* obj_) - { - JS::RootedObject obj(cx, obj_); - obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); - if (!obj) - return nullptr; - if (!IS_WRAPPER_CLASS(js::GetObjectClass(obj))) - return nullptr; - - if (IS_SLIM_WRAPPER_OBJECT(obj) && !MorphSlimWrapper(cx, obj)) - return nullptr; - MOZ_ASSERT(IS_WN_WRAPPER(obj)); - return XPCWrappedNative::Get(obj); - } - static nsresult ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope, XPCWrappedNativeScope* aNewScope, @@ -2672,7 +2614,6 @@ private: private: JSBool Init(JS::HandleObject parent, const XPCNativeScriptableCreateInfo* sci); - JSBool Init(JSObject *existingJSObject); JSBool FinishInit(); JSBool ExtendSet(XPCNativeInterface* aInterface); diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 1ce3db287c84..6d3e5e6cc7ea 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -82,48 +82,16 @@ xpc_LocalizeRuntime(JSRuntime *rt); NS_EXPORT_(void) xpc_DelocalizeRuntime(JSRuntime *rt); -nsresult -xpc_MorphSlimWrapper(JSContext *cx, nsISupports *tomorph); +// If IS_WN_CLASS for the JSClass of an object is true, the object is a +// wrappednative wrapper, holding the XPCWrappedNative in its private slot. -static inline bool IS_WRAPPER_CLASS(js::Class* clazz) +static inline bool IS_WN_CLASS(js::Class* clazz) { return clazz->ext.isWrappedNative; } - -// If IS_WRAPPER_CLASS for the JSClass of an object is true, the object can be -// a slim wrapper, holding a native in its private slot, or a wrappednative -// wrapper, holding the XPCWrappedNative in its private slot. A slim wrapper -// also holds a pointer to its XPCWrappedNativeProto in a reserved slot, we can -// check that slot for a private value (i.e. a double) to distinguish between -// the two. This allows us to store a JSObject in that slot for non-slim wrappers -// while still being able to distinguish the two cases. - -// NB: This slot isn't actually reserved for us on globals, because SpiderMonkey -// uses the first N slots on globals internally. The fact that we use it for -// wrapped global objects is totally broken. But due to a happy coincidence, the -// JS engine never uses that slot. This still needs fixing though. See bug 760095. -#define WRAPPER_MULTISLOT 0 - -static inline bool IS_WN_WRAPPER_OBJECT(JSObject *obj) +static inline bool IS_WN_REFLECTOR(JSObject *obj) { - MOZ_ASSERT(IS_WRAPPER_CLASS(js::GetObjectClass(obj))); - return !js::GetReservedSlot(obj, WRAPPER_MULTISLOT).isDouble(); -} -static inline bool IS_SLIM_WRAPPER_OBJECT(JSObject *obj) -{ - return !IS_WN_WRAPPER_OBJECT(obj); -} - -// Use these functions if IS_WRAPPER_CLASS(GetObjectClass(obj)) might be false. -// Avoid calling them if IS_WRAPPER_CLASS(GetObjectClass(obj)) can only be -// true, as we'd do a redundant call to IS_WRAPPER_CLASS. -static inline bool IS_WN_WRAPPER(JSObject *obj) -{ - return IS_WRAPPER_CLASS(js::GetObjectClass(obj)) && IS_WN_WRAPPER_OBJECT(obj); -} -static inline bool IS_SLIM_WRAPPER(JSObject *obj) -{ - return IS_WRAPPER_CLASS(js::GetObjectClass(obj)) && IS_SLIM_WRAPPER_OBJECT(obj); + return IS_WN_CLASS(js::GetObjectClass(obj)); } extern bool @@ -134,14 +102,10 @@ xpc_FastGetCachedWrapper(nsWrapperCache *cache, JSObject *scope, jsval *vp) { if (cache) { JSObject* wrapper = cache->GetWrapper(); - NS_ASSERTION(!wrapper || - !cache->IsDOMBinding() || - !IS_SLIM_WRAPPER(wrapper), - "Should never have a slim wrapper when IsDOMBinding()"); if (wrapper && js::GetObjectCompartment(wrapper) == js::GetObjectCompartment(scope) && (cache->IsDOMBinding() ? !cache->HasSystemOnlyWrapper() : - (IS_SLIM_WRAPPER(wrapper) || xpc_OkToHandOutWrapper(cache)))) { + xpc_OkToHandOutWrapper(cache))) { *vp = OBJECT_TO_JSVAL(wrapper); return wrapper; } diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index be79dc31365a..0467e86a5fbd 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -179,8 +179,8 @@ IsFrameId(JSContext *cx, JSObject *objArg, jsid idArg) obj = JS_ObjectToInnerObject(cx, obj); MOZ_ASSERT(!js::IsWrapper(obj)); - XPCWrappedNative *wn = IS_WN_WRAPPER(obj) ? XPCWrappedNative::Get(obj) - : nullptr; + XPCWrappedNative *wn = IS_WN_REFLECTOR(obj) ? XPCWrappedNative::Get(obj) + : nullptr; if (!wn) { return false; } @@ -272,7 +272,7 @@ AccessCheck::needsSystemOnlyWrapper(JSObject *obj) if (dom::GetSameCompartmentWrapperForDOMBinding(wrapper)) return wrapper != obj; - if (!IS_WN_WRAPPER(obj)) + if (!IS_WN_REFLECTOR(obj)) return false; XPCWrappedNative *wn = static_cast(js::GetObjectPrivate(obj)); diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index 1edeb8e67847..1a0a9406754a 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -152,11 +152,6 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope, // We should never get a proxy here (the JS engine unwraps those for us). MOZ_ASSERT(!IsWrapper(obj)); - // As soon as an object is wrapped in a security wrapper, it morphs to be - // a fat wrapper. (see also: bug XXX). - if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) - return nullptr; - // If the object being wrapped is a prototype for a standard class and the // wrapper does not subsumes the wrappee, use the one from the content // compartment. This is generally safer all-around, and in the COW case this @@ -201,7 +196,7 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope, // those objects in a security wrapper, then we need to hand back the // wrapper for the new scope instead. Also, global objects don't move // between scopes so for those we also want to return the wrapper. So... - if (!IS_WN_WRAPPER(obj) || !js::GetObjectParent(obj)) + if (!IS_WN_REFLECTOR(obj) || !js::GetObjectParent(obj)) return DoubleWrap(cx, obj, flags); XPCWrappedNative *wn = static_cast(xpc_GetJSPrivate(obj)); @@ -300,7 +295,7 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope, NS_ENSURE_SUCCESS(rv, nullptr); obj = JSVAL_TO_OBJECT(v); - NS_ASSERTION(IS_WN_WRAPPER(obj), "bad object"); + NS_ASSERTION(IS_WN_REFLECTOR(obj), "bad object"); // Because the underlying native didn't have a PreCreate hook, we had // to a new (or possibly pre-existing) XPCWN in our compartment. @@ -522,7 +517,7 @@ WrapperFactory::WrapForSameCompartment(JSContext *cx, HandleObject objArg) MOZ_ASSERT(!dom::IsDOMObject(obj)); - if (!IS_WN_WRAPPER(obj)) + if (!IS_WN_REFLECTOR(obj)) return obj; // Extract the WN. It should exist. diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 548a8fd98477..5efceda74bb5 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -61,11 +61,9 @@ GetXrayType(JSObject *obj) return XrayForDOMObject; js::Class* clasp = js::GetObjectClass(obj); - if (IS_WRAPPER_CLASS(clasp) || clasp->ext.innerObject) { - NS_ASSERTION(clasp->ext.innerObject || IS_WN_WRAPPER_OBJECT(obj), - "We forgot to Morph a slim wrapper!"); + if (IS_WN_CLASS(clasp) || clasp->ext.innerObject) return XrayForWrappedNative; - } + return NotXray; } @@ -511,7 +509,7 @@ GetHolder(JSObject *obj) static XPCWrappedNative * GetWrappedNative(JSObject *obj) { - MOZ_ASSERT(IS_WN_WRAPPER_OBJECT(obj)); + MOZ_ASSERT(IS_WN_REFLECTOR(obj)); return static_cast(js::GetObjectPrivate(obj)); } diff --git a/layout/base/Units.h b/layout/base/Units.h index 516a8eee9fdc..1d20677f95d2 100644 --- a/layout/base/Units.h +++ b/layout/base/Units.h @@ -8,69 +8,95 @@ #define MOZ_UNITS_H_ #include "mozilla/gfx/Point.h" +#include "mozilla/gfx/Rect.h" +#include "mozilla/gfx/ScaleFactor.h" #include "nsDeviceContext.h" namespace mozilla { +struct CSSPixel; +struct LayerPixel; +struct ScreenPixel; + +typedef gfx::PointTyped CSSPoint; +typedef gfx::IntPointTyped CSSIntPoint; +typedef gfx::SizeTyped CSSSize; +typedef gfx::IntSizeTyped CSSIntSize; +typedef gfx::RectTyped CSSRect; +typedef gfx::IntRectTyped CSSIntRect; + +typedef gfx::PointTyped LayerPoint; +typedef gfx::IntPointTyped LayerIntPoint; +typedef gfx::SizeTyped LayerSize; +typedef gfx::IntSizeTyped LayerIntSize; +typedef gfx::RectTyped LayerRect; +typedef gfx::IntRectTyped LayerIntRect; + +typedef gfx::PointTyped ScreenPoint; +typedef gfx::IntPointTyped ScreenIntPoint; +typedef gfx::SizeTyped ScreenSize; +typedef gfx::IntSizeTyped ScreenIntSize; +typedef gfx::RectTyped ScreenRect; +typedef gfx::IntRectTyped ScreenIntRect; + +typedef gfx::ScaleFactor CSSToLayerScale; +typedef gfx::ScaleFactor LayerToCSSScale; +typedef gfx::ScaleFactor CSSToScreenScale; +typedef gfx::ScaleFactor ScreenToCSSScale; +typedef gfx::ScaleFactor LayerToScreenScale; +typedef gfx::ScaleFactor ScreenToLayerScale; + /* * The pixels that content authors use to specify sizes in. */ struct CSSPixel { - static gfx::IntPointTyped RoundToInt(const gfx::PointTyped& aPoint) { - return gfx::IntPointTyped(NS_lround(aPoint.x), - NS_lround(aPoint.y)); + + // Conversions from app units + + static CSSPoint FromAppUnits(const nsPoint& aPoint) { + return CSSPoint(NSAppUnitsToFloatPixels(aPoint.x, float(nsDeviceContext::AppUnitsPerCSSPixel())), + NSAppUnitsToFloatPixels(aPoint.y, float(nsDeviceContext::AppUnitsPerCSSPixel()))); } - static gfx::PointTyped FromAppUnits(const nsPoint& aPoint) { - return gfx::PointTyped(NSAppUnitsToFloatPixels(aPoint.x, float(nsDeviceContext::AppUnitsPerCSSPixel())), - NSAppUnitsToFloatPixels(aPoint.y, float(nsDeviceContext::AppUnitsPerCSSPixel()))); + static CSSRect FromAppUnits(const nsRect& aRect) { + return CSSRect(NSAppUnitsToFloatPixels(aRect.x, float(nsDeviceContext::AppUnitsPerCSSPixel())), + NSAppUnitsToFloatPixels(aRect.y, float(nsDeviceContext::AppUnitsPerCSSPixel())), + NSAppUnitsToFloatPixels(aRect.width, float(nsDeviceContext::AppUnitsPerCSSPixel())), + NSAppUnitsToFloatPixels(aRect.height, float(nsDeviceContext::AppUnitsPerCSSPixel()))); } - static gfx::IntPointTyped FromAppUnitsRounded(const nsPoint& aPoint) { - return gfx::IntPointTyped(NSAppUnitsToIntPixels(aPoint.x, float(nsDeviceContext::AppUnitsPerCSSPixel())), - NSAppUnitsToIntPixels(aPoint.y, float(nsDeviceContext::AppUnitsPerCSSPixel()))); + static CSSIntPoint FromAppUnitsRounded(const nsPoint& aPoint) { + return CSSIntPoint(NSAppUnitsToIntPixels(aPoint.x, float(nsDeviceContext::AppUnitsPerCSSPixel())), + NSAppUnitsToIntPixels(aPoint.y, float(nsDeviceContext::AppUnitsPerCSSPixel()))); } - static nsPoint ToAppUnits(const gfx::PointTyped& aPoint) { + static CSSIntRect FromAppUnitsRounded(const nsRect& aRect) { + return CSSIntRect(NSAppUnitsToIntPixels(aRect.x, float(nsDeviceContext::AppUnitsPerCSSPixel())), + NSAppUnitsToIntPixels(aRect.y, float(nsDeviceContext::AppUnitsPerCSSPixel())), + NSAppUnitsToIntPixels(aRect.width, float(nsDeviceContext::AppUnitsPerCSSPixel())), + NSAppUnitsToIntPixels(aRect.height, float(nsDeviceContext::AppUnitsPerCSSPixel()))); + } + + // Conversions to app units + + static nsPoint ToAppUnits(const CSSPoint& aPoint) { return nsPoint(NSFloatPixelsToAppUnits(aPoint.x, float(nsDeviceContext::AppUnitsPerCSSPixel())), NSFloatPixelsToAppUnits(aPoint.y, float(nsDeviceContext::AppUnitsPerCSSPixel()))); } - static nsPoint ToAppUnits(const gfx::IntPointTyped& aPoint) - { + static nsPoint ToAppUnits(const CSSIntPoint& aPoint) { return nsPoint(NSIntPixelsToAppUnits(aPoint.x, nsDeviceContext::AppUnitsPerCSSPixel()), NSIntPixelsToAppUnits(aPoint.y, nsDeviceContext::AppUnitsPerCSSPixel())); } - static gfx::RectTyped FromAppUnits(const nsRect& aRect) { - return gfx::RectTyped(NSAppUnitsToFloatPixels(aRect.x, float(nsDeviceContext::AppUnitsPerCSSPixel())), - NSAppUnitsToFloatPixels(aRect.y, float(nsDeviceContext::AppUnitsPerCSSPixel())), - NSAppUnitsToFloatPixels(aRect.width, float(nsDeviceContext::AppUnitsPerCSSPixel())), - NSAppUnitsToFloatPixels(aRect.height, float(nsDeviceContext::AppUnitsPerCSSPixel()))); - } - - static nsRect ToAppUnits(const gfx::RectTyped& aRect) { + static nsRect ToAppUnits(const CSSRect& aRect) { return nsRect(NSFloatPixelsToAppUnits(aRect.x, float(nsDeviceContext::AppUnitsPerCSSPixel())), NSFloatPixelsToAppUnits(aRect.y, float(nsDeviceContext::AppUnitsPerCSSPixel())), NSFloatPixelsToAppUnits(aRect.width, float(nsDeviceContext::AppUnitsPerCSSPixel())), NSFloatPixelsToAppUnits(aRect.height, float(nsDeviceContext::AppUnitsPerCSSPixel()))); } - - static gfx::IntRectTyped FromAppUnitsRounded(const nsRect& aRect) - { - return gfx::IntRectTyped(NSAppUnitsToIntPixels(aRect.x, float(nsDeviceContext::AppUnitsPerCSSPixel())), - NSAppUnitsToIntPixels(aRect.y, float(nsDeviceContext::AppUnitsPerCSSPixel())), - NSAppUnitsToIntPixels(aRect.width, float(nsDeviceContext::AppUnitsPerCSSPixel())), - NSAppUnitsToIntPixels(aRect.height, float(nsDeviceContext::AppUnitsPerCSSPixel()))); - } }; -typedef gfx::PointTyped CSSPoint; -typedef gfx::IntPointTyped CSSIntPoint; -typedef gfx::SizeTyped CSSSize; -typedef gfx::RectTyped CSSRect; -typedef gfx::IntRectTyped CSSIntRect; - /* * The pixels that layout rasterizes and delivers to the graphics code. * These are generally referred to as "device pixels" in layout code. Layer @@ -80,42 +106,8 @@ typedef gfx::IntRectTyped CSSIntRect; * 3) the "widget scale" (nsIWidget::GetDefaultScale) */ struct LayerPixel { - static gfx::IntPointTyped FromCSSPointRounded(const CSSPoint& aPoint, float aResolutionX, float aResolutionY) { - return gfx::IntPointTyped(NS_lround(aPoint.x * aResolutionX), - NS_lround(aPoint.y * aResolutionY)); - } - - static gfx::IntRectTyped RoundToInt(const gfx::RectTyped& aRect) { - return gfx::IntRectTyped(NS_lround(aRect.x), - NS_lround(aRect.y), - NS_lround(aRect.width), - NS_lround(aRect.height)); - } - - static gfx::RectTyped FromCSSRect(const CSSRect& aRect, float aResolutionX, float aResolutionY) { - return gfx::RectTyped(aRect.x * aResolutionX, - aRect.y * aResolutionY, - aRect.width * aResolutionX, - aRect.height * aResolutionY); - } - - static gfx::IntRectTyped FromCSSRectRounded(const CSSRect& aRect, float aResolutionX, float aResolutionY) { - return RoundToInt(FromCSSRect(aRect, aResolutionX, aResolutionY)); - } - - static CSSIntRect ToCSSIntRectRoundIn(const gfx::IntRectTyped& aRect, float aResolutionX, float aResolutionY) { - gfx::IntRectTyped ret(aRect.x, aRect.y, aRect.width, aRect.height); - ret.ScaleInverseRoundIn(aResolutionX, aResolutionY); - return ret; - } }; -typedef gfx::PointTyped LayerPoint; -typedef gfx::IntPointTyped LayerIntPoint; -typedef gfx::IntSizeTyped LayerIntSize; -typedef gfx::RectTyped LayerRect; -typedef gfx::IntRectTyped LayerIntRect; - /* * The pixels that are displayed on the screen. * On non-OMTC platforms this should be equivalent to LayerPixel units. @@ -126,16 +118,53 @@ typedef gfx::IntRectTyped LayerIntRect; * generally be represented in ScreenPixel units. */ struct ScreenPixel { - static CSSPoint ToCSSPoint(const gfx::PointTyped& aPoint, float aResolutionX, float aResolutionY) { - return CSSPoint(aPoint.x * aResolutionX, - aPoint.y * aResolutionY); - } }; -typedef gfx::PointTyped ScreenPoint; -typedef gfx::IntPointTyped ScreenIntPoint; -typedef gfx::SizeTyped ScreenSize; -typedef gfx::IntSizeTyped ScreenIntSize; +// Operators to apply ScaleFactors directly to Points and Rects + +template +gfx::PointTyped operator*(const gfx::PointTyped& aPoint, const gfx::ScaleFactor& aScale) { + return gfx::PointTyped(aPoint.x * aScale.scale, + aPoint.y * aScale.scale); +} + +template +gfx::PointTyped operator/(const gfx::PointTyped& aPoint, const gfx::ScaleFactor& aScale) { + return gfx::PointTyped(aPoint.x / aScale.scale, + aPoint.y / aScale.scale); +} + +template +gfx::RectTyped operator*(const gfx::RectTyped& aRect, const gfx::ScaleFactor& aScale) { + return gfx::RectTyped(aRect.x * aScale.scale, + aRect.y * aScale.scale, + aRect.width * aScale.scale, + aRect.height * aScale.scale); +} + +template +gfx::RectTyped operator/(const gfx::RectTyped& aRect, const gfx::ScaleFactor& aScale) { + return gfx::RectTyped(aRect.x / aScale.scale, + aRect.y / aScale.scale, + aRect.width / aScale.scale, + aRect.height / aScale.scale); +} + +template +gfx::RectTyped operator*(const gfx::IntRectTyped& aRect, const gfx::ScaleFactor& aScale) { + return gfx::RectTyped(float(aRect.x) * aScale.scale, + float(aRect.y) * aScale.scale, + float(aRect.width) * aScale.scale, + float(aRect.height) * aScale.scale); +} + +template +gfx::RectTyped operator/(const gfx::IntRectTyped& aRect, const gfx::ScaleFactor& aScale) { + return gfx::RectTyped(float(aRect.x) / aScale.scale, + float(aRect.y) / aScale.scale, + float(aRect.width) / aScale.scale, + float(aRect.height) / aScale.scale); +} }; diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 6cc8e9090662..69d03c0499a8 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -676,8 +676,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame, if (nsIWidget* widget = aForFrame->GetNearestWidget()) { nsIntRect bounds; widget->GetBounds(bounds); - // I don't know what units bounds are in, hence FromUnknownRect - metrics.mCompositionBounds = LayerIntRect::FromUnknownRect( + metrics.mCompositionBounds = ScreenIntRect::FromUnknownRect( mozilla::gfx::IntRect(bounds.x, bounds.y, bounds.width, bounds.height)); } diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index c6f905d9e0b5..755478efe1a1 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -918,7 +918,7 @@ nsInlineFrame::AccessibleType() if (tagAtom == nsGkAtoms::input) // Broken return a11y::eHTMLButtonType; if (tagAtom == nsGkAtoms::img) // Create accessible for broken - return a11y::eImageType; + return a11y::eHyperTextType; if (tagAtom == nsGkAtoms::label) // Creat accessible for