author | Wes Kocher <wkocher@mozilla.com> |
Wed, 19 Jun 2013 16:37:58 -0700 | |
changeset 147151 | 8ea92aeab78353889f6928cb24d87f7330cd8c74 |
parent 147101 | ca07be78813b38465a78eda64da0961c4c96fdf5 (current diff) |
parent 147150 | 32bffdedafeeeb1dfbe3d8824c4cf9e55d81fa42 (diff) |
child 147216 | 34a280cae36826f84110f8d5177f2e027ab65b28 |
child 147253 | f5a90edfa8f62ebb226c1408752c59f4faab16fa |
child 147284 | 148f8183bf89577fbecab72da8ca29f5a9ce01dd |
push id | 2697 |
push user | bbajaj@mozilla.com |
push date | Mon, 05 Aug 2013 18:49:53 +0000 |
treeherder | mozilla-beta@dfec938c7b63 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 24.0a1 |
first release with | nightly linux32
8ea92aeab783
/
24.0a1
/
20130620031010
/
files
nightly linux64
8ea92aeab783
/
24.0a1
/
20130620031010
/
files
nightly mac
8ea92aeab783
/
24.0a1
/
20130620031010
/
files
nightly win32
8ea92aeab783
/
24.0a1
/
20130620031010
/
files
nightly win64
8ea92aeab783
/
24.0a1
/
20130620031010
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
24.0a1
/
20130620031010
/
pushlog to previous
nightly linux64
24.0a1
/
20130620031010
/
pushlog to previous
nightly mac
24.0a1
/
20130620031010
/
pushlog to previous
nightly win32
24.0a1
/
20130620031010
/
pushlog to previous
nightly win64
24.0a1
/
20130620031010
/
pushlog to previous
|
content/html/content/src/nsHTMLFormElement.cpp | file | annotate | diff | comparison | revisions | |
content/html/content/src/nsHTMLFormElement.h | file | annotate | diff | comparison | revisions |
--- a/browser/base/content/browser-social.js +++ b/browser/base/content/browser-social.js @@ -107,17 +107,17 @@ SocialUI = { case "social:ambient-notification-changed": if (this._matchesCurrentProvider(data)) { SocialToolbar.updateButton(); SocialMenu.populate(); } break; case "social:profile-changed": if (this._matchesCurrentProvider(data)) { - SocialToolbar.updateProfile(); + SocialToolbar.updateProvider(); SocialMark.update(); SocialChatBar.update(); } break; case "social:page-mark-config": if (this._matchesCurrentProvider(data)) { SocialMark.updateMarkState(); } @@ -1068,17 +1068,16 @@ SocialToolbar = { userDetailsBroadcaster.removeAttribute("src"); userDetailsBroadcaster.removeAttribute("image"); } userDetailsBroadcaster.setAttribute("value", loggedInStatusValue); userDetailsBroadcaster.setAttribute("label", loggedInStatusValue); }, - // XXX doesn't this need to be called for profile changes, given its use of provider.profile? updateButton: function SocialToolbar_updateButton() { this._updateButtonHiddenState(); let panel = document.getElementById("social-notification-panel"); panel.hidden = !SocialUI.enabled; let command = document.getElementById("Social:ToggleNotifications"); command.setAttribute("checked", Services.prefs.getBoolPref("social.toast-notifications.enabled"));
--- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -54,31 +54,31 @@ endif # # browser_sanitizeDialog_treeView.js is disabled until the tree view is added # back to the clear recent history dialog (sanitize.xul), if it ever is (bug # 480169) # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638. # browser_bug321000.js is disabled because newline handling is shaky (bug 592528) +# browser_bug386835.js is disabled for intermittent failures (bug 880226) _BROWSER_FILES = \ head.js \ browser_typeAheadFind.js \ browser_keywordSearch.js \ browser_keywordSearch_postData.js \ POSTSearchEngine.xml \ print_postdata.sjs \ browser_alltabslistener.js \ browser_bug304198.js \ title_test.svg \ browser_bug329212.js \ browser_bug356571.js \ browser_bug380960.js \ - browser_bug386835.js \ browser_bug405137.js \ browser_bug406216.js \ browser_bug409481.js \ browser_bug409624.js \ browser_bug413915.js \ browser_bug416661.js \ browser_bug417483.js \ browser_bug419612.js \
--- a/browser/base/content/test/browser_CTP_drag_drop.js +++ b/browser/base/content/test/browser_CTP_drag_drop.js @@ -127,17 +127,20 @@ function part11() { // we have to actually show the panel to get the bindings to instantiate notification.options.eventCallback = part12; // this scripts the plugin, triggering the popup notification try { gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test").wrappedJSObject.getObjectValue(); } catch (e) {} } -function part12() { +function part12(type) { + if (type != "shown") { + return; + } let notification = PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser); notification.options.eventCallback = null; let centerAction = null; for (let action of notification.options.centerActions) { if (action.message == "Test") { centerAction = action; break; }
--- a/browser/base/content/test/browser_pluginnotification.js +++ b/browser/base/content/test/browser_pluginnotification.js @@ -713,16 +713,19 @@ function test18e() { function test18f() { var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); ok(notification, "Test 18f, Should have a click-to-play notification"); ok(notification.dismissed, "Test 18f, notification should start dismissed"); var plugin = gTestBrowser.contentDocument.getElementById("test"); var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); ok(!objLoadingContent.activated, "Test 18f, Plugin should not be activated"); + // XXXBAD: this code doesn't do what you think it does! it is actually + // observing the "removed" event of the old notification, since we create + // a *new* one when the plugin is clicked. notification.options.eventCallback = function() { executeSoon(test18g); }; EventUtils.synthesizeMouseAtCenter(plugin, {}, gTestBrowser.contentWindow); } function test18g() { var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); ok(notification, "Test 18g, Should have a click-to-play notification"); ok(!notification.dismissed, "Test 18g, notification should be open"); @@ -874,17 +877,20 @@ function test21a() { ok(!objLoadingContent.activated, "Test 21a, Plugin with id=" + plugin.id + " should not be activated"); } // we have to actually show the panel to get the bindings to instantiate notification.options.eventCallback = test21b; notification.reshow(); } -function test21b() { +function test21b(type) { + if (type != "shown") { + return; + } var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); notification.options.eventCallback = null; var centerAction = null; for (var action of notification.options.centerActions) { if (action.message == "Test") { centerAction = action; break; } @@ -933,17 +939,20 @@ function test21c() { ok(!objLoadingContent.activated, "Test 21c, Plugin with id=" + plugin.id + " should not be activated"); } // we have to actually show the panel to get the bindings to instantiate notification.options.eventCallback = test21d; notification.reshow(); } -function test21d() { +function test21d(type) { + if (type != "shown") { + return; + } var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); notification.options.eventCallback = null; var centerAction = null; for (var action of notification.options.centerActions) { if (action.message == "Second Test") { centerAction = action; break;
--- a/browser/base/content/test/browser_plugins_added_dynamically.js +++ b/browser/base/content/test/browser_plugins_added_dynamically.js @@ -106,17 +106,20 @@ function testActivateAddSameTypePart2() let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); ok(popupNotification, "testActivateAddSameTypePart2: should have a click-to-play notification"); // we have to actually show the panel to get the bindings to instantiate popupNotification.options.eventCallback = testActivateAddSameTypePart3; popupNotification.reshow(); } -function testActivateAddSameTypePart3() { +function testActivateAddSameTypePart3(type) { + if (type != "shown") { + return; + } let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); popupNotification.options.eventCallback = null; let centerAction = null; for (let action of popupNotification.options.centerActions) { if (action.message == "Test") { centerAction = action; break; } @@ -184,17 +187,20 @@ function testActivateAddDifferentTypePar let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); ok(popupNotification, "testActivateAddDifferentTypePart2: should have a click-to-play notification"); // we have to actually show the panel to get the bindings to instantiate popupNotification.options.eventCallback = testActivateAddDifferentTypePart3; popupNotification.reshow(); } -function testActivateAddDifferentTypePart3() { +function testActivateAddDifferentTypePart3(type) { + if (type != "shown") { + return; + } let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); popupNotification.options.eventCallback = null; let centerAction = null; for (let action of popupNotification.options.centerActions) { if (action.message == "Test") { centerAction = action; break; }
--- a/browser/base/content/test/browser_popupNotification.js +++ b/browser/base/content/test/browser_popupNotification.js @@ -132,16 +132,19 @@ function basicNotification() { } ]; this.options = { eventCallback: function (eventName) { switch (eventName) { case "dismissed": self.dismissalCallbackTriggered = true; break; + case "showing": + self.showingCallbackTriggered = true; + break; case "shown": self.shownCallbackTriggered = true; break; case "removed": self.removedCallbackTriggered = true; break; } } @@ -853,32 +856,54 @@ var tests = [ "notification2 anchor should be visible"); dismissNotification(popup); }, onHidden: function(popup) { this.notification1.remove(); this.notification2.remove(); } + }, + { // Test #30 - Showing should be able to modify the popup data + run: function() { + this.notifyObj = new basicNotification(); + var normalCallback = this.notifyObj.options.eventCallback; + this.notifyObj.options.eventCallback = function (eventName) { + if (eventName == "showing") { + this.mainAction.label = "Alternate Label"; + } + normalCallback.call(this, eventName); + }; + showNotification(this.notifyObj); + }, + onShown: function(popup) { + // checkPopup checks for the matching label. Note that this assumes that + // this.notifyObj.mainAction is the same as notification.mainAction, + // which could be a problem if we ever decided to deep-copy. + checkPopup(popup, this.notifyObj); + triggerMainCommand(popup); + }, + onHidden: function() { } } ]; function showNotification(notifyObj) { return PopupNotifications.show(notifyObj.browser, notifyObj.id, notifyObj.message, notifyObj.anchorID, notifyObj.mainAction, notifyObj.secondaryActions, notifyObj.options); } function checkPopup(popup, notificationObj) { info("[Test #" + gTestIndex + "] checking popup"); + ok(notificationObj.showingCallbackTriggered, "showing callback was triggered"); ok(notificationObj.shownCallbackTriggered, "shown callback was triggered"); let notifications = popup.childNodes; is(notifications.length, 1, "one notification displayed"); let notification = notifications[0]; if (!notification) return; let icon = document.getAnonymousElementByAttribute(notification, "class", "popup-notification-icon");
--- a/browser/base/content/test/head.js +++ b/browser/base/content/test/head.js @@ -110,18 +110,18 @@ function getTestPlugin(aName) { ok(false, "Unable to find plugin"); return null; } function updateBlocklist(aCallback) { var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"] .getService(Ci.nsITimerCallback); var observer = function() { - aCallback(); Services.obs.removeObserver(observer, "blocklist-updated"); + SimpleTest.executeSoon(aCallback); }; Services.obs.addObserver(observer, "blocklist-updated", false); blocklistNotifier.notify(null); } var _originalTestBlocklistURL = null; function setAndUpdateBlocklist(aURL, aCallback) { if (!_originalTestBlocklistURL)
--- a/browser/base/content/test/social/browser_social_toolbar.js +++ b/browser/base/content/test/social/browser_social_toolbar.js @@ -1,21 +1,22 @@ /* 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/. */ +let manifest = { // normal provider + name: "provider 1", + origin: "https://example.com", + workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js", + iconURL: "https://example.com/browser/browser/base/content/test/moz.png" +}; + function test() { waitForExplicitFinish(); - let manifest = { // normal provider - name: "provider 1", - origin: "https://example.com", - workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js", - iconURL: "https://example.com/browser/browser/base/content/test/moz.png" - }; runSocialTestWithProvider(manifest, function (finishcb) { runSocialTests(tests, undefined, undefined, finishcb); }); } var tests = { testProfileNone: function(next, useNull) { let profile = useNull ? null : {}; @@ -30,24 +31,29 @@ var tests = { ok(!userButton.hidden, "username is visible"); is(userButton.getAttribute("label"), notLoggedInStatusValue, "label reflects not being logged in"); next(); }, testProfileNull: function(next) { this.testProfileNone(next, true); }, testProfileSet: function(next) { + let statusIcon = document.getElementById("social-provider-button").style.listStyleImage; + is(statusIcon, "url(\"" + manifest.iconURL + "\")", "manifest iconURL is showing"); let profile = { portrait: "https://example.com/portrait.jpg", userName: "trickster", displayName: "Kuma Lisa", - profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa" + profileURL: "http://example.com/Kuma_Lisa", + iconURL: "https://example.com/browser/browser/base/content/test/social/moz.png" } Social.provider.updateUserProfile(profile); // check dom values + statusIcon = document.getElementById("social-provider-button").style.listStyleImage; + is(statusIcon, "url(\"" + profile.iconURL + "\")", "profile iconURL is showing"); let portrait = document.getElementsByClassName("social-statusarea-user-portrait")[0].getAttribute("src"); is(profile.portrait, portrait, "portrait is set"); let userButton = document.getElementsByClassName("social-statusarea-loggedInStatus")[0]; ok(!userButton.hidden, "username is visible"); is(userButton.value, profile.userName, "username is set"); next(); }, testNoAmbientNotificationsIsNoKeyboardMenu: function(next) {
new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..769c636340e11f9d2a0b7eb6a84d574dd9563f0c GIT binary patch literal 580 zc$@)50=xZ*P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz)=5M`RCwBA z{Qv(y10?_;fS8au@87>?@9gaSt*os4-<6T^zln*-e<1(Y>eZ{a-@A8D7MlS80mJ}u z0SKQtbH>fs*!aH-1H=C_K)ecw?*efe5W7I}s#U9Y!PLVrKmdV>nKNfT1{(H16si$K zmjm&CV+al6D=8`c7X*o+82}JK4A3z64>JJB_`e(E3S)?2<zN>X{|^lf1sei(+1<Me zFarPr2&}oIqvIC?)OL^o?-&p^!wh-{#k-;2f_VoZfS{%bLi}zFF<>UtAY{W<LBj?n zz6$CsfB=HI;P*^44eyZn#$YcBg1rF~2L~`P&;bI75#$0;v@zVf$It;Z4d`qJS0Dzu zh@l)BQx!mb7Roj*FK2kaXAgtR*|Q9LfP8=e0=od{pY0$UI-sVXf!f>w#jt?wfcn3@ zy!=0d5|Evi_8%aC7~Z{m#}1AKK|~<_M{=g1px}QcP=ErR57Iaj7$e5OumVLr$n^jL z1djz!sJcLHd57c@W2lWFi_p^m2m=HVoB>kgf@C|$pqa*ykjAAMgaHBwo)>`0c=vmt z+g3yQpuk*x7A(#H^u|wInF%0(FiZq_r2`t3pnwGh6fWCA7$ATcDb3CR0R{jJCzQv) SYsoAC0000<MNUMnLSTYrIq9PS
--- a/browser/components/sessionstore/test/Makefile.in +++ b/browser/components/sessionstore/test/Makefile.in @@ -10,16 +10,17 @@ relativesrcdir = @relativesrcdir@ include $(DEPTH)/config/autoconf.mk # browser_506482.js is disabled because of frequent failures (bug 538672) # browser_526613.js is disabled because of frequent failures (bug 534489) # browser_589246.js is disabled for leaking browser windows (bug 752467) # browser_580512.js is disabled for leaking browser windows (bug 752467) # browser_capabilities.js is disabled for using resources outside of the build network (bug 882575) +# browser_707862.js & browser_705597.js are disabled whilst waiting for review (bug 861700 & bug 883592) MOCHITEST_BROWSER_FILES = \ head.js \ browser_attributes.js \ browser_dying_cache.js \ browser_form_restore_events.js \ browser_form_restore_events_sample.html \ browser_formdata_format.js \ @@ -127,18 +128,16 @@ MOCHITEST_BROWSER_FILES = \ browser_662743_sample.html \ browser_662812.js \ browser_665702-state_session.js \ browser_682507.js \ browser_687710.js \ browser_687710_2.js \ browser_694378.js \ browser_701377.js \ - browser_705597.js \ - browser_707862.js \ browser_739531.js \ browser_739531_sample.html \ browser_739805.js \ browser_819510_perwindowpb.js \ browser_833286_atomic_backup.js \ $(filter disabled-for-intermittent-failures--bug-766044, browser_459906_empty.html) \ $(filter disabled-for-intermittent-failures--bug-766044, browser_459906_sample.html) \ $(filter disabled-for-intermittent-failures--bug-765389, browser_461743_sample.html) \
--- a/build/mobile/robocop/Makefile.in +++ b/build/mobile/robocop/Makefile.in @@ -8,18 +8,16 @@ srcdir = @srcdir@ VPATH = @srcdir@ mobile-tests := mobile/android/base/tests TESTPATH := $(topsrcdir)/$(mobile-tests) dir-tests := $(DEPTH)/$(mobile-tests) include $(DEPTH)/config/autoconf.mk -ANDROID_APK_NAME := robocop-debug - ROBOTIUM_PATH = $(srcdir)/robotium-solo-3.6.jar JAVAFILES = \ R.java \ $(NULL) RES_FILES = \ res/values/strings.xml \ @@ -78,55 +76,49 @@ MOCHITEST_ROBOCOP_FILES := \ $(wildcard $(TESTPATH)/*.xml) \ $(NULL) GARBAGE += \ AndroidManifest.xml \ $(java-tests-dep) \ $(_JAVA_HARNESS) \ classes.dex \ - $(ANDROID_APK_NAME).ap_ \ - $(ANDROID_APK_NAME)-unsigned-unaligned.apk \ - $(ANDROID_APK_NAME)-unaligned.apk \ - $(ANDROID_APK_NAME).apk \ + robocop.ap_ \ + robocop-debug-signed.apk \ + robocop-debug-signed-unaligned.apk \ $(robocop-deps) \ $(NULL) DEFINES += \ -DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \ $(NULL) JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar:$(ROBOTIUM_PATH) include $(topsrcdir)/config/rules.mk # Override rules.mk java flags with the android specific ones include $(topsrcdir)/config/android-common.mk GENERATED_DIRS_tools = classes $(dir-tests) -tools:: $(ANDROID_APK_NAME).apk +libs:: robocop-debug-signed.apk -classes.dex: $(ANDROID_APK_NAME).ap_ +classes.dex: robocop.ap_ classes.dex: $(robocop-deps) classes.dex: $(java-harness-dep) classes.dex: $(java-tests-dep) $(JAVAC) $(JAVAC_FLAGS) -d classes $(JAVAFILES) $(_JAVA_HARNESS) $(java-tests-dep) $(DX) --dex --output=$@ classes $(ROBOTIUM_PATH) $(ANDROID_COMPT_LIB) -$(ANDROID_APK_NAME).ap_: AndroidManifest.xml $(TESTPATH)/assets/* +robocop.ap_: AndroidManifest.xml $(TESTPATH)/assets/* $(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -I . -S res -A $(TESTPATH)/assets -F $@ -J ./ -$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex - cp $< $@ - $(ZIP) -v0 $@ classes.dex +robocop-debug-signed-unaligned.apk: robocop.ap_ classes.dex + $(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z robocop.ap_ -f classes.dex -$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk - cp $< $@ - $(DEBUG_JARSIGNER) $@ - -$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk - $(ZIPALIGN) -f -v 4 $< $@ +robocop-debug-signed.apk: robocop-debug-signed-unaligned.apk + $(ZIPALIGN) -f -v 4 $^ $@ # PP_java-tests not fully usable here # Intermediate step toward a library rule. $(dir-tests)/%.java: $(TESTPATH)/%.java.in $(call mkdir_deps,$(dir-tests)) $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@
--- a/build/mobile/sutagent/android/Makefile.in +++ b/build/mobile/sutagent/android/Makefile.in @@ -4,18 +4,16 @@ DEPTH = @DEPTH@ topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -ANDROID_APK_NAME := sutAgentAndroid - JAVAFILES = \ AlertLooperThread.java \ ASMozStub.java \ CmdWorkerThread.java \ DataWorkerThread.java \ DoAlert.java \ DoCommand.java \ FindProcThread.java \ @@ -36,44 +34,45 @@ RES_FILES = \ res/drawable/ic_stat_warning.png \ res/layout/main.xml \ res/values/strings.xml \ $(NULL) GARBAGE += \ AndroidManifest.xml \ classes.dex \ - $(ANDROID_APK_NAME).ap_ \ - $(ANDROID_APK_NAME)-unsigned-unaligned.apk \ - $(ANDROID_APK_NAME)-unaligned.apk \ - $(ANDROID_APK_NAME).apk \ + sutAgentAndroid.apk \ + sutAgentAndroid.ap_ \ + sutAgentAndroid-unsigned-unaligned.apk \ + sutAgentAndroid-unaligned.apk \ $(NULL) GARBAGE_DIRS += network-libs EXTRA_JARS = $(srcdir)/network-libs/commons-net-2.0.jar:$(srcdir)/network-libs/jmdns.jar JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar:$(EXTRA_JARS) include $(topsrcdir)/config/rules.mk # include Android specific java flags - using these instead of what's in rules.mk include $(topsrcdir)/config/android-common.mk -tools:: $(ANDROID_APK_NAME).apk +tools:: sutAgentAndroid.apk classes.dex: $(JAVAFILES) $(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(DX) --dex --output=$@ classes $(subst :, ,$(EXTRA_JARS)) -$(ANDROID_APK_NAME).ap_: AndroidManifest.xml +sutAgentAndroid.ap_: $(srcdir)/AndroidManifest.xml $(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@ -$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex - cp $< $@ - $(ZIP) -v0 $@ classes.dex +sutAgentAndroid-unsigned-unaligned.apk: sutAgentAndroid.ap_ classes.dex + $(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z sutAgentAndroid.ap_ -f classes.dex -$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk +sutAgentAndroid-unaligned.apk: sutAgentAndroid-unsigned-unaligned.apk cp $< $@ - $(DEBUG_JARSIGNER) $@ +ifdef JARSIGNER + $(JARSIGNER) $@ +endif -$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk - $(ZIPALIGN) -f -v 4 $< $@ +sutAgentAndroid.apk: sutAgentAndroid-unaligned.apk + $(ZIPALIGN) -f -v 4 sutAgentAndroid-unaligned.apk $@
--- a/build/mobile/sutagent/android/fencp/Makefile.in +++ b/build/mobile/sutagent/android/fencp/Makefile.in @@ -4,18 +4,16 @@ DEPTH = @DEPTH@ topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -ANDROID_APK_NAME := FenCP - JAVAFILES = \ DirCursor.java \ FenCP.java \ FenCPFP.java \ FileCursor.java \ R.java \ $(NULL) @@ -25,42 +23,40 @@ RES_FILES = \ res/drawable-mdpi/icon.png \ res/layout/main.xml \ res/values/strings.xml \ $(NULL) GARBAGE += \ AndroidManifest.xml \ classes.dex \ - $(ANDROID_APK_NAME).ap_ \ - $(ANDROID_APK_NAME)-unsigned-unaligned.apk \ - $(ANDROID_APK_NAME)-unaligned.apk \ - $(ANDROID_APK_NAME).apk \ + FenCP.apk \ $(NULL) GARBAGE_DIRS += network-libs JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar include $(topsrcdir)/config/rules.mk # include Android specific java flags - using these instead of what's in rules.mk include $(topsrcdir)/config/android-common.mk -tools:: $(ANDROID_APK_NAME).apk +tools:: FenCP.apk classes.dex: $(JAVAFILES) $(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(DX) --dex --output=$@ classes -$(ANDROID_APK_NAME).ap_: AndroidManifest.xml - $(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@ +FenCP.ap_: $(srcdir)/AndroidManifest.xml + $(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@ -$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex - cp $< $@ - $(ZIP) -v0 $@ classes.dex +FenCP-unsigned-unaligned.apk: FenCP.ap_ classes.dex + $(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FenCP.ap_ -f classes.dex -$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk - cp $< $@ - $(DEBUG_JARSIGNER) $@ +FenCP-unaligned.apk: FenCP-unsigned-unaligned.apk + cp FenCP-unsigned-unaligned.apk $@ +ifdef JARSIGNER + $(JARSIGNER) $@ +endif -$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk - $(ZIPALIGN) -f -v 4 $< $@ +FenCP.apk: FenCP-unaligned.apk + $(ZIPALIGN) -f -v 4 FenCP-unaligned.apk $@
--- a/build/mobile/sutagent/android/ffxcp/Makefile.in +++ b/build/mobile/sutagent/android/ffxcp/Makefile.in @@ -4,18 +4,16 @@ DEPTH = @DEPTH@ topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -ANDROID_APK_NAME := FfxCP - JAVAFILES = \ DirCursor.java \ ffxcp.java \ FfxCPFP.java \ FileCursor.java \ R.java \ $(NULL) @@ -25,42 +23,40 @@ RES_FILES = \ res/drawable-mdpi/icon.png \ res/layout/main.xml \ res/values/strings.xml \ $(NULL) GARBAGE += \ AndroidManifest.xml \ classes.dex \ - $(ANDROID_APK_NAME).ap_ \ - $(ANDROID_APK_NAME)-unsigned-unaligned.apk \ - $(ANDROID_APK_NAME)-unaligned.apk \ - $(ANDROID_APK_NAME).apk \ + FfxCP.apk \ $(NULL) GARBAGE_DIRS += network-libs JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar include $(topsrcdir)/config/rules.mk # include Android specific java flags - using these instead of what's in rules.mk include $(topsrcdir)/config/android-common.mk -tools:: $(ANDROID_APK_NAME).apk +tools:: FfxCP.apk classes.dex: $(JAVAFILES) $(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(DX) --dex --output=$@ classes -$(ANDROID_APK_NAME).ap_: AndroidManifest.xml - $(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@ +FfxCP.ap_: $(srcdir)/AndroidManifest.xml + $(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@ -$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex - cp $< $@ - $(ZIP) -v0 $@ classes.dex +FfxCP-unsigned-unaligned.apk: FfxCP.ap_ classes.dex + $(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FfxCP.ap_ -f classes.dex -$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk - cp $< $@ - $(DEBUG_JARSIGNER) $@ +FfxCP-unaligned.apk: FfxCP-unsigned-unaligned.apk + cp FfxCP-unsigned-unaligned.apk $@ +ifdef JARSIGNER + $(JARSIGNER) $@ +endif -$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk - $(ZIPALIGN) -f -v 4 $< $@ +FfxCP.apk: FfxCP-unaligned.apk + $(ZIPALIGN) -f -v 4 FfxCP-unaligned.apk $@
--- a/build/mobile/sutagent/android/watcher/Makefile.in +++ b/build/mobile/sutagent/android/watcher/Makefile.in @@ -4,18 +4,16 @@ DEPTH = @DEPTH@ topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -ANDROID_APK_NAME := Watcher - JAVAFILES = \ IWatcherService.java \ RedirOutputThread.java \ R.java \ WatcherMain.java \ WatcherReceiver.java \ WatcherService.java \ $(NULL) @@ -29,43 +27,46 @@ RES_FILES = \ res/drawable-mdpi/ateamlogo.png \ res/layout/main.xml \ res/values/strings.xml \ $(NULL) GARBAGE += \ AndroidManifest.xml \ classes.dex \ - $(ANDROID_APK_NAME).ap_ \ - $(ANDROID_APK_NAME)-unsigned-unaligned.apk \ - $(ANDROID_APK_NAME)-unaligned.apk \ - $(ANDROID_APK_NAME).apk \ + Watcher.apk \ $(NULL) GARBAGE_DIRS += res classes network-libs JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar include $(topsrcdir)/config/rules.mk # include Android specific java flags - using these instead of what's in rules.mk include $(topsrcdir)/config/android-common.mk -tools:: $(ANDROID_APK_NAME).apk +tools:: Watcher.apk classes.dex: $(JAVAFILES) $(NSINSTALL) -D classes $(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(DX) --dex --output=$@ classes -$(ANDROID_APK_NAME).ap_: AndroidManifest.xml - $(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@ +Watcher.ap_: $(srcdir)/AndroidManifest.xml + $(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@ -$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex - cp $< $@ - $(ZIP) -v0 $@ classes.dex +Watcher-unsigned-unaligned.apk: Watcher.ap_ classes.dex + $(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z Watcher.ap_ -f classes.dex -$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk - cp $< $@ - $(DEBUG_JARSIGNER) $@ +Watcher-unaligned.apk: Watcher-unsigned-unaligned.apk + cp Watcher-unsigned-unaligned.apk $@ +ifdef JARSIGNER + $(JARSIGNER) $@ +endif -$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk - $(ZIPALIGN) -f -v 4 $< $@ +Watcher.apk: Watcher-unaligned.apk + $(ZIPALIGN) -f -v 4 Watcher-unaligned.apk $@ + +export:: + $(NSINSTALL) -D res + @(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/sutagent/android/watcher/res && tar -xf -) +
--- a/build/unix/stdc++compat/Makefile.in +++ b/build/unix/stdc++compat/Makefile.in @@ -5,17 +5,16 @@ DEPTH = @DEPTH@ topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk LIBRARY_NAME = stdc++compat -DISABLED_HOST_LIBRARY_NAME = host_stdc++compat FORCE_STATIC_LIB= 1 STL_FLAGS = NO_EXPAND_LIBS = 1 NO_PROFILE_GUIDED_OPTIMIZE = 1 $(NULL) HOST_CPPSRCS = $(CPPSRCS)
--- a/caps/include/nsScriptSecurityManager.h +++ b/caps/include/nsScriptSecurityManager.h @@ -369,17 +369,17 @@ private: nsScriptSecurityManager(); virtual ~nsScriptSecurityManager(); bool SubjectIsPrivileged(); static JSBool CheckObjectAccess(JSContext *cx, JSHandleObject obj, JSHandleId id, JSAccessMode mode, - JSMutableHandleValue vp); + JS::MutableHandle<JS::Value> vp); // Decides, based on CSP, whether or not eval() and stuff can be executed. static JSBool ContentSecurityPolicyPermitsJSAction(JSContext *cx); // Returns null if a principal cannot be found; generally callers // should error out at that point. static nsIPrincipal* doGetObjectPrincipal(JS::Handle<JSObject*> obj);
--- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -481,17 +481,17 @@ nsScriptSecurityManager::ContentSecurity return evalOK; } JSBool nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSHandleObject obj, JSHandleId id, JSAccessMode mode, - JSMutableHandleValue vp) + JS::MutableHandle<JS::Value> vp) { // Get the security manager nsScriptSecurityManager *ssm = nsScriptSecurityManager::GetScriptSecurityManager(); NS_ASSERTION(ssm, "Failed to get security manager service"); if (!ssm) return JS_FALSE;
--- a/config/android-common.mk +++ b/config/android-common.mk @@ -9,19 +9,22 @@ ifndef ANDROID_SDK endif ifndef JAVA_CLASSPATH $(error JAVA_CLASSPATH must be defined before including android-common.mk) endif DX=$(ANDROID_BUILD_TOOLS)/dx AAPT=$(ANDROID_BUILD_TOOLS)/aapt +APKBUILDER=$(ANDROID_SDK)/../../tools/apkbuilder ZIPALIGN=$(ANDROID_SDK)/../../tools/zipalign -# DEBUG_JARSIGNER always debug signs. -DEBUG_JARSIGNER=$(PYTHON) $(call core_abspath,$(topsrcdir)/mobile/android/debug_sign_tool.py) + +ifdef JARSIGNER + APKBUILDER_FLAGS += -u +endif # For Android, this defaults to $(ANDROID_SDK)/android.jar ifndef JAVA_BOOTCLASSPATH JAVA_BOOTCLASSPATH = $(ANDROID_SDK)/android.jar:$(ANDROID_COMPAT_LIB) endif # For Android, we default to 1.5 ifndef JAVA_VERSION
--- a/config/rules.mk +++ b/config/rules.mk @@ -12,16 +12,17 @@ endif # Integrate with mozbuild-generated make files. We first verify that no # variables provided by the automatically generated .mk files are # present. If they are, this is a violation of the separation of # responsibility between Makefile.in and mozbuild files. _MOZBUILD_EXTERNAL_VARIABLES := \ DIRS \ HOST_CSRCS \ + HOST_LIBRARY_NAME \ MODULE \ PARALLEL_DIRS \ TEST_DIRS \ TIERS \ TOOL_DIRS \ XPIDL_MODULE \ $(NULL)
--- a/content/base/public/nsContentCID.h +++ b/content/base/public/nsContentCID.h @@ -38,26 +38,16 @@ // {e7ba1480-1dea-11d3-830f-00104bed045e} #define NS_TEXT_ENCODER_CID \ { 0xe7ba1480, 0x1dea, 0x11d3, {0x83, 0x0f, 0x00, 0x10, 0x4b, 0xed, 0x04, 0x5e} } // {7f915b01-98fc-11d4-8eb0-a803f80ff1bc} #define NS_HTMLCOPY_TEXT_ENCODER_CID \ { 0x7f915b01, 0x98fc, 0x11d4, { 0x8e, 0xb0, 0xa8, 0x03, 0xf8, 0x0f, 0xf1, 0xbc } } -#define NS_HTMLIMAGEELEMENT_CID \ -{ /* d6008c40-4dad-11d2-b328-00805f8a3859 */ \ - 0xd6008c40, 0x4dad, 0x11d2, \ - {0xb3, 0x28, 0x00, 0x80, 0x5f, 0x8a, 0x38, 0x59}} - -#define NS_HTMLOPTIONELEMENT_CID \ -{ /* a6cf90f5-15b3-11d2-932e-00805f8add32 */ \ - 0xa6cf90f5, 0x15b3, 0x11d2, \ - {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}} - #define NS_NAMESPACEMANAGER_CID \ { /* d9783472-8fe9-11d2-9d3c-0060088f9ff7 */ \ 0xd9783472, 0x8fe9, 0x11d2, \ {0x9d, 0x3c, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}} #define NS_CONTENTITERATOR_CID \ {/* {a6cf90e3-15b3-11d2-932e-00805f8add32}*/ \ 0xa6cf90e3, 0x15b3, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32 } }
--- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -272,17 +272,17 @@ public: // Among the sub-classes that inherit (directly or indirectly) from nsINode, // measurement of the following members may be added later if DMD finds it is // worthwhile: // - nsGenericHTMLElement: mForm, mFieldSet // - nsGenericHTMLFrameElement: mFrameLoader (bug 672539) // - HTMLBodyElement: mContentStyleRule // - HTMLDataListElement: mOptions // - HTMLFieldSetElement: mElements, mDependentElements, mFirstLegend - // - nsHTMLFormElement: many! + // - HTMLFormElement: many! // - HTMLFrameSetElement: mRowSpecs, mColSpecs // - HTMLInputElement: mInputData, mFiles, mFileList, mStaticDocfileList // - nsHTMLMapElement: mAreas // - HTMLMediaElement: many! // - nsHTMLOutputElement: mDefaultValue, mTokenList // - nsHTMLRowElement: mCells // - nsHTMLSelectElement: mOptions, mRestoreState // - nsHTMLTableElement: mTBodies, mRows, mTableInheritedAttributes
--- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1860,18 +1860,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns tmp->mRadioGroups.Clear(); // nsDocument has a pretty complex destructor, so we're going to // assume that *most* cycles you actually want to break somewhere // else, and not unlink an awful lot here. tmp->mIdentifierMap.Clear(); - ++tmp->mExpandoAndGeneration.generation; - tmp->mExpandoAndGeneration.expando = JS::UndefinedValue(); + tmp->mExpandoAndGeneration.Unlink(); tmp->mCustomPrototypes.Clear(); if (tmp->mAnimationController) { tmp->mAnimationController->Unlink(); } tmp->mPendingTitleChangeEvent.Revoke();
--- a/content/base/src/nsFormData.cpp +++ b/content/base/src/nsFormData.cpp @@ -1,17 +1,17 @@ /* 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 "nsFormData.h" #include "nsIVariant.h" #include "nsIInputStream.h" #include "nsIDOMFile.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" #include "mozilla/dom/FormDataBinding.h" #include "nsContentUtils.h" using namespace mozilla; using namespace mozilla::dom; nsFormData::nsFormData(nsISupports* aOwner) : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr) @@ -104,23 +104,22 @@ nsFormData::Append(const nsAString& aNam /* virtual */ JSObject* nsFormData::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) { return FormDataBinding::Wrap(aCx, aScope, this); } /* static */ already_AddRefed<nsFormData> nsFormData::Constructor(const GlobalObject& aGlobal, - const Optional<nsHTMLFormElement*>& aFormElement, + const Optional<NonNull<HTMLFormElement> >& aFormElement, ErrorResult& aRv) { nsRefPtr<nsFormData> formData = new nsFormData(aGlobal.Get()); if (aFormElement.WasPassed()) { - MOZ_ASSERT(aFormElement.Value()); - aRv = aFormElement.Value()->WalkFormElements(formData); + aRv = aFormElement.Value().WalkFormElements(formData); } return formData.forget(); } // ------------------------------------------------------------------------- // nsIXHRSendable NS_IMETHODIMP
--- a/content/base/src/nsFormData.h +++ b/content/base/src/nsFormData.h @@ -9,23 +9,23 @@ #include "nsIDOMFormData.h" #include "nsIXMLHttpRequest.h" #include "nsFormSubmission.h" #include "nsWrapperCache.h" #include "nsTArray.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/BindingDeclarations.h" -class nsHTMLFormElement; class nsIDOMFile; namespace mozilla { class ErrorResult; namespace dom { +class HTMLFormElement; class GlobalObject; } // namespace dom } // namespace mozilla class nsFormData : public nsIDOMFormData, public nsIXHRSendable, public nsFormSubmission, public nsWrapperCache @@ -47,17 +47,17 @@ public: // WebIDL nsISupports* GetParentObject() const { return mOwner; } static already_AddRefed<nsFormData> Constructor(const mozilla::dom::GlobalObject& aGlobal, - const mozilla::dom::Optional<nsHTMLFormElement*>& aFormElement, + const mozilla::dom::Optional<mozilla::dom::NonNull<mozilla::dom::HTMLFormElement> >& aFormElement, mozilla::ErrorResult& aRv); void Append(const nsAString& aName, const nsAString& aValue); void Append(const nsAString& aName, nsIDOMBlob* aBlob, const mozilla::dom::Optional<nsAString>& aFilename); // nsFormSubmission virtual nsresult GetEncodedSubmission(nsIURI* aURI, nsIInputStream** aPostDataStream) MOZ_OVERRIDE;
--- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -293,17 +293,17 @@ nsFrameLoader::nsFrameLoader(Element* aO ResetPermissionManagerStatus(); } nsFrameLoader* nsFrameLoader::Create(Element* aOwner, bool aNetworkCreated) { NS_ENSURE_TRUE(aOwner, nullptr); nsIDocument* doc = aOwner->OwnerDoc(); - NS_ENSURE_TRUE(!doc->GetDisplayDocument() && + NS_ENSURE_TRUE(!doc->IsResourceDoc() && ((!doc->IsLoadedAsData() && aOwner->GetCurrentDoc()) || doc->IsStaticDocument()), nullptr); return new nsFrameLoader(aOwner, aNetworkCreated); } NS_IMETHODIMP @@ -1787,17 +1787,17 @@ nsresult nsFrameLoader::GetWindowDimensions(nsRect& aRect) { // Need to get outer window position here nsIDocument* doc = mOwnerContent->GetDocument(); if (!doc) { return NS_ERROR_FAILURE; } - if (doc->GetDisplayDocument()) { + if (doc->IsResourceDoc()) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_GetInterface(doc->GetScriptGlobalObject()); if (!parentAsWebNav) { return NS_ERROR_FAILURE; @@ -1962,17 +1962,17 @@ nsFrameLoader::TryRemoteBrowser() { NS_ASSERTION(!mRemoteBrowser, "TryRemoteBrowser called with a remote browser already?"); nsIDocument* doc = mOwnerContent->GetDocument(); if (!doc) { return false; } - if (doc->GetDisplayDocument()) { + if (doc->IsResourceDoc()) { // Don't allow subframe loads in external reference documents return false; } nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_GetInterface(doc->GetScriptGlobalObject()); if (!parentAsWebNav) {
--- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -1056,18 +1056,50 @@ NS_IMETHODIMP nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType, uint32_t* aType) { *aType = GetTypeOfContent(PromiseFlatCString(aMIMEType)); return NS_OK; } // nsIInterfaceRequestor +// We use a shim class to implement this so that JS consumers still +// see an interface requestor even though WebIDL bindings don't expose +// that stuff. +class ObjectInterfaceRequestorShim MOZ_FINAL : public nsIInterfaceRequestor, + public nsIChannelEventSink +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ObjectInterfaceRequestorShim, + nsIInterfaceRequestor) + NS_DECL_NSIINTERFACEREQUESTOR + NS_FORWARD_NSICHANNELEVENTSINK(mContent->) + + ObjectInterfaceRequestorShim(nsIChannelEventSink* aContent) + : mContent(aContent) + {} + +protected: + nsRefPtr<nsIChannelEventSink> mContent; +}; + +NS_IMPL_CYCLE_COLLECTION_1(ObjectInterfaceRequestorShim, mContent) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ObjectInterfaceRequestorShim) + NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) + NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInterfaceRequestor) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(ObjectInterfaceRequestorShim) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ObjectInterfaceRequestorShim) + NS_IMETHODIMP -nsObjectLoadingContent::GetInterface(const nsIID & aIID, void **aResult) +ObjectInterfaceRequestorShim::GetInterface(const nsIID & aIID, void **aResult) { if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) { nsIChannelEventSink* sink = this; *aResult = sink; NS_ADDREF(sink); return NS_OK; } return NS_NOINTERFACE; @@ -2074,17 +2106,19 @@ nsObjectLoadingContent::OpenChannel() nsCOMPtr<nsIContentSecurityPolicy> csp; rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp)); NS_ENSURE_SUCCESS(rv, rv); if (csp) { channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); channelPolicy->SetContentSecurityPolicy(csp); channelPolicy->SetLoadType(nsIContentPolicy::TYPE_OBJECT); } - rv = NS_NewChannel(getter_AddRefs(chan), mURI, nullptr, group, this, + nsRefPtr<ObjectInterfaceRequestorShim> shim = + new ObjectInterfaceRequestorShim(this); + rv = NS_NewChannel(getter_AddRefs(chan), mURI, nullptr, group, shim, nsIChannel::LOAD_CALL_CONTENT_SNIFFERS | nsIChannel::LOAD_CLASSIFY_URI, channelPolicy); NS_ENSURE_SUCCESS(rv, rv); // Referrer nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan)); if (httpChan) {
--- a/content/base/src/nsObjectLoadingContent.h +++ b/content/base/src/nsObjectLoadingContent.h @@ -11,17 +11,16 @@ */ #ifndef NSOBJECTLOADINGCONTENT_H_ #define NSOBJECTLOADINGCONTENT_H_ #include "mozilla/Attributes.h" #include "nsImageLoadingContent.h" #include "nsIStreamListener.h" -#include "nsIInterfaceRequestor.h" #include "nsIChannelEventSink.h" #include "nsIObjectLoadingContent.h" #include "nsIRunnable.h" #include "nsPluginInstanceOwner.h" #include "nsIThreadInternal.h" #include "nsIFrame.h" #include "nsIFrameLoader.h" @@ -31,17 +30,16 @@ class AutoSetInstantiatingToFalse; class nsObjectFrame; class nsFrameLoader; class nsXULElement; class nsObjectLoadingContent : public nsImageLoadingContent , public nsIStreamListener , public nsIFrameLoaderOwner , public nsIObjectLoadingContent - , public nsIInterfaceRequestor , public nsIChannelEventSink { friend class AutoSetInstantiatingToFalse; friend class AutoSetLoadingToFalse; friend class CheckPluginStopEvent; friend class nsStopPluginRunnable; friend class nsAsyncInstantiateEvent; @@ -95,17 +93,16 @@ class nsObjectLoadingContent : public ns nsObjectLoadingContent(); virtual ~nsObjectLoadingContent(); NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER NS_DECL_NSIFRAMELOADEROWNER NS_DECL_NSIOBJECTLOADINGCONTENT - NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSICHANNELEVENTSINK /** * Object state. This is a bitmask of NS_EVENT_STATEs epresenting the * current state of the object. */ nsEventStates ObjectState() const;
--- a/content/base/test/chrome/test_bug391728.html +++ b/content/base/test/chrome/test_bug391728.html @@ -53,18 +53,18 @@ function init_test() { if (!PluginUtils.withTestPlugin(start_test)) SimpleTest.finish(); } function updateBlocklist(aCallback) { var blocklistNotifier = Components.classes["@mozilla.org/extensions/blocklist;1"] .getService(Components.interfaces.nsITimerCallback); var observer = function() { - aCallback(); Services.obs.removeObserver(observer, "blocklist-updated"); + SimpleTest.executeSoon(aCallback); }; Services.obs.addObserver(observer, "blocklist-updated", false); blocklistNotifier.notify(null); } var _originalBlocklistURL = null; function setAndUpdateBlocklist(aURL, aCallback) { info("Setting blocklist to " + aURL);
--- a/content/events/src/nsIMEStateManager.cpp +++ b/content/events/src/nsIMEStateManager.cpp @@ -26,17 +26,17 @@ #include "nsISelectionListener.h" #include "nsISelectionController.h" #include "nsIMutationObserver.h" #include "nsContentEventHandler.h" #include "nsIObserverService.h" #include "mozilla/Services.h" #include "nsIFormControl.h" #include "nsIForm.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" #include "mozilla/Attributes.h" #include "nsEventDispatcher.h" #include "TextComposition.h" #include "mozilla/Preferences.h" #include "nsAsyncDOMEvent.h" using namespace mozilla; using namespace mozilla::widget; @@ -482,17 +482,17 @@ nsIMEStateManager::SetIMEState(const IME mozilla::dom::Element* formElement = control->GetFormElement(); nsCOMPtr<nsIForm> form; if (control) { // is this a form and does it have a default submit element? if ((form = do_QueryInterface(formElement)) && form->GetDefaultSubmitElement()) { willSubmit = true; // is this an html form and does it only have a single text input element? } else if (formElement && formElement->Tag() == nsGkAtoms::form && formElement->IsHTML() && - static_cast<nsHTMLFormElement*>(formElement)->HasSingleTextControl()) { + static_cast<dom::HTMLFormElement*>(formElement)->HasSingleTextControl()) { willSubmit = true; } } context.mActionHint.Assign(willSubmit ? control->GetType() == NS_FORM_INPUT_SEARCH ? NS_LITERAL_STRING("search") : NS_LITERAL_STRING("go") : formElement ? NS_LITERAL_STRING("next")
--- a/content/html/content/src/HTMLButtonElement.cpp +++ b/content/html/content/src/HTMLButtonElement.cpp @@ -24,17 +24,17 @@ #include "nsIDocument.h" #include "nsGUIEvent.h" #include "nsUnicharUtils.h" #include "nsLayoutUtils.h" #include "nsEventDispatcher.h" #include "nsPresState.h" #include "nsError.h" #include "nsFocusManager.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" #include "mozAutoDocUpdate.h" #define NS_IN_SUBMIT_CLICK (1 << 0) #define NS_OUTER_ACTIVATE_EVENT (1 << 1) NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Button) namespace mozilla { @@ -366,17 +366,17 @@ HTMLButtonElement::PostHandleEvent(nsEve mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) || // We know the element is a submit control, if this check is moved, // make sure formnovalidate is used only if it's a submit control. HasAttr(kNameSpaceID_None, nsGkAtoms::formnovalidate) || mForm->CheckValidFormSubmission())) { // TODO: removing this code and have the submit event sent by the form // see bug 592124. // Hold a strong ref while dispatching - nsRefPtr<nsHTMLFormElement> form(mForm); + nsRefPtr<HTMLFormElement> form(mForm); presShell->HandleDOMEventWithTarget(mForm, &event, &status); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } } } else if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) { // Tell the form to flush a possible pending submission. // the reason is that the script returned false (the event was
--- a/content/html/content/src/HTMLFieldSetElement.h +++ b/content/html/content/src/HTMLFieldSetElement.h @@ -5,17 +5,17 @@ #ifndef mozilla_dom_HTMLFieldSetElement_h #define mozilla_dom_HTMLFieldSetElement_h #include "mozilla/Attributes.h" #include "nsGenericHTMLElement.h" #include "nsIDOMHTMLFieldSetElement.h" #include "nsIConstraintValidation.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" #include "mozilla/dom/ValidityState.h" namespace mozilla { namespace dom { class HTMLFieldSetElement : public nsGenericHTMLFormElement, public nsIDOMHTMLFieldSetElement, public nsIConstraintValidation
rename from content/html/content/src/nsHTMLFormElement.cpp rename to content/html/content/src/HTMLFormElement.cpp --- a/content/html/content/src/nsHTMLFormElement.cpp +++ b/content/html/content/src/HTMLFormElement.cpp @@ -1,13 +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/. */ -#include "nsHTMLFormElement.h" + +#include "mozilla/dom/HTMLFormElement.h" +#include "mozilla/dom/HTMLFormElementBinding.h" #include "nsIHTMLDocument.h" #include "nsEventStateManager.h" #include "nsEventStates.h" #include "nsGkAtoms.h" #include "nsStyleConsts.h" #include "nsPresContext.h" #include "nsIDocument.h" #include "nsIFormControlFrame.h" @@ -52,43 +54,63 @@ #include "nsIDOMHTMLButtonElement.h" #include "mozilla/dom/HTMLCollectionBinding.h" #include "mozilla/dom/BindingUtils.h" #include "nsSandboxFlags.h" // images #include "mozilla/dom/HTMLImageElement.h" -using namespace mozilla::dom; +DOMCI_NODE_DATA(HTMLFormElement, mozilla::dom::HTMLFormElement) + +// construction, destruction +nsGenericHTMLElement* +NS_NewHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo, + mozilla::dom::FromParser aFromParser) +{ + mozilla::dom::HTMLFormElement* it = new mozilla::dom::HTMLFormElement(aNodeInfo); + + nsresult rv = it->Init(); + + if (NS_FAILED(rv)) { + delete it; + return nullptr; + } + + return it; +} + +namespace mozilla { +namespace dom { static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16; static const uint8_t NS_FORM_AUTOCOMPLETE_ON = 1; static const uint8_t NS_FORM_AUTOCOMPLETE_OFF = 0; static const nsAttrValue::EnumTable kFormAutocompleteTable[] = { { "on", NS_FORM_AUTOCOMPLETE_ON }, { "off", NS_FORM_AUTOCOMPLETE_OFF }, { 0 } }; // Default autocomplete value is 'on'. static const nsAttrValue::EnumTable* kFormDefaultAutocomplete = &kFormAutocompleteTable[0]; -// nsHTMLFormElement - -bool nsHTMLFormElement::gFirstFormSubmitted = false; -bool nsHTMLFormElement::gPasswordManagerInitialized = false; +// HTMLFormElement + +bool HTMLFormElement::gFirstFormSubmitted = false; +bool HTMLFormElement::gPasswordManagerInitialized = false; // nsFormControlList class nsFormControlList : public nsIHTMLCollection, public nsWrapperCache { public: - nsFormControlList(nsHTMLFormElement* aForm); + nsFormControlList(HTMLFormElement* aForm); virtual ~nsFormControlList(); nsresult Init(); void DropFormReference(); NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -129,17 +151,17 @@ public: // nsWrapperCache virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) MOZ_OVERRIDE { return HTMLCollectionBinding::Wrap(cx, scope, this); } - nsHTMLFormElement* mForm; // WEAK - the form owns me + HTMLFormElement* mForm; // WEAK - the form owns me nsTArray<nsGenericHTMLFormElement*> mElements; // Holds WEAK references - bug 36639 // This array holds on to all form controls that are not contained // in mElements (form.elements in JS, see ShouldBeInFormControl()). // This is needed to properly clean up the bi-directional references // (both weak and strong) between the form and its form controls. @@ -204,36 +226,19 @@ ShouldBeInElements(nsIFormControl* aForm // form.elements array // // NS_FORM_INPUT_IMAGE // NS_FORM_LABEL return false; } -// nsHTMLFormElement implementation - -// construction, destruction -nsGenericHTMLElement* -NS_NewHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo, - FromParser aFromParser) -{ - nsHTMLFormElement* it = new nsHTMLFormElement(aNodeInfo); - - nsresult rv = it->Init(); - - if (NS_FAILED(rv)) { - delete it; - return nullptr; - } - - return it; -} - -nsHTMLFormElement::nsHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo) +// HTMLFormElement implementation + +HTMLFormElement::HTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo) : nsGenericHTMLElement(aNodeInfo), mGeneratingSubmit(false), mGeneratingReset(false), mIsSubmitting(false), mDeferSubmission(false), mNotifiedObservers(false), mNotifiedObserversResult(false), mSubmitPopupState(openAbused), @@ -243,29 +248,31 @@ nsHTMLFormElement::nsHTMLFormElement(alr mDefaultSubmitElement(nullptr), mFirstSubmitInElements(nullptr), mFirstSubmitNotInElements(nullptr), mInvalidElementsCount(0), mEverTriedInvalidSubmit(false) { mImageNameLookupTable.Init(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE); mPastNameLookupTable.Init(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE); + + SetIsDOMBinding(); } -nsHTMLFormElement::~nsHTMLFormElement() +HTMLFormElement::~HTMLFormElement() { if (mControls) { mControls->DropFormReference(); } Clear(); } nsresult -nsHTMLFormElement::Init() +HTMLFormElement::Init() { mControls = new nsFormControlList(this); if (!mControls) { return NS_ERROR_OUT_OF_MEMORY; } nsresult rv = mControls->Init(); @@ -291,64 +298,76 @@ ElementTraverser(const nsAString& key, n { nsCycleCollectionTraversalCallback *cb = static_cast<nsCycleCollectionTraversalCallback*>(userArg); cb->NoteXPCOMChild(element); return PL_DHASH_NEXT; } -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLFormElement, +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLFormElement, nsGenericHTMLElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControls) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageNameLookupTable) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPastNameLookupTable) tmp->mSelectedRadioButtons.EnumerateRead(ElementTraverser, &cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLFormElement, +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLFormElement, nsGenericHTMLElement) tmp->Clear(); + tmp->mExpandoAndGeneration.Unlink(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_IMPL_ADDREF_INHERITED(nsHTMLFormElement, Element) -NS_IMPL_RELEASE_INHERITED(nsHTMLFormElement, Element) - - -DOMCI_NODE_DATA(HTMLFormElement, nsHTMLFormElement) - -// QueryInterface implementation for nsHTMLFormElement -NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLFormElement) +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(HTMLFormElement, + nsGenericHTMLElement) + if (tmp->PreservingWrapper()) { + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration.expando); + } +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_ADDREF_INHERITED(HTMLFormElement, Element) +NS_IMPL_RELEASE_INHERITED(HTMLFormElement, Element) + + +// QueryInterface implementation for HTMLFormElement +NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLFormElement) NS_HTML_CONTENT_INTERFACES(nsGenericHTMLElement) - NS_INTERFACE_TABLE_INHERITED4(nsHTMLFormElement, + NS_INTERFACE_TABLE_INHERITED4(HTMLFormElement, nsIDOMHTMLFormElement, nsIForm, nsIWebProgressListener, nsIRadioGroupContainer) NS_INTERFACE_TABLE_TO_MAP_SEGUE NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLFormElement) NS_ELEMENT_INTERFACE_MAP_END // nsIDOMHTMLFormElement -NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsHTMLFormElement) +NS_IMPL_ELEMENT_CLONE_WITH_INIT(HTMLFormElement) + +nsIHTMLCollection* +HTMLFormElement::Elements() +{ + return mControls; +} NS_IMETHODIMP -nsHTMLFormElement::GetElements(nsIDOMHTMLCollection** aElements) +HTMLFormElement::GetElements(nsIDOMHTMLCollection** aElements) { - *aElements = mControls; + *aElements = Elements(); NS_ADDREF(*aElements); return NS_OK; } nsresult -nsHTMLFormElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName, - nsIAtom* aPrefix, const nsAString& aValue, - bool aNotify) +HTMLFormElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName, + nsIAtom* aPrefix, const nsAString& aValue, + bool aNotify) { if ((aName == nsGkAtoms::action || aName == nsGkAtoms::target) && aNameSpaceID == kNameSpaceID_None) { if (mPendingSubmission) { // aha, there is a pending submission that means we're in // the script and we need to flush it. let's tell it // that the event was ignored to force the flush. // the second argument is not playing a role at all. @@ -360,18 +379,18 @@ nsHTMLFormElement::SetAttr(int32_t aName ForgetCurrentSubmission(); mNotifiedObservers = notifiedObservers; } return nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue, aNotify); } nsresult -nsHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, - const nsAttrValue* aValue, bool aNotify) +HTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, + const nsAttrValue* aValue, bool aNotify) { if (aName == nsGkAtoms::novalidate && aNameSpaceID == kNameSpaceID_None) { // Update all form elements states because they might be [no longer] // affected by :-moz-ui-valid or :-moz-ui-invalid. for (uint32_t i = 0, length = mControls->mElements.Length(); i < length; ++i) { mControls->mElements[i]->UpdateState(true); } @@ -380,67 +399,73 @@ nsHTMLFormElement::AfterSetAttr(int32_t i < length; ++i) { mControls->mNotInElements[i]->UpdateState(true); } } return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify); } -NS_IMPL_STRING_ATTR(nsHTMLFormElement, AcceptCharset, acceptcharset) -NS_IMPL_ACTION_ATTR(nsHTMLFormElement, Action, action) -NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Autocomplete, autocomplete, +NS_IMPL_STRING_ATTR(HTMLFormElement, AcceptCharset, acceptcharset) +NS_IMPL_ACTION_ATTR(HTMLFormElement, Action, action) +NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLFormElement, Autocomplete, autocomplete, kFormDefaultAutocomplete->tag) -NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Enctype, enctype, +NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLFormElement, Enctype, enctype, kFormDefaultEnctype->tag) -NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Method, method, +NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLFormElement, Method, method, kFormDefaultMethod->tag) -NS_IMPL_BOOL_ATTR(nsHTMLFormElement, NoValidate, novalidate) -NS_IMPL_STRING_ATTR(nsHTMLFormElement, Name, name) -NS_IMPL_STRING_ATTR(nsHTMLFormElement, Target, target) - -NS_IMETHODIMP -nsHTMLFormElement::Submit() +NS_IMPL_BOOL_ATTR(HTMLFormElement, NoValidate, novalidate) +NS_IMPL_STRING_ATTR(HTMLFormElement, Name, name) +NS_IMPL_STRING_ATTR(HTMLFormElement, Target, target) + +void +HTMLFormElement::Submit(ErrorResult& aRv) { // Send the submit event - nsresult rv = NS_OK; nsRefPtr<nsPresContext> presContext = GetPresContext(); if (mPendingSubmission) { // aha, we have a pending submission that was not flushed // (this happens when form.submit() is called twice) // we have to delete it and build a new one since values // might have changed inbetween (we emulate IE here, that's all) mPendingSubmission = nullptr; } - rv = DoSubmitOrReset(nullptr, NS_FORM_SUBMIT); - return rv; + aRv = DoSubmitOrReset(nullptr, NS_FORM_SUBMIT); } NS_IMETHODIMP -nsHTMLFormElement::Reset() +HTMLFormElement::Submit() +{ + ErrorResult rv; + Submit(rv); + return rv.ErrorCode(); +} + +NS_IMETHODIMP +HTMLFormElement::Reset() { nsFormEvent event(true, NS_FORM_RESET); nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this), nullptr, &event); return NS_OK; } NS_IMETHODIMP -nsHTMLFormElement::CheckValidity(bool* retVal) +HTMLFormElement::CheckValidity(bool* retVal) { - *retVal = CheckFormValidity(nullptr); + *retVal = CheckValidity(); return NS_OK; } bool -nsHTMLFormElement::ParseAttribute(int32_t aNamespaceID, - nsIAtom* aAttribute, - const nsAString& aValue, - nsAttrValue& aResult) +HTMLFormElement::ParseAttribute(int32_t aNamespaceID, + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult) { if (aNamespaceID == kNameSpaceID_None) { if (aAttribute == nsGkAtoms::method) { return aResult.ParseEnumValue(aValue, kFormMethodTable, false); } if (aAttribute == nsGkAtoms::enctype) { return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false); } @@ -449,19 +474,19 @@ nsHTMLFormElement::ParseAttribute(int32_ } } return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue, aResult); } nsresult -nsHTMLFormElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, - nsIContent* aBindingParent, - bool aCompileEventHandlers) +HTMLFormElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + bool aCompileEventHandlers) { nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, aBindingParent, aCompileEventHandlers); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(aDocument)); if (htmlDoc) { @@ -563,17 +588,17 @@ CollectOrphans(nsINode* aRemovalRoot, nsCOMPtr<nsIDOMHTMLFormElement> form = node->GetForm(); NS_ASSERTION(form == aThisForm, "How did that happen?"); } #endif /* DEBUG */ } } void -nsHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent) +HTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent) { nsCOMPtr<nsIHTMLDocument> oldDocument = do_QueryInterface(GetCurrentDoc()); // Mark all of our controls as maybe being orphans MarkOrphans(mControls->mElements); MarkOrphans(mControls->mNotInElements); MarkOrphans(mImageElements); @@ -607,17 +632,17 @@ nsHTMLFormElement::UnbindFromTree(bool a if (oldDocument) { oldDocument->RemovedForm(); } ForgetCurrentSubmission(); } nsresult -nsHTMLFormElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor) +HTMLFormElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor) { aVisitor.mWantsWillHandleEvent = true; if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) { uint32_t msg = aVisitor.mEvent->message; if (msg == NS_FORM_SUBMIT) { if (mGeneratingSubmit) { aVisitor.mCanHandle = false; return NS_OK; @@ -636,32 +661,32 @@ nsHTMLFormElement::PreHandleEvent(nsEven } mGeneratingReset = true; } } return nsGenericHTMLElement::PreHandleEvent(aVisitor); } nsresult -nsHTMLFormElement::WillHandleEvent(nsEventChainPostVisitor& aVisitor) +HTMLFormElement::WillHandleEvent(nsEventChainPostVisitor& aVisitor) { // If this is the bubble stage and there is a nested form below us which // received a submit event we do *not* want to handle the submit event // for this form too. if ((aVisitor.mEvent->message == NS_FORM_SUBMIT || aVisitor.mEvent->message == NS_FORM_RESET) && aVisitor.mEvent->mFlags.mInBubblingPhase && aVisitor.mEvent->originalTarget != static_cast<nsIContent*>(this)) { aVisitor.mEvent->mFlags.mPropagationStopped = true; } return NS_OK; } nsresult -nsHTMLFormElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor) +HTMLFormElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor) { if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) { uint32_t msg = aVisitor.mEvent->message; if (msg == NS_FORM_SUBMIT) { // let the form know not to defer subsequent submissions mDeferSubmission = false; } @@ -698,18 +723,18 @@ nsHTMLFormElement::PostHandleEvent(nsEve else if (msg == NS_FORM_RESET) { mGeneratingReset = false; } } return NS_OK; } nsresult -nsHTMLFormElement::DoSubmitOrReset(nsEvent* aEvent, - int32_t aMessage) +HTMLFormElement::DoSubmitOrReset(nsEvent* aEvent, + int32_t aMessage) { // Make sure the presentation is up-to-date nsIDocument* doc = GetCurrentDoc(); if (doc) { doc->FlushPendingNotifications(Flush_ContentAndNotify); } // JBK Don't get form frames anymore - bug 34297 @@ -728,17 +753,17 @@ nsHTMLFormElement::DoSubmitOrReset(nsEve return DoSubmit(aEvent); } MOZ_ASSERT(false); return NS_OK; } nsresult -nsHTMLFormElement::DoReset() +HTMLFormElement::DoReset() { // JBK walk the elements[] array instead of form frame controls - bug 34297 uint32_t numElements = GetElementCount(); for (uint32_t elementX = 0; elementX < numElements; ++elementX) { // Hold strong ref in case the reset does something weird nsCOMPtr<nsIFormControl> controlNode = GetElementAt(elementX); if (controlNode) { controlNode->Reset(); @@ -750,17 +775,17 @@ nsHTMLFormElement::DoReset() #define NS_ENSURE_SUBMIT_SUCCESS(rv) \ if (NS_FAILED(rv)) { \ ForgetCurrentSubmission(); \ return rv; \ } nsresult -nsHTMLFormElement::DoSubmit(nsEvent* aEvent) +HTMLFormElement::DoSubmit(nsEvent* aEvent) { NS_ASSERTION(GetCurrentDoc(), "Should never get here without a current doc"); if (mIsSubmitting) { NS_WARNING("Preventing double form submission"); // XXX Should this return an error? return NS_OK; } @@ -804,18 +829,18 @@ nsHTMLFormElement::DoSubmit(nsEvent* aEv // // perform the submission // return SubmitSubmission(submission); } nsresult -nsHTMLFormElement::BuildSubmission(nsFormSubmission** aFormSubmission, - nsEvent* aEvent) +HTMLFormElement::BuildSubmission(nsFormSubmission** aFormSubmission, + nsEvent* aEvent) { NS_ASSERTION(!mPendingSubmission, "tried to build two submissions!"); // Get the originating frame (failure is non-fatal) nsGenericHTMLElement* originatingElement = nullptr; if (aEvent) { if (NS_FORM_EVENT == aEvent->eventStructType) { nsIContent* originator = ((nsFormEvent *)aEvent)->originator; @@ -842,17 +867,17 @@ nsHTMLFormElement::BuildSubmission(nsFor // rv = WalkFormElements(*aFormSubmission); NS_ENSURE_SUBMIT_SUCCESS(rv); return NS_OK; } nsresult -nsHTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission) +HTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission) { nsresult rv; nsIContent* originatingElement = aFormSubmission->GetOriginatingElement(); // // Get the action and target // nsCOMPtr<nsIURI> actionURI; @@ -976,19 +1001,19 @@ nsHTMLFormElement::SubmitSubmission(nsFo } else { ForgetCurrentSubmission(); } return rv; } nsresult -nsHTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL, - bool* aCancelSubmit, - bool aEarlyNotify) +HTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL, + bool* aCancelSubmit, + bool aEarlyNotify) { // If this is the first form, bring alive the first form submit // category observers if (!gFirstFormSubmitted) { gFirstFormSubmitted = true; NS_CreateServicesFromCategory(NS_FIRST_FORMSUBMIT_CATEGORY, nullptr, NS_FIRST_FORMSUBMIT_CATEGORY); @@ -1035,17 +1060,17 @@ nsHTMLFormElement::NotifySubmitObservers } } return rv; } nsresult -nsHTMLFormElement::WalkFormElements(nsFormSubmission* aFormSubmission) +HTMLFormElement::WalkFormElements(nsFormSubmission* aFormSubmission) { nsTArray<nsGenericHTMLFormElement*> sortedControls; nsresult rv = mControls->GetSortedControls(sortedControls); NS_ENSURE_SUCCESS(rv, rv); uint32_t len = sortedControls.Length(); // Hold a reference to the elements so they can't be deleted while @@ -1068,25 +1093,33 @@ nsHTMLFormElement::WalkFormElements(nsFo } return NS_OK; } // nsIForm NS_IMETHODIMP_(uint32_t) -nsHTMLFormElement::GetElementCount() const +HTMLFormElement::GetElementCount() const { uint32_t count = 0; mControls->GetLength(&count); return count; } +Element* +HTMLFormElement::IndexedGetter(uint32_t aIndex, bool &aFound) +{ + Element* element = mControls->mElements.SafeElementAt(aIndex, nullptr); + aFound = element != nullptr; + return element; +} + NS_IMETHODIMP_(nsIFormControl*) -nsHTMLFormElement::GetElementAt(int32_t aIndex) const +HTMLFormElement::GetElementAt(int32_t aIndex) const { return mControls->mElements.SafeElementAt(aIndex, nullptr); } /** * Compares the position of aControl1 and aControl2 in the document * @param aControl1 First control to compare. * @param aControl2 Second control to compare. @@ -1149,17 +1182,17 @@ AssertDocumentOrder(const nsTArray<nsGen aForm) < 0, "Form controls not ordered correctly"); } } } #endif void -nsHTMLFormElement::PostPasswordEvent() +HTMLFormElement::PostPasswordEvent() { // Don't fire another add event if we have a pending add event. if (mFormPasswordEvent.get()) { return; } nsRefPtr<FormPasswordEvent> event = new FormPasswordEvent(this, NS_LITERAL_STRING("DOMFormHasPassword")); @@ -1167,17 +1200,17 @@ nsHTMLFormElement::PostPasswordEvent() event->PostDOMEvent(); } // This function return true if the element, once appended, is the last one in // the array. template<typename ElementType> static bool AddElementToList(nsTArray<ElementType*>& aList, ElementType* aChild, - nsHTMLFormElement* aForm) + HTMLFormElement* aForm) { NS_ASSERTION(aList.IndexOf(aChild) == aList.NoIndex, "aChild already in aList"); uint32_t count = aList.Length(); ElementType* element; bool lastElement = false; @@ -1214,18 +1247,18 @@ AddElementToList(nsTArray<ElementType*>& // WEAK - don't addref aList.InsertElementAt(low, aChild); } return lastElement; } nsresult -nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild, - bool aUpdateValidity, bool aNotify) +HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild, + bool aUpdateValidity, bool aNotify) { // If an element has a @form, we can assume it *might* be able to not have // a parent and still be in the form. NS_ASSERTION(aChild->HasAttr(kNameSpaceID_None, nsGkAtoms::form) || aChild->GetParent(), "Form control should have a parent"); // Determine whether to add the new element to the elements or @@ -1319,26 +1352,26 @@ nsHTMLFormElement::AddElement(nsGenericH static_cast<HTMLInputElement*>(aChild); radio->AddedToRadioGroup(); } return NS_OK; } nsresult -nsHTMLFormElement::AddElementToTable(nsGenericHTMLFormElement* aChild, - const nsAString& aName) +HTMLFormElement::AddElementToTable(nsGenericHTMLFormElement* aChild, + const nsAString& aName) { return mControls->AddElementToTable(aChild, aName); } nsresult -nsHTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild, - bool aUpdateValidity) +HTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild, + bool aUpdateValidity) { // // Remove it from the radio group if it's a radio button // nsresult rv = NS_OK; if (aChild->GetType() == NS_FORM_INPUT_RADIO) { nsRefPtr<HTMLInputElement> radio = static_cast<HTMLInputElement*>(aChild); @@ -1396,17 +1429,17 @@ nsHTMLFormElement::RemoveElement(nsGener UpdateValidity(true); } } return rv; } void -nsHTMLFormElement::HandleDefaultSubmitRemoval() +HTMLFormElement::HandleDefaultSubmitRemoval() { if (mDefaultSubmitElement) { // Already got reset somehow; nothing else to do here return; } if (!mFirstSubmitNotInElements) { mDefaultSubmitElement = mFirstSubmitInElements; @@ -1427,30 +1460,31 @@ nsHTMLFormElement::HandleDefaultSubmitRe "What happened here?"); // Notify about change if needed. if (mDefaultSubmitElement) { mDefaultSubmitElement->UpdateState(true); } } -static nsresult -RemoveElementFromTableInternal( +nsresult +HTMLFormElement::RemoveElementFromTableInternal( nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable, nsIContent* aChild, const nsAString& aName) { nsCOMPtr<nsISupports> supports; if (!aTable.Get(aName, getter_AddRefs(supports))) return NS_OK; // Single element in the hash, just remove it if it's the one // we're trying to remove... if (supports == aChild) { aTable.Remove(aName); + ++mExpandoAndGeneration.generation; return NS_OK; } nsCOMPtr<nsIContent> content(do_QueryInterface(supports)); if (content) { return NS_OK; } @@ -1464,16 +1498,17 @@ RemoveElementFromTableInternal( uint32_t length = 0; list->GetLength(&length); if (!length) { // If the list is empty we remove if from our hash, this shouldn't // happen tho aTable.Remove(aName); + ++mExpandoAndGeneration.generation; } else if (length == 1) { // Only one element left, replace the list in the hash with the // single element. nsIContent* node = list->Item(0); if (node) { aTable.Put(aName, node); } } @@ -1485,68 +1520,92 @@ static PLDHashOperator RemovePastNames(const nsAString& aName, nsCOMPtr<nsISupports>& aData, void* aClosure) { return aClosure == aData ? PL_DHASH_REMOVE : PL_DHASH_NEXT; } nsresult -nsHTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement, - const nsAString& aName, - RemoveElementReason aRemoveReason) +HTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement, + const nsAString& aName, + RemoveElementReason aRemoveReason) { // If the element is being removed from the form, we have to remove it from // the past names map. if (aRemoveReason == ElementRemoved) { + uint32_t oldCount = mPastNameLookupTable.Count(); mPastNameLookupTable.Enumerate(RemovePastNames, aElement); + if (oldCount != mPastNameLookupTable.Count()) { + ++mExpandoAndGeneration.generation; + } } return mControls->RemoveElementFromTable(aElement, aName); } already_AddRefed<nsISupports> -nsHTMLFormElement::FindNamedItem(const nsAString& aName, - nsWrapperCache** aCache) +HTMLFormElement::NamedGetter(const nsAString& aName, bool &aFound) { + aFound = true; + nsCOMPtr<nsISupports> result = DoResolveName(aName, true); if (result) { - // FIXME Get the wrapper cache from DoResolveName. - *aCache = nullptr; AddToPastNamesMap(aName, result); return result.forget(); } result = mImageNameLookupTable.GetWeak(aName); if (result) { - *aCache = nullptr; AddToPastNamesMap(aName, result); return result.forget(); } result = mPastNameLookupTable.GetWeak(aName); if (result) { + return result.forget(); + } + + aFound = false; + return nullptr; +} + +void +HTMLFormElement::GetSupportedNames(nsTArray<nsString >& aRetval) +{ + // TODO https://www.w3.org/Bugs/Public/show_bug.cgi?id=22320 +} + +already_AddRefed<nsISupports> +HTMLFormElement::FindNamedItem(const nsAString& aName, + nsWrapperCache** aCache) +{ + // FIXME Get the wrapper cache from DoResolveName. + + bool found; + nsCOMPtr<nsISupports> result = NamedGetter(aName, found); + if (result) { *aCache = nullptr; return result.forget(); } return nullptr; } already_AddRefed<nsISupports> -nsHTMLFormElement::DoResolveName(const nsAString& aName, - bool aFlushContent) +HTMLFormElement::DoResolveName(const nsAString& aName, + bool aFlushContent) { nsCOMPtr<nsISupports> result = mControls->NamedItemInternal(aName, aFlushContent); return result.forget(); } void -nsHTMLFormElement::OnSubmitClickBegin(nsIContent* aOriginatingElement) +HTMLFormElement::OnSubmitClickBegin(nsIContent* aOriginatingElement) { mDeferSubmission = true; // Prepare to run NotifySubmitObservers early before the // scripts on the page get to modify the form data, possibly // throwing off any password manager. (bug 257781) nsCOMPtr<nsIURI> actionURI; nsresult rv; @@ -1564,36 +1623,36 @@ nsHTMLFormElement::OnSubmitClickBegin(ns if (NS_SUCCEEDED(rv)) { mNotifiedObservers = true; mNotifiedObserversResult = cancelSubmit; } } } void -nsHTMLFormElement::OnSubmitClickEnd() +HTMLFormElement::OnSubmitClickEnd() { mDeferSubmission = false; } void -nsHTMLFormElement::FlushPendingSubmission() +HTMLFormElement::FlushPendingSubmission() { if (mPendingSubmission) { // Transfer owning reference so that the submissioin doesn't get deleted // if we reenter nsAutoPtr<nsFormSubmission> submission = mPendingSubmission; SubmitSubmission(submission); } } nsresult -nsHTMLFormElement::GetActionURL(nsIURI** aActionURL, - nsIContent* aOriginatingElement) +HTMLFormElement::GetActionURL(nsIURI** aActionURL, + nsIContent* aOriginatingElement) { nsresult rv = NS_OK; *aActionURL = nullptr; // // Grab the URL string // @@ -1688,27 +1747,27 @@ nsHTMLFormElement::GetActionURL(nsIURI** // *aActionURL = actionURL; NS_ADDREF(*aActionURL); return rv; } NS_IMETHODIMP_(nsIFormControl*) -nsHTMLFormElement::GetDefaultSubmitElement() const +HTMLFormElement::GetDefaultSubmitElement() const { NS_PRECONDITION(mDefaultSubmitElement == mFirstSubmitInElements || mDefaultSubmitElement == mFirstSubmitNotInElements, "What happened here?"); return mDefaultSubmitElement; } bool -nsHTMLFormElement::IsDefaultSubmitElement(const nsIFormControl* aControl) const +HTMLFormElement::IsDefaultSubmitElement(const nsIFormControl* aControl) const { NS_PRECONDITION(aControl, "Unexpected call"); if (aControl == mDefaultSubmitElement) { // Yes, it is return true; } @@ -1733,65 +1792,69 @@ nsHTMLFormElement::IsDefaultSubmitElemen nsIFormControl* defaultSubmit = CompareFormControlPosition(mFirstSubmitInElements, mFirstSubmitNotInElements, this) < 0 ? mFirstSubmitInElements : mFirstSubmitNotInElements; return aControl == defaultSubmit; } bool -nsHTMLFormElement::HasSingleTextControl() const +HTMLFormElement::HasSingleTextControl() const { // Input text controls are always in the elements list. uint32_t numTextControlsFound = 0; uint32_t length = mControls->mElements.Length(); for (uint32_t i = 0; i < length && numTextControlsFound < 2; ++i) { if (mControls->mElements[i]->IsSingleLineTextControl(false)) { numTextControlsFound++; } } return numTextControlsFound == 1; } NS_IMETHODIMP -nsHTMLFormElement::GetEncoding(nsAString& aEncoding) +HTMLFormElement::GetEncoding(nsAString& aEncoding) { return GetEnctype(aEncoding); } NS_IMETHODIMP -nsHTMLFormElement::SetEncoding(const nsAString& aEncoding) +HTMLFormElement::SetEncoding(const nsAString& aEncoding) { return SetEnctype(aEncoding); } +int32_t +HTMLFormElement::Length() +{ + return mControls->Length(); +} + NS_IMETHODIMP -nsHTMLFormElement::GetLength(int32_t* aLength) +HTMLFormElement::GetLength(int32_t* aLength) { - uint32_t length; - nsresult rv = mControls->GetLength(&length); - *aLength = length; - return rv; + *aLength = Length(); + return NS_OK; } void -nsHTMLFormElement::ForgetCurrentSubmission() +HTMLFormElement::ForgetCurrentSubmission() { mNotifiedObservers = false; mIsSubmitting = false; mSubmittingRequest = nullptr; nsCOMPtr<nsIWebProgress> webProgress = do_QueryReferent(mWebProgress); if (webProgress) { webProgress->RemoveProgressListener(this); } mWebProgress = nullptr; } bool -nsHTMLFormElement::CheckFormValidity(nsIMutableArray* aInvalidElements) const +HTMLFormElement::CheckFormValidity(nsIMutableArray* aInvalidElements) const { bool ret = true; nsTArray<nsGenericHTMLFormElement*> sortedControls; if (NS_FAILED(mControls->GetSortedControls(sortedControls))) { return false; } @@ -1828,17 +1891,17 @@ nsHTMLFormElement::CheckFormValidity(nsI for (uint32_t i = 0; i < len; ++i) { static_cast<nsGenericHTMLElement*>(sortedControls[i])->Release(); } return ret; } bool -nsHTMLFormElement::CheckValidFormSubmission() +HTMLFormElement::CheckValidFormSubmission() { /** * Check for form validity: do not submit a form if there are unhandled * invalid controls in the form. * This should not be done if the form has been submitted with .submit(). * * NOTE: for the moment, we are also checking that there is an observer for * NS_INVALIDFORMSUBMIT_SUBJECT so it will prevent blocking form submission @@ -1943,17 +2006,17 @@ nsHTMLFormElement::CheckValidFormSubmiss NS_WARNING("There is no observer for \"invalidformsubmit\". \ One should be implemented!"); } return true; } void -nsHTMLFormElement::UpdateValidity(bool aElementValidity) +HTMLFormElement::UpdateValidity(bool aElementValidity) { if (aElementValidity) { --mInvalidElementsCount; } else { ++mInvalidElementsCount; } NS_ASSERTION(mInvalidElementsCount >= 0, "Something went seriously wrong!"); @@ -1993,99 +2056,99 @@ nsHTMLFormElement::UpdateValidity(bool a } } UpdateState(true); } // nsIWebProgressListener NS_IMETHODIMP -nsHTMLFormElement::OnStateChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - uint32_t aStateFlags, - nsresult aStatus) +HTMLFormElement::OnStateChange(nsIWebProgress* aWebProgress, + nsIRequest* aRequest, + uint32_t aStateFlags, + nsresult aStatus) { // If STATE_STOP is never fired for any reason (redirect? Failed state // change?) the form element will leak. It will be kept around by the // nsIWebProgressListener (assuming it keeps a strong pointer). We will // consequently leak the request. if (aRequest == mSubmittingRequest && aStateFlags & nsIWebProgressListener::STATE_STOP) { ForgetCurrentSubmission(); } return NS_OK; } NS_IMETHODIMP -nsHTMLFormElement::OnProgressChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - int32_t aCurSelfProgress, - int32_t aMaxSelfProgress, - int32_t aCurTotalProgress, - int32_t aMaxTotalProgress) +HTMLFormElement::OnProgressChange(nsIWebProgress* aWebProgress, + nsIRequest* aRequest, + int32_t aCurSelfProgress, + int32_t aMaxSelfProgress, + int32_t aCurTotalProgress, + int32_t aMaxTotalProgress) { NS_NOTREACHED("notification excluded in AddProgressListener(...)"); return NS_OK; } NS_IMETHODIMP -nsHTMLFormElement::OnLocationChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - nsIURI* location, - uint32_t aFlags) +HTMLFormElement::OnLocationChange(nsIWebProgress* aWebProgress, + nsIRequest* aRequest, + nsIURI* location, + uint32_t aFlags) { NS_NOTREACHED("notification excluded in AddProgressListener(...)"); return NS_OK; } NS_IMETHODIMP -nsHTMLFormElement::OnStatusChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - nsresult aStatus, - const PRUnichar* aMessage) +HTMLFormElement::OnStatusChange(nsIWebProgress* aWebProgress, + nsIRequest* aRequest, + nsresult aStatus, + const PRUnichar* aMessage) { NS_NOTREACHED("notification excluded in AddProgressListener(...)"); return NS_OK; } NS_IMETHODIMP -nsHTMLFormElement::OnSecurityChange(nsIWebProgress* aWebProgress, - nsIRequest* aRequest, - uint32_t state) +HTMLFormElement::OnSecurityChange(nsIWebProgress* aWebProgress, + nsIRequest* aRequest, + uint32_t state) { NS_NOTREACHED("notification excluded in AddProgressListener(...)"); return NS_OK; } NS_IMETHODIMP_(int32_t) -nsHTMLFormElement::IndexOfControl(nsIFormControl* aControl) +HTMLFormElement::IndexOfControl(nsIFormControl* aControl) { int32_t index = 0; return mControls->IndexOfControl(aControl, &index) == NS_OK ? index : 0; } void -nsHTMLFormElement::SetCurrentRadioButton(const nsAString& aName, - nsIDOMHTMLInputElement* aRadio) +HTMLFormElement::SetCurrentRadioButton(const nsAString& aName, + nsIDOMHTMLInputElement* aRadio) { mSelectedRadioButtons.Put(aName, aRadio); } nsIDOMHTMLInputElement* -nsHTMLFormElement::GetCurrentRadioButton(const nsAString& aName) +HTMLFormElement::GetCurrentRadioButton(const nsAString& aName) { return mSelectedRadioButtons.GetWeak(aName); } NS_IMETHODIMP -nsHTMLFormElement::GetNextRadioButton(const nsAString& aName, - const bool aPrevious, - nsIDOMHTMLInputElement* aFocusedRadio, - nsIDOMHTMLInputElement** aRadioOut) +HTMLFormElement::GetNextRadioButton(const nsAString& aName, + const bool aPrevious, + nsIDOMHTMLInputElement* aFocusedRadio, + nsIDOMHTMLInputElement** aRadioOut) { // Return the radio button relative to the focused radio button. // If no radio is focused, get the radio relative to the selected one. *aRadioOut = nullptr; nsCOMPtr<nsIDOMHTMLInputElement> currentRadio; if (aFocusedRadio) { currentRadio = aFocusedRadio; @@ -2135,19 +2198,19 @@ nsHTMLFormElement::GetNextRadioButton(co radio->GetDisabled(&disabled); } while (disabled && radio != currentRadio); NS_IF_ADDREF(*aRadioOut = radio); return NS_OK; } NS_IMETHODIMP -nsHTMLFormElement::WalkRadioGroup(const nsAString& aName, - nsIRadioVisitor* aVisitor, - bool aFlushContent) +HTMLFormElement::WalkRadioGroup(const nsAString& aName, + nsIRadioVisitor* aVisitor, + bool aFlushContent) { if (aName.IsEmpty()) { // // XXX If the name is empty, it's not stored in the control list. There // *must* be a more efficient way to do this. // nsCOMPtr<nsIFormControl> control; uint32_t len = GetElementCount(); @@ -2195,31 +2258,31 @@ nsHTMLFormElement::WalkRadioGroup(const !aVisitor->Visit(formControl)) { break; } } return NS_OK; } void -nsHTMLFormElement::AddToRadioGroup(const nsAString& aName, - nsIFormControl* aRadio) +HTMLFormElement::AddToRadioGroup(const nsAString& aName, + nsIFormControl* aRadio) { nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio); NS_ASSERTION(element, "radio controls have to be content elements!"); if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) { mRequiredRadioButtonCounts.Put(aName, mRequiredRadioButtonCounts.Get(aName)+1); } } void -nsHTMLFormElement::RemoveFromRadioGroup(const nsAString& aName, - nsIFormControl* aRadio) +HTMLFormElement::RemoveFromRadioGroup(const nsAString& aName, + nsIFormControl* aRadio) { nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio); NS_ASSERTION(element, "radio controls have to be content elements!"); if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) { uint32_t requiredNb = mRequiredRadioButtonCounts.Get(aName); NS_ASSERTION(requiredNb >= 1, "At least one radio button has to be required!"); @@ -2228,24 +2291,24 @@ nsHTMLFormElement::RemoveFromRadioGroup( mRequiredRadioButtonCounts.Remove(aName); } else { mRequiredRadioButtonCounts.Put(aName, requiredNb-1); } } } uint32_t -nsHTMLFormElement::GetRequiredRadioCount(const nsAString& aName) const +HTMLFormElement::GetRequiredRadioCount(const nsAString& aName) const { return mRequiredRadioButtonCounts.Get(aName); } void -nsHTMLFormElement::RadioRequiredChanged(const nsAString& aName, - nsIFormControl* aRadio) +HTMLFormElement::RadioRequiredChanged(const nsAString& aName, + nsIFormControl* aRadio) { nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio); NS_ASSERTION(element, "radio controls have to be content elements!"); if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) { mRequiredRadioButtonCounts.Put(aName, mRequiredRadioButtonCounts.Get(aName)+1); } else { @@ -2256,57 +2319,57 @@ nsHTMLFormElement::RadioRequiredChanged( mRequiredRadioButtonCounts.Remove(aName); } else { mRequiredRadioButtonCounts.Put(aName, requiredNb-1); } } } bool -nsHTMLFormElement::GetValueMissingState(const nsAString& aName) const +HTMLFormElement::GetValueMissingState(const nsAString& aName) const { return mValueMissingRadioGroups.Get(aName); } void -nsHTMLFormElement::SetValueMissingState(const nsAString& aName, bool aValue) +HTMLFormElement::SetValueMissingState(const nsAString& aName, bool aValue) { mValueMissingRadioGroups.Put(aName, aValue); } nsEventStates -nsHTMLFormElement::IntrinsicState() const +HTMLFormElement::IntrinsicState() const { nsEventStates state = nsGenericHTMLElement::IntrinsicState(); if (mInvalidElementsCount) { state |= NS_EVENT_STATE_INVALID; } else { state |= NS_EVENT_STATE_VALID; } return state; } void -nsHTMLFormElement::Clear() +HTMLFormElement::Clear() { for (int32_t i = mImageElements.Length() - 1; i >= 0; i--) { mImageElements[i]->ClearForm(false); } mImageElements.Clear(); mImageNameLookupTable.Clear(); mPastNameLookupTable.Clear(); } //---------------------------------------------------------------------- // nsFormControlList implementation, this could go away if there were // a lightweight collection implementation somewhere -nsFormControlList::nsFormControlList(nsHTMLFormElement* aForm) : +nsFormControlList::nsFormControlList(HTMLFormElement* aForm) : mForm(aForm), // Initialize the elements list to have an initial capacity // of 8 to reduce allocations on small forms. mElements(8) { SetIsDOMBinding(); } @@ -2449,43 +2512,44 @@ nsFormControlList::NamedItemInternal(con { if (aFlushContent) { FlushPendingNotifications(); } return mNameLookupTable.GetWeak(aName); } -static nsresult -AddElementToTableInternal( +nsresult +HTMLFormElement::AddElementToTableInternal( nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable, - nsIContent* aChild, const nsAString& aName, nsHTMLFormElement* aForm) + nsIContent* aChild, const nsAString& aName) { nsCOMPtr<nsISupports> supports; aTable.Get(aName, getter_AddRefs(supports)); if (!supports) { // No entry found, add the element aTable.Put(aName, aChild); + ++mExpandoAndGeneration.generation; } else { // Found something in the hash, check its type nsCOMPtr<nsIContent> content = do_QueryInterface(supports); if (content) { // Check if the new content is the same as the one we found in the // hash, if it is then we leave it in the hash as it is, this will // happen if a form control has both a name and an id with the same // value if (content == aChild) { return NS_OK; } // Found an element, create a list, add the element to the list and put // the list in the hash - nsSimpleContentList *list = new nsSimpleContentList(aForm); + nsSimpleContentList *list = new nsSimpleContentList(this); // If an element has a @form, we can assume it *might* be able to not have // a parent and still be in the form. NS_ASSERTION(content->HasAttr(kNameSpaceID_None, nsGkAtoms::form) || content->GetParent(), "Item in list without parent"); // Determine the ordering between the new and old element. bool newFirst = nsContentUtils::PositionIsBefore(aChild, content); @@ -2551,17 +2615,17 @@ AddElementToTableInternal( nsresult nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild, const nsAString& aName) { if (!ShouldBeInElements(aChild)) { return NS_OK; } - return AddElementToTableInternal(mNameLookupTable, aChild, aName, mForm); + return mForm->AddElementToTableInternal(mNameLookupTable, aChild, aName); } nsresult nsFormControlList::IndexOfControl(nsIFormControl* aControl, int32_t* aIndex) { // Note -- not a DOM method; callers should handle flushing themselves @@ -2575,17 +2639,17 @@ nsFormControlList::IndexOfControl(nsIFor nsresult nsFormControlList::RemoveElementFromTable(nsGenericHTMLFormElement* aChild, const nsAString& aName) { if (!ShouldBeInElements(aChild)) { return NS_OK; } - return RemoveElementFromTableInternal(mNameLookupTable, aChild, aName); + return mForm->RemoveElementFromTableInternal(mNameLookupTable, aChild, aName); } nsresult nsFormControlList::GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const { #ifdef DEBUG AssertDocumentOrder(mElements, mForm); AssertDocumentOrder(mNotInElements, mForm); @@ -2701,58 +2765,66 @@ nsFormControlList::GetSupportedNames(nsT FlushPendingNotifications(); // Just enumerate mNameLookupTable. This won't guarantee order, but // that's OK, because the HTML5 spec doesn't define an order for // this enumeration. mNameLookupTable.EnumerateRead(CollectNames, &aNames); } nsresult -nsHTMLFormElement::AddImageElement(HTMLImageElement* aChild) +HTMLFormElement::AddImageElement(HTMLImageElement* aChild) { AddElementToList(mImageElements, aChild, this); return NS_OK; } nsresult -nsHTMLFormElement::AddImageElementToTable(HTMLImageElement* aChild, - const nsAString& aName) +HTMLFormElement::AddImageElementToTable(HTMLImageElement* aChild, + const nsAString& aName) { - return AddElementToTableInternal(mImageNameLookupTable, aChild, aName, this); + return AddElementToTableInternal(mImageNameLookupTable, aChild, aName); } nsresult -nsHTMLFormElement::RemoveImageElement(HTMLImageElement* aChild) +HTMLFormElement::RemoveImageElement(HTMLImageElement* aChild) { uint32_t index = mImageElements.IndexOf(aChild); NS_ENSURE_STATE(index != mImageElements.NoIndex); mImageElements.RemoveElementAt(index); return NS_OK; } nsresult -nsHTMLFormElement::RemoveImageElementFromTable(HTMLImageElement* aElement, - const nsAString& aName, - RemoveElementReason aRemoveReason) +HTMLFormElement::RemoveImageElementFromTable(HTMLImageElement* aElement, + const nsAString& aName, + RemoveElementReason aRemoveReason) { // If the element is being removed from the form, we have to remove it from // the past names map. if (aRemoveReason == ElementRemoved) { mPastNameLookupTable.Enumerate(RemovePastNames, aElement); } return RemoveElementFromTableInternal(mImageNameLookupTable, aElement, aName); } void -nsHTMLFormElement::AddToPastNamesMap(const nsAString& aName, - nsISupports* aChild) +HTMLFormElement::AddToPastNamesMap(const nsAString& aName, + nsISupports* aChild) { // If candidates contains exactly one node. Add a mapping from name to the // node in candidates in the form element's past names map, replacing the // previous entry with the same name, if any. nsCOMPtr<nsIContent> node = do_QueryInterface(aChild); if (node) { mPastNameLookupTable.Put(aName, aChild); } } - + +JSObject* +HTMLFormElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope) +{ + return HTMLFormElementBinding::Wrap(aCx, aScope, this); +} + +} // namespace dom +} // namespace mozilla
rename from content/html/content/src/nsHTMLFormElement.h rename to content/html/content/src/HTMLFormElement.h --- a/content/html/content/src/nsHTMLFormElement.h +++ b/content/html/content/src/HTMLFormElement.h @@ -1,15 +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/. */ -#ifndef nsHTMLFormElement_h__ -#define nsHTMLFormElement_h__ +#ifndef mozilla_dom_HTMLFormElement_h +#define mozilla_dom_HTMLFormElement_h #include "mozilla/Attributes.h" #include "nsCOMPtr.h" #include "nsIForm.h" #include "nsIFormControl.h" #include "nsFormSubmission.h" #include "nsGenericHTMLElement.h" #include "nsIDOMHTMLFormElement.h" @@ -23,35 +23,41 @@ // Including 'windows.h' will #define GetClassInfo to something else. #ifdef XP_WIN #ifdef GetClassInfo #undef GetClassInfo #endif #endif -class nsFormControlList; class nsIMutableArray; class nsIURI; namespace mozilla { namespace dom { class HTMLImageElement; } } -class nsHTMLFormElement : public nsGenericHTMLElement, - public nsIDOMHTMLFormElement, - public nsIWebProgressListener, - public nsIForm, - public nsIRadioGroupContainer +namespace mozilla { +namespace dom { + +class nsFormControlList; + +class HTMLFormElement : public nsGenericHTMLElement, + public nsIDOMHTMLFormElement, + public nsIWebProgressListener, + public nsIForm, + public nsIRadioGroupContainer { + friend class nsFormControlList; + public: - nsHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo); - virtual ~nsHTMLFormElement(); + HTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo); + virtual ~HTMLFormElement(); nsresult Init(); // nsISupports NS_DECL_ISUPPORTS_INHERITED // nsIDOMNode NS_FORWARD_NSIDOMNODE_TO_NSINODE @@ -122,18 +128,18 @@ public: /** * Forget all information about the current submission (and the fact that we * are currently submitting at all). */ void ForgetCurrentSubmission(); virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE; - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLFormElement, - nsGenericHTMLElement) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(HTMLFormElement, + nsGenericHTMLElement) /** * Remove an element from this form's list of elements * * @param aElement the element to remove * @param aUpdateValidity If true, updates the form validity. * @return NS_OK if the element was successfully removed. */ @@ -306,82 +312,182 @@ public: /** * Implements form[name]. Returns form controls in this form with the correct * value of the name attribute. */ already_AddRefed<nsISupports> FindNamedItem(const nsAString& aName, nsWrapperCache** aCache); + // WebIDL + + void GetAcceptCharset(DOMString& aValue) + { + GetHTMLAttr(nsGkAtoms::acceptcharset, aValue); + } + + void SetAcceptCharset(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::acceptcharset, aValue, aRv); + } + + // XPCOM GetAction() is OK + void SetAction(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::action, aValue, aRv); + } + + // XPCOM GetAutocomplete() is OK + void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv); + } + + // XPCOM GetEnctype() is OK + void SetEnctype(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::enctype, aValue, aRv); + } + + // XPCOM GetEncoding() is OK + void SetEncoding(const nsAString& aValue, ErrorResult& aRv) + { + SetEnctype(aValue, aRv); + } + + // XPCOM GetMethod() is OK + void SetMethod(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::method, aValue, aRv); + } + + void GetName(DOMString& aValue) + { + GetHTMLAttr(nsGkAtoms::name, aValue); + } + + void SetName(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::name, aValue, aRv); + } + + bool NoValidate() const + { + return GetBoolAttr(nsGkAtoms::novalidate); + } + + void SetNoValidate(bool aValue, ErrorResult& aRv) + { + SetHTMLBoolAttr(nsGkAtoms::novalidate, aValue, aRv); + } + + void GetTarget(DOMString& aValue) + { + GetHTMLAttr(nsGkAtoms::target, aValue); + } + + void SetTarget(const nsAString& aValue, ErrorResult& aRv) + { + SetHTMLAttr(nsGkAtoms::target, aValue, aRv); + } + + // it's only out-of-line because the class definition is not available in the + // header + nsIHTMLCollection* Elements(); + + int32_t Length(); + + void Submit(ErrorResult& aRv); + + // XPCOM Reset() is OK + + bool CheckValidity() + { + return CheckFormValidity(nullptr); + } + + Element* + IndexedGetter(uint32_t aIndex, bool &aFound); + + already_AddRefed<nsISupports> + NamedGetter(const nsAString& aName, bool &aFound); + + void GetSupportedNames(nsTArray<nsString >& aRetval); + + js::ExpandoAndGeneration mExpandoAndGeneration; + protected: + virtual JSObject* WrapNode(JSContext* aCx, + JS::Handle<JSObject*> aScope) MOZ_OVERRIDE; + void PostPasswordEvent(); void EventHandled() { mFormPasswordEvent = nullptr; } class FormPasswordEvent : public nsAsyncDOMEvent { public: - FormPasswordEvent(nsHTMLFormElement* aEventNode, + FormPasswordEvent(HTMLFormElement* aEventNode, const nsAString& aEventType) : nsAsyncDOMEvent(aEventNode, aEventType, true, true) {} NS_IMETHOD Run() MOZ_OVERRIDE { - static_cast<nsHTMLFormElement*>(mEventNode.get())->EventHandled(); + static_cast<HTMLFormElement*>(mEventNode.get())->EventHandled(); return nsAsyncDOMEvent::Run(); } }; nsRefPtr<FormPasswordEvent> mFormPasswordEvent; class RemoveElementRunnable; friend class RemoveElementRunnable; class RemoveElementRunnable : public nsRunnable { public: - RemoveElementRunnable(nsHTMLFormElement* aForm) + RemoveElementRunnable(HTMLFormElement* aForm) : mForm(aForm) {} NS_IMETHOD Run() MOZ_OVERRIDE { mForm->HandleDefaultSubmitRemoval(); return NS_OK; } private: - nsRefPtr<nsHTMLFormElement> mForm; + nsRefPtr<HTMLFormElement> mForm; }; nsresult DoSubmitOrReset(nsEvent* aEvent, int32_t aMessage); nsresult DoReset(); // Async callback to handle removal of our default submit void HandleDefaultSubmitRemoval(); // // Submit Helpers // // /** - * Attempt to submit (submission might be deferred) + * Attempt to submit (submission might be deferred) * (called by DoSubmitOrReset) * * @param aPresContext the presentation context * @param aEvent the DOM event that was passed to us for the submit */ nsresult DoSubmit(nsEvent* aEvent); /** * Prepare the submission object (called by DoSubmit) * * @param aFormSubmission the submission object * @param aEvent the DOM event that was passed to us for the submit */ - nsresult BuildSubmission(nsFormSubmission** aFormSubmission, + nsresult BuildSubmission(nsFormSubmission** aFormSubmission, nsEvent* aEvent); /** * Perform the submission (called by DoSubmit and FlushPendingSubmission) * * @param aFormSubmission the submission object */ nsresult SubmitSubmission(nsFormSubmission* aFormSubmission); @@ -421,16 +527,26 @@ protected: bool CheckFormValidity(nsIMutableArray* aInvalidElements) const; // Clear the mImageNameLookupTable and mImageElements. void Clear(); // Insert a element into the past names map. void AddToPastNamesMap(const nsAString& aName, nsISupports* aChild); + nsresult + AddElementToTableInternal( + nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable, + nsIContent* aChild, const nsAString& aName); + + nsresult + RemoveElementFromTableInternal( + nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable, + nsIContent* aChild, const nsAString& aName); + public: /** * Flush a possible pending submission. If there was a scripted submission * triggered by a button or image, the submission was defered. This method * forces the pending submission to be submitted. (happens when the handler * returns false or there is an action/target change in the script) */ void FlushPendingSubmission(); @@ -514,9 +630,12 @@ protected: protected: /** Detection of first form to notify observers */ static bool gFirstFormSubmitted; /** Detection of first password input to initialize the password manager */ static bool gPasswordManagerInitialized; }; -#endif // nsHTMLFormElement_h__ +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_HTMLFormElement_h
--- a/content/html/content/src/HTMLImageElement.cpp +++ b/content/html/content/src/HTMLImageElement.cpp @@ -20,53 +20,33 @@ #include "nsNetUtil.h" #include "nsContentUtils.h" #include "nsIFrame.h" #include "nsNodeInfoManager.h" #include "nsGUIEvent.h" #include "nsContentPolicyUtils.h" #include "nsIDOMWindow.h" #include "nsFocusManager.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" #include "imgIContainer.h" #include "imgILoader.h" #include "imgINotificationObserver.h" #include "imgRequestProxy.h" #include "nsILoadGroup.h" #include "nsRuleData.h" #include "nsIDOMHTMLMapElement.h" #include "nsEventDispatcher.h" #include "nsLayoutUtils.h" -nsGenericHTMLElement* -NS_NewHTMLImageElement(already_AddRefed<nsINodeInfo> aNodeInfo, - mozilla::dom::FromParser aFromParser) -{ - /* - * HTMLImageElement's will be created without a nsINodeInfo passed in - * if someone says "var img = new Image();" in JavaScript, in a case like - * that we request the nsINodeInfo from the document's nodeinfo list. - */ - nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo); - if (!nodeInfo) { - nsCOMPtr<nsIDocument> doc = nsContentUtils::GetDocumentFromCaller(); - NS_ENSURE_TRUE(doc, nullptr); - - nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::img, nullptr, - kNameSpaceID_XHTML, - nsIDOMNode::ELEMENT_NODE); - } - - return new mozilla::dom::HTMLImageElement(nodeInfo.forget()); -} +NS_IMPL_NS_NEW_HTML_ELEMENT(Image) namespace mozilla { namespace dom { HTMLImageElement::HTMLImageElement(already_AddRefed<nsINodeInfo> aNodeInfo) : nsGenericHTMLElement(aNodeInfo) , mForm(nullptr) { @@ -307,17 +287,17 @@ HTMLImageElement::BeforeSetAttr(int32_t if (aNameSpaceID == kNameSpaceID_None && mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id)) { // remove the image from the hashtable as needed nsAutoString tmp; GetAttr(kNameSpaceID_None, aName, tmp); if (!tmp.IsEmpty()) { mForm->RemoveImageElementFromTable(this, tmp, - nsHTMLFormElement::AttributeUpdated); + HTMLFormElement::AttributeUpdated); } } return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName, aValue, aNotify); } nsresult @@ -669,17 +649,17 @@ HTMLImageElement::GetForm() const void HTMLImageElement::SetForm(nsIDOMHTMLFormElement* aForm) { NS_PRECONDITION(aForm, "Don't pass null here"); NS_ASSERTION(!mForm, "We don't support switching from one non-null form to another."); - mForm = static_cast<nsHTMLFormElement*>(aForm); + mForm = static_cast<HTMLFormElement*>(aForm); } void HTMLImageElement::ClearForm(bool aRemoveFromForm) { NS_ASSERTION((mForm != nullptr) == HasFlag(ADDED_TO_FORM), "Form control should have had flag set correctly"); @@ -691,22 +671,22 @@ HTMLImageElement::ClearForm(bool aRemove nsAutoString nameVal, idVal; GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal); GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal); mForm->RemoveImageElement(this); if (!nameVal.IsEmpty()) { mForm->RemoveImageElementFromTable(this, nameVal, - nsHTMLFormElement::ElementRemoved); + HTMLFormElement::ElementRemoved); } if (!idVal.IsEmpty()) { mForm->RemoveImageElementFromTable(this, idVal, - nsHTMLFormElement::ElementRemoved); + HTMLFormElement::ElementRemoved); } } UnsetFlags(ADDED_TO_FORM); mForm = nullptr; } } // namespace dom
--- a/content/html/content/src/HTMLImageElement.h +++ b/content/html/content/src/HTMLImageElement.h @@ -192,15 +192,15 @@ protected: const nsAttrValueOrString* aValue, bool aNotify) MOZ_OVERRIDE; virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, const nsAttrValue* aValue, bool aNotify) MOZ_OVERRIDE; // This is a weak reference that this element and the HTMLFormElement // cooperate in maintaining. - nsHTMLFormElement* mForm; + HTMLFormElement* mForm; }; } // namespace dom } // namespace mozilla #endif /* mozilla_dom_HTMLImageElement_h */
--- a/content/html/content/src/HTMLInputElement.cpp +++ b/content/html/content/src/HTMLInputElement.cpp @@ -2319,17 +2319,17 @@ HTMLInputElement::MaybeSubmitForm(nsPres shell->HandleDOMEventWithTarget(submitContent, &event, &status); } else if (mForm->HasSingleTextControl() && (mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) || mForm->CheckValidFormSubmission())) { // TODO: removing this code and have the submit event sent by the form, // bug 592124. // If there's only one text control, just submit the form // Hold strong ref across the event - nsRefPtr<nsHTMLFormElement> form = mForm; + nsRefPtr<mozilla::dom::HTMLFormElement> form = mForm; nsFormEvent event(true, NS_FORM_SUBMIT); nsEventStatus status = nsEventStatus_eIgnore; shell->HandleDOMEventWithTarget(mForm, &event, &status); } return NS_OK; } @@ -3160,17 +3160,17 @@ HTMLInputElement::PostHandleEvent(nsEven // form, see bug 592124. if (presShell && (event.message != NS_FORM_SUBMIT || mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) || // We know the element is a submit control, if this check is moved, // make sure formnovalidate is used only if it's a submit control. HasAttr(kNameSpaceID_None, nsGkAtoms::formnovalidate) || mForm->CheckValidFormSubmission())) { // Hold a strong ref while dispatching - nsRefPtr<nsHTMLFormElement> form(mForm); + nsRefPtr<mozilla::dom::HTMLFormElement> form(mForm); presShell->HandleDOMEventWithTarget(mForm, &event, &status); aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; } } break; default: break;
--- a/content/html/content/src/HTMLInputElement.h +++ b/content/html/content/src/HTMLInputElement.h @@ -12,17 +12,17 @@ #include "nsIDOMHTMLInputElement.h" #include "nsITextControlElement.h" #include "nsIPhonetic.h" #include "nsIDOMNSEditableElement.h" #include "nsTextEditorState.h" #include "nsCOMPtr.h" #include "nsIConstraintValidation.h" #include "nsDOMFile.h" -#include "nsHTMLFormElement.h" // for ShouldShowInvalidUI() +#include "mozilla/dom/HTMLFormElement.h" // for ShouldShowInvalidUI() #include "nsIFile.h" #include "nsIFilePicker.h" #include "nsIContentPrefService2.h" #include "mozilla/Decimal.h" class nsDOMFileList; class nsIFilePicker; class nsIRadioGroupContainer;
--- a/content/html/content/src/HTMLLegendElement.cpp +++ b/content/html/content/src/HTMLLegendElement.cpp @@ -159,22 +159,22 @@ void HTMLLegendElement::PerformAccesskey(bool aKeyCausesActivation, bool aIsTrustedEvent) { // just use the same behaviour as the focus method ErrorResult rv; Focus(rv); } -already_AddRefed<nsHTMLFormElement> +already_AddRefed<HTMLFormElement> HTMLLegendElement::GetForm() { Element* form = GetFormElement(); MOZ_ASSERT_IF(form, form->IsHTML(nsGkAtoms::form)); - nsRefPtr<nsHTMLFormElement> ret = static_cast<nsHTMLFormElement*>(form); + nsRefPtr<HTMLFormElement> ret = static_cast<HTMLFormElement*>(form); return ret.forget(); } JSObject* HTMLLegendElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope) { return HTMLLegendElementBinding::Wrap(aCx, aScope, this); }
--- a/content/html/content/src/HTMLLegendElement.h +++ b/content/html/content/src/HTMLLegendElement.h @@ -4,17 +4,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_HTMLLegendElement_h #define mozilla_dom_HTMLLegendElement_h #include "mozilla/Attributes.h" #include "nsIDOMHTMLLegendElement.h" #include "nsGenericHTMLElement.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" namespace mozilla { namespace dom { class HTMLLegendElement : public nsGenericHTMLElement, public nsIDOMHTMLLegendElement { public: @@ -80,17 +80,17 @@ public: } virtual nsIDOMNode* AsDOMNode() MOZ_OVERRIDE { return this; } /** * WebIDL Interface */ - already_AddRefed<nsHTMLFormElement> GetForm(); + already_AddRefed<HTMLFormElement> GetForm(); // The XPCOM GetAlign is OK for us void SetAlign(const nsAString& aAlign, ErrorResult& aError) { SetHTMLAttr(nsGkAtoms::align, aAlign, aError); } nsINode* GetParentObject() {
--- a/content/html/content/src/HTMLObjectElement.cpp +++ b/content/html/content/src/HTMLObjectElement.cpp @@ -75,26 +75,25 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_ADDREF_INHERITED(HTMLObjectElement, Element) NS_IMPL_RELEASE_INHERITED(HTMLObjectElement, Element) NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLObjectElement) NS_HTML_CONTENT_INTERFACES(nsGenericHTMLFormElement) - NS_INTERFACE_TABLE_INHERITED11(HTMLObjectElement, + NS_INTERFACE_TABLE_INHERITED10(HTMLObjectElement, nsIDOMHTMLObjectElement, imgINotificationObserver, nsIRequestObserver, nsIStreamListener, nsIFrameLoaderOwner, nsIObjectLoadingContent, nsIImageLoadingContent, imgIOnloadBlocker, - nsIInterfaceRequestor, nsIChannelEventSink, nsIConstraintValidation) NS_INTERFACE_TABLE_TO_MAP_SEGUE NS_ELEMENT_INTERFACE_MAP_END NS_IMPL_ELEMENT_CLONE(HTMLObjectElement) // nsIConstraintValidation
--- a/content/html/content/src/HTMLOptionElement.cpp +++ b/content/html/content/src/HTMLOptionElement.cpp @@ -27,37 +27,17 @@ #include "nsContentCreatorFunctions.h" #include "mozAutoDocUpdate.h" #include "nsTextNode.h" /** * Implementation of <option> */ -nsGenericHTMLElement* -NS_NewHTMLOptionElement(already_AddRefed<nsINodeInfo> aNodeInfo, - mozilla::dom::FromParser aFromParser) -{ - /* - * HTMLOptionElement's will be created without a nsINodeInfo passed in - * if someone says "var opt = new Option();" in JavaScript, in a case like - * that we request the nsINodeInfo from the document's nodeinfo list. - */ - nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo); - if (!nodeInfo) { - nsCOMPtr<nsIDocument> doc = nsContentUtils::GetDocumentFromCaller(); - NS_ENSURE_TRUE(doc, nullptr); - - nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::option, nullptr, - kNameSpaceID_XHTML, - nsIDOMNode::ELEMENT_NODE); - } - - return new mozilla::dom::HTMLOptionElement(nodeInfo.forget()); -} +NS_IMPL_NS_NEW_HTML_ELEMENT(Option) namespace mozilla { namespace dom { HTMLOptionElement::HTMLOptionElement(already_AddRefed<nsINodeInfo> aNodeInfo) : nsGenericHTMLElement(aNodeInfo), mSelectedChanged(false), mIsSelected(false), @@ -94,17 +74,17 @@ NS_IMPL_ELEMENT_CLONE(HTMLOptionElement) NS_IMETHODIMP HTMLOptionElement::GetForm(nsIDOMHTMLFormElement** aForm) { NS_IF_ADDREF(*aForm = GetForm()); return NS_OK; } -nsHTMLFormElement* +mozilla::dom::HTMLFormElement* HTMLOptionElement::GetForm() { HTMLSelectElement* selectControl = GetSelect(); return selectControl ? selectControl->GetForm() : nullptr; } void HTMLOptionElement::SetSelectedInternal(bool aValue, bool aNotify)
--- a/content/html/content/src/HTMLOptionElement.h +++ b/content/html/content/src/HTMLOptionElement.h @@ -6,17 +6,17 @@ #ifndef mozilla_dom_HTMLOptionElement_h__ #define mozilla_dom_HTMLOptionElement_h__ #include "mozilla/Attributes.h" #include "nsGenericHTMLElement.h" #include "nsIDOMHTMLOptionElement.h" #include "nsIJSNativeInitializer.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" namespace mozilla { namespace dom { class HTMLSelectElement; class HTMLOptionElement : public nsGenericHTMLElement, public nsIDOMHTMLOptionElement @@ -86,17 +86,17 @@ public: return GetBoolAttr(nsGkAtoms::disabled); } void SetDisabled(bool aValue, ErrorResult& aRv) { SetHTMLBoolAttr(nsGkAtoms::disabled, aValue, aRv); } - nsHTMLFormElement* GetForm(); + HTMLFormElement* GetForm(); // The XPCOM GetLabel is OK for us void SetLabel(const nsAString& aLabel, ErrorResult& aError) { SetHTMLAttr(nsGkAtoms::label, aLabel, aError); } // The XPCOM DefaultSelected is OK for us
--- a/content/html/content/src/HTMLOutputElement.cpp +++ b/content/html/content/src/HTMLOutputElement.cpp @@ -5,17 +5,17 @@ #include "mozilla/dom/HTMLOutputElement.h" #include "mozilla/dom/HTMLOutputElementBinding.h" #include "nsFormSubmission.h" #include "nsDOMSettableTokenList.h" #include "nsEventStates.h" #include "mozAutoDocUpdate.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" NS_IMPL_NS_NEW_HTML_ELEMENT(Output) namespace mozilla { namespace dom { HTMLOutputElement::HTMLOutputElement(already_AddRefed<nsINodeInfo> aNodeInfo) : nsGenericHTMLFormElement(aNodeInfo)
--- a/content/html/content/src/HTMLSelectElement.h +++ b/content/html/content/src/HTMLSelectElement.h @@ -11,17 +11,17 @@ #include "nsIConstraintValidation.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/HTMLOptionsCollection.h" #include "mozilla/ErrorResult.h" #include "nsCheapSets.h" #include "nsCOMPtr.h" #include "nsError.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" class nsIDOMHTMLOptionElement; class nsISelectControlFrame; class nsPresState; namespace mozilla { namespace dom { @@ -145,17 +145,17 @@ public: bool Disabled() const { return GetBoolAttr(nsGkAtoms::disabled); } void SetDisabled(bool aVal, ErrorResult& aRv) { SetHTMLBoolAttr(nsGkAtoms::disabled, aVal, aRv); } - nsHTMLFormElement* GetForm() const + HTMLFormElement* GetForm() const { return nsGenericHTMLFormElement::GetForm(); } bool Multiple() const { return GetBoolAttr(nsGkAtoms::multiple); } void SetMultiple(bool aVal, ErrorResult& aRv)
--- a/content/html/content/src/HTMLSharedObjectElement.cpp +++ b/content/html/content/src/HTMLSharedObjectElement.cpp @@ -88,25 +88,24 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_ADDREF_INHERITED(HTMLSharedObjectElement, Element) NS_IMPL_RELEASE_INHERITED(HTMLSharedObjectElement, Element) NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLSharedObjectElement) NS_HTML_CONTENT_INTERFACES_AMBIGUOUS(nsGenericHTMLElement, nsIDOMHTMLAppletElement) - NS_INTERFACE_TABLE_INHERITED9(HTMLSharedObjectElement, + NS_INTERFACE_TABLE_INHERITED8(HTMLSharedObjectElement, nsIRequestObserver, nsIStreamListener, nsIFrameLoaderOwner, nsIObjectLoadingContent, imgINotificationObserver, nsIImageLoadingContent, imgIOnloadBlocker, - nsIInterfaceRequestor, nsIChannelEventSink) NS_INTERFACE_TABLE_TO_MAP_SEGUE NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLAppletElement, applet) NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLEmbedElement, embed) NS_ELEMENT_INTERFACE_MAP_END NS_IMPL_ELEMENT_CLONE(HTMLSharedObjectElement)
--- a/content/html/content/src/HTMLTextAreaElement.h +++ b/content/html/content/src/HTMLTextAreaElement.h @@ -11,17 +11,17 @@ #include "nsIDOMHTMLTextAreaElement.h" #include "nsITextControlElement.h" #include "nsIDOMNSEditableElement.h" #include "nsCOMPtr.h" #include "nsGenericHTMLElement.h" #include "nsEventStates.h" #include "nsStubMutationObserver.h" #include "nsIConstraintValidation.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" #include "nsGkAtoms.h" #include "nsTextEditorState.h" class nsFormSubmission; class nsIControllers; class nsIDocument; class nsPresContext;
--- a/content/html/content/src/moz.build +++ b/content/html/content/src/moz.build @@ -19,16 +19,17 @@ EXPORTS.mozilla.dom += [ 'HTMLBRElement.h', 'HTMLBodyElement.h', 'HTMLButtonElement.h', 'HTMLDataElement.h', 'HTMLDataListElement.h', 'HTMLDivElement.h', 'HTMLFieldSetElement.h', 'HTMLFontElement.h', + 'HTMLFormElement.h', 'HTMLFrameElement.h', 'HTMLFrameSetElement.h', 'HTMLHRElement.h', 'HTMLHeadingElement.h', 'HTMLIFrameElement.h', 'HTMLImageElement.h', 'HTMLInputElement.h', 'HTMLLIElement.h', @@ -142,14 +143,14 @@ CPP_SOURCES += [ 'UndoManager.cpp', 'ValidityState.cpp', 'nsClientRect.cpp', 'nsDOMStringMap.cpp', 'nsFormSubmission.cpp', 'nsGenericHTMLElement.cpp', 'nsGenericHTMLFrameElement.cpp', 'nsHTMLDNSPrefetch.cpp', - 'nsHTMLFormElement.cpp', + 'HTMLFormElement.cpp', 'nsIConstraintValidation.cpp', 'nsRadioVisitor.cpp', 'nsTextEditorState.cpp', ]
--- a/content/html/content/src/nsDOMStringMap.cpp +++ b/content/html/content/src/nsDOMStringMap.cpp @@ -23,18 +23,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER // Check that mElement exists in case the unlink code is run more than once. if (tmp->mElement) { // Call back to element to null out weak reference to this object. tmp->mElement->ClearDataset(); tmp->mElement->RemoveMutationObserver(tmp); tmp->mElement = nullptr; } - ++tmp->mExpandoAndGeneration.generation; - tmp->mExpandoAndGeneration.expando = JS::UndefinedValue(); + tmp->mExpandoAndGeneration.Unlink(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMStringMap) NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER if (tmp->PreservingWrapper()) { NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration.expando); } NS_IMPL_CYCLE_COLLECTION_TRACE_END
--- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -59,17 +59,17 @@ #include "nsGkAtoms.h" #include "nsEventStateManager.h" #include "nsIDOMEvent.h" #include "nsDOMCSSDeclaration.h" #include "nsITextControlFrame.h" #include "nsIForm.h" #include "nsIFormControl.h" #include "nsIDOMHTMLFormElement.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" #include "nsFocusManager.h" #include "nsAttrValueOrString.h" #include "nsMutationEvent.h" #include "nsDOMStringMap.h" #include "nsIEditor.h" #include "nsIEditorIMESupport.h" @@ -646,18 +646,18 @@ nsGenericHTMLElement::UnbindFromTree(boo if (htmlDocument) { htmlDocument->ChangeContentEditableCount(this, -1); } } nsStyledElement::UnbindFromTree(aDeep, aNullParent); } -nsHTMLFormElement* -nsGenericHTMLElement::FindAncestorForm(nsHTMLFormElement* aCurrentForm) +HTMLFormElement* +nsGenericHTMLElement::FindAncestorForm(HTMLFormElement* aCurrentForm) { NS_ASSERTION(!HasAttr(kNameSpaceID_None, nsGkAtoms::form), "FindAncestorForm should not be called if @form is set!"); // Make sure we don't end up finding a form that's anonymous from // our point of view. nsIContent* bindingParent = GetBindingParent(); @@ -672,17 +672,17 @@ nsGenericHTMLElement::FindAncestorForm(n // anonymous. Check for this the hard way. for (nsIContent* child = this; child != content; child = child->GetParent()) { NS_ASSERTION(child->GetParent()->IndexOf(child) != -1, "Walked too far?"); } } #endif - return static_cast<nsHTMLFormElement*>(content); + return static_cast<HTMLFormElement*>(content); } nsIContent *prevContent = content; content = prevContent->GetParent(); if (!content && aCurrentForm) { // We got to the root of the subtree we're in, and we're being removed // from the DOM (the only time we get into this method with a non-null @@ -2153,17 +2153,17 @@ nsGenericHTMLFormElement::SaveSubtreeSta void nsGenericHTMLFormElement::SetForm(nsIDOMHTMLFormElement* aForm) { NS_PRECONDITION(aForm, "Don't pass null here"); NS_ASSERTION(!mForm, "We don't support switching from one non-null form to another."); // keep a *weak* ref to the form here - mForm = static_cast<nsHTMLFormElement*>(aForm); + mForm = static_cast<HTMLFormElement*>(aForm); } void nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm) { NS_ASSERTION((mForm != nullptr) == HasFlag(ADDED_TO_FORM), "Form control should have had flag set correctly"); @@ -2175,22 +2175,22 @@ nsGenericHTMLFormElement::ClearForm(bool nsAutoString nameVal, idVal; GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal); GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal); mForm->RemoveElement(this, true); if (!nameVal.IsEmpty()) { mForm->RemoveElementFromTable(this, nameVal, - nsHTMLFormElement::ElementRemoved); + HTMLFormElement::ElementRemoved); } if (!idVal.IsEmpty()) { mForm->RemoveElementFromTable(this, idVal, - nsHTMLFormElement::ElementRemoved); + HTMLFormElement::ElementRemoved); } } UnsetFlags(ADDED_TO_FORM); mForm = nullptr; } Element* @@ -2312,33 +2312,33 @@ nsGenericHTMLFormElement::BeforeSetAttr( // remove the control from the hashtable as needed if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id)) { GetAttr(kNameSpaceID_None, aName, tmp); if (!tmp.IsEmpty()) { mForm->RemoveElementFromTable(this, tmp, - nsHTMLFormElement::AttributeUpdated); + HTMLFormElement::AttributeUpdated); } } if (mForm && aName == nsGkAtoms::type) { GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp); if (!tmp.IsEmpty()) { mForm->RemoveElementFromTable(this, tmp, - nsHTMLFormElement::AttributeUpdated); + HTMLFormElement::AttributeUpdated); } GetAttr(kNameSpaceID_None, nsGkAtoms::id, tmp); if (!tmp.IsEmpty()) { mForm->RemoveElementFromTable(this, tmp, - nsHTMLFormElement::AttributeUpdated); + HTMLFormElement::AttributeUpdated); } mForm->RemoveElement(this, false); // Removing the element from the form can make it not be the default // control anymore. Go ahead and notify on that change, though we might // end up readding and becoming the default control again in // AfterSetAttr. @@ -2650,17 +2650,17 @@ nsGenericHTMLFormElement::UpdateFormOwne "aFormIdElement shouldn't be set if aBindToTree is true!"); bool needStateUpdate = false; if (!aBindToTree) { needStateUpdate = mForm && mForm->IsDefaultSubmitElement(this); ClearForm(true); } - nsHTMLFormElement *oldForm = mForm; + HTMLFormElement *oldForm = mForm; if (!mForm) { // If @form is set, we have to use that to find the form. nsAutoString formId; if (GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId)) { if (!formId.IsEmpty()) { Element* element = nullptr; @@ -2673,17 +2673,17 @@ nsGenericHTMLFormElement::UpdateFormOwne NS_ASSERTION(GetCurrentDoc(), "The element should be in a document " "when UpdateFormOwner is called!"); NS_ASSERTION(!GetCurrentDoc() || element == GetCurrentDoc()->GetElementById(formId), "element should be equals to the current element " "associated with the id in @form!"); if (element && element->IsHTML(nsGkAtoms::form)) { - mForm = static_cast<nsHTMLFormElement*>(element); + mForm = static_cast<HTMLFormElement*>(element); } } } else { // We now have a parent, so we may have picked up an ancestor form. Search // for it. Note that if mForm is already set we don't want to do this, // because that means someone (probably the content sink) has already set // it to the right value. Also note that even if being bound here didn't // change our parent, we still need to search, since our parent chain
--- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -28,23 +28,23 @@ class nsIDOMCSSStyleDeclaration; class nsIURI; class nsIFormControlFrame; class nsIForm; class nsPresState; class nsILayoutHistoryState; class nsIEditor; struct nsRect; struct nsSize; -class nsHTMLFormElement; class nsIDOMHTMLMenuElement; class nsIDOMHTMLCollection; class nsDOMSettableTokenList; namespace mozilla { namespace dom{ +class HTMLFormElement; class HTMLPropertiesCollection; class HTMLMenuElement; } } typedef nsMappedAttributeElement nsGenericHTMLElementBase; /** @@ -661,17 +661,18 @@ public: * Find an ancestor of this content node which is a form (could be null) * @param aCurrentForm the current form for this node. If this is * non-null, and no ancestor form is found, and the current form is in * a connected subtree with the node, the current form will be * returned. This is needed to handle cases when HTML elements have a * current form that they're not descendants of. * @note This method should not be called if the element has a form attribute. */ - nsHTMLFormElement* FindAncestorForm(nsHTMLFormElement* aCurrentForm = nullptr); + mozilla::dom::HTMLFormElement* + FindAncestorForm(mozilla::dom::HTMLFormElement* aCurrentForm = nullptr); virtual void RecompileScriptEventListeners() MOZ_OVERRIDE; /** * See if the document being tested has nav-quirks mode enabled. * @param doc the document */ static bool InNavQuirksMode(nsIDocument* aDoc); @@ -1082,17 +1083,17 @@ public: nsINode* GetParentObject() const; virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE; virtual void SaveSubtreeState() MOZ_OVERRIDE; // nsIFormControl virtual mozilla::dom::Element* GetFormElement() MOZ_OVERRIDE; - nsHTMLFormElement* GetForm() const + mozilla::dom::HTMLFormElement* GetForm() const { return mForm; } virtual void SetForm(nsIDOMHTMLFormElement* aForm) MOZ_OVERRIDE; virtual void ClearForm(bool aRemoveFromForm) MOZ_OVERRIDE; nsresult GetForm(nsIDOMHTMLFormElement** aForm); @@ -1216,17 +1217,17 @@ protected: eActiveWindow }; // Get our focus state. If this returns eInactiveWindow, it will set this // element as the focused element for that window. FocusTristate FocusState(); /** The form that contains this control */ - nsHTMLFormElement* mForm; + mozilla::dom::HTMLFormElement* mForm; /* This is a pointer to our closest fieldset parent if any */ mozilla::dom::HTMLFieldSetElement* mFieldSet; }; //---------------------------------------------------------------------- /**
--- a/content/html/content/src/nsIConstraintValidation.cpp +++ b/content/html/content/src/nsIConstraintValidation.cpp @@ -2,17 +2,17 @@ /* 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 "nsIConstraintValidation.h" #include "nsAString.h" #include "nsGenericHTMLElement.h" -#include "nsHTMLFormElement.h" +#include "mozilla/dom/HTMLFormElement.h" #include "mozilla/dom/ValidityState.h" #include "nsIFormControl.h" #include "nsContentUtils.h" const uint16_t nsIConstraintValidation::sContentSpecifiedMaxLengthMessage = 256; nsIConstraintValidation::nsIConstraintValidation() : mValidityBitField(0) @@ -131,18 +131,18 @@ nsIConstraintValidation::SetValidityStat mValidityBitField &= ~aState; } // Inform the form element if our validity has changed. if (previousValidity != IsValid() && IsCandidateForConstraintValidation()) { nsCOMPtr<nsIFormControl> formCtrl = do_QueryInterface(this); NS_ASSERTION(formCtrl, "This interface should be used by form elements!"); - nsHTMLFormElement* form = - static_cast<nsHTMLFormElement*>(formCtrl->GetFormElement()); + mozilla::dom::HTMLFormElement* form = + static_cast<mozilla::dom::HTMLFormElement*>(formCtrl->GetFormElement()); if (form) { form->UpdateValidity(IsValid()); } } } void nsIConstraintValidation::SetCustomValidity(const nsAString& aError) @@ -159,18 +159,18 @@ nsIConstraintValidation::SetBarredFromCo mBarredFromConstraintValidation = aBarred; // Inform the form element if our status regarding constraint validation // is going to change. if (!IsValid() && previousBarred != mBarredFromConstraintValidation) { nsCOMPtr<nsIFormControl> formCtrl = do_QueryInterface(this); NS_ASSERTION(formCtrl, "This interface should be used by form elements!"); - nsHTMLFormElement* form = - static_cast<nsHTMLFormElement*>(formCtrl->GetFormElement()); + mozilla::dom::HTMLFormElement* form = + static_cast<mozilla::dom::HTMLFormElement*>(formCtrl->GetFormElement()); if (form) { // If the element is going to be barred from constraint validation, // we can inform the form that we are now valid. // Otherwise, we are now invalid. form->UpdateValidity(aBarred); } } }
--- a/content/html/content/test/reflect.js +++ b/content/html/content/test/reflect.js @@ -53,40 +53,28 @@ function reflectString(aParameters) element.setAttribute(contentAttr, null); is(element.getAttribute(contentAttr), "null", "null should have been stringified to 'null' for '" + contentAttr + "'"); is(element[idlAttr], "null", "null should have been stringified to 'null' for '" + idlAttr + "'"); element.removeAttribute(contentAttr); element[idlAttr] = null; - // TODO: remove this ugly hack when null stringification will work as expected. - var todoAttrs = { - form: [ "acceptCharset", "name", "target" ], - }; - if (!(element.localName in todoAttrs) || todoAttrs[element.localName].indexOf(idlAttr) == -1) { - if (treatNullAs == "EmptyString") { - is(element.getAttribute(contentAttr), "", - "null should have been stringified to '' for '" + contentAttr + "'"); - is(element[idlAttr], "", - "null should have been stringified to '' for '" + idlAttr + "'"); - } else { - is(element.getAttribute(contentAttr), "null", - "null should have been stringified to 'null' for '" + contentAttr + "'"); - is(element[idlAttr], "null", - "null should have been stringified to 'null' for '" + contentAttr + "'"); - } - element.removeAttribute(contentAttr); + if (treatNullAs == "EmptyString") { + is(element.getAttribute(contentAttr), "", + "null should have been stringified to '' for '" + contentAttr + "'"); + is(element[idlAttr], "", + "null should have been stringified to '' for '" + idlAttr + "'"); } else { - todo_is(element.getAttribute(contentAttr), "null", + is(element.getAttribute(contentAttr), "null", "null should have been stringified to 'null' for '" + contentAttr + "'"); - todo_is(element[idlAttr], "null", + is(element[idlAttr], "null", "null should have been stringified to 'null' for '" + contentAttr + "'"); - element.removeAttribute(contentAttr); } + element.removeAttribute(contentAttr); // Tests various strings. var stringsToTest = [ // [ test value, expected result ] [ "", "" ], [ "null", "null" ], [ "undefined", "undefined" ], [ "foo", "foo" ],
--- a/content/html/content/test/test_bug389797.html +++ b/content/html/content/test/test_bug389797.html @@ -67,18 +67,17 @@ function HTML_TAG(aTagName, aImplClass) for (i = 0; i < arguments[3].length; ++i) { interfacesNonClassinfo[aTagName].push(arguments[3][i]); } } } const objectIfaces = [ "imgINotificationObserver", "nsIRequestObserver", "nsIStreamListener", - "nsIFrameLoaderOwner", "nsIObjectLoadingContent", "nsIInterfaceRequestor", - "nsIChannelEventSink" + "nsIFrameLoaderOwner", "nsIObjectLoadingContent", "nsIChannelEventSink" ]; var objectIfaces2 = []; for (var iface of objectIfaces) { objectIfaces2.push(iface); } objectIfaces2.push("nsIImageLoadingContent");
--- a/content/html/content/test/test_bug879319.html +++ b/content/html/content/test/test_bug879319.html @@ -47,19 +47,19 @@ ok("tmp1" in form.elements, "tmp1 is in ok(!("tmp0" in form.elements), "tmp0 is not in form.elements"); ok(!("foo0" in form.elements), "foo0 is not in form.elements"); is(form.tmp0, input0, "Form.tmp0 == input0"); is(form.tmp1, input0, "Form.tmp1 == input0"); is(form.foo0, input0, "Form.foo0 is still here"); input0.setAttribute("form", ""); ok(!("foo0" in form.elements), "foo0 is not in form.elements"); -todo_is(form.foo0, undefined, "Form.foo0 should not still be here"); -todo_is(form.tmp0, undefined, "Form.tmp0 should not still be here"); -todo_is(form.tmp1, undefined, "Form.tmp1 should not still be here"); +is(form.foo0, undefined, "Form.foo0 should not still be here"); +is(form.tmp0, undefined, "Form.tmp0 should not still be here"); +is(form.tmp1, undefined, "Form.tmp1 should not still be here"); var input1 = document.getElementById("input1"); ok(input1, "input1 exists"); is(form.foo1, input1, "Form.foo1 should exist"); ok("foo1" in form.elements, "foo1 in form.elements"); is(input1.form, form, "input1.form is form"); @@ -68,24 +68,25 @@ ok("foo0" in form.elements, "foo0 is in is(form.foo0, input1, "Form.foo0 should be input1"); is(form.foo1, input1, "Form.foo1 should be input1"); var input2 = document.getElementById("input2"); ok(input2, "input2 exists"); is(form.foo2, input2, "Form.foo2 should exist"); input2.parentNode.removeChild(input2); ok(!("foo2" in form.elements), "foo2 is not in form.elements"); -todo_is(form.foo2, undefined, "Form.foo2 should not longer be there"); +is(form.foo2, undefined, "Form.foo2 should not longer be there"); var img0 = document.getElementById("img0"); ok(img0, "img0 exists"); is(form.bar0, img0, "Form.bar0 should exist"); img0.setAttribute("name", "old_bar0"); +is(form.old_bar0, img0, "Form.bar0 is still here"); is(form.bar0, img0, "Form.bar0 is still here"); img0.parentNode.removeChild(img0); -todo_is(form.bar0, undefined, "Form.bar0 should not be here"); +is(form.bar0, undefined, "Form.bar0 should not be here"); </script> </pre> </body> </html>
--- a/content/media/AudioNodeStream.h +++ b/content/media/AudioNodeStream.h @@ -103,16 +103,22 @@ public: bool IsAudioParamStream() const { return mAudioParamStream; } const OutputChunks& LastChunks() const { return mLastChunks; } + virtual bool MainThreadNeedsUpdates() const MOZ_OVERRIDE + { + // Only source and external streams need updates on the main thread. + return (mKind == MediaStreamGraph::SOURCE_STREAM && mFinished) || + mKind == MediaStreamGraph::EXTERNAL_STREAM; + } // Any thread AudioNodeEngine* Engine() { return mEngine; } TrackRate SampleRate() const { return mSampleRate; } protected: void FinishOutput();
--- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -888,28 +888,34 @@ MediaStreamGraphImpl::PlayVideo(MediaStr } } void MediaStreamGraphImpl::PrepareUpdatesToMainThreadState(bool aFinalUpdate) { mMonitor.AssertCurrentThreadOwns(); + mStreamUpdates.SetCapacity(mStreamUpdates.Length() + mStreams.Length()); for (uint32_t i = 0; i < mStreams.Length(); ++i) { MediaStream* stream = mStreams[i]; + if (!stream->MainThreadNeedsUpdates()) { + continue; + } StreamUpdate* update = mStreamUpdates.AppendElement(); update->mGraphUpdateIndex = stream->mGraphUpdateIndices.GetAt(mCurrentTime); update->mStream = stream; update->mNextMainThreadCurrentTime = GraphTimeToStreamTime(stream, mCurrentTime); update->mNextMainThreadFinished = stream->mFinished && StreamTimeToGraphTime(stream, stream->GetBufferEnd()) <= mCurrentTime; } - mUpdateRunnables.MoveElementsFrom(mPendingUpdateRunnables); + if (!mPendingUpdateRunnables.IsEmpty()) { + mUpdateRunnables.MoveElementsFrom(mPendingUpdateRunnables); + } // Don't send the message to the main thread if it's not going to have // any work to do. if (aFinalUpdate || !mUpdateRunnables.IsEmpty() || !mCurrentTaskMessageQueue.IsEmpty() || !mStreamUpdates.IsEmpty()) { EnsureStableStateEventPosted();
--- a/content/media/MediaStreamGraph.h +++ b/content/media/MediaStreamGraph.h @@ -438,16 +438,22 @@ public: void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment); DOMMediaStream* GetWrapper() { NS_ASSERTION(NS_IsMainThread(), "Only use DOMMediaStream on main thread"); return mWrapper; } + // Return true if the main thread needs to observe updates from this stream. + virtual bool MainThreadNeedsUpdates() const + { + return true; + } + protected: virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime, GraphTime aBlockedTime) { mBufferStartTime += aBlockedTime; mGraphUpdateIndices.InsertTimeAtStart(aBlockedTime); mGraphUpdateIndices.AdvanceCurrentTime(aCurrentTime); mExplicitBlockerCount.AdvanceCurrentTime(aCurrentTime); @@ -932,17 +938,17 @@ public: * tracks, whichever is greater. * TODO at some point we will probably need to add API to select * particular tracks of each input stream. */ ProcessedMediaStream* CreateTrackUnionStream(DOMMediaStream* aWrapper); // Internal AudioNodeStreams can only pass their output to another // AudioNode, whereas external AudioNodeStreams can pass their output // to an nsAudioStream for playback. - enum AudioNodeStreamKind { INTERNAL_STREAM, EXTERNAL_STREAM }; + enum AudioNodeStreamKind { SOURCE_STREAM, INTERNAL_STREAM, EXTERNAL_STREAM }; /** * Create a stream that will process audio for an AudioNode. * Takes ownership of aEngine. aSampleRate is the sampling rate used * for the stream. If 0 is passed, the sampling rate of the engine's * node will get used. */ AudioNodeStream* CreateAudioNodeStream(AudioNodeEngine* aEngine, AudioNodeStreamKind aKind,
--- a/content/media/VideoUtils.h +++ b/content/media/VideoUtils.h @@ -159,17 +159,17 @@ CheckedInt64 UsecsToFrames(int64_t aUsec // Number of microseconds per second. 1e6. static const int64_t USECS_PER_S = 1000000; // Number of microseconds per millisecond. static const int64_t USECS_PER_MS = 1000; // Converts seconds to milliseconds. -#define SECONDS_TO_MS(s) ((s) / PR_MSEC_PER_SEC) +#define MS_TO_SECONDS(s) ((s) / PR_MSEC_PER_SEC) // The maximum height and width of the video. Used for // sanitizing the memory allocation of the RGB buffer. // The maximum resolution we anticipate encountering in the // wild is 2160p - 3840x2160 pixels. static const int32_t MAX_VIDEO_WIDTH = 4000; static const int32_t MAX_VIDEO_HEIGHT = 3000;
--- a/content/media/WebVTTLoadListener.cpp +++ b/content/media/WebVTTLoadListener.cpp @@ -155,17 +155,17 @@ WebVTTLoadListener::ParseChunk(nsIInputS void WebVTTLoadListener::OnParsedCue(webvtt_cue* aCue) { const char* text = webvtt_string_text(&aCue->body); nsRefPtr<TextTrackCue> textTrackCue = new TextTrackCue(mElement->OwnerDoc()->GetParentObject(), - SECONDS_TO_MS(aCue->from), SECONDS_TO_MS(aCue->until), + MS_TO_SECONDS(aCue->from), MS_TO_SECONDS(aCue->until), NS_ConvertUTF8toUTF16(text), mElement, aCue->node_head); text = webvtt_string_text(&aCue->id); textTrackCue->SetId(NS_ConvertUTF8toUTF16(text)); textTrackCue->SetSnapToLines(aCue->snap_to_lines); textTrackCue->SetSize(aCue->settings.size);
--- a/content/media/webaudio/AudioBufferSourceNode.cpp +++ b/content/media/webaudio/AudioBufferSourceNode.cpp @@ -433,17 +433,17 @@ AudioBufferSourceNode::AudioBufferSource , mDuration(std::numeric_limits<double>::min()) , mPlaybackRate(new AudioParam(this, SendPlaybackRateToStream, 1.0f)) , mLoop(false) , mStartCalled(false) , mStopped(false) { mStream = aContext->Graph()->CreateAudioNodeStream( new AudioBufferSourceNodeEngine(this, aContext->Destination()), - MediaStreamGraph::INTERNAL_STREAM); + MediaStreamGraph::SOURCE_STREAM); mStream->AddMainThreadListener(this); } AudioBufferSourceNode::~AudioBufferSourceNode() { if (Context()) { Context()->UnregisterAudioBufferSourceNode(this); }
--- a/content/media/webaudio/AudioContext.cpp +++ b/content/media/webaudio/AudioContext.cpp @@ -361,17 +361,17 @@ AudioContext::DecodeAudioData(const Arra // Failed type sniffing will be handled by AsyncDecodeMedia. nsAutoCString contentType; NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, aBuffer.Data(), aBuffer.Length(), contentType); nsCOMPtr<DecodeErrorCallback> failureCallback; if (aFailureCallback.WasPassed()) { - failureCallback = aFailureCallback.Value().get(); + failureCallback = &aFailureCallback.Value(); } nsAutoPtr<WebAudioDecodeJob> job( new WebAudioDecodeJob(contentType, this, &aSuccessCallback, failureCallback)); mDecoder.AsyncDecodeMedia(contentType.get(), aBuffer.Data(), aBuffer.Length(), *job); // Transfer the ownership to mDecodeJobs mDecodeJobs.AppendElement(job.forget());
--- a/content/xbl/src/nsXBLDocumentInfo.cpp +++ b/content/xbl/src/nsXBLDocumentInfo.cpp @@ -114,33 +114,33 @@ nsXBLDocGlobalObject::doCheckAccess(JSCo nsresult rv = ssm->CheckPropertyAccess(cx, base, JS_GetClass(base)->name, id, accessType); return NS_SUCCEEDED(rv); } static JSBool nsXBLDocGlobalObject_getProperty(JSContext *cx, JSHandleObject obj, - JSHandleId id, JSMutableHandleValue vp) + JSHandleId id, JS::MutableHandle<JS::Value> vp) { return nsXBLDocGlobalObject:: doCheckAccess(cx, obj, id, nsIXPCSecurityManager::ACCESS_GET_PROPERTY); } static JSBool nsXBLDocGlobalObject_setProperty(JSContext *cx, JSHandleObject obj, - JSHandleId id, JSBool strict, JSMutableHandleValue vp) + JSHandleId id, JSBool strict, JS::MutableHandle<JS::Value> vp) { return nsXBLDocGlobalObject:: doCheckAccess(cx, obj, id, nsIXPCSecurityManager::ACCESS_SET_PROPERTY); } static JSBool nsXBLDocGlobalObject_checkAccess(JSContext *cx, JSHandleObject obj, JSHandleId id, - JSAccessMode mode, JSMutableHandleValue vp) + JSAccessMode mode, JS::MutableHandle<JS::Value> vp) { uint32_t translated; if (mode & JSACC_WRITE) { translated = nsIXPCSecurityManager::ACCESS_SET_PROPERTY; } else { translated = nsIXPCSecurityManager::ACCESS_GET_PROPERTY; }
--- a/content/xbl/src/nsXBLMaybeCompiled.h +++ b/content/xbl/src/nsXBLMaybeCompiled.h @@ -60,26 +60,26 @@ private: // An pointer that represents the function before being compiled, with // BIT_UNCOMPILED set. uintptr_t mUncompiled; // The JS object for the compiled result. JSObject* mCompiled; }; - friend class js::RootMethods<nsXBLMaybeCompiled<UncompiledT> >; + friend class js::GCMethods<nsXBLMaybeCompiled<UncompiledT> >; }; /* Add support for JS::Heap<nsXBLMaybeCompiled>. */ namespace js { template <class UncompiledT> -struct RootMethods<nsXBLMaybeCompiled<UncompiledT> > : public RootMethods<JSObject *> +struct GCMethods<nsXBLMaybeCompiled<UncompiledT> > : public GCMethods<JSObject *> { - typedef struct RootMethods<JSObject *> Base; + typedef struct GCMethods<JSObject *> Base; static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); } static bool poisoned(nsXBLMaybeCompiled<UncompiledT> function) { return function.IsCompiled() && Base::poisoned(function.GetJSFunction()); }
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -12144,17 +12144,17 @@ nsDocShell::OnLinkClickSync(nsIContent * } if (!IsOKToLoadURI(aURI)) { return NS_OK; } // XXX When the linking node was HTMLFormElement, it is synchronous event. // That is, the caller of this method is not |OnLinkClickEvent::Run()| - // but |nsHTMLFormElement::SubmitSubmission(...)|. + // but |HTMLFormElement::SubmitSubmission(...)|. if (nsGkAtoms::form == aContent->Tag() && ShouldBlockLoadingForBackButton()) { return NS_OK; } if (aContent->IsEditable()) { return NS_OK; }
--- a/dom/apps/src/OfflineCacheInstaller.jsm +++ b/dom/apps/src/OfflineCacheInstaller.jsm @@ -73,17 +73,17 @@ function storeCache(applicationCache, ur applicationCache.markEntry(url, itemType); cacheEntry.close(); } }); } function readFile(aFile, aCallback) { let channel = NetUtil.newChannel(aFile); - channel.contentType = "pain/text"; + channel.contentType = "plain/text"; NetUtil.asyncFetch(channel, function(aStream, aResult) { if (!Components.isSuccessCode(aResult)) { Cu.reportError("OfflineCacheInstaller: Could not read file " + aFile.path); if (aCallback) aCallback(null); return; }
--- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -521,17 +521,17 @@ static nsDOMClassInfoData sClassInfoData #undef MOZ_GENERATED_EVENT_LIST NS_DEFINE_CLASSINFO_DATA(DeviceAcceleration, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(DeviceRotationRate, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) // HTML element classes - NS_DEFINE_CLASSINFO_DATA(HTMLFormElement, nsHTMLFormElementSH, + NS_DEFINE_CLASSINFO_DATA(HTMLFormElement, HTMLFormElementSH, ELEMENT_SCRIPTABLE_FLAGS | nsIXPCScriptable::WANT_GETPROPERTY | nsIXPCScriptable::WANT_NEWENUMERATE) // CSS classes NS_DEFINE_CLASSINFO_DATA(CSSStyleRule, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(CSSCharsetRule, nsDOMGenericSH, @@ -2647,17 +2647,17 @@ static JSClass sGlobalScopePolluterClass JS_ConvertStub, nullptr }; // static JSBool nsWindowSH::GlobalScopePolluterGetProperty(JSContext *cx, JSHandleObject obj, - JSHandleId id, JSMutableHandleValue vp) + JSHandleId id, JS::MutableHandle<JS::Value> vp) { // Someone is accessing a element by referencing its name/id in the // global scope, do a security check to make sure that's ok. nsresult rv = sSecMan->CheckPropertyAccess(cx, ::JS_GetGlobalForObject(cx, obj), "Window", id, nsIXPCSecurityManager::ACCESS_GET_PROPERTY); @@ -2670,17 +2670,17 @@ nsWindowSH::GlobalScopePolluterGetProper } return JS_TRUE; } // Gets a subframe. static JSBool ChildWindowGetter(JSContext *cx, JSHandleObject obj, JSHandleId id, - JSMutableHandleValue vp) + JS::MutableHandle<JS::Value> vp) { MOZ_ASSERT(JSID_IS_STRING(id)); // Grab the native DOM window. vp.setUndefined(); nsCOMPtr<nsISupports> winSupports = do_QueryInterface(nsDOMClassInfo::XPConnect()->GetNativeOfWrapper(cx, obj)); if (!winSupports) return true; @@ -3153,17 +3153,17 @@ static const IDBConstant sIDBConstants[] { IDBConstant::IDBRequest, "LOADING", "pending" }, { IDBConstant::IDBRequest, "DONE", "done" }, { IDBConstant::IDBTransaction, "READ_ONLY", "readonly" }, { IDBConstant::IDBTransaction, "READ_WRITE", "readwrite" }, { IDBConstant::IDBTransaction, "VERSION_CHANGE", "versionchange" }, }; static JSBool -IDBConstantGetter(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) +IDBConstantGetter(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp) { JSString *idstr = JSID_TO_STRING(id); unsigned index; for (index = 0; index < mozilla::ArrayLength(sIDBConstants); index++) { JSBool match; if (!JS_StringEqualsAscii(cx, idstr, sIDBConstants[index].name, &match)) { return JS_FALSE; } @@ -4290,30 +4290,30 @@ LocationSetterGuts(JSContext *cx, JSObje NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED); return location->SetHref(depStr); } template<class Interface> static JSBool LocationSetter(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, - JSMutableHandleValue vp) + JS::MutableHandle<JS::Value> vp) { nsresult rv = LocationSetterGuts<Interface>(cx, obj, vp.address()); if (NS_FAILED(rv)) { xpc::Throw(cx, rv); return JS_FALSE; } return JS_TRUE; } static JSBool LocationSetterUnwrapper(JSContext *cx, JSHandleObject obj_, JSHandleId id, JSBool strict, - JSMutableHandleValue vp) + JS::MutableHandle<JS::Value> vp) { JS::RootedObject obj(cx, obj_); JSObject *wrapped = XPCWrapper::UnsafeUnwrapSecurityWrapper(obj); if (wrapped) { obj = wrapped; } @@ -5696,17 +5696,17 @@ nsHTMLDocumentSH::GetDocumentAllNodeList return JS_FALSE; } return *nodeList != nullptr; } JSBool nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSHandleObject obj_, - JSHandleId id, JSMutableHandleValue vp) + JSHandleId id, JS::MutableHandle<JS::Value> vp) { JS::Rooted<JSObject*> obj(cx, obj_); // document.all.item and .namedItem get their value in the // newResolve hook, so nothing to do for those properties here. And // we need to return early to prevent <div id="item"> from shadowing // document.all.item(), etc. if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) { @@ -5886,63 +5886,63 @@ nsHTMLDocumentSH::CallToGetPropMapper(JS return ::JS_GetUCProperty(cx, self, chars, length, vp); } // HTMLFormElement helper NS_IMETHODIMP -nsHTMLFormElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *aObj, jsid aId, - uint32_t flags, JSObject **objp, - bool *_retval) +HTMLFormElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper, + JSContext *cx, JSObject *aObj, jsid aId, + uint32_t flags, JSObject **objp, + bool *_retval) { JS::Rooted<JSObject*> obj(cx, aObj); JS::Rooted<jsid> id(cx, aId); // For native wrappers, do not resolve random names on form if ((!(JSRESOLVE_ASSIGNING & flags)) && JSID_IS_STRING(id) && (!ObjectIsNativeWrapper(cx, obj) || xpc::WrapperFactory::XrayWrapperNotShadowing(obj, id))) { nsCOMPtr<nsIForm> form(do_QueryWrappedNative(wrapper, obj)); nsDependentJSString name(id); nsWrapperCache* cache; nsCOMPtr<nsISupports> result = - static_cast<nsHTMLFormElement*>(form.get())->FindNamedItem(name, &cache); + static_cast<HTMLFormElement*>(form.get())->FindNamedItem(name, &cache); if (result) { *_retval = ::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nullptr, nullptr, JSPROP_ENUMERATE); *objp = obj; return *_retval ? NS_OK : NS_ERROR_FAILURE; } } return nsElementSH::NewResolve(wrapper, cx, obj, id, flags, objp, _retval); } NS_IMETHODIMP -nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *aObj, jsid aId, - jsval *vp, bool *_retval) +HTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, + JSContext *cx, JSObject *aObj, jsid aId, + jsval *vp, bool *_retval) { JS::Rooted<JSObject*> obj(cx, aObj); JS::Rooted<jsid> id(cx, aId); nsCOMPtr<nsIForm> form(do_QueryWrappedNative(wrapper, obj)); if (JSID_IS_STRING(id)) { // For native wrappers, do not get random names on form nsDependentJSString name(id); nsWrapperCache* cache; nsCOMPtr<nsISupports> result = - static_cast<nsHTMLFormElement*>(form.get())->FindNamedItem(name, &cache); + static_cast<HTMLFormElement*>(form.get())->FindNamedItem(name, &cache); if (result) { // Wrap result, result can be either an element or a list of // elements nsresult rv = WrapNative(cx, obj, result, cache, true, vp); return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING; } } else { @@ -5960,20 +5960,20 @@ nsHTMLFormElementSH::GetProperty(nsIXPCo } } } return NS_OK; } NS_IMETHODIMP -nsHTMLFormElementSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, - uint32_t enum_op, jsval *statep, - jsid *idp, bool *_retval) +HTMLFormElementSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, + JSContext *cx, JSObject *obj, + uint32_t enum_op, jsval *statep, + jsid *idp, bool *_retval) { switch (enum_op) { case JSENUMERATE_INIT: case JSENUMERATE_INIT_ALL: { nsCOMPtr<nsIForm> form(do_QueryWrappedNative(wrapper, obj)); if (!form) {
--- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -367,17 +367,17 @@ public: JSObject *obj) MOZ_OVERRIDE; NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, JSObject * *_retval) MOZ_OVERRIDE; static JSBool GlobalScopePolluterNewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags, JS::MutableHandle<JSObject*> objp); static JSBool GlobalScopePolluterGetProperty(JSContext *cx, JSHandleObject obj, - JSHandleId id, JSMutableHandleValue vp); + JSHandleId id, JS::MutableHandle<JS::Value> vp); static JSBool InvalidateGlobalScopePolluter(JSContext *cx, JS::Handle<JSObject*> obj); static nsresult InstallGlobalScopePolluter(JSContext *cx, JS::Handle<JSObject*> obj); static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { return new nsWindowSH(aData); } @@ -597,34 +597,34 @@ extern JSClass sHTMLDocumentAllClass; class nsHTMLDocumentSH { protected: static JSBool GetDocumentAllNodeList(JSContext *cx, JS::Handle<JSObject*> obj, nsDocument *doc, nsContentList **nodeList); public: static JSBool DocumentAllGetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, - JSMutableHandleValue vp); + JS::MutableHandle<JS::Value> vp); static JSBool DocumentAllNewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags, JS::MutableHandle<JSObject*> objp); static void ReleaseDocument(JSFreeOp *fop, JSObject *obj); static JSBool CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp); }; // HTMLFormElement helper -class nsHTMLFormElementSH : public nsElementSH +class HTMLFormElementSH : public nsElementSH { protected: - nsHTMLFormElementSH(nsDOMClassInfoData* aData) : nsElementSH(aData) + HTMLFormElementSH(nsDOMClassInfoData* aData) : nsElementSH(aData) { } - virtual ~nsHTMLFormElementSH() + virtual ~HTMLFormElementSH() { } public: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, jsid id, uint32_t flags, JSObject **objp, bool *_retval) MOZ_OVERRIDE; NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, @@ -633,17 +633,17 @@ public: NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, uint32_t enum_op, jsval *statep, jsid *idp, bool *_retval) MOZ_OVERRIDE; static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { - return new nsHTMLFormElementSH(aData); + return new HTMLFormElementSH(aData); } }; // Plugin helper class nsPluginSH : public nsNamedArraySH {
--- a/dom/bindings/BindingDeclarations.h +++ b/dom/bindings/BindingDeclarations.h @@ -260,35 +260,43 @@ public: } template <class T1, class T2> void Construct(const T1 &t1, const T2 &t2) { mImpl.construct(t1, t2); } - const InternalType& Value() const + const T& Value() const { return mImpl.ref(); } + // Return InternalType here so we can work with it usefully. InternalType& Value() { return mImpl.ref(); } + // And an explicit way to get the InternalType even if we're const. + const InternalType& InternalValue() const + { + return mImpl.ref(); + } + // If we ever decide to add conversion operators for optional arrays // like the ones Nullable has, we'll need to ensure that Maybe<> has // the boolean before the actual data. private: // Forbid copy-construction and assignment Optional_base(const Optional_base& other) MOZ_DELETE; const Optional_base &operator=(const Optional_base &other) MOZ_DELETE; +protected: Maybe<InternalType> mImpl; }; template<typename T> class Optional : public Optional_base<T, T> { public: Optional() : @@ -313,16 +321,30 @@ public: Optional_base<JS::Handle<T>, JS::Rooted<T> >() { this->Construct(cx); } Optional(JSContext* cx, const T& aValue) : Optional_base<JS::Handle<T>, JS::Rooted<T> >(cx, aValue) {} + + // Override the const Value() to return the right thing so we're not + // returning references to temporaries. + JS::Handle<T> Value() const + { + return this->mImpl.ref(); + } + + // And we have to override the non-const one too, since we're + // shadowing the one on the superclass. + JS::Rooted<T>& Value() + { + return this->mImpl.ref(); + } }; // A specialization of Optional for JSObject* to make sure that when someone // calls Construct() on it we will pre-initialized the JSObject* to nullptr so // it can be traced safely. template<> class Optional<JSObject*> : public Optional_base<JSObject*, JSObject*> { @@ -374,16 +396,61 @@ public: template <class T1> void Construct(const T1& t1) { Optional_base<JS::Value, JS::Value>::Construct(t1); } }; +// A specialization of Optional for NonNull that lets us get a T& from Value() +template<typename U> class NonNull; +template<typename T> +class Optional<NonNull<T> > : public Optional_base<T, NonNull<T> > +{ +public: + // We want our Value to actually return a non-const reference, even + // if we're const. At least for things that are normally pointer + // types... + T& Value() const + { + return *this->mImpl.ref().get(); + } + + // And we have to override the non-const one too, since we're + // shadowing the one on the superclass. + NonNull<T>& Value() + { + return this->mImpl.ref(); + } +}; + +// A specialization of Optional for OwningNonNull that lets us get a +// T& from Value() +template<typename U> class OwningNonNull; +template<typename T> +class Optional<OwningNonNull<T> > : public Optional_base<T, OwningNonNull<T> > +{ +public: + // We want our Value to actually return a non-const reference, even + // if we're const. At least for things that are normally pointer + // types... + T& Value() const + { + return *this->mImpl.ref().get(); + } + + // And we have to override the non-const one too, since we're + // shadowing the one on the superclass. + OwningNonNull<T>& Value() + { + return this->mImpl.ref(); + } +}; + // Specialization for strings. // XXXbz we can't pull in FakeDependentString here, because it depends on // internal strings. So we just have to forward-declare it and reimplement its // ToAStringPtr. struct FakeDependentString; template<> @@ -423,16 +490,82 @@ private: // Forbid copy-construction and assignment Optional(const Optional& other) MOZ_DELETE; const Optional &operator=(const Optional &other) MOZ_DELETE; bool mPassed; const nsAString* mStr; }; +template<class T> +class NonNull +{ +public: + NonNull() +#ifdef DEBUG + : inited(false) +#endif + {} + + operator T&() { + MOZ_ASSERT(inited); + MOZ_ASSERT(ptr, "NonNull<T> was set to null"); + return *ptr; + } + + operator const T&() const { + MOZ_ASSERT(inited); + MOZ_ASSERT(ptr, "NonNull<T> was set to null"); + return *ptr; + } + + void operator=(T* t) { + ptr = t; + MOZ_ASSERT(ptr); +#ifdef DEBUG + inited = true; +#endif + } + + template<typename U> + void operator=(U* t) { + ptr = t->ToAStringPtr(); + MOZ_ASSERT(ptr); +#ifdef DEBUG + inited = true; +#endif + } + + T** Slot() { +#ifdef DEBUG + inited = true; +#endif + return &ptr; + } + + T* Ptr() { + MOZ_ASSERT(inited); + MOZ_ASSERT(ptr, "NonNull<T> was set to null"); + return ptr; + } + + // Make us work with smart-ptr helpers that expect a get() + T* get() const { + MOZ_ASSERT(inited); + MOZ_ASSERT(ptr); + return ptr; + } + +protected: + T* ptr; +#ifdef DEBUG + bool inited; +#endif +}; + // Class for representing sequences in arguments. We use a non-auto array // because that allows us to use sequences of sequences and the like. This // needs to be fallible because web content controls the length of the array, // and can easily try to create very large lengths. template<typename T> class Sequence : public FallibleTArray<T> { public:
--- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -1750,17 +1750,17 @@ InterfaceHasInstance(JSContext* cx, JS:: } } *bp = false; return true; } JSBool -InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue vp, +InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JS::MutableHandle<JS::Value> vp, JSBool* bp) { if (!vp.isObject()) { *bp = false; return true; } JS::Rooted<JSObject*> instanceObject(cx, &vp.toObject());
--- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1346,75 +1346,16 @@ GetPropertyOnPrototype(JSContext* cx, JS JS::Value* vp); bool HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy, DOMProxyHandler* handler, JS::Handle<jsid> id); template<class T> -class NonNull -{ -public: - NonNull() -#ifdef DEBUG - : inited(false) -#endif - {} - - operator T&() { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr, "NonNull<T> was set to null"); - return *ptr; - } - - operator const T&() const { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr, "NonNull<T> was set to null"); - return *ptr; - } - - void operator=(T* t) { - ptr = t; - MOZ_ASSERT(ptr); -#ifdef DEBUG - inited = true; -#endif - } - - template<typename U> - void operator=(U* t) { - ptr = t->ToAStringPtr(); - MOZ_ASSERT(ptr); -#ifdef DEBUG - inited = true; -#endif - } - - T* Ptr() { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr, "NonNull<T> was set to null"); - return ptr; - } - - // Make us work with smart-ptr helpers that expect a get() - T* get() const { - MOZ_ASSERT(inited); - MOZ_ASSERT(ptr); - return ptr; - } - -protected: - T* ptr; -#ifdef DEBUG - bool inited; -#endif -}; - -template<class T> class OwningNonNull { public: OwningNonNull() #ifdef DEBUG : inited(false) #endif {} @@ -2024,17 +1965,17 @@ ReparentWrapper(JSContext* aCx, JS::Hand * * instance should not be a security wrapper. */ JSBool InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<JSObject*> instance, JSBool* bp); JSBool -InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue vp, +InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JS::MutableHandle<JS::Value> vp, JSBool* bp); // Helper for lenient getters/setters to report to console. If this // returns false, we couldn't even get a global. bool ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle<JSObject*> obj); inline JSObject*
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -324,17 +324,16 @@ DOMInterfaces = { 'resultNotAddRefed': [ 'threshold', 'knee', 'ratio', 'reduction', 'attack', 'release' ], 'binaryNames': { 'release': 'getRelease' }, }, 'Element': { - 'hasXPConnectImpls': True, 'resultNotAddRefed': [ 'classList', 'attributes', 'children', 'firstElementChild', 'lastElementChild', 'previousElementSibling', 'nextElementSibling', 'getAttributeNode', 'getAttributeNodeNS', 'querySelector' ] }, 'Event': [ @@ -453,17 +452,16 @@ DOMInterfaces = { 'nativeType': 'nsHTMLDocument', 'resultNotAddRefed': [ 'body', 'head', 'images', 'embeds', 'plugins', 'links', 'forms', 'scripts', 'anchors', 'applets' ], 'implicitJSContext': [ 'open', 'write', 'writeln' ] }, 'HTMLElement': { 'nativeType': 'nsGenericHTMLElement', - 'hasXPConnectImpls': True, 'resultNotAddRefed': [ 'itemType', 'itemRef', 'itemProp', 'properties', 'contextMenu', 'style', 'offsetParent' ] }, 'HTMLEmbedElement': { 'nativeType': 'mozilla::dom::HTMLSharedObjectElement' @@ -687,17 +685,16 @@ DOMInterfaces = { 'headerFile': 'nsDOMMutationObserver.h', 'resultNotAddRefed': [ 'target', 'addedNodes', 'removedNodes', 'previousSibling', 'nextSibling' ] }, 'Node': { 'nativeType': 'nsINode', 'concrete': False, - 'hasXPConnectImpls': True, 'resultNotAddRefed': [ 'ownerDocument', 'parentNode', 'parentElement', 'childNodes', 'firstChild', 'lastChild', 'previousSibling', 'nextSibling', 'insertBefore', 'appendChild', 'replaceChild', 'removeChild', 'attributes' ] }, 'NodeIterator': { @@ -1601,24 +1598,16 @@ def addExternalIface(iface, nativeType=N } if not nativeType is None: domInterface['nativeType'] = nativeType if not headerFile is None: domInterface['headerFile'] = headerFile domInterface['notflattened'] = notflattened DOMInterfaces[iface] = domInterface -# If you add one of these, you need to make sure nsDOMQS.h has the relevant -# macros added for it -def addExternalHTMLElement(element): - nativeElement = 'ns' + element - addExternalIface(element, nativeType=nativeElement, - headerFile=nativeElement + '.h') - -addExternalHTMLElement('HTMLFormElement') addExternalIface('ActivityOptions', nativeType='nsIDOMMozActivityOptions', headerFile='nsIDOMActivityOptions.h') addExternalIface('Counter') addExternalIface('CSSRule') addExternalIface('DeviceAcceleration', headerFile='nsIDOMDeviceMotionEvent.h', notflattened=True) addExternalIface('DeviceRotationRate', headerFile='nsIDOMDeviceMotionEvent.h', notflattened=True) addExternalIface('mozIDOMApplication', nativeType='mozIDOMApplication', headerFile='nsIDOMApplicationRegistry.h') addExternalIface('CSSRuleList')
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -926,17 +926,17 @@ class CGAbstractClassHook(CGAbstractStat assert(False) class CGAddPropertyHook(CGAbstractClassHook): """ A hook for addProperty, used to preserve our wrapper from GC. """ def __init__(self, descriptor): args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'), - Argument('JSHandleId', 'id'), Argument('JSMutableHandleValue', 'vp')] + Argument('JSHandleId', 'id'), Argument('JS::MutableHandle<JS::Value>', 'vp')] CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME, 'JSBool', args) def generate_code(self): assert not self.descriptor.workers and self.descriptor.wrapperCache if self.descriptor.nativeOwnership == 'nsisupports': preserveArgs = "reinterpret_cast<nsISupports*>(self), self" else: @@ -1183,17 +1183,17 @@ class CGNamedConstructors(CGThing): namedConstructors = CGWrapper(CGIndenter(namedConstructors), pre="static const NamedConstructor namedConstructors[] = {\n", post="\n};\n") return nativePropertyHooks + namedConstructors.define() class CGClassHasInstanceHook(CGAbstractStaticMethod): def __init__(self, descriptor): args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'), - Argument('JSMutableHandleValue', 'vp'), Argument('JSBool*', 'bp')] + Argument('JS::MutableHandle<JS::Value>', 'vp'), Argument('JSBool*', 'bp')] CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME, 'JSBool', args) def define(self): if not NeedsGeneratedHasInstance(self.descriptor): return "" return CGAbstractStaticMethod.define(self) @@ -8012,17 +8012,17 @@ class CGDictionary(CGThing): def getMemberDefinition(self, memberInfo): member = memberInfo[0] declType = memberInfo[1].declType memberLoc = self.makeMemberName(member.identifier.name) if member.defaultValue: memberData = memberLoc else: # The data is inside the Optional<> - memberData = "%s.Value()" % memberLoc + memberData = "%s.InternalValue()" % memberLoc if self.workers: propDef = ( 'JS_DefineProperty(cx, obj, "%s", temp, nullptr, nullptr, JSPROP_ENUMERATE)' % member.identifier.name) else: propDef = ( 'JS_DefinePropertyById(cx, obj, %s, temp, nullptr, nullptr, JSPROP_ENUMERATE)' %
--- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -104,38 +104,38 @@ NPClass nsJSObjWrapper::sJSObjWrapperNPC nsJSObjWrapper::NP_GetProperty, nsJSObjWrapper::NP_SetProperty, nsJSObjWrapper::NP_RemoveProperty, nsJSObjWrapper::NP_Enumerate, nsJSObjWrapper::NP_Construct }; static JSBool -NPObjWrapper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); +NPObjWrapper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp); static JSBool NPObjWrapper_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded); static JSBool NPObjWrapper_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, - JSMutableHandleValue vp); + JS::MutableHandle<JS::Value> vp); static JSBool -NPObjWrapper_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); +NPObjWrapper_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp); static JSBool NPObjWrapper_newEnumerate(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, JS::Value *statep, jsid *idp); static JSBool NPObjWrapper_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags, JS::MutableHandle<JSObject*> objp); static JSBool -NPObjWrapper_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp); +NPObjWrapper_Convert(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandle<JS::Value> vp); static void NPObjWrapper_Finalize(JSFreeOp *fop, JSObject *obj); static JSBool NPObjWrapper_Call(JSContext *cx, unsigned argc, JS::Value *vp); static JSBool @@ -166,17 +166,17 @@ JSClass sNPObjectJSWrapperClass = typedef struct NPObjectMemberPrivate { JSObject *npobjWrapper; JS::Value fieldValue; NPIdentifier methodName; NPP npp; } NPObjectMemberPrivate; static JSBool -NPObjectMember_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp); +NPObjectMember_Convert(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandle<JS::Value> vp); static void NPObjectMember_Finalize(JSFreeOp *fop, JSObject *obj); static JSBool NPObjectMember_Call(JSContext *cx, unsigned argc, JS::Value *vp); static void @@ -1103,17 +1103,17 @@ GetNPObject(JSContext *cx, JSObject *obj return (NPObject *)::JS_GetPrivate(obj); } // Does not actually add a property because this is always followed by a // SetProperty call. static JSBool -NPObjWrapper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) +NPObjWrapper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp) { NPObject *npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class || !npobj->_class->hasProperty || !npobj->_class->hasMethod) { ThrowJSException(cx, "Bad NPObject as private data!"); return JS_FALSE; @@ -1178,17 +1178,17 @@ NPObjWrapper_DelProperty(JSContext *cx, if (!npobj->_class->removeProperty(npobj, identifier)) *succeeded = false; return ReportExceptionIfPending(cx); } static JSBool NPObjWrapper_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, - JSMutableHandleValue vp) + JS::MutableHandle<JS::Value> vp) { NPObject *npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class || !npobj->_class->hasProperty || !npobj->_class->setProperty) { ThrowJSException(cx, "Bad NPObject as private data!"); return JS_FALSE; @@ -1237,17 +1237,17 @@ NPObjWrapper_SetProperty(JSContext *cx, return JS_FALSE; } return JS_TRUE; } static JSBool -NPObjWrapper_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) +NPObjWrapper_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp) { NPObject *npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class || !npobj->_class->hasProperty || !npobj->_class->hasMethod || !npobj->_class->getProperty) { ThrowJSException(cx, "Bad NPObject as private data!"); return JS_FALSE; @@ -1601,17 +1601,17 @@ NPObjWrapper_NewResolve(JSContext *cx, J return fnc != nullptr; } // no property or method return JS_TRUE; } static JSBool -NPObjWrapper_Convert(JSContext *cx, JSHandleObject obj, JSType hint, JSMutableHandleValue vp) +NPObjWrapper_Convert(JSContext *cx, JSHandleObject obj, JSType hint, JS::MutableHandle<JS::Value> vp) { JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID); // Plugins do not simply use JS_ConvertStub, and the default [[DefaultValue]] // behavior, because that behavior involves calling toString or valueOf on // objects which weren't designed to accommodate this. Usually this wouldn't // be a problem, because the absence of either property, or the presence of // either property with a value that isn't callable, will cause that property @@ -2021,17 +2021,17 @@ CreateNPObjectMember(NPP npp, JSContext memberPrivate->npp = npp; ::JS_RemoveValueRoot(cx, vp); return JS_TRUE; } static JSBool -NPObjectMember_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp) +NPObjectMember_Convert(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandle<JS::Value> vp) { NPObjectMemberPrivate *memberPrivate = (NPObjectMemberPrivate *)::JS_GetInstancePrivate(cx, obj, &sNPObjectMemberClass, nullptr); if (!memberPrivate) { NS_ERROR("no Ambiguous Member Private data!"); return JS_FALSE;
--- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -287,16 +287,17 @@ nsPluginHost::nsPluginHost() Preferences::AddStrongObserver(this, "plugin.disable"); Preferences::AddStrongObserver(this, "plugins.click_to_play"); nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService(); if (obsService) { obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); + obsService->AddObserver(this, "blocklist-updated", false); #ifdef MOZ_WIDGET_ANDROID obsService->AddObserver(this, "application-foreground", false); obsService->AddObserver(this, "application-background", false); #endif } #ifdef PLUGIN_LOGGING nsPluginLogging::gNPNLog = PR_NewLogModule(NPN_LOG_NAME); @@ -1063,27 +1064,22 @@ nsPluginHost::GetStateForType(const nsAC nsresult nsPluginHost::GetBlocklistStateForType(const char *aMimeType, uint32_t *aState) { nsPluginTag *plugin = FindPluginForType(aMimeType, true); if (!plugin) { plugin = FindPluginForType(aMimeType, false); } - if (plugin) { - nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1"); - if (blocklist) { - // The EmptyString()s are so we use the currently running application - // and toolkit versions - return blocklist->GetPluginBlocklistState(plugin, EmptyString(), - EmptyString(), aState); - } + if (!plugin) { + return NS_ERROR_FAILURE; } - return NS_ERROR_FAILURE; + *aState = plugin->GetBlocklistState(); + return NS_OK; } NS_IMETHODIMP nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType, nsACString &aPermissionString) { aPermissionString.Truncate(); uint32_t blocklistState; nsresult rv = GetBlocklistStateForType(aMimeType.Data(), &blocklistState); @@ -1926,35 +1922,27 @@ nsresult nsPluginHost::ScanPluginsDirect pluginTag = new nsPluginTag(&info); pluginFile.FreePluginInfo(info); if (!pluginTag) return NS_ERROR_OUT_OF_MEMORY; pluginTag->mLibrary = library; pluginTag->mLastModifiedTime = fileModTime; - - nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1"); - if (blocklist) { - uint32_t state; - rv = blocklist->GetPluginBlocklistState(pluginTag, EmptyString(), - EmptyString(), &state); - - if (NS_SUCCEEDED(rv)) { - // If the blocklist says it is risky and we have never seen this - // plugin before, then disable it. - // If the blocklist says this is an outdated plugin, warn about - // outdated plugins. - if (state == nsIBlocklistService::STATE_SOFTBLOCKED && !seenBefore) { - pluginTag->SetEnabledState(nsIPluginTag::STATE_DISABLED); - } - if (state == nsIBlocklistService::STATE_OUTDATED && !seenBefore) { - warnOutdated = true; - } - } + uint32_t state = pluginTag->GetBlocklistState(); + + // If the blocklist says it is risky and we have never seen this + // plugin before, then disable it. + // If the blocklist says this is an outdated plugin, warn about + // outdated plugins. + if (state == nsIBlocklistService::STATE_SOFTBLOCKED && !seenBefore) { + pluginTag->SetEnabledState(nsIPluginTag::STATE_DISABLED); + } + if (state == nsIBlocklistService::STATE_OUTDATED && !seenBefore) { + warnOutdated = true; } // Plugin unloading is tag-based. If we created a new tag and loaded // the library in the process then we want to attempt to unload it here. // Only do this if the pref is set for aggressive unloading. if (UnloadPluginsASAP()) { pluginTag->TryUnloadPlugin(false); } @@ -3141,44 +3129,51 @@ nsresult nsPluginHost::NewPluginStreamLi return NS_OK; } NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData) { - if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) { + if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) { OnShutdown(); UnloadPlugins(); sInst->Release(); } - if (!nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) { + if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) { mPluginsDisabled = Preferences::GetBool("plugin.disable", false); mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false); // Unload or load plugins as needed if (mPluginsDisabled) { UnloadPlugins(); } else { LoadPlugins(); } } + if (!strcmp("blocklist-updated", aTopic)) { + nsPluginTag* plugin = mPlugins; + while (plugin) { + plugin->InvalidateBlocklistState(); + plugin = plugin->mNext; + } + } #ifdef MOZ_WIDGET_ANDROID - if (!nsCRT::strcmp("application-background", aTopic)) { + if (!strcmp("application-background", aTopic)) { for(uint32_t i = 0; i < mInstances.Length(); i++) { mInstances[i]->NotifyForeground(false); } } - if (!nsCRT::strcmp("application-foreground", aTopic)) { + if (!strcmp("application-foreground", aTopic)) { for(uint32_t i = 0; i < mInstances.Length(); i++) { if (mInstances[i]->IsOnScreen()) mInstances[i]->NotifyForeground(true); } } - if (!nsCRT::strcmp("memory-pressure", aTopic)) { + if (!strcmp("memory-pressure", aTopic)) { for(uint32_t i = 0; i < mInstances.Length(); i++) { mInstances[i]->MemoryPressure(); } } #endif return NS_OK; }
--- a/dom/plugins/base/nsPluginTags.cpp +++ b/dom/plugins/base/nsPluginTags.cpp @@ -75,31 +75,35 @@ nsPluginTag::nsPluginTag(nsPluginTag* aP mExtensions(aPluginTag->mExtensions), mLibrary(nullptr), mIsJavaPlugin(aPluginTag->mIsJavaPlugin), mIsFlashPlugin(aPluginTag->mIsFlashPlugin), mFileName(aPluginTag->mFileName), mFullPath(aPluginTag->mFullPath), mVersion(aPluginTag->mVersion), mLastModifiedTime(0), - mNiceFileName() + mNiceFileName(), + mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED), + mCachedBlocklistStateValid(false) { } nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo) : mName(aPluginInfo->fName), mDescription(aPluginInfo->fDescription), mLibrary(nullptr), mIsJavaPlugin(false), mIsFlashPlugin(false), mFileName(aPluginInfo->fFileName), mFullPath(aPluginInfo->fFullPath), mVersion(aPluginInfo->fVersion), mLastModifiedTime(0), - mNiceFileName() + mNiceFileName(), + mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED), + mCachedBlocklistStateValid(false) { InitMime(aPluginInfo->fMimeTypeArray, aPluginInfo->fMimeDescriptionArray, aPluginInfo->fExtensionArray, aPluginInfo->fVariantCount); EnsureMembersAreUTF8(); } @@ -118,17 +122,19 @@ nsPluginTag::nsPluginTag(const char* aNa mDescription(aDescription), mLibrary(nullptr), mIsJavaPlugin(false), mIsFlashPlugin(false), mFileName(aFileName), mFullPath(aFullPath), mVersion(aVersion), mLastModifiedTime(aLastModifiedTime), - mNiceFileName() + mNiceFileName(), + mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED), + mCachedBlocklistStateValid(false) { InitMime(aMimeTypes, aMimeDescriptions, aExtensions, static_cast<uint32_t>(aVariants)); if (!aArgsAreUTF8) EnsureMembersAreUTF8(); } nsPluginTag::~nsPluginTag() @@ -533,8 +539,40 @@ nsCString nsPluginTag::GetNiceFileName() } void nsPluginTag::ImportFlagsToPrefs(uint32_t flags) { if (!(flags & NS_PLUGIN_FLAG_ENABLED)) { SetPluginState(ePluginState_Disabled); } } + +uint32_t +nsPluginTag::GetBlocklistState() +{ + if (mCachedBlocklistStateValid) { + return mCachedBlocklistState; + } + + nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1"); + if (!blocklist) { + return nsIBlocklistService::STATE_NOT_BLOCKED; + } + + // The EmptyString()s are so we use the currently running application + // and toolkit versions + uint32_t state; + if (NS_FAILED(blocklist->GetPluginBlocklistState(this, EmptyString(), + EmptyString(), &state))) { + return nsIBlocklistService::STATE_NOT_BLOCKED; + } + + MOZ_ASSERT(state <= UINT16_MAX); + mCachedBlocklistState = (uint16_t) state; + mCachedBlocklistStateValid = true; + return state; +} + +void +nsPluginTag::InvalidateBlocklistState() +{ + mCachedBlocklistStateValid = false; +}
--- a/dom/plugins/base/nsPluginTags.h +++ b/dom/plugins/base/nsPluginTags.h @@ -80,18 +80,24 @@ public: nsRefPtr<nsNPAPIPlugin> mPlugin; bool mIsJavaPlugin; bool mIsFlashPlugin; nsCString mFileName; // UTF-8 nsCString mFullPath; // UTF-8 nsCString mVersion; // UTF-8 int64_t mLastModifiedTime; nsCOMPtr<nsITimer> mUnloadTimer; + + uint32_t GetBlocklistState(); + void InvalidateBlocklistState(); + private: nsCString mNiceFileName; // UTF-8 + uint16_t mCachedBlocklistState; + bool mCachedBlocklistStateValid; void InitMime(const char* const* aMimeTypes, const char* const* aMimeDescriptions, const char* const* aExtensions, uint32_t aVariantCount); nsresult EnsureMembersAreUTF8(); };
--- a/dom/src/notification/Notification.cpp +++ b/dom/src/notification/Notification.cpp @@ -377,17 +377,17 @@ Notification::RequestPermission(const Gl if (!sop) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal(); NotificationPermissionCallback* permissionCallback = nullptr; if (aCallback.WasPassed()) { - permissionCallback = aCallback.Value().get(); + permissionCallback = &aCallback.Value(); } nsCOMPtr<nsIRunnable> request = new NotificationPermissionRequest(principal, window, permissionCallback); NS_DispatchToMainThread(request); } NotificationPermission
--- a/dom/webidl/FormData.webidl +++ b/dom/webidl/FormData.webidl @@ -2,15 +2,13 @@ /* 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 origin of this IDL file is * http://xhr.spec.whatwg.org */ -interface HTMLFormElement; - [Constructor(optional HTMLFormElement form)] interface FormData { void append(DOMString name, Blob value, optional DOMString filename); void append(DOMString name, DOMString value); -}; \ No newline at end of file +};
new file mode 100644 --- /dev/null +++ b/dom/webidl/HTMLFormElement.webidl @@ -0,0 +1,48 @@ +/* -*- 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/. + * + * The origin of this IDL file is + * http://www.whatwg.org/specs/web-apps/current-work/#htmlformelement + * + * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and + * Opera Software ASA. You are granted a license to use, reproduce + * and create derivative works of this document. + */ + +[OverrideBuiltins] +interface HTMLFormElement : HTMLElement { + [Pure, SetterThrows] + attribute DOMString acceptCharset; + [Pure, SetterThrows] + attribute DOMString action; + [Pure, SetterThrows] + attribute DOMString autocomplete; + [Pure, SetterThrows] + attribute DOMString enctype; + [Pure, SetterThrows] + attribute DOMString encoding; + [Pure, SetterThrows] + attribute DOMString method; + [Pure, SetterThrows] + attribute DOMString name; + [Pure, SetterThrows] + attribute boolean noValidate; + [Pure, SetterThrows] + attribute DOMString target; + + [Constant] + readonly attribute HTMLCollection elements; + [Pure] + readonly attribute long length; + + getter Element (unsigned long index); + // TODO this should be: getter (RadioNodeList or HTMLInputElement or HTMLImageElement) (DOMString name); + getter nsISupports (DOMString name); + + [Throws] + void submit(); + void reset(); + boolean checkValidity(); +};
--- a/dom/webidl/WebIDL.mk +++ b/dom/webidl/WebIDL.mk @@ -104,16 +104,17 @@ webidl_files = \ HTMLDirectoryElement.webidl \ HTMLDivElement.webidl \ HTMLDListElement.webidl \ HTMLDocument.webidl \ HTMLElement.webidl \ HTMLEmbedElement.webidl \ HTMLFieldSetElement.webidl \ HTMLFontElement.webidl \ + HTMLFormElement.webidl \ HTMLFrameElement.webidl \ HTMLFrameSetElement.webidl \ HTMLHeadElement.webidl \ HTMLHeadingElement.webidl \ HTMLHRElement.webidl \ HTMLHtmlElement.webidl \ HTMLIFrameElement.webidl \ HTMLImageElement.webidl \
--- a/dom/workers/Events.cpp +++ b/dom/workers/Events.cpp @@ -215,33 +215,33 @@ private: static void Finalize(JSFreeOp* aFop, JSObject* aObj) { JS_ASSERT(IsThisClass(JS_GetClass(aObj))); delete GetJSPrivateSafeish<Event>(aObj); } static JSBool - GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); int32_t slot = JSID_TO_INT(aIdval); const char* name = sProperties[slot - SLOT_FIRST].name; if (!GetInstancePrivate(aCx, aObj, name)) { return false; } aVp.set(JS_GetReservedSlot(aObj, slot)); return true; } static JSBool - GetConstant(JSContext* aCx, JSHandleObject aObj, JSHandleId idval, JSMutableHandleValue aVp) + GetConstant(JSContext* aCx, JSHandleObject aObj, JSHandleId idval, JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(idval)); JS_ASSERT(JSID_TO_INT(idval) >= CAPTURING_PHASE && JSID_TO_INT(idval) <= BUBBLING_PHASE); aVp.set(INT_TO_JSVAL(JSID_TO_INT(idval))); return true; } @@ -500,17 +500,17 @@ private: Finalize(JSFreeOp* aFop, JSObject* aObj) { JS_ASSERT(IsThisClass(JS_GetClass(aObj))); MessageEvent* priv = GetJSPrivateSafeish<MessageEvent>(aObj); delete priv; } static JSBool - GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); int32_t slot = JSID_TO_INT(aIdval); JS_ASSERT(slot >= SLOT_data && slot < SLOT_COUNT); const char* name = sProperties[slot - SLOT_FIRST].name; @@ -707,17 +707,17 @@ private: static void Finalize(JSFreeOp* aFop, JSObject* aObj) { JS_ASSERT(IsThisClass(JS_GetClass(aObj))); delete GetJSPrivateSafeish<ErrorEvent>(aObj); } static JSBool - GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); int32_t slot = JSID_TO_INT(aIdval); JS_ASSERT(slot >= SLOT_message && slot < SLOT_COUNT); const char* name = sProperties[slot - SLOT_FIRST].name; @@ -886,17 +886,17 @@ private: static void Finalize(JSFreeOp* aFop, JSObject* aObj) { JS_ASSERT(JS_GetClass(aObj) == &sClass); delete GetJSPrivateSafeish<ProgressEvent>(aObj); } static JSBool - GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); int32_t slot = JSID_TO_INT(aIdval); JS_ASSERT(slot >= SLOT_lengthComputable && slot < SLOT_COUNT); const char* name = sProperties[slot - SLOT_FIRST].name;
--- a/dom/workers/Exceptions.cpp +++ b/dom/workers/Exceptions.cpp @@ -121,17 +121,17 @@ private: return false; } JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(out)); return true; } static JSBool - GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); int32_t slot = JSID_TO_INT(aIdval); JSClass* classPtr = JS_GetClass(aObj); if (classPtr != &sClass || !GetJSPrivateSafeish<DOMException>(aObj)) { @@ -141,17 +141,17 @@ private: return false; } aVp.set(JS_GetReservedSlot(aObj, slot)); return true; } static JSBool - GetConstant(JSContext* aCx, JSHandleObject aObj, JSHandleId idval, JSMutableHandleValue aVp) + GetConstant(JSContext* aCx, JSHandleObject aObj, JSHandleId idval, JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(idval)); aVp.set(INT_TO_JSVAL(JSID_TO_INT(idval))); return true; } }; JSClass DOMException::sClass = {
--- a/dom/workers/File.cpp +++ b/dom/workers/File.cpp @@ -108,17 +108,17 @@ private: { JS_ASSERT(JS_GetClass(aObj) == &sClass); nsIDOMBlob* blob = GetPrivate(aObj); NS_IF_RELEASE(blob); } static JSBool - GetSize(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetSize(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { nsIDOMBlob* blob = GetInstancePrivate(aCx, aObj, "size"); if (!blob) { return false; } uint64_t size; if (NS_FAILED(blob->GetSize(&size))) { @@ -127,17 +127,17 @@ private: } aVp.set(JS_NumberValue(double(size))); return true; } static JSBool - GetType(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetType(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { nsIDOMBlob* blob = GetInstancePrivate(aCx, aObj, "type"); if (!blob) { return false; } nsString type; if (NS_FAILED(blob->GetType(type))) { @@ -297,17 +297,17 @@ private: { JS_ASSERT(JS_GetClass(aObj) == &sClass); nsIDOMFile* file = GetPrivate(aObj); NS_IF_RELEASE(file); } static JSBool - GetMozFullPath(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetMozFullPath(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "mozFullPath"); if (!file) { return false; } nsString fullPath; @@ -323,17 +323,17 @@ private: return false; } aVp.set(STRING_TO_JSVAL(jsFullPath)); return true; } static JSBool - GetName(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetName(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "name"); if (!file) { return false; } nsString name; if (NS_FAILED(file->GetName(name))) { @@ -345,17 +345,17 @@ private: return false; } aVp.set(STRING_TO_JSVAL(jsName)); return true; } static JSBool - GetLastModifiedDate(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetLastModifiedDate(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "lastModifiedDate"); if (!file) { return false; } JS::Rooted<JS::Value> value(aCx); if (NS_FAILED(file->GetLastModifiedDate(aCx, value.address()))) {
--- a/dom/workers/ImageData.cpp +++ b/dom/workers/ImageData.cpp @@ -110,17 +110,17 @@ private: static void Finalize(JSFreeOp* aFop, JSObject* aObj) { MOZ_ASSERT(JS_GetClass(aObj) == &sClass); delete static_cast<ImageData*>(JS_GetPrivate(aObj)); } static JSBool - GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JSClass* classPtr = JS_GetClass(aObj); if (classPtr != &sClass) { JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, sClass.name, "GetProperty", classPtr->name); return false; }
--- a/dom/workers/Location.cpp +++ b/dom/workers/Location.cpp @@ -124,17 +124,17 @@ private: jsval href = JS_GetReservedSlot(obj, SLOT_href); JS_SET_RVAL(aCx, aVp, href); return true; } static JSBool - GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JSClass* classPtr = JS_GetClass(aObj); if (classPtr != &sClass) { JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, sClass.name, "GetProperty", classPtr->name); return false; }
--- a/dom/workers/Navigator.cpp +++ b/dom/workers/Navigator.cpp @@ -112,17 +112,17 @@ private: static void Finalize(JSFreeOp* aFop, JSObject* aObj) { JS_ASSERT(JS_GetClass(aObj) == &sClass); delete static_cast<Navigator*>(JS_GetPrivate(aObj)); } static JSBool - GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JSClass* classPtr = JS_GetClass(aObj); if (classPtr != &sClass) { JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, sClass.name, "GetProperty", classPtr->name); return false; }
--- a/dom/workers/Worker.cpp +++ b/dom/workers/Worker.cpp @@ -170,17 +170,17 @@ protected: private: // No instance of this class should ever be created so these are explicitly // left without an implementation to prevent linking in case someone tries to // make one. Worker(); ~Worker(); static JSBool - GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT); const char* name = sEventStrings[JSID_TO_INT(aIdval)]; WorkerPrivate* worker = GetInstancePrivate(aCx, aObj, name); if (!worker) { return !JS_IsExceptionPending(aCx); @@ -195,17 +195,17 @@ private: } aVp.set(listener ? OBJECT_TO_JSVAL(listener) : JSVAL_NULL); return true; } static JSBool SetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSBool aStrict, - JSMutableHandleValue aVp) + JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT); const char* name = sEventStrings[JSID_TO_INT(aIdval)]; WorkerPrivate* worker = GetInstancePrivate(aCx, aObj, name); if (!worker) { return !JS_IsExceptionPending(aCx);
--- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -137,17 +137,17 @@ protected: virtual void _finalize(JSFreeOp* aFop) MOZ_OVERRIDE { EventTarget::_finalize(aFop); } private: static JSBool - GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT); const char* name = sEventStrings[JSID_TO_INT(aIdval)]; WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name); if (!scope) { return false; @@ -164,17 +164,17 @@ private: } aVp.set(listener ? OBJECT_TO_JSVAL(listener) : JSVAL_NULL); return true; } static JSBool SetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSBool aStrict, - JSMutableHandleValue aVp) + JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT); const char* name = sEventStrings[JSID_TO_INT(aIdval)]; WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name); if (!scope) { return false; @@ -204,28 +204,28 @@ private: Construct(JSContext* aCx, unsigned aArgc, jsval* aVp) { JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR, sClass.name); return false; } static JSBool - GetSelf(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetSelf(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { if (!GetInstancePrivate(aCx, aObj, "self")) { return false; } aVp.set(OBJECT_TO_JSVAL(aObj)); return true; } static JSBool - GetLocation(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetLocation(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, sProperties[SLOT_location].name); if (!scope) { return false; } if (JSVAL_IS_VOID(scope->mSlots[SLOT_location])) { @@ -304,17 +304,17 @@ private: !JS_CallFunctionName(aCx, event, "preventDefault", 0, NULL, rval.address())) { return false; } return true; } static JSBool - GetOnErrorListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetOnErrorListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { const char* name = sEventStrings[STRING_onerror]; WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name); if (!scope) { return false; } ErrorResult rv; @@ -336,17 +336,17 @@ private: JS_ASSERT(!JSVAL_IS_PRIMITIVE(aVp)); return true; } static JSBool SetOnErrorListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, - JSBool aStrict, JSMutableHandleValue aVp) + JSBool aStrict, JS::MutableHandle<JS::Value> aVp) { const char* name = sEventStrings[STRING_onerror]; WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name); if (!scope) { return false; } if (JSVAL_IS_PRIMITIVE(aVp)) { @@ -378,17 +378,17 @@ private: JS_ReportError(aCx, "Failed to set event listener!"); return false; } return true; } static JSBool - GetNavigator(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetNavigator(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, sProperties[SLOT_navigator].name); if (!scope) { return false; } if (JSVAL_IS_VOID(scope->mSlots[SLOT_navigator])) { @@ -727,17 +727,17 @@ protected: MOZ_COUNT_DTOR(mozilla::dom::workers::DedicatedWorkerGlobalScope); } private: using EventTarget::GetEventListener; using EventTarget::SetEventListener; static JSBool - GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp) + GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT); const char* name = sEventStrings[JSID_TO_INT(aIdval)]; DedicatedWorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name); if (!scope) { return false; @@ -754,17 +754,17 @@ private: } aVp.set(listener ? OBJECT_TO_JSVAL(listener) : JSVAL_NULL); return true; } static JSBool SetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSBool aStrict, - JSMutableHandleValue aVp) + JS::MutableHandle<JS::Value> aVp) { JS_ASSERT(JSID_IS_INT(aIdval)); JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT); const char* name = sEventStrings[JSID_TO_INT(aIdval)]; DedicatedWorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name); if (!scope) { return false;
--- a/gfx/2d/SourceSurfaceD2DTarget.cpp +++ b/gfx/2d/SourceSurfaceD2DTarget.cpp @@ -94,16 +94,21 @@ SourceSurfaceD2DTarget::GetSRView() void SourceSurfaceD2DTarget::DrawTargetWillChange() { RefPtr<ID3D10Texture2D> oldTexture = mTexture; D3D10_TEXTURE2D_DESC desc; mTexture->GetDesc(&desc); + // Our original texture might implement the keyed mutex flag. We shouldn't + // need that here. We actually specifically don't want it since we don't lock + // our texture for usage! + desc.MiscFlags = 0; + // Get a copy of the surface data so the content at snapshot time was saved. Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(mTexture)); Factory::GetDirect3D10Device()->CopyResource(mTexture, oldTexture); mBitmap = nullptr; DrawTargetD2D::mVRAMUsageSS += desc.Width * desc.Height * BytesPerPixel(mFormat); mOwnsCopy = true;
--- a/gfx/layers/ipc/PGrallocBuffer.ipdl +++ b/gfx/layers/ipc/PGrallocBuffer.ipdl @@ -14,17 +14,16 @@ namespace layers { /** * This is a trivial protocol that's used to track gralloc buffers * across thread contexts. A live PGrallocBuffer actor always * corresponds 1:1 to a pre-shared gralloc buffer (sharing is done by * the PGrallocBuffer constructor). */ async protocol PGrallocBuffer { - // FIXME: Bug 783451: shouldn't be managed by PCompositor or PImageContainer manager PImageBridge or PLayerTransaction; /** Gralloc buffers can be "owned" by either parent or child. */ both: async __delete__(); }; } // namespace layers
--- a/ipc/chromium/src/base/pickle.cc +++ b/ipc/chromium/src/base/pickle.cc @@ -1,58 +1,133 @@ // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/pickle.h" +#include "mozilla/Endian.h" +#include "mozilla/TypeTraits.h" +#include "mozilla/Util.h" + #include <stdlib.h> #include <limits> #include <string> //------------------------------------------------------------------------------ +MOZ_STATIC_ASSERT(MOZ_ALIGNOF(Pickle::memberAlignmentType) >= MOZ_ALIGNOF(uint32_t), + "Insufficient alignment"); + // static const int Pickle::kPayloadUnit = 64; // We mark a read only pickle with a special capacity_. static const uint32_t kCapacityReadOnly = (uint32_t) -1; static const char kBytePaddingMarker = char(0xbf); -// Payload is uint32_t aligned. +namespace { + +// We want to copy data to our payload as efficiently as possible. +// memcpy fits the bill for copying, but not all compilers or +// architectures support inlining memcpy from void*, which has unknown +// static alignment. However, we know that all the members of our +// payload will be aligned on memberAlignmentType boundaries. We +// therefore use that knowledge to construct a copier that will copy +// efficiently (via standard C++ assignment mechanisms) if the datatype +// needs that alignment or less, and memcpy otherwise. (The compiler +// may still inline memcpy, of course.) + +template<typename T, size_t size, bool hasSufficientAlignment> +struct Copier +{ + static void Copy(T* dest, void** iter) { + memcpy(dest, *iter, sizeof(T)); + } +}; + +// Copying 64-bit quantities happens often enough and can easily be made +// worthwhile on 32-bit platforms, so handle it specially. Only do it +// if 64-bit types aren't sufficiently aligned; the alignment +// requirements for them vary between 32-bit platforms. +#ifndef HAVE_64BIT_OS +template<typename T> +struct Copier<T, sizeof(uint64_t), false> +{ + static void Copy(T* dest, void** iter) { +#if MOZ_LITTLE_ENDIAN + static const int loIndex = 0, hiIndex = 1; +#else + static const int loIndex = 1, hiIndex = 0; +#endif + MOZ_STATIC_ASSERT(MOZ_ALIGNOF(uint32_t*) == MOZ_ALIGNOF(void*), + "Pointers have different alignments"); + uint32_t* src = *reinterpret_cast<uint32_t**>(iter); + uint32_t* uint32dest = reinterpret_cast<uint32_t*>(dest); + uint32dest[loIndex] = src[loIndex]; + uint32dest[hiIndex] = src[hiIndex]; + } +}; +#endif + +template<typename T, size_t size> +struct Copier<T, size, true> +{ + static void Copy(T* dest, void** iter) { + // The reinterpret_cast is only safe if two conditions hold: + // (1) If the alignment of T* is the same as void*; + // (2) The alignment of the data in *iter is at least as + // big as MOZ_ALIGNOF(T). + // Check the first condition, as the second condition is already + // known to be true, or we wouldn't be here. + MOZ_STATIC_ASSERT(MOZ_ALIGNOF(T*) == MOZ_ALIGNOF(void*), + "Pointers have different alignments"); + *dest = *(*reinterpret_cast<T**>(iter)); + } +}; + +template<typename T> +void CopyFromIter(T* dest, void** iter) { + MOZ_STATIC_ASSERT(mozilla::IsPod<T>::value, "Copied type must be a POD type"); + Copier<T, sizeof(T), (MOZ_ALIGNOF(T) <= sizeof(Pickle::memberAlignmentType))>::Copy(dest, iter); +} + +} // anonymous namespace + +// Payload is sizeof(Pickle::memberAlignmentType) aligned. Pickle::Pickle() : header_(NULL), header_size_(sizeof(Header)), capacity_(0), variable_buffer_offset_(0) { Resize(kPayloadUnit); header_->payload_size = 0; } Pickle::Pickle(int header_size) : header_(NULL), - header_size_(AlignInt(header_size, sizeof(uint32_t))), + header_size_(AlignInt(header_size)), capacity_(0), variable_buffer_offset_(0) { - DCHECK(static_cast<uint32_t>(header_size) >= sizeof(Header)); + DCHECK(static_cast<memberAlignmentType>(header_size) >= sizeof(Header)); DCHECK(header_size <= kPayloadUnit); Resize(kPayloadUnit); header_->payload_size = 0; } Pickle::Pickle(const char* data, int data_len) : header_(reinterpret_cast<Header*>(const_cast<char*>(data))), header_size_(data_len - header_->payload_size), capacity_(kCapacityReadOnly), variable_buffer_offset_(0) { DCHECK(header_size_ >= sizeof(Header)); - DCHECK(header_size_ == AlignInt(header_size_, sizeof(uint32_t))); + DCHECK(header_size_ == AlignInt(header_size_)); } Pickle::Pickle(const Pickle& other) : header_(NULL), header_size_(other.header_size_), capacity_(0), variable_buffer_offset_(other.variable_buffer_offset_) { uint32_t payload_size = header_size_ + other.header_->payload_size; @@ -93,67 +168,62 @@ bool Pickle::ReadBool(void** iter, bool* bool Pickle::ReadInt16(void** iter, int16_t* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; - memcpy(result, *iter, sizeof(*result)); + CopyFromIter(result, iter); UpdateIter(iter, sizeof(*result)); return true; } bool Pickle::ReadUInt16(void** iter, uint16_t* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; - memcpy(result, *iter, sizeof(*result)); + CopyFromIter(result, iter); UpdateIter(iter, sizeof(*result)); return true; } bool Pickle::ReadInt(void** iter, int* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; - // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on - // alignment. - // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result)); - *result = *reinterpret_cast<int*>(*iter); + CopyFromIter(result, iter); UpdateIter(iter, sizeof(*result)); return true; } // Always written as a 64-bit value since the size for this type can // differ between architectures. bool Pickle::ReadLong(void** iter, long* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); int64_t bigResult = 0; if (!IteratorHasRoomFor(*iter, sizeof(bigResult))) return false; - // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on - // alignment. - memcpy(&bigResult, *iter, sizeof(bigResult)); + CopyFromIter(&bigResult, iter); DCHECK(bigResult <= LONG_MAX && bigResult >= LONG_MIN); *result = static_cast<long>(bigResult); UpdateIter(iter, sizeof(bigResult)); return true; } // Always written as a 64-bit value since the size for this type can @@ -162,19 +232,17 @@ bool Pickle::ReadULong(void** iter, unsi DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); uint64_t bigResult = 0; if (!IteratorHasRoomFor(*iter, sizeof(bigResult))) return false; - // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on - // alignment. - memcpy(&bigResult, *iter, sizeof(bigResult)); + CopyFromIter(&bigResult, iter); DCHECK(bigResult <= ULONG_MAX); *result = static_cast<unsigned long>(bigResult); UpdateIter(iter, sizeof(bigResult)); return true; } bool Pickle::ReadLength(void** iter, int* result) const { @@ -189,124 +257,122 @@ bool Pickle::ReadSize(void** iter, size_ DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); uint64_t bigResult = 0; if (!IteratorHasRoomFor(*iter, sizeof(bigResult))) return false; - // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on - // alignment. - memcpy(&bigResult, *iter, sizeof(bigResult)); + CopyFromIter(&bigResult, iter); DCHECK(bigResult <= std::numeric_limits<size_t>::max()); *result = static_cast<size_t>(bigResult); UpdateIter(iter, sizeof(bigResult)); return true; } bool Pickle::ReadInt32(void** iter, int32_t* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; - memcpy(result, *iter, sizeof(*result)); + CopyFromIter(result, iter); UpdateIter(iter, sizeof(*result)); return true; } bool Pickle::ReadUInt32(void** iter, uint32_t* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; - memcpy(result, *iter, sizeof(*result)); + CopyFromIter(result, iter); UpdateIter(iter, sizeof(*result)); return true; } bool Pickle::ReadInt64(void** iter, int64_t* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; - memcpy(result, *iter, sizeof(*result)); + CopyFromIter(result, iter); UpdateIter(iter, sizeof(*result)); return true; } bool Pickle::ReadUInt64(void** iter, uint64_t* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; - memcpy(result, *iter, sizeof(*result)); + CopyFromIter(result, iter); UpdateIter(iter, sizeof(*result)); return true; } bool Pickle::ReadDouble(void** iter, double* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; - memcpy(result, *iter, sizeof(*result)); + CopyFromIter(result, iter); UpdateIter(iter, sizeof(*result)); return true; } // Always written as a 64-bit value since the size for this type can // differ between architectures. bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); int64_t bigResult = 0; if (!IteratorHasRoomFor(*iter, sizeof(bigResult))) return false; - memcpy(&bigResult, *iter, sizeof(bigResult)); + CopyFromIter(&bigResult, iter); DCHECK(bigResult <= std::numeric_limits<intptr_t>::max() && bigResult >= std::numeric_limits<intptr_t>::min()); *result = static_cast<intptr_t>(bigResult); UpdateIter(iter, sizeof(bigResult)); return true; } bool Pickle::ReadUnsignedChar(void** iter, unsigned char* result) const { DCHECK(iter); if (!*iter) *iter = const_cast<char*>(payload()); if (!IteratorHasRoomFor(*iter, sizeof(*result))) return false; - memcpy(result, *iter, sizeof(*result)); + CopyFromIter(result, iter); UpdateIter(iter, sizeof(*result)); return true; } bool Pickle::ReadString(void** iter, std::string* result) const { DCHECK(iter); if (!*iter) @@ -406,19 +472,19 @@ bool Pickle::ReadData(void** iter, const return ReadBytes(iter, data, *length); } char* Pickle::BeginWrite(uint32_t length, uint32_t alignment) { DCHECK(alignment % 4 == 0) << "Must be at least 32-bit aligned!"; // write at an alignment-aligned offset from the beginning of the header - uint32_t offset = AlignInt(header_->payload_size, sizeof(uint32_t)); + uint32_t offset = AlignInt(header_->payload_size); uint32_t padding = (header_size_ + offset) % alignment; - uint32_t new_size = offset + padding + AlignInt(length, sizeof(uint32_t)); + uint32_t new_size = offset + padding + AlignInt(length); uint32_t needed_size = header_size_ + new_size; if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size))) return NULL; DCHECK(intptr_t(header_) % alignment == 0); #ifdef ARCH_CPU_64_BITS @@ -436,18 +502,19 @@ char* Pickle::BeginWrite(uint32_t length header_->payload_size = new_size; return buffer; } void Pickle::EndWrite(char* dest, int length) { // Zero-pad to keep tools like purify from complaining about uninitialized // memory. - if (length % sizeof(uint32_t)) - memset(dest + length, 0, sizeof(uint32_t) - (length % sizeof(uint32_t))); + if (length % sizeof(memberAlignmentType)) + memset(dest + length, 0, + sizeof(memberAlignmentType) - (length % sizeof(memberAlignmentType))); } bool Pickle::WriteBytes(const void* data, int data_len, uint32_t alignment) { DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly"; DCHECK(alignment == 4 || alignment == 8); DCHECK(intptr_t(header_) % alignment == 0); char* dest = BeginWrite(data_len, alignment); @@ -489,17 +556,17 @@ bool Pickle::WriteData(const char* data, char* Pickle::BeginWriteData(int length) { DCHECK_EQ(variable_buffer_offset_, 0U) << "There can only be one variable buffer in a Pickle"; if (!WriteInt(length)) return NULL; - char *data_ptr = BeginWrite(length, sizeof(uint32_t)); + char *data_ptr = BeginWrite(length, sizeof(memberAlignmentType)); if (!data_ptr) return NULL; variable_buffer_offset_ = data_ptr - reinterpret_cast<char*>(header_) - sizeof(int); // EndWrite doesn't necessarily have to be called after the write operation, // so we call it here to pad out what the caller will eventually write. @@ -520,33 +587,33 @@ void Pickle::TrimWriteData(int new_lengt } // Update the payload size and variable buffer size header_->payload_size -= (*cur_length - new_length); *cur_length = new_length; } bool Pickle::Resize(uint32_t new_capacity) { - new_capacity = AlignInt(new_capacity, kPayloadUnit); + new_capacity = ConstantAligner<kPayloadUnit>::align(new_capacity); void* p = realloc(header_, new_capacity); if (!p) return false; header_ = reinterpret_cast<Header*>(p); capacity_ = new_capacity; return true; } // static const char* Pickle::FindNext(uint32_t header_size, const char* start, const char* end) { - DCHECK(header_size == AlignInt(header_size, sizeof(uint32_t))); - DCHECK(header_size <= static_cast<uint32_t>(kPayloadUnit)); + DCHECK(header_size == AlignInt(header_size)); + DCHECK(header_size <= static_cast<memberAlignmentType>(kPayloadUnit)); const Header* hdr = reinterpret_cast<const Header*>(start); const char* payload_base = start + header_size; const char* payload_end = payload_base + hdr->payload_size; if (payload_end < payload_base) return NULL; return (payload_end > end) ? NULL : payload_end;
--- a/ipc/chromium/src/base/pickle.h +++ b/ipc/chromium/src/base/pickle.h @@ -79,17 +79,17 @@ class Pickle { bool ReadDouble(void** iter, double* result) const; bool ReadIntPtr(void** iter, intptr_t* result) const; bool ReadUnsignedChar(void** iter, unsigned char* result) const; bool ReadString(void** iter, std::string* result) const; bool ReadWString(void** iter, std::wstring* result) const; bool ReadString16(void** iter, string16* result) const; bool ReadData(void** iter, const char** data, int* length) const; bool ReadBytes(void** iter, const char** data, int length, - uint32_t alignment = sizeof(uint32_t)) const; + uint32_t alignment = sizeof(memberAlignmentType)) const; // Safer version of ReadInt() checks for the result not being negative. // Use it for reading the object sizes. bool ReadLength(void** iter, int* result) const; // Methods for adding to the payload of the Pickle. These values are // appended to the end of the Pickle's payload. When reading values from a // Pickle, it is important to read them in the order in which they were added @@ -144,17 +144,17 @@ class Pickle { bool WriteUnsignedChar(unsigned char value) { return WriteBytes(&value, sizeof(value)); } bool WriteString(const std::string& value); bool WriteWString(const std::wstring& value); bool WriteString16(const string16& value); bool WriteData(const char* data, int length); bool WriteBytes(const void* data, int data_len, - uint32_t alignment = sizeof(uint32_t)); + uint32_t alignment = sizeof(memberAlignmentType)); // Same as WriteData, but allows the caller to write directly into the // Pickle. This saves a copy in cases where the data is not already // available in a buffer. The caller should take care to not write more // than the length it declares it will. Use ReadData to get the data. // Returns NULL on failure. // // The returned pointer will only be valid until the next write operation @@ -201,16 +201,18 @@ class Pickle { bool IteratorHasRoomFor(const void* iter, int len) const { if ((len < 0) || (iter < header_) || iter > end_of_payload()) return false; const char* end_of_region = reinterpret_cast<const char*>(iter) + len; // Watch out for overflow in pointer calculation, which wraps. return (iter <= end_of_region) && (end_of_region <= end_of_payload()); } + typedef uint32_t memberAlignmentType; + protected: uint32_t payload_size() const { return header_->payload_size; } char* payload() { return reinterpret_cast<char*>(header_) + header_size_; } const char* payload() const { return reinterpret_cast<const char*>(header_) + header_size_; @@ -241,26 +243,35 @@ class Pickle { void EndWrite(char* dest, int length); // Resize the capacity, note that the input value should include the size of // the header: new_capacity = sizeof(Header) + desired_payload_capacity. // A realloc() failure will cause a Resize failure... and caller should check // the return result for true (i.e., successful resizing). bool Resize(uint32_t new_capacity); - // Aligns 'i' by rounding it up to the next multiple of 'alignment' - static uint32_t AlignInt(uint32_t i, int alignment) { - return i + (alignment - (i % alignment)) % alignment; + // Round 'bytes' up to the next multiple of 'alignment'. 'alignment' must be + // a power of 2. + template<uint32_t alignment> struct ConstantAligner { + static uint32_t align(int bytes) { + MOZ_STATIC_ASSERT((alignment & (alignment - 1)) == 0, + "alignment must be a power of two"); + return (bytes + (alignment - 1)) & ~static_cast<uint32_t>(alignment - 1); + } + }; + + static uint32_t AlignInt(int bytes) { + return ConstantAligner<sizeof(memberAlignmentType)>::align(bytes); } // Moves the iterator by the given number of bytes, making sure it is aligned. // Pointer (iterator) is NOT aligned, but the change in the pointer - // is guaranteed to be a multiple of sizeof(uint32_t). + // is guaranteed to be a multiple of sizeof(memberAlignmentType). static void UpdateIter(void** iter, int bytes) { - *iter = static_cast<char*>(*iter) + AlignInt(bytes, sizeof(uint32_t)); + *iter = static_cast<char*>(*iter) + AlignInt(bytes); } // Find the end of the pickled data that starts at range_start. Returns NULL // if the entire Pickle is not found in the given data range. static const char* FindNext(uint32_t header_size, const char* range_start, const char* range_end);
new file mode 100644 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh @@ -0,0 +1,15 @@ +include protocol PTestIndirectProtocolParamSecond; + +namespace mozilla { +namespace _ipdltest { + +struct IndirectParamStruct { + PTestIndirectProtocolParamSecond actor; +}; + +union IndirectParamUnion { + IndirectParamStruct; +}; + +} +}
new file mode 100644 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl @@ -0,0 +1,19 @@ +include protocol PTestIndirectProtocolParamManage; +// FIXME/bug 792908 protocol PTestIndirectProtocolParamSecond is +// already included in PTestIndirectProtocolParam.ipdlh +include protocol PTestIndirectProtocolParamSecond; +include PTestIndirectProtocolParam; + +namespace mozilla { +namespace _ipdltest { + +sync protocol PTestIndirectProtocolParamFirst { + manager PTestIndirectProtocolParamManage; +parent: + sync Test(IndirectParamUnion actor); +both: + __delete__(); +}; + +} +}
new file mode 100644 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl @@ -0,0 +1,17 @@ +include protocol PTestIndirectProtocolParamFirst; +include protocol PTestIndirectProtocolParamSecond; + +namespace mozilla { +namespace _ipdltest { + +sync protocol PTestIndirectProtocolParamManage { + manages PTestIndirectProtocolParamFirst; + manages PTestIndirectProtocolParamSecond; +both: + PTestIndirectProtocolParamFirst(); + PTestIndirectProtocolParamSecond(); + __delete__(); +}; + +} +}
new file mode 100644 --- /dev/null +++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl @@ -0,0 +1,13 @@ +include protocol PTestIndirectProtocolParamManage; + +namespace mozilla { +namespace _ipdltest { + +sync protocol PTestIndirectProtocolParamSecond { + manager PTestIndirectProtocolParamManage; +both: + __delete__(); +}; + +} +}
--- a/ipc/ipdl/test/cxx/ipdl.mk +++ b/ipc/ipdl/test/cxx/ipdl.mk @@ -45,9 +45,13 @@ IPDLSRCS = \ PTestShutdownSubsub.ipdl \ PTestStackHooks.ipdl \ PTestSyncError.ipdl \ PTestSyncHang.ipdl \ PTestSyncWakeup.ipdl \ PTestSysVShmem.ipdl \ PTestBadActor.ipdl \ PTestBadActorSub.ipdl \ + PTestIndirectProtocolParam.ipdlh \ + PTestIndirectProtocolParamManage.ipdl \ + PTestIndirectProtocolParamFirst.ipdl \ + PTestIndirectProtocolParamSecond.ipdl \ $(NULL)
--- a/js/ipc/ObjectWrapperParent.cpp +++ b/js/ipc/ObjectWrapperParent.cpp @@ -383,17 +383,17 @@ jsval_to_nsString(JSContext* cx, jsid fr *to = chars; return true; } return false; } /*static*/ JSBool ObjectWrapperParent::CPOW_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, - JSMutableHandleValue vp) + MutableHandleValue vp) { CPOW_LOG(("Calling CPOW_AddProperty (%s)...", JSVAL_TO_CSTR(cx, id))); ObjectWrapperParent* self = Unwrap(cx, obj); if (!self) return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_AddProperty"); @@ -410,17 +410,17 @@ ObjectWrapperParent::CPOW_AddProperty(JS return (self->Manager()->RequestRunToCompletion() && self->CallAddProperty(in_id, aco.StatusPtr()) && aco.Ok()); } /*static*/ JSBool ObjectWrapperParent::CPOW_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, - JSMutableHandleValue vp) + MutableHandleValue vp) { CPOW_LOG(("Calling CPOW_GetProperty (%s)...", JSVAL_TO_CSTR(cx, id))); ObjectWrapperParent* self = Unwrap(cx, obj); if (!self) return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_GetProperty"); @@ -437,17 +437,17 @@ ObjectWrapperParent::CPOW_GetProperty(JS self->CallGetProperty(in_id, aco.StatusPtr(), &out_v) && aco.Ok() && self->jsval_from_JSVariant(cx, out_v, vp.address())); } /*static*/ JSBool ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, - JSBool strict, JSMutableHandleValue vp) + JSBool strict, MutableHandleValue vp) { CPOW_LOG(("Calling CPOW_SetProperty (%s)...", JSVAL_TO_CSTR(cx, id))); ObjectWrapperParent* self = Unwrap(cx, obj); if (!self) return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_SetProperty"); @@ -609,17 +609,17 @@ ObjectWrapperParent::CPOW_NewResolve(JSC JS_DefinePropertyById(cx, obj2, id, JSVAL_VOID, NULL, NULL, JSPROP_ENUMERATE); } return JS_TRUE; } /*static*/ JSBool ObjectWrapperParent::CPOW_Convert(JSContext *cx, JSHandleObject obj, JSType type, - JSMutableHandleValue vp) + MutableHandleValue vp) { CPOW_LOG(("Calling CPOW_Convert (to %s)...", JS_GetTypeName(cx, type))); ObjectWrapperParent* self = Unwrap(cx, obj); if (!self) return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_Convert"); @@ -703,17 +703,17 @@ ObjectWrapperParent::CPOW_Construct(JSCo return (constructor->Manager()->RequestRunToCompletion() && constructor->CallConstruct(in_argv, aco.StatusPtr(), &out_powp) && aco.Ok() && jsval_from_PObjectWrapperParent(cx, out_powp, vp)); } /*static*/ JSBool -ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSHandleObject obj, JSMutableHandleValue v, +ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSHandleObject obj, MutableHandleValue v, JSBool *bp) { CPOW_LOG(("Calling CPOW_HasInstance...")); *bp = JS_FALSE; ObjectWrapperParent* self = Unwrap(cx, obj); if (!self)
--- a/js/ipc/ObjectWrapperParent.h +++ b/js/ipc/ObjectWrapperParent.h @@ -54,52 +54,52 @@ protected: ContextWrapperParent* Manager(); private: mutable JSObject* mObj; static JSBool - CPOW_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); + CPOW_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandleValue vp); static JSBool CPOW_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded); static JSBool - CPOW_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); + CPOW_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandleValue vp); static JSBool - CPOW_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp); + CPOW_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JS::MutableHandleValue vp); JSBool NewEnumerateInit(JSContext* cx, jsval* statep, jsid* idp); JSBool NewEnumerateNext(JSContext* cx, jsval* statep, jsid* idp); JSBool NewEnumerateDestroy(JSContext* cx, jsval state); static JSBool CPOW_NewEnumerate(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, jsval *statep, jsid *idp); static JSBool CPOW_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags, JS::MutableHandleObject objp); static JSBool - CPOW_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp); + CPOW_Convert(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandleValue vp); static void CPOW_Finalize(js::FreeOp* fop, JSObject* obj); static JSBool CPOW_Call(JSContext* cx, unsigned argc, jsval* vp); static JSBool CPOW_Construct(JSContext *cx, unsigned argc, jsval *vp); static JSBool - CPOW_HasInstance(JSContext *cx, JSHandleObject obj, JSMutableHandleValue vp, JSBool *bp); + CPOW_HasInstance(JSContext *cx, JSHandleObject obj, JS::MutableHandleValue vp, JSBool *bp); static bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to); static bool jsval_from_JSVariant(JSContext* cx, const JSVariant& from, jsval* to); static bool boolean_from_JSVariant(JSContext* cx, const JSVariant& from, JSBool* to); static bool JSObject_to_PObjectWrapperParent(JSContext* cx, JSObject* from, PObjectWrapperParent** to);
--- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -97,17 +97,17 @@ */ namespace js { class Module; class ScriptSourceObject; template <typename T> -struct RootMethods {}; +struct GCMethods {}; template <typename T> class RootedBase {}; template <typename T> class HandleBase {}; template <typename T> @@ -176,23 +176,23 @@ struct JS_PUBLIC_API(NullPtr) */ template <typename T> class Heap : public js::HeapBase<T> { public: Heap() { MOZ_STATIC_ASSERT(sizeof(T) == sizeof(Heap<T>), "Heap<T> must be binary compatible with T."); - init(js::RootMethods<T>::initial()); + init(js::GCMethods<T>::initial()); } explicit Heap(T p) { init(p); } explicit Heap(const Heap<T> &p) { init(p.ptr); } ~Heap() { - if (js::RootMethods<T>::needsPostBarrier(ptr)) + if (js::GCMethods<T>::needsPostBarrier(ptr)) relocate(); } bool operator!=(const T &other) const { return ptr != other; } bool operator==(const T &other) const { return ptr == other; } operator T() const { return ptr; } T operator->() const { return ptr; } @@ -202,46 +202,46 @@ class Heap : public js::HeapBase<T> T *unsafeGet() { return &ptr; } Heap<T> &operator=(T p) { set(p); return *this; } void set(T newPtr) { - JS_ASSERT(!js::RootMethods<T>::poisoned(newPtr)); - if (js::RootMethods<T>::needsPostBarrier(newPtr)) { + JS_ASSERT(!js::GCMethods<T>::poisoned(newPtr)); + if (js::GCMethods<T>::needsPostBarrier(newPtr)) { ptr = newPtr; post(); - } else if (js::RootMethods<T>::needsPostBarrier(ptr)) { + } else if (js::GCMethods<T>::needsPostBarrier(ptr)) { relocate(); /* Called before overwriting ptr. */ ptr = newPtr; } else { ptr = newPtr; } } private: void init(T newPtr) { - JS_ASSERT(!js::RootMethods<T>::poisoned(newPtr)); + JS_ASSERT(!js::GCMethods<T>::poisoned(newPtr)); ptr = newPtr; - if (js::RootMethods<T>::needsPostBarrier(ptr)) + if (js::GCMethods<T>::needsPostBarrier(ptr)) post(); } void post() { #ifdef JSGC_GENERATIONAL - JS_ASSERT(js::RootMethods<T>::needsPostBarrier(ptr)); - js::RootMethods<T>::postBarrier(&ptr); + JS_ASSERT(js::GCMethods<T>::needsPostBarrier(ptr)); + js::GCMethods<T>::postBarrier(&ptr); #endif } void relocate() { #ifdef JSGC_GENERATIONAL - js::RootMethods<T>::relocate(&ptr); + js::GCMethods<T>::relocate(&ptr); #endif } T ptr; }; /* * Reference to a T that has been rooted elsewhere. This is most useful @@ -358,17 +358,17 @@ typedef Handle<Value> */ template <typename T> class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T> { public: inline MutableHandle(Rooted<T> *root); void set(T v) { - JS_ASSERT(!js::RootMethods<T>::poisoned(v)); + JS_ASSERT(!js::GCMethods<T>::poisoned(v)); *ptr = v; } /* * This may be called only if the location of the T is guaranteed * to be marked (for some reason other than being a Rooted), * e.g., if it is guaranteed to be reachable from an implicit root. * @@ -476,17 +476,17 @@ class InternalHandle<T*> */ template <typename T> struct RootKind<T *> { static ThingRootKind rootKind() { return T::rootKind(); } }; template <typename T> -struct RootMethods<T *> +struct GCMethods<T *> { static T *initial() { return NULL; } static ThingRootKind kind() { return RootKind<T *>::rootKind(); } static bool poisoned(T *v) { return JS::IsPoisonedPtr(v); } static bool needsPostBarrier(T *v) { return v; } #ifdef JSGC_GENERATIONAL static void postBarrier(T **vp) { JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell **>(vp)); @@ -523,49 +523,49 @@ class MOZ_STACK_CLASS Rooted : public js #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) commonInit(pt->thingGCRooters); #endif } public: Rooted(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : ptr(js::RootMethods<T>::initial()) + : ptr(js::GCMethods<T>::initial()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; init(cx); } Rooted(JSContext *cx, T initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : ptr(initial) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; init(cx); } Rooted(js::PerThreadData *pt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : ptr(js::RootMethods<T>::initial()) + : ptr(js::GCMethods<T>::initial()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; init(js::PerThreadDataFriendFields::get(pt)); } Rooted(js::PerThreadData *pt, T initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : ptr(initial) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; init(js::PerThreadDataFriendFields::get(pt)); } Rooted(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : ptr(js::RootMethods<T>::initial()) + : ptr(js::GCMethods<T>::initial()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; init(js::PerThreadDataFriendFields::getMainThread(rt)); } Rooted(JSRuntime *rt, T initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : ptr(initial) @@ -592,43 +592,43 @@ class MOZ_STACK_CLASS Rooted : public js operator const T&() const { return ptr; } T operator->() const { return ptr; } T *address() { return &ptr; } const T *address() const { return &ptr; } T &get() { return ptr; } const T &get() const { return ptr; } T &operator=(T value) { - JS_ASSERT(!js::RootMethods<T>::poisoned(value)); + JS_ASSERT(!js::GCMethods<T>::poisoned(value)); ptr = value; return ptr; } T &operator=(const Rooted &value) { ptr = value; return ptr; } void set(T value) { - JS_ASSERT(!js::RootMethods<T>::poisoned(value)); + JS_ASSERT(!js::GCMethods<T>::poisoned(value)); ptr = value; } bool operator!=(const T &other) const { return ptr != other; } bool operator==(const T &other) const { return ptr == other; } private: void commonInit(Rooted<void*> **thingGCRooters) { #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) - js::ThingRootKind kind = js::RootMethods<T>::kind(); + js::ThingRootKind kind = js::GCMethods<T>::kind(); this->stack = &thingGCRooters[kind]; this->prev = *stack; *stack = reinterpret_cast<Rooted<void*>*>(this); - JS_ASSERT(!js::RootMethods<T>::poisoned(ptr)); + JS_ASSERT(!js::GCMethods<T>::poisoned(ptr)); #endif } #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING) Rooted<void*> **stack, *prev; #endif #if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE) @@ -743,17 +743,17 @@ class SkipRoot /* Interface substitute for Rooted<T> which does not root the variable's memory. */ template <typename T> class FakeRooted : public RootedBase<T> { public: FakeRooted(JSContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : ptr(RootMethods<T>::initial()) + : ptr(GCMethods<T>::initial()) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } FakeRooted(JSContext *cx, T initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : ptr(initial) { @@ -763,17 +763,17 @@ class FakeRooted : public RootedBase<T> operator T() const { return ptr; } T operator->() const { return ptr; } T *address() { return &ptr; } const T *address() const { return &ptr; } T &get() { return ptr; } const T &get() const { return ptr; } T &operator=(T value) { - JS_ASSERT(!RootMethods<T>::poisoned(value)); + JS_ASSERT(!GCMethods<T>::poisoned(value)); ptr = value; return ptr; } bool operator!=(const T &other) const { return ptr != other; } bool operator==(const T &other) const { return ptr == other; } private: @@ -793,17 +793,17 @@ class FakeMutableHandle : public js::Mut ptr = t; } FakeMutableHandle(FakeRooted<T> *root) { ptr = root->address(); } void set(T v) { - JS_ASSERT(!js::RootMethods<T>::poisoned(v)); + JS_ASSERT(!js::GCMethods<T>::poisoned(v)); *ptr = v; } T *address() const { return ptr; } T get() const { return *ptr; } operator T() const { return get(); } T operator->() const { return get(); }
--- a/js/public/Value.h +++ b/js/public/Value.h @@ -1396,24 +1396,24 @@ SameType(const Value &lhs, const Value & namespace JS { JS_PUBLIC_API(void) HeapValuePostBarrier(Value *valuep); JS_PUBLIC_API(void) HeapValueRelocate(Value *valuep); } #endif namespace js { -template <> struct RootMethods<const JS::Value> +template <> struct GCMethods<const JS::Value> { static JS::Value initial() { return JS::UndefinedValue(); } static ThingRootKind kind() { return THING_ROOT_VALUE; } static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); } }; -template <> struct RootMethods<JS::Value> +template <> struct GCMethods<JS::Value> { static JS::Value initial() { return JS::UndefinedValue(); } static ThingRootKind kind() { return THING_ROOT_VALUE; } static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); } static bool needsPostBarrier(const JS::Value &v) { return v.isMarkable(); } #ifdef JSGC_GENERATIONAL static void postBarrier(JS::Value *v) { JS::HeapValuePostBarrier(v); } static void relocate(JS::Value *v) { JS::HeapValueRelocate(v); }
--- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -1123,27 +1123,17 @@ MapObject::mark(JSTracer *trc, JSObject #ifdef JSGC_GENERATIONAL template <typename TableType> class OrderedHashTableRef : public gc::BufferableRef { TableType *table; HashableValue key; public: - OrderedHashTableRef(TableType *t, const HashableValue &k) : table(t), key(k) {} - - bool match(void *location) { - if (!table->has(key)) - return false; - for (typename TableType::Range r = table->all(); !r.empty(); r.popFront()) { - if ((void*)&r.front() == location) - return true; - } - return false; - } + explicit OrderedHashTableRef(TableType *t, const HashableValue &k) : table(t), key(k) {} void mark(JSTracer *trc) { HashableValue prior = key; key = key.mark(trc); table->rekeyOneEntry(prior, key); } }; #endif
--- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -12,16 +12,17 @@ endif # Integrate with mozbuild-generated make files. We first verify that no # variables provided by the automatically generated .mk files are # present. If they are, this is a violation of the separation of # responsibility between Makefile.in and mozbuild files. _MOZBUILD_EXTERNAL_VARIABLES := \ DIRS \ HOST_CSRCS \ + HOST_LIBRARY_NAME \ MODULE \ PARALLEL_DIRS \ TEST_DIRS \ TIERS \ TOOL_DIRS \ XPIDL_MODULE \ $(NULL)
--- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -169,17 +169,17 @@ namespace CType { static JSBool NameGetter(JSContext* cx, JSHandleObject obj, JSHandleId idval, MutableHandleValue vp); static JSBool SizeGetter(JSContext* cx, JSHandleObject obj, JSHandleId idval, MutableHandleValue vp); static JSBool PtrGetter(JSContext* cx, JSHandleObject obj, JSHandleId idval, MutableHandleValue vp); static JSBool CreateArray(JSContext* cx, unsigned argc, jsval* vp); static JSBool ToString(JSContext* cx, unsigned argc, jsval* vp); static JSBool ToSource(JSContext* cx, unsigned argc, jsval* vp); - static JSBool HasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue v, JSBool* bp); + static JSBool HasInstance(JSContext* cx, JSHandleObject obj, MutableHandleValue v, JSBool* bp); /* * Get the global "ctypes" object. * * |obj| must be a CType object. * * This function never returns NULL. @@ -3742,17 +3742,17 @@ CType::ToSource(JSContext* cx, unsigned if (!result) return JS_FALSE; args.rval().setString(result); return JS_TRUE; } JSBool -CType::HasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue v, JSBool* bp) +CType::HasInstance(JSContext* cx, JSHandleObject obj, MutableHandleValue v, JSBool* bp) { JS_ASSERT(CType::IsCType(obj)); jsval slot = JS_GetReservedSlot(obj, SLOT_PROTO); JS::Rooted<JSObject*> prototype(cx, &slot.toObject()); JS_ASSERT(prototype); JS_ASSERT(CData::IsCDataProto(prototype));
--- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6498,20 +6498,19 @@ template <> ParseNode * Parser<FullParseHandler>::newRegExp(const jschar *buf, size_t length, RegExpFlag flags) { ParseNode *pn = NullaryNode::create(PNK_REGEXP, &handler); if (!pn) return NULL; const StableCharPtr chars(buf, length); - RegExpStatics *res = context->regExpStatics(); Rooted<RegExpObject*> reobj(context); - if (context->hasfp()) + if (RegExpStatics *res = context->regExpStatics()) reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream); else reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream); if (!reobj) return NULL; pn->pn_objbox = newObjectBox(reobj); @@ -6523,20 +6522,19 @@ Parser<FullParseHandler>::newRegExp(cons } template <> SyntaxParseHandler::Node Parser<SyntaxParseHandler>::newRegExp(const jschar *buf, size_t length, RegExpFlag flags) { // 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()) + if (RegExpStatics *res = context->regExpStatics()) 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 <typename ParseHandler>
--- a/js/src/gc/Barrier-inl.h +++ b/js/src/gc/Barrier-inl.h @@ -407,22 +407,16 @@ class DenseRangeRef : public gc::Buffera public: DenseRangeRef(JSObject *obj, uint32_t start, uint32_t end) : owner(obj), start(start), end(end) { JS_ASSERT(start < end); } - bool match(void *location) { - uint32_t len = owner->getDenseInitializedLength(); - return location >= &owner->getDenseElement(Min(start, len)) && - location <= &owner->getDenseElement(Min(end, len)) - 1; - } - void mark(JSTracer *trc) { /* Apply forwarding, if we have already visited owner. */ IsObjectMarked(&owner); uint32_t initLen = owner->getDenseInitializedLength(); uint32_t clampedStart = Min(start, initLen); gc::MarkArraySlots(trc, Min(end, initLen) - clampedStart, owner->getDenseElements() + clampedStart, "element"); }
--- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -100,14 +100,48 @@ EndVerifyPreBarriers(JSRuntime *rt); void StartVerifyPostBarriers(JSRuntime *rt); void EndVerifyPostBarriers(JSRuntime *rt); void FinishVerifier(JSRuntime *rt); + +class AutoStopVerifyingBarriers +{ + JSRuntime *runtime; + bool restartPreVerifier; + bool restartPostVerifier; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + + public: + AutoStopVerifyingBarriers(JSRuntime *rt, bool isShutdown + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : runtime(rt) + { + restartPreVerifier = !isShutdown && rt->gcVerifyPreData; + restartPostVerifier = !isShutdown && rt->gcVerifyPostData; + if (rt->gcVerifyPreData) + EndVerifyPreBarriers(rt); + if (rt->gcVerifyPostData) + EndVerifyPostBarriers(rt); + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + + ~AutoStopVerifyingBarriers() { + if (restartPreVerifier) + StartVerifyPreBarriers(runtime); + if (restartPostVerifier) + StartVerifyPostBarriers(runtime); + } +}; +#else +struct AutoStopVerifyingBarriers +{ + AutoStopVerifyingBarriers(JSRuntime *, bool) {} +}; #endif /* JS_GC_ZEAL */ } /* namespace gc */ } /* namespace js */ #endif /* jsgc_internal_h___ */
--- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -8,16 +8,17 @@ #include "mozilla/DebugOnly.h" #include "ion/IonCode.h" #include "vm/Shape.h" #include "jscompartmentinlines.h" +#include "gc/Nursery-inl.h" #include "vm/Shape-inl.h" #include "vm/String-inl.h" using namespace js; using namespace js::gc; using mozilla::DebugOnly;
--- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -31,16 +31,29 @@ js::Nursery::init() JS_ASSERT(start() == 0); if (!hugeSlots.init()) return false; fallbackBitmap.clear(false); void *heap = MapAlignedPages(NurserySize, Alignment); +#ifdef JSGC_ROOT_ANALYSIS + // Our poison pointers are not guaranteed to be invalid on 64-bit + // architectures, and often are valid. We can't just reserve the full + // poison range, because it might already have been taken up by something + // else (shared library, previous allocation). So we'll just loop and + // discard poison pointers until we get something valid. + // + // This leaks all of these poisoned pointers. It would be better if they + // were marked as uncommitted, but it's a little complicated to avoid + // clobbering pre-existing unrelated mappings. + while (IsPoisonedPtr(heap) || IsPoisonedPtr((void*)(uintptr_t(heap) + NurserySize))) + heap = MapAlignedPages(NurserySize, Alignment); +#endif if (!heap) return false; JSRuntime *rt = runtime(); rt->gcNurseryStart_ = uintptr_t(heap); rt->gcNurseryEnd_ = chunk(LastNurseryChunk).end(); numActiveChunks_ = 1; setCurrentChunk(0); @@ -506,16 +519,18 @@ js::Nursery::collect(JSRuntime *rt, JS:: if (!isEnabled()) return; if (position() == start()) return; rt->gcHelperThread.waitBackgroundSweepEnd(); + AutoStopVerifyingBarriers av(rt, false); + /* Move objects pointed to by roots from the nursery to the major heap. */ MinorCollectionTracer trc(rt, this); MarkRuntime(&trc); Debugger::markAll(&trc); for (CompartmentsIter comp(rt); !comp.done(); comp.next()) { comp->markAllCrossCompartmentWrappers(&trc); comp->markAllInitialShapeTableEntries(&trc); }
--- a/js/src/gc/StoreBuffer.cpp +++ b/js/src/gc/StoreBuffer.cpp @@ -39,21 +39,20 @@ StoreBuffer::SlotEdge::deref() const } JS_ALWAYS_INLINE void * StoreBuffer::SlotEdge::location() const { return (void *)slotLocation(); } -template <typename NurseryType> JS_ALWAYS_INLINE bool -StoreBuffer::SlotEdge::inRememberedSet(NurseryType *nursery) const +StoreBuffer::SlotEdge::inRememberedSet(const Nursery &nursery) const { - return !nursery->isInside(object) && nursery->isInside(deref()); + return !nursery.isInside(object) && nursery.isInside(deref()); } JS_ALWAYS_INLINE bool StoreBuffer::SlotEdge::isNullEdge() const { return !deref(); } @@ -97,19 +96,18 @@ StoreBuffer::MonoTypeBuffer<T>::disable( template <typename T> void StoreBuffer::MonoTypeBuffer<T>::clear() { pos = base; } template <typename T> -template <typename NurseryType> void -StoreBuffer::MonoTypeBuffer<T>::compactNotInSet(NurseryType *nursery) +StoreBuffer::MonoTypeBuffer<T>::compactNotInSet(const Nursery &nursery) { T *insert = base; for (T *v = base; v != pos; ++v) { if (v->inRememberedSet(nursery)) *insert++ = *v; } pos = insert; } @@ -131,22 +129,17 @@ StoreBuffer::MonoTypeBuffer<T>::compactR pos = insert; duplicates.clear(); } template <typename T> void StoreBuffer::MonoTypeBuffer<T>::compact() { -#ifdef JS_GC_ZEAL - if (owner->runtime->gcVerifyPostData) - compactNotInSet(&owner->runtime->gcVerifierNursery); - else -#endif - compactNotInSet(&owner->runtime->gcNursery); + compactNotInSet(owner->runtime->gcNursery); compactRemoveDuplicates(); } template <typename T> void StoreBuffer::MonoTypeBuffer<T>::mark(JSTracer *trc) { compact(); @@ -156,64 +149,32 @@ StoreBuffer::MonoTypeBuffer<T>::mark(JST if (edge.isNullEdge()) continue; edge.mark(trc); } } -template <typename T> -bool -StoreBuffer::MonoTypeBuffer<T>::accumulateEdges(EdgeSet &edges) -{ - compact(); - T *cursor = base; - while (cursor != pos) { - T edge = *cursor++; - - /* Note: the relocatable buffer is allowed to store pointers to NULL. */ - if (edge.isNullEdge()) - continue; - if (!edges.putNew(edge.location())) - return false; - } - return true; -} - namespace js { namespace gc { class AccumulateEdgesTracer : public JSTracer { EdgeSet *edges; static void tracer(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) { AccumulateEdgesTracer *trc = static_cast<AccumulateEdgesTracer *>(jstrc); trc->edges->put(thingp); } public: AccumulateEdgesTracer(JSRuntime *rt, EdgeSet *edgesArg) : edges(edgesArg) { JS_TracerInit(this, rt, AccumulateEdgesTracer::tracer); } }; - -template <> -bool -StoreBuffer::MonoTypeBuffer<StoreBuffer::WholeCellEdges>::accumulateEdges(EdgeSet &edges) -{ - compact(); - AccumulateEdgesTracer trc(owner->runtime, &edges); - StoreBuffer::WholeCellEdges *cursor = base; - while (cursor != pos) { - cursor->mark(&trc); - cursor++; - } - return true; -} } /* namespace gc */ } /* namespace js */ /*** RelocatableMonoTypeBuffer ***/ template <typename T> void StoreBuffer::RelocatableMonoTypeBuffer<T>::compactMoved() @@ -281,32 +242,16 @@ StoreBuffer::GenericBuffer::mark(JSTrace BufferableRef *edge = reinterpret_cast<BufferableRef *>(p); edge->mark(trc); p += size; } } -bool -StoreBuffer::GenericBuffer::containsEdge(void *location) const -{ - uint8_t *p = base; - while (p < pos) { - unsigned size = *((unsigned *)p); - p += sizeof(unsigned); - - if (((BufferableRef *)p)->match(location)) - return true; - - p += size; - } - return false; -} - /*** Edges ***/ void StoreBuffer::CellPtrEdge::mark(JSTracer *trc) { MarkObjectRoot(trc, reinterpret_cast<JSObject**>(edge), "store buffer edge"); } @@ -440,51 +385,16 @@ StoreBuffer::setAboutToOverflow() void StoreBuffer::setOverflowed() { JS_ASSERT(enabled); overflowed = true; } bool -StoreBuffer::coalesceForVerification() -{ - if (!edgeSet.initialized()) { - if (!edgeSet.init()) - return false; - } - JS_ASSERT(edgeSet.empty()); - if (!bufferVal.accumulateEdges(edgeSet)) - return false; - if (!bufferCell.accumulateEdges(edgeSet)) - return false; - if (!bufferSlot.accumulateEdges(edgeSet)) - return false; - if (!bufferWholeCell.accumulateEdges(edgeSet)) - return false; - if (!bufferRelocVal.accumulateEdges(edgeSet)) - return false; - if (!bufferRelocCell.accumulateEdges(edgeSet)) - return false; - return true; -} - -bool -StoreBuffer::containsEdgeAt(void *loc) const -{ - return edgeSet.has(loc) || bufferGeneric.containsEdge(loc); -} - -void -StoreBuffer::releaseVerificationData() -{ - edgeSet.finish(); -} - -bool StoreBuffer::inParallelSection() const { return InParallelSection(); } JS_PUBLIC_API(void) JS::HeapCellPostBarrier(js::gc::Cell **cellp) {
--- a/js/src/gc/StoreBuffer.h +++ b/js/src/gc/StoreBuffer.h @@ -17,69 +17,25 @@ #include "jsalloc.h" #include "jsobj.h" namespace js { namespace gc { class AccumulateEdgesTracer; -#ifdef JS_GC_ZEAL -/* - * Note: this is a stub Nursery that does not actually contain a heap, just a - * set of pointers which are "inside" the nursery to implement verification. - */ -class VerifierNursery -{ - HashSet<const void *, PointerHasher<const void *, 3>, SystemAllocPolicy> nursery; - - public: - explicit VerifierNursery() : nursery() {} - - bool enable() { - if (!nursery.initialized()) - return nursery.init(); - return true; - } - - void disable() { - if (!nursery.initialized()) - return; - nursery.finish(); - } - - bool isEnabled() const { - return nursery.initialized(); - } - - bool clear() { - disable(); - return enable(); - } - - bool isInside(const void *cell) const { - return nursery.initialized() && nursery.has(cell); - } - - void insertPointer(void *cell) { - nursery.putNew(cell); - } -}; -#endif /* JS_GC_ZEAL */ - /* * BufferableRef represents an abstract reference for use in the generational * GC's remembered set. Entries in the store buffer that cannot be represented * with the simple pointer-to-a-pointer scheme must derive from this class and * use the generic store buffer interface. */ class BufferableRef { public: - virtual bool match(void *location) = 0; virtual void mark(JSTracer *trc) = 0; }; /* * HashKeyRef represents a reference to a HashTable key. Manual HashTable * barriers should should instantiate this template with their own table/key * type to insert into the generic buffer with putGeneric. */ @@ -90,29 +46,23 @@ class HashKeyRef : public BufferableRef Key key; typedef typename Map::Entry::ValueType ValueType; typedef typename Map::Ptr Ptr; public: HashKeyRef(Map *m, const Key &k) : map(m), key(k) {} - bool match(void *location) { - Ptr p = map->lookup(key); - if (!p) - return false; - return &p->key == location; - } - void mark(JSTracer *trc) { Key prior = key; typename Map::Ptr p = map->lookup(key); if (!p) return; ValueType value = p->value; + JS_SET_TRACING_LOCATION(trc, (void*)&p->key); Mark(trc, &key, "HashKeyRef"); if (prior != key) { map->remove(prior); map->put(key, value); } } }; @@ -165,18 +115,17 @@ class StoreBuffer void disable(); void clear(); bool isEmpty() const { return pos == base; } bool isFull() const { JS_ASSERT(pos <= top); return pos == top; } bool isAboutToOverflow() const { return pos >= highwater; } /* Compaction algorithms. */ - template <typename NurseryType> - void compactNotInSet(NurseryType *nursery); + void compactNotInSet(const Nursery &nursery); void compactRemoveDuplicates(); /* * Attempts to reduce the usage of the buffer by removing unnecessary * entries. */ virtual void compact(); @@ -203,19 +152,16 @@ class StoreBuffer clear(); } } } } /* Mark the source of all edges in the store buffer. */ void mark(JSTracer *trc); - - /* For verification. */ - bool accumulateEdges(EdgeSet &edges); }; /* * Overrides the MonoTypeBuffer to support pointers that may be moved in * memory outside of the GC's control. */ template <typename T> class RelocatableMonoTypeBuffer : public MonoTypeBuffer<T> @@ -255,19 +201,16 @@ class StoreBuffer bool enable(uint8_t *region, size_t len); void disable(); void clear(); /* Mark all generic edges. */ void mark(JSTracer *trc); - /* Check if a pointer is present in the buffer. */ - bool containsEdge(void *location) const; - template <typename T> void put(const T &t) { JS_ASSERT(!owner->inParallelSection()); /* Check if we have been enabled. */ if (!pos) return; @@ -295,19 +238,18 @@ class StoreBuffer Cell **edge; CellPtrEdge(Cell **v) : edge(v) {} bool operator==(const CellPtrEdge &other) const { return edge == other.edge; } bool operator!=(const CellPtrEdge &other) const { return edge != other.edge; } void *location() const { return (void *)edge; } - template <typename NurseryType> - bool inRememberedSet(NurseryType *nursery) const { - return !nursery->isInside(edge) && nursery->isInside(*edge); + bool inRememberedSet(const Nursery &nursery) const { + return !nursery.isInside(edge) && nursery.isInside(*edge); } bool isNullEdge() const { return !*edge; } void mark(JSTracer *trc); @@ -326,19 +268,18 @@ class StoreBuffer ValueEdge(Value *v) : edge(v) {} bool operator==(const ValueEdge &other) const { return edge == other.edge; } bool operator!=(const ValueEdge &other) const { return edge != other.edge; } void *deref() const { return edge->isGCThing() ? edge->toGCThing() : NULL; } void *location() const { return (void *)edge; } - template <typename NurseryType> - bool inRememberedSet(NurseryType *nursery) const { - return !nursery->isInside(edge) && nursery->isInside(deref()); + bool inRememberedSet(const Nursery &nursery) const { + return !nursery.isInside(edge) && nursery.isInside(deref()); } bool isNullEdge() const { return !deref(); } void mark(JSTracer *trc); @@ -369,18 +310,17 @@ class StoreBuffer } JS_ALWAYS_INLINE HeapSlot *slotLocation() const; JS_ALWAYS_INLINE void *deref() const; JS_ALWAYS_INLINE void *location() const; - template <typename NurseryType> - JS_ALWAYS_INLINE bool inRememberedSet(NurseryType *nursery) const; + JS_ALWAYS_INLINE bool inRememberedSet(const Nursery &nursery) const; JS_ALWAYS_INLINE bool isNullEdge() const; void mark(JSTracer *trc); }; class WholeCellEdges { @@ -391,18 +331,17 @@ class StoreBuffer WholeCellEdges(Cell *cell) : tenured(cell) { JS_ASSERT(tenured->isTenured()); } bool operator==(const WholeCellEdges &other) const { return tenured == other.tenured; } bool operator!=(const WholeCellEdges &other) const { return tenured != other.tenured; } - template <typename NurseryType> - bool inRememberedSet(NurseryType *nursery) const { return true; } + bool inRememberedSet(const Nursery &nursery) const { return true; } /* This is used by RemoveDuplicates as a unique pointer to this Edge. */ void *location() const { return (void *)tenured; } bool isNullEdge() const { return false; } void mark(JSTracer *trc); }; @@ -418,19 +357,16 @@ class StoreBuffer JSRuntime *runtime; void *buffer; bool aboutToOverflow; bool overflowed; bool enabled; - /* For the verifier. */ - EdgeSet edgeSet; - /* TODO: profile to find the ideal size for these. */ static const size_t ValueBufferSize = 1 * 1024 * sizeof(ValueEdge); static const size_t CellBufferSize = 2 * 1024 * sizeof(CellPtrEdge); static const size_t SlotBufferSize = 2 * 1024 * sizeof(SlotEdge); static const size_t WholeCellBufferSize = 2 * 1024 * sizeof(WholeCellEdges); static const size_t RelocValueBufferSize = 1 * 1024 * sizeof(ValueEdge); static const size_t RelocCellBufferSize = 1 * 1024 * sizeof(CellPtrEdge); static const size_t GenericBufferSize = 1 * 1024 * sizeof(int); @@ -489,21 +425,16 @@ class StoreBuffer template <typename T> void putGeneric(const T &t) { bufferGeneric.put(t); } /* Mark the source of all edges in the store buffer. */ void mark(JSTracer *trc); - /* For the verifier. */ - bool coalesceForVerification(); - void releaseVerificationData(); - bool containsEdgeAt(void *loc) const; - /* We cannot call InParallelSection directly because of a circular dependency. */ bool inParallelSection() const; /* For use by our owned buffers and for testing. */ void setAboutToOverflow(); void setOverflowed(); };
--- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -9,16 +9,18 @@ #include "jscompartment.h" #include "jsgc.h" #include "jsprf.h" #include "js/HashTable.h" #include "gc/GCInternals.h" #include "gc/Zone.h" +#include "jsgcinlines.h" + #ifdef MOZ_VALGRIND # include <valgrind/memcheck.h> #endif using namespace js; using namespace js::gc; using namespace mozilla; @@ -300,47 +302,16 @@ JS::CheckStackRoots(JSContext *cx) for (Rooter *p = rooters.begin(); p != rooters.end(); p++) p->rooter->scanned = true; } #endif /* DEBUG && JS_GC_ZEAL && JSGC_ROOT_ANALYSIS && !JS_THREADSAFE */ #ifdef JS_GC_ZEAL -static void -DisableGGCForVerification(JSRuntime *rt) -{ -#ifdef JSGC_GENERATIONAL - if (rt->gcVerifyPreData || rt->gcVerifyPostData) - return; - - if (rt->gcNursery.isEnabled()) { - MinorGC(rt, JS::gcreason::API); - rt->gcNursery.disable(); - } - - if (rt->gcStoreBuffer.isEnabled()) - rt->gcStoreBuffer.disable(); -#endif -} - -static void -EnableGGCAfterVerification(JSRuntime *rt) -{ -#ifdef JSGC_GENERATIONAL - if (rt->gcVerifyPreData || rt->gcVerifyPostData) - return; - - if (rt->gcGenerationalEnabled) { - rt->gcNursery.enable(); - rt->gcStoreBuffer.enable(); - } -#endif -} - /* * Write barrier verification * * The next few functions are for write barrier verification. * * The VerifyBarriers function is a shorthand. It checks if a verification phase * is currently running. If not, it starts one. Otherwise, it ends the current * phase and starts a new one. @@ -417,16 +388,18 @@ struct VerifyPreTracer : JSTracer { * This function builds up the heap snapshot by adding edges to the current * node. */ static void AccumulateEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) { VerifyPreTracer *trc = (VerifyPreTracer *)jstrc; + JS_ASSERT(!IsInsideNursery(trc->runtime, *(uintptr_t **)thingp)); + trc->edgeptr += sizeof(EdgeValue); if (trc->edgeptr >= trc->term) { trc->edgeptr = trc->term; return; } VerifyNode *node = trc->curnode; uint32_t i = node->count; @@ -473,17 +446,17 @@ gc::StartVerifyPreBarriers(JSRuntime *rt { if (rt->gcVerifyPreData || rt->gcIncrementalState != NO_INCREMENTAL || !IsIncrementalGCSafe(rt)) { return; } - DisableGGCForVerification(rt); + MinorGC(rt, JS::gcreason::API); AutoPrepareForTracing prep(rt); for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) r.front()->bitmap.clear(); VerifyPreTracer *trc = js_new<VerifyPreTracer>(); @@ -545,17 +518,16 @@ gc::StartVerifyPreBarriers(JSRuntime *rt } return; oom: rt->gcIncrementalState = NO_INCREMENTAL; js_delete(trc); rt->gcVerifyPreData = NULL; - EnableGGCAfterVerification(rt); } static bool IsMarkedOrAllocated(Cell *cell) { return cell->isMarked() || cell->arenaHeader()->allocatedDuringIncremental; } @@ -650,28 +622,30 @@ gc::EndVerifyPreBarriers(JSRuntime *rt) node = NextNode(node); } } rt->gcMarker.reset(); rt->gcMarker.stop(); js_delete(trc); - - EnableGGCAfterVerification(rt); } /*** Post-Barrier Verifyier ***/ struct VerifyPostTracer : JSTracer { /* The gcNumber when the verification began. */ uint64_t number; /* This counts up to gcZealFrequency to decide whether to verify. */ int count; + + /* The set of edges in the StoreBuffer at the end of verification. */ + typedef HashSet<void **, PointerHasher<void **, 3>, SystemAllocPolicy> EdgeSet; + EdgeSet *edges; }; /* * The post-barrier verifier runs the full store buffer and a fake nursery when * running and when it stops, walks the full heap to ensure that all the * important edges were inserted into the storebuffer. */ void @@ -679,108 +653,124 @@ gc::StartVerifyPostBarriers(JSRuntime *r { #ifdef JSGC_GENERATIONAL if (rt->gcVerifyPostData || rt->gcIncrementalState != NO_INCREMENTAL) { return; } - DisableGGCForVerification(rt); + MinorGC(rt, JS::gcreason::API); VerifyPostTracer *trc = js_new<VerifyPostTracer>(); rt->gcVerifyPostData = trc; rt->gcNumber++; trc->number = rt->gcNumber; trc->count = 0; - - if (!rt->gcVerifierNursery.enable()) - goto oom; - - if (!rt->gcStoreBuffer.enable()) - goto oom; - - return; -oom: - js_delete(trc); - rt->gcVerifyPostData = NULL; - EnableGGCAfterVerification(rt); #endif } #ifdef JSGC_GENERATIONAL +void +PostVerifierCollectStoreBufferEdges(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) +{ + VerifyPostTracer *trc = (VerifyPostTracer *)jstrc; + + /* The nursery only stores objects. */ + if (kind != JSTRACE_OBJECT) + return; + + /* The store buffer may store extra, non-cross-generational edges. */ + JSObject *dst = *reinterpret_cast<JSObject **>(thingp); + if (trc->runtime->gcNursery.isInside(thingp) || !trc->runtime->gcNursery.isInside(dst)) + return; + + /* + * Values will be unpacked to the stack before getting here. However, the + * only things that enter this callback are marked by the store buffer. The + * store buffer ensures that the real tracing location is set correctly. + */ + void **loc = trc->realLocation != NULL ? (void **)trc->realLocation : thingp; + + trc->edges->put(loc); +} + static void -AssertStoreBufferContainsEdge(StoreBuffer *storebuf, void *loc, void *dst) +AssertStoreBufferContainsEdge(VerifyPostTracer::EdgeSet *edges, void **loc, JSObject *dst) { - if (storebuf->containsEdgeAt(loc)) + if (edges->has(loc)) return; char msgbuf[1024]; JS_snprintf(msgbuf, sizeof(msgbuf), "[post-barrier verifier] Missing edge @ %p to %p", - loc, dst); + (void *)loc, (void *)dst); MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__); MOZ_CRASH(); } void PostVerifierVisitEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) { VerifyPostTracer *trc = (VerifyPostTracer *)jstrc; - Cell *dst = (Cell *)*thingp; - JSRuntime *rt = dst->runtime(); + + /* The nursery only stores objects. */ + if (kind != JSTRACE_OBJECT) + return; /* Filter out non cross-generational edges. */ - if (!rt->gcVerifierNursery.isInside(dst)) + JS_ASSERT(!trc->runtime->gcNursery.isInside(thingp)); + JSObject *dst = *reinterpret_cast<JSObject **>(thingp); + if (!trc->runtime->gcNursery.isInside(dst)) return; /* - * Note: since Value travels through the stack to get Cell**, we need to use - * the annotated location in the tracer instead of the indirect location for - * these edges. + * Values will be unpacked to the stack before getting here. However, the + * only things that enter this callback are marked by the JS_TraceChildren + * below. Since ObjectImpl::markChildren handles this, the real trace + * location will be set correctly in these cases. */ - Cell *loc = (Cell *)(trc->realLocation != NULL ? trc->realLocation : thingp); + void **loc = trc->realLocation != NULL ? (void **)trc->realLocation : thingp; - AssertStoreBufferContainsEdge(&rt->gcStoreBuffer, loc, dst); + AssertStoreBufferContainsEdge(trc->edges, loc, dst); } #endif void js::gc::EndVerifyPostBarriers(JSRuntime *rt) { #ifdef JSGC_GENERATIONAL + VerifyPostTracer::EdgeSet edges; AutoPrepareForTracing prep(rt); VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData; - JS_TracerInit(trc, rt, PostVerifierVisitEdge); - trc->count = 0; if (rt->gcStoreBuffer.hasOverflowed()) goto oom; - if (!rt->gcStoreBuffer.coalesceForVerification()) + /* Visit every entry in the store buffer and put the edges in a hash set. */ + JS_TracerInit(trc, rt, PostVerifierCollectStoreBufferEdges); + if (!edges.init()) goto oom; + trc->edges = &edges; + rt->gcStoreBuffer.mark(trc); - /* Walk the heap. */ + /* Walk the heap to find any edges not the the |edges| set. */ + JS_TracerInit(trc, rt, PostVerifierVisitEdge); for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { for (size_t kind = 0; kind < FINALIZE_LIMIT; ++kind) { for (CellIterUnderGC cells(zone, AllocKind(kind)); !cells.done(); cells.next()) { Cell *src = cells.getCell(); - if (!rt->gcVerifierNursery.isInside(src)) - JS_TraceChildren(trc, src, MapAllocToTraceKind(AllocKind(kind))); + JS_TraceChildren(trc, src, MapAllocToTraceKind(AllocKind(kind))); } } } oom: js_delete(trc); rt->gcVerifyPostData = NULL; - rt->gcVerifierNursery.disable(); - rt->gcStoreBuffer.disable(); - rt->gcStoreBuffer.releaseVerificationData(); - EnableGGCAfterVerification(rt); #endif } /*** Barrier Verifier Scheduling ***/ static void VerifyPreBarriers(JSRuntime *rt) { @@ -856,18 +846,14 @@ js::gc::FinishVerifier(JSRuntime *rt) { if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData) { js_delete(trc); rt->gcVerifyPreData = NULL; } #ifdef JSGC_GENERATIONAL if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData) { js_delete(trc); - rt->gcVerifierNursery.disable(); - rt->gcStoreBuffer.disable(); - rt->gcStoreBuffer.releaseVerificationData(); rt->gcVerifyPostData = NULL; } #endif - EnableGGCAfterVerification(rt); } #endif /* JS_GC_ZEAL */
--- a/js/src/ion/BaselineBailouts.cpp +++ b/js/src/ion/BaselineBailouts.cpp @@ -1210,17 +1210,17 @@ ion::FinishBailoutToBaseline(BaselineBai if (topFrame->scopeChain() && !EnsureHasScopeObjects(cx, topFrame)) return false; // Create arguments objects for bailed out frames, to maintain the invariant // that script->needsArgsObj() implies frame->hasArgsObj(). RootedScript innerScript(cx, NULL); RootedScript outerScript(cx, NULL); - JS_ASSERT(cx->mainThread().currentlyRunningInJit()); + JS_ASSERT(cx->currentlyRunningInJit()); IonFrameIterator iter(cx->mainThread().ionTop); uint32_t frameno = 0; while (frameno < numFrames) { JS_ASSERT(!iter.isOptimizedJS()); if (iter.isBaselineJS()) { BaselineFrame *frame = iter.baselineFrame();
--- a/js/src/ion/BaselineFrame.h +++ b/js/src/ion/BaselineFrame.h @@ -145,30 +145,30 @@ class BaselineFrame JS_ASSERT((size % sizeof(Value)) == 0); return size / sizeof(Value); } Value *valueSlot(size_t slot) const { JS_ASSERT(slot < numValueSlots()); return (Value *)this - (slot + 1); } - Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing) const { + Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i)); JS_ASSERT(i < script()->nfixed); return *valueSlot(i); } - Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing) const { + Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { JS_ASSERT(i < numFormalArgs()); JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals()); JS_ASSERT_IF(checkAliasing, !script()->formalIsAliased(i)); return argv()[i]; } - Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const { + Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { JS_ASSERT(i < numActualArgs()); JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals()); JS_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i)); return argv()[i]; } Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { #ifdef DEBUG @@ -332,16 +332,19 @@ class BaselineFrame return isNonStrictEvalFrame() && isDirectEvalFrame(); } bool isNonEvalFunctionFrame() const { return isFunctionFrame() && !isEvalFrame(); } bool isDebuggerFrame() const { return false; } + bool isGeneratorFrame() const { + return false; + } IonJSFrameLayout *framePrefix() const { uint8_t *fp = (uint8_t *)this + Size() + FramePointerOffset; return (IonJSFrameLayout *)fp; } // Methods below are used by the compiler. static size_t offsetOfCalleeToken() {
--- a/js/src/ion/BaselineIC.cpp +++ b/js/src/ion/BaselineIC.cpp @@ -671,17 +671,17 @@ ICStubCompiler::emitPostWriteBarrierSlot #endif // JSGC_GENERATIONAL // // UseCount_Fallback // static bool IsTopFrameConstructing(JSContext *cx) { - JS_ASSERT(cx->mainThread().currentlyRunningInJit()); + JS_ASSERT(cx->currentlyRunningInJit()); JitActivationIterator activations(cx->runtime()); IonFrameIterator iter(activations); JS_ASSERT(iter.type() == IonFrame_Exit); ++iter; JS_ASSERT(iter.type() == IonFrame_BaselineStub); ++iter; @@ -2463,16 +2463,19 @@ DoBinaryArithFallback(JSContext *cx, Bas return false; break; } default: JS_NOT_REACHED("Unhandled baseline arith op"); return false; } + if (ret.isDouble()) + stub->setSawDoubleResult(); + // Check to see if a new stub should be generated. if (stub->numOptimizedStubs() >= ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS) { // TODO: Discard all stubs in this IC and replace with inert megamorphic stub. // But for now we just bail. return true; } // Handle string concat. @@ -2965,16 +2968,19 @@ DoUnaryArithFallback(JSContext *cx, Base if (!NegOperation(cx, script, pc, val, res)) return false; break; default: JS_NOT_REACHED("Unexpected op"); return false; } + if (res.isDouble()) + stub->setSawDoubleResult(); + if (stub->numOptimizedStubs() >= ICUnaryArith_Fallback::MAX_OPTIMIZED_STUBS) { // TODO: Discard/replace stubs. return true; } if (val.isInt32() && res.isInt32()) { IonSpew(IonSpew_BaselineIC, " Generating %s(Int32 => Int32) stub", js_CodeName[op]); ICUnaryArith_Int32::Compiler compiler(cx, op);
--- a/js/src/ion/BaselineIC.h +++ b/js/src/ion/BaselineIC.h @@ -2370,27 +2370,37 @@ class ICToNumber_Fallback : public ICFal // JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR // JSOP_LSH, JSOP_RSH, JSOP_URSH class ICBinaryArith_Fallback : public ICFallbackStub { friend class ICStubSpace; ICBinaryArith_Fallback(IonCode *stubCode) - : ICFallbackStub(BinaryArith_Fallback, stubCode) {} + : ICFallbackStub(BinaryArith_Fallback, stubCode) + { + extra_ = 0; + } public: static const uint32_t MAX_OPTIMIZED_STUBS = 8; static inline ICBinaryArith_Fallback *New(ICStubSpace *space, IonCode *code) { if (!code) return NULL; return space->allocate<ICBinaryArith_Fallback>(code); } + bool sawDoubleResult() { + return extra_; + } + void setSawDoubleResult() { + extra_ = 1; + } + // Compiler for this stub kind. class Compiler : public ICStubCompiler { protected: bool generateStubCode(MacroAssembler &masm); public: Compiler(JSContext *cx) : ICStubCompiler(cx, ICStub::BinaryArith_Fallback) {} @@ -2658,27 +2668,37 @@ class ICBinaryArith_DoubleWithInt32 : pu // JSOP_BITNOT // JSOP_NEG class ICUnaryArith_Fallback : public ICFallbackStub { friend class ICStubSpace; ICUnaryArith_Fallback(IonCode *stubCode) - : ICFallbackStub(UnaryArith_Fallback, stubCode) {} + : ICFallbackStub(UnaryArith_Fallback, stubCode) + { + extra_ = 0; + } public: static const uint32_t MAX_OPTIMIZED_STUBS = 8; static inline ICUnaryArith_Fallback *New(ICStubSpace *space, IonCode *code) { if (!code) return NULL; return space->allocate<ICUnaryArith_Fallback>(code); } + bool sawDoubleResult() { + return extra_; + } + void setSawDoubleResult() { + extra_ = 1; + } + // Compiler for this stub kind. class Compiler : public ICStubCompiler { protected: bool generateStubCode(MacroAssembler &masm); public: Compiler(JSContext *cx) : ICStubCompiler(cx, ICStub::UnaryArith_Fallback)
--- a/js/src/ion/BaselineInspector.cpp +++ b/js/src/ion/BaselineInspector.cpp @@ -160,19 +160,19 @@ BaselineInspector::expectedResultType(js switch (stub->kind()) { case ICStub::BinaryArith_Int32: if (stub->toBinaryArith_Int32()->allowDouble()) return MIRType_Double; return MIRType_Int32; case ICStub::BinaryArith_BooleanWithInt32: case ICStub::UnaryArith_Int32: + case ICStub::BinaryArith_DoubleWithInt32: return MIRType_Int32; case ICStub::BinaryArith_Double: - case ICStub::BinaryArith_DoubleWithInt32: case ICStub::UnaryArith_Double: return MIRType_Double; case ICStub::BinaryArith_StringConcat: case ICStub::BinaryArith_StringObjectConcat: return MIRType_String; default: return MIRType_None; } @@ -306,8 +306,27 @@ BaselineInspector::hasSeenAccessedGetter const ICEntry &entry = icEntryFromPC(pc); ICStub *stub = entry.fallbackStub(); if (stub->isGetProp_Fallback()) return stub->toGetProp_Fallback()->hasAccessedGetter(); return false; } + +bool +BaselineInspector::hasSeenDoubleResult(jsbytecode *pc) +{ + if (!hasBaselineScript()) + return false; + + const ICEntry &entry = icEntryFromPC(pc); + ICStub *stub = entry.fallbackStub(); + + JS_ASSERT(stub->isUnaryArith_Fallback() || stub->isBinaryArith_Fallback()); + + if (stub->isUnaryArith_Fallback()) + return stub->toUnaryArith_Fallback()->sawDoubleResult(); + else + return stub->toBinaryArith_Fallback()->sawDoubleResult(); + + return false; +}
--- a/js/src/ion/BaselineInspector.h +++ b/js/src/ion/BaselineInspector.h @@ -103,16 +103,17 @@ class BaselineInspector } MIRType expectedResultType(jsbytecode *pc); MCompare::CompareType expectedCompareType(jsbytecode *pc); MIRType expectedBinaryArithSpecialization(jsbytecode *pc); bool hasSeenNonNativeGetElement(jsbytecode *pc); bool hasSeenAccessedGetter(jsbytecode *pc); + bool hasSeenDoubleResult(jsbytecode *pc); }; } // namespace ion } // namespace js #endif // JS_ION #endif // jsion_baseline_inspector_h__
--- a/js/src/ion/BaselineJIT.cpp +++ b/js/src/ion/BaselineJIT.cpp @@ -38,151 +38,162 @@ BaselineScript::BaselineScript(uint32_t #ifdef DEBUG spsOn_(false), #endif spsPushToggleOffset_(spsPushToggleOffset), flags_(0) { } static const size_t BASELINE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4096; +static const unsigned BASELINE_MAX_ARGS_LENGTH = 20000; static bool CheckFrame(StackFrame *fp) { if (fp->isGeneratorFrame()) { IonSpew(IonSpew_BaselineAbort, "generator frame"); return false; } if (fp->isDebuggerFrame()) { // Debugger eval-in-frame. These are likely short-running scripts so // don't bother compiling them for now. IonSpew(IonSpew_BaselineAbort, "debugger frame"); return false; } - static const unsigned MAX_ARGS_LENGTH = 20000; - - if (fp->isNonEvalFunctionFrame() && fp->numActualArgs() > MAX_ARGS_LENGTH) { + if (fp->isNonEvalFunctionFrame() && fp->numActualArgs() > BASELINE_MAX_ARGS_LENGTH) { // Fall back to the interpreter to avoid running out of stack space. IonSpew(IonSpew_BaselineAbort, "Too many arguments (%u)", fp->numActualArgs()); return false; } return true; } static bool IsJSDEnabled(JSContext *cx) { return cx->compartment()->debugMode() && cx->runtime()->debugHooks.callHook; } static IonExecStatus -EnterBaseline(JSContext *cx, StackFrame *fp, void *jitcode, bool osr) +EnterBaseline(JSContext *cx, EnterJitData &data) { JS_CHECK_RECURSION(cx, return IonExec_Aborted); JS_ASSERT(ion::IsBaselineEnabled(cx)); - JS_ASSERT(CheckFrame(fp)); + JS_ASSERT_IF(data.osrFrame, CheckFrame(data.osrFrame)); EnterIonCode enter = cx->compartment()->ionCompartment()->enterBaselineJIT(); - // maxArgc is the maximum of arguments between the number of actual - // arguments and the number of formal arguments. It accounts for |this|. - int maxArgc = 0; - Value *maxArgv = NULL; - unsigned numActualArgs = 0; - RootedValue thisv(cx); + // Caller must construct |this| before invoking the Ion function. + JS_ASSERT_IF(data.constructing, data.maxArgv[0].isObject()); - void *calleeToken; - if (fp->isNonEvalFunctionFrame()) { - numActualArgs = fp->numActualArgs(); - maxArgc = Max(numActualArgs, fp->numFormalArgs()) + 1; // +1 = include |this| - maxArgv = fp->argv() - 1; // -1 = include |this| - calleeToken = CalleeToToken(&fp->callee()); - } else { - // For eval function frames, set the callee token to the enclosing function. - if (fp->isFunctionFrame()) - calleeToken = CalleeToToken(&fp->callee()); - else - calleeToken = CalleeToToken(fp->script()); - thisv = fp->thisValue(); - maxArgc = 1; - maxArgv = thisv.address(); - } - - // Caller must construct |this| before invoking the Ion function. - JS_ASSERT_IF(fp->isConstructing(), fp->functionThis().isObject()); - - RootedValue result(cx, Int32Value(numActualArgs)); + data.result.setInt32(data.numActualArgs); { AssertCompartmentUnchanged pcc(cx); IonContext ictx(cx, NULL); - JitActivation activation(cx, fp->isConstructing()); + JitActivation activation(cx, data.constructing); JSAutoResolveFlags rf(cx, RESOLVE_INFER); - - fp->setRunningInJit(); + AutoFlushInhibitor afi(cx->compartment()->ionCompartment()); - // Pass the scope chain for global and eval frames. - JSObject *scopeChain = NULL; - if (!fp->isNonEvalFunctionFrame()) - scopeChain = fp->scopeChain(); + if (data.osrFrame) + data.osrFrame->setRunningInJit(); - // For OSR, pass the number of locals + stack values. - uint32_t numStackValues = osr ? fp->script()->nfixed + cx->regs().stackDepth() : 0; - JS_ASSERT_IF(osr, !IsJSDEnabled(cx)); + JS_ASSERT_IF(data.osrFrame, !IsJSDEnabled(cx)); - AutoFlushInhibitor afi(cx->compartment()->ionCompartment()); // Single transition point from Interpreter to Baseline. - enter(jitcode, maxArgc, maxArgv, osr ? fp : NULL, calleeToken, scopeChain, numStackValues, - result.address()); + enter(data.jitcode, data.maxArgc, data.maxArgv, data.osrFrame, data.calleeToken, + data.scopeChain, data.osrNumStackValues, data.result.address()); - fp->clearRunningInJit(); + if (data.osrFrame) + data.osrFrame->clearRunningInJit(); } - JS_ASSERT(fp == cx->fp()); JS_ASSERT(!cx->runtime()->hasIonReturnOverride()); - // The trampoline wrote the return value but did not set the HAS_RVAL flag. - fp->setReturnValue(result); - - // Ion callers wrap primitive constructor return. - if (!result.isMagic() && fp->isConstructing() && fp->returnValue().isPrimitive()) - fp->setReturnValue(ObjectValue(fp->constructorThis())); + // Jit callers wrap primitive constructor return. + if (!data.result.isMagic() && data.constructing && data.result.isPrimitive()) + data.result = data.maxArgv[0]; // Release temporary buffer used for OSR into Ion. cx->runtime()->getIonRuntime(cx)->freeOsrTempData(); - JS_ASSERT_IF(result.isMagic(), result.isMagic(JS_ION_ERROR)); - return result.isMagic() ? IonExec_Error : IonExec_Ok; + JS_ASSERT_IF(data.result.isMagic(), data.result.isMagic(JS_ION_ERROR)); + return data.result.isMagic() ? IonExec_Error : IonExec_Ok; } IonExecStatus -ion::EnterBaselineMethod(JSContext *cx, StackFrame *fp) +ion::EnterBaselineMethod(JSContext *cx, RunState &state) { - BaselineScript *baseline = fp->script()->baselineScript(); - void *jitcode = baseline->method()->raw(); + BaselineScript *baseline = state.script()->baselineScript(); + + EnterJitData data(cx); + data.jitcode = baseline->method()->raw(); - return EnterBaseline(cx, fp, jitcode, /* osr = */false); + AutoValueVector vals(cx); + if (!SetEnterJitData(cx, data, state, vals)) + return IonExec_Error; + + IonExecStatus status = EnterBaseline(cx, data); + if (status != IonExec_Ok) + return status; + + state.setReturnValue(data.result); + return IonExec_Ok; } IonExecStatus ion::EnterBaselineAtBranch(JSContext *cx, StackFrame *fp, jsbytecode *pc) { JS_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY); BaselineScript *baseline = fp->script()->baselineScript(); - uint8_t *jitcode = baseline->nativeCodeForPC(fp->script(), pc); + + EnterJitData data(cx); + data.jitcode = baseline->nativeCodeForPC(fp->script(), pc); // Skip debug breakpoint/trap handler, the interpreter already handled it // for the current op. if (cx->compartment()->debugMode()) - jitcode += MacroAssembler::ToggledCallSize(); + data.jitcode += MacroAssembler::ToggledCallSize(); + + data.osrFrame = fp; + data.osrNumStackValues = fp->script()->nfixed + cx->interpreterRegs().stackDepth(); + + RootedValue thisv(cx); - return EnterBaseline(cx, fp, jitcode, /* osr = */true); + if (fp->isNonEvalFunctionFrame()) { + data.constructing = fp->isConstructing(); + data.numActualArgs = fp->numActualArgs(); + data.maxArgc = Max(fp->numActualArgs(), fp->numFormalArgs()) + 1; // +1 = include |this| + data.maxArgv = fp->argv() - 1; // -1 = include |this| + data.scopeChain = NULL; + data.calleeToken = CalleeToToken(&fp->callee()); + } else { + thisv = fp->thisValue(); + data.constructing = false; + data.numActualArgs = 0; + data.maxArgc = 1; + data.maxArgv = thisv.address(); + data.scopeChain = fp->scopeChain(); + + // For eval function frames, set the callee token to the enclosing function. + if (fp->isFunctionFrame()) + data.calleeToken = CalleeToToken(&fp->callee()); + else + data.calleeToken = CalleeToToken(fp->script()); + } + + IonExecStatus status = EnterBaseline(cx, data); + if (status != IonExec_Ok) + return status; + + fp->setReturnValue(data.result); + return IonExec_Ok; } static MethodStatus BaselineCompile(JSContext *cx, HandleScript script) { JS_ASSERT(!script->hasBaselineScript()); JS_ASSERT(script->canBaselineCompile()); @@ -205,54 +216,39 @@ BaselineCompile(JSContext *cx, HandleScr JS_ASSERT_IF(status != Method_Compiled, !script->hasBaselineScript()); if (status == Method_CantCompile) script->setBaselineScript(BASELINE_DISABLED_SCRIPT); return status; } -MethodStatus -ion::CanEnterBaselineJIT(JSContext *cx, JSScript *scriptArg, StackFrame *fp, bool newType) +static MethodStatus +CanEnterBaselineJIT(JSContext *cx, HandleScript script, bool osr) { - // Skip if baseline compilation is disabled in options. JS_ASSERT(ion::IsBaselineEnabled(cx)); // Skip if the script has been disabled. - if (!scriptArg->canBaselineCompile()) + if (!script->canBaselineCompile()) return Method_Skipped; - if (scriptArg->length > BaselineScript::MAX_JSSCRIPT_LENGTH) - return Method_CantCompile; - - RootedScript script(cx, scriptArg); - - // If constructing, allocate a new |this| object. - if (fp->isConstructing() && fp->functionThis().isPrimitive()) { - RootedObject callee(cx, &fp->callee()); - RootedObject obj(cx, CreateThisForFunction(cx, callee, newType)); - if (!obj) - return Method_Skipped; - fp->functionThis().setObject(*obj); - } - - if (!CheckFrame(fp)) + if (script->length > BaselineScript::MAX_JSSCRIPT_LENGTH) return Method_CantCompile; if (!cx->compartment()->ensureIonCompartmentExists(cx)) return Method_Error; if (script->hasBaselineScript()) return Method_Compiled; // Check script use count. However, always eagerly compile scripts if JSD // is enabled, so that we don't have to OSR and don't have to update the // frame pointer stored in JSD's frames list. if (IsJSDEnabled(cx)) { - if (JSOp(*cx->regs().pc) == JSOP_LOOPENTRY) // No OSR. + if (osr) return Method_Skipped; } else if (script->incUseCount() <= js_IonOptions.baselineUsesBeforeCompile) { return Method_Skipped; } if (script->isCallsiteClone) { // Ensure the original function is compiled too, so that bailouts from // Ion code have a BaselineScript to resume into. @@ -267,16 +263,70 @@ ion::CanEnterBaselineJIT(JSContext *cx, if (status != Method_Compiled) return status; } } return BaselineCompile(cx, script); } +MethodStatus +ion::CanEnterBaselineAtBranch(JSContext *cx, StackFrame *fp, bool newType) +{ + // If constructing, allocate a new |this| object. + if (fp->isConstructing() && fp->functionThis().isPrimitive()) { + RootedObject callee(cx, &fp->callee()); + RootedObject obj(cx, CreateThisForFunction(cx, callee, newType)); + if (!obj) + return Method_Skipped; + fp->functionThis().setObject(*obj); + } + + if (!CheckFrame(fp)) + return Method_CantCompile; + + RootedScript script(cx, fp->script()); + return CanEnterBaselineJIT(cx, script, /* osr = */true); +} + +MethodStatus +ion::CanEnterBaselineMethod(JSContext *cx, RunState &state) +{ + if (state.isInvoke()) { + InvokeState &invoke = *state.asInvoke(); + + if (invoke.args().length() > BASELINE_MAX_ARGS_LENGTH) { + IonSpew(IonSpew_BaselineAbort, "Too many arguments (%u)", invoke.args().length()); + return Method_CantCompile; + } + + // If constructing, allocate a new |this| object. + if (invoke.constructing() && invoke.args().thisv().isPrimitive()) { + RootedObject callee(cx, &invoke.args().callee()); + RootedObject obj(cx, CreateThisForFunction(cx, callee, invoke.useNewType())); + if (!obj) + return Method_Skipped; + invoke.args().setThis(ObjectValue(*obj)); + } + } else if (state.isExecute()) { + ExecuteType type = state.asExecute()->type(); + if (type == EXECUTE_DEBUG || type == EXECUTE_DEBUG_GLOBAL) { + IonSpew(IonSpew_BaselineAbort, "debugger frame"); + return Method_CantCompile; + } + } else { + JS_ASSERT(state.isGenerator()); + IonSpew(IonSpew_BaselineAbort, "generator frame"); + return Method_CantCompile; + } + + RootedScript script(cx, state.script()); + return CanEnterBaselineJIT(cx, script, /* osr = */false); +}; + // Be safe, align IC entry list to 8 in all cases. static const unsigned DataAlignment = sizeof(uintptr_t); BaselineScript * BaselineScript::New(JSContext *cx, uint32_t prologueOffset, uint32_t spsPushToggleOffset, size_t icEntries, size_t pcMappingIndexEntries, size_t pcMappingSize) {
--- a/js/src/ion/BaselineJIT.h +++ b/js/src/ion/BaselineJIT.h @@ -258,20 +258,23 @@ struct BaselineScript inline bool IsBaselineEnabled(JSContext *cx) { return cx->hasOption(JSOPTION_BASELINE); } MethodStatus -CanEnterBaselineJIT(JSContext *cx, JSScript *scriptArg, StackFrame *fp, bool newType); +CanEnterBaselineMethod(JSContext *cx, RunState &state); + +MethodStatus +CanEnterBaselineAtBranch(JSContext *cx, StackFrame *fp, bool newType); IonExecStatus -EnterBaselineMethod(JSContext *cx, StackFrame *fp); +EnterBaselineMethod(JSContext *cx, RunState &state); IonExecStatus EnterBaselineAtBranch(JSContext *cx, StackFrame *fp, jsbytecode *pc); void FinishDiscardBaselineScript(FreeOp *fop, JSScript *script); void
--- a/js/src/ion/Ion.cpp +++ b/js/src/ion/Ion.cpp @@ -1337,17 +1337,17 @@ OffThreadCompilationAvailable(JSContext return OffThreadCompilationEnabled(cx) && cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL && !cx->runtime()->profilingScripts && !cx->runtime()->spsProfiler.enabled(); } static AbortReason IonCompile(JSContext *cx, JSScript *script, - AbstractFramePtr fp, jsbytecode *osrPc, bool constructing, + BaselineFrame *baselineFrame, jsbytecode *osrPc, bool constructing, ExecutionMode executionMode) { #if JS_TRACE_LOGGING AutoTraceLog logger(TraceLogging::defaultLogger(), TraceLogging::ION_COMPILE_START, TraceLogging::ION_COMPILE_STOP, script); #endif @@ -1386,22 +1386,22 @@ IonCompile(JSContext *cx, JSScript *scri AutoFlushCache afc("IonCompile"); types::AutoEnterCompilation enterCompiler(cx, CompilerOutputKind(executionMode)); if (!enterCompiler.init(script)) return AbortReason_Disable; AutoTempAllocatorRooter root(cx, temp); - IonBuilder *builder = alloc->new_<IonBuilder>(cx, temp, graph, &inspector, info, fp); + IonBuilder *builder = alloc->new_<IonBuilder>(cx, temp, graph, &inspector, info, baselineFrame); if (!builder) return AbortReason_Alloc; JS_ASSERT(!GetIonScript(builder->script(), executionMode)); - JS_ASSERT(builder->script()->canIonCompile()); + JS_ASSERT(CanIonCompile(builder->script(), executionMode)); RootedScript builderScript(cx, builder->script()); IonSpewNewFunction(graph, builderScript); if (!builder->build()) { IonSpew(IonSpew_Abort, "Builder failed to build."); return builder->abortReason(); } @@ -1432,53 +1432,47 @@ IonCompile(JSContext *cx, JSScript *scri bool success = codegen->link(); IonSpewEndFunction(); return success ? AbortReason_NoAbort : AbortReason_Disable; } static bool -CheckFrame(AbstractFramePtr fp) +TooManyArguments(unsigned nargs) { - if (fp.isEvalFrame()) { - // Eval frames are not yet supported. Supporting this will require new - // logic in pushBailoutFrame to deal with linking prev. - // Additionally, JSOP_DEFVAR support will require baking in isEvalFrame(). - IonSpew(IonSpew_Abort, "eval frame"); - return false; - } - - if (fp.isGeneratorFrame()) { - // Err... no. - IonSpew(IonSpew_Abort, "generator frame"); - return false; - } - - if (fp.isDebuggerFrame()) { - IonSpew(IonSpew_Abort, "debugger frame"); - return false; - } - - // This check is to not overrun the stack. Eventually, we will want to - // handle this when we support JSOP_ARGUMENTS or function calls. - if (fp.isFunctionFrame() && - (fp.numActualArgs() >= SNAPSHOT_MAX_NARGS || - fp.numActualArgs() > js_IonOptions.maxStackArgs)) - { + return (nargs >= SNAPSHOT_MAX_NARGS || nargs > js_IonOptions.maxStackArgs); +} + +static bool +CheckFrame(BaselineFrame *frame) +{ + JS_ASSERT(!frame->isGeneratorFrame()); + JS_ASSERT(!frame->isDebuggerFrame()); + + // This check is to not overrun the stack. + if (frame->isFunctionFrame() && TooManyArguments(frame->numActualArgs())) { IonSpew(IonSpew_Abort, "too many actual args"); return false; } return true; } static bool CheckScript(JSContext *cx, JSScript *script, bool osr) { + if (script->isForEval()) { + // Eval frames are not yet supported. Supporting this will require new + // logic in pushBailoutFrame to deal with linking prev. + // Additionally, JSOP_DEFVAR support will require baking in isEvalFrame(). + IonSpew(IonSpew_Abort, "eval script"); + return false; + } + if (!script->analyzedArgsUsage() && !script->ensureRanAnalysis(cx)) { IonSpew(IonSpew_Abort, "OOM under ensureRanAnalysis"); return false; } if (osr && script->needsArgsObj()) { // OSR-ing into functions with arguments objects is not supported. IonSpew(IonSpew_Abort, "OSR script has argsobj"); @@ -1541,17 +1535,17 @@ CanIonCompileScript(JSContext *cx, Handl { if (!script->canIonCompile() || !CheckScript(cx, script, osr)) return false; return CheckScriptSize(cx, script) == Method_Compiled; } static MethodStatus -Compile(JSContext *cx, HandleScript script, AbstractFramePtr fp, jsbytecode *osrPc, +Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc, bool constructing, ExecutionMode executionMode) { JS_ASSERT(ion::IsEnabled(cx)); JS_ASSERT(ion::IsBaselineEnabled(cx)); JS_ASSERT_IF(osrPc != NULL, (JSOp)*osrPc == JSOP_LOOPENTRY); if (executionMode == SequentialExecution && !script->hasBaselineScript()) return Method_Skipped; @@ -1581,31 +1575,31 @@ Compile(JSContext *cx, HandleScript scri if (executionMode == SequentialExecution) { // Use getUseCount instead of incUseCount to avoid bumping the // use count twice. if (script->getUseCount() < js_IonOptions.usesBeforeCompile) return Method_Skipped; } - AbortReason reason = IonCompile(cx, script, fp, osrPc, constructing, executionMode); + AbortReason reason = IonCompile(cx, script, osrFrame, osrPc, constructing, executionMode); if (reason == AbortReason_Disable) return Method_CantCompile; // Compilation succeeded or we invalidated right away or an inlining/alloc abort return HasIonScript(script, executionMode) ? Method_Compiled : Method_Skipped; } } // namespace ion } // namespace js // Decide if a transition from interpreter execution to Ion code should occur. // May compile or recompile the target JSScript. MethodStatus -ion::CanEnterAtBranch(JSContext *cx, JSScript *script, AbstractFramePtr fp, +ion::CanEnterAtBranch(JSContext *cx, JSScript *script, BaselineFrame *osrFrame, jsbytecode *pc, bool isConstructing) { JS_ASSERT(ion::IsEnabled(cx)); JS_ASSERT((JSOp)*pc == JSOP_LOOPENTRY); // Skip if the script has been disabled. if (!script->canIonCompile()) return Method_Skipped; @@ -1618,24 +1612,24 @@ ion::CanEnterAtBranch(JSContext *cx, JSS if (script->hasIonScript() && script->ionScript()->bailoutExpected()) return Method_Skipped; // Optionally ignore on user request. if (!js_IonOptions.osr) return Method_Skipped; // Mark as forbidden if frame can't be handled. - if (!CheckFrame(fp)) { + if (!CheckFrame(osrFrame)) { ForbidCompilation(cx, script); return Method_CantCompile; } // Attempt compilation. Returns Method_Compiled if already compiled. RootedScript rscript(cx, script); - MethodStatus status = Compile(cx, rscript, fp, pc, isConstructing, SequentialExecution); + MethodStatus status = Compile(cx, rscript, osrFrame, pc, isConstructing, SequentialExecution); if (status != Method_Compiled) { if (status == Method_CantCompile) ForbidCompilation(cx, script); return status; } if (script->ionScript()->osrPc() != pc) { // If we keep failing to enter the script due to an OSR pc mismatch, @@ -1650,88 +1644,100 @@ ion::CanEnterAtBranch(JSContext *cx, JSS } script->ionScript()->resetOsrPcMismatchCounter(); return Method_Compiled; } MethodStatus -ion::CanEnter(JSContext *cx, HandleScript script, AbstractFramePtr fp, bool isConstructing) +ion::CanEnter(JSContext *cx, RunState &state) { JS_ASSERT(ion::IsEnabled(cx)); + JSScript *script = state.script(); + // Skip if the script has been disabled. if (!script->canIonCompile()) return Method_Skipped; // Skip if the script is being compiled off thread. if (script->isIonCompilingOffThread()) return Method_Skipped; // Skip if the code is expected to result in a bailout. if (script->hasIonScript() && script->ionScript()->bailoutExpected()) return Method_Skipped; // If constructing, allocate a new |this| object before building Ion. // Creating |this| is done before building Ion because it may change the // type information and invalidate compilation results. - if (isConstructing && fp.thisValue().isPrimitive()) { - RootedObject callee(cx, fp.callee()); - RootedObject obj(cx, CreateThisForFunction(cx, callee, fp.useNewType())); - if (!obj || !ion::IsEnabled(cx)) // Note: OOM under CreateThis can disable TI. - return Method_Skipped; - fp.thisValue().setObject(*obj); - } - - // Mark as forbidden if frame can't be handled. - if (!CheckFrame(fp)) { + if (state.isInvoke()) { + InvokeState &invoke = *state.asInvoke(); + + if (TooManyArguments(invoke.args().length())) { + IonSpew(IonSpew_Abort, "too many actual args"); + ForbidCompilation(cx, script); + return Method_CantCompile; + } + + if (invoke.constructing() && invoke.args().thisv().isPrimitive()) { + RootedScript scriptRoot(cx, script); + RootedObject callee(cx, &invoke.args().callee()); + RootedObject obj(cx, CreateThisForFunction(cx, callee, invoke.useNewType())); + if (!obj || !ion::IsEnabled(cx)) // Note: OOM under CreateThis can disable TI. + return Method_Skipped; + invoke.args().setThis(ObjectValue(*obj)); + script = scriptRoot; + } + } else if (state.isGenerator()) { + IonSpew(IonSpew_Abort, "generator frame"); ForbidCompilation(cx, script); return Method_CantCompile; } // If --ion-eager is used, compile with Baseline first, so that we // can directly enter IonMonkey. if (js_IonOptions.eagerCompilation && !script->hasBaselineScript()) { - bool newType = isConstructing && fp.asStackFrame()->useNewType(); - MethodStatus status = CanEnterBaselineJIT(cx, script, fp.asStackFrame(), newType); + MethodStatus status = CanEnterBaselineMethod(cx, state); if (status != Method_Compiled) return status; } // Attempt compilation. Returns Method_Compiled if already compiled. RootedScript rscript(cx, script); - MethodStatus status = Compile(cx, rscript, fp, NULL, isConstructing, SequentialExecution); + bool constructing = state.isInvoke() && state.asInvoke()->constructing(); + MethodStatus status = Compile(cx, rscript, NULL, NULL, constructing, SequentialExecution); if (status != Method_Compiled) { if (status == Method_CantCompile) ForbidCompilation(cx, script); return status; } return Method_Compiled; } MethodStatus -ion::CompileFunctionForBaseline(JSContext *cx, HandleScript script, AbstractFramePtr fp, +ion::CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame, bool isConstructing) { JS_ASSERT(ion::IsEnabled(cx)); - JS_ASSERT(fp.fun()->nonLazyScript()->canIonCompile()); - JS_ASSERT(!fp.fun()->nonLazyScript()->isIonCompilingOffThread()); - JS_ASSERT(!fp.fun()->nonLazyScript()->hasIonScript()); - JS_ASSERT(fp.isFunctionFrame()); + JS_ASSERT(frame->fun()->nonLazyScript()->canIonCompile()); + JS_ASSERT(!frame->fun()->nonLazyScript()->isIonCompilingOffThread()); + JS_ASSERT(!frame->fun()->nonLazyScript()->hasIonScript()); + JS_ASSERT(frame->isFunctionFrame()); // Mark as forbidden if frame can't be handled. - if (!CheckFrame(fp)) { + if (!CheckFrame(frame)) { ForbidCompilation(cx, script); return Method_CantCompile; } // Attempt compilation. Returns Method_Compiled if already compiled. - MethodStatus status = Compile(cx, script, fp, NULL, isConstructing, SequentialExecution); + MethodStatus status = Compile(cx, script, frame, NULL, isConstructing, SequentialExecution); if (status != Method_Compiled) { if (status == Method_CantCompile) ForbidCompilation(cx, script); return status; } return Method_Compiled; } @@ -1746,18 +1752,17 @@ ion::CanEnterInParallel(JSContext *cx, H // condition differently treats it more like an error. if (!script->canParallelIonCompile()) return Method_Skipped; // Skip if the script is being compiled off thread. if (script->isParallelIonCompilingOffThread()) return Method_Skipped; - MethodStatus status = Compile(cx, script, AbstractFramePtr(), NULL, false, - ParallelExecution); + MethodStatus status = Compile(cx, script, NULL, NULL, false, ParallelExecution); if (status != Method_Compiled) { if (status == Method_CantCompile) ForbidCompilation(cx, script, ParallelExecution); return status; } // This can GC, so afterward, script->parallelIon is // not guaranteed to be valid. @@ -1803,106 +1808,134 @@ ion::CanEnterUsingFastInvoke(JSContext * if (!script->hasIonScript()) return Method_Skipped; return Method_Compiled; } static IonExecStatus -EnterIon(JSContext *cx, StackFrame *fp, void *jitcode) +EnterIon(JSContext *cx, EnterJitData &data) { JS_CHECK_RECURSION(cx, return IonExec_Aborted); JS_ASSERT(ion::IsEnabled(cx)); - JS_ASSERT(CheckFrame(fp)); - JS_ASSERT(!fp->script()->ionScript()->bailoutExpected()); + JS_ASSERT(!data.osrFrame); EnterIonCode enter = cx->compartment()->ionCompartment()->enterJIT(); - // maxArgc is the maximum of arguments between the number of actual - // arguments and the number of formal arguments. It accounts for |this|. - int maxArgc = 0; - Value *maxArgv = NULL; - unsigned numActualArgs = 0; - RootedValue thisv(cx); - - void *calleeToken; - if (fp->isFunctionFrame()) { - numActualArgs = fp->numActualArgs(); - maxArgc = Max(numActualArgs, fp->numFormalArgs()) + 1; // +1 = include |this| - maxArgv = fp->argv() - 1; // -1 = include |this| - calleeToken = CalleeToToken(&fp->callee()); - } else { - calleeToken = CalleeToToken(fp->script()); - thisv = fp->thisValue(); - maxArgc = 1; - maxArgv = thisv.address(); - } - // Caller must construct |this| before invoking the Ion function. - JS_ASSERT_IF(fp->isConstructing(), fp->functionThis().isObject()); - RootedValue result(cx, Int32Value(numActualArgs)); + JS_ASSERT_IF(data.constructing, data.maxArgv[0].isObject()); + + data.result.setInt32(data.numActualArgs); { AssertCompartmentUnchanged pcc(cx); IonContext ictx(cx, NULL); - JitActivation activation(cx, fp->isConstructing()); + JitActivation activation(cx, data.constructing); JSAutoResolveFlags rf(cx, RESOLVE_INFER); AutoFlushInhibitor afi(cx->compartment()->ionCompartment()); - fp->setRunningInJit(); - - // Single transition point from Interpreter to Ion. - enter(jitcode, maxArgc, maxArgv, fp, calleeToken, /* scopeChain = */ NULL, 0, - result.address()); - - fp->clearRunningInJit(); + // Single transition point from Interpreter to Baseline. + enter(data.jitcode, data.maxArgc, data.maxArgv, /* osrFrame = */NULL, data.calleeToken, + /* scopeChain = */ NULL, 0, data.result.address()); } - JS_ASSERT(fp == cx->fp()); JS_ASSERT(!cx->runtime()->hasIonReturnOverride()); - // The trampoline wrote the return value but did not set the HAS_RVAL flag. - fp->setReturnValue(result); - - // Ion callers wrap primitive constructor return. - if (!result.isMagic() && fp->isConstructing() && fp->returnValue().isPrimitive()) - fp->setReturnValue(ObjectValue(fp->constructorThis())); - - JS_ASSERT_IF(result.isMagic(), result.isMagic(JS_ION_ERROR)); - return result.isMagic() ? IonExec_Error : IonExec_Ok; + // Jit callers wrap primitive constructor return. + if (!data.result.isMagic() && data.constructing && data.result.isPrimitive()) + data.result = data.maxArgv[0]; + + // Release temporary buffer used for OSR into Ion. + cx->runtime()->getIonRuntime(cx)->freeOsrTempData(); + + JS_ASSERT_IF(data.result.isMagic(), data.result.isMagic(JS_ION_ERROR)); + return data.result.isMagic() ? IonExec_Error : IonExec_Ok; +} + +bool +ion::SetEnterJitData(JSContext *cx, EnterJitData &data, RunState &state, AutoValueVector &vals) +{ + data.osrFrame = NULL; + + if (state.isInvoke()) { + CallArgs &args = state.asInvoke()->args(); + unsigned numFormals = state.script()->function()->nargs; + data.constructing = state.asInvoke()->constructing(); + data.numActualArgs = args.length(); + data.maxArgc = Max(args.length(), numFormals) + 1; + data.scopeChain = NULL; + data.calleeToken = CalleeToToken(args.callee().toFunction()); + + if (data.numActualArgs >= numFormals) { + data.maxArgv = args.base() + 1; + } else { + // Pad missing arguments with |undefined|. + for (size_t i = 1; i < args.length() + 2; i++) { + if (!vals.append(args.base()[i])) + return false; + } + + while (vals.length() < numFormals + 1) { + if (!vals.append(UndefinedValue())) + return false; + } + + JS_ASSERT(vals.length() >= numFormals + 1); + data.maxArgv = vals.begin(); + } + } else { + data.constructing = false; + data.numActualArgs = 0; + data.maxArgc = 1; + data.maxArgv = state.asExecute()->addressOfThisv(); + data.scopeChain = state.asExecute()->scopeChain(); + + data.calleeToken = CalleeToToken(state.script()); + + if (state.script()->isForEval() && + !(state.asExecute()->type() & StackFrame::GLOBAL)) + { + ScriptFrameIter iter(cx); + if (iter.isFunctionFrame()) + data.calleeToken = CalleeToToken(iter.callee()); + } + } + + return true; } IonExecStatus -ion::Cannon(JSContext *cx, StackFrame *fp) +ion::Cannon(JSContext *cx, RunState &state) { - RootedScript script(cx, fp->script()); - IonScript *ion = script->ionScript(); - IonCode *code = ion->method(); - void *jitcode = code->raw(); + IonScript *ion = state.script()->ionScript(); + + EnterJitData data(cx); + data.jitcode = ion->method()->raw(); + + AutoValueVector vals(cx); + if (!SetEnterJitData(cx, data, state, vals)) + return IonExec_Error; #if JS_TRACE_LOGGING TraceLog(TraceLogging::defaultLogger(), TraceLogging::ION_CANNON_START, script); #endif - IonExecStatus status = EnterIon(cx, fp, jitcode); + IonExecStatus status = EnterIon(cx, data); #if JS_TRACE_LOGGING - if (status == IonExec_Bailout) { - TraceLog(TraceLogging::defaultLogger(), - TraceLogging::ION_CANNON_BAIL, - script); - } else { - TraceLog(TraceLogging::defaultLogger(), - TraceLogging::ION_CANNON_STOP, - script); - } + TraceLog(TraceLogging::defaultLogger(), + TraceLogging::ION_CANNON_STOP, + script); #endif + if (status == IonExec_Ok) + state.setReturnValue(data.result); + return status; } IonExecStatus ion::FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args) { JS_CHECK_RECURSION(cx, return IonExec_Error);
--- a/js/src/ion/Ion.h +++ b/js/src/ion/Ion.h @@ -269,19 +269,19 @@ bool InitializeIon(); IonContext *GetIonContext(); IonContext *MaybeGetIonContext(); bool SetIonContext(IonContext *ctx); bool CanIonCompileScript(JSContext *cx, HandleScript script, bool osr); MethodStatus CanEnterAtBranch(JSContext *cx, JSScript *script, - AbstractFramePtr fp, jsbytecode *pc, bool isConstructing); -MethodStatus CanEnter(JSContext *cx, HandleScript script, AbstractFramePtr fp, bool isConstructing); -MethodStatus CompileFunctionForBaseline(JSContext *cx, HandleScript script, AbstractFramePtr fp, + BaselineFrame *frame, jsbytecode *pc, bool isConstructing); +MethodStatus CanEnter(JSContext *cx, RunState &state); +MethodStatus CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame, bool isConstructing); MethodStatus CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs); MethodStatus CanEnterInParallel(JSContext *cx, HandleScript script); enum IonExecStatus { // The method call had to be aborted due to a stack limit check. This @@ -297,17 +297,21 @@ enum IonExecStatus }; static inline bool IsErrorStatus(IonExecStatus status) { return status == IonExec_Error || status == IonExec_Aborted; } -IonExecStatus Cannon(JSContext *cx, StackFrame *fp); +struct EnterJitData; + +bool SetEnterJitData(JSContext *cx, EnterJitData &data, RunState &state, AutoValueVector &vals); + +IonExecStatus Cannon(JSContext *cx, RunState &state); // Used to enter Ion from C++ natives like Array.map. Called from FastInvokeGuard. IonExecStatus FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args); // Walk the stack and invalidate active Ion frames for the invalid scripts. void Invalidate(types::TypeCompartment &types, FreeOp *fop, const Vector<types::RecompileInfo> &invalid, bool resetUses = true); void Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses = true);
--- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -29,23 +29,23 @@ #endif using namespace js; using namespace js::ion; using mozilla::DebugOnly; IonBuilder::IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph, - BaselineInspector *inspector, CompileInfo *info, AbstractFramePtr fp, + BaselineInspector *inspector, CompileInfo *info, BaselineFrame *baselineFrame, size_t inliningDepth, uint32_t loopDepth) : MIRGenerator(cx->compartment(), temp, graph, info), backgroundCodegen_(NULL), recompileInfo(cx->compartment()->types.compiledInfo), cx(cx), - fp(fp), + baselineFrame_(baselineFrame), abortReason_(AbortReason_Disable), loopDepth_(loopDepth), callerResumePoint_(NULL), callerBuilder_(NULL), inspector(inspector), inliningDepth_(inliningDepth), numLoopRestarts_(0), failedBoundsCheck_(info->script()->failedBoundsCheck), @@ -57,17 +57,17 @@ IonBuilder::IonBuilder(JSContext *cx, Te script_.init(info->script()); pc = info->startPC(); } void IonBuilder::clearForBackEnd() { cx = NULL; - fp = AbstractFramePtr(); + baselineFrame_ = NULL; } bool IonBuilder::abort(const char *message, ...) { // Don't call PCToLineNumber in release builds. #ifdef DEBUG va_list ap; @@ -3455,17 +3455,17 @@ IonBuilder::inlineScriptedCall(CallInfo this->info().executionMode()); if (!info) return false; MIRGraphExits saveExits; AutoAccumulateExits aae(graph(), saveExits); // Build the graph. - IonBuilder inlineBuilder(cx, &temp(), &graph(), &inspector, info, AbstractFramePtr(), + IonBuilder inlineBuilder(cx, &temp(), &graph(), &inspector, info, NULL, inliningDepth_ + 1, loopDepth_); if (!inlineBuilder.buildInline(this, outerResumePoint, callInfo)) { JS_ASSERT(calleeScript->hasAnalysis()); // Inlining the callee failed. Disable inlining the function if (inlineBuilder.abortReason_ == AbortReason_Disable) calleeScript->analysis()->setIonUninlineable(); @@ -5597,29 +5597,29 @@ IonBuilder::newPendingLoopHeader(MBasicB // Unbox the MOsrValue if it is known to be unboxable. for (uint32_t i = info().startArgSlot(); i < block->stackDepth(); i++) { MPhi *phi = block->getSlot(i)->toPhi(); bool haveValue = false; Value existingValue; if (info().fun() && i == info().thisSlot()) { haveValue = true; - existingValue = fp.thisValue(); + existingValue = baselineFrame_->thisValue(); } else { uint32_t arg = i - info().firstArgSlot(); uint32_t var = i - info().firstLocalSlot(); if (arg < info().nargs()) { if (!script()->formalIsAliased(arg)) { haveValue = true; - existingValue = fp.unaliasedFormal(arg); + existingValue = baselineFrame_->unaliasedFormal(arg); } } else if (var < info().nlocals()) { if (!script()->varIsAliased(var)) { haveValue = true; - existingValue = fp.unaliasedVar(var); + existingValue = baselineFrame_->unaliasedVar(var); } } } if (haveValue) { MIRType type = existingValue.isDouble() ? MIRType_Double : MIRTypeFromValueType(existingValue.extractNonDoubleType()); types::Type ntype = types::GetValueType(cx, existingValue); @@ -8143,17 +8143,17 @@ IonBuilder::jsop_this() if (script()->strict) { current->pushSlot(info().thisSlot()); return true; } types::StackTypeSet *types = types::TypeScript::ThisTypes(script()); if (types && (types->getKnownTypeTag() == JSVAL_TYPE_OBJECT || - (types->empty() && fp && fp.thisValue().isObject()))) + (types->empty() && baselineFrame_ && baselineFrame_->thisValue().isObject()))) { // This is safe, because if the entry type of |this| is an object, it // will necessarily be an object throughout the entire function. OSR // can introduce a phi, but this phi will be specialized. current->pushSlot(info().thisSlot()); return true; } @@ -8304,18 +8304,18 @@ IonBuilder::hasStaticScopeObject(ScopeCo environment = environment->enclosingScope(); } // Look for the call object on the current frame, if we are compiling the // outer script itself. Don't do this if we are at entry to the outer // script, as the call object we see will not be the real one --- after // entering the Ion code a different call object will be created. - if (script() == outerScript && fp && info().osrPc()) { - JSObject *scope = fp.scopeChain(); + if (script() == outerScript && baselineFrame_ && info().osrPc()) { + JSObject *scope = baselineFrame_->scopeChain(); if (scope->is<CallObject>() && scope->as<CallObject>().callee().nonLazyScript() == outerScript) { JS_ASSERT(scope->hasSingletonType()); pcall.set(scope); return true; } }
--- a/js/src/ion/IonBuilder.h +++ b/js/src/ion/IonBuilder.h @@ -193,17 +193,17 @@ class IonBuilder : public MIRGenerator static CFGState CondSwitch(jsbytecode *exitpc, jsbytecode *defaultTarget); static CFGState Label(jsbytecode *exitpc); }; static int CmpSuccessors(const void *a, const void *b); public: IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph, - BaselineInspector *inspector, CompileInfo *info, AbstractFramePtr fp, + BaselineInspector *inspector, CompileInfo *info, BaselineFrame *baselineFrame, size_t inliningDepth = 0, uint32_t loopDepth = 0); bool build(); bool buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoint, CallInfo &callInfo); private: bool traverseBytecode(); @@ -581,17 +581,17 @@ class IonBuilder : public MIRGenerator CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; } void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; } AbortReason abortReason() { return abortReason_; } private: JSContext *cx; - AbstractFramePtr fp; + BaselineFrame *baselineFrame_; AbortReason abortReason_; jsbytecode *pc; MBasicBlock *current; uint32_t loopDepth_; /* Information used for inline-call builders. */ MResumePoint *callerResumePoint_;
--- a/js/src/ion/IonCaches.cpp +++ b/js/src/ion/IonCaches.cpp @@ -931,17 +931,17 @@ GenerateCallGetter(JSContext *cx, IonScr Address(StackPointer, IonOOLNativeGetterExitFrameLayout::offsetOfResult()), JSReturnOperand); } else { Register argObjReg = argUintNReg; Register argIdReg = regSet.takeGeneral(); PropertyOp target = shape->getterOp(); JS_ASSERT(target); - // JSPropertyOp: JSBool fn(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) + // JSPropertyOp: JSBool fn(JSContext *cx, JSHandleObject obj, JSHandleId id, MutableHandleValue vp) // Push args on stack first so we can take pointers to make handles. masm.Push(UndefinedValue()); masm.movePtr(StackPointer, argVpReg); // push canonical jsid from shape instead of propertyname. RootedId propId(cx); if (!shape->getUserId(cx, &propId)) @@ -1841,17 +1841,17 @@ SetPropertyIC::attachSetterCall(JSContex Label success, exception; attacher.pushStubCodePointer(masm); StrictPropertyOp target = shape->setterOp(); JS_ASSERT(target); // JSStrictPropertyOp: JSBool fn(JSContext *cx, JSHandleObject obj, - // JSHandleId id, JSBool strict, JSMutableHandleValue vp); + // JSHandleId id, JSBool strict, MutableHandleValue vp); // Push args on stack first so we can take pointers to make handles. if (value().constant()) masm.Push(value().value()); else masm.Push(value().reg()); masm.movePtr(StackPointer, argVpReg);
--- a/js/src/ion/IonCompartment.h +++ b/js/src/ion/IonCompartment.h @@ -21,17 +21,40 @@ namespace ion { class FrameSizeClass; enum EnterJitType { EnterJitBaseline = 0, EnterJitOptimized = 1 }; -typedef void (*EnterIonCode)(void *code, int argc, Value *argv, StackFrame *fp, +struct EnterJitData +{ + explicit EnterJitData(JSContext *cx) + : scopeChain(cx), + result(cx) + {} + + uint8_t *jitcode; + StackFrame *osrFrame; + + void *calleeToken; + + Value *maxArgv; + unsigned maxArgc; + unsigned numActualArgs; + unsigned osrNumStackValues; + + RootedObject scopeChain; + RootedValue result; + + bool constructing; +}; + +typedef void (*EnterIonCode)(void *code, unsigned argc, Value *argv, StackFrame *fp, CalleeToken calleeToken, JSObject *scopeChain, size_t numStackValues, Value *vp); class IonBuilder; typedef Vector<IonBuilder*, 0, SystemAllocPolicy> OffThreadCompilationVector; // ICStubSpace is an abstraction for allocation policy and storage for stub data.
--- a/js/src/ion/MIR.cpp +++ b/js/src/ion/MIR.cpp @@ -950,17 +950,17 @@ void MUrsh::infer(BaselineInspector *inspector, jsbytecode *pc) { if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object)) { specialization_ = MIRType_None; setResultType(MIRType_Value); return; } - if (inspector->expectedResultType(pc) == MIRType_Double) { + if (inspector->hasSeenDoubleResult(pc)) { specialization_ = MIRType_Double; setResultType(MIRType_Double); return; } specialization_ = MIRType_Int32; setResultType(MIRType_Int32); } @@ -1304,17 +1304,17 @@ MBinaryArithInstruction::infer(BaselineI if (lhs == MIRType_Int32 && rhs == MIRType_Int32) setResultType(MIRType_Int32); else if (lhs == MIRType_Double || rhs == MIRType_Double) setResultType(MIRType_Double); else return inferFallback(inspector, pc); // If the operation has ever overflowed, use a double specialization. - if (inspector->expectedResultType(pc) == MIRType_Double) + if (inspector->hasSeenDoubleResult(pc)) setResultType(MIRType_Double); // If the operation will always overflow on its constant operands, use a // double specialization so that it can be constant folded later. if ((isMul() || isDiv()) && lhs == MIRType_Int32 && rhs == MIRType_Int32) { bool typeChange = false; EvaluateConstantOperands(this, &typeChange); if (typeChange)
--- a/js/src/ion/VMFunctions.cpp +++ b/js/src/ion/VMFunctions.cpp @@ -565,21 +565,16 @@ FilterArguments(JSContext *cx, JSString static const jschar arguments[] = {'a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's'}; return !StringHasPattern(chars, str->length(), arguments, mozilla::ArrayLength(arguments)); } #ifdef JSGC_GENERATIONAL void PostWriteBarrier(JSRuntime *rt, JSObject *obj) { -#ifdef JS_GC_ZEAL - /* The jitcode version of IsInsideNursery does not know about the verifier. */ - if (rt->gcVerifyPostData && rt->gcVerifierNursery.isInside(obj)) - return; -#endif JS_ASSERT(!IsInsideNursery(rt, obj)); rt->gcStoreBuffer.putWholeCell(obj); } #endif uint32_t GetIndexFromString(JSString *str) {
--- a/js/src/ion/arm/IonFrames-arm.h +++ b/js/src/ion/arm/IonFrames-arm.h @@ -345,17 +345,17 @@ class IonOOLPropertyOpExitFrameLayout IonExitFrameLayout exit_; // Object for JSHandleObject JSObject *obj_; // id for JSHandleId jsid id_; - // space for JSMutableHandleValue result + // space for MutableHandleValue result // use two uint32_t so compiler doesn't align. uint32_t vp0_; uint32_t vp1_; // pointer to root the stub's IonCode IonCode *stubCode_; public: @@ -393,17 +393,17 @@ class IonOOLProxyGetExitFrameLayout JSObject *proxy_; // Object for JSHandleObject JSObject *receiver_; // id for JSHandleId jsid id_; - // space for JSMutableHandleValue result + // space for MutableHandleValue result // use two uint32_t so compiler doesn't align. uint32_t vp0_; uint32_t vp1_; // pointer to root the stub's IonCode IonCode *stubCode_; public:
--- a/js/src/ion/shared/IonFrames-x86-shared.h +++ b/js/src/ion/shared/IonFrames-x86-shared.h @@ -309,17 +309,17 @@ class IonOOLPropertyOpExitFrameLayout IonExitFrameLayout exit_; // Object for JSHandleObject JSObject *obj_; // id for JSHandleId jsid id_; - // space for JSMutableHandleValue result + // space for MutableHandleValue result // use two uint32_t so compiler doesn't align. uint32_t vp0_; uint32_t vp1_; // pointer to root the stub's IonCode IonCode *stubCode_; public: @@ -357,17 +357,17 @@ class IonOOLProxyGetExitFrameLayout JSObject *proxy_; // Object for JSHandleObject JSObject *receiver_; // id for JSHandleId jsid id_; - // space for JSMutableHandleValue result + // space for MutableHandleValue result // use two uint32_t so compiler doesn't align. uint32_t vp0_; uint32_t vp1_; // pointer to root the stub's IonCode IonCode *stubCode_; public:
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/baseline/bug877589.js @@ -0,0 +1,7 @@ +function x() { + [1]; +} +Array.prototype.__proto__ = {}; +x(); +Array.prototype.__proto__ = null; +x();
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug-870034.js @@ -0,0 +1,12 @@ +// |jit-test| ion-eager +function f(b) { + var a = arguments; + if (b) + f(false); + else + g = { + apply:function(x,y) { "use asm"; function g() {} return g } + }; + g.apply(null, a); +} +f(true);
--- a/js/src/jsanalyze.cpp +++ b/js/src/jsanalyze.cpp @@ -409,22 +409,22 @@ ScriptAnalysis::analyzeBytecode(JSContex case JSOP_GETELEM: case JSOP_CALLELEM: numPropertyReads_++; break; case JSOP_THROW: case JSOP_EXCEPTION: case JSOP_DEBUGGER: - case JSOP_FUNCALL: isIonInlineable = false; break; /* Additional opcodes which can be both compiled both normally and inline. */ case JSOP_ARGUMENTS: + case JSOP_FUNCALL: case JSOP_FUNAPPLY: case JSOP_CALLEE: case JSOP_NOP: case JSOP_UNDEFINED: case JSOP_GOTO: case JSOP_DEFAULT: case JSOP_IFEQ: case JSOP_IFNE:
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -811,19 +811,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads gcSliceBudget(SliceBudget::Unlimited), gcIncrementalEnabled(true), gcGenerationalEnabled(true), gcManipulatingDeadZones(false), gcObjectsMarkedInDeadZones(0), gcPoke(false), heapState(Idle), #ifdef JSGC_GENERATIONAL -# ifdef JS_GC_ZEAL - gcVerifierNursery(), -# endif gcNursery(thisFromCtor()), gcStoreBuffer(thisFromCtor()), #endif #ifdef JS_GC_ZEAL gcZeal_(0), gcZealFrequency(0), gcNextScheduled(0), gcDeterministicOnly(false), @@ -3204,23 +3201,23 @@ JS_DefaultValue(JSContext *cx, JSObject if (!JSObject::defaultValue(cx, obj, hint, &value)) return false; *vp = value; return true; } JS_PUBLIC_API(JSBool) -JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp) +JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, MutableHandleValue vp) { return JS_TRUE; } JS_PUBLIC_API(JSBool) -JS_StrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp) +JS_StrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, MutableHandleValue vp) { return JS_TRUE; } JS_PUBLIC_API(JSBool) JS_DeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded) { *succeeded = true; @@ -3235,17 +3232,17 @@ JS_EnumerateStub(JSContext *cx, JSHandle JS_PUBLIC_API(JSBool) JS_ResolveStub(JSContext *cx, JSHandleObject obj, JSHandleId id) { return JS_TRUE; } JS_PUBLIC_API(JSBool) -JS_ConvertStub(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp) +JS_ConvertStub(JSContext *cx, JSHandleObject obj, JSType type, MutableHandleValue vp) { JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION); JS_ASSERT(obj); return DefaultValue(cx, obj, type, vp); } JS_PUBLIC_API(JSObject *) JS_InitClass(JSContext *cx, JSObject *objArg, JSObject *parent_protoArg, @@ -5960,17 +5957,17 @@ JS_PUBLIC_API(void) JS_TriggerOperationCallback(JSRuntime *rt) { rt->triggerOperationCallback(); } JS_PUBLIC_API(JSBool) JS_IsRunning(JSContext *cx) { - return cx->hasfp(); + return cx->currentlyRunning(); } JS_PUBLIC_API(JSBool) JS_SaveFrameChain(JSContext *cx) { AssertHeapIsIdleOrIterating(cx); CHECK_REQUEST(cx); return cx->saveFrameChain();
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -713,39 +713,35 @@ CallNonGenericMethod(JSContext *cx, IsAc /************************************************************************/ typedef JS::Handle<JSObject*> JSHandleObject; typedef JS::Handle<JSString*> JSHandleString; typedef JS::Handle<JS::Value> JSHandleValue; typedef JS::Handle<jsid> JSHandleId; -typedef JS::MutableHandle<JSFunction*> JSMutableHandleFunction; -typedef JS::MutableHandle<JSString*> JSMutableHandleString; -typedef JS::MutableHandle<JS::Value> JSMutableHandleValue; - /* JSClass operation signatures. */ /* * Add or get a property named by id in obj. Note the jsid id type -- id may * be a string (Unicode property identifier) or an int (element index). The * *vp out parameter, on success, is the new property value after the action. */ typedef JSBool -(* JSPropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); +(* JSPropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp); /* * Set a property named by id in obj, treating the assignment as strict * mode code if strict is true. Note the jsid id type -- id may be a string * (Unicode property identifier) or an int (element index). The *vp out * parameter, on success, is the new property value after the * set. */ typedef JSBool -(* JSStrictPropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp); +(* JSStrictPropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JS::MutableHandle<JS::Value> vp); /* * Delete a property named by id in obj. * * If an error occurred, return false as per normal JSAPI error practice. * * If no error occurred, but the deletion attempt wasn't allowed (perhaps * because the property was non-configurable), set *succeeded to false and @@ -789,17 +785,17 @@ typedef JSBool * call to this function when enum_op was JSENUMERATE_INIT or * JSENUMERATE_INIT_ALL. * * The return value is used to indicate success, with a value of JS_FALSE * indicating failure. */ typedef JSBool (* JSNewEnumerateOp)(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, - JSMutableHandleValue statep, JS::MutableHandleId idp); + JS::MutableHandle<JS::Value> statep, JS::MutableHandleId idp); /* * The old-style JSClass.enumerate op should define all lazy properties not * yet reflected in obj. */ typedef JSBool (* JSEnumerateOp)(JSContext *cx, JSHandleObject obj); @@ -834,17 +830,17 @@ typedef JSBool (* JSNewResolveOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags, JS::MutableHandleObject objp); /* * Convert obj to the given type, returning true with the resulting value in * *vp on success, and returning false on error or exception. */ typedef JSBool -(* JSConvertOp)(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp); +(* JSConvertOp)(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandle<JS::Value> vp); typedef struct JSFreeOp JSFreeOp; struct JSFreeOp { private: JSRuntime *runtime_; protected: @@ -877,25 +873,25 @@ struct JSStringFinalizer { /* * JSClass.checkAccess type: check whether obj[id] may be accessed per mode, * returning false on error/exception, true on success with obj[id]'s last-got * value in *vp, and its attributes in *attrsp. As for JSPropertyOp above, id * is either a string or an int jsval. */ typedef JSBool (* JSCheckAccessOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSAccessMode mode, - JSMutableHandleValue vp); + JS::MutableHandle<JS::Value> vp); /* * Check whether v is an instance of obj. Return false on error or exception, * true on success with JS_TRUE in *bp if v is an instance of obj, JS_FALSE in * *bp otherwise. */ typedef JSBool -(* JSHasInstanceOp)(JSContext *cx, JSHandleObject obj, JSMutableHandleValue vp, JSBool *bp); +(* JSHasInstanceOp)(JSContext *cx, JSHandleObject obj, JS::MutableHandle<JS::Value> vp, JSBool *bp); /* * Function type for trace operation of the class called to enumerate all * traceable things reachable from obj's private data structure. For each such * thing, a trace implementation must call one of the JS_Call*Tracer variants * on the thing. * * JSTraceOp implementation can assume that no other threads mutates object @@ -1025,27 +1021,27 @@ typedef struct JSErrorFormatString { int16_t exnType; } JSErrorFormatString; typedef const JSErrorFormatString * (* JSErrorCallback)(void *userRef, const char *locale, const unsigned errorNumber); typedef JSBool -(* JSLocaleToUpperCase)(JSContext *cx, JSHandleString src, JSMutableHandleValue rval); +(* JSLocaleToUpperCase)(JSContext *cx, JSHandleString src, JS::MutableHandle<JS::Value> rval); typedef JSBool -(* JSLocaleToLowerCase)(JSContext *cx, JSHandleString src, JSMutableHandleValue rval); +(* JSLocaleToLowerCase)(JSContext *cx, JSHandleString src, JS::MutableHandle<JS::Value> rval); typedef JSBool (* JSLocaleCompare)(JSContext *cx, JSHandleString src1, JSHandleString src2, - JSMutableHandleValue rval); + JS::MutableHandle<JS::Value> rval); typedef JSBool -(* JSLocaleToUnicode)(JSContext *cx, const char *src, JSMutableHandleValue rval); +(* JSLocaleToUnicode)(JSContext *cx, const char *src, JS::MutableHandle<JS::Value> rval); /* * Security protocol types. */ typedef void (* JSDestroyPrincipalsOp)(JSPrincipals *principals); @@ -1781,17 +1777,17 @@ IsPoisonedId(jsid iden) return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden)); return false; } } /* namespace JS */ namespace js { -template <> struct RootMethods<jsid> +template <> struct GCMethods<jsid> { static jsid initial() { return JSID_VOID; } static ThingRootKind kind() { return THING_ROOT_ID; } static bool poisoned(jsid id) { return JS::IsPoisonedId(id); } static bool needsPostBarrier(jsid id) { return false; } #ifdef JSGC_GENERATIONAL static void postBarrier(jsid *idp) {} static void relocate(jsid *idp) {} @@ -2859,17 +2855,17 @@ struct JSClass { * member initial value. The "original ... value" verbiage is there because * in ECMA-262, global properties naming class objects are read/write and * deleteable, for the most part. * * Implementing this efficiently requires that global objects have classes * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was * prevously allowed, but is now an ES5 violation and thus unsupported. */ -#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 26) +#define JSCLASS_GLOBAL_SLOT_COUNT (JSProto_LIMIT * 3 + 25) #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) #define JSCLASS_GLOBAL_FLAGS \ JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0) #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \ (((clasp)->flags & JSCLASS_IS_GLOBAL) \ && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT) @@ -2962,32 +2958,32 @@ JS_IdToValue(JSContext *cx, jsid id, jsv * the specified object, computing a primitive default value for the object. * The hint must be JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_VOID (no hint). On * success the resulting value is stored in *vp. */ extern JS_PUBLIC_API(JSBool) JS_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp); extern JS_PUBLIC_API(JSBool) -JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp); +JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp); extern JS_PUBLIC_API(JSBool) -JS_StrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp); +JS_StrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JS::MutableHandle<JS::Value> vp); extern JS_PUBLIC_API(JSBool) JS_DeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded); extern JS_PUBLIC_API(JSBool) JS_EnumerateStub(JSContext *cx, JSHandleObject obj); extern JS_PUBLIC_API(JSBool) JS_ResolveStub(JSContext *cx, JSHandleObject obj, JSHandleId id); extern JS_PUBLIC_API(JSBool) -JS_ConvertStub(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp); +JS_ConvertStub(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandle<JS::Value> vp); struct JSConstDoubleSpec { double dval; const char *name; uint8_t flags; uint8_t spare[3]; }; @@ -3338,17 +3334,17 @@ class PropertyDescriptorOperations void setSetterObject(JSObject *obj) { desc()->setter = reinterpret_cast<JSStrictPropertyOp>(obj); } }; } /* namespace JS */ namespace js { template <> -struct RootMethods<JSPropertyDescriptor> { +struct GCMethods<JSPropertyDescriptor> { static JSPropertyDescriptor initial() { return JSPropertyDescriptor(); } static ThingRootKind kind() { return THING_ROOT_PROPERTY_DESCRIPTOR; } static bool poisoned(const JSPropertyDescriptor &desc) { return (desc.obj && JS::IsPoisonedPtr(desc.obj)) || (desc.attrs & JSPROP_GETTER && desc.getter && JS::IsPoisonedPtr(desc.getter)) || (desc.attrs & JSPROP_SETTER && desc.setter && JS::IsPoisonedPtr(desc.setter)) || (desc.value.isGCThing() && JS::IsPoisonedPtr(desc.value.toGCThing())); }
--- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -166,18 +166,16 @@ js_InitBooleanClass(JSContext *cx, Handl RootedValue value(cx, ObjectValue(*valueOf)); if (!JSObject::defineProperty(cx, booleanProto, valueOfName, value, JS_PropertyStub, JS_StrictPropertyStub, 0)) { return NULL; } - global->setBooleanValueOf(valueOf); - if (!DefineConstructorAndPrototype(cx, global, JSProto_Boolean, ctor, booleanProto)) return NULL; return booleanProto; } JSString * js_BooleanToString(JSContext *cx, JSBool b) @@ -190,21 +188,21 @@ js::ToBooleanSlow(const Value &v) { if (v.isString()) return v.toString()->length() != 0; JS_ASSERT(v.isObject()); return !EmulatesUndefined(&v.toObject()); } +/* + * This slow path is only ever taken for Boolean objects from other + * compartments. The only caller of the fast path, JSON's PreprocessValue, + * makes sure of that. + */ bool -js::BooleanGetPrimitiveValueSlow(JSContext *cx, HandleObject obj, Value *vp) +js::BooleanGetPrimitiveValueSlow(HandleObject wrappedBool, JSContext *cx) { - InvokeArgsGuard ag; - if (!cx->stack.pushInvokeArgs(cx, 0, &ag)) - return false; - ag.setCallee(cx->compartment()->maybeGlobal()->booleanValueOf()); - ag.setThis(ObjectValue(*obj)); - if (!Invoke(cx, ag)) - return false; - *vp = ag.rval(); - return true; + JS_ASSERT(wrappedBool->isCrossCompartmentWrapper()); + JSObject *obj = Wrapper::wrappedObject(wrappedBool); + JS_ASSERT(obj); + return obj->asBoolean().unbox(); }
--- a/js/src/jsbool.h +++ b/js/src/jsbool.h @@ -16,13 +16,13 @@ extern JSObject * js_InitBooleanClass(JSContext *cx, js::HandleObject obj); extern JSString * js_BooleanToString(JSContext *cx, JSBool b); namespace js { inline bool -BooleanGetPrimitiveValue(JSContext *cx, HandleObject obj, Value *vp); +BooleanGetPrimitiveValue(HandleObject obj, JSContext *cx); } /* namespace js */ #endif /* jsbool_h___ */
--- a/js/src/jsboolinlines.h +++ b/js/src/jsboolinlines.h @@ -11,27 +11,26 @@ #include "mozilla/Likely.h" #include "js/RootingAPI.h" #include "vm/BooleanObject-inl.h" namespace js { -bool BooleanGetPrimitiveValueSlow(JSContext *, HandleObject, Value *); +bool +BooleanGetPrimitiveValueSlow(HandleObject, JSContext *); inline bool -BooleanGetPrimitiveValue(JSContext *cx, HandleObject obj, Value *vp) +BooleanGetPrimitiveValue(HandleObject obj, JSContext *cx) { - if (obj->isBoolean()) { - *vp = BooleanValue(obj->asBoolean().unbox()); - return true; - } + if (obj->isBoolean()) + return obj->asBoolean().unbox(); - return BooleanGetPrimitiveValueSlow(cx, obj, vp); + return BooleanGetPrimitiveValueSlow(obj, cx); } inline bool EmulatesUndefined(JSObject *obj) { JSObject *actual = MOZ_LIKELY(!obj->isWrapper()) ? obj : UncheckedUnwrap(obj); bool emulatesUndefined = actual->getClass()->emulatesUndefined(); MOZ_ASSERT_IF(emulatesUndefined, obj->type()->flags & types::OBJECT_FLAG_EMULATES_UNDEFINED);
--- a/js/src/jsclass.h +++ b/js/src/jsclass.h @@ -382,17 +382,17 @@ IsObjectWithClass(const Value &v, ESClas inline bool IsPoisonedSpecialId(js::SpecialId iden) { if (iden.isObject()) return IsPoisonedPtr(iden.toObject()); return false; } -template <> struct RootMethods<SpecialId> +template <> struct GCMethods<SpecialId> { static SpecialId initial() { return SpecialId(); } static ThingRootKind kind() { return THING_ROOT_ID; } static bool poisoned(SpecialId id) { return IsPoisonedSpecialId(id); } }; } /* namespace js */
--- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -343,16 +343,21 @@ js::DestroyContext(JSContext *cx, Destro JSRuntime *rt = cx->runtime(); JS_AbortIfWrongThread(rt); #ifdef JS_THREADSAFE if (cx->outstandingRequests != 0) MOZ_CRASH(); #endif +#if (defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)) && defined(DEBUG) + for (int i = 0; i < THING_ROOT_LIMIT; ++i) + JS_ASSERT(cx->thingGCRooters[i] == NULL); +#endif + if (mode != DCM_NEW_FAILED) { if (JSContextCallback cxCallback = rt->cxCallback) { /* * JSCONTEXT_DESTROY callback is not allowed to fail and must * return true. */ JS_ALWAYS_TRUE(cxCallback(cx, JSCONTEXT_DESTROY)); } @@ -1294,16 +1299,30 @@ JSContext::restoreFrameChain() if (Activation *act = mainThread().activation()) act->restoreFrameChain(); if (isExceptionPending()) wrapPendingException(); } +bool +JSContext::currentlyRunning() const +{ + for (ActivationIterator iter(runtime()); !iter.done(); ++iter) { + if (iter.activation()->cx() == this) { + if (iter.activation()->hasSavedFrameChain()) + return false; + return true; + } + } + + return false; +} + void JSRuntime::setGCMaxMallocBytes(size_t value) { /* * For compatibility treat any value that exceeds PTRDIFF_T_MAX to * mean that value. */ gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
--- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -19,17 +19,19 @@ #include "jsfriendapi.h" #include "jsprvtd.h" #include "jsatom.h" #include "jsclist.h" #include "jsgc.h" #include "ds/LifoAlloc.h" #include "frontend/ParseMaps.h" +#include "gc/Nursery.h" #include "gc/Statistics.h" +#include "gc/StoreBuffer.h" #include "js/HashTable.h" #include "js/Vector.h" #include "vm/DateTime.h" #include "vm/SPSProfiler.h" #include "vm/Stack.h" #include "vm/ThreadPool.h" #ifdef _MSC_VER @@ -516,22 +518,16 @@ class PerThreadData : public js::PerThre } js::AsmJSActivation *asmJSActivationStackFromOwnerThread() const { return asmJSActivationStack_; } js::Activation *activation() const { return activation_; } - bool currentlyRunningInInterpreter() const { - return activation_->isInterpreter(); - } - bool currentlyRunningInJit() const { - return activation_->isJit(); - } /* * When this flag is non-zero, any attempt to GC will be skipped. It is used * to suppress GC when reporting an OOM (see js_ReportOutOfMemory) and in * debugging facilities that cannot tolerate a GC and would rather OOM * immediately, such as utilities exposed to GDB. Setting this flag is * extremely dangerous and should only be used when in an OOM situation or * in non-exposed debugging facilities. @@ -1040,19 +1036,16 @@ struct JSRuntime : public JS::shadow::Ru volatile js::HeapState heapState; bool isHeapBusy() { return heapState != js::Idle; } bool isHeapMajorCollecting() { return heapState == js::MajorCollecting; } bool isHeapMinorCollecting() { return heapState == js::MinorCollecting; } bool isHeapCollecting() { return isHeapMajorCollecting() || isHeapMinorCollecting(); } #ifdef JSGC_GENERATIONAL -# ifdef JS_GC_ZEAL - js::gc::VerifierNursery gcVerifierNursery; -# endif js::Nursery gcNursery; js::gc::StoreBuffer gcStoreBuffer; #endif /* * These options control the zealousness of the GC. The fundamental values * are gcNextScheduled and gcDebugCompartmentGC. At every allocation, * gcNextScheduled is decremented. When it reaches zero, we do either a @@ -1522,17 +1515,17 @@ struct JSContext : js::ContextFriendFiel JSRuntime *runtime() const { return runtime_; } JSCompartment *compartment() const { return compartment_; } 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; } + js::PerThreadData &mainThread() const { return runtime()->mainThread; } private: /* See JSContext::findVersion. */ JSVersion defaultVersion; /* script compilation version */ JSVersion versionOverride; /* supercedes defaultVersion when valid */ bool hasVersionOverride; /* Exception state -- the exception member is a GC root by definition. */ @@ -1612,23 +1605,16 @@ struct JSContext : js::ContextFriendFiel js::ContextStack stack; /* * Current global. This is only safe to use within the scope of the * AutoCompartment from which it's called. */ inline js::Handle<js::GlobalObject*> global() const; - /* ContextStack convenience functions */ - inline bool hasfp() const { return stack.hasfp(); } - inline js::StackFrame* fp() const { return stack.fp(); } - inline js::StackFrame* maybefp() const { return stack.maybefp(); } - inline js::FrameRegs& regs() const { return stack.regs(); } - inline js::FrameRegs* maybeRegs() const { return stack.maybeRegs(); } - /* Wrap cx->exception for the current compartment. */ void wrapPendingException(); /* State for object and array toSource conversion. */ js::ObjectSet cycleDetectorSet; /* Per-context optional error reporter. */ JSErrorReporter errorReporter; @@ -1728,16 +1714,32 @@ struct JSContext : js::ContextFriendFiel js::Value iterValue; bool jitIsBroken; inline bool typeInferenceEnabled() const; void updateJITEnabled(); + /* Whether this context has JS frames on the stack. */ + bool currentlyRunning() const; + + bool currentlyRunningInInterpreter() const { + return mainThread().activation()->isInterpreter(); + } + bool currentlyRunningInJit() const { + return mainThread().activation()->isJit(); + } + js::StackFrame *interpreterFrame() const { + return mainThread().activation()->asInterpreter()->current(); + } + js::FrameRegs &interpreterRegs() const { + return mainThread().activation()->asInterpreter()->regs(); + } + #ifdef MOZ_TRACE_JSCALLS /* Function entry/exit debugging callback. */ JSFunctionCallback functionCallback; void doFunctionCallback(const JSFunction *fun, const JSScript *scr, int entering) const {
--- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -121,21 +121,21 @@ NewObjectCache::newObjectFromHit(JSConte } return NULL; } struct PreserveRegsGuard { PreserveRegsGuard(JSContext *cx, FrameRegs ®s) - : prevContextRegs(cx->maybeRegs()), cx(cx), regs_(regs) { + : prevContextRegs(cx->stack.maybeRegs()), cx(cx), regs_(regs) { cx->stack.repointRegs(®s_); } ~PreserveRegsGuard() { - JS_ASSERT(cx->maybeRegs() == ®s_); + JS_ASSERT(cx->stack.maybeRegs() == ®s_); *prevContextRegs = regs_; cx->stack.repointRegs(prevContextRegs); } FrameRegs *prevContextRegs; private: JSContext *cx; @@ -453,17 +453,17 @@ CallSetter(JSContext *cx, HandleObject o return CallJSPropertyOpSetter(cx, op, obj, nid, strict, vp); } } /* namespace js */ inline bool JSContext::canSetDefaultVersion() const { - return !stack.hasfp() && !hasVersionOverride; + return !currentlyRunning() && !hasVersionOverride; } inline void JSContext::overrideVersion(JSVersion newVersion) { JS_ASSERT(!canSetDefaultVersion()); versionOverride = newVersion; hasVersionOverride = true; @@ -513,17 +513,17 @@ JSContext::setDefaultCompartmentObject(J if (!hasEnteredCompartment()) { /* * If JSAPI callers want to JS_SetGlobalObject while code is running, * they must have entered a compartment (otherwise there will be no * final leaveCompartment call to set the context's compartment back to * defaultCompartmentObject->compartment()). */ - JS_ASSERT(!hasfp()); + JS_ASSERT(!currentlyRunning()); setCompartment(obj ? obj->compartment() : NULL); if (throwing) wrapPendingException(); } } inline void JSContext::setDefaultCompartmentObjectIfUnset(JSObject *obj)
--- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -71,17 +71,17 @@ IsTopFrameConstructing(JSContext *cx, Ab ScriptFrameIter iter(cx); JS_ASSERT(iter.abstractFramePtr() == frame); return iter.isConstructing(); } JSTrapStatus js::ScriptDebugPrologue(JSContext *cx, AbstractFramePtr frame) { - JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->fp()); + JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->interpreterFrame()); if (!frame.script()->selfHosted) { if (frame.isFramePushedByExecute()) { if (JSInterpreterHook hook = cx->runtime()->debugHooks.executeHook) frame.setHookData(hook(cx, Jsvalify(frame), IsTopFrameConstructing(cx, frame), true, 0, cx->runtime()->debugHooks.executeHookData)); } else { if (JSInterpreterHook hook = cx->runtime()->debugHooks.callHook) @@ -108,17 +108,18 @@ js::ScriptDebugPrologue(JSContext *cx, A JS_NOT_REACHED("bad Debugger::onEnterFrame JSTrapStatus value"); } return status; } bool js::ScriptDebugEpilogue(JSContext *cx, AbstractFramePtr frame, bool okArg) { - JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->fp()); + JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->interpreterFrame()); + JSBool ok = okArg; // We don't add hook data for self-hosted scripts, so we don't need to check for them, here. if (void *hookData = frame.maybeHookData()) { if (frame.isFramePushedByExecute()) { if (JSInterpreterHook hook = cx->runtime()->debugHooks.executeHook) hook(cx, Jsvalify(frame), IsTopFrameConstructing(cx, frame), false, &ok, hookData); } else {
--- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -399,24 +399,24 @@ JS_FRIEND_API(bool) js::IsOriginalScriptFunction(JSFunction *fun) { return fun->nonLazyScript()->function() == fun; } JS_FRIEND_API(JSScript *) js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx) { - if (!cx->hasfp()) + ScriptFrameIter iter(cx); + if (iter.done()) return NULL; - StackFrame *fp = cx->fp(); - if (!fp->isFunctionFrame()) + if (!iter.isFunctionFrame()) return NULL; - RootedFunction scriptedCaller(cx, fp->fun()); + RootedFunction scriptedCaller(cx, iter.callee()); RootedScript outermost(cx, scriptedCaller->nonLazyScript()); for (StaticScopeIter i(cx, scriptedCaller); !i.done(); i++) { if (i.type() == StaticScopeIter::FUNCTION) outermost = i.funScript(); } return outermost; }
--- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -120,17 +120,17 @@ JS_ObjectToOuterObject(JSContext *cx, JS extern JS_FRIEND_API(JSObject *) JS_CloneObject(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent); extern JS_FRIEND_API(JSString *) JS_BasicObjectToString(JSContext *cx, JSHandleObject obj); extern JS_FRIEND_API(JSBool) -js_GetterOnlyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp); +js_GetterOnlyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JS::MutableHandleValue vp); JS_FRIEND_API(void) js_ReportOverRecursed(JSContext *maybecx); #ifdef DEBUG /* * Routines to print out values during debugging. These are FRIEND_API to help @@ -887,16 +887,22 @@ NukeCrossCompartmentWrappers(JSContext* */ struct ExpandoAndGeneration { ExpandoAndGeneration() : expando(UndefinedValue()), generation(0) {} + void Unlink() + { + ++generation; + expando.setUndefined(); + } + JS::Heap<JS::Value> expando; uint32_t generation; }; typedef enum DOMProxyShadowsResult { ShadowCheckFailed, Shadows, DoesntShadow,
--- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -879,17 +879,17 @@ js_fun_apply(JSContext *cx, unsigned arg * function and read actuals out of the frame. */ /* Steps 4-6. */ #ifdef JS_ION // We do not want to use ScriptFrameIter to abstract here because this // is supposed to be a fast path as opposed to ScriptFrameIter which is // doing complex logic to settle on the next frame twice. - if (cx->mainThread().currentlyRunningInJit()) { + if (cx->currentlyRunningInJit()) { ion::JitActivationIterator activations(cx->runtime()); ion::IonFrameIterator frame(activations); if (frame.isNative()) { // Stop on the next Ion JS Frame. ++frame; if (frame.isOptimizedJS()) { ion::InlineFrameIterator iter(cx, &frame); @@ -924,17 +924,17 @@ js_fun_apply(JSContext *cx, unsigned arg JS_ASSERT(frame.isBaselineJS());