--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
#
# Modifying this file will now automatically clobber the buildbot machines \o/
#
# Are you updating CLOBBER because you think it's needed for your WebIDL
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
-Bug 1061335 - CLOBBER for Win32 compiler update.
+Bug 609976 - CLOBBER
--- a/b2g/chrome/content/content.css
+++ b/b2g/chrome/content/content.css
@@ -23,17 +23,16 @@ html xul|scrollbar[root="true"] {
}
html xul|scrollbar {
-moz-appearance: none !important;
background-color: transparent !important;
background-image: none !important;
border: 0px solid transparent !important;
pointer-events: none;
- opacity: 1;
}
xul|scrollbar[orient="vertical"] {
-moz-margin-start: -8px;
min-width: 8px;
max-width: 8px;
}
@@ -51,17 +50,16 @@ xul|scrollbar[orient="horizontal"] {
xul|scrollbar[orient="horizontal"] xul|thumb {
max-height: 6px !important;
min-height: 6px !important;
}
xul|scrollbar:not([active="true"]),
xul|scrollbar[disabled] {
opacity: 0;
- transition: opacity 1s ease;
}
xul|scrollbarbutton {
min-height: 8px !important;
min-width: 8px !important;
-moz-appearance: none !important;
visibility: hidden;
}
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was git://codeaurora.org/-->
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was git://codeaurora.org/-->
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was git://codeaurora.org/-->
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
"git_revision": "",
"remote": "",
"branch": ""
},
- "revision": "63436aa17e7fa3ad521fdeffdc22b81c36e5d69b",
+ "revision": "934b8c3014a3e20dd5d90ecf95f4b6b704dddb1e",
"repo_path": "/integration/gaia-central"
}
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
- <project name="gaia.git" path="gaia" remote="mozillaorg" revision="abef62c0623e5504a97b4fd411e879a67b285b52"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1daf2dadcd0d554c733661a4c0be1b82001e9da0"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -69,8 +69,18 @@ tabpanels {
* Optimization for tabs that are restored lazily. We can save a good amount of
* memory that to-be-restored tabs would otherwise consume simply by setting
* their browsers to 'display: none' as that will prevent them from having to
* create a presentation and the like.
*/
browser[pending] {
display: none;
}
+
+browser[pendingpaint] {
+ opacity: 0;
+}
+
+tabbrowser[pendingpaint] {
+ background-image: url(chrome://global/skin/spinner.png);
+ background-repeat: no-repeat;
+ background-position: center center;
+}
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -131,16 +131,20 @@
<field name="_previewMode">
false
</field>
<field name="_lastFindValue">
""
</field>
+ <field name="_contentWaitingCount">
+ 0
+ </field>
+
<property name="_numPinnedTabs" readonly="true">
<getter><![CDATA[
for (var i = 0; i < this.tabs.length; i++) {
if (!this.tabs[i].pinned)
break;
}
return i;
]]></getter>
@@ -3223,16 +3227,41 @@
</body>
</method>
<method name="getStripVisibility">
<body>
return this.tabContainer.visible;
</body>
</method>
+ <method name="_showBusySpinnerRemoteBrowser">
+ <parameter name="aBrowser"/>
+ <body><![CDATA[
+ aBrowser.setAttribute("pendingpaint", "true");
+ if (this._contentWaitingCount <= 0) {
+ // We are not currently spinning
+ this.setAttribute("pendingpaint", "true");
+ this._contentWaitingCount = 1;
+ } else {
+ this._contentWaitingCount++;
+ }
+ ]]></body>
+ </method>
+
+ <method name="_hideBusySpinnerRemoteBrowser">
+ <parameter name="aBrowser"/>
+ <body><![CDATA[
+ aBrowser.removeAttribute("pendingpaint");
+ this._contentWaitingCount--;
+ if (this._contentWaitingCount <= 0) {
+ this.removeAttribute("pendingpaint");
+ }
+ ]]></body>
+ </method>
+
<method name="_prepareForTabSwitch">
<parameter name="toTab"/>
<parameter name="fromTab"/>
<body><![CDATA[
const kTabSwitchTimeout = 300;
let toBrowser = this.getBrowserForTab(toTab);
let fromBrowser = fromTab ? this.getBrowserForTab(fromTab)
: null;
@@ -3261,26 +3290,29 @@
// We switched away or closed the browser before we timed
// out. We reject, which will cancel the tab switch.
aReject();
}
};
let timeoutPromise = new Promise((aResolve, aReject) => {
timeoutId = setTimeout(() => {
+ this._showBusySpinnerRemoteBrowser(toBrowser);
attemptTabSwitch(aResolve, aReject);
}, kTabSwitchTimeout);
});
let paintPromise = new Promise((aResolve, aReject) => {
- toBrowser.addEventListener("MozAfterRemotePaint", function onRemotePaint() {
+ let onRemotePaint = () => {
toBrowser.removeEventListener("MozAfterRemotePaint", onRemotePaint);
+ this._hideBusySpinnerRemoteBrowser(toBrowser);
clearTimeout(timeoutId);
attemptTabSwitch(aResolve, aReject);
- });
+ };
+ toBrowser.addEventListener("MozAfterRemotePaint", onRemotePaint);
toBrowser.QueryInterface(Ci.nsIFrameLoaderOwner)
.frameLoader
.requestNotifyAfterRemotePaint();
// We need to activate the docShell on the tab we're switching
// to - otherwise, we won't initiate a remote paint request and
// therefore we won't get the MozAfterRemotePaint event that we're
// waiting for.
// Note that this happens, as we require, even if the timeout in the
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -1371,17 +1371,17 @@ PlacesToolbar.prototype = {
return null;
let dropPoint = { ip: null, beforeIndex: null, folderElt: null };
let elt = aEvent.target;
if (elt._placesNode && elt != this._rootElt &&
elt.localName != "menupopup") {
let eltRect = elt.getBoundingClientRect();
let eltIndex = Array.indexOf(this._rootElt.childNodes, elt);
- if (PlacesUIUtils.nodeIsFolder(elt._placesNode) &&
+ if (PlacesUtils.nodeIsFolder(elt._placesNode) &&
!PlacesUIUtils.isContentsReadOnly(elt._placesNode)) {
// This is a folder.
// If we are in the middle of it, drop inside it.
// Otherwise, drop before it, with regards to RTL mode.
let threshold = eltRect.width * 0.25;
if (this.isRTL ? (aEvent.clientX > eltRect.right - threshold)
: (aEvent.clientX < eltRect.left + threshold)) {
// Drop before this folder.
--- a/browser/installer/Makefile.in
+++ b/browser/installer/Makefile.in
@@ -132,16 +132,19 @@ DEFINES += -DMOZ_REPLACE_MALLOC
endif
ifdef MOZ_JEMALLOC3
DEFINES += -DMOZ_JEMALLOC3
endif
DEFINES += -DMOZ_ICU_DBG_SUFFIX=$(MOZ_ICU_DBG_SUFFIX)
ifdef CLANG_CXX
DEFINES += -DCLANG_CXX
endif
+ifdef CLANG_CL
+DEFINES += -DCLANG_CL
+endif
libs::
$(MAKE) -C $(DEPTH)/browser/locales langpack
ifeq (WINNT,$(OS_ARCH))
PKGCOMP_FIND_OPTS =
else
PKGCOMP_FIND_OPTS = -L
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -916,9 +916,12 @@ bin/libfreebl_32int64_3.so
@BINPATH@/components/DataStoreImpl.js
@BINPATH@/components/dom_datastore.xpt
#ifdef MOZ_ASAN
#ifdef CLANG_CXX
@BINPATH@/llvm-symbolizer
#endif
+#ifdef CLANG_CL
+@BINPATH@/clang_rt.asan_dynamic-i386.dll
#endif
+#endif
--- a/browser/modules/PluginContent.jsm
+++ b/browser/modules/PluginContent.jsm
@@ -89,16 +89,19 @@ PluginContent.prototype = {
},
onPageHide: function (event) {
// Ignore events that aren't from the main document.
if (!this.content || event.target != this.content.document) {
return;
}
+ if (Services.telemetry.canSend) {
+ this._finishRecordingFlashPluginTelemetry();
+ }
this.clearPluginDataCache();
},
getPluginUI: function (plugin, anonid) {
return plugin.ownerDocument.
getAnonymousElementByAttribute(plugin, "anonid", anonid);
},
@@ -373,16 +376,21 @@ PluginContent.prototype = {
shouldShowNotification = true;
break;
case "PluginInstantiated":
shouldShowNotification = true;
break;
}
+ if (Services.telemetry.canSend && this._getPluginInfo(plugin).mimetype ===
+ "application/x-shockwave-flash") {
+ this._recordFlashPluginTelemetry(eventType, plugin);
+ }
+
// Show the in-content UI if it's not too big. The crashed plugin handler already did this.
if (eventType != "PluginCrashed") {
let overlay = this.getPluginUI(plugin, "main");
if (overlay != null) {
this.setVisibility(plugin, overlay,
this.shouldShowOverlay(plugin, overlay));
let resizeListener = (event) => {
this.setVisibility(plugin, overlay,
@@ -402,16 +410,52 @@ PluginContent.prototype = {
}, true);
}
if (shouldShowNotification) {
this._showClickToPlayNotification(plugin, false);
}
},
+ _recordFlashPluginTelemetry: function (eventType, plugin) {
+ if (!this.flashPluginStats) {
+ this.flashPluginStats = {
+ instancesCount: 0,
+ plugins: new WeakSet()
+ };
+ }
+
+ if (!this.flashPluginStats.plugins.has(plugin)) {
+ // Reporting plugin instance and its dimensions only once.
+ this.flashPluginStats.plugins.add(plugin);
+
+ this.flashPluginStats.instancesCount++;
+
+ let pluginRect = plugin.getBoundingClientRect();
+ Services.telemetry.getHistogramById('FLASH_PLUGIN_WIDTH')
+ .add(pluginRect.width);
+ Services.telemetry.getHistogramById('FLASH_PLUGIN_HEIGHT')
+ .add(pluginRect.height);
+ Services.telemetry.getHistogramById('FLASH_PLUGIN_AREA')
+ .add(pluginRect.width * pluginRect.height);
+
+ let state = this._getPluginInfo(plugin).fallbackType;
+ Services.telemetry.getHistogramById('FLASH_PLUGIN_STATES')
+ .add(state);
+ }
+ },
+
+ _finishRecordingFlashPluginTelemetry: function () {
+ if (this.flashPluginStats) {
+ Services.telemetry.getHistogramById('FLASH_PLUGIN_INSTANCES_ON_PAGE')
+ .add(this.flashPluginStats.instancesCount);
+ delete this.flashPluginStats;
+ }
+ },
+
isKnownPlugin: function (objLoadingContent) {
return (objLoadingContent.getContentTypeForMIMEType(objLoadingContent.actualType) ==
Ci.nsIObjectLoadingContent.TYPE_PLUGIN);
},
canActivatePlugin: function (objLoadingContent) {
// if this isn't a known plugin, we can't activate it
// (this also guards pluginHost.getPermissionStringForType against
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -61,16 +61,23 @@ LLDBINIT_OBJDIR := .lldbinit.in
LLDBINIT_OBJDIR_PATH = $(DEPTH)
LLDBINIT_OBJDIR_FLAGS += -Dtopsrcdir=$(abspath $(topsrcdir))
PP_TARGETS += LLDBINIT_OBJDIR
LLDBINIT_FINAL_TARGET_FILES := $(DEPTH)/.lldbinit
LLDBINIT_FINAL_TARGET_DEST = $(FINAL_TARGET)
INSTALL_TARGETS += LLDBINIT_FINAL_TARGET
+ifeq (1_1,$(MOZ_ASAN)_$(CLANG_CL))
+# Install the clang-cl runtime library for ASAN next to the binaries we produce.
+CLANG_RT_ASAN_FILES := $(MOZ_CLANG_RT_ASAN_LIB_PATH)
+CLANG_RT_ASAN_DEST = $(FINAL_TARGET)
+INSTALL_TARGETS += CLANG_RT_ASAN
+endif
+
include $(topsrcdir)/config/rules.mk
TARGET_DEPTH = ..
include $(srcdir)/automation-build.mk
ifdef MOZ_APP_BASENAME
$(FINAL_TARGET)/application.ini: $(APP_INI_DEPS)
--- a/configure.in
+++ b/configure.in
@@ -501,16 +501,21 @@ case "$target" in
AC_SUBST(MSVS_VERSION)
AC_SUBST(MSVC_C_RUNTIME_DLL)
AC_SUBST(MSVC_CXX_RUNTIME_DLL)
# Disable SEH on clang-cl because it doesn't implement them yet.
if test -z "$CLANG_CL"; then
AC_DEFINE(HAVE_SEH_EXCEPTIONS)
else
+ # Build on clang-cl with MSVC 2013 with fallback emulation.
+ CFLAGS="$CFLAGS -fmsc-version=1800 -fallback"
+ CXXFLAGS="$CXXFLAGS -fmsc-version=1800 -fallback"
+ # Send our CFLAGS to NSS too
+ MOZ_CFLAGS_NSS=1
AC_DEFINE_UNQUOTED(GTEST_HAS_SEH, 0)
fi
if test -n "$WIN32_REDIST_DIR"; then
if test ! -d "$WIN32_REDIST_DIR"; then
AC_MSG_ERROR([Invalid Win32 Redist directory: ${WIN32_REDIST_DIR}])
fi
WIN32_REDIST_DIR=`cd "$WIN32_REDIST_DIR" && pwd`
@@ -1255,16 +1260,26 @@ dnl ====================================
dnl = Use Address Sanitizer
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(address-sanitizer,
[ --enable-address-sanitizer Enable Address Sanitizer (default=no)],
MOZ_ASAN=1,
MOZ_ASAN= )
if test -n "$MOZ_ASAN"; then
MOZ_LLVM_HACKS=1
+ if test -n "$CLANG_CL"; then
+ # Look for clang_rt.asan_dynamic-i386.dll
+ MOZ_CLANG_RT_ASAN_LIB=clang_rt.asan_dynamic-i386.dll
+ # We use MOZ_PATH_PROG in order to get a Windows style path.
+ MOZ_PATH_PROG(MOZ_CLANG_RT_ASAN_LIB_PATH, $MOZ_CLANG_RT_ASAN_LIB)
+ if test -z "$MOZ_CLANG_RT_ASAN_LIB_PATH"; then
+ AC_MSG_ERROR([Couldn't find $MOZ_CLANG_RT_ASAN_LIB. It should be available in the same location as clang-cl.])
+ fi
+ AC_SUBST(MOZ_CLANG_RT_ASAN_LIB_PATH)
+ fi
AC_DEFINE(MOZ_ASAN)
MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
fi
AC_SUBST(MOZ_ASAN)
dnl ========================================================
dnl = Use Memory Sanitizer
dnl ========================================================
@@ -3791,21 +3806,16 @@ fi
AC_SUBST(MOZ_NATIVE_HUNSPELL)
dnl ========================================================
dnl system libffi Support
dnl ========================================================
MOZ_CONFIG_FFI()
-# split JS out by default to avoid VS2005 PGO crash (bug 591836).
-if test "$OS_ARCH" = "WINNT"; then
- JS_SHARED_LIBRARY=1
-fi
-
MOZ_ARG_ENABLE_BOOL(shared-js,
[ --enable-shared-js
Create a shared JavaScript library.],
JS_SHARED_LIBRARY=1,
JS_SHARED_LIBRARY=)
dnl ========================================================
dnl Java SDK support
@@ -7948,18 +7958,17 @@ fi
dnl ========================================================
dnl =
dnl = Static Build Options
dnl =
dnl ========================================================
MOZ_ARG_HEADER(Static build options)
-if test "$OS_ARCH" = "WINNT"; then
- GKMEDIAS_SHARED_LIBRARY=1
+if test -n "$GKMEDIAS_SHARED_LIBRARY"; then
AC_DEFINE(GKMEDIAS_SHARED_LIBRARY)
fi
AC_SUBST(GKMEDIAS_SHARED_LIBRARY)
if test -z "$MOZ_NATIVE_ZLIB"; then
if test -n "$JS_SHARED_LIBRARY" -o "$GKMEDIAS_SHARED_LIBRARY"; then
ZLIB_IN_MOZGLUE=1
AC_DEFINE(ZLIB_IN_MOZGLUE)
--- a/content/base/public/FragmentOrElement.h
+++ b/content/base/public/FragmentOrElement.h
@@ -407,17 +407,17 @@ public:
/**
* XBL binding installed on the lement.
*/
nsCOMPtr<nsIContent> mXBLInsertionParent;
/**
* Web components custom element data.
*/
- nsAutoPtr<CustomElementData> mCustomElementData;
+ nsRefPtr<CustomElementData> mCustomElementData;
};
protected:
void GetMarkup(bool aIncludeSelf, nsAString& aMarkup);
void SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError);
// Override from nsINode
virtual nsINode::nsSlots* CreateSlots() MOZ_OVERRIDE;
--- a/content/base/src/DOMParser.cpp
+++ b/content/base/src/DOMParser.cpp
@@ -233,28 +233,25 @@ DOMParser::ParseFromStream(nsIInputStrea
nsCOMPtr<nsIDOMDocument> domDocument;
rv = SetUpDocument(svg ? DocumentFlavorSVG : DocumentFlavorLegacyGuess,
getter_AddRefs(domDocument));
NS_ENSURE_SUCCESS(rv, rv);
// Create a fake channel
nsCOMPtr<nsIChannel> parserChannel;
- NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI, nullptr,
- nsDependentCString(contentType), nullptr);
+ NS_NewInputStreamChannel(getter_AddRefs(parserChannel),
+ mDocumentURI,
+ nullptr, // aStream
+ mOriginalPrincipal,
+ nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
+ nsIContentPolicy::TYPE_OTHER,
+ nsDependentCString(contentType));
NS_ENSURE_STATE(parserChannel);
- // More principal-faking here
- nsCOMPtr<nsILoadInfo> loadInfo =
- new LoadInfo(mOriginalPrincipal,
- nullptr,
- nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
- nsIContentPolicy::TYPE_OTHER);
- parserChannel->SetLoadInfo(loadInfo);
-
if (charset) {
parserChannel->SetContentCharset(nsDependentCString(charset));
}
// Tell the document to start loading
nsCOMPtr<nsIStreamListener> listener;
// Have to pass false for reset here, else the reset will remove
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -188,16 +188,18 @@ public:
// These attributes are used for error reporting.
nsCString mScriptFile;
uint32_t mScriptLine;
uint64_t mInnerWindowID;
WorkerPrivate* mWorkerPrivate;
nsAutoPtr<WorkerFeature> mWorkerFeature;
+ nsWeakPtr mWeakLoadGroup;
+
private:
~WebSocketImpl()
{
// If we threw during Init we never called disconnect
if (!mDisconnected) {
Disconnect();
}
}
@@ -523,18 +525,17 @@ WebSocketImpl::Disconnect()
return NS_OK;
}
void
WebSocketImpl::DisconnectInternal()
{
AssertIsOnMainThread();
- nsCOMPtr<nsILoadGroup> loadGroup;
- GetLoadGroup(getter_AddRefs(loadGroup));
+ nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakLoadGroup);
if (loadGroup) {
loadGroup->RemoveRequest(this, nullptr, NS_OK);
}
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
@@ -1385,16 +1386,18 @@ WebSocketImpl::InitializeConnection()
// provide the http stack the loadgroup info too
nsCOMPtr<nsILoadGroup> loadGroup;
rv = GetLoadGroup(getter_AddRefs(loadGroup));
if (loadGroup) {
rv = wsChannel->SetLoadGroup(loadGroup);
NS_ENSURE_SUCCESS(rv, rv);
rv = loadGroup->AddRequest(this, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
+
+ mWeakLoadGroup = do_GetWeakReference(loadGroup);
}
// manually adding loadinfo to the channel since it
// was not set during channel creation.
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mOriginDocument);
nsCOMPtr<nsILoadInfo> loadInfo =
new LoadInfo(mPrincipal,
doc,
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -5839,22 +5839,17 @@ nsDocument::ProcessBaseElementQueue()
}
// static
void
nsDocument::ProcessTopElementQueue(bool aIsBaseQueue)
{
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
- if (sProcessingStack.isNothing()) {
- // If XPCOM shutdown has reset the processing stack, don't do anything.
- return;
- }
-
- nsTArray<CustomElementData*>& stack = *sProcessingStack;
+ nsTArray<nsRefPtr<CustomElementData>>& stack = *sProcessingStack;
uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr);
if (aIsBaseQueue && firstQueue != 0) {
return;
}
for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) {
// Callback queue may have already been processed in an earlier
@@ -5881,17 +5876,17 @@ bool
nsDocument::RegisterEnabled()
{
static bool sPrefValue =
Preferences::GetBool("dom.webcomponents.enabled", false);
return sPrefValue;
}
// static
-Maybe<nsTArray<mozilla::dom::CustomElementData*>>
+Maybe<nsTArray<nsRefPtr<mozilla::dom::CustomElementData>>>
nsDocument::sProcessingStack;
// static
bool
nsDocument::sProcessingBaseElementQueue;
void
nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -320,16 +320,18 @@ private:
// callback queue.
CustomElementData* mOwnerData;
};
// Each custom element has an associated callback queue and an element is
// being created flag.
struct CustomElementData
{
+ NS_INLINE_DECL_REFCOUNTING(CustomElementData)
+
explicit CustomElementData(nsIAtom* aType);
// Objects in this array are transient and empty after each microtask
// checkpoint.
nsTArray<nsAutoPtr<CustomElementCallback>> mCallbackQueue;
// Custom element type, for <button is="x-button"> or <x-button>
// this would be x-button.
nsCOMPtr<nsIAtom> mType;
// The callback that is next to be processed upon calling RunCallbackQueue.
@@ -341,16 +343,19 @@ struct CustomElementData
bool mCreatedCallbackInvoked;
// The microtask level associated with the callbacks in the callback queue,
// it is used to determine if a new queue needs to be pushed onto the
// processing stack.
int32_t mAssociatedMicroTask;
// Empties the callback queue.
void RunCallbackQueue();
+
+private:
+ virtual ~CustomElementData() {}
};
// The required information for a custom element as defined in:
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html
struct CustomElementDefinition
{
CustomElementDefinition(JSObject* aPrototype,
nsIAtom* aType,
@@ -1515,17 +1520,17 @@ protected:
private:
// Array representing the processing stack in the custom elements
// specification. The processing stack is conceptually a stack of
// element queues. Each queue is represented by a sequence of
// CustomElementData in this array, separated by nullptr that
// represent the boundaries of the items in the stack. The first
// queue in the stack is the base element queue.
- static mozilla::Maybe<nsTArray<mozilla::dom::CustomElementData*>> sProcessingStack;
+ static mozilla::Maybe<nsTArray<nsRefPtr<mozilla::dom::CustomElementData>>> sProcessingStack;
// Flag to prevent re-entrance into base element queue as described in the
// custom elements speicification.
static bool sProcessingBaseElementQueue;
static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
public:
--- a/content/base/src/nsHostObjectProtocolHandler.cpp
+++ b/content/base/src/nsHostObjectProtocolHandler.cpp
@@ -514,17 +514,21 @@ nsHostObjectProtocolHandler::NewChannel(
FileImpl* blob = static_cast<FileImpl*>(blobImpl.get());
nsCOMPtr<nsIInputStream> stream;
nsresult rv = blob->GetInternalStream(getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannel> channel;
rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
uri,
- stream);
+ stream,
+ info->mPrincipal,
+ nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
+ nsIContentPolicy::TYPE_OTHER);
+
NS_ENSURE_SUCCESS(rv, rv);
nsString type;
blob->GetType(type);
if (blob->IsFile()) {
nsString filename;
blob->GetName(filename);
@@ -532,22 +536,16 @@ nsHostObjectProtocolHandler::NewChannel(
}
ErrorResult error;
uint64_t size = blob->GetSize(error);
if (NS_WARN_IF(error.Failed())) {
return error.ErrorCode();
}
- nsCOMPtr<nsILoadInfo> loadInfo =
- new mozilla::LoadInfo(info->mPrincipal,
- nullptr,
- nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
- nsIContentPolicy::TYPE_OTHER);
- channel->SetLoadInfo(loadInfo);
channel->SetOriginalURI(uri);
channel->SetContentType(NS_ConvertUTF16toUTF8(type));
channel->SetContentLength(size);
channel.forget(result);
return NS_OK;
}
--- a/content/base/test/chrome/cpows_child.js
+++ b/content/base/test/chrome/cpows_child.js
@@ -7,16 +7,19 @@ var done_count = 0;
var is_remote;
(function start() {
[is_remote] = sendSyncMessage("cpows:is_remote");
parent_test();
error_reporting_test();
dom_test();
xray_test();
+ if (typeof Symbol === "function") {
+ symbol_test();
+ }
compartment_test();
regexp_test();
sync_test();
async_test();
rpc_test();
nested_sync_test();
// The sync-ness of this call is important, because otherwise
// we tear down the child's document while we are
@@ -114,25 +117,23 @@ function xray_test()
sendSyncMessage("cpows:xray_test", {}, {element: element});
}
function symbol_test()
{
let iterator = Symbol.iterator;
let named = Symbol.for("cpow-test");
- // let unique = Symbol();
let object = {
[iterator]: iterator,
[named]: named,
- // [unique]: unique,
- // "unique": unique
};
- sendSyncMessage("cpows:symbol_test", {}, object);
+ let test = ['a'];
+ sendSyncMessage("cpows:symbol_test", {}, {object: object, test: test});
}
// Parent->Child references should go X->parent.privilegedJunkScope->child.privilegedJunkScope->Y
// Child->Parent references should go X->child.privilegedJunkScope->parent.unprivilegedJunkScope->Y
function compartment_test()
{
// This test primarily checks various compartment invariants for CPOWs, and
// doesn't make sense to run in-process.
--- a/content/base/test/chrome/cpows_parent.xul
+++ b/content/base/test/chrome/cpows_parent.xul
@@ -201,20 +201,26 @@
}
function recvXrayTest(message) {
let element = message.objects.element;
is(element.foo, undefined, "DOM element does not expose content properties");
}
function recvSymbolTest(message) {
- let object = message.objects;
+ let object = message.objects.object;
is(object[Symbol.iterator], Symbol.iterator, "Should use Symbol.iterator");
is(Symbol.keyFor(object[Symbol.for("cpow-test")]), "cpow-test", "Symbols aren't registered correctly");
- // is(object.unique, object[object.unique], "Unique symbols as ids and values don't seem to work");
+ let symbols = Object.getOwnPropertySymbols(object);
+ is(symbols.length, 2, "Object should have two symbol keys");
+ let test = undefined;
+ for (let x of message.objects.test) {
+ test = x;
+ }
+ is(test, "a", "for .. of iteration should work");
}
let systemGlobal = this;
function recvCompartmentTest(message) {
let getUnprivilegedObject = message.objects.getUnprivilegedObject;
let testParentObject = message.objects.testParentObject;
// Make sure that parent->child CPOWs live in the parent's privileged junk scope.
@@ -302,17 +308,19 @@
mm.addMessageListener("cpows:reenter_sync", recvReenterSyncMessage);
mm.addMessageListener("cpows:done", recvDoneMessage);
mm.addMessageListener("cpows:fail", recvFailMessage);
mm.addMessageListener("cpows:parent_test", recvParentTest);
mm.addMessageListener("cpows:error_reporting_test", recvErrorReportingTest);
mm.addMessageListener("cpows:dom_test", recvDomTest);
mm.addMessageListener("cpows:dom_test_after_gc", recvDomTestAfterGC);
mm.addMessageListener("cpows:xray_test", recvXrayTest);
- mm.addMessageListener("cpows:symbol_test", recvSymbolTest);
+ if (typeof Symbol === "function") {
+ mm.addMessageListener("cpows:symbol_test", recvSymbolTest);
+ }
mm.addMessageListener("cpows:compartment_test", recvCompartmentTest);
mm.addMessageListener("cpows:regexp_test", recvRegExpTest);
mm.addMessageListener("cpows:lifetime_test_1", recvLifetimeTest1);
mm.addMessageListener("cpows:lifetime_test_2", recvLifetimeTest2);
mm.loadFrameScript("chrome://mochitests/content/chrome/content/base/test/chrome/cpows_child.js", true);
}
function start() {
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1650,22 +1650,35 @@ nsDocShell::LoadStream(nsIInputStream *a
// Get the appropriate LoadType from nsIDocShellLoadInfo type
loadType = ConvertDocShellLoadInfoToLoadType(lt);
}
NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
mLoadType = loadType;
+ nsCOMPtr<nsISupports> owner;
+ aLoadInfo->GetOwner(getter_AddRefs(owner));
+ nsCOMPtr<nsIPrincipal> requestingPrincipal = do_QueryInterface(owner);
+ if (!requestingPrincipal) {
+ requestingPrincipal = nsContentUtils::GetSystemPrincipal();
+ }
+
// build up a channel for this stream.
nsCOMPtr<nsIChannel> channel;
- NS_ENSURE_SUCCESS(NS_NewInputStreamChannel
- (getter_AddRefs(channel), uri, aStream,
- aContentType, aContentCharset),
- NS_ERROR_FAILURE);
+ nsresult rv =
+ NS_NewInputStreamChannel(getter_AddRefs(channel),
+ uri,
+ aStream,
+ requestingPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
+ aContentType,
+ aContentCharset);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsCOMPtr<nsIURILoader>
uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader, false),
NS_ERROR_FAILURE);
return NS_OK;
@@ -10261,35 +10274,38 @@ nsDocShell::DoURILoad(nsIURI * aURI,
if (isViewSource) {
nsViewSourceHandler *vsh = nsViewSourceHandler::GetInstance();
NS_ENSURE_TRUE(vsh,NS_ERROR_FAILURE);
rv = vsh->NewSrcdocChannel(aURI, aSrcdoc, aBaseURI,
getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsILoadInfo> loadInfo =
+ new LoadInfo(requestingPrincipal,
+ requestingNode,
+ securityFlags,
+ aContentPolicyType);
+ channel->SetLoadInfo(loadInfo);
}
else {
- rv = NS_NewInputStreamChannel(getter_AddRefs(channel),aURI,
- aSrcdoc,
- NS_LITERAL_CSTRING("text/html"),
- true);
+ rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
+ aURI,
+ aSrcdoc,
+ NS_LITERAL_CSTRING("text/html"),
+ requestingNode,
+ requestingPrincipal,
+ securityFlags,
+ aContentPolicyType,
+ true);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel);
MOZ_ASSERT(isc);
isc->SetBaseURI(aBaseURI);
}
- // NS_NewInputStreamChannel does not yet attach the loadInfo in nsNetutil.h,
- // hence we have to manually attach the loadInfo for that channel.
- nsCOMPtr<nsILoadInfo> loadInfo =
- new LoadInfo(requestingPrincipal,
- requestingNode,
- securityFlags,
- aContentPolicyType);
- channel->SetLoadInfo(loadInfo);
}
nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
do_QueryInterface(channel);
if (appCacheChannel) {
// Any document load should not inherit application cache.
appCacheChannel->SetInheritApplicationCache(false);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -594,30 +594,17 @@ class nsOuterWindowProxy : public js::Wr
{
public:
MOZ_CONSTEXPR nsOuterWindowProxy() : js::Wrapper(0) { }
virtual bool finalizeInBackground(JS::Value priv) const MOZ_OVERRIDE {
return false;
}
- virtual const char *className(JSContext *cx,
- JS::Handle<JSObject*> wrapper) const MOZ_OVERRIDE;
- virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
-
- // Fundamental traps
- virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
- const MOZ_OVERRIDE;
- virtual bool preventExtensions(JSContext *cx,
- JS::Handle<JSObject*> proxy) const MOZ_OVERRIDE;
- virtual bool getPropertyDescriptor(JSContext* cx,
- JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id,
- JS::MutableHandle<JSPropertyDescriptor> desc)
- const MOZ_OVERRIDE;
+ // Standard internal methods
virtual bool getOwnPropertyDescriptor(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc)
const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
@@ -626,47 +613,61 @@ public:
virtual bool ownPropertyKeys(JSContext *cx,
JS::Handle<JSObject*> proxy,
JS::AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::AutoIdVector &props) const MOZ_OVERRIDE;
-
- virtual bool watch(JSContext *cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const MOZ_OVERRIDE;
- virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id) const MOZ_OVERRIDE;
- virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE {
- return false;
- }
- virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
- return false;
- }
-
- // Derived traps
+ virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
+ const MOZ_OVERRIDE;
+ virtual bool preventExtensions(JSContext *cx,
+ JS::Handle<JSObject*> proxy) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, bool *bp) const MOZ_OVERRIDE;
- virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id,
JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id,
bool strict,
JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
- virtual bool keys(JSContext *cx, JS::Handle<JSObject*> proxy,
- JS::AutoIdVector &props) const MOZ_OVERRIDE;
+
+ // SpiderMonkey extensions
+ virtual bool getPropertyDescriptor(JSContext* cx,
+ JS::Handle<JSObject*> proxy,
+ JS::Handle<jsid> id,
+ JS::MutableHandle<JSPropertyDescriptor> desc)
+ const MOZ_OVERRIDE;
+ virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
+ JS::Handle<jsid> id, bool *bp) const MOZ_OVERRIDE;
+ virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
+ JS::AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
unsigned flags,
JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
+ virtual const char *className(JSContext *cx,
+ JS::Handle<JSObject*> wrapper) const MOZ_OVERRIDE;
+
+ virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
+
+ virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE {
+ return false;
+ }
+ virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
+ return false;
+ }
+
+ virtual bool watch(JSContext *cx, JS::Handle<JSObject*> proxy,
+ JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const MOZ_OVERRIDE;
+ virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
+ JS::Handle<jsid> id) const MOZ_OVERRIDE;
static void ObjectMoved(JSObject *obj, const JSObject *old);
static const nsOuterWindowProxy singleton;
protected:
static nsGlobalWindow* GetWindow(JSObject *proxy)
{
@@ -925,22 +926,22 @@ nsOuterWindowProxy::set(JSContext *cx, J
}
return true;
}
return js::Wrapper::set(cx, proxy, receiver, id, strict, vp);
}
bool
-nsOuterWindowProxy::keys(JSContext *cx, JS::Handle<JSObject*> proxy,
- JS::AutoIdVector &props) const
+nsOuterWindowProxy::getOwnEnumerablePropertyKeys(JSContext *cx, JS::Handle<JSObject*> proxy,
+ JS::AutoIdVector &props) const
{
// BaseProxyHandler::keys seems to do what we want here: call
// ownPropertyKeys and then filter out the non-enumerable properties.
- return js::BaseProxyHandler::keys(cx, proxy, props);
+ return js::BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
}
bool
nsOuterWindowProxy::iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
unsigned flags, JS::MutableHandle<JS::Value> vp) const
{
// BaseProxyHandler::iterate seems to do what we want here: fall
// back on the property names returned from keys() and enumerate().
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -77,14 +77,15 @@ skip-if = (buildapp == 'b2g' && toolkit
[test_url_empty_port.html]
[test_url_malformedHost.html]
[test_urlExceptions.html]
[test_urlSearchParams.html]
[test_urlSearchParams_utf8.html]
[test_urlutils_stringify.html]
[test_window_constructor.html]
[test_window_cross_origin_props.html]
+[test_window_define_symbol.html]
[test_window_enumeration.html]
[test_window_extensible.html]
[test_window_indexing.html]
[test_window_named_frame_enumeration.html]
[test_writable-replaceable.html]
[test_navigatorPrefOverride.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_window_define_symbol.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1082672
+-->
+<head>
+ <meta charset="UTF-8">
+ <title>Test for Bug 1082672 part 2</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1082672">Mozilla Bug 1082672</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+var sym = Symbol("ponies");
+Object.defineProperty(window, sym, {configurable: true, value: 3});
+is(window[sym], 3);
+</script>
+</pre>
+</body>
+</html>
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1401,18 +1401,21 @@ XrayAttributeOrMethodKeys(JSContext* cx,
unsigned flags, JS::AutoIdVector& props)
{
for (; list->specs; ++list) {
if (list->isEnabled(cx, obj)) {
// Set i to be the index into our full list of ids/specs that we're
// looking at now.
size_t i = list->specs - specList;
for ( ; ids[i] != JSID_VOID; ++i) {
+ // Skip non-enumerable properties and symbol-keyed properties unless
+ // they are specially requested via flags.
if (((flags & JSITER_HIDDEN) ||
(specList[i].flags & JSPROP_ENUMERATE)) &&
+ ((flags & JSITER_SYMBOLS) || !JSID_IS_SYMBOL(ids[i])) &&
!props.append(ids[i])) {
return false;
}
}
}
}
return true;
}
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1680,17 +1680,17 @@ InitIds(JSContext* cx, const Prefable<Sp
{
MOZ_ASSERT(prefableSpecs);
MOZ_ASSERT(prefableSpecs->specs);
do {
// We ignore whether the set of ids is enabled and just intern all the IDs,
// because this is only done once per application runtime.
Spec* spec = prefableSpecs->specs;
do {
- if (!InternJSString(cx, *ids, spec->name)) {
+ if (!JS::PropertySpecNameToPermanentId(cx, spec->name, ids)) {
return false;
}
} while (++ids, (++spec)->name);
// We ran out of ids for that pref. Put a JSID_VOID in on the id
// corresponding to the list terminator for the pref.
*ids = JSID_VOID;
++ids;
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -272,17 +272,17 @@ DOMProxyHandler::delete_(JSContext* cx,
bool
BaseDOMProxyHandler::enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
AutoIdVector& props) const
{
JS::Rooted<JSObject*> proto(cx);
if (!JS_GetPrototype(cx, proxy, &proto)) {
return false;
}
- return keys(cx, proxy, props) &&
+ return getOwnEnumerablePropertyKeys(cx, proxy, props) &&
(!proto || js::GetPropertyKeys(cx, proto, 0, &props));
}
bool
BaseDOMProxyHandler::watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::Handle<JSObject*> callable) const
{
return js::WatchGuts(cx, proxy, id, callable);
@@ -294,23 +294,23 @@ BaseDOMProxyHandler::unwatch(JSContext*
return js::UnwatchGuts(cx, proxy, id);
}
bool
BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::AutoIdVector& props) const
{
- return ownPropNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN, props);
+ return ownPropNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
}
bool
-BaseDOMProxyHandler::keys(JSContext* cx,
- JS::Handle<JSObject*> proxy,
- JS::AutoIdVector& props) const
+BaseDOMProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx,
+ JS::Handle<JSObject*> proxy,
+ JS::AutoIdVector& props) const
{
return ownPropNames(cx, proxy, JSITER_OWNONLY, props);
}
bool
DOMProxyHandler::has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) const
{
if (!hasOwn(cx, proxy, id, bp)) {
@@ -340,17 +340,18 @@ DOMProxyHandler::has(JSContext* cx, JS::
}
int32_t
IdToInt32(JSContext* cx, JS::Handle<jsid> id)
{
JS::Rooted<JS::Value> idval(cx);
double array_index;
int32_t i;
- if (!::JS_IdToValue(cx, id, &idval) ||
+ if (JSID_IS_SYMBOL(id) ||
+ !::JS_IdToValue(cx, id, &idval) ||
!JS::ToNumber(cx, idval, &array_index) ||
!::JS_DoubleIsInt32(array_index, &i)) {
return -1;
}
return i;
}
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -45,44 +45,48 @@ template<typename T> struct Prefable;
class BaseDOMProxyHandler : public js::BaseProxyHandler
{
public:
explicit MOZ_CONSTEXPR BaseDOMProxyHandler(const void* aProxyFamily, bool aHasPrototype = false)
: js::BaseProxyHandler(aProxyFamily, aHasPrototype)
{}
- // Implementations of traps that can be implemented in terms of
- // fundamental traps.
+ // Implementations of methods that can be implemented in terms of
+ // other lower-level methods.
+ bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
+ JS::Handle<jsid> id,
+ JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
+ JS::AutoIdVector &props) const MOZ_OVERRIDE;
bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::AutoIdVector& props) const MOZ_OVERRIDE;
+
bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
- bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id,
- JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+
+
+ // We override getOwnEnumerablePropertyKeys() and implement it directly
+ // instead of using the default implementation, which would call
+ // ownPropertyKeys and then filter out the non-enumerable ones. This avoids
+ // unnecessary work during enumeration.
+ virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
+ JS::AutoIdVector &props) const MOZ_OVERRIDE;
bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::Handle<JSObject*> callable) const MOZ_OVERRIDE;
bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id) const MOZ_OVERRIDE;
- virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
- JS::AutoIdVector &props) const MOZ_OVERRIDE;
- // We override keys() and implement it directly instead of using the
- // default implementation, which would getOwnPropertyNames and then
- // filter out the non-enumerable ones. This avoids doing
- // unnecessary work during enumeration.
- virtual bool keys(JSContext* cx, JS::Handle<JSObject*> proxy,
- JS::AutoIdVector &props) const MOZ_OVERRIDE;
protected:
// Hook for subclasses to implement shared ownPropertyKeys()/keys()
// functionality. The "flags" argument is either JSITER_OWNONLY (for keys())
- // or JSITER_OWNONLY | JSITER_HIDDEN (for ownPropertyKeys()).
+ // or JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS (for
+ // ownPropertyKeys()).
virtual bool ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy,
unsigned flags,
JS::AutoIdVector& props) const = 0;
// Hook for subclasses to allow set() to ignore named props while other things
// that look at property descriptors see them. This is intentionally not
// named getOwnPropertyDescriptor to avoid subclasses that override it hiding
// our public getOwnPropertyDescriptor.
@@ -95,35 +99,35 @@ protected:
class DOMProxyHandler : public BaseDOMProxyHandler
{
public:
MOZ_CONSTEXPR DOMProxyHandler()
: BaseDOMProxyHandler(&family)
{}
- bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy) const MOZ_OVERRIDE;
bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE
{
bool unused;
return defineProperty(cx, proxy, id, desc, &unused);
}
virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined)
const;
+ bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
+ JS::Handle<jsid> id, bool* bp) const MOZ_OVERRIDE;
+ bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
+ const MOZ_OVERRIDE;
+ bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy) const MOZ_OVERRIDE;
+ bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
+ bool* bp) const MOZ_OVERRIDE;
bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
JS::Handle<jsid> id, bool strict, JS::MutableHandle<JS::Value> vp)
const MOZ_OVERRIDE;
- bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id, bool* bp) const MOZ_OVERRIDE;
- bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
- bool* bp) const MOZ_OVERRIDE;
- bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
- const MOZ_OVERRIDE;
/*
* If assigning to proxy[id] hits a named setter with OverrideBuiltins or
* an indexed setter, call it and set *done to true on success. Otherwise, set
* *done to false.
*/
virtual bool setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<JS::Value> vp, bool *done) const;
--- a/dom/bluetooth2/bluedroid/b2g_bdroid_buildcfg.h
+++ b/dom/bluetooth2/bluedroid/b2g_bdroid_buildcfg.h
@@ -34,9 +34,14 @@
#define BTIF_HF_FEATURES ( BTA_AG_FEAT_3WAY | \
BTA_AG_FEAT_REJECT | \
BTA_AG_FEAT_ECS | \
BTA_AG_FEAT_EXTERR)
/* CHLD values */
#define BTA_AG_CHLD_VAL "(0,1,2,3)"
+/* BLE Feature */
+#define BTA_GATT_INCLUDED TRUE
+#define BLE_INCLUDED TRUE
+#define SMP_INCLUDED TRUE
+
#endif /* B2G_BDROID_BUILDCFG_H */
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -61,17 +61,21 @@ public:
// -------------------------------------------------------------------------
// Texture objects - WebGL2ContextTextures.cpp
void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height,
GLsizei depth);
-
+ void TexImage3D(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type,
+ const Nullable<dom::ArrayBufferView> &pixels,
+ ErrorResult& rv);
void TexSubImage3D(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const Nullable<dom::ArrayBufferView>& pixels,
ErrorResult& rv);
void TexSubImage3D(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLenum format, GLenum type, dom::ImageData* data,
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -200,16 +200,129 @@ WebGL2Context::TexStorage3D(GLenum targe
WebGLImageDataStatus::UninitializedImageData);
w = std::max(1, w >> 1);
h = std::max(1, h >> 1);
d = std::max(1, d >> 1);
}
}
void
+WebGL2Context::TexImage3D(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type,
+ const Nullable<dom::ArrayBufferView> &pixels,
+ ErrorResult& rv)
+{
+ if (IsContextLost())
+ return;
+
+ void* data;
+ size_t dataLength;
+ js::Scalar::Type jsArrayType;
+ if (pixels.IsNull()) {
+ data = nullptr;
+ dataLength = 0;
+ jsArrayType = js::Scalar::TypeMax;
+ } else {
+ const ArrayBufferView& view = pixels.Value();
+ view.ComputeLengthAndData();
+
+ data = view.Data();
+ dataLength = view.Length();
+ jsArrayType = JS_GetArrayBufferViewType(view.Obj());
+ }
+
+ const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
+ const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;
+
+ if (!ValidateTexImageTarget(target, func, dims))
+ return;
+
+ TexImageTarget texImageTarget = target;
+
+ if (!ValidateTexImage(texImageTarget, level, internalformat,
+ 0, 0, 0,
+ width, height, depth,
+ border, format, type, func, dims))
+ {
+ return;
+ }
+
+ if (!ValidateTexInputData(type, jsArrayType, func, dims))
+ return;
+
+ TexInternalFormat effectiveInternalFormat =
+ EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
+
+ if (effectiveInternalFormat == LOCAL_GL_NONE) {
+ return ErrorInvalidOperation("texImage3D: bad combination of internalformat and type");
+ }
+
+ // we need to find the exact sized format of the source data. Slightly abusing
+ // EffectiveInternalFormatFromInternalFormatAndType for that purpose. Really, an unsized source format
+ // is the same thing as an unsized internalformat.
+ TexInternalFormat effectiveSourceFormat =
+ EffectiveInternalFormatFromInternalFormatAndType(format, type);
+ MOZ_ASSERT(effectiveSourceFormat != LOCAL_GL_NONE); // should have validated format/type combo earlier
+ const size_t srcbitsPerTexel = GetBitsPerTexel(effectiveSourceFormat);
+ MOZ_ASSERT((srcbitsPerTexel % 8) == 0); // should not have compressed formats here.
+ size_t srcTexelSize = srcbitsPerTexel / 8;
+
+ CheckedUint32 checked_neededByteLength =
+ GetImageSize(height, width, depth, srcTexelSize, mPixelStoreUnpackAlignment);
+
+ if (!checked_neededByteLength.isValid())
+ return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
+
+ uint32_t bytesNeeded = checked_neededByteLength.value();
+
+ if (dataLength && dataLength < bytesNeeded)
+ return ErrorInvalidOperation("texImage3D: not enough data for operation (need %d, have %d)",
+ bytesNeeded, dataLength);
+
+ WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
+
+ if (!tex)
+ return ErrorInvalidOperation("texImage3D: no texture is bound to this target");
+
+ if (tex->IsImmutable()) {
+ return ErrorInvalidOperation(
+ "texImage3D: disallowed because the texture "
+ "bound to this target has already been made immutable by texStorage3D");
+ }
+
+ GLenum driverType = LOCAL_GL_NONE;
+ GLenum driverInternalFormat = LOCAL_GL_NONE;
+ GLenum driverFormat = LOCAL_GL_NONE;
+ DriverFormatsFromEffectiveInternalFormat(gl,
+ effectiveInternalFormat,
+ &driverInternalFormat,
+ &driverFormat,
+ &driverType);
+
+ MakeContextCurrent();
+ GetAndFlushUnderlyingGLErrors();
+ gl->fTexImage3D(texImageTarget.get(), level,
+ driverInternalFormat,
+ width, height, depth,
+ 0, driverFormat, driverType,
+ data);
+ GLenum error = GetAndFlushUnderlyingGLErrors();
+ if (error) {
+ return GenerateWarning("texImage3D generated error %s", ErrorName(error));
+ }
+
+ tex->SetImageInfo(texImageTarget, level,
+ width, height, depth,
+ effectiveInternalFormat,
+ data ? WebGLImageDataStatus::InitializedImageData
+ : WebGLImageDataStatus::UninitializedImageData);
+}
+
+void
WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const Nullable<dom::ArrayBufferView>& pixels,
ErrorResult& rv)
{
if (IsContextLost())
return;
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -917,17 +917,21 @@ WebGLContext::GenerateMipmap(GLenum rawT
WebGLTexture *tex = activeBoundTextureForTarget(target);
if (!tex)
return ErrorInvalidOperation("generateMipmap: No texture is bound to this target.");
const TexImageTarget imageTarget = (target == LOCAL_GL_TEXTURE_2D)
? LOCAL_GL_TEXTURE_2D
: LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
- if (!tex->HasImageInfoAt(imageTarget, tex->GetBaseMipmapLevel()))
+ if (!tex->IsMipmapRangeValid())
+ {
+ return ErrorInvalidOperation("generateMipmap: Texture does not have a valid mipmap range.");
+ }
+ if (!tex->HasImageInfoAt(imageTarget, tex->EffectiveBaseMipmapLevel()))
{
return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
}
if (!IsWebGL2() && !tex->IsFirstImagePowerOfTwo())
return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
TexInternalFormat internalformat = tex->ImageInfoAt(imageTarget, 0).EffectiveInternalFormat();
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -862,16 +862,17 @@ InfoFrom(WebGLTexImageFunc func, WebGLTe
case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
case WebGLTexImageFunc::CompTexImage: return "compressedTexImage2D";
case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
default:
MOZ_CRASH();
}
case WebGLTexDimensions::Tex3D:
switch (func) {
+ case WebGLTexImageFunc::TexImage: return "texImage3D";
case WebGLTexImageFunc::TexSubImage: return "texSubImage3D";
case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage3D";
case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage3D";
default:
MOZ_CRASH();
}
default:
MOZ_CRASH();
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -9,16 +9,17 @@
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/Scoped.h"
#include "ScopedGLHelpers.h"
#include "WebGLContext.h"
#include "WebGLContextUtils.h"
#include "WebGLTexelConversions.h"
#include <algorithm>
+#include "mozilla/MathAlgorithms.h"
using namespace mozilla;
JSObject*
WebGLTexture::WrapObject(JSContext *cx) {
return dom::WebGLTextureBinding::Wrap(cx, this);
}
@@ -59,62 +60,75 @@ WebGLTexture::ImageInfo::MemoryUsage() c
}
size_t
WebGLTexture::MemoryUsage() const {
if (IsDeleted())
return 0;
size_t result = 0;
for(size_t face = 0; face < mFacesCount; face++) {
- for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
- result += ImageInfoAtFace(face, level).MemoryUsage();
- }
+ for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
+ result += ImageInfoAtFace(face, level).MemoryUsage();
+ }
return result;
}
+static inline size_t
+MipmapLevelsForSize(const WebGLTexture::ImageInfo &info)
+{
+ GLsizei size = std::max(std::max(info.Width(), info.Height()), info.Depth());
+
+ // Find floor(log2(size)). (ES 3.0.4, 3.8 - Mipmapping).
+ return mozilla::FloorLog2(size);
+}
+
bool
WebGLTexture::DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const
{
+ // We could not have generated a mipmap if the base image wasn't defined.
if (mHaveGeneratedMipmap)
return true;
- if (GetMaxMipmapLevel() < GetBaseMipmapLevel())
+ if (!IsMipmapRangeValid())
return false;
// We want a copy here so we can modify it temporarily.
- ImageInfo expected = ImageInfoAt(texImageTarget, GetBaseMipmapLevel());
+ ImageInfo expected = ImageInfoAt(texImageTarget, EffectiveBaseMipmapLevel());
+ if (!expected.IsPositive())
+ return false;
- // checks if custom level>0 images are all defined up to the highest level defined
- // and have the expected dimensions
- for (size_t level = GetBaseMipmapLevel(); level <= GetMaxMipmapLevel(); ++level) {
+ // If Level{max} is > mMaxLevelWithCustomImages, then check if we are
+ // missing any image levels.
+ if (mMaxMipmapLevel > mMaxLevelWithCustomImages) {
+ if (MipmapLevelsForSize(expected) > mMaxLevelWithCustomImages)
+ return false;
+ }
+
+ // Checks if custom images are all defined up to the highest level and
+ // have the expected dimensions.
+ for (size_t level = EffectiveBaseMipmapLevel(); level <= EffectiveMaxMipmapLevel(); ++level) {
const ImageInfo& actual = ImageInfoAt(texImageTarget, level);
if (actual != expected)
return false;
- // Check the raw value here, not the clamped one, since we don't want
- // to terminate early if there aren't enough levels defined.
- if (level == mMaxMipmapLevel)
- return true;
-
expected.mWidth = std::max(1, expected.mWidth / 2);
expected.mHeight = std::max(1, expected.mHeight / 2);
expected.mDepth = std::max(1, expected.mDepth / 2);
// if the current level has size 1x1, we can stop here: the spec doesn't seem to forbid the existence
// of extra useless levels.
if (actual.mWidth == 1 &&
actual.mHeight == 1 &&
actual.mDepth == 1)
{
return true;
}
}
- // if we're here, we've exhausted all levels without finding a 1x1 image
- return false;
+ return true;
}
void
WebGLTexture::Bind(TexTarget aTexTarget) {
// this function should only be called by bindTexture().
// it assumes that the GL context is already current.
bool firstTimeThisTextureIsBound = !HasEverBeenBound();
@@ -172,35 +186,29 @@ WebGLTexture::SetGeneratedMipmap() {
mHaveGeneratedMipmap = true;
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
}
void
WebGLTexture::SetCustomMipmap() {
if (mHaveGeneratedMipmap) {
- // if we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
- // we need to compute now all the mipmap image info.
+ if (!IsMipmapRangeValid())
+ return;
- // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info,
- // and are power-of-two.
- ImageInfo imageInfo = ImageInfoAtFace(0, GetBaseMipmapLevel());
+ // If we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
+ // we now need to compute all the mipmap image info.
+ ImageInfo imageInfo = ImageInfoAtFace(0, EffectiveBaseMipmapLevel());
NS_ASSERTION(mContext->IsWebGL2() || imageInfo.IsPowerOfTwo(),
"this texture is NPOT, so how could GenerateMipmap() ever accept it?");
- GLsizei size = std::max(std::max(imageInfo.mWidth, imageInfo.mHeight), imageInfo.mDepth);
+ size_t maxLevel = MipmapLevelsForSize(imageInfo);
+ EnsureMaxLevelWithCustomImagesAtLeast(EffectiveBaseMipmapLevel() + maxLevel);
- // Find floor(log2(size)). (ES 3.0.4, 3.8 - Mipmapping).
- size_t maxLevel = 0;
- for (GLsizei n = size; n > 1; n >>= 1)
- ++maxLevel;
-
- EnsureMaxLevelWithCustomImagesAtLeast(maxLevel);
-
- for (size_t level = GetBaseMipmapLevel() + 1; level <= GetMaxMipmapLevel(); ++level) {
+ for (size_t level = EffectiveBaseMipmapLevel() + 1; level <= EffectiveMaxMipmapLevel(); ++level) {
imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1);
imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1);
imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1);
for(size_t face = 0; face < mFacesCount; ++face)
ImageInfoAtFace(face, level) = imageInfo;
}
}
mHaveGeneratedMipmap = false;
@@ -214,21 +222,16 @@ WebGLTexture::AreAllLevel0ImageInfosEqua
}
return true;
}
bool
WebGLTexture::IsMipmapComplete() const {
MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_2D ||
mTarget == LOCAL_GL_TEXTURE_3D);
-
- if (!ImageInfoAtFace(0, GetBaseMipmapLevel()).IsPositive())
- return false;
- if (mHaveGeneratedMipmap)
- return true;
return DoesMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D);
}
bool
WebGLTexture::IsCubeComplete() const {
MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_CUBE_MAP);
const ImageInfo &first = ImageInfoAt(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
@@ -244,27 +247,42 @@ WebGLTexture::IsMipmapCubeComplete() con
for (int i = 0; i < 6; i++) {
const TexImageTarget face = TexImageTargetForTargetAndFace(LOCAL_GL_TEXTURE_CUBE_MAP, i);
if (!DoesMipmapHaveAllLevelsConsistentlyDefined(face))
return false;
}
return true;
}
+bool
+WebGLTexture::IsMipmapRangeValid() const
+{
+ // In ES3, if a texture is immutable, the mipmap levels are clamped.
+ if (IsImmutable())
+ return true;
+ if (mBaseMipmapLevel > std::min(mMaxLevelWithCustomImages, mMaxMipmapLevel))
+ return false;
+ return true;
+}
+
WebGLTextureFakeBlackStatus
WebGLTexture::ResolvedFakeBlackStatus() {
if (MOZ_LIKELY(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown)) {
return mFakeBlackStatus;
}
// Determine if the texture needs to be faked as a black texture.
- // See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec.
-
+ // See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec, and 3.8.13 in
+ // the OpenGL ES 3.0.4 spec.
+ if (!IsMipmapRangeValid()) {
+ mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
+ return mFakeBlackStatus;
+ }
for (size_t face = 0; face < mFacesCount; ++face) {
- if (ImageInfoAtFace(face, GetBaseMipmapLevel()).mImageDataStatus == WebGLImageDataStatus::NoImageData) {
+ if (ImageInfoAtFace(face, EffectiveBaseMipmapLevel()).mImageDataStatus == WebGLImageDataStatus::NoImageData) {
// In case of undefined texture image, we don't print any message because this is a very common
// and often legitimate case (asynchronous texture loading).
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
return mFakeBlackStatus;
}
}
const char *msg_rendering_as_black
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -12,16 +12,17 @@
#include "WebGLStrongTypes.h"
#include "nsWrapperCache.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Assertions.h"
#include <algorithm>
+#include "nsAlgorithm.h"
namespace mozilla {
// Zero is not an integer power of two.
inline bool is_pot_assuming_nonnegative(GLsizei x)
{
return x && (x & (x-1)) == 0;
}
@@ -281,26 +282,32 @@ public:
bool IsMipmapCubeComplete() const;
void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x);
bool IsImmutable() const { return mImmutable; }
void SetImmutable() { mImmutable = true; }
- void SetBaseMipmapLevel(unsigned level) { mBaseMipmapLevel = level; }
- void SetMaxMipmapLevel(unsigned level) { mMaxMipmapLevel = level; }
- size_t GetBaseMipmapLevel() const {
- // Clamp to [0, levels - 1]
- return std::min(mBaseMipmapLevel, mMaxLevelWithCustomImages);
+ void SetBaseMipmapLevel(size_t level) { mBaseMipmapLevel = level; }
+ void SetMaxMipmapLevel(size_t level) { mMaxMipmapLevel = level; }
+
+ // Clamping (from ES 3.0.4, section 3.8 - Texturing). When not immutable,
+ // the ranges must be guarded.
+ size_t EffectiveBaseMipmapLevel() const {
+ if (IsImmutable())
+ return std::min(mBaseMipmapLevel, mMaxLevelWithCustomImages);
+ return mBaseMipmapLevel;
}
- size_t GetMaxMipmapLevel() const {
- // Clamp to [base, levels - 1]
+ size_t EffectiveMaxMipmapLevel() const {
+ if (IsImmutable())
+ return mozilla::clamped(mMaxMipmapLevel, EffectiveBaseMipmapLevel(), mMaxLevelWithCustomImages);
return std::min(mMaxMipmapLevel, mMaxLevelWithCustomImages);
}
+ bool IsMipmapRangeValid() const;
size_t MaxLevelWithCustomImages() const { return mMaxLevelWithCustomImages; }
// Returns the current fake-black-status, except if it was Unknown,
// in which case this function resolves it first, so it never returns Unknown.
WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus();
};
--- a/dom/json/nsJSON.cpp
+++ b/dom/json/nsJSON.cpp
@@ -17,16 +17,17 @@
#include "nsIUnicodeDecoder.h"
#include "nsXPCOMStrings.h"
#include "nsNetUtil.h"
#include "nsContentUtils.h"
#include "nsIScriptError.h"
#include "nsCRTGlue.h"
#include "nsAutoPtr.h"
#include "nsIScriptSecurityManager.h"
+#include "nsNullPrincipal.h"
#include "mozilla/Maybe.h"
#include <algorithm>
using mozilla::dom::EncodingUtils;
#define JSON_STREAM_BUFSIZE 4096
NS_INTERFACE_MAP_BEGIN(nsJSON)
@@ -404,19 +405,29 @@ nsJSON::DecodeInternal(JSContext* cx,
// Consume the stream
nsCOMPtr<nsIChannel> jsonChannel;
if (!mURI) {
NS_NewURI(getter_AddRefs(mURI), NS_LITERAL_CSTRING("about:blank"), 0, 0 );
if (!mURI)
return NS_ERROR_OUT_OF_MEMORY;
}
- nsresult rv =
- NS_NewInputStreamChannel(getter_AddRefs(jsonChannel), mURI, aStream,
- NS_LITERAL_CSTRING("application/json"));
+ nsresult rv;
+ nsCOMPtr<nsIPrincipal> nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = NS_NewInputStreamChannel(getter_AddRefs(jsonChannel),
+ mURI,
+ aStream,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
+ NS_LITERAL_CSTRING("application/json"));
+
if (!jsonChannel || NS_FAILED(rv))
return NS_ERROR_FAILURE;
nsRefPtr<nsJSONListener> jsonListener =
new nsJSONListener(cx, aRetval.address(), aNeedsConverter);
//XXX this stream pattern should be consolidated in netwerk
rv = jsonListener->OnStartRequest(jsonChannel, nullptr);
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -31,16 +31,17 @@
#include "nsXPIDLString.h"
#include "prprf.h"
#include "nsEscape.h"
#include "nsIWebNavigation.h"
#include "nsIDocShell.h"
#include "nsIContentViewer.h"
#include "nsIXPConnect.h"
#include "nsContentUtils.h"
+#include "nsNullPrincipal.h"
#include "nsJSUtils.h"
#include "nsThreadUtils.h"
#include "nsIScriptChannel.h"
#include "nsIDocument.h"
#include "nsILoadInfo.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsIWritablePropertyBag2.h"
@@ -422,19 +423,28 @@ nsresult nsJSChannel::Init(nsIURI *aURI)
if (!mIOThunk)
return NS_ERROR_OUT_OF_MEMORY;
// Create a stock input stream channel...
// Remember, until AsyncOpen is called, the script will not be evaluated
// and the underlying Input Stream will not be created...
nsCOMPtr<nsIChannel> channel;
+ nsCOMPtr<nsIPrincipal> nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
// If the resultant script evaluation actually does return a value, we
// treat it as html.
- rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, mIOThunk,
+ rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
+ aURI,
+ mIOThunk,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING("text/html"));
if (NS_FAILED(rv)) return rv;
rv = mIOThunk->Init(aURI);
if (NS_SUCCEEDED(rv)) {
mStreamChannel = channel;
mPropertyBag = do_QueryInterface(channel);
nsCOMPtr<nsIWritablePropertyBag2> writableBag =
--- a/dom/webidl/MediaKeySession.webidl
+++ b/dom/webidl/MediaKeySession.webidl
@@ -16,33 +16,29 @@ interface MediaKeySession : EventTarget
readonly attribute MediaKeyError? error;
// session properties
readonly attribute DOMString keySystem;
readonly attribute DOMString sessionId;
readonly attribute unrestricted double expiration;
- // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
readonly attribute Promise<void> closed;
[NewObject, Throws]
Promise<void> generateRequest(DOMString initDataType, (ArrayBufferView or ArrayBuffer) initData);
[NewObject, Throws]
Promise<boolean> load(DOMString sessionId);
// session operations
- // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
[NewObject, Throws]
Promise<void> update((ArrayBufferView or ArrayBuffer) response);
- // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
[NewObject, Throws]
Promise<void> close();
- // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
[NewObject, Throws]
Promise<void> remove();
[NewObject, Throws]
Promise<sequence<ArrayBuffer>> getUsableKeyIds();
};
--- a/dom/webidl/MediaKeys.webidl
+++ b/dom/webidl/MediaKeys.webidl
@@ -15,17 +15,16 @@ enum SessionType { "temporary", "persist
[Pref="media.eme.enabled"]
interface MediaKeys {
readonly attribute DOMString keySystem;
[NewObject, Throws]
MediaKeySession createSession(optional SessionType sessionType = "temporary");
- // void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
[NewObject, Throws]
Promise<void> setServerCertificate((ArrayBufferView or ArrayBuffer) serverCertificate);
[Throws,NewObject]
static Promise<MediaKeys> create(DOMString keySystem);
static IsTypeSupportedResult isTypeSupported(DOMString keySystem, optional DOMString initDataType, optional DOMString contentType, optional DOMString capability);
};
--- a/dom/webidl/WebGL2RenderingContext.webidl
+++ b/dom/webidl/WebGL2RenderingContext.webidl
@@ -337,16 +337,21 @@ interface WebGL2RenderingContext : WebGL
/* Renderbuffer objects */
void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
/* Texture objects */
void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
void texStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height,
GLsizei depth);
+ [Throws]
+ void texImage3D(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format,
+ GLenum type, ArrayBufferView? pixels);
[Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
ArrayBufferView? pixels);
[Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLenum format, GLenum type, ImageData? data);
[Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLenum format, GLenum type, HTMLImageElement image);
[Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
--- a/editor/libeditor/nsHTMLEditorEventListener.cpp
+++ b/editor/libeditor/nsHTMLEditorEventListener.cpp
@@ -67,16 +67,21 @@ nsHTMLEditorEventListener::MouseUp(nsIDO
return nsEditorEventListener::MouseUp(aMouseEvent);
}
nsresult
nsHTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
{
nsHTMLEditor* htmlEditor = GetHTMLEditor();
+ // Contenteditable should disregard mousedowns outside it.
+ // IsAcceptableInputEvent() checks it for a mouse event.
+ if (!htmlEditor->IsAcceptableInputEvent(aMouseEvent)) {
+ return NS_OK;
+ }
// Detect only "context menu" click
// XXX This should be easier to do!
// But eDOMEvents_contextmenu and NS_CONTEXTMENU is not exposed in any event
// interface :-(
int16_t buttonNumber;
nsresult rv = aMouseEvent->GetButton(&buttonNumber);
NS_ENSURE_SUCCESS(rv, rv);
@@ -88,21 +93,16 @@ nsHTMLEditorEventListener::MouseDown(nsI
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMEventTarget> target;
rv = aMouseEvent->GetExplicitOriginalTarget(getter_AddRefs(target));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(target, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
- // Contenteditable should disregard mousedowns outside it
- if (element && !htmlEditor->IsDescendantOfEditorRoot(element)) {
- return NS_OK;
- }
-
if (isContextClick || (buttonNumber == 0 && clickCount == 2)) {
nsCOMPtr<nsISelection> selection;
mEditor->GetSelection(getter_AddRefs(selection));
NS_ENSURE_TRUE(selection, NS_OK);
// Get location of mouse within target node
nsCOMPtr<nsIDOMNode> parent;
rv = aMouseEvent->GetRangeParent(getter_AddRefs(parent));
--- a/extensions/gio/nsGIOProtocolHandler.cpp
+++ b/extensions/gio/nsGIOProtocolHandler.cpp
@@ -12,16 +12,17 @@
#include "nsIPrefBranch.h"
#include "nsIObserver.h"
#include "nsThreadUtils.h"
#include "nsProxyRelease.h"
#include "nsIStringBundle.h"
#include "nsIStandardURL.h"
#include "nsMimeTypes.h"
#include "nsNetUtil.h"
+#include "nsNullPrincipal.h"
#include "mozilla/Monitor.h"
#include <gio/gio.h>
#include <algorithm>
#define MOZ_GIO_SCHEME "moz-gio"
#define MOZ_GIO_SUPPORTED_PROTOCOLS "network.gio.supported-protocols"
//-----------------------------------------------------------------------------
@@ -1057,21 +1058,28 @@ nsGIOProtocolHandler::NewChannel(nsIURI
nsRefPtr<nsGIOInputStream> stream = new nsGIOInputStream(spec);
if (!stream)
{
rv = NS_ERROR_OUT_OF_MEMORY;
}
else
{
+ nsCOMPtr<nsIPrincipal> nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
// start out assuming an unknown content-type. we'll set the content-type
// to something better once we open the URI.
rv = NS_NewInputStreamChannel(aResult,
aURI,
stream,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE));
if (NS_SUCCEEDED(rv))
stream->SetChannel(*aResult);
}
return rv;
}
NS_IMETHODIMP
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -543,21 +543,22 @@ Factory::SetDirect3D10Device(ID3D10Devic
// On Windows 8 error codes are the default, but on Windows 7 the
// default is to throw (or perhaps only with some drivers?)
aDevice->SetExceptionMode(0);
mD3D10Device = aDevice;
}
ID3D10Device1*
Factory::GetDirect3D10Device()
-
{
#ifdef DEBUG
- UINT mode = mD3D10Device->GetExceptionMode();
- MOZ_ASSERT(0 == mode);
+ if (mD3D10Device) {
+ UINT mode = mD3D10Device->GetExceptionMode();
+ MOZ_ASSERT(0 == mode);
+ }
#endif
return mD3D10Device;
}
#ifdef USE_D2D1_1
TemporaryRef<DrawTarget>
Factory::CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceFormat aFormat)
{
--- a/gfx/angle/Makefile.in
+++ b/gfx/angle/Makefile.in
@@ -12,13 +12,8 @@ endif
ifdef MOZ_D3DCOMPILER_XP_CAB
expand '$(MOZ_D3DCOMPILER_XP_CAB)' -F:$(MOZ_D3DCOMPILER_XP_DLL) '$(DIST)/bin'
endif
endif
include $(topsrcdir)/config/rules.mk
-# We have to filter out -pedantic, because of
-# comma-at-end-of-enumerator list failures. We can try to get this fixed
-# upstream at some point.
-CXXFLAGS := $(filter-out -pedantic,$(CXXFLAGS))
-CFLAGS := $(filter-out -pedantic,$(CFLAGS))
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -1248,17 +1248,17 @@ GLContext::InitWithPrefix(const char *pr
MarkUnsupported(GLFeature::map_buffer_range);
ClearSymbols(mapBufferRangeSymbols);
}
}
if (IsSupported(GLFeature::texture_3D)) {
SymLoadStruct coreSymbols[] = {
- // TexImage3D is not required for WebGL2 so not queried here.
+ { (PRFuncPtr*) &mSymbols.fTexImage3D, { "TexImage3D", nullptr } },
{ (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3D", nullptr } },
END_SYMBOLS
};
SymLoadStruct extSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3DEXT", "TexSubImage3DOES", nullptr } },
END_SYMBOLS
};
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -3127,16 +3127,31 @@ public:
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fTexStorage3D);
mSymbols.fTexStorage3D(target, levels, internalformat, width, height, depth);
AFTER_GL_CALL;
}
// -----------------------------------------------------------------------------
// 3D Textures
+ void fTexImage3D(GLenum target, GLint level,
+ GLint internalFormat,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type,
+ const GLvoid * data)
+ {
+ BEFORE_GL_CALL;
+ ASSERT_SYMBOL_PRESENT(fTexImage3D);
+ mSymbols.fTexImage3D(target, level, internalFormat,
+ width, height, depth,
+ border, format, type,
+ data);
+ AFTER_GL_CALL;
+ }
+
void fTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const GLvoid* pixels)
{
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fTexSubImage3D);
mSymbols.fTexSubImage3D(target, level, xoffset, yoffset, zoffset,
width, height, depth, format, type,
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -637,16 +637,22 @@ struct GLContextSymbols
typedef void (GLAPIENTRY * PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint* value);
PFNGLUNIFORM3UIVPROC fUniform3uiv;
typedef void (GLAPIENTRY * PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint* value);
PFNGLUNIFORM4UIVPROC fUniform4uiv;
typedef GLint (GLAPIENTRY * PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar* name);
PFNGLGETFRAGDATALOCATIONPROC fGetFragDataLocation;
// 3D Textures
+ typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level,
+ GLenum internalFormat,
+ GLenum width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type,
+ const GLvoid* pixels);
+ PFNGLTEXIMAGE3DPROC fTexImage3D;
typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset,
GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format,
GLenum type, const GLvoid* pixels);
PFNGLTEXSUBIMAGE3DPROC fTexSubImage3D;
typedef void (GLAPIENTRY * PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset,
GLint yoffset, GLint zoffset, GLint x,
GLint y, GLsizei width, GLsizei height);
--- a/gfx/thebes/gfxSVGGlyphs.cpp
+++ b/gfx/thebes/gfxSVGGlyphs.cpp
@@ -364,27 +364,26 @@ gfxSVGGlyphsDocument::ParseDocument(cons
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> document(do_QueryInterface(domDoc));
if (!document) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIChannel> channel;
- rv = NS_NewInputStreamChannel(getter_AddRefs(channel), uri, nullptr /* stream */,
- SVG_CONTENT_TYPE, UTF8_CHARSET);
+ rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
+ uri,
+ nullptr, //aStream
+ principal,
+ nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
+ nsIContentPolicy::TYPE_OTHER,
+ SVG_CONTENT_TYPE,
+ UTF8_CHARSET);
NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsILoadInfo> loadInfo =
- new LoadInfo(principal,
- nullptr,
- nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
- nsIContentPolicy::TYPE_OTHER);
- channel->SetLoadInfo(loadInfo);
-
// Set this early because various decisions during page-load depend on it.
document->SetIsBeingUsedAsImage();
document->SetReadyStateInternal(nsIDocument::READYSTATE_UNINITIALIZED);
nsCOMPtr<nsIStreamListener> listener;
rv = document->StartDocumentLoad("external-resource", channel,
nullptr, // aLoadGroup
nullptr, // aContainer
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -408,34 +408,34 @@ gfxUserFontEntry::LoadNextSrc()
if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_Local) {
gfxFontEntry* fe =
gfxPlatform::GetPlatform()->LookupLocalFont(currSrc.mLocalName,
mWeight,
mStretch,
mItalic);
mFontSet->SetLocalRulesUsed();
if (fe) {
- LOG(("fontset (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
+ LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
mFontSet, mSrcIndex,
NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
NS_ConvertUTF16toUTF8(mFamilyName).get(),
uint32_t(mFontSet->mGeneration)));
fe->mFeatureSettings.AppendElements(mFeatureSettings);
fe->mLanguageOverride = mLanguageOverride;
fe->mFamilyName = mFamilyName;
// For src:local(), we don't care whether the request is from
// a private window as there's no issue of caching resources;
// local fonts are just available all the time.
StoreUserFontData(fe, false, nsString(), nullptr, 0,
gfxUserFontData::kUnknownCompression);
mPlatformFontEntry = fe;
SetLoadState(STATUS_LOADED);
return;
} else {
- LOG(("fontset (%p) [src %d] failed local: (%s) for (%s)\n",
+ LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n",
mFontSet, mSrcIndex,
NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
}
}
// src url ==> start the load process
else if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL) {
@@ -642,32 +642,32 @@ gfxUserFontEntry::LoadPlatformFont(const
fe->mFamilyName = mFamilyName;
StoreUserFontData(fe, mFontSet->GetPrivateBrowsing(), originalFullName,
&metadata, metaOrigLen, compression);
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
nsAutoCString fontURI;
mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) gen: %8.8x\n",
- this, mSrcIndex, fontURI.get(),
+ mFontSet, mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(mFamilyName).get(),
uint32_t(mFontSet->mGeneration)));
}
#endif
mPlatformFontEntry = fe;
SetLoadState(STATUS_LOADED);
gfxUserFontSet::UserFontCache::CacheFont(fe);
} else {
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
nsAutoCString fontURI;
mSrcList[mSrcIndex].mURI->GetSpec(fontURI);
LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
" error making platform font\n",
- this, mSrcIndex, fontURI.get(),
+ mFontSet, mSrcIndex, fontURI.get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
}
#endif
}
// The downloaded data can now be discarded; the font entry is using the
// sanitized copy
moz_free((void*)aFontData);
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -462,16 +462,20 @@ public:
static nsTHashtable<Entry>* sUserFonts;
};
void SetLocalRulesUsed() {
mLocalRulesUsed = true;
}
+#ifdef PR_LOGGING
+ static PRLogModuleInfo* GetUserFontsLog();
+#endif
+
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~gfxUserFontSet();
// Return whether the font set is associated with a private-browsing tab.
virtual bool GetPrivateBrowsing() = 0;
// parse data for a data URL
@@ -507,18 +511,16 @@ protected:
// font families defined by @font-face rules
nsRefPtrHashtable<nsStringHashKey, gfxUserFontFamily> mFontFamilies;
uint64_t mGeneration; // bumped on any font load change
uint64_t mRebuildGeneration; // only bumped on rebuilds
// true when local names have been looked up, false otherwise
bool mLocalRulesUsed;
-
- static PRLogModuleInfo* GetUserFontsLog();
};
// acts a placeholder until the real font is downloaded
class gfxUserFontEntry : public gfxFontEntry {
friend class gfxUserFontSet;
friend class nsUserFontSet;
friend class nsFontFaceLoader;
--- a/image/decoders/icon/android/nsIconChannel.cpp
+++ b/image/decoders/icon/android/nsIconChannel.cpp
@@ -7,16 +7,17 @@
#include "mozilla/dom/ContentChild.h"
#include "nsMimeTypes.h"
#include "nsIURL.h"
#include "nsXULAppAPI.h"
#include "AndroidBridge.h"
#include "nsIconChannel.h"
#include "nsIStringStream.h"
#include "nsNetUtil.h"
+#include "nsNullPrincipal.h"
NS_IMPL_ISUPPORTS(nsIconChannel,
nsIRequest,
nsIChannel)
using namespace mozilla;
using mozilla::dom::ContentChild;
@@ -97,17 +98,26 @@ moz_icon_to_channel(nsIURI *aURI, const
nsCOMPtr<nsIStringInputStream> stream =
do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = stream->AdoptData((char*)buf, buf_size);
NS_ENSURE_SUCCESS(rv, rv);
- return NS_NewInputStreamChannel(aChannel, aURI, stream,
+ nsCOMPtr<nsIPrincipal> nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_NewInputStreamChannel(aChannel,
+ aURI,
+ stream,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING(IMAGE_ICON_MS));
}
nsresult
nsIconChannel::Init(nsIURI* aURI)
{
nsCOMPtr<nsIMozIconURI> iconURI = do_QueryInterface(aURI);
NS_ASSERTION(iconURI, "URI is not an nsIMozIconURI");
--- a/image/decoders/icon/gtk/nsIconChannel.cpp
+++ b/image/decoders/icon/gtk/nsIconChannel.cpp
@@ -28,16 +28,17 @@ extern "C" {
#include <gtk/gtk.h>
#include "nsMimeTypes.h"
#include "nsIMIMEService.h"
#include "nsIStringBundle.h"
#include "nsNetUtil.h"
+#include "nsNullPrincipal.h"
#include "nsIURL.h"
#include "prlink.h"
#include "nsIconChannel.h"
NS_IMPL_ISUPPORTS(nsIconChannel,
nsIRequest,
nsIChannel)
@@ -132,19 +133,27 @@ moz_gdk_pixbuf_to_channel(GdkPixbuf* aPi
// stream takes ownership of buf and will free it on destruction.
// This function cannot fail.
rv = stream->AdoptData((char*)buf, buf_size);
// If this no longer holds then re-examine buf's lifetime.
MOZ_ASSERT(NS_SUCCEEDED(rv));
NS_ENSURE_SUCCESS(rv, rv);
- rv = NS_NewInputStreamChannel(aChannel, aURI, stream,
- NS_LITERAL_CSTRING(IMAGE_ICON_MS));
- return rv;
+ nsCOMPtr<nsIPrincipal> nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_NewInputStreamChannel(aChannel,
+ aURI,
+ stream,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
+ NS_LITERAL_CSTRING(IMAGE_ICON_MS));
}
static GtkWidget *gProtoWindow = nullptr;
static GtkWidget *gStockImageWidget = nullptr;
#ifdef MOZ_ENABLE_GNOMEUI
static GnomeIconTheme *gIconTheme = nullptr;
#endif //MOZ_ENABLE_GNOMEUI
--- a/image/decoders/icon/qt/nsIconChannel.cpp
+++ b/image/decoders/icon/qt/nsIconChannel.cpp
@@ -11,16 +11,17 @@
#include "mozilla/Endian.h"
#include "nsMimeTypes.h"
#include "nsIMIMEService.h"
#include "nsIStringBundle.h"
#include "nsNetUtil.h"
+#include "nsNullPrincipal.h"
#include "nsIURL.h"
#include "nsIconChannel.h"
#include "nsGtkQtIconsConverter.h"
NS_IMPL_ISUPPORTS(nsIconChannel,
nsIRequest,
nsIChannel)
@@ -78,17 +79,26 @@ moz_qicon_to_channel(QImage *image, nsIU
nsresult rv;
nsCOMPtr<nsIStringInputStream> stream =
do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = stream->AdoptData((char*)buf, buf_size);
NS_ENSURE_SUCCESS(rv, rv);
- return NS_NewInputStreamChannel(aChannel, aURI, stream,
+ nsCOMPtr<nsIPrincipal> nullPrincipal =
+ do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_NewInputStreamChannel(aChannel,
+ aURI,
+ stream,
+ nullPrincipal,
+ nsILoadInfo::SEC_NORMAL,
+ nsIContentPolicy::TYPE_OTHER,
NS_LITERAL_CSTRING(IMAGE_ICON_MS));
}
nsresult
nsIconChannel::Init(nsIURI* aURI)
{
nsCOMPtr<nsIMozIconURI> iconURI = do_QueryInterface(aURI);
--- a/ipc/chromium/src/base/message_loop.cc
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -120,16 +120,19 @@ MessageLoop::MessageLoop(Type type)
case TYPE_MOZILLA_NONMAINTHREAD:
pump_ = new mozilla::ipc::MessagePumpForNonMainThreads();
return;
#if defined(OS_WIN)
case TYPE_MOZILLA_NONMAINUITHREAD:
pump_ = new mozilla::ipc::MessagePumpForNonMainUIThreads();
return;
#endif
+ default:
+ // Create one of Chromium's standard MessageLoop types below.
+ break;
}
#if defined(OS_WIN)
// TODO(rvargas): Get rid of the OS guards.
if (type_ == TYPE_DEFAULT) {
pump_ = new base::MessagePumpDefault();
} else if (type_ == TYPE_IO) {
pump_ = new base::MessagePumpForIO();
--- a/js/ipc/JavaScriptBase.h
+++ b/js/ipc/JavaScriptBase.h
@@ -97,18 +97,18 @@ class JavaScriptBase : public WrapperOwn
bool RecvClassName(const uint64_t &objId, nsString *result) {
return Answer::RecvClassName(ObjectId::deserialize(objId), result);
}
bool RecvRegExpToShared(const uint64_t &objId, ReturnStatus *rs, nsString *source, uint32_t *flags) {
return Answer::RecvRegExpToShared(ObjectId::deserialize(objId), rs, source, flags);
}
bool RecvGetPropertyKeys(const uint64_t &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray<nsString> *names) {
- return Answer::RecvGetPropertyKeys(ObjectId::deserialize(objId), flags, rs, names);
+ ReturnStatus *rs, nsTArray<JSIDVariant> *ids) {
+ return Answer::RecvGetPropertyKeys(ObjectId::deserialize(objId), flags, rs, ids);
}
bool RecvInstanceOf(const uint64_t &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof) {
return Answer::RecvInstanceOf(ObjectId::deserialize(objId), iid, rs, instanceof);
}
bool RecvDOMInstanceOf(const uint64_t &objId, const int &prototypeID, const int &depth,
ReturnStatus *rs, bool *instanceof) {
return Answer::RecvDOMInstanceOf(ObjectId::deserialize(objId), prototypeID, depth, rs, instanceof);
@@ -195,18 +195,18 @@ class JavaScriptBase : public WrapperOwn
}
bool SendRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
nsString *source, uint32_t *flags) {
return Base::SendRegExpToShared(objId.serialize(), rs, source, flags);
}
bool SendGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray<nsString> *names) {
- return Base::SendGetPropertyKeys(objId.serialize(), flags, rs, names);
+ ReturnStatus *rs, nsTArray<JSIDVariant> *ids) {
+ return Base::SendGetPropertyKeys(objId.serialize(), flags, rs, ids);
}
bool SendInstanceOf(const ObjectId &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof) {
return Base::SendInstanceOf(objId.serialize(), iid, rs, instanceof);
}
bool SendDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
ReturnStatus *rs, bool *instanceof) {
return Base::SendDOMInstanceOf(objId.serialize(), prototypeID, depth, rs, instanceof);
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -435,17 +435,18 @@ JavaScriptShared::toSymbolVariant(JSCont
}
if (code == SymbolCode::InSymbolRegistry) {
nsAutoJSString autoStr;
if (!autoStr.init(cx, GetSymbolDescription(sym)))
return false;
*symVarp = RegisteredSymbol(autoStr);
return true;
}
- MOZ_CRASH("unique symbols not yet implemented");
+
+ JS_ReportError(cx, "unique symbol can't be used with CPOW");
return false;
}
JS::Symbol *
JavaScriptShared::fromSymbolVariant(JSContext *cx, SymbolVariant symVar)
{
switch (symVar.type()) {
case SymbolVariant::TWellKnownSymbol: {
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -37,17 +37,17 @@ both:
prio(high) sync IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
prio(high) sync CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
prio(high) sync HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
prio(high) sync ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
prio(high) sync ClassName(uint64_t objId) returns (nsString name);
prio(high) sync RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
- prio(high) sync GetPropertyKeys(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, nsString[] names);
+ prio(high) sync GetPropertyKeys(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, JSIDVariant[] ids);
prio(high) sync InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
prio(high) sync DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
prio(high) sync IsCallable(uint64_t objId) returns (bool result);
prio(high) sync IsConstructor(uint64_t objId) returns (bool result);
parent:
async __delete__();
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -575,17 +575,17 @@ WrapperAnswer::RecvRegExpToShared(const
*flags = JS_GetRegExpFlags(cx, obj);
return ok(rs);
}
bool
WrapperAnswer::RecvGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray<nsString> *names)
+ ReturnStatus *rs, nsTArray<JSIDVariant> *ids)
{
AutoSafeJSContext cx;
JSAutoRequest request(cx);
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(cx, rs);
@@ -593,21 +593,21 @@ WrapperAnswer::RecvGetPropertyKeys(const
LOG("%s.getPropertyKeys()", ReceiverObj(objId));
AutoIdVector props(cx);
if (!js::GetPropertyKeys(cx, obj, flags, &props))
return fail(cx, rs);
for (size_t i = 0; i < props.length(); i++) {
- nsString name;
- if (!convertIdToGeckoString(cx, props[i], &name))
+ JSIDVariant id;
+ if (!toJSIDVariant(cx, props[i], &id))
return fail(cx, rs);
- names->AppendElement(name);
+ ids->AppendElement(id);
}
return ok(rs);
}
bool
WrapperAnswer::RecvInstanceOf(const ObjectId &objId, const JSIID &iid, ReturnStatus *rs,
bool *instanceof)
--- a/js/ipc/WrapperAnswer.h
+++ b/js/ipc/WrapperAnswer.h
@@ -50,17 +50,17 @@ class WrapperAnswer : public virtual Jav
nsTArray<JSParam> *outparams);
bool RecvHasInstance(const ObjectId &objId, const JSVariant &v, ReturnStatus *rs, bool *bp);
bool RecvObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
bool *result);
bool RecvClassName(const ObjectId &objId, nsString *result);
bool RecvRegExpToShared(const ObjectId &objId, ReturnStatus *rs, nsString *source, uint32_t *flags);
bool RecvGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray<nsString> *names);
+ ReturnStatus *rs, nsTArray<JSIDVariant> *ids);
bool RecvInstanceOf(const ObjectId &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof);
bool RecvDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
ReturnStatus *rs, bool *instanceof);
bool RecvIsCallable(const ObjectId &objId, bool *result);
bool RecvIsConstructor(const ObjectId &objId, bool *result);
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -58,39 +58,39 @@ class CPOWProxyHandler : public BaseProx
public:
MOZ_CONSTEXPR CPOWProxyHandler()
: BaseProxyHandler(&family) {}
virtual bool finalizeInBackground(Value priv) const MOZ_OVERRIDE {
return false;
}
- virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
- virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
- MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
-
+ virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
+ virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
- virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp) const MOZ_OVERRIDE;
- virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
-
- virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
+
+ virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+ MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
+ virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject proxy,
MutableHandleValue v, bool *bp) const MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue,
JSContext *cx) const MOZ_OVERRIDE;
virtual const char* className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
virtual void objectMoved(JSObject *proxy, const JSObject *old) const MOZ_OVERRIDE;
@@ -227,17 +227,17 @@ CPOWProxyHandler::ownPropertyKeys(JSCont
AutoIdVector &props) const
{
FORWARD(ownPropertyKeys, (cx, proxy, props));
}
bool
WrapperOwner::ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
- return getPropertyKeys(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN, props);
+ return getPropertyKeys(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
}
bool
CPOWProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const
{
FORWARD(delete_, (cx, proxy, id, bp));
}
@@ -458,23 +458,24 @@ WrapperOwner::set(JSContext *cx, JS::Han
if (!ok(cx, status))
return false;
return fromVariant(cx, result, vp);
}
bool
-CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
+CPOWProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const
{
- FORWARD(keys, (cx, proxy, props));
+ FORWARD(getOwnEnumerablePropertyKeys, (cx, proxy, props));
}
bool
-WrapperOwner::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+WrapperOwner::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
return getPropertyKeys(cx, proxy, JSITER_OWNONLY, props);
}
bool
CPOWProxyHandler::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const
{
FORWARD(isExtensible, (cx, proxy, extensible));
@@ -771,30 +772,30 @@ WrapperOwner::init()
}
bool
WrapperOwner::getPropertyKeys(JSContext *cx, HandleObject proxy, uint32_t flags, AutoIdVector &props)
{
ObjectId objId = idOf(proxy);
ReturnStatus status;
- InfallibleTArray<nsString> names;
- if (!SendGetPropertyKeys(objId, flags, &status, &names))
+ InfallibleTArray<JSIDVariant> ids;
+ if (!SendGetPropertyKeys(objId, flags, &status, &ids))
return ipcfail(cx);
LOG_STACK();
if (!ok(cx, status))
return false;
- for (size_t i = 0; i < names.Length(); i++) {
- RootedId name(cx);
- if (!convertGeckoStringToId(cx, names[i], &name))
+ for (size_t i = 0; i < ids.Length(); i++) {
+ RootedId id(cx);
+ if (!fromJSIDVariant(cx, ids[i], &id))
return false;
- if (!props.append(name))
+ if (!props.append(id))
return false;
}
return true;
}
namespace mozilla {
namespace jsipc {
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -26,47 +26,46 @@ class WrapperOwner : public virtual Java
public:
typedef mozilla::ipc::IProtocolManager<
mozilla::ipc::IProtocol>::ActorDestroyReason
ActorDestroyReason;
explicit WrapperOwner(JSRuntime *rt);
bool init();
- // Fundamental proxy traps. These are required.
+ // Standard internal methods.
// (The traps should be in the same order like js/src/jsproxy.h)
- bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
- bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
- JS::MutableHandle<JSPropertyDescriptor> desc);
bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc);
bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc);
bool ownPropertyKeys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool enumerate(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
-
- // Derived proxy traps. Implementing these is useful for perfomance.
+ bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
+ bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
- bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, JS::MutableHandleValue vp);
bool set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
JS::HandleId id, bool strict, JS::MutableHandleValue vp);
- bool keys(JSContext *cx, JS::HandleObject proxy, JS::AutoIdVector &props);
- // We use "iterate" provided by the base class here.
-
- // SpiderMonkey Extensions.
- bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
- bool regexp_toShared(JSContext *cx, JS::HandleObject proxy, js::RegExpGuard *g);
bool callOrConstruct(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args,
bool construct);
+
+ // SpiderMonkey extensions.
+ bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
+ JS::MutableHandle<JSPropertyDescriptor> desc);
+ bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
+ bool getOwnEnumerablePropertyKeys(JSContext *cx, JS::HandleObject proxy,
+ JS::AutoIdVector &props);
+ // We use "iterate" provided by the base class here.
bool hasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp);
bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
const char* className(JSContext *cx, JS::HandleObject proxy);
+ bool regexp_toShared(JSContext *cx, JS::HandleObject proxy, js::RegExpGuard *g);
bool isCallable(JSObject *obj);
bool isConstructor(JSObject *obj);
nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
bool toString(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args);
/*
@@ -141,17 +140,17 @@ class WrapperOwner : public virtual Java
ReturnStatus *rs, bool *bp) = 0;
virtual bool SendObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
bool *result) = 0;
virtual bool SendClassName(const ObjectId &objId, nsString *result) = 0;
virtual bool SendRegExpToShared(const ObjectId &objId, ReturnStatus *rs, nsString *source,
uint32_t *flags) = 0;
virtual bool SendGetPropertyKeys(const ObjectId &objId, const uint32_t &flags,
- ReturnStatus *rs, nsTArray<nsString> *names) = 0;
+ ReturnStatus *rs, nsTArray<JSIDVariant> *ids) = 0;
virtual bool SendInstanceOf(const ObjectId &objId, const JSIID &iid,
ReturnStatus *rs, bool *instanceof) = 0;
virtual bool SendDOMInstanceOf(const ObjectId &objId, const int &prototypeID, const int &depth,
ReturnStatus *rs, bool *instanceof) = 0;
virtual bool SendIsCallable(const ObjectId &objId, bool *result) = 0;
virtual bool SendIsConstructor(const ObjectId &objId, bool *result) = 0;
};
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -310,16 +310,17 @@ export:: selfhosting
selfhosting:: selfhosted.out.h
selfhosting_srcs := \
$(srcdir)/builtin/Utilities.js \
$(srcdir)/builtin/ParallelUtilities.js \
$(srcdir)/builtin/Array.js \
$(srcdir)/builtin/Date.js \
$(srcdir)/builtin/Error.js \
+ $(srcdir)/builtin/Generator.js \
$(srcdir)/builtin/Intl.js \
$(srcdir)/builtin/IntlData.js \
$(srcdir)/builtin/Iterator.js \
$(srcdir)/builtin/Map.js \
$(srcdir)/builtin/Number.js \
$(srcdir)/builtin/Object.js \
$(srcdir)/builtin/String.js \
$(srcdir)/builtin/Set.js \
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/Generator.js
@@ -0,0 +1,104 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function StarGeneratorNext(val) {
+ if (!IsObject(this) || !IsStarGeneratorObject(this))
+ return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorNext");
+
+ if (StarGeneratorObjectIsClosed(this))
+ return { value: undefined, done: true };
+
+ if (GeneratorIsRunning(this))
+ ThrowError(JSMSG_NESTING_GENERATOR);
+
+ try {
+ return resumeGenerator(this, val, 'next');
+ } catch (e) {
+ if (!StarGeneratorObjectIsClosed(this))
+ GeneratorSetClosed(this);
+ throw e;
+ }
+}
+
+function StarGeneratorThrow(val) {
+ if (!IsObject(this) || !IsStarGeneratorObject(this))
+ return callFunction(CallStarGeneratorMethodIfWrapped, this, val, "StarGeneratorThrow");
+
+ if (StarGeneratorObjectIsClosed(this))
+ throw val;
+
+ if (GeneratorIsRunning(this))
+ ThrowError(JSMSG_NESTING_GENERATOR);
+
+ try {
+ return resumeGenerator(this, val, 'throw');
+ } catch (e) {
+ if (!StarGeneratorObjectIsClosed(this))
+ GeneratorSetClosed(this);
+ throw e;
+ }
+}
+
+function LegacyGeneratorNext(val) {
+ if (!IsObject(this) || !IsLegacyGeneratorObject(this))
+ return callFunction(CallLegacyGeneratorMethodIfWrapped, this, val, "LegacyGeneratorNext");
+
+ if (LegacyGeneratorObjectIsClosed(this))
+ ThrowStopIteration();
+
+ if (GeneratorIsRunning(this))
+ ThrowError(JSMSG_NESTING_GENERATOR);
+
+ try {
+ return resumeGenerator(this, val, 'next');
+ } catch(e) {
+ if (!LegacyGeneratorObjectIsClosed(this))
+ GeneratorSetClosed(this);
+ throw e;
+ }
+}
+
+function LegacyGeneratorThrow(val) {
+ if (!IsObject(this) || !IsLegacyGeneratorObject(this))
+ return callFunction(CallLegacyGeneratorMethodIfWrapped, this, val, "LegacyGeneratorThrow");
+
+ if (LegacyGeneratorObjectIsClosed(this))
+ throw val;
+
+ if (GeneratorIsRunning(this))
+ ThrowError(JSMSG_NESTING_GENERATOR);
+
+ try {
+ return resumeGenerator(this, val, 'throw');
+ } catch(e) {
+ if (!LegacyGeneratorObjectIsClosed(this))
+ GeneratorSetClosed(this);
+ throw e;
+ }
+}
+
+// Called by js::CloseIterator.
+function LegacyGeneratorCloseInternal() {
+ assert(IsObject(this), "Not an object: " + ToString(this));
+ assert(IsLegacyGeneratorObject(this), "Not a legacy generator object: " + ToString(this));
+ assert(!LegacyGeneratorObjectIsClosed(this), "Already closed: " + ToString(this));
+ assert(!CloseNewbornLegacyGeneratorObject(this), "Newborn: " + ToString(this));
+
+ if (GeneratorIsRunning(this))
+ ThrowError(JSMSG_NESTING_GENERATOR);
+
+ resumeGenerator(this, undefined, 'close');
+ if (!LegacyGeneratorObjectIsClosed(this))
+ CloseClosingLegacyGeneratorObject(this);
+}
+
+function LegacyGeneratorClose() {
+ if (!IsObject(this) || !IsLegacyGeneratorObject(this))
+ return callFunction(CallLegacyGeneratorMethodIfWrapped, this, "LegacyGeneratorClose");
+
+ if (LegacyGeneratorObjectIsClosed(this) || CloseNewbornLegacyGeneratorObject(this))
+ return;
+
+ callFunction(LegacyGeneratorCloseInternal, this);
+}
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1289,25 +1289,25 @@ if test "$GNU_CXX"; then
# -Wtrigraphs - catches unlikely use of trigraphs
# -Wtype-limits - catches overflow bugs, few false positives
# -Wunknown-pragmas - catches unexpected #pragma directives
# -Wunused-label - catches unused goto labels
# -Wunused-value - catches unused expression results
# -Wwrite-strings - catches non-const char* pointers to string literals
#
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall"
- _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wignored-qualifiers"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wsign-compare"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
# Treat some warnings as errors:
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=char-subscripts"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=comment"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=empty-body"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=endif-labels"
+ _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=ignored-qualifiers"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=int-to-pointer-cast"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=missing-braces"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=overloaded-virtual"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=pointer-arith"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=reorder"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=sequence-point"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=switch"
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -2620,35 +2620,37 @@ ImplicitConvert(JSContext* cx,
return TypeError(cx, "array", val);
}
break;
}
case TYPE_struct: {
if (val.isObject() && !sourceData) {
// Enumerate the properties of the object; if they match the struct
// specification, convert the fields.
- RootedObject iter(cx, JS_NewPropertyIterator(cx, valObj));
- if (!iter)
+ AutoIdArray props(cx, JS_Enumerate(cx, valObj));
+ if (!props)
return false;
// Convert into an intermediate, in case of failure.
size_t structSize = CType::GetSize(targetType);
AutoPtr<char> intermediate(cx->pod_malloc<char>(structSize));
if (!intermediate) {
JS_ReportAllocationOverflow(cx);
return false;
}
+ const FieldInfoHash* fields = StructType::GetFieldInfo(targetType);
+ if (props.length() != fields->count()) {
+ JS_ReportError(cx, "missing fields");
+ return false;
+ }
+
RootedId id(cx);
- size_t i = 0;
- while (1) {
- if (!JS_NextProperty(cx, iter, &id))
- return false;
- if (JSID_IS_VOID(id))
- break;
+ for (size_t i = 0; i < props.length(); ++i) {
+ id = props[i];
if (!JSID_IS_STRING(id)) {
JS_ReportError(cx, "property name is not a string");
return false;
}
JSFlatString *name = JSID_TO_FLAT_STRING(id);
const FieldInfo* field = StructType::LookupField(cx, targetType, name);
@@ -2658,24 +2660,16 @@ ImplicitConvert(JSContext* cx,
RootedValue prop(cx);
if (!JS_GetPropertyById(cx, valObj, id, &prop))
return false;
// Convert the field via ImplicitConvert().
char* fieldData = intermediate.get() + field->mOffset;
if (!ImplicitConvert(cx, prop, field->mType, fieldData, false, nullptr))
return false;
-
- ++i;
- }
-
- const FieldInfoHash* fields = StructType::GetFieldInfo(targetType);
- if (i != fields->count()) {
- JS_ReportError(cx, "missing fields");
- return false;
}
memcpy(buffer, intermediate.get(), structSize);
break;
}
return TypeError(cx, "struct", val);
}
@@ -4700,43 +4694,33 @@ ArrayType::AddressOfElement(JSContext* c
static JSFlatString*
ExtractStructField(JSContext* cx, jsval val, MutableHandleObject typeObj)
{
if (val.isPrimitive()) {
JS_ReportError(cx, "struct field descriptors require a valid name and type");
return nullptr;
}
- RootedObject obj(cx, val.toObjectOrNull());
- RootedObject iter(cx, JS_NewPropertyIterator(cx, obj));
- if (!iter)
+ RootedObject obj(cx, &val.toObject());
+ AutoIdArray props(cx, JS_Enumerate(cx, obj));
+ if (!props)
return nullptr;
- RootedId nameid(cx);
- if (!JS_NextProperty(cx, iter, &nameid))
+ // make sure we have one, and only one, property
+ if (props.length() != 1) {
+ JS_ReportError(cx, "struct field descriptors must contain one property");
return nullptr;
- if (JSID_IS_VOID(nameid)) {
- JS_ReportError(cx, "struct field descriptors require a valid name and type");
- return nullptr;
- }
-
+ }
+
+ RootedId nameid(cx, props[0]);
if (!JSID_IS_STRING(nameid)) {
JS_ReportError(cx, "struct field descriptors require a valid name and type");
return nullptr;
}
- // make sure we have one, and only one, property
- RootedId id(cx);
- if (!JS_NextProperty(cx, iter, &id))
- return nullptr;
- if (!JSID_IS_VOID(id)) {
- JS_ReportError(cx, "struct field descriptors must contain one property");
- return nullptr;
- }
-
RootedValue propVal(cx);
if (!JS_GetPropertyById(cx, obj, nameid, &propVal))
return nullptr;
if (propVal.isPrimitive() || !CType::IsCType(&propVal.toObject())) {
JS_ReportError(cx, "struct field descriptors require a valid name and type");
return nullptr;
}
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -26,16 +26,17 @@
#include "jsscript.h"
#include "jstypes.h"
#include "jsutil.h"
#include "asmjs/AsmJSLink.h"
#include "frontend/Parser.h"
#include "frontend/TokenStream.h"
#include "vm/Debugger.h"
+#include "vm/GeneratorObject.h"
#include "vm/Stack.h"
#include "jsatominlines.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
#include "frontend/ParseMaps-inl.h"
#include "frontend/ParseNode-inl.h"
@@ -1984,20 +1985,20 @@ CheckSideEffects(ExclusiveContext *cx, B
if (pn->isOp(JSOP_NOT)) {
/* ! does not convert its operand via toString or valueOf. */
return CheckSideEffects(cx, bce, pn->pn_kid, answer);
}
/* FALL THROUGH */
default:
/*
- * All of PNK_INC, PNK_DEC, PNK_THROW, PNK_YIELD, and PNK_YIELD_STAR
- * have direct effects. Of the remaining unary-arity node types, we
- * can't easily prove that the operand never denotes an object with
- * a toString or valueOf method.
+ * All of PNK_INC, PNK_DEC and PNK_THROW have direct effects. Of
+ * the remaining unary-arity node types, we can't easily prove that
+ * the operand never denotes an object with a toString or valueOf
+ * method.
*/
*answer = true;
return true;
}
MOZ_CRASH("We have a returning default case");
case PN_NAME:
/*
@@ -2968,51 +2969,53 @@ frontend::EmitFunctionScript(ExclusiveCo
if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, varIndex, DontCheckLexical, bce))
return false;
}
if (Emit1(cx, bce, JSOP_POP) < 0)
return false;
bce->switchToMain();
}
- if (funbox->isGenerator()) {
- bce->switchToProlog();
- if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
- return false;
- bce->switchToMain();
- }
-
/*
* Emit a prologue for run-once scripts which will deoptimize JIT code if
* the script ends up running multiple times via foo.caller related
* shenanigans.
*/
bool runOnce = bce->isRunOnceLambda();
if (runOnce) {
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_RUNONCE) < 0)
return false;
bce->switchToMain();
}
if (!EmitTree(cx, bce, body))
return false;
- // If we fall off the end of an ES6 generator, return a boxed iterator
- // result object of the form { value: undefined, done: true }.
- if (bce->sc->isFunctionBox() && bce->sc->asFunctionBox()->isStarGenerator()) {
- if (!EmitPrepareIteratorResult(cx, bce))
- return false;
+ // If we fall off the end of a generator, do a final yield.
+ if (bce->sc->isFunctionBox() && bce->sc->asFunctionBox()->isGenerator()) {
+ if (bce->sc->asFunctionBox()->isStarGenerator() && !EmitPrepareIteratorResult(cx, bce))
+ return false;
+
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
return false;
- if (!EmitFinishIteratorResult(cx, bce, true))
+
+ if (bce->sc->asFunctionBox()->isStarGenerator() && !EmitFinishIteratorResult(cx, bce, true))
+ return false;
+
+ ScopeCoordinate sc;
+ // We know that .generator is on the top scope chain node, as we are
+ // at the function end.
+ sc.setHops(0);
+ MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().dotGenerator, &sc));
+ if (!EmitAliasedVarOp(cx, JSOP_GETALIASEDVAR, sc, DontCheckLexical, bce))
return false;
// No need to check for finally blocks, etc as in EmitReturn.
- if (Emit1(cx, bce, JSOP_RETURN) < 0)
+ if (Emit1(cx, bce, JSOP_FINALYIELD) < 0)
return false;
}
/*
* Always end the script with a JSOP_RETRVAL. Some other parts of the codebase
* depend on this opcode, e.g. js_InternalInterpret.
*/
if (Emit1(cx, bce, JSOP_RETRVAL) < 0)
@@ -5458,35 +5461,80 @@ EmitReturn(ExclusiveContext *cx, Bytecod
* with the correct stack pointer (i.e., after popping any with,
* for/in, etc., slots nested inside the finally's try).
*
* In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an
* extra JSOP_RETRVAL after the fixups.
*/
ptrdiff_t top = bce->offset();
- if (Emit1(cx, bce, JSOP_RETURN) < 0)
- return false;
+ bool isGenerator = bce->sc->isFunctionBox() && bce->sc->asFunctionBox()->isGenerator();
+ if (Emit1(cx, bce, isGenerator ? JSOP_SETRVAL : JSOP_RETURN) < 0)
+ return false;
NonLocalExitScope nle(cx, bce);
if (!nle.prepareForNonLocalJump(nullptr))
return false;
- if (top + static_cast<ptrdiff_t>(JSOP_RETURN_LENGTH) != bce->offset()) {
+ if (isGenerator) {
+ ScopeCoordinate sc;
+ // We know that .generator is on the top scope chain node, as we just
+ // exited nested scopes.
+ sc.setHops(0);
+ MOZ_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().dotGenerator, &sc));
+ if (!EmitAliasedVarOp(cx, JSOP_GETALIASEDVAR, sc, DontCheckLexical, bce))
+ return false;
+ if (Emit1(cx, bce, JSOP_FINALYIELDRVAL) < 0)
+ return false;
+ } else if (top + static_cast<ptrdiff_t>(JSOP_RETURN_LENGTH) != bce->offset()) {
bce->code()[top] = JSOP_SETRVAL;
if (Emit1(cx, bce, JSOP_RETRVAL) < 0)
return false;
}
return true;
}
static bool
-EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter)
+EmitYield(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
+{
+ MOZ_ASSERT(bce->sc->isFunctionBox());
+
+ if (pn->getOp() == JSOP_YIELD) {
+ if (bce->sc->asFunctionBox()->isStarGenerator()) {
+ if (!EmitPrepareIteratorResult(cx, bce))
+ return false;
+ }
+ if (pn->pn_left) {
+ if (!EmitTree(cx, bce, pn->pn_left))
+ return false;
+ } else {
+ if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
+ return false;
+ }
+ if (bce->sc->asFunctionBox()->isStarGenerator()) {
+ if (!EmitFinishIteratorResult(cx, bce, false))
+ return false;
+ }
+ } else {
+ MOZ_ASSERT(pn->getOp() == JSOP_INITIALYIELD);
+ }
+
+ if (!EmitTree(cx, bce, pn->pn_right))
+ return false;
+
+ if (Emit1(cx, bce, pn->getOp()) < 0)
+ return false;
+
+ return true;
+}
+
+static bool
+EmitYieldStar(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *iter, ParseNode *gen)
{
MOZ_ASSERT(bce->sc->isFunctionBox());
MOZ_ASSERT(bce->sc->asFunctionBox()->isStarGenerator());
if (!EmitTree(cx, bce, iter)) // ITERABLE
return false;
// Convert iterable to iterator.
@@ -5495,50 +5543,57 @@ EmitYieldStar(ExclusiveContext *cx, Byte
if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // ITERABLE @@ITERATOR
return false;
if (Emit1(cx, bce, JSOP_SWAP) < 0) // @@ITERATOR ITERABLE
return false;
if (EmitCall(cx, bce, JSOP_CALL, 0, iter) < 0) // ITER
return false;
CheckTypeSet(cx, bce, JSOP_CALL);
- int depth = bce->stackDepth;
- MOZ_ASSERT(depth >= 1);
-
// Initial send value is undefined.
if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) // ITER RECEIVED
return false;
+
+ int depth = bce->stackDepth;
+ MOZ_ASSERT(depth >= 2);
+
ptrdiff_t initialSend = -1;
if (EmitBackPatchOp(cx, bce, &initialSend) < 0) // goto initialSend
return false;
// Try prologue. // ITER RESULT
StmtInfoBCE stmtInfo(cx);
PushStatementBCE(bce, &stmtInfo, STMT_TRY, bce->offset());
ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_TRY);
+ ptrdiff_t tryStart = bce->offset(); // tryStart:
if (noteIndex < 0 || Emit1(cx, bce, JSOP_TRY) < 0)
return false;
- ptrdiff_t tryStart = bce->offset(); // tryStart:
- MOZ_ASSERT(bce->stackDepth == depth + 1);
+ MOZ_ASSERT(bce->stackDepth == depth);
+
+ // Load the generator object.
+ if (!EmitTree(cx, bce, gen)) // ITER RESULT GENOBJ
+ return false;
// Yield RESULT as-is, without re-boxing.
if (Emit1(cx, bce, JSOP_YIELD) < 0) // ITER RECEIVED
return false;
// Try epilogue.
- if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, bce->offset() - tryStart + JSOP_TRY_LENGTH))
+ if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, bce->offset() - tryStart))
return false;
ptrdiff_t subsequentSend = -1;
if (EmitBackPatchOp(cx, bce, &subsequentSend) < 0) // goto subsequentSend
return false;
ptrdiff_t tryEnd = bce->offset(); // tryEnd:
// Catch location.
- // THROW? = 'throw' in ITER // ITER
- bce->stackDepth = (uint32_t) depth;
+ bce->stackDepth = uint32_t(depth); // ITER RESULT
+ if (Emit1(cx, bce, JSOP_POP) < 0) // ITER
+ return false;
+ // THROW? = 'throw' in ITER
if (Emit1(cx, bce, JSOP_EXCEPTION) < 0) // ITER EXCEPTION
return false;
if (Emit1(cx, bce, JSOP_SWAP) < 0) // EXCEPTION ITER
return false;
if (Emit1(cx, bce, JSOP_DUP) < 0) // EXCEPTION ITER ITER
return false;
if (!EmitAtomOp(cx, cx->names().throw_, JSOP_STRING, bce)) // EXCEPTION ITER ITER "throw"
return false;
@@ -5552,42 +5607,42 @@ EmitYieldStar(ExclusiveContext *cx, Byte
return false;
if (Emit1(cx, bce, JSOP_POP) < 0) // EXCEPTION
return false;
if (Emit1(cx, bce, JSOP_THROW) < 0) // throw EXCEPTION
return false;
SetJumpOffsetAt(bce, checkThrow); // delegate:
// RESULT = ITER.throw(EXCEPTION) // EXCEPTION ITER
- bce->stackDepth = (uint32_t) depth + 1;
+ bce->stackDepth = uint32_t(depth);
if (Emit1(cx, bce, JSOP_DUP) < 0) // EXCEPTION ITER ITER
return false;
if (Emit1(cx, bce, JSOP_DUP) < 0) // EXCEPTION ITER ITER ITER
return false;
if (!EmitAtomOp(cx, cx->names().throw_, JSOP_CALLPROP, bce)) // EXCEPTION ITER ITER THROW
return false;
if (Emit1(cx, bce, JSOP_SWAP) < 0) // EXCEPTION ITER THROW ITER
return false;
if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)3) < 0) // ITER THROW ITER EXCEPTION
return false;
if (EmitCall(cx, bce, JSOP_CALL, 1, iter) < 0) // ITER RESULT
return false;
CheckTypeSet(cx, bce, JSOP_CALL);
- MOZ_ASSERT(bce->stackDepth == depth + 1);
+ MOZ_ASSERT(bce->stackDepth == depth);
ptrdiff_t checkResult = -1;
if (EmitBackPatchOp(cx, bce, &checkResult) < 0) // goto checkResult
return false;
// Catch epilogue.
if (!PopStatementBCE(cx, bce))
return false;
// This is a peace offering to ReconstructPCStack. See the note in EmitTry.
if (Emit1(cx, bce, JSOP_NOP) < 0)
return false;
- if (!bce->tryNoteList.append(JSTRY_CATCH, depth, tryStart, tryEnd))
+ if (!bce->tryNoteList.append(JSTRY_CATCH, depth, tryStart + JSOP_TRY_LENGTH, tryEnd))
return false;
// After the try/catch block: send the received value to the iterator.
if (!BackPatch(cx, bce, initialSend, bce->code().end(), JSOP_GOTO)) // initialSend:
return false;
if (!BackPatch(cx, bce, subsequentSend, bce->code().end(), JSOP_GOTO)) // subsequentSend:
return false;
@@ -5603,17 +5658,17 @@ EmitYieldStar(ExclusiveContext *cx, Byte
return false;
if (Emit1(cx, bce, JSOP_SWAP) < 0) // RECEIVED ITER NEXT ITER
return false;
if (Emit2(cx, bce, JSOP_PICK, (jsbytecode)3) < 0) // ITER NEXT ITER RECEIVED
return false;
if (EmitCall(cx, bce, JSOP_CALL, 1, iter) < 0) // ITER RESULT
return false;
CheckTypeSet(cx, bce, JSOP_CALL);
- MOZ_ASSERT(bce->stackDepth == depth + 1);
+ MOZ_ASSERT(bce->stackDepth == depth);
if (!BackPatch(cx, bce, checkResult, bce->code().end(), JSOP_GOTO)) // checkResult:
return false;
// if (!result.done) goto tryStart; // ITER RESULT
if (Emit1(cx, bce, JSOP_DUP) < 0) // ITER RESULT RESULT
return false;
if (!EmitAtomOp(cx, cx->names().done, JSOP_GETPROP, bce)) // ITER RESULT DONE
return false;
@@ -5624,17 +5679,17 @@ EmitYieldStar(ExclusiveContext *cx, Byte
// result.value
if (Emit1(cx, bce, JSOP_SWAP) < 0) // RESULT ITER
return false;
if (Emit1(cx, bce, JSOP_POP) < 0) // RESULT
return false;
if (!EmitAtomOp(cx, cx->names().value, JSOP_GETPROP, bce)) // VALUE
return false;
- MOZ_ASSERT(bce->stackDepth == depth);
+ MOZ_ASSERT(bce->stackDepth == depth - 1);
return true;
}
static bool
EmitStatementList(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
{
MOZ_ASSERT(pn->isArity(PN_LIST));
@@ -5803,16 +5858,90 @@ EmitDelete(ExclusiveContext *cx, Bytecod
return true;
}
static bool
EmitArray(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, uint32_t count);
static bool
+EmitSelfHostedCallFunction(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
+{
+ // Special-casing of callFunction to emit bytecode that directly
+ // invokes the callee with the correct |this| object and arguments.
+ // callFunction(fun, thisArg, arg0, arg1) thus becomes:
+ // - emit lookup for fun
+ // - emit lookup for thisArg
+ // - emit lookups for arg0, arg1
+ //
+ // argc is set to the amount of actually emitted args and the
+ // emitting of args below is disabled by setting emitArgs to false.
+ if (pn->pn_count < 3) {
+ bce->reportError(pn, JSMSG_MORE_ARGS_NEEDED, "callFunction", "1", "s");
+ return false;
+ }
+
+ ParseNode *pn2 = pn->pn_head;
+ ParseNode *funNode = pn2->pn_next;
+ if (!EmitTree(cx, bce, funNode))
+ return false;
+
+ ParseNode *thisArg = funNode->pn_next;
+ if (!EmitTree(cx, bce, thisArg))
+ return false;
+
+ bool oldEmittingForInit = bce->emittingForInit;
+ bce->emittingForInit = false;
+
+ for (ParseNode *argpn = thisArg->pn_next; argpn; argpn = argpn->pn_next) {
+ if (!EmitTree(cx, bce, argpn))
+ return false;
+ }
+
+ bce->emittingForInit = oldEmittingForInit;
+
+ uint32_t argc = pn->pn_count - 3;
+ if (EmitCall(cx, bce, pn->getOp(), argc) < 0)
+ return false;
+
+ CheckTypeSet(cx, bce, pn->getOp());
+ return true;
+}
+
+static bool
+EmitSelfHostedResumeGenerator(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
+{
+ // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'close')
+ if (pn->pn_count != 4) {
+ bce->reportError(pn, JSMSG_MORE_ARGS_NEEDED, "resumeGenerator", "1", "s");
+ return false;
+ }
+
+ ParseNode *funNode = pn->pn_head; // The resumeGenerator node.
+
+ ParseNode *genNode = funNode->pn_next;
+ if (!EmitTree(cx, bce, genNode))
+ return false;
+
+ ParseNode *valNode = genNode->pn_next;
+ if (!EmitTree(cx, bce, valNode))
+ return false;
+
+ ParseNode *kindNode = valNode->pn_next;
+ MOZ_ASSERT(kindNode->isKind(PNK_STRING));
+ uint16_t operand = GeneratorObject::getResumeKind(cx, kindNode->pn_atom);
+ MOZ_ASSERT(!kindNode->pn_next);
+
+ if (EmitCall(cx, bce, JSOP_RESUME, operand) < 0)
+ return false;
+
+ return true;
+}
+
+static bool
EmitCallOrNew(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
{
bool callop = pn->isKind(PNK_CALL) || pn->isKind(PNK_TAGGED_TEMPLATE);
/*
* Emit callable invocation or operator new (constructor call) code.
* First, emit code for the left operand to evaluate the callable or
* constructable object expression.
*
@@ -5830,56 +5959,31 @@ EmitCallOrNew(ExclusiveContext *cx, Byte
if (argc >= ARGC_LIMIT) {
bce->parser->tokenStream.reportError(callop
? JSMSG_TOO_MANY_FUN_ARGS
: JSMSG_TOO_MANY_CON_ARGS);
return false;
}
- bool emitArgs = true;
ParseNode *pn2 = pn->pn_head;
bool spread = JOF_OPTYPE(pn->getOp()) == JOF_BYTE;
switch (pn2->getKind()) {
case PNK_NAME:
- if (bce->emitterMode == BytecodeEmitter::SelfHosting &&
- pn2->name() == cx->names().callFunction &&
- !spread)
- {
- /*
- * Special-casing of callFunction to emit bytecode that directly
- * invokes the callee with the correct |this| object and arguments.
- * callFunction(fun, thisArg, arg0, arg1) thus becomes:
- * - emit lookup for fun
- * - emit lookup for thisArg
- * - emit lookups for arg0, arg1
- *
- * argc is set to the amount of actually emitted args and the
- * emitting of args below is disabled by setting emitArgs to false.
- */
- if (pn->pn_count < 3) {
- bce->reportError(pn, JSMSG_MORE_ARGS_NEEDED, "callFunction", "1", "s");
- return false;
- }
- ParseNode *funNode = pn2->pn_next;
- if (!EmitTree(cx, bce, funNode))
- return false;
- ParseNode *thisArg = funNode->pn_next;
- if (!EmitTree(cx, bce, thisArg))
- return false;
- bool oldEmittingForInit = bce->emittingForInit;
- bce->emittingForInit = false;
- for (ParseNode *argpn = thisArg->pn_next; argpn; argpn = argpn->pn_next) {
- if (!EmitTree(cx, bce, argpn))
- return false;
- }
- bce->emittingForInit = oldEmittingForInit;
- argc -= 2;
- emitArgs = false;
- break;
+ if (bce->emitterMode == BytecodeEmitter::SelfHosting && !spread) {
+ // We shouldn't see foo(bar) = x in self-hosted code.
+ MOZ_ASSERT(!(pn->pn_xflags & PNX_SETCALL));
+
+ // Calls to "callFunction" or "resumeGenerator" in self-hosted code
+ // generate inline bytecode.
+ if (pn2->name() == cx->names().callFunction)
+ return EmitSelfHostedCallFunction(cx, bce, pn);
+ if (pn2->name() == cx->names().resumeGenerator)
+ return EmitSelfHostedResumeGenerator(cx, bce, pn);
+ // Fall through.
}
if (!EmitNameOp(cx, bce, pn2, callop))
return false;
break;
case PNK_DOT:
if (!EmitPropOp(cx, pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP, bce))
return false;
break;
@@ -5917,35 +6021,33 @@ EmitCallOrNew(ExclusiveContext *cx, Byte
break;
}
if (!callop) {
JSOp thisop = pn->isKind(PNK_GENEXP) ? JSOP_THIS : JSOP_UNDEFINED;
if (Emit1(cx, bce, thisop) < 0)
return false;
}
- if (emitArgs) {
- /*
- * Emit code for each argument in order, then emit the JSOP_*CALL or
- * JSOP_NEW bytecode with a two-byte immediate telling how many args
- * were pushed on the operand stack.
- */
- bool oldEmittingForInit = bce->emittingForInit;
- bce->emittingForInit = false;
- if (!spread) {
- for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
- if (!EmitTree(cx, bce, pn3))
- return false;
- }
- } else {
- if (!EmitArray(cx, bce, pn2->pn_next, argc))
+ /*
+ * Emit code for each argument in order, then emit the JSOP_*CALL or
+ * JSOP_NEW bytecode with a two-byte immediate telling how many args
+ * were pushed on the operand stack.
+ */
+ bool oldEmittingForInit = bce->emittingForInit;
+ bce->emittingForInit = false;
+ if (!spread) {
+ for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
+ if (!EmitTree(cx, bce, pn3))
return false;
}
- bce->emittingForInit = oldEmittingForInit;
- }
+ } else {
+ if (!EmitArray(cx, bce, pn2->pn_next, argc))
+ return false;
+ }
+ bce->emittingForInit = oldEmittingForInit;
if (!spread) {
if (EmitCall(cx, bce, pn->getOp(), argc, pn) < 0)
return false;
} else {
if (Emit1(cx, bce, pn->getOp()) < 0)
return false;
}
@@ -6682,38 +6784,26 @@ frontend::EmitTree(ExclusiveContext *cx,
return false;
break;
case PNK_RETURN:
ok = EmitReturn(cx, bce, pn);
break;
case PNK_YIELD_STAR:
- ok = EmitYieldStar(cx, bce, pn->pn_kid);
+ ok = EmitYieldStar(cx, bce, pn->pn_left, pn->pn_right);
+ break;
+
+ case PNK_GENERATOR:
+ if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
+ return false;
break;
case PNK_YIELD:
- MOZ_ASSERT(bce->sc->isFunctionBox());
- if (bce->sc->asFunctionBox()->isStarGenerator()) {
- if (!EmitPrepareIteratorResult(cx, bce))
- return false;
- }
- if (pn->pn_kid) {
- if (!EmitTree(cx, bce, pn->pn_kid))
- return false;
- } else {
- if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
- return false;
- }
- if (bce->sc->asFunctionBox()->isStarGenerator()) {
- if (!EmitFinishIteratorResult(cx, bce, false))
- return false;
- }
- if (Emit1(cx, bce, JSOP_YIELD) < 0)
- return false;
+ ok = EmitYield(cx, bce, pn);
break;
case PNK_STATEMENTLIST:
ok = EmitStatementList(cx, bce, pn, top);
break;
case PNK_SEQ:
ok = EmitSyntheticStatements(cx, bce, pn, top);
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -318,16 +318,27 @@ class FullParseHandler
ParseNode *propdef = newBinary(PNK_COLON, name, fn, op);
if (!propdef)
return false;
literal->append(propdef);
return true;
}
+ ParseNode *newYieldExpression(uint32_t begin, ParseNode *value, ParseNode *gen,
+ JSOp op = JSOP_YIELD) {
+ TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
+ return new_<BinaryNode>(PNK_YIELD, op, pos, value, gen);
+ }
+
+ ParseNode *newYieldStarExpression(uint32_t begin, ParseNode *value, ParseNode *gen) {
+ TokenPos pos(begin, value->pn_pos.end);
+ return new_<BinaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen);
+ }
+
// Statements
ParseNode *newStatementList(unsigned blockid, const TokenPos &pos) {
ParseNode *pn = new_<ListNode>(PNK_STATEMENTLIST, pos);
if (pn)
pn->pn_blockid = blockid;
return pn;
}
@@ -347,16 +358,41 @@ class FullParseHandler
MOZ_ASSERT_IF(pc->sc->isFunctionBox(),
pc->sc->asFunctionBox()->hasExtensibleScope());
}
}
list->append(stmt);
}
+ bool prependInitialYield(ParseNode *stmtList, ParseNode *genName) {
+ MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST));
+
+ TokenPos yieldPos(stmtList->pn_pos.begin, stmtList->pn_pos.begin + 1);
+ ParseNode *makeGen = new_<NullaryNode>(PNK_GENERATOR, yieldPos);
+ if (!makeGen)
+ return false;
+
+ MOZ_ASSERT(genName->getOp() == JSOP_NAME);
+ genName->setOp(JSOP_SETNAME);
+ genName->markAsAssigned();
+ ParseNode *genInit = newBinary(PNK_ASSIGN, genName, makeGen);
+
+ ParseNode *initialYield = newYieldExpression(yieldPos.begin, nullptr, genInit,
+ JSOP_INITIALYIELD);
+ if (!initialYield)
+ return false;
+
+ initialYield->pn_next = stmtList->pn_head;
+ stmtList->pn_head = initialYield;
+ stmtList->pn_count++;
+
+ return true;
+ }
+
ParseNode *newEmptyStatement(const TokenPos &pos) {
return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, pos, (ParseNode *) nullptr);
}
ParseNode *newImportDeclaration(ParseNode *importSpecSet,
ParseNode *moduleSpec, const TokenPos &pos)
{
ParseNode *pn = new_<BinaryNode>(PNK_IMPORT, JSOP_NOP, pos,
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -119,16 +119,17 @@ class UpvarCookie
F(NEW) \
F(DELETE) \
F(TRY) \
F(CATCH) \
F(CATCHLIST) \
F(FINALLY) \
F(THROW) \
F(DEBUGGER) \
+ F(GENERATOR) \
F(YIELD) \
F(YIELD_STAR) \
F(GENEXP) \
F(ARRAYCOMP) \
F(ARRAYPUSH) \
F(LEXICALSCOPE) \
F(LET) \
F(IMPORT) \
@@ -417,16 +418,19 @@ enum ParseNodeKind
* PNK_NUMBER dval pn_dval: double value of numeric literal
* PNK_TRUE, nullary pn_op: JSOp bytecode
* PNK_FALSE,
* PNK_NULL,
* PNK_THIS
*
* PNK_LEXICALSCOPE name pn_objbox: block object in ObjectBox holder
* pn_expr: block body
+ * PNK_GENERATOR nullary
+ * PNK_YIELD, binary pn_left: expr or null; pn_right: generator object
+ * PNK_YIELD_STAR
* PNK_ARRAYCOMP list pn_count: 1
* pn_head: list of 1 element, which is block
* enclosing for loop(s) and optionally
* if-guarded PNK_ARRAYPUSH
* PNK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
* pn_kid: array comprehension expression
* PNK_NOP nullary
*/
@@ -768,18 +772,19 @@ class ParseNode
/* Return true if this node appears in a Directive Prologue. */
bool isDirectivePrologueMember() const { return pn_prologue; }
#ifdef JS_HAS_GENERATOR_EXPRS
ParseNode *generatorExpr() const {
MOZ_ASSERT(isKind(PNK_GENEXP));
ParseNode *callee = this->pn_head;
ParseNode *body = callee->pn_body;
- MOZ_ASSERT(body->isKind(PNK_LEXICALSCOPE) || body->isKind(PNK_FOR));
- return body;
+ MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
+ MOZ_ASSERT(body->last()->isKind(PNK_LEXICALSCOPE) || body->last()->isKind(PNK_FOR));
+ return body->last();
}
#endif
inline void markAsAssigned();
/*
* Compute a pointer to the last element in a singly-linked list. NB: list
* must be non-empty for correct PN_LAST usage -- this is asserted!
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1030,16 +1030,33 @@ Parser<ParseHandler>::functionBody(Funct
break;
case StarGenerator:
MOZ_ASSERT(kind != Arrow);
MOZ_ASSERT(type == StatementListBody);
break;
}
+ if (pc->isGenerator()) {
+ MOZ_ASSERT(type == StatementListBody);
+ Node generator = newName(context->names().dotGenerator);
+ if (!generator)
+ return null();
+ if (!pc->define(tokenStream, context->names().dotGenerator, generator, Definition::VAR))
+ return null();
+
+ generator = newName(context->names().dotGenerator);
+ if (!generator)
+ return null();
+ if (!noteNameUse(context->names().dotGenerator, generator))
+ return null();
+ if (!handler.prependInitialYield(pn, generator))
+ return null();
+ }
+
/* Define the 'arguments' binding if necessary. */
if (!checkFunctionArguments())
return null();
return pn;
}
/* See comment for use in Parser::functionDef. */
@@ -5004,16 +5021,31 @@ Parser<ParseHandler>::returnStatement()
return null();
}
return pn;
}
template <typename ParseHandler>
typename ParseHandler::Node
+Parser<ParseHandler>::newYieldExpression(uint32_t begin, typename ParseHandler::Node expr,
+ bool isYieldStar)
+{
+ Node generator = newName(context->names().dotGenerator);
+ if (!generator)
+ return null();
+ if (!noteNameUse(context->names().dotGenerator, generator))
+ return null();
+ if (isYieldStar)
+ return handler.newYieldStarExpression(begin, expr, generator);
+ return handler.newYieldExpression(begin, expr, generator);
+}
+
+template <typename ParseHandler>
+typename ParseHandler::Node
Parser<ParseHandler>::yieldExpression()
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_YIELD));
uint32_t begin = pos().begin;
switch (pc->generatorKind()) {
case StarGenerator:
{
@@ -5047,17 +5079,17 @@ Parser<ParseHandler>::yieldExpression()
kind = PNK_YIELD_STAR;
tokenStream.consumeKnownToken(TOK_MUL);
// Fall through.
default:
exprNode = assignExpr();
if (!exprNode)
return null();
}
- return handler.newUnary(kind, JSOP_NOP, begin, exprNode);
+ return newYieldExpression(begin, exprNode, kind == PNK_YIELD_STAR);
}
case NotGenerator:
// We are in code that has not seen a yield, but we are in JS 1.7 or
// later. Try to transition to being a legacy generator.
MOZ_ASSERT(tokenStream.versionNumber() >= JSVERSION_1_7);
MOZ_ASSERT(pc->lastYieldOffset == ParseContext<ParseHandler>::NoYieldOffset);
@@ -5105,17 +5137,17 @@ Parser<ParseHandler>::yieldExpression()
exprNode = null();
break;
default:
exprNode = assignExpr();
if (!exprNode)
return null();
}
- return handler.newUnary(PNK_YIELD, JSOP_NOP, begin, exprNode);
+ return newYieldExpression(begin, exprNode);
}
}
MOZ_CRASH("yieldExpr");
}
template <>
ParseNode *
@@ -6184,19 +6216,27 @@ LegacyCompExprTransplanter::transplant(P
}
RootedAtom atom(parser->context, pn->pn_atom);
#ifdef DEBUG
StmtInfoPC *stmt = LexicalLookup(pc, atom, nullptr, (StmtInfoPC *)nullptr);
MOZ_ASSERT(!stmt || stmt != pc->topStmt);
#endif
if (isGenexp && !dn->isOp(JSOP_CALLEE)) {
- MOZ_ASSERT(!pc->decls().lookupFirst(atom));
-
- if (dn->pn_pos < root->pn_pos) {
+ MOZ_ASSERT_IF(atom != parser->context->names().dotGenerator,
+ !pc->decls().lookupFirst(atom));
+
+ if (atom == parser->context->names().dotGenerator) {
+ if (dn->dn_uses == pn) {
+ if (!BumpStaticLevel(parser->tokenStream, dn, pc))
+ return false;
+ if (!AdjustBlockId(parser->tokenStream, dn, adjust, pc))
+ return false;
+ }
+ } else if (dn->pn_pos < root->pn_pos) {
/*
* The variable originally appeared to be a use of a
* definition or placeholder outside the generator, but now
* we know it is scoped within the legacy comprehension
* tail's clauses. Make it (along with any other uses within
* the generator) a use of a new placeholder in the
* generator's lexdeps.
*/
@@ -6299,17 +6339,17 @@ LegacyComprehensionHeadBlockScopeDepth(P
* or generator expression signified by this |for| keyword in context.
*
* Return null on failure, else return the top-most parse node for the array
* comprehension or generator expression, with a unary node as the body of the
* (possibly nested) for-loop, initialized by |kind, op, kid|.
*/
template <>
ParseNode *
-Parser<FullParseHandler>::legacyComprehensionTail(ParseNode *bodyStmt, unsigned blockid,
+Parser<FullParseHandler>::legacyComprehensionTail(ParseNode *bodyExpr, unsigned blockid,
GeneratorKind comprehensionKind,
ParseContext<FullParseHandler> *outerpc,
unsigned innerBlockScopeDepth)
{
/*
* If we saw any inner functions while processing the generator expression
* then they may have upvars referring to the let vars in this generator
* which were not correctly processed. Bail out and start over without
@@ -6363,25 +6403,25 @@ Parser<FullParseHandler>::legacyComprehe
MOZ_ASSERT(blockid <= pn->pn_blockid);
MOZ_ASSERT(blockid < pc->blockidGen);
MOZ_ASSERT(pc->bodyid < blockid);
pn->pn_blockid = stmtInfo.blockid = blockid;
MOZ_ASSERT(adjust < blockid);
adjust = blockid - adjust;
}
- handler.setBeginPosition(pn, bodyStmt);
+ handler.setBeginPosition(pn, bodyExpr);
pnp = &pn->pn_expr;
- LegacyCompExprTransplanter transplanter(bodyStmt, this, outerpc, comprehensionKind, adjust);
+ LegacyCompExprTransplanter transplanter(bodyExpr, this, outerpc, comprehensionKind, adjust);
if (!transplanter.init())
return null();
- if (!transplanter.transplant(bodyStmt))
+ if (!transplanter.transplant(bodyExpr))
return null();
MOZ_ASSERT(pc->staticScope && pc->staticScope == pn->pn_objbox->object);
data.initLet(HoistVars, &pc->staticScope->as<StaticBlockObject>(), JSMSG_ARRAY_INIT_TOO_BIG);
do {
/*
* FOR node is binary, left is loop control and right is body. Use
@@ -6527,16 +6567,33 @@ Parser<FullParseHandler>::legacyComprehe
return null();
pn2->pn_kid1 = condition();
if (!pn2->pn_kid1)
return null();
*pnp = pn2;
pnp = &pn2->pn_kid2;
}
+ ParseNode *bodyStmt;
+ if (isGenexp) {
+ ParseNode *yieldExpr = newYieldExpression(bodyExpr->pn_pos.begin, bodyExpr);
+ if (!yieldExpr)
+ return null();
+ yieldExpr->setInParens(true);
+
+ bodyStmt = handler.newExprStatement(yieldExpr, bodyExpr->pn_pos.end);
+ if (!bodyStmt)
+ return null();
+ } else {
+ bodyStmt = handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH,
+ bodyExpr->pn_pos.begin, bodyExpr);
+ if (!bodyStmt)
+ return null();
+ }
+
*pnp = bodyStmt;
pc->topStmt->innerBlockScopeDepth += innerBlockScopeDepth;
PopStatementPC(tokenStream, pc);
handler.setEndPosition(pn, pos().end);
return pn;
@@ -6563,22 +6620,17 @@ Parser<FullParseHandler>::legacyArrayCom
// Remove the single element from array's linked list, leaving us with an
// empty array literal and a comprehension expression.
MOZ_ASSERT(array->pn_count == 1);
ParseNode *bodyExpr = array->last();
array->pn_count = 0;
array->pn_tail = &array->pn_head;
*array->pn_tail = nullptr;
- ParseNode *arrayPush = handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH,
- bodyExpr->pn_pos.begin, bodyExpr);
- if (!arrayPush)
- return null();
-
- ParseNode *comp = legacyComprehensionTail(arrayPush, array->pn_blockid, NotGenerator,
+ ParseNode *comp = legacyComprehensionTail(bodyExpr, array->pn_blockid, NotGenerator,
nullptr, LegacyComprehensionHeadBlockScopeDepth(pc));
if (!comp)
return null();
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION);
TokenPos p = handler.getPosition(array);
p.end = pos().end;
@@ -6591,20 +6643,20 @@ Parser<SyntaxParseHandler>::legacyArrayC
{
abortIfSyntaxParser();
return null();
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::generatorComprehensionLambda(GeneratorKind comprehensionKind,
- unsigned begin, Node innerStmt)
+ unsigned begin, Node innerExpr)
{
MOZ_ASSERT(comprehensionKind == LegacyGenerator || comprehensionKind == StarGenerator);
- MOZ_ASSERT(!!innerStmt == (comprehensionKind == LegacyGenerator));
+ MOZ_ASSERT(!!innerExpr == (comprehensionKind == LegacyGenerator));
Node genfn = handler.newFunctionDefinition();
if (!genfn)
return null();
handler.setOp(genfn, JSOP_LAMBDA);
ParseContext<ParseHandler> *outerpc = pc;
@@ -6645,39 +6697,57 @@ Parser<ParseHandler>::generatorComprehen
genFunbox->anyCxFlags = outerpc->sc->anyCxFlags;
if (outerpc->sc->isFunctionBox())
genFunbox->funCxFlags = outerpc->sc->asFunctionBox()->funCxFlags;
MOZ_ASSERT(genFunbox->generatorKind() == comprehensionKind);
genFunbox->inGenexpLambda = true;
handler.setBlockId(genfn, genpc.bodyid);
- Node body;
-
+ Node generator = newName(context->names().dotGenerator);
+ if (!generator)
+ return null();
+ if (!pc->define(tokenStream, context->names().dotGenerator, generator, Definition::VAR))
+ return null();
+
+ Node body = handler.newStatementList(pc->blockid(), TokenPos(begin, pos().end));
+ if (!body)
+ return null();
+
+ Node comp;
if (comprehensionKind == StarGenerator) {
- body = comprehension(StarGenerator);
- if (!body)
+ comp = comprehension(StarGenerator);
+ if (!comp)
return null();
} else {
MOZ_ASSERT(comprehensionKind == LegacyGenerator);
- body = legacyComprehensionTail(innerStmt, outerpc->blockid(), LegacyGenerator,
+ comp = legacyComprehensionTail(innerExpr, outerpc->blockid(), LegacyGenerator,
outerpc, LegacyComprehensionHeadBlockScopeDepth(outerpc));
- if (!body)
+ if (!comp)
return null();
}
if (comprehensionKind == StarGenerator)
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
- handler.setBeginPosition(body, begin);
+ handler.setBeginPosition(comp, begin);
+ handler.setEndPosition(comp, pos().end);
+ handler.addStatementToList(body, comp, pc);
handler.setEndPosition(body, pos().end);
-
handler.setBeginPosition(genfn, begin);
handler.setEndPosition(genfn, pos().end);
+ generator = newName(context->names().dotGenerator);
+ if (!generator)
+ return null();
+ if (!noteNameUse(context->names().dotGenerator, generator))
+ return null();
+ if (!handler.prependInitialYield(body, generator))
+ return null();
+
// Note that if we ever start syntax-parsing generators, we will also
// need to propagate the closed-over variable set to the inner
// lazyscript, as in finishFunctionDefinition.
handler.setFunctionBody(genfn, body);
PropagateTransitiveParseFlags(genFunbox, outerpc->sc);
if (!leaveFunction(genfn, outerpc, /* bodyLevelHoistedUse = */ false))
@@ -6704,29 +6774,18 @@ Parser<ParseHandler>::generatorComprehen
* is merely sugar for a generator function expression and its application.
*/
template <>
ParseNode *
Parser<FullParseHandler>::legacyGeneratorExpr(ParseNode *expr)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FOR));
- /* Create a |yield| node for |kid|. */
- ParseNode *yieldExpr = handler.newUnary(PNK_YIELD, JSOP_NOP, expr->pn_pos.begin, expr);
- if (!yieldExpr)
- return null();
- yieldExpr->setInParens(true);
-
- // A statement to wrap the yield expression.
- ParseNode *yieldStmt = handler.newExprStatement(yieldExpr, expr->pn_pos.end);
- if (!yieldStmt)
- return null();
-
/* Make a new node for the desugared generator function. */
- ParseNode *genfn = generatorComprehensionLambda(LegacyGenerator, expr->pn_pos.begin, yieldStmt);
+ ParseNode *genfn = generatorComprehensionLambda(LegacyGenerator, expr->pn_pos.begin, expr);
if (!genfn)
return null();
/*
* Our result is a call expression that invokes the anonymous generator
* function object.
*/
ParseNode *result = ListNode::create(PNK_GENEXP, &handler);
@@ -6866,17 +6925,17 @@ Parser<ParseHandler>::comprehensionTail(
Node bodyExpr = assignExpr();
if (!bodyExpr)
return null();
if (comprehensionKind == NotGenerator)
return handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, begin, bodyExpr);
MOZ_ASSERT(comprehensionKind == StarGenerator);
- Node yieldExpr = handler.newUnary(PNK_YIELD, JSOP_NOP, begin, bodyExpr);
+ Node yieldExpr = newYieldExpression(begin, bodyExpr);
if (!yieldExpr)
return null();
handler.setInParens(yieldExpr);
return handler.newExprStatement(yieldExpr, pos().end);
}
// Parse an ES6 generator or array comprehension, starting at the first 'for'.
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -459,16 +459,17 @@ class Parser : private JS::AutoGCRooter,
Node stringLiteral();
Node noSubstitutionTemplate();
Node templateLiteral();
bool taggedTemplate(Node nodeList, TokenKind tt);
bool appendToCallSiteObj(Node callSiteObj);
bool addExprAndGetNextTemplStrToken(Node nodeList, TokenKind &tt);
inline Node newName(PropertyName *name);
+ inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
inline bool abortIfSyntaxParser();
public:
/* Public entry points for parsing. */
Node statement(bool canHaveDirectives = false);
bool maybeParseDirective(Node list, Node pn, bool *cont);
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -130,21 +130,24 @@ class SyntaxParseHandler
bool addElision(Node literal, const TokenPos &pos) { return true; }
bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; }
bool addArrayElement(Node literal, Node element) { return true; }
Node newObjectLiteral(uint32_t begin) { return NodeGeneric; }
bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
bool addPropertyDefinition(Node literal, Node name, Node expr, bool isShorthand = false) { return true; }
bool addMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
+ Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
+ Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
// Statements
Node newStatementList(unsigned blockid, const TokenPos &pos) { return NodeGeneric; }
void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler> *pc) {}
+ bool prependInitialYield(Node stmtList, Node gen) { return true; }
Node newEmptyStatement(const TokenPos &pos) { return NodeGeneric; }
Node newExprStatement(Node expr, uint32_t end) {
return expr == NodeString ? NodeStringExprStatement : NodeGeneric;
}
Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; }
Node newDoWhileStatement(Node body, Node cond, const TokenPos &pos) { return NodeGeneric; }
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -20,17 +20,17 @@
/*
* A write barrier is a mechanism used by incremental or generation GCs to
* ensure that every value that needs to be marked is marked. In general, the
* write barrier should be invoked whenever a write can cause the set of things
* traced through by the GC to change. This includes:
* - writes to object properties
* - writes to array slots
* - writes to fields like JSObject::shape_ that we trace through
- * - writes to fields in private data, like JSGenerator::obj
+ * - writes to fields in private data
* - writes to non-markable fields like JSObject::private that point to
* markable data
* The last category is the trickiest. Even though the private pointers does not
* point to a GC thing, changing the private pointer may change the set of
* objects that are traced by the GC. Therefore it needs a write barrier.
*
* Every barriered write should have the following form:
* <pre-barrier>
--- a/js/src/jit-test/tests/debug/Frame-onPop-generators-01.js
+++ b/js/src/jit-test/tests/debug/Frame-onPop-generators-01.js
@@ -1,10 +1,11 @@
+// |jit-test| error: StopIteration
// Returning {throw:} from an onPop handler when yielding works and
-// does not close the generator-iterator.
+// does closes the generator-iterator.
load(libdir + "asserts.js");
var g = newGlobal();
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
dbg.onDebuggerStatement = function handleDebugger(frame) {
frame.onPop = function (c) {
@@ -12,9 +13,9 @@ dbg.onDebuggerStatement = function handl
};
};
g.eval("function g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
g.eval("var it = g();");
var rv = gw.evalInGlobal("it.next();");
assertEq(rv.throw, "fit");
dbg.enabled = false;
-assertEq(g.it.next(), 1);
+g.it.next();
--- a/js/src/jit-test/tests/debug/Frame-onPop-star-generators-01.js
+++ b/js/src/jit-test/tests/debug/Frame-onPop-star-generators-01.js
@@ -1,10 +1,10 @@
// Returning {throw:} from an onPop handler when yielding works and
-// does not close the generator-iterator.
+// closes the generator-iterator.
load(libdir + "iteration.js");
var g = newGlobal();
var dbg = new Debugger;
var gw = dbg.addDebuggee(g);
dbg.onDebuggerStatement = function handleDebugger(frame) {
frame.onPop = function (c) {
@@ -12,9 +12,9 @@ dbg.onDebuggerStatement = function handl
};
};
g.eval("function* g() { for (var i = 0; i < 10; i++) { debugger; yield i; } }");
g.eval("var it = g();");
var rv = gw.evalInGlobal("it.next();");
assertEq(rv.throw, "fit");
dbg.enabled = false;
-assertIteratorNext(g.it, 1);
+assertIteratorDone(g.it);
--- a/js/src/jit-test/tests/debug/resumption-04.js
+++ b/js/src/jit-test/tests/debug/resumption-04.js
@@ -1,14 +1,19 @@
+// |jit-test| error: already executing generator
// Forced return from a generator frame.
var g = newGlobal();
g.debuggeeGlobal = this;
g.eval("var dbg = new Debugger(debuggeeGlobal);" +
"dbg.onDebuggerStatement = function () { return {return: '!'}; };");
function gen() {
yield '1';
debugger; // Force return here. The value is ignored.
yield '2';
}
-var x = [v for (v in gen())];
-assertEq(x.join(","), "1");
+
+var iter = gen();
+assertEq(iter.next(), "1");
+assertEq(iter.next(), "!");
+iter.next();
+assertEq(0, 1);
--- a/js/src/jit-test/tests/debug/resumption-06.js
+++ b/js/src/jit-test/tests/debug/resumption-06.js
@@ -1,8 +1,9 @@
+// |jit-test| error: already executing generator
// Forced return from a star generator frame.
load(libdir + 'asserts.js')
load(libdir + 'iteration.js')
var g = newGlobal();
g.debuggeeGlobal = this;
g.eval("var dbg = new Debugger(debuggeeGlobal);" +
@@ -11,9 +12,10 @@ g.eval("var dbg = new Debugger(debuggeeG
function* gen() {
yield '1';
debugger; // Force return here. The value is ignored.
yield '2';
}
var iter = gen();
assertIteratorNext(iter, '1');
assertEq(iter.next(), '!');
-assertIteratorDone(iter);
+iter.next();
+assertEq(0, 1);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/generators/throw-closes.js
@@ -0,0 +1,49 @@
+// When a generator function throws, the generator is closed.
+
+load(libdir + "asserts.js");
+load(libdir + "iteration.js");
+
+// Star generator, next() throws.
+function *g() {
+ yield 1;
+ yield 2;
+ throw 3;
+ yield 4;
+}
+var i = g();
+assertIteratorNext(i, 1);
+assertIteratorNext(i, 2);
+assertThrowsValue(() => i.next(), 3);
+assertIteratorDone(i);
+assertIteratorDone(i);
+
+// Star generator, throw() throws.
+function *h() {
+ yield 1;
+ yield 2;
+}
+var i = h();
+assertIteratorNext(i, 1);
+assertThrowsValue(() => i.throw(4), 4);
+assertIteratorDone(i);
+
+// Legacy generator, throw() throws.
+function l1() {
+ yield 1;
+ yield 2;
+}
+var i = l1();
+assertEq(i.next(), 1);
+assertThrowsValue(() => i.throw(5), 5);
+assertThrowsInstanceOf(() => i.next(), StopIteration);
+
+// Legacy generator, next() throws.
+function l2() {
+ yield 1;
+ throw 6;
+ yield 2;
+}
+var i = l2();
+assertEq(i.next(), 1);
+assertThrowsValue(() => i.next(), 6);
+assertThrowsInstanceOf(() => i.next(), StopIteration);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/generators/wrappers.js
@@ -0,0 +1,34 @@
+// Generator methods work transparently on CrossCompartmentWrappers.
+
+load(libdir + "asserts.js");
+load(libdir + "iteration.js");
+
+function gen() { yield 1; yield 2; }
+var it = gen();
+
+var g = newGlobal();
+g.eval("function gen2() { yield 3; yield 4; }; var it2 = gen2();");
+
+// LegacyGenerator.next
+assertEq(it.next.call(g.it2), 3);
+
+// LegacyGenerator.throw
+assertThrowsValue(() => it.throw.call(g.it2, 7), 7);
+
+function *gen3() { yield 1; yield 2; }
+it = gen3();
+g.eval("function *gen4() { yield 5; yield 6; }; var it4 = gen4();");
+
+// StarGenerator.next
+assertIteratorResult(it.next.call(g.it4), 5, false)
+
+// StarGenerator.throw
+assertThrowsValue(() => it.throw.call(g.it4, 8), 8);
+
+// Other objects should throw.
+try {
+ it.next.call([]);
+ assertEq(0, 1);
+} catch (e) {
+ assertEq(e.toString().contains("called on incompatible Array"), true);
+}
--- a/js/src/jit-test/tests/saved-stacks/generators.js
+++ b/js/src/jit-test/tests/saved-stacks/generators.js
@@ -5,11 +5,12 @@ const { value: frame } = (function iife1
yield (function iife2() {
return saveStack();
}());
}()).next();
}());
assertEq(frame.functionDisplayName, "iife2");
assertEq(frame.parent.functionDisplayName, "generator");
-assertEq(frame.parent.parent.functionDisplayName, "iife1");
-assertEq(frame.parent.parent.parent.functionDisplayName, null);
-assertEq(frame.parent.parent.parent.parent, null);
+assertEq(frame.parent.parent.functionDisplayName, "next");
+assertEq(frame.parent.parent.parent.functionDisplayName, "iife1");
+assertEq(frame.parent.parent.parent.parent.functionDisplayName, null);
+assertEq(frame.parent.parent.parent.parent.parent, null);
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -44,17 +44,19 @@ jit::Bailout(BailoutStack *sp, BaselineB
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
TraceLogTimestamp(logger, TraceLogger::Bailout);
JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
MOZ_ASSERT(IsBaselineEnabled(cx));
*bailoutInfo = nullptr;
- uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo);
+ bool poppedLastSPSFrame = false;
+ uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo,
+ /* excInfo = */ nullptr, &poppedLastSPSFrame);
MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
retval == BAILOUT_RETURN_FATAL_ERROR ||
retval == BAILOUT_RETURN_OVERRECURSED);
MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
if (retval != BAILOUT_RETURN_OK) {
// If the bailout failed, then bailout trampoline will pop the
// current frame and jump straight to exception handling code when
@@ -63,17 +65,18 @@ jit::Bailout(BailoutStack *sp, BaselineB
//
// We call ExitScript here to ensure that if the ionScript had SPS
// instrumentation, then the SPS entry for it is popped.
//
// However, if the bailout was during argument check, then a
// pseudostack frame would not have been pushed in the first
// place, so don't pop anything in that case.
bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
- (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck);
+ (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck) &&
+ !poppedLastSPSFrame;
JSScript *script = iter.script();
probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
EnsureExitFrame(iter.jsFrame());
}
return retval;
}
@@ -100,17 +103,19 @@ jit::InvalidationBailout(InvalidationBai
JitSpew(JitSpew_IonBailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
// Note: the frame size must be computed before we return from this function.
*frameSizeOut = iter.frameSize();
MOZ_ASSERT(IsBaselineEnabled(cx));
*bailoutInfo = nullptr;
- uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo);
+ bool poppedLastSPSFrame = false;
+ uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo,
+ /* excInfo = */ nullptr, &poppedLastSPSFrame);
MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
retval == BAILOUT_RETURN_FATAL_ERROR ||
retval == BAILOUT_RETURN_OVERRECURSED);
MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
if (retval != BAILOUT_RETURN_OK) {
// If the bailout failed, then bailout trampoline will pop the
// current frame and jump straight to exception handling code when
@@ -119,17 +124,18 @@ jit::InvalidationBailout(InvalidationBai
//
// We call ExitScript here to ensure that if the ionScript had SPS
// instrumentation, then the SPS entry for it is popped.
//
// However, if the bailout was during argument check, then a
// pseudostack frame would not have been pushed in the first
// place, so don't pop anything in that case.
bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
- (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck);
+ (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck) &&
+ !poppedLastSPSFrame;
JSScript *script = iter.script();
probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
IonJSFrameLayout *frame = iter.jsFrame();
JitSpew(JitSpew_IonInvalidate, "Bailout failed (%s): converting to exit frame",
(retval == BAILOUT_RETURN_FATAL_ERROR) ? "Fatal Error" : "Over Recursion");
JitSpew(JitSpew_IonInvalidate, " orig calleeToken %p", (void *) frame->calleeToken());
JitSpew(JitSpew_IonInvalidate, " orig frameSize %u", unsigned(frame->prevFrameLocalSize()));
@@ -175,17 +181,19 @@ jit::ExceptionHandlerBailout(JSContext *
cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
gc::AutoSuppressGC suppress(cx);
JitActivationIterator jitActivations(cx->runtime());
BailoutFrameInfo bailoutData(jitActivations, frame.frame());
JitFrameIterator iter(jitActivations);
BaselineBailoutInfo *bailoutInfo = nullptr;
- uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, &bailoutInfo, &excInfo);
+ bool poppedLastSPSFrame = false;
+ uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true,
+ &bailoutInfo, &excInfo, &poppedLastSPSFrame);
if (retval == BAILOUT_RETURN_OK) {
MOZ_ASSERT(bailoutInfo);
// Overwrite the kind so HandleException after the bailout returns
// false, jumping directly to the exception tail.
if (excInfo.propagatingIonExceptionForDebugMode())
bailoutInfo->bailoutKind = Bailout_IonExceptionDebugMode;
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -510,19 +510,22 @@ GetNextNonLoopEntryPc(jsbytecode *pc)
// | ReturnAddr | <-- return into ArgumentsRectifier after call
// +===============+
//
static bool
InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
HandleFunction fun, HandleScript script, IonScript *ionScript,
SnapshotIterator &iter, bool invalidate, BaselineStackBuilder &builder,
AutoValueVector &startFrameFormals, MutableHandleFunction nextCallee,
- jsbytecode **callPC, const ExceptionBailoutInfo *excInfo)
+ jsbytecode **callPC, const ExceptionBailoutInfo *excInfo,
+ bool *poppedLastSPSFrameOut)
{
MOZ_ASSERT(script->hasBaselineScript());
+ MOZ_ASSERT(poppedLastSPSFrameOut);
+ MOZ_ASSERT(!*poppedLastSPSFrameOut);
// Are we catching an exception?
bool catchingException = excInfo && excInfo->catchingException();
// If we are catching an exception, we are bailing out to a catch or
// finally block and this is the frame where we will resume. Usually the
// expression stack should be empty in this case but there can be
// iterators on the stack.
@@ -1030,16 +1033,21 @@ InitFromBailout(JSContext *cx, HandleScr
// 4. If resuming into top-level code main body, an SPS entry will
// have been pushed, and can be left alone.
//
// Only need to handle case 3 here.
if (!caller && bailoutKind != Bailout_ArgumentCheck) {
JitSpew(JitSpew_BaselineBailouts,
" Popping SPS entry for outermost frame");
cx->runtime()->spsProfiler.exit(script, fun);
+
+ // Notify caller that the last SPS frame was popped, so not
+ // to do it again.
+ if (poppedLastSPSFrameOut)
+ *poppedLastSPSFrameOut = true;
}
}
} else {
opReturnAddr = nativeCodeForPC;
}
builder.setResumeAddr(opReturnAddr);
JitSpew(JitSpew_BaselineBailouts, " Set resumeAddr=%p", opReturnAddr);
}
@@ -1286,25 +1294,28 @@ InitFromBailout(JSContext *cx, HandleScr
return false;
return true;
}
uint32_t
jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
bool invalidate, BaselineBailoutInfo **bailoutInfo,
- const ExceptionBailoutInfo *excInfo)
+ const ExceptionBailoutInfo *excInfo, bool *poppedLastSPSFrameOut)
{
// The Baseline frames we will reconstruct on the heap are not rooted, so GC
// must be suppressed here.
MOZ_ASSERT(cx->mainThread().suppressGC);
MOZ_ASSERT(bailoutInfo != nullptr);
MOZ_ASSERT(*bailoutInfo == nullptr);
+ MOZ_ASSERT(poppedLastSPSFrameOut);
+ MOZ_ASSERT(!*poppedLastSPSFrameOut);
+
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
TraceLogStopEvent(logger, TraceLogger::IonMonkey);
TraceLogStartEvent(logger, TraceLogger::Baseline);
// The caller of the top frame must be one of the following:
// IonJS - Ion calling into Ion.
// BaselineStub - Baseline calling into Ion.
// Entry - Interpreter or other calling into Ion.
@@ -1424,17 +1435,18 @@ jit::BailoutIonToBaseline(JSContext *cx,
// We also need to pass excInfo if we're bailing out in place for
// debug mode.
bool passExcInfo = handleException || propagatingExceptionForDebugMode;
jsbytecode *callPC = nullptr;
RootedFunction nextCallee(cx, nullptr);
if (!InitFromBailout(cx, caller, callerPC, fun, scr, iter.ionScript(),
snapIter, invalidate, builder, startFrameFormals,
- &nextCallee, &callPC, passExcInfo ? excInfo : nullptr))
+ &nextCallee, &callPC, passExcInfo ? excInfo : nullptr,
+ poppedLastSPSFrameOut))
{
return BAILOUT_RETURN_FATAL_ERROR;
}
if (!snapIter.moreFrames()) {
MOZ_ASSERT(!callPC);
break;
}
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -318,26 +318,23 @@ jit::CanEnterBaselineMethod(JSContext *c
if (invoke.args().length() > BASELINE_MAX_ARGS_LENGTH) {
JitSpew(JitSpew_BaselineAbort, "Too many arguments (%u)", invoke.args().length());
return Method_CantCompile;
}
if (!state.maybeCreateThisForConstructor(cx))
return Method_Skipped;
- } else if (state.isExecute()) {
+ } else {
+ MOZ_ASSERT(state.isExecute());
ExecuteType type = state.asExecute()->type();
if (type == EXECUTE_DEBUG || type == EXECUTE_DEBUG_GLOBAL) {
JitSpew(JitSpew_BaselineAbort, "debugger frame");
return Method_CantCompile;
}
- } else {
- MOZ_ASSERT(state.isGenerator());
- JitSpew(JitSpew_BaselineAbort, "generator frame");
- return Method_CantCompile;
}
RootedScript script(cx, state.script());
return CanEnterBaselineJIT(cx, script, /* osr = */false);
};
BaselineScript *
BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilogueOffset,
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -434,17 +434,18 @@ struct BaselineBailoutInfo
// The bailout kind.
BailoutKind bailoutKind;
};
uint32_t
BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
bool invalidate, BaselineBailoutInfo **bailoutInfo,
- const ExceptionBailoutInfo *exceptionInfo = nullptr);
+ const ExceptionBailoutInfo *exceptionInfo,
+ bool *poppedLastSPSFrame);
// Mark baseline scripts on the stack as active, so that they are not discarded
// during GC.
void
MarkActiveBaselineScripts(Zone *zone);
MethodStatus
BaselineCompile(JSContext *cx, JSScript *script);
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2396,20 +2396,16 @@ jit::CanEnter(JSContext *cx, RunState &s
if (TooManyFormalArguments(invoke.args().callee().as<JSFunction>().nargs())) {
JitSpew(JitSpew_IonAbort, "too many args");
ForbidCompilation(cx, script);
return Method_CantCompile;
}
if (!state.maybeCreateThisForConstructor(cx))
return Method_Skipped;
- } else if (state.isGenerator()) {
- JitSpew(JitSpew_IonAbort, "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_JitOptions.eagerCompilation && !rscript->hasBaselineScript()) {
MethodStatus status = CanEnterBaselineMethod(cx, state);
if (status != Method_Compiled)
return status;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2776,17 +2776,18 @@ JS_AlreadyHasOwnUCProperty(JSContext *cx
{
JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
if (!atom)
return false;
RootedId id(cx, AtomToId(atom));
return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
}
-/* Wrapper functions to create wrappers with no corresponding JSJitInfo from API
+/*
+ * Wrapper functions to create wrappers with no corresponding JSJitInfo from API
* function arguments.
*/
static JSPropertyOpWrapper
GetterWrapper(JSPropertyOp getter)
{
JSPropertyOpWrapper ret;
ret.op = getter;
ret.info = nullptr;
@@ -2820,18 +2821,16 @@ DefinePropertyById(JSContext *cx, Handle
// When we use DefineProperty, we need full scriptable Function objects rather
// than JSNatives. However, we might be pulling this property descriptor off
// of something with JSNative property descriptors. If we are, wrap them in
// JS Function objects.
if (attrs & JSPROP_NATIVE_ACCESSORS) {
MOZ_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
JSFunction::Flags zeroFlags = JSAPIToJSFunctionFlags(0);
- // We can't just use JS_NewFunctionById here because it assumes a
- // string id.
RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr);
attrs &= ~JSPROP_NATIVE_ACCESSORS;
if (getter) {
RootedObject global(cx, (JSObject*) &obj->global());
JSFunction *getobj = NewFunction(cx, NullPtr(), (Native) getter, 0,
zeroFlags, global, atom);
if (!getobj)
return false;
@@ -2858,22 +2857,22 @@ DefinePropertyById(JSContext *cx, Handle
attrs |= JSPROP_SETTER;
}
}
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, id, value,
- (attrs & JSPROP_GETTER)
- ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
- : nullptr,
- (attrs & JSPROP_SETTER)
- ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
- : nullptr);
+ (attrs & JSPROP_GETTER)
+ ? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
+ : nullptr,
+ (attrs & JSPROP_SETTER)
+ ? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
+ : nullptr);
return JSObject::defineGeneric(cx, obj, id, value, getter, setter, attrs);
}
JS_PUBLIC_API(bool)
JS_DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter)
{
@@ -3007,64 +3006,53 @@ DefineProperty(JSContext *cx, HandleObje
if (!atom)
return false;
id = AtomToId(atom);
}
return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags);
}
-
static bool
-DefineSelfHostedProperty(JSContext *cx,
- HandleObject obj,
- const char *name,
- const char *getterName,
- const char *setterName,
- unsigned attrs,
- unsigned flags)
-{
- RootedAtom nameAtom(cx, Atomize(cx, name, strlen(name)));
- if (!nameAtom)
- return false;
-
+DefineSelfHostedProperty(JSContext *cx, HandleObject obj, HandleId id,
+ const char *getterName, const char *setterName,
+ unsigned attrs, unsigned flags)
+{
RootedAtom getterNameAtom(cx, Atomize(cx, getterName, strlen(getterName)));
if (!getterNameAtom)
return false;
+ RootedAtom name(cx, IdToFunctionName(cx, id));
+ if (!name)
+ return false;
+
RootedValue getterValue(cx);
- if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, nameAtom,
- 0, &getterValue))
- {
+ if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, name, 0, &getterValue))
return false;
- }
MOZ_ASSERT(getterValue.isObject() && getterValue.toObject().is<JSFunction>());
RootedFunction getterFunc(cx, &getterValue.toObject().as<JSFunction>());
JSPropertyOp getterOp = JS_DATA_TO_FUNC_PTR(PropertyOp, getterFunc.get());
RootedFunction setterFunc(cx);
if (setterName) {
RootedAtom setterNameAtom(cx, Atomize(cx, setterName, strlen(setterName)));
if (!setterNameAtom)
return false;
RootedValue setterValue(cx);
- if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, nameAtom,
- 0, &setterValue))
- {
+ if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, name, 0, &setterValue))
return false;
- }
MOZ_ASSERT(setterValue.isObject() && setterValue.toObject().is<JSFunction>());
setterFunc = &getterValue.toObject().as<JSFunction>();
}
JSStrictPropertyOp setterOp = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setterFunc.get());
- return DefineProperty(cx, obj, name, JS::UndefinedHandleValue,
- GetterWrapper(getterOp), SetterWrapper(setterOp),
- attrs, flags);
+ return DefinePropertyById(cx, obj, id, JS::UndefinedHandleValue,
+ GetterWrapper(getterOp), SetterWrapper(setterOp),
+ attrs, flags);
}
JS_PUBLIC_API(bool)
JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue value,
unsigned attrs,
PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
{
return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter),
@@ -3251,47 +3239,91 @@ JS_DefineConstDoubles(JSContext *cx, Han
return DefineConstScalar(cx, obj, cds);
}
JS_PUBLIC_API(bool)
JS_DefineConstIntegers(JSContext *cx, HandleObject obj, const JSConstIntegerSpec *cis)
{
return DefineConstScalar(cx, obj, cis);
}
+static JS::SymbolCode
+PropertySpecNameToSymbolCode(const char *name)
+{
+ MOZ_ASSERT(JS::PropertySpecNameIsSymbol(name));
+ uintptr_t u = reinterpret_cast<uintptr_t>(name);
+ return JS::SymbolCode(u - 1);
+}
+
+static bool
+PropertySpecNameToId(JSContext *cx, const char *name, MutableHandleId id,
+ js::InternBehavior ib = js::DoNotInternAtom)
+{
+ if (JS::PropertySpecNameIsSymbol(name)) {
+ JS::SymbolCode which = PropertySpecNameToSymbolCode(name);
+ id.set(SYMBOL_TO_JSID(cx->wellKnownSymbols().get(which)));
+ } else {
+ JSAtom *atom = Atomize(cx, name, strlen(name), ib);
+ if (!atom)
+ return false;
+ id.set(AtomToId(atom));
+ }
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+JS::PropertySpecNameToPermanentId(JSContext *cx, const char *name, jsid *idp)
+{
+ // We are calling fromMarkedLocation(idp) even though idp points to a
+ // location that will never be marked. This is OK because the whole point
+ // of this API is to populate *idp with a jsid that does not need to be
+ // marked.
+ return PropertySpecNameToId(cx, name, MutableHandleId::fromMarkedLocation(idp),
+ js::InternAtom);
+}
+
JS_PUBLIC_API(bool)
JS_DefineProperties(JSContext *cx, HandleObject obj, const JSPropertySpec *ps)
{
- bool ok;
- for (ok = true; ps->name; ps++) {
+ RootedId id(cx);
+
+ for (; ps->name; ps++) {
+ if (!PropertySpecNameToId(cx, ps->name, &id))
+ return false;
+
if (ps->flags & JSPROP_NATIVE_ACCESSORS) {
// If you declare native accessors, then you should have a native
// getter.
MOZ_ASSERT(ps->getter.propertyOp.op);
+
// If you do not have a self-hosted getter, you should not have a
// self-hosted setter. This is the closest approximation to that
// assertion we can have with our setup.
MOZ_ASSERT_IF(ps->setter.propertyOp.info, ps->setter.propertyOp.op);
- ok = DefineProperty(cx, obj, ps->name, JS::UndefinedHandleValue,
- ps->getter.propertyOp, ps->setter.propertyOp, ps->flags, 0);
+ if (!DefinePropertyById(cx, obj, id, JS::UndefinedHandleValue,
+ ps->getter.propertyOp, ps->setter.propertyOp, ps->flags, 0))
+ {
+ return false;
+ }
} else {
// If you have self-hosted getter/setter, you can't have a
// native one.
MOZ_ASSERT(!ps->getter.propertyOp.op && !ps->setter.propertyOp.op);
MOZ_ASSERT(ps->flags & JSPROP_GETTER);
- ok = DefineSelfHostedProperty(cx, obj, ps->name,
+ if (!DefineSelfHostedProperty(cx, obj, id,
ps->getter.selfHosted.funname,
ps->setter.selfHosted.funname,
- ps->flags, 0);
+ ps->flags, 0))
+ {
+ return false;
+ }
}
- if (!ok)
- break;
}
- return ok;
+ return true;
}
JS_PUBLIC_API(bool)
JS::ParsePropertyDescriptorObject(JSContext *cx,
HandleObject obj,
HandleValue descObj,
MutableHandle<JSPropertyDescriptor> desc)
{
@@ -3615,147 +3647,16 @@ JS_Enumerate(JSContext *cx, HandleObject
AutoIdVector props(cx);
JSIdArray *ida;
if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &props) || !VectorToIdArray(cx, props, &ida))
return nullptr;
return ida;
}
-/*
- * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
- * prop_iterator_class somehow...
- * + preserve the obj->enumerate API while optimizing the native object case
- * + native case here uses a JSShape *, but that iterates in reverse!
- * + so we make non-native match, by reverse-iterating after JS_Enumerating
- */
-static const uint32_t JSSLOT_ITER_INDEX = 0;
-
-static void
-prop_iter_finalize(FreeOp *fop, JSObject *obj)
-{
- void *pdata = obj->as<NativeObject>().getPrivate();
- if (!pdata)
- return;
-
- if (obj->as<NativeObject>().getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
- /* Non-native case: destroy the ida enumerated when obj was created. */
- JSIdArray *ida = (JSIdArray *) pdata;
- fop->free_(ida);
- }
-}
-
-static void
-prop_iter_trace(JSTracer *trc, JSObject *obj)
-{
- void *pdata = obj->as<NativeObject>().getPrivate();
- if (!pdata)
- return;
-
- if (obj->as<NativeObject>().getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
- /*
- * Native case: just mark the next property to visit. We don't need a
- * barrier here because the pointer is updated via setPrivate, which
- * always takes a barrier.
- */
- Shape *tmp = static_cast<Shape *>(pdata);
- MarkShapeUnbarriered(trc, &tmp, "prop iter shape");
- obj->as<NativeObject>().setPrivateUnbarriered(tmp);
- } else {
- /* Non-native case: mark each id in the JSIdArray private. */
- JSIdArray *ida = (JSIdArray *) pdata;
- MarkIdRange(trc, ida->length, ida->vector, "prop iter");
- }
-}
-
-static const Class prop_iter_class = {
- "PropertyIterator",
- JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(1),
- JS_PropertyStub, /* addProperty */
- JS_DeletePropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- prop_iter_finalize,
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- prop_iter_trace
-};
-
-JS_PUBLIC_API(JSObject *)
-JS_NewPropertyIterator(JSContext *cx, HandleObject obj)
-{
- AssertHeapIsIdle(cx);
- CHECK_REQUEST(cx);
- assertSameCompartment(cx, obj);
-
- RootedNativeObject iterobj(cx, NewNativeObjectWithClassProto(cx, &prop_iter_class,
- nullptr, obj));
- if (!iterobj)
- return nullptr;
-
- int index;
- if (obj->isNative()) {
- /* Native case: start with the last property in obj. */
- iterobj->setPrivateGCThing(obj->lastProperty());
- index = -1;
- } else {
- /* Non-native case: enumerate a JSIdArray and keep it via private. */
- JSIdArray *ida = JS_Enumerate(cx, obj);
- if (!ida)
- return nullptr;
- iterobj->setPrivate((void *)ida);
- index = ida->length;
- }
-
- /* iterobj cannot escape to other threads here. */
- iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(index));
- return iterobj;
-}
-
-JS_PUBLIC_API(bool)
-JS_NextProperty(JSContext *cx, HandleObject iterobj, MutableHandleId idp)
-{
- AssertHeapIsIdle(cx);
- CHECK_REQUEST(cx);
- assertSameCompartment(cx, iterobj);
- int32_t i = iterobj->as<NativeObject>().getSlot(JSSLOT_ITER_INDEX).toInt32();
- if (i < 0) {
- /* Native case: private data is a property tree node pointer. */
- MOZ_ASSERT(iterobj->getParent()->isNative());
- Shape *shape = static_cast<Shape *>(iterobj->as<NativeObject>().getPrivate());
-
- while (shape->previous() && !shape->enumerable())
- shape = shape->previous();
-
- if (!shape->previous()) {
- MOZ_ASSERT(shape->isEmptyShape());
- idp.set(JSID_VOID);
- } else {
- iterobj->as<NativeObject>().setPrivateGCThing(const_cast<Shape *>(shape->previous().get()));
- idp.set(shape->propid());
- }
- } else {
- /* Non-native case: use the ida enumerated when iterobj was created. */
- JSIdArray *ida = (JSIdArray *) iterobj->as<NativeObject>().getPrivate();
- MOZ_ASSERT(i <= ida->length);
- STATIC_ASSUME(i <= ida->length);
- if (i == 0) {
- idp.set(JSID_VOID);
- } else {
- idp.set(ida->vector[--i]);
- iterobj->as<NativeObject>().setSlot(JSSLOT_ITER_INDEX, Int32Value(i));
- }
- }
- return true;
-}
-
JS_PUBLIC_API(jsval)
JS_GetReservedSlot(JSObject *obj, uint32_t index)
{
return obj->fakeNativeGetReservedSlot(index);
}
JS_PUBLIC_API(void)
JS_SetReservedSlot(JSObject *obj, uint32_t index, Value value)
@@ -3894,22 +3795,24 @@ JS_NewFunctionById(JSContext *cx, JSNati
RootedAtom name(cx, JSID_TO_ATOM(id));
JSFunction::Flags funFlags = JSAPIToJSFunctionFlags(flags);
return NewFunction(cx, NullPtr(), native, nargs, funFlags, parent, name);
}
JS_PUBLIC_API(JSFunction *)
JS::GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, HandleId id, unsigned nargs)
{
- MOZ_ASSERT(JSID_IS_STRING(id));
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
- RootedAtom name(cx, JSID_TO_ATOM(id));
+ RootedAtom name(cx, IdToFunctionName(cx, id));
+ if (!name)
+ return nullptr;
+
RootedAtom shName(cx, Atomize(cx, selfHostedName, strlen(selfHostedName)));
if (!shName)
return nullptr;
RootedValue funVal(cx);
if (!cx->global()->getSelfHostedFunction(cx, shName, name, nargs, &funVal))
return nullptr;
return &funVal.toObject().as<JSFunction>();
}
@@ -4063,31 +3966,21 @@ js_generic_native_method_dispatcher(JSCo
JS_PUBLIC_API(bool)
JS_DefineFunctions(JSContext *cx, HandleObject obj, const JSFunctionSpec *fs)
{
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
+ RootedId id(cx);
for (; fs->name; fs++) {
- RootedAtom atom(cx);
- // If the name starts with "@@", it must be a well-known symbol.
- if (fs->name[0] != '@' || fs->name[1] != '@')
- atom = Atomize(cx, fs->name, strlen(fs->name));
- else if (strcmp(fs->name, "@@iterator") == 0)
- // FIXME: This atom should be a symbol: bug 918828.
- atom = cx->names().std_iterator;
- else
- JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_SYMBOL, fs->name);
- if (!atom)
+ if (!PropertySpecNameToId(cx, fs->name, &id))
return false;
- Rooted<jsid> id(cx, AtomToId(atom));
-
/*
* Define a generic arity N+1 static method for the arity N prototype
* method if flags contains JSFUN_GENERIC_NATIVE.
*/
unsigned flags = fs->flags;
if (flags & JSFUN_GENERIC_NATIVE) {
// We require that any consumers using JSFUN_GENERIC_NATIVE stash
// the prototype and constructor in the global slots before invoking
@@ -4119,18 +4012,21 @@ JS_DefineFunctions(JSContext *cx, Handle
*/
if (fs->selfHostedName) {
MOZ_ASSERT(!fs->call.op);
MOZ_ASSERT(!fs->call.info);
RootedAtom shName(cx, Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName)));
if (!shName)
return false;
+ RootedAtom name(cx, IdToFunctionName(cx, id));
+ if (!name)
+ return false;
RootedValue funVal(cx);
- if (!cx->global()->getSelfHostedFunction(cx, shName, atom, fs->nargs, &funVal))
+ if (!cx->global()->getSelfHostedFunction(cx, shName, name, fs->nargs, &funVal))
return false;
if (!JSObject::defineGeneric(cx, obj, id, funVal, nullptr, nullptr, flags))
return false;
} else {
JSFunction *fun = DefineFunction(cx, obj, id, fs->call.op, fs->nargs, flags);
if (!fun)
return false;
if (fs->call.info)
@@ -5623,16 +5519,43 @@ JS::GetSymbolCode(Handle<Symbol*> symbol
}
JS_PUBLIC_API(JS::Symbol *)
JS::GetWellKnownSymbol(JSContext *cx, JS::SymbolCode which)
{
return cx->runtime()->wellKnownSymbols->get(uint32_t(which));
}
+static bool
+PropertySpecNameIsDigits(const char *s) {
+ if (JS::PropertySpecNameIsSymbol(s))
+ return false;
+ if (!*s)
+ return false;
+ for (; *s; s++) {
+ if (*s < '0' || *s > '9')
+ return false;
+ }
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+JS::PropertySpecNameEqualsId(const char *name, HandleId id)
+{
+ if (JS::PropertySpecNameIsSymbol(name)) {
+ if (!JSID_IS_SYMBOL(id))
+ return false;
+ Symbol *sym = JSID_TO_SYMBOL(id);
+ return sym->isWellKnownSymbol() && sym->code() == PropertySpecNameToSymbolCode(name);
+ }
+
+ MOZ_ASSERT(!PropertySpecNameIsDigits(name));
+ return JSID_IS_ATOM(id) && JS_FlatStringEqualsAscii(JSID_TO_ATOM(id), name);
+}
+
JS_PUBLIC_API(bool)
JS_Stringify(JSContext *cx, MutableHandleValue vp, HandleObject replacer,
HandleValue space, JSONWriteCallback callback, void *data)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, replacer, space);
StringBuffer sb(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2470,25 +2470,37 @@ struct JSFunctionSpec {
#define JS_FS_END JS_FS(nullptr,nullptr,0,0)
/*
* Initializer macros for a JSFunctionSpec array element. JS_FN (whose name pays
* homage to the old JSNative/JSFastNative split) simply adds the flag
* JSFUN_STUB_GSOPS. JS_FNINFO allows the simple adding of
* JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted function. Finally
* JS_FNSPEC has slots for all the fields.
+ *
+ * The _SYM variants allow defining a function with a symbol key rather than a
+ * string key. For example, use JS_SYM_FN(iterator, ...) to define an
+ * @@iterator method.
*/
#define JS_FS(name,call,nargs,flags) \
JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr)
#define JS_FN(name,call,nargs,flags) \
JS_FNSPEC(name, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr)
+#define JS_SYM_FN(name,call,nargs,flags) \
+ JS_SYM_FNSPEC(symbol, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr)
#define JS_FNINFO(name,call,info,nargs,flags) \
JS_FNSPEC(name, call, info, nargs, flags, nullptr)
#define JS_SELF_HOSTED_FN(name,selfHostedName,nargs,flags) \
JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName)
+#define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \
+ JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName)
+#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
+ JS_FNSPEC(reinterpret_cast<const char *>( \
+ uint32_t(::JS::SymbolCode::symbol) + 1), \
+ call, info, nargs, flags, selfHostedName)
#define JS_FNSPEC(name,call,info,nargs,flags,selfHostedName) \
{name, {call, info}, nargs, flags, selfHostedName}
extern JS_PUBLIC_API(JSObject *)
JS_InitClass(JSContext *cx, JS::HandleObject obj, JS::HandleObject parent_proto,
const JSClass *clasp, JSNative constructor, unsigned nargs,
const JSPropertySpec *ps, const JSFunctionSpec *fs,
const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs);
@@ -3300,32 +3312,16 @@ JS_CreateMappedArrayBufferContents(int f
* release the resource used by the object.
*/
extern JS_PUBLIC_API(void)
JS_ReleaseMappedArrayBufferContents(void *contents, size_t length);
extern JS_PUBLIC_API(JSIdArray *)
JS_Enumerate(JSContext *cx, JS::HandleObject obj);
-/*
- * Create an object to iterate over enumerable properties of obj, in arbitrary
- * property definition order. NB: This differs from longstanding for..in loop
- * order, which uses order of property definition in obj.
- */
-extern JS_PUBLIC_API(JSObject *)
-JS_NewPropertyIterator(JSContext *cx, JS::Handle<JSObject*> obj);
-
-/*
- * Return true on success with *idp containing the id of the next enumerable
- * property to visit using iterobj, or JSID_IS_VOID if there is no such property
- * left to visit. Return false on error.
- */
-extern JS_PUBLIC_API(bool)
-JS_NextProperty(JSContext *cx, JS::HandleObject iterobj, JS::MutableHandleId idp);
-
extern JS_PUBLIC_API(jsval)
JS_GetReservedSlot(JSObject *obj, uint32_t index);
extern JS_PUBLIC_API(void)
JS_SetReservedSlot(JSObject *obj, uint32_t index, jsval v);
/************************************************************************/
@@ -4505,16 +4501,41 @@ GetSymbolCode(Handle<Symbol*> symbol);
* Get one of the well-known symbols defined by ES6. A single set of well-known
* symbols is shared by all compartments in a JSRuntime.
*
* `which` must be in the range [0, WellKnownSymbolLimit).
*/
JS_PUBLIC_API(Symbol *)
GetWellKnownSymbol(JSContext *cx, SymbolCode which);
+/*
+ * Return true if the given JSPropertySpec::name or JSFunctionSpec::name value
+ * is actually a symbol code and not a string. See JS_SYM_FN.
+ */
+inline bool
+PropertySpecNameIsSymbol(const char *name)
+{
+ uintptr_t u = reinterpret_cast<uintptr_t>(name);
+ return u != 0 && u - 1 < WellKnownSymbolLimit;
+}
+
+JS_PUBLIC_API(bool)
+PropertySpecNameEqualsId(const char *name, HandleId id);
+
+/*
+ * Create a jsid that does not need to be marked for GC.
+ *
+ * 'name' is a JSPropertySpec::name or JSFunctionSpec::name value. The
+ * resulting jsid, on success, is either an interned string or a well-known
+ * symbol; either way it is immune to GC so there is no need to visit *idp
+ * during GC marking.
+ */
+JS_PUBLIC_API(bool)
+PropertySpecNameToPermanentId(JSContext *cx, const char *name, jsid *idp);
+
} /* namespace JS */
/************************************************************************/
/*
* JSON functions
*/
typedef bool (* JSONWriteCallback)(const char16_t *buf, uint32_t len, void *data);
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -53,17 +53,16 @@ JS_FOR_EACH_PROTOTYPE(DEFINE_PROTO_STRIN
FOR_EACH_COMMON_PROPERTYNAME(CONST_CHAR_STR)
#undef CONST_CHAR_STR
/* Constant strings that are not atomized. */
const char js_break_str[] = "break";
const char js_case_str[] = "case";
const char js_catch_str[] = "catch";
const char js_class_str[] = "class";
-const char js_close_str[] = "close";
const char js_const_str[] = "const";
const char js_continue_str[] = "continue";
const char js_debugger_str[] = "debugger";
const char js_default_str[] = "default";
const char js_do_str[] = "do";
const char js_else_str[] = "else";
const char js_enum_str[] = "enum";
const char js_export_str[] = "export";
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1104,21 +1104,20 @@ JSContext::JSContext(JSRuntime *rt)
reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
resolvingList(nullptr),
generatingError(false),
savedFrameChains_(),
cycleDetectorSet(MOZ_THIS_IN_INITIALIZER_LIST()),
data(nullptr),
data2(nullptr),
outstandingRequests(0),
- jitIsBroken(false),
+ jitIsBroken(false)
#ifdef MOZ_TRACE_JSCALLS
- functionCallback(nullptr),
+ , functionCallback(nullptr)
#endif
- innermostGenerator_(nullptr)
{
MOZ_ASSERT(static_cast<ContextFriendFields*>(this) ==
ContextFriendFields::get(this));
}
JSContext::~JSContext()
{
/* Free the stuff hanging off of cx. */
@@ -1141,33 +1140,16 @@ JSContext::getPendingException(MutableHa
}
bool
JSContext::isThrowingOutOfMemory()
{
return throwing && unwrappedException_ == StringValue(names().outOfMemory);
}
-void
-JSContext::enterGenerator(JSGenerator *gen)
-{
- MOZ_ASSERT(!gen->prevGenerator);
- gen->prevGenerator = innermostGenerator_;
- innermostGenerator_ = gen;
-}
-
-void
-JSContext::leaveGenerator(JSGenerator *gen)
-{
- MOZ_ASSERT(innermostGenerator_ == gen);
- innermostGenerator_ = innermostGenerator_->prevGenerator;
- gen->prevGenerator = nullptr;
-}
-
-
bool
JSContext::saveFrameChain()
{
if (!savedFrameChains_.append(SavedFrameChain(compartment(), enterCompartmentDepth_)))
return false;
if (Activation *act = mainThread().activation())
act->saveFrameChain();
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -279,16 +279,17 @@ struct ThreadSafeContext : ContextFriend
void reportAllocationOverflow() {
js_ReportAllocationOverflow(this);
}
// Accessors for immutable runtime data.
JSAtomState &names() { return *runtime_->commonNames; }
StaticStrings &staticStrings() { return *runtime_->staticStrings; }
AtomSet &permanentAtoms() { return *runtime_->permanentAtoms; }
+ WellKnownSymbols &wellKnownSymbols() { return *runtime_->wellKnownSymbols; }
const JS::AsmJSCacheOps &asmJSCacheOps() { return runtime_->asmJSCacheOps; }
PropertyName *emptyString() { return runtime_->emptyString; }
FreeOp *defaultFreeOp() { return runtime_->defaultFreeOp(); }
void *runtimeAddressForJit() { return runtime_; }
void *runtimeAddressOfInterrupt() { return &runtime_->interrupt; }
void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; }
void *stackLimitAddressForJitCode(StackKind kind);
size_t gcSystemPageSize() { return gc::SystemPageSize(); }
@@ -546,24 +547,17 @@ struct JSContext : public js::ExclusiveC
void minorGC(JS::gcreason::Reason reason) {
runtime_->gc.minorGC(this, reason);
}
void gcIfNeeded() {
runtime_->gc.gcIfNeeded(this);
}
- private:
- /* Innermost-executing generator or null if no generator are executing. */
- JSGenerator *innermostGenerator_;
public:
- JSGenerator *innermostGenerator() const { return innermostGenerator_; }
- void enterGenerator(JSGenerator *gen);
- void leaveGenerator(JSGenerator *gen);
-
bool isExceptionPending() {
return throwing;
}
MOZ_WARN_UNUSED_RESULT
bool getPendingException(JS::MutableHandleValue rval);
bool isThrowingOutOfMemory();
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -966,17 +966,17 @@ CopyStringChars(JSContext *cx, char16_t
inline void
CopyFlatStringChars(char16_t *dest, JSFlatString *s, size_t len)
{
CopyLinearStringChars(dest, FlatStringToLinearString(s), len);
}
JS_FRIEND_API(bool)
-GetPropertyKeys(JSContext *cx, JSObject *obj, unsigned flags, JS::AutoIdVector *props);
+GetPropertyKeys(JSContext *cx, JS::HandleObject obj, unsigned flags, JS::AutoIdVector *props);
JS_FRIEND_API(bool)
AppendUnique(JSContext *cx, JS::AutoIdVector &base, JS::AutoIdVector &others);
JS_FRIEND_API(bool)
GetGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, JS::Value *vp);
JS_FRIEND_API(bool)
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -2058,26 +2058,50 @@ js::CloneFunctionObject(JSContext *cx, H
* no enclosing lexical scope (only the global scope).
*/
if (cloneRoot->isInterpreted() && !CloneFunctionScript(cx, fun, cloneRoot, newKindArg))
return nullptr;
return cloneRoot;
}
+/*
+ * Return an atom for use as the name of a builtin method with the given
+ * property id.
+ *
+ * Function names are always strings. If id is the well-known @@iterator
+ * symbol, this returns "[Symbol.iterator]".
+ *
+ * Implements step 4 of SetFunctionName in ES6 draft rev 27 (24 Aug 2014).
+ */
+JSAtom *
+js::IdToFunctionName(JSContext *cx, HandleId id)
+{
+ if (JSID_IS_ATOM(id))
+ return JSID_TO_ATOM(id);
+
+ if (JSID_IS_SYMBOL(id)) {
+ RootedAtom desc(cx, JSID_TO_SYMBOL(id)->description());
+ StringBuffer sb(cx);
+ if (!sb.append('[') || !sb.append(desc) || !sb.append(']'))
+ return nullptr;
+ return sb.finishAtom();
+ }
+
+ RootedValue idv(cx, IdToValue(id));
+ return ToAtom<CanGC>(cx, idv);
+}
+
JSFunction *
js::DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
unsigned nargs, unsigned flags, AllocKind allocKind /* = FinalizeKind */,
NewObjectKind newKind /* = GenericObject */)
{
PropertyOp gop;
StrictPropertyOp sop;
-
- RootedFunction fun(cx);
-
if (flags & JSFUN_STUB_GSOPS) {
/*
* JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
* the defined property's attributes. This allows us to encode another,
* internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
* for more on this.
*/
flags &= ~JSFUN_STUB_GSOPS;
@@ -2088,18 +2112,23 @@ js::DefineFunction(JSContext *cx, Handle
sop = nullptr;
}
JSFunction::Flags funFlags;
if (!native)
funFlags = JSFunction::INTERPRETED_LAZY;
else
funFlags = JSAPIToJSFunctionFlags(flags);
- RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr);
- fun = NewFunction(cx, NullPtr(), native, nargs, funFlags, obj, atom, allocKind, newKind);
+
+ RootedAtom atom(cx, IdToFunctionName(cx, id));
+ if (!atom)
+ return nullptr;
+
+ RootedFunction fun(cx, NewFunction(cx, NullPtr(), native, nargs, funFlags, obj, atom,
+ allocKind, newKind));
if (!fun)
return nullptr;
RootedValue funVal(cx, ObjectValue(*fun));
if (!JSObject::defineGeneric(cx, obj, id, funVal, gop, sop, flags & ~JSFUN_FLAGS_MASK))
return nullptr;
return fun;
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -516,16 +516,19 @@ NewFunction(ExclusiveContext *cx, Handle
// If proto is nullptr, Function.prototype is used instead.
extern JSFunction *
NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobj, JSNative native, unsigned nargs,
JSFunction::Flags flags, HandleObject parent, HandleAtom atom,
JSObject *proto, gc::AllocKind allocKind = JSFunction::FinalizeKind,
NewObjectKind newKind = GenericObject);
+extern JSAtom *
+IdToFunctionName(JSContext *cx, HandleId id);
+
extern JSFunction *
DefineFunction(JSContext *cx, HandleObject obj, HandleId id, JSNative native,
unsigned nargs, unsigned flags,
gc::AllocKind allocKind = JSFunction::FinalizeKind,
NewObjectKind newKind = GenericObject);
bool
FunctionHasResolveHook(const JSAtomState &atomState, PropertyName *name);
@@ -567,17 +570,16 @@ class FunctionExtended : public JSFuncti
HeapValue extendedSlots[NUM_EXTENDED_SLOTS];
};
extern JSFunction *
CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
gc::AllocKind kind = JSFunction::FinalizeKind,
NewObjectKind newKindArg = GenericObject);
-
extern bool
FindBody(JSContext *cx, HandleFunction fun, HandleLinearString src, size_t *bodyStart,
size_t *bodyEnd);
} // namespace js
inline js::FunctionExtended *
JSFunction::toExtended()
@@ -659,17 +661,17 @@ extern const JSFunctionSpec function_met
} /* namespace js */
extern bool
js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp);
extern bool
js_fun_call(JSContext *cx, unsigned argc, js::Value *vp);
-extern JSObject*
+extern JSObject *
js_fun_bind(JSContext *cx, js::HandleObject target, js::HandleValue thisArg,
js::Value *boundArgs, unsigned argslen);
#ifdef DEBUG
namespace JS {
namespace detail {
JS_PUBLIC_API(void)
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2259,16 +2259,18 @@ types::UseNewType(JSContext *cx, JSScrip
*
* Sub1.prototype = new Super();
* Sub2.prototype = new Super();
*
* Using distinct type objects for the particular prototypes of Sub1 and
* Sub2 lets us continue to distinguish the two subclasses and any extra
* properties added to those prototype objects.
*/
+ if (script->isGenerator())
+ return false;
if (JSOp(*pc) != JSOP_NEW)
return false;
pc += JSOP_NEW_LENGTH;
if (JSOp(*pc) == JSOP_SETPROP) {
jsid id = GetAtomId(cx, script, pc, 0);
if (id == id_prototype(cx))
return true;
}
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -266,17 +266,17 @@ struct SortComparatorIds
*lessOrEqualp = (result <= 0);
return true;
}
};
#endif /* JS_MORE_DETERMINISTIC */
static bool
-Snapshot(JSContext *cx, JSObject *pobj_, unsigned flags, AutoIdVector *props)
+Snapshot(JSContext *cx, HandleObject pobj_, unsigned flags, AutoIdVector *props)
{
IdSet ht(cx);
if (!ht.init(32))
return false;
RootedObject pobj(cx, pobj_);
do {
@@ -295,17 +295,17 @@ Snapshot(JSContext *cx, JSObject *pobj_,
if (flags & JSITER_OWNONLY) {
if (flags & JSITER_HIDDEN) {
// This gets all property keys, both strings and
// symbols. The call to Enumerate in the loop below
// will filter out unwanted keys, per the flags.
if (!Proxy::ownPropertyKeys(cx, pobj, proxyProps))
return false;
} else {
- if (!Proxy::keys(cx, pobj, proxyProps))
+ if (!Proxy::getOwnEnumerablePropertyKeys(cx, pobj, proxyProps))
return false;
}
} else {
if (!Proxy::enumerate(cx, pobj, proxyProps))
return false;
}
for (size_t n = 0, len = proxyProps.length(); n < len; n++) {
@@ -391,17 +391,17 @@ js::VectorToIdArray(JSContext *cx, AutoI
jsid *v = props.begin();
for (int i = 0; i < ida->length; i++)
ida->vector[i].init(v[i]);
*idap = ida;
return true;
}
JS_FRIEND_API(bool)
-js::GetPropertyKeys(JSContext *cx, JSObject *obj, unsigned flags, AutoIdVector *props)
+js::GetPropertyKeys(JSContext *cx, HandleObject obj, unsigned flags, AutoIdVector *props)
{
return Snapshot(cx, obj,
flags & (JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY),
props);
}
size_t sCustomIteratorCount = 0;
@@ -1004,19 +1004,16 @@ const Class StringIteratorObject::class_
};
static const JSFunctionSpec string_iterator_methods[] = {
JS_SELF_HOSTED_FN("@@iterator", "StringIteratorIdentity", 0, 0),
JS_SELF_HOSTED_FN("next", "StringIteratorNext", 0, 0),
JS_FS_END
};
-static bool
-CloseLegacyGenerator(JSContext *cx, HandleObject genobj);
-
bool
js::ValueToIterator(JSContext *cx, unsigned flags, MutableHandleValue vp)
{
/* JSITER_KEYVALUE must always come with JSITER_FOREACH */
MOZ_ASSERT_IF(flags & JSITER_KEYVALUE, flags & JSITER_FOREACH);
RootedObject obj(cx);
if (vp.isObject()) {
@@ -1053,17 +1050,24 @@ js::CloseIterator(JSContext *cx, HandleO
/*
* Reset the enumerator; it may still be in the cached iterators
* for this thread, and can be reused.
*/
ni->props_cursor = ni->props_array;
}
} else if (obj->is<LegacyGeneratorObject>()) {
- return CloseLegacyGenerator(cx, obj);
+ Rooted<LegacyGeneratorObject*> genObj(cx, &obj->as<LegacyGeneratorObject>());
+ if (genObj->isClosed())
+ return true;
+ if (genObj->isRunning() || genObj->isClosing()) {
+ // Nothing sensible to do.
+ return true;
+ }
+ return LegacyGeneratorObject::close(cx, obj);
}
return true;
}
bool
js::UnwindIteratorForException(JSContext *cx, HandleObject obj)
{
RootedValue v(cx);
@@ -1506,516 +1510,16 @@ ForOfIterator::materializeArrayIterator(
return false;
index = NOT_ARRAY;
// Result of call to ArrayValuesAt must be an object.
iterator = &args.rval().toObject();
return true;
}
-/*** Generators **********************************************************************************/
-
-template<typename T>
-static void
-FinalizeGenerator(FreeOp *fop, JSObject *obj)
-{
- MOZ_ASSERT(obj->is<T>());
- JSGenerator *gen = obj->as<T>().getGenerator();
- MOZ_ASSERT(gen);
- // gen is open when a script has not called its close method while
- // explicitly manipulating it.
- MOZ_ASSERT(gen->state == JSGEN_NEWBORN ||
- gen->state == JSGEN_CLOSED ||
- gen->state == JSGEN_OPEN);
- // If gen->state is JSGEN_CLOSED, gen->fp may be nullptr.
- if (gen->fp)
- JS_POISON(gen->fp, JS_SWEPT_FRAME_PATTERN, sizeof(InterpreterFrame));
- JS_POISON(gen, JS_SWEPT_FRAME_PATTERN, sizeof(JSGenerator));
- fop->free_(gen);
-}
-
-static void
-MarkGeneratorFrame(JSTracer *trc, JSGenerator *gen)
-{
- gen->obj = MaybeForwarded(gen->obj.get());
- MarkObject(trc, &gen->obj, "Generator Object");
- MarkValueRange(trc,
- HeapValueify(gen->fp->generatorArgsSnapshotBegin()),
- HeapValueify(gen->fp->generatorArgsSnapshotEnd()),
- "Generator Floating Args");
- gen->fp->mark(trc);
- MarkValueRange(trc,
- HeapValueify(gen->fp->generatorSlotsSnapshotBegin()),
- HeapValueify(gen->regs.sp),
- "Generator Floating Stack");
-}
-
-static void
-GeneratorWriteBarrierPre(JSContext *cx, JSGenerator *gen)
-{
- JS::Zone *zone = cx->zone();
- if (zone->needsIncrementalBarrier())
- MarkGeneratorFrame(zone->barrierTracer(), gen);
-}
-
-static void
-GeneratorWriteBarrierPost(JSContext *cx, JSGenerator *gen)
-{
-#ifdef JSGC_GENERATIONAL
- cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(gen->obj);
-#endif
-}
-
-/*
- * Only mark generator frames/slots when the generator is not active on the
- * stack or closed. Barriers when copying onto the stack or closing preserve
- * gc invariants.
- */
-static bool
-GeneratorHasMarkableFrame(JSGenerator *gen)
-{
- return gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN;
-}
-
-/*
- * When a generator is closed, the GC things reachable from the contained frame
- * and slots become unreachable and thus require a write barrier.
- */
-static void
-SetGeneratorClosed(JSContext *cx, JSGenerator *gen)
-{
- MOZ_ASSERT(gen->state != JSGEN_CLOSED);
- if (GeneratorHasMarkableFrame(gen))
- GeneratorWriteBarrierPre(cx, gen);
- gen->state = JSGEN_CLOSED;
-
-#ifdef DEBUG
- MakeRangeGCSafe(gen->fp->generatorArgsSnapshotBegin(),
- gen->fp->generatorArgsSnapshotEnd());
- MakeRangeGCSafe(gen->fp->generatorSlotsSnapshotBegin(),
- gen->regs.sp);
- PodZero(&gen->regs, 1);
- gen->fp = nullptr;
-#endif
-}
-
-template<typename T>
-static void
-TraceGenerator(JSTracer *trc, JSObject *obj)
-{
- MOZ_ASSERT(obj->is<T>());
- JSGenerator *gen = obj->as<T>().getGenerator();
- MOZ_ASSERT(gen);
- if (GeneratorHasMarkableFrame(gen))
- MarkGeneratorFrame(trc, gen);
-}
-
-GeneratorState::GeneratorState(JSContext *cx, JSGenerator *gen, JSGeneratorState futureState)
- : RunState(cx, Generator, gen->fp->script()),
- cx_(cx),
- gen_(gen),
- futureState_(futureState),
- entered_(false)
-{ }
-
-GeneratorState::~GeneratorState()
-{
- gen_->fp->setSuspended();
-
- if (entered_)
- cx_->leaveGenerator(gen_);
-}
-
-InterpreterFrame *
-GeneratorState::pushInterpreterFrame(JSContext *cx)
-{
- /*
- * Write barrier is needed since the generator stack can be updated,
- * and it's not barriered in any other way. We need to do it before
- * gen->state changes, which can cause us to trace the generator
- * differently.
- *
- * We could optimize this by setting a bit on the generator to signify
- * that it has been marked. If this bit has already been set, there is no
- * need to mark again. The bit would have to be reset before the next GC,
- * or else some kind of epoch scheme would have to be used.
- */
- GeneratorWriteBarrierPre(cx, gen_);
- gen_->state = futureState_;
-
- gen_->fp->clearSuspended();
-
- cx->enterGenerator(gen_); /* OOM check above. */
- entered_ = true;
- return gen_->fp;
-}
-
-const Class LegacyGeneratorObject::class_ = {
- "Generator",
- JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
- JS_PropertyStub, /* addProperty */
- JS_DeletePropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- FinalizeGenerator<LegacyGeneratorObject>,
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- TraceGenerator<LegacyGeneratorObject>,
- JS_NULL_CLASS_SPEC,
- {
- nullptr, /* outerObject */
- nullptr, /* innerObject */
- iterator_iteratorObject,
- }
-};
-
-const Class StarGeneratorObject::class_ = {
- "Generator",
- JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
- JS_PropertyStub, /* addProperty */
- JS_DeletePropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- FinalizeGenerator<StarGeneratorObject>,
- nullptr, /* call */
- nullptr, /* hasInstance */
- nullptr, /* construct */
- TraceGenerator<StarGeneratorObject>,
-};
-
-/*
- * Called from the JSOP_GENERATOR case in the interpreter, with fp referring
- * to the frame by which the generator function was activated. Create a new
- * JSGenerator object, which contains its own InterpreterFrame that we populate
- * from *fp. We know that upon return, the JSOP_GENERATOR opcode will return
- * from the activation in fp, so we can steal away fp->callobj and fp->argsobj
- * if they are non-null.
- */
-JSObject *
-js_NewGenerator(JSContext *cx, const InterpreterRegs &stackRegs)
-{
- MOZ_ASSERT(stackRegs.stackDepth() == 0);
- InterpreterFrame *stackfp = stackRegs.fp();
-
- MOZ_ASSERT(stackfp->script()->isGenerator());
-
- Rooted<GlobalObject*> global(cx, &stackfp->global());
- RootedNativeObject obj(cx);
- if (stackfp->script()->isStarGenerator()) {
- RootedValue pval(cx);
- RootedObject fun(cx, stackfp->fun());
- // FIXME: This would be faster if we could avoid doing a lookup to get
- // the prototype for the instance. Bug 906600.
- if (!JSObject::getProperty(cx, fun, fun, cx->names().prototype, &pval))
- return nullptr;
- JSObject *proto = pval.isObject() ? &pval.toObject() : nullptr;
- if (!proto) {
- proto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global);
- if (!proto)
- return nullptr;
- }
- obj = NewNativeObjectWithGivenProto(cx, &StarGeneratorObject::class_, proto, global);
- } else {
- MOZ_ASSERT(stackfp->script()->isLegacyGenerator());
- JSObject *proto = GlobalObject::getOrCreateLegacyGeneratorObjectPrototype(cx, global);
- if (!proto)
- return nullptr;
- obj = NewNativeObjectWithGivenProto(cx, &LegacyGeneratorObject::class_, proto, global);
- }
- if (!obj)
- return nullptr;
-
- /* Load and compute stack slot counts. */
- Value *stackvp = stackfp->generatorArgsSnapshotBegin();
- unsigned vplen = stackfp->generatorArgsSnapshotEnd() - stackvp;
-
- static_assert(sizeof(InterpreterFrame) % sizeof(HeapValue) == 0,
- "The Values stored after InterpreterFrame must be aligned.");
- unsigned nvals = vplen + VALUES_PER_STACK_FRAME + stackfp->script()->nslots();
- JSGenerator *gen = obj->zone()->pod_calloc_with_extra<JSGenerator, HeapValue>(nvals);
- if (!gen)
- return nullptr;
-
- /* Cut up floatingStack space. */
- HeapValue *genvp = gen->stackSnapshot();
- SetValueRangeToUndefined((Value *)genvp, vplen);
-
- InterpreterFrame *genfp = reinterpret_cast<InterpreterFrame *>(genvp + vplen);
-
- /* Initialize JSGenerator. */
- gen->obj.init(obj);
- gen->state = JSGEN_NEWBORN;
- gen->fp = genfp;
- gen->prevGenerator = nullptr;
-
- /* Copy from the stack to the generator's floating frame. */
- gen->regs.rebaseFromTo(stackRegs, *genfp);
- genfp->copyFrameAndValues<InterpreterFrame::DoPostBarrier>(cx, (Value *)genvp, stackfp,
- stackvp, stackRegs.sp);
- genfp->setSuspended();
- obj->setPrivate(gen);
- return obj;
-}
-
-static void
-SetGeneratorClosed(JSContext *cx, JSGenerator *gen);
-
-typedef enum JSGeneratorOp {
- JSGENOP_NEXT,
- JSGENOP_SEND,
- JSGENOP_THROW,
- JSGENOP_CLOSE
-} JSGeneratorOp;
-
-/*
- * Start newborn or restart yielding generator and perform the requested
- * operation inside its frame.
- */
-static bool
-SendToGenerator(JSContext *cx, JSGeneratorOp op, HandleObject obj,
- JSGenerator *gen, HandleValue arg, GeneratorKind generatorKind,
- MutableHandleValue rval)
-{
- MOZ_ASSERT(generatorKind == LegacyGenerator || generatorKind == StarGenerator);
-
- if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NESTING_GENERATOR);
- return false;
- }
-
- JSGeneratorState futureState;
- MOZ_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN);
- switch (op) {
- case JSGENOP_NEXT:
- case JSGENOP_SEND:
- if (gen->state == JSGEN_OPEN) {
- /*
- * Store the argument to send as the result of the yield
- * expression. The generator stack is not barriered, so we need
- * write barriers here.
- */
- HeapValue::writeBarrierPre(gen->regs.sp[-1]);
- gen->regs.sp[-1] = arg;
- HeapValue::writeBarrierPost(gen->regs.sp[-1], &gen->regs.sp[-1]);
- }
- futureState = JSGEN_RUNNING;
- break;
-
- case JSGENOP_THROW:
- cx->setPendingException(arg);
- futureState = JSGEN_RUNNING;
- break;
-
- default:
- MOZ_ASSERT(op == JSGENOP_CLOSE);
- MOZ_ASSERT(generatorKind == LegacyGenerator);
- cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING));
- futureState = JSGEN_CLOSING;
- break;
- }
-
- bool ok;
- {
- GeneratorState state(cx, gen, futureState);
- ok = RunScript(cx, state);
- if (!ok && gen->state == JSGEN_CLOSED)
- return false;
- }
-
- if (gen->fp->isYielding()) {
- /*
- * Yield is ordinarily infallible, but ok can be false here if a
- * Debugger.Frame.onPop hook fails.
- */
- MOZ_ASSERT(gen->state == JSGEN_RUNNING);
- MOZ_ASSERT(op != JSGENOP_CLOSE);
- gen->fp->clearYielding();
- gen->state = JSGEN_OPEN;
- GeneratorWriteBarrierPost(cx, gen);
- rval.set(gen->fp->returnValue());
- return ok;
- }
-
- if (ok) {
- if (generatorKind == StarGenerator) {
- // Star generators return a {value:FOO, done:true} object.
- rval.set(gen->fp->returnValue());
- } else {
- MOZ_ASSERT(generatorKind == LegacyGenerator);
-
- // Otherwise we discard the return value and throw a StopIteration
- // if needed.
- rval.setUndefined();
- if (op != JSGENOP_CLOSE)
- ok = ThrowStopIteration(cx);
- }
- }
-
- SetGeneratorClosed(cx, gen);
- return ok;
-}
-
-MOZ_ALWAYS_INLINE bool
-star_generator_next(JSContext *cx, CallArgs args)
-{
- RootedObject thisObj(cx, &args.thisv().toObject());
- JSGenerator *gen = thisObj->as<StarGeneratorObject>().getGenerator();
-
- if (gen->state == JSGEN_CLOSED) {
- RootedObject obj(cx, CreateItrResultObject(cx, JS::UndefinedHandleValue, true));
- if (!obj)
- return false;
- args.rval().setObject(*obj);
- return true;
- }
-
- return SendToGenerator(cx, JSGENOP_SEND, thisObj, gen, args.get(0), StarGenerator,
- args.rval());
-}
-
-MOZ_ALWAYS_INLINE bool
-star_generator_throw(JSContext *cx, CallArgs args)
-{
- RootedObject thisObj(cx, &args.thisv().toObject());
-
- JSGenerator *gen = thisObj->as<StarGeneratorObject>().getGenerator();
- if (gen->state == JSGEN_CLOSED) {
- cx->setPendingException(args.get(0));
- return false;
- }
-
- return SendToGenerator(cx, JSGENOP_THROW, thisObj, gen, args.get(0), StarGenerator,
- args.rval());
-}
-
-MOZ_ALWAYS_INLINE bool
-legacy_generator_next(JSContext *cx, CallArgs args)
-{
- RootedObject thisObj(cx, &args.thisv().toObject());
-
- JSGenerator *gen = thisObj->as<LegacyGeneratorObject>().getGenerator();
- if (gen->state == JSGEN_CLOSED)
- return ThrowStopIteration(cx);
-
- return SendToGenerator(cx, JSGENOP_SEND, thisObj, gen, args.get(0), LegacyGenerator,
- args.rval());
-}
-
-MOZ_ALWAYS_INLINE bool
-legacy_generator_throw(JSContext *cx, CallArgs args)
-{
- RootedObject thisObj(cx, &args.thisv().toObject());
-
- JSGenerator *gen = thisObj->as<LegacyGeneratorObject>().getGenerator();
- if (gen->state == JSGEN_CLOSED) {
- cx->setPendingException(args.length() >= 1 ? args[0] : UndefinedValue());
- return false;
- }
-
- return SendToGenerator(cx, JSGENOP_THROW, thisObj, gen, args.get(0), LegacyGenerator,
- args.rval());
-}
-
-static bool
-CloseLegacyGenerator(JSContext *cx, HandleObject obj, MutableHandleValue rval)
-{
- MOZ_ASSERT(obj->is<LegacyGeneratorObject>());
-
- JSGenerator *gen = obj->as<LegacyGeneratorObject>().getGenerator();
-
- if (gen->state == JSGEN_CLOSED) {
- rval.setUndefined();
- return true;
- }
-
- if (gen->state == JSGEN_NEWBORN) {
- SetGeneratorClosed(cx, gen);
- rval.setUndefined();
- return true;
- }
-
- return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, JS::UndefinedHandleValue, LegacyGenerator,
- rval);
-}
-
-static bool
-CloseLegacyGenerator(JSContext *cx, HandleObject obj)
-{
- RootedValue rval(cx);
- return CloseLegacyGenerator(cx, obj, &rval);
-}
-
-MOZ_ALWAYS_INLINE bool
-legacy_generator_close(JSContext *cx, CallArgs args)
-{
- RootedObject thisObj(cx, &args.thisv().toObject());
-
- return CloseLegacyGenerator(cx, thisObj, args.rval());
-}
-
-template<typename T>
-MOZ_ALWAYS_INLINE bool
-IsObjectOfType(HandleValue v)
-{
- return v.isObject() && v.toObject().is<T>();
-}
-
-template<typename T, NativeImpl Impl>
-static bool
-NativeMethod(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsObjectOfType<T>, Impl>(cx, args);
-}
-
-#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT)
-#define JS_METHOD(name, T, impl, len, attrs) JS_FN(name, (NativeMethod<T,impl>), len, attrs)
-
-static const JSFunctionSpec star_generator_methods[] = {
- JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
- JS_METHOD("next", StarGeneratorObject, star_generator_next, 1, 0),
- JS_METHOD("throw", StarGeneratorObject, star_generator_throw, 1, 0),
- JS_FS_END
-};
-
-static const JSFunctionSpec legacy_generator_methods[] = {
- JS_SELF_HOSTED_FN("@@iterator", "LegacyGeneratorIteratorShim", 0, 0),
- // "send" is an alias for "next".
- JS_METHOD("next", LegacyGeneratorObject, legacy_generator_next, 1, JSPROP_ROPERM),
- JS_METHOD("send", LegacyGeneratorObject, legacy_generator_next, 1, JSPROP_ROPERM),
- JS_METHOD("throw", LegacyGeneratorObject, legacy_generator_throw, 1, JSPROP_ROPERM),
- JS_METHOD("close", LegacyGeneratorObject, legacy_generator_close, 0, JSPROP_ROPERM),
- JS_FS_END
-};
-
-static JSObject*
-NewSingletonObjectWithObjectPrototype(JSContext *cx, Handle<GlobalObject *> global)
-{
- JSObject *proto = global->getOrCreateObjectPrototype(cx);
- if (!proto)
- return nullptr;
- return NewObjectWithGivenProto(cx, &JSObject::class_, proto, global, SingletonObject);
-}
-
-static JSObject*
-NewSingletonObjectWithFunctionPrototype(JSContext *cx, Handle<GlobalObject *> global)
-{
- JSObject *proto = global->getOrCreateFunctionPrototype(cx);
- if (!proto)
- return nullptr;
- return NewObjectWithGivenProto(cx, &JSObject::class_, proto, global, SingletonObject);
-}
-
/* static */ bool
GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
{
RootedObject iteratorProto(cx);
Value iteratorProtoVal = global->getPrototype(JSProto_Iterator);
if (iteratorProtoVal.isObject()) {
iteratorProto = &iteratorProtoVal.toObject();
} else {
@@ -2058,53 +1562,16 @@ GlobalObject::initIteratorClasses(JSCont
if (global->getSlot(STRING_ITERATOR_PROTO).isUndefined()) {
const Class *cls = &StringIteratorPrototypeClass;
proto = global->createBlankPrototype(cx, cls);
if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, string_iterator_methods))
return false;
global->setReservedSlot(STRING_ITERATOR_PROTO, ObjectValue(*proto));
}
- if (global->getSlot(LEGACY_GENERATOR_OBJECT_PROTO).isUndefined()) {
- proto = NewSingletonObjectWithObjectPrototype(cx, global);
- if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods))
- return false;
- global->setReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO, ObjectValue(*proto));
- }
-
- if (global->getSlot(STAR_GENERATOR_OBJECT_PROTO).isUndefined()) {
- RootedObject genObjectProto(cx, NewSingletonObjectWithObjectPrototype(cx, global));
- if (!genObjectProto)
- return false;
- if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods))
- return false;
-
- RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
- if (!genFunctionProto)
- return false;
- if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto))
- return false;
-
- RootedValue function(cx, global->getConstructor(JSProto_Function));
- if (!function.toObjectOrNull())
- return false;
- RootedAtom name(cx, cx->names().GeneratorFunction);
- RootedObject genFunction(cx, NewFunctionWithProto(cx, NullPtr(), Generator, 1,
- JSFunction::NATIVE_CTOR, global, name,
- &function.toObject()));
- if (!genFunction)
- return false;
- if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
- return false;
-
- global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
- global->setConstructor(JSProto_GeneratorFunction, ObjectValue(*genFunction));
- global->setPrototype(JSProto_GeneratorFunction, ObjectValue(*genFunctionProto));
- }
-
return GlobalObject::initStopIterationClass(cx, global);
}
/* static */ bool
GlobalObject::initStopIterationClass(JSContext *cx, Handle<GlobalObject *> global)
{
if (!global->getPrototype(JSProto_StopIteration).isUndefined())
return true;
@@ -2123,10 +1590,12 @@ GlobalObject::initStopIterationClass(JSC
}
JSObject *
js_InitIteratorClasses(JSContext *cx, HandleObject obj)
{
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
if (!GlobalObject::initIteratorClasses(cx, global))
return nullptr;
+ if (!GlobalObject::initGeneratorClasses(cx, global))
+ return nullptr;
return global->getIteratorPrototype();
}
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -214,45 +214,12 @@ ThrowStopIteration(JSContext *cx);
* Create an object of the form { value: VALUE, done: DONE }.
* ES6 draft from 2013-09-05, section 25.4.3.4.
*/
extern JSObject *
CreateItrResultObject(JSContext *cx, HandleValue value, bool done);
} /* namespace js */
-/*
- * Generator state codes.
- */
-enum JSGeneratorState
-{
- JSGEN_NEWBORN, /* not yet started */
- JSGEN_OPEN, /* started by a .next() or .send(undefined) call */
- JSGEN_RUNNING, /* currently executing via .next(), etc., call */
- JSGEN_CLOSING, /* close method is doing asynchronous return */
- JSGEN_CLOSED /* closed, cannot be started or closed again */
-};
-
-struct JSGenerator
-{
- js::HeapPtrObject obj;
- JSGeneratorState state;
- js::InterpreterRegs regs;
- JSGenerator *prevGenerator;
- js::InterpreterFrame *fp;
-#if JS_BITS_PER_WORD == 32
- uint32_t padding;
-#endif
-
- js::HeapValue *stackSnapshot() {
- static_assert(sizeof(JSGenerator) % sizeof(js::HeapValue) == 0,
- "The generator must have Value alignment for JIT access.");
- return reinterpret_cast<js::HeapValue *>(this + 1);
- }
-};
-
-extern JSObject *
-js_NewGenerator(JSContext *cx, const js::InterpreterRegs ®s);
-
extern JSObject *
js_InitIteratorClasses(JSContext *cx, js::HandleObject obj);
#endif /* jsiter_h */
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -4245,18 +4245,16 @@ js_DumpInterpreterFrame(JSContext *cx, I
fprintf(stderr, " flags:");
if (i.isConstructing())
fprintf(stderr, " constructing");
if (!i.isJit() && i.interpFrame()->isDebuggerFrame())
fprintf(stderr, " debugger");
if (i.isEvalFrame())
fprintf(stderr, " eval");
- if (!i.isJit() && i.interpFrame()->isYielding())
- fprintf(stderr, " yielding");
if (!i.isJit() && i.interpFrame()->isGeneratorFrame())
fprintf(stderr, " generator");
fputc('\n', stderr);
fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) i.scopeChain());
fputc('\n', stderr);
}
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -293,16 +293,18 @@ IsJumpOpcode(JSOp op)
static inline bool
BytecodeFallsThrough(JSOp op)
{
switch (op) {
case JSOP_GOTO:
case JSOP_DEFAULT:
case JSOP_RETURN:
case JSOP_RETRVAL:
+ case JSOP_FINALYIELD:
+ case JSOP_FINALYIELDRVAL:
case JSOP_THROW:
case JSOP_TABLESWITCH:
return false;
case JSOP_GOSUB:
/* These fall through indirectly, after executing a 'finally'. */
return true;
default:
return true;
@@ -594,18 +596,28 @@ BytecodeFlowsToBitop(jsbytecode *pc)
extern bool
IsValidBytecodeOffset(JSContext *cx, JSScript *script, size_t offset);
inline bool
FlowsIntoNext(JSOp op)
{
/* JSOP_YIELD is considered to flow into the next instruction, like JSOP_CALL. */
- return op != JSOP_RETRVAL && op != JSOP_RETURN && op != JSOP_THROW &&
- op != JSOP_GOTO && op != JSOP_RETSUB;
+ switch (op) {
+ case JSOP_RETRVAL:
+ case JSOP_RETURN:
+ case JSOP_THROW:
+ case JSOP_GOTO:
+ case JSOP_RETSUB:
+ case JSOP_FINALYIELD:
+ case JSOP_FINALYIELDRVAL:
+ return false;
+ default:
+ return true;
+ }
}
inline bool
IsArgOp(JSOp op)
{
return JOF_OPTYPE(op) == JOF_QARG;
}
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -28,67 +28,130 @@ using JS::MutableHandleValue;
using JS::NativeImpl;
using JS::PrivateValue;
using JS::Value;
class RegExpGuard;
class JS_FRIEND_API(Wrapper);
/*
- * A proxy is a JSObject that implements generic behavior by providing custom
- * implementations for each object trap. The implementation for each trap is
- * provided by a C++ object stored on the proxy, known as its handler.
+ * A proxy is a JSObject with highly customizable behavior. ES6 specifies a
+ * single kind of proxy, but the customization mechanisms we use to implement
+ * ES6 Proxy objects are also useful wherever an object with weird behavior is
+ * wanted. Proxies are used to implement:
+ *
+ * - the scope objects used by the Debugger's frame.eval() method
+ * (see js::GetDebugScopeForFunction)
+ *
+ * - the khuey hack, whereby a whole compartment can be blown away
+ * even if other compartments hold references to objects in it
+ * (see js::NukeCrossCompartmentWrappers)
*
- * A major use case for proxies is to forward each trap to another object,
- * known as its target. The target can be an arbitrary C++ object. Not every
- * proxy has the notion of a target, however.
+ * - XPConnect security wrappers, which protect chrome from malicious content
+ * (js/xpconnect/wrappers)
+ *
+ * - DOM objects with special property behavior, like named getters
+ * (dom/bindings/Codegen.py generates these proxies from WebIDL)
*
- * Proxy traps are grouped into fundamental and derived traps. Every proxy has
- * to at least provide implementations for the fundamental traps, but the
- * derived traps can be implemented in terms of the fundamental ones
- * BaseProxyHandler provides implementations of the derived traps in terms of
- * the (pure virtual) fundamental traps.
+ * - semi-transparent use of objects that live in other processes
+ * (CPOWs, implemented in js/ipc)
+ *
+ * ### Proxies and internal methods
+ *
+ * ES6 draft rev 27 (24 August 2014) specifies 14 internal methods. The runtime
+ * semantics of just about everything a script can do to an object is specified
+ * in terms of these internal methods. For example:
*
- * In addition to the normal traps, there are two models for proxy prototype
- * chains. First, proxies may opt to use the standard prototype mechanism used
- * throughout the engine. To do so, simply pass a prototype to NewProxyObject()
- * at creation time. All prototype accesses will then "just work" to treat the
- * proxy as a "normal" object. Alternatively, if instead the proxy wishes to
- * implement more complicated prototype semantics (if, for example, it wants to
- * delegate the prototype lookup to a wrapped object), it may pass Proxy::LazyProto
- * as the prototype at create time and opt in to the trapped prototype system,
- * which guarantees that their trap will be called on any and every prototype
- * chain access of the object.
+ * JS code ES6 internal method that gets called
+ * --------------------------- --------------------------------
+ * obj.prop obj.[[Get]](obj, "prop")
+ * "prop" in obj obj.[[HasProperty]]("prop")
+ * new obj() obj.[[Construct]](<empty argument List>)
+ * for (k in obj) {} obj.[[Enumerate]]()
+ *
+ * With regard to the implementation of these internal methods, there are three
+ * very different kinds of object in SpiderMonkey.
+ *
+ * 1. Native objects' internal methods are implemented in js::baseops in
+ * vm/NativeObject.cpp, with duplicate (but functionally identical)
+ * implementations scattered through the ICs and JITs.
*
- * This system is implemented with two traps: {get,set}PrototypeOf. The default
- * implementation of setPrototypeOf throws a TypeError. Since it is not possible
- * to create an object without a sense of prototype chain, handler implementors
- * must provide a getPrototypeOf trap if opting in to the dynamic prototype system.
+ * 2. Certain non-native objects have internal methods that are implemented as
+ * magical js::ObjectOps hooks. We're trying to get rid of these.
+ *
+ * 3. All other objects are proxies. A proxy's internal methods are
+ * implemented in C++, as the virtual methods of a C++ object stored on the
+ * proxy, known as its handler.
+ *
+ * This means that just about anything you do to a proxy will end up going
+ * through a C++ virtual method call. Possibly several. There's no reason the
+ * JITs and ICs can't specialize for particular proxies, based on the handler;
+ * but currently we don't do much of this, so the virtual method overhead
+ * typically is actually incurred.
+ *
+ * ### The proxy handler hierarchy
+ *
+ * A major use case for proxies is to forward each internal method call to
+ * another object, known as its target. The target can be an arbitrary JS
+ * object. Not every proxy has the notion of a target, however.
*
* To minimize code duplication, a set of abstract proxy handler classes is
- * provided, from which other handlers may inherit. These abstract classes
- * are organized in the following hierarchy:
+ * provided, from which other handlers may inherit. These abstract classes are
+ * organized in the following hierarchy:
+ *
+ * BaseProxyHandler
+ * |
+ * DirectProxyHandler // has a target
+ * |
+ * Wrapper // can be unwrapped, revealing target
+ * | // (see js::CheckedUnwrap)
+ * |
+ * CrossCompartmentWrapper // target is in another compartment;
+ * // implements membrane between compartments
+ *
+ * Example: Some DOM objects (including all the arraylike DOM objects) are
+ * implemented as proxies. Since these objects don't need to forward operations
+ * to any underlying JS object, DOMJSProxyHandler directly subclasses
+ * BaseProxyHandler.
+ *
+ * Gecko's security wrappers are examples of cross-compartment wrappers.
*
- * BaseProxyHandler
- * |
- * DirectProxyHandler
- * |
- * Wrapper
+ * ### Proxy prototype chains
+ *
+ * In addition to the normal methods, there are two models for proxy prototype
+ * chains.
+ *
+ * 1. Proxies can use the standard prototype mechanism used throughout the
+ * engine. To do so, simply pass a prototype to NewProxyObject() at
+ * creation time. All prototype accesses will then "just work" to treat the
+ * proxy as a "normal" object.
+ *
+ * 2. A proxy can implement more complicated prototype semantics (if, for
+ * example, it wants to delegate the prototype lookup to a wrapped object)
+ * by passing Proxy::LazyProto as the prototype at create time. This
+ * guarantees that the getPrototypeOf() handler method will be called every
+ * time the object's prototype chain is accessed.
+ *
+ * This system is implemented with two methods: {get,set}PrototypeOf. The
+ * default implementation of setPrototypeOf throws a TypeError. Since it is
+ * not possible to create an object without a sense of prototype chain,
+ * handlers must implement getPrototypeOf if opting in to the dynamic
+ * prototype system.
*/
/*
* BaseProxyHandler is the most generic kind of proxy handler. It does not make
* any assumptions about the target. Consequently, it does not provide any
- * default implementation for the fundamental traps. It does, however, implement
- * the derived traps in terms of the fundamental ones. This allows consumers of
- * this class to define any custom behavior they want.
+ * default implementation for most methods. As a convenience, a few high-level
+ * methods, like get() and set(), are given default implementations that work by
+ * calling the low-level methods, like getOwnPropertyDescriptor().
*
- * Important: If you add a trap here, you should probably also add a Proxy::foo
- * entry point with an AutoEnterPolicy. If you don't, you need an explicit
- * override for the trap in SecurityWrapper. See bug 945826 comment 0.
+ * Important: If you add a method here, you should probably also add a
+ * Proxy::foo entry point with an AutoEnterPolicy. If you don't, you need an
+ * explicit override for the method in SecurityWrapper. See bug 945826 comment 0.
*/
class JS_FRIEND_API(BaseProxyHandler)
{
/*
* Sometimes it's desirable to designate groups of proxy handlers as "similar".
* For this, we use the notion of a "family": A consumer-provided opaque pointer
* that designates the larger group to which this proxy belongs.
*
@@ -98,19 +161,20 @@ class JS_FRIEND_API(BaseProxyHandler)
const void *mFamily;
/*
* Proxy handlers can use mHasPrototype to request the following special
* treatment from the JS engine:
*
* - When mHasPrototype is true, the engine never calls these methods:
* getPropertyDescriptor, has, set, enumerate, iterate. Instead, for
- * these operations, it calls the "own" traps like
- * getOwnPropertyDescriptor, hasOwn, defineProperty, keys, etc., and
- * consults the prototype chain if needed.
+ * these operations, it calls the "own" methods like
+ * getOwnPropertyDescriptor, hasOwn, defineProperty,
+ * getOwnEnumerablePropertyKeys, etc., and consults the prototype chain
+ * if needed.
*
* - When mHasPrototype is true, the engine calls handler->get() only if
* handler->hasOwn() says an own property exists on the proxy. If not,
* it consults the prototype chain.
*
* This is useful because it frees the ProxyHandler from having to implement
* any behavior having to do with the prototype chain.
*/
@@ -150,24 +214,24 @@ class JS_FRIEND_API(BaseProxyHandler)
virtual bool finalizeInBackground(Value priv) const {
/*
* Called on creation of a proxy to determine whether its finalize
* method can be finalized on the background thread.
*/
return true;
}
- /* Policy enforcement traps.
+ /* Policy enforcement methods.
*
* enter() allows the policy to specify whether the caller may perform |act|
* on the proxy's |id| property. In the case when |act| is CALL, |id| is
* generally JSID_VOID.
*
* The |act| parameter to enter() specifies the action being performed.
- * If |bp| is false, the trap suggests that the caller throw (though it
+ * If |bp| is false, the method suggests that the caller throw (though it
* may still decide to squelch the error).
*
* We make these OR-able so that assertEnteredPolicy can pass a union of them.
* For example, get{,Own}PropertyDescriptor is invoked by calls to ::get()
* ::set(), in addition to being invoked on its own, so there are several
* valid Actions that could have been entered.
*/
typedef uint32_t Action;
@@ -178,56 +242,83 @@ class JS_FRIEND_API(BaseProxyHandler)
CALL = 0x04,
ENUMERATE = 0x08,
GET_PROPERTY_DESCRIPTOR = 0x10
};
virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,
bool *bp) const;
- /* ES5 Harmony fundamental proxy traps. */
- virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const = 0;
- virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
- MutableHandle<JSPropertyDescriptor> desc) const = 0;
- virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
- HandleId id, MutableHandle<JSPropertyDescriptor> desc) const = 0;
+ /* Standard internal methods. */
+ virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+ MutableHandle<JSPropertyDescriptor> desc) const = 0;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const = 0;
virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const = 0;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const = 0;
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const = 0;
+ virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const = 0;
+ virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const = 0;
- /* ES5 Harmony derived proxy traps. */
+ /*
+ * These methods are standard, but the engine does not normally call them.
+ * They're opt-in. See "Proxy prototype chains" above.
+ *
+ * getPrototypeOf() crashes if called. setPrototypeOf() throws a TypeError.
+ */
+ virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const;
+ virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp) const;
+
+ /*
+ * These standard internal methods are implemented, as a convenience, so
+ * that ProxyHandler subclasses don't have to provide every single method.
+ *
+ * The base-class implementations work by calling getPropertyDescriptor().
+ * They do not follow any standard. When in doubt, override them.
+ */
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const;
- virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const;
- virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const;
+
+ /*
+ * [[Call]] and [[Construct]] are standard internal methods but according
+ * to the spec, they are not present on every object.
+ *
+ * SpiderMonkey never calls a proxy's call()/construct() internal method
+ * unless isCallable()/isConstructor() returns true for that proxy.
+ *
+ * BaseProxyHandler::isCallable()/isConstructor() always return false, and
+ * BaseProxyHandler::call()/construct() crash if called. So if you're
+ * creating a kind of that is never callable, you don't have to override
+ * anything, but otherwise you probably want to override all four.
+ */
+ virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const;
+ virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const;
+
+ /* SpiderMonkey extensions. */
+ virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+ MutableHandle<JSPropertyDescriptor> desc) const = 0;
+ virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const;
+ virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const;
virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const;
-
- /* Spidermonkey extensions. */
- virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const = 0;
- virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const;
- virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) const;
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp) const;
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const;
virtual const char *className(JSContext *cx, HandleObject proxy) const;
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const;
virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const;
virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) const;
virtual void finalize(JSFreeOp *fop, JSObject *proxy) const;
virtual void objectMoved(JSObject *proxy, const JSObject *old) const;
- virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const;
- virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp) const;
// Allow proxies, wrappers in particular, to specify callability at runtime.
// Note: These do not take const JSObject *, but they do in spirit.
// We are not prepared to do this, as there's little const correctness
// in the external APIs that handle proxies.
virtual bool isCallable(JSObject *obj) const;
virtual bool isConstructor(JSObject *obj) const;
@@ -241,84 +332,82 @@ class JS_FRIEND_API(BaseProxyHandler)
HandleObject result) const;
/* See comment for weakmapKeyDelegateOp in js/Class.h. */
virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const;
virtual bool isScripted() const { return false; }
};
/*
- * DirectProxyHandler includes a notion of a target object. All traps are
+ * DirectProxyHandler includes a notion of a target object. All methods are
* reimplemented such that they forward their behavior to the target. This
* allows consumers of this class to forward to another object as transparently
* and efficiently as possible.
*
- * Important: If you add a trap implementation here, you probably also need to
- * add an override in CrossCompartmentWrapper. If you don't, you risk
+ * Important: If you add a method implementation here, you probably also need
+ * to add an override in CrossCompartmentWrapper. If you don't, you risk
* compartment mismatches. See bug 945826 comment 0.
*/
class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
{
public:
explicit MOZ_CONSTEXPR DirectProxyHandler(const void *aFamily, bool aHasPrototype = false,
bool aHasSecurityPolicy = false)
: BaseProxyHandler(aFamily, aHasPrototype, aHasSecurityPolicy)
{ }
- /* ES5 Harmony fundamental proxy traps. */
- virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
- virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
- MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ /* Standard internal methods. */
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const MOZ_OVERRIDE;
-
- /* ES5 Harmony derived proxy traps. */
+ virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
+ virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
+ virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
+ MutableHandleObject protop) const MOZ_OVERRIDE;
+ virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
+ bool *bp) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id,
bool *bp) const MOZ_OVERRIDE;
- virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id,
- bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
- virtual bool keys(JSContext *cx, HandleObject proxy,
- AutoIdVector &props) const MOZ_OVERRIDE;
+ virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
+ virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
+
+ /* SpiderMonkey extensions. */
+ virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+ MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id,
+ bool *bp) const MOZ_OVERRIDE;
+ virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const MOZ_OVERRIDE;
-
- /* Spidermonkey extensions. */
- virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
- virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
- virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) const MOZ_OVERRIDE;
- virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
- MutableHandleObject protop) const MOZ_OVERRIDE;
- virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
- bool *bp) const MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
JSContext *cx) const MOZ_OVERRIDE;
virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy,
unsigned indent) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy,
RegExpGuard *g) const MOZ_OVERRIDE;
virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const;
+ virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const MOZ_OVERRIDE;
- virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
};
extern JS_FRIEND_DATA(const js::Class* const) ProxyClassPtr;
inline bool IsProxy(JSObject *obj)
{
return GetObjectClass(obj)->isProxy();
}
@@ -464,18 +553,18 @@ class JS_FRIEND_API(AutoEnterPolicy)
#ifdef JS_DEBUG
JSContext *context;
mozilla::Maybe<HandleObject> enteredProxy;
mozilla::Maybe<HandleId> enteredId;
Action enteredAction;
// NB: We explicitly don't track the entered action here, because sometimes
- // SET traps do an implicit GET during their implementation, leading to
- // spurious assertions.
+ // set() methods do an implicit get() during their implementation, leading
+ // to spurious assertions.
AutoEnterPolicy *prev;
void recordEnter(JSContext *cx, HandleObject proxy, HandleId id, Action act);
void recordLeave();
friend JS_FRIEND_API(void) assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id, Action act);
#else
inline void recordEnter(JSContext *cx, JSObject *proxy, jsid id, Action act) {}
inline void recordLeave() {}
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -2660,21 +2660,21 @@ ASTSerializer::generatorExpression(Parse
if (next->isKind(PNK_IF)) {
if (!optExpression(next->pn_kid1, &filter))
return false;
next = next->pn_kid2;
}
LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
next->pn_kid->isKind(PNK_YIELD) &&
- next->pn_kid->pn_kid);
+ next->pn_kid->pn_left);
RootedValue body(cx);
- return expression(next->pn_kid->pn_kid, &body) &&
+ return expression(next->pn_kid->pn_left, &body) &&
builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst);
}
bool
ASTSerializer::expression(ParseNode *pn, MutableHandleValue dst)
{
JS_CHECK_RECURSION(cx, return false);
switch (pn->getKind()) {
@@ -2991,29 +2991,29 @@ ASTSerializer::expression(ParseNode *pn,
case PNK_NUMBER:
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
return literal(pn, dst);
case PNK_YIELD_STAR:
{
- MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
+ MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
RootedValue arg(cx);
- return expression(pn->pn_kid, &arg) &&
+ return expression(pn->pn_left, &arg) &&
builder.yieldExpression(arg, Delegating, &pn->pn_pos, dst);
}
case PNK_YIELD:
{
- MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
+ MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
RootedValue arg(cx);
- return optExpression(pn->pn_kid, &arg) &&
+ return optExpression(pn->pn_left, &arg) &&
builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
}
case PNK_ARRAYCOMP:
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_head->pn_pos));
/* NB: it's no longer the case that pn_count could be 2. */
LOCAL_ASSERT(pn->pn_count == 1);
@@ -3308,16 +3308,22 @@ ASTSerializer::functionArgsAndBody(Parse
}
case PNK_STATEMENTLIST: /* statement closure */
{
ParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
? pnbody->pn_head->pn_next
: pnbody->pn_head;
+ // Skip over initial yield in generator.
+ if (pnstart && pnstart->isKind(PNK_YIELD)) {
+ MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
+ pnstart = pnstart->pn_next;
+ }
+
return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
functionBody(pnstart, &pnbody->pn_pos, body);
}
default:
LOCAL_NOT_REACHED("unexpected function contents");
}
}
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -41,22 +41,23 @@ class MOZ_STACK_CLASS WrapperOptions : p
}
private:
mozilla::Maybe<JS::RootedObject> proto_;
};
/*
* A wrapper is a proxy with a target object to which it generally forwards
- * operations, but may restrict access to certain operations or instrument
- * the trap operations in various ways. A wrapper is distinct from a Direct Proxy
- * Handler in the sense that it can be "unwrapped" in C++, exposing the underlying
+ * operations, but may restrict access to certain operations or instrument the
+ * methods in various ways. A wrapper is distinct from a Direct Proxy Handler
+ * in the sense that it can be "unwrapped" in C++, exposing the underlying
* object (Direct Proxy Handlers have an underlying target object, but don't
* expect to expose this object via any kind of unwrapping operation). Callers
- * should be careful to avoid unwrapping security wrappers in the wrong context.
+ * should be careful to avoid unwrapping security wrappers in the wrong
+ * context.
*/
class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
{
unsigned mFlags;
public:
using BaseProxyHandler::Action;
@@ -107,59 +108,58 @@ WrapperOptions::proto() const
class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
{
public:
explicit MOZ_CONSTEXPR CrossCompartmentWrapper(unsigned aFlags, bool aHasPrototype = false,
bool aHasSecurityPolicy = false)
: Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy)
{ }
- /* ES5 Harmony fundamental wrapper traps. */
- virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE;
- virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
- MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ /* Standard internal methods. */
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE;
-
- /* ES5 Harmony derived wrapper traps. */
+ virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE;
+ virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE;
+ virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
+ MutableHandleObject protop) const MOZ_OVERRIDE;
+ virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
+ bool *bp) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
- virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject wrapper, HandleObject receiver,
HandleId id, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject wrapper, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
- virtual bool keys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE;
+ virtual bool call(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;
+ virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;
+
+ /* SpiderMonkey extensions. */
+ virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
+ MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
+ virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
+ AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool iterate(JSContext *cx, HandleObject wrapper, unsigned flags,
MutableHandleValue vp) const MOZ_OVERRIDE;
-
- /* Spidermonkey extensions. */
- virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE;
- virtual bool call(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;
- virtual bool construct(JSContext *cx, HandleObject wrapper, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject wrapper, MutableHandleValue v,
bool *bp) const MOZ_OVERRIDE;
virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, HandleObject wrapper,
unsigned indent) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
MutableHandleValue vp) const MOZ_OVERRIDE;
- virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
- MutableHandleObject protop) const MOZ_OVERRIDE;
- virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
- bool *bp) const MOZ_OVERRIDE;
static const CrossCompartmentWrapper singleton;
static const CrossCompartmentWrapper singletonWithPrototype;
};
/*
* Base class for security wrappers. A security wrapper is potentially hiding
* all or part of some wrapped object thus SecurityWrapper defaults to denying
@@ -172,41 +172,42 @@ class JS_FRIEND_API(CrossCompartmentWrap
template <class Base>
class JS_FRIEND_API(SecurityWrapper) : public Base
{
public:
explicit MOZ_CONSTEXPR SecurityWrapper(unsigned flags, bool hasPrototype = false)
: Base(flags, hasPrototype, /* hasSecurityPolicy = */ true)
{ }
- virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE;
- virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE;
virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Wrapper::Action act,
bool *bp) const MOZ_OVERRIDE;
+
+ virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
+ MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ virtual bool isExtensible(JSContext *cx, HandleObject wrapper, bool *extensible) const MOZ_OVERRIDE;
+ virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) const MOZ_OVERRIDE;
+ virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
+ bool *bp) const MOZ_OVERRIDE;
+
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
- virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
- MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
JSContext *cx) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const MOZ_OVERRIDE;
- virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
- MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
+ MutableHandleValue vp) const MOZ_OVERRIDE;
- virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto,
- bool *bp) const MOZ_OVERRIDE;
+ // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
+ // against.
virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
JS::HandleObject callable) const MOZ_OVERRIDE;
virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) const MOZ_OVERRIDE;
- // Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
- // against.
-
/*
* Allow our subclasses to select the superclass behavior they want without
* needing to specify an exact superclass.
*/
typedef Base Permissive;
typedef SecurityWrapper<Base> Restrictive;
};
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -238,16 +238,17 @@ UNIFIED_SOURCES += [
'vm/CallNonGenericMethod.cpp',
'vm/CharacterEncoding.cpp',
'vm/Compression.cpp',
'vm/DateTime.cpp',
'vm/Debugger.cpp',
'vm/DebuggerMemory.cpp',
'vm/ErrorObject.cpp',
'vm/ForkJoin.cpp',
+ 'vm/GeneratorObject.cpp',
'vm/GlobalObject.cpp',
'vm/HelperThreads.cpp',
'vm/Id.cpp',
'vm/Interpreter.cpp',
'vm/JSONParser.cpp',
'vm/MemoryMetrics.cpp',
'vm/Monitor.cpp',
'vm/NativeObject.cpp',
--- a/js/src/proxy/BaseProxyHandler.cpp
+++ b/js/src/proxy/BaseProxyHandler.cpp
@@ -160,17 +160,18 @@ js::SetPropertyIgnoringNamedGetter(JSCon
desc.value().set(vp.get());
desc.setAttributes(JSPROP_ENUMERATE);
desc.setGetter(nullptr);
desc.setSetter(nullptr); // Pick up the class getter/setter.
return handler->defineProperty(cx, receiver, id, desc);
}
bool
-BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
+BaseProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
MOZ_ASSERT(props.length() == 0);
if (!ownPropertyKeys(cx, proxy, props))
return false;
/* Select only the enumerable properties through in-place iteration. */
@@ -199,17 +200,17 @@ BaseProxyHandler::keys(JSContext *cx, Ha
bool
BaseProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
AutoIdVector props(cx);
if ((flags & JSITER_OWNONLY)
- ? !keys(cx, proxy, props)
+ ? !getOwnEnumerablePropertyKeys(cx, proxy, props)
: !enumerate(cx, proxy, props)) {
return false;
}
return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
}
bool
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -146,21 +146,22 @@ CrossCompartmentWrapper::set(JSContext *
PIERCE(cx, wrapper,
cx->compartment()->wrap(cx, &receiverCopy) &&
cx->compartment()->wrap(cx, vp),
Wrapper::set(cx, wrapper, receiverCopy, id, strict, vp),
NOTHING);
}
bool
-CrossCompartmentWrapper::keys(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const
+CrossCompartmentWrapper::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject wrapper,
+ AutoIdVector &props) const
{
PIERCE(cx, wrapper,
NOTHING,
- Wrapper::keys(cx, wrapper, props),
+ Wrapper::getOwnEnumerablePropertyKeys(cx, wrapper, props),
NOTHING);
}
/*
* We can reify non-escaping iterator objects instead of having to wrap them. This
* allows fast iteration over objects across a compartment boundary.
*/
static bool
--- a/js/src/proxy/DeadObjectProxy.h
+++ b/js/src/proxy/DeadObjectProxy.h
@@ -13,46 +13,46 @@ namespace js {
class DeadObjectProxy : public BaseProxyHandler
{
public:
explicit MOZ_CONSTEXPR DeadObjectProxy()
: BaseProxyHandler(&family)
{ }
- /* ES5 Harmony fundamental wrapper traps. */
- virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
- virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
- MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ /* Standard internal methods. */
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool ownPropertyKeys(JSContext *cx, HandleObject wrapper,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) const MOZ_OVERRIDE;
-
- /* Spidermonkey extensions. */
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
+ virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
+ virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
+ MutableHandleObject protop) const MOZ_OVERRIDE;
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
+
+ /* SpiderMonkey extensions. */
+ virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
+ MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp) const MOZ_OVERRIDE;
virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
JSContext *cx) const MOZ_OVERRIDE;
virtual const char *className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint,
MutableHandleValue vp) const MOZ_OVERRIDE;
- virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy,
- MutableHandleObject protop) const MOZ_OVERRIDE;
static const char family;
static const DeadObjectProxy singleton;
};
bool
IsDeadProxyObject(JSObject *obj);
--- a/js/src/proxy/DirectProxyHandler.cpp
+++ b/js/src/proxy/DirectProxyHandler.cpp
@@ -213,17 +213,18 @@ DirectProxyHandler::set(JSContext *cx, H
HandleId id, bool strict, MutableHandleValue vp) const
{
assertEnteredPolicy(cx, proxy, id, SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::setGeneric(cx, target, receiver, id, vp, strict);
}
bool
-DirectProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
+DirectProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const
{
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetPropertyKeys(cx, target, JSITER_OWNONLY, &props);
}
bool
DirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -211,17 +211,17 @@ Proxy::enumerate(JSContext *cx, HandleOb
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
if (!policy.allowed())
return policy.returnValue();
if (!handler->hasPrototype())
return proxy->as<ProxyObject>().handler()->enumerate(cx, proxy, props);
- if (!handler->keys(cx, proxy, props))
+ if (!handler->getOwnEnumerablePropertyKeys(cx, proxy, props))
return false;
AutoIdVector protoProps(cx);
INVOKE_ON_PROTOTYPE(cx, handler, proxy,
GetPropertyKeys(cx, proto, 0, &protoProps) &&
AppendUnique(cx, props, protoProps));
}
bool
@@ -336,24 +336,24 @@ Proxy::set(JSContext *cx, HandleObject p
newDesc.setAttributes(desc.attributes());
else
newDesc.setAttributes(JSPROP_ENUMERATE);
newDesc.value().set(vp);
return handler->defineProperty(cx, receiver, id, &newDesc);
}
bool
-Proxy::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
+Proxy::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
if (!policy.allowed())
return policy.returnValue();
- return handler->keys(cx, proxy, props);
+ return handler->getOwnEnumerablePropertyKeys(cx, proxy, props);
}
bool
Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
vp.setUndefined(); // default result if we refuse to perform this action
@@ -367,17 +367,17 @@ Proxy::iterate(JSContext *cx, HandleObje
return policy.returnValue() &&
EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
}
return handler->iterate(cx, proxy, flags, vp);
}
AutoIdVector props(cx);
// The other Proxy::foo methods do the prototype-aware work for us here.
if ((flags & JSITER_OWNONLY)
- ? !Proxy::keys(cx, proxy, props)
+ ? !Proxy::getOwnEnumerablePropertyKeys(cx, proxy, props)
: !Proxy::enumerate(cx, proxy, props)) {
return false;
}
return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
}
bool
Proxy::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
--- a/js/src/proxy/Proxy.h
+++ b/js/src/proxy/Proxy.h
@@ -13,63 +13,62 @@
namespace js {
class RegExpGuard;
/*
* Dispatch point for handlers that executes the appropriate C++ or scripted traps.
*
- * Important: All proxy traps need either (a) an AutoEnterPolicy in their
+ * Important: All proxy methods need either (a) an AutoEnterPolicy in their
* Proxy::foo entry point below or (b) an override in SecurityWrapper. See bug
* 945826 comment 0.
*/
class Proxy
{
public:
- /* ES5 Harmony fundamental proxy traps. */
- static bool preventExtensions(JSContext *cx, HandleObject proxy);
- static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
- MutableHandle<JSPropertyDescriptor> desc);
- static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
- MutableHandleValue vp);
+ /* Standard internal methods. */
static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandleValue vp);
static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc);
static bool ownPropertyKeys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props);
-
- /* ES5 Harmony derived proxy traps. */
+ static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible);
+ static bool preventExtensions(JSContext *cx, HandleObject proxy);
+ static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
+ static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
- static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp);
static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp);
- static bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
- static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp);
-
- /* Spidermonkey extensions. */
- static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible);
static bool call(JSContext *cx, HandleObject proxy, const CallArgs &args);
static bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args);
+
+ /* SpiderMonkey extensions. */
+ static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+ MutableHandle<JSPropertyDescriptor> desc);
+ static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+ MutableHandleValue vp);
+ static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
+ static bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props);
+ static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp);
static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
static const char *className(JSContext *cx, HandleObject proxy);
static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
static bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp);
static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
- static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
- static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable);
static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id);
static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end,
HandleObject result);
/* IC entry path for handling __noSuchMethod__ on access. */
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -167,17 +167,18 @@ ReportInvalidTrapResult(JSContext *cx, J
RootedValue v(cx, ObjectOrNullValue(proxy));
JSAutoByteString bytes;
if (!AtomToPrintableString(cx, atom, &bytes))
return;
js_ReportValueError2(cx, JSMSG_INVALID_TRAP_RESULT, JSDVG_IGNORE_STACK, v,
js::NullPtr(), bytes.ptr());
}
-// This function is shared between ownPropertyKeys, enumerate, and keys
+// This function is shared between ownPropertyKeys, enumerate, and
+// getOwnEnumerablePropertyKeys.
static bool
ArrayToIdVector(JSContext *cx, HandleObject proxy, HandleObject target, HandleValue v,
AutoIdVector &props, unsigned flags, JSAtom *trapName_)
{
MOZ_ASSERT(v.isObject());
RootedObject array(cx, &v.toObject());
RootedAtom trapName(cx, trapName_);
--- a/js/src/proxy/ScriptedDirectProxyHandler.h
+++ b/js/src/proxy/ScriptedDirectProxyHandler.h
@@ -13,52 +13,53 @@ namespace js {
/* Derived class for all scripted direct proxy handlers. */
class ScriptedDirectProxyHandler : public DirectProxyHandler {
public:
MOZ_CONSTEXPR ScriptedDirectProxyHandler()
: DirectProxyHandler(&family)
{ }
- /* ES5 Harmony fundamental proxy traps. */
- virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
- virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
- MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ /* Standard internal methods. */
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
-
- /* ES5 Harmony derived proxy traps. */
+ virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
+ virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
- virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE {
- return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
- }
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
- // Kick keys out to getOwnPropertyName and then filter. [[GetOwnProperty]] could potentially
- // change the enumerability of the target's properties.
- virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE {
- return BaseProxyHandler::keys(cx, proxy, props);
+ virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
+ virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
+
+ /* SpiderMonkey extensions. */
+ virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+ MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE {
+ return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
+ }
+
+
+ // Kick getOwnEnumerablePropertyKeys out to ownPropertyKeys and then
+ // filter. [[GetOwnProperty]] could potentially change the enumerability of
+ // the target's properties.
+ virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const MOZ_OVERRIDE {
+ return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
}
virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const MOZ_OVERRIDE;
- /* ES6 Harmony traps */
- virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
-
- /* Spidermonkey extensions. */
- virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
- virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
// For now we maintain the broken behavior that a scripted proxy is constructable if it's
// callable. See bug 929467.
return isCallable(obj);
}
virtual bool isScripted() const MOZ_OVERRIDE { return true; }
--- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp
@@ -297,24 +297,25 @@ ScriptedIndirectProxyHandler::set(JSCont
if (!GetDerivedTrap(cx, handler, cx->names().set, &fval))
return false;
if (!IsCallable(fval))
return BaseProxyHandler::set(cx, proxy, receiver, id, strict, vp);
return Trap(cx, handler, fval, 3, argv.begin(), &idv);
}
bool
-ScriptedIndirectProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const
+ScriptedIndirectProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
RootedValue value(cx);
if (!GetDerivedTrap(cx, handler, cx->names().keys, &value))
return false;
if (!IsCallable(value))
- return BaseProxyHandler::keys(cx, proxy, props);
+ return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
return Trap(cx, handler, value, 0, nullptr, &value) &&
ArrayToIdVector(cx, value, props);
}
bool
ScriptedIndirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const
{
--- a/js/src/proxy/ScriptedIndirectProxyHandler.h
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.h
@@ -14,42 +14,41 @@ namespace js {
/* Derived class for all scripted indirect proxy handlers. */
class ScriptedIndirectProxyHandler : public BaseProxyHandler
{
public:
MOZ_CONSTEXPR ScriptedIndirectProxyHandler()
: BaseProxyHandler(&family)
{ }
- /* ES5 Harmony fundamental proxy traps. */
- virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
- virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
- MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ /* Standard internal methods. */
virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
virtual bool ownPropertyKeys(JSContext *cx, HandleObject proxy,
AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
-
- /* ES5 Harmony derived proxy traps. */
+ virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
+ virtual bool preventExtensions(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
- virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
MutableHandleValue vp) const MOZ_OVERRIDE;
virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp) const MOZ_OVERRIDE;
- virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props) const MOZ_OVERRIDE;
+
+ /* SpiderMonkey extensions. */
+ virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+ MutableHandle<JSPropertyDescriptor> desc) const MOZ_OVERRIDE;
+ virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) const MOZ_OVERRIDE;
+ virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
+ AutoIdVector &props) const MOZ_OVERRIDE;
virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp) const MOZ_OVERRIDE;
-
- /* Spidermonkey extensions. */
- virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
CallArgs args) const MOZ_OVERRIDE;
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
virtual bool isScripted() const MOZ_OVERRIDE { return true; }
static const char family;
static const ScriptedIndirectProxyHandler singleton;
};
--- a/js/src/tests/ecma_6/Symbol/equality.js
+++ b/js/src/tests/ecma_6/Symbol/equality.js
@@ -5,17 +5,18 @@ if (typeof Symbol === "function") {
// Symbol.for returns the same symbol whenever the same argument is passed.
assertEq(Symbol.for("q") === Symbol.for("q"), true);
// Several distinct Symbol values.
var symbols = [
Symbol(),
Symbol("Symbol.iterator"),
Symbol("Symbol.iterator"), // distinct new symbol with the same description
- Symbol.for("Symbol.iterator")
+ Symbol.for("Symbol.iterator"),
+ Symbol.iterator
];
// Distinct symbols are never equal to each other, even if they have the same
// description.
for (var i = 0; i < symbols.length; i++) {
for (var j = i; j < symbols.length; j++) {
var expected = (i === j);
assertEq(symbols[i] == symbols[j], expected);
--- a/js/src/tests/ecma_6/Symbol/surfaces.js
+++ b/js/src/tests/ecma_6/Symbol/surfaces.js
@@ -17,15 +17,20 @@ if (typeof Symbol === "function") {
assertEq(desc.writable, false);
assertEq(Symbol.prototype.constructor, Symbol);
desc = Object.getOwnPropertyDescriptor(Symbol.prototype, "constructor");
assertEq(desc.configurable, true);
assertEq(desc.enumerable, false);
assertEq(desc.writable, true);
+ desc = Object.getOwnPropertyDescriptor(Symbol, "iterator");
+ assertEq(desc.configurable, false);
+ assertEq(desc.enumerable, false);
+ assertEq(desc.writable, false);
+
assertEq(Symbol.for.length, 1);
assertEq(Symbol.prototype.toString.length, 0);
assertEq(Symbol.prototype.valueOf.length, 0);
}
if (typeof reportCompare === "function")
reportCompare(0, 0);
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -28,16 +28,17 @@
macro(bytes, bytes, "bytes") \
macro(BYTES_PER_ELEMENT, BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \
macro(call, call, "call") \
macro(callee, callee, "callee") \
macro(caller, caller, "caller") \
macro(callFunction, callFunction, "callFunction") \
macro(caseFirst, caseFirst, "caseFirst") \
macro(class_, class_, "class") \
+ macro(close, close, "close") \
macro(Collator, Collator, "Collator") \
macro(CollatorCompareGet, CollatorCompareGet, "Intl_Collator_compare_get") \
macro(columnNumber, columnNumber, "columnNumber") \
macro(comma, comma, ",") \
macro(compare, compare, "compare") \
macro(configurable, configurable, "configurable") \
macro(construct, construct, "construct") \
macro(constructor, constructor, "constructor") \
@@ -53,16 +54,17 @@
macro(default_, default_, "default") \
macro(defineProperty, defineProperty, "defineProperty") \
macro(defineGetter, defineGetter, "__defineGetter__") \
macro(defineSetter, defineSetter, "__defineSetter__") \
macro(delete, delete_, "delete") \
macro(deleteProperty, deleteProperty, "deleteProperty") \
macro(displayURL, displayURL, "displayURL") \
macro(done, done, "done") \
+ macro(dotGenerator, dotGenerator, ".generator") \
macro(each, each, "each") \
macro(elementType, elementType, "elementType") \
macro(empty, empty, "") \
macro(encodeURI, encodeURI, "encodeURI") \
macro(encodeURIComponent, encodeURIComponent, "encodeURIComponent") \
macro(enumerable, enumerable, "enumerable") \
macro(enumerate, enumerate, "enumerate") \
macro(escape, escape, "escape") \
@@ -105,16 +107,17 @@
macro(int8, int8, "int8") \
macro(int16, int16, "int16") \
macro(int32, int32, "int32") \
macro(isExtensible, isExtensible, "isExtensible") \
macro(iteratorIntrinsic, iteratorIntrinsic, "__iterator__") \
macro(join, join, "join") \
macro(keys, keys, "keys") \
macro(lastIndex, lastIndex, "lastIndex") \
+ macro(LegacyGeneratorCloseInternal, LegacyGeneratorCloseInternal, "LegacyGeneratorCloseInternal") \
macro(length, length, "length") \
macro(let, let, "let") \
macro(line, line, "line") \
macro(lineNumber, lineNumber, "lineNumber") \
macro(loc, loc, "loc") \
macro(locale, locale, "locale") \
macro(lookupGetter, lookupGetter, "__lookupGetter__") \
macro(lookupSetter, lookupSetter, "__lookupSetter__") \
@@ -157,16 +160,17 @@
macro(parseInt, parseInt, "parseInt") \
macro(pattern, pattern, "pattern") \
macro(preventExtensions, preventExtensions, "preventExtensions") \
macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \
macro(proto, proto, "__proto__") \
macro(prototype, prototype, "prototype") \
macro(proxy, proxy, "proxy") \
macro(Reify, Reify, "Reify") \
+ macro(resumeGenerator, resumeGenerator, "resumeGenerator") \
macro(return, return_, "return") \
macro(revoke, revoke, "revoke") \
macro(scripts, scripts, "scripts") \
macro(sensitivity, sensitivity, "sensitivity") \
macro(set, set, "set") \
macro(shape, shape, "shape") \
macro(signMask, signMask, "signMask") \
macro(source, source, "source") \
new file mode 100644
--- /dev/null
+++ b/js/src/vm/GeneratorObject.cpp
@@ -0,0 +1,329 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/GeneratorObject.h"
+
+#include "jsatominlines.h"
+#include "jsscriptinlines.h"
+
+#include "vm/NativeObject-inl.h"
+#include "vm/Stack-inl.h"
+
+using namespace js;
+using namespace js::types;
+
+JSObject *
+GeneratorObject::create(JSContext *cx, const InterpreterRegs ®s)
+{
+ MOZ_ASSERT(regs.stackDepth() == 0);
+ InterpreterFrame *fp = regs.fp();
+
+ MOZ_ASSERT(fp->script()->isGenerator());
+
+ Rooted<GlobalObject*> global(cx, &fp->global());
+ RootedNativeObject obj(cx);
+ if (fp->script()->isStarGenerator()) {
+ RootedValue pval(cx);
+ RootedObject fun(cx, fp->fun());
+ // FIXME: This would be faster if we could avoid doing a lookup to get
+ // the prototype for the instance. Bug 906600.
+ if (!JSObject::getProperty(cx, fun, fun, cx->names().prototype, &pval))
+ return nullptr;
+ JSObject *proto = pval.isObject() ? &pval.toObject() : nullptr;
+ if (!proto) {
+ proto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global);
+ if (!proto)
+ return nullptr;
+ }
+ obj = NewNativeObjectWithGivenProto(cx, &StarGeneratorObject::class_, proto, global);
+ } else {
+ MOZ_ASSERT(fp->script()->isLegacyGenerator());
+ JSObject *proto = GlobalObject::getOrCreateLegacyGeneratorObjectPrototype(cx, global);
+ if (!proto)
+ return nullptr;
+ obj = NewNativeObjectWithGivenProto(cx, &LegacyGeneratorObject::class_, proto, global);
+ }
+ if (!obj)
+ return nullptr;
+
+ Rooted<GeneratorObject *> genObj(cx, &obj->as<GeneratorObject>());
+
+ genObj->setCallee(fp->callee());
+ genObj->setThisValue(fp->thisValue());
+ genObj->setScopeChain(*fp->scopeChain());
+ if (fp->script()->needsArgsObj())
+ genObj->setArgsObj(fp->argsObj());
+ genObj->clearExpressionStack();
+
+ return obj;
+}
+
+bool
+GeneratorObject::suspend(JSContext *cx, HandleObject obj, InterpreterFrame *fp, jsbytecode *pc,
+ Value *vp, unsigned nvalues, GeneratorObject::SuspendKind suspendKind)
+{
+ Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
+ MOZ_ASSERT(!genObj->hasExpressionStack());
+
+ if (suspendKind == NORMAL && genObj->isClosing()) {
+ MOZ_ASSERT(genObj->is<LegacyGeneratorObject>());
+ RootedValue val(cx, ObjectValue(fp->callee()));
+ js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, js::NullPtr());
+ return false;
+ }
+
+ genObj->setSuspendedBytecodeOffset(pc - fp->script()->code(), suspendKind == INITIAL);
+ genObj->setScopeChain(*fp->scopeChain());
+
+ if (nvalues) {
+ ArrayObject *stack = NewDenseCopiedArray(cx, nvalues, vp);
+ if (!stack)
+ return false;
+ genObj->setExpressionStack(*stack);
+ }
+
+ return true;
+}
+
+bool
+GeneratorObject::finalSuspend(JSContext *cx, HandleObject obj)
+{
+ Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
+ MOZ_ASSERT(genObj->isRunning() || genObj->isClosing());
+
+ bool closing = genObj->isClosing();
+ MOZ_ASSERT_IF(closing, genObj->is<LegacyGeneratorObject>());
+ genObj->setClosed();
+
+ if (genObj->is<LegacyGeneratorObject>() && !closing)
+ return ThrowStopIteration(cx);
+
+ return true;
+}
+
+bool
+GeneratorObject::resume(JSContext *cx, InterpreterActivation &activation,
+ HandleObject obj, HandleValue arg, GeneratorObject::ResumeKind resumeKind)
+{
+ Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
+ MOZ_ASSERT(genObj->isSuspended());
+
+ RootedFunction callee(cx, &genObj->callee());
+ RootedValue thisv(cx, genObj->thisValue());
+ RootedObject scopeChain(cx, &genObj->scopeChain());
+ if (!activation.resumeGeneratorFrame(callee, thisv, scopeChain))
+ return false;
+
+ if (genObj->hasArgsObj())
+ activation.regs().fp()->initArgsObj(genObj->argsObj());
+
+ if (genObj->hasExpressionStack()) {
+ uint32_t len = genObj->expressionStack().length();
+ MOZ_ASSERT(activation.regs().spForStackDepth(len));
+ RootedObject array(cx, &genObj->expressionStack());
+ GetElements(cx, array, len, activation.regs().sp);
+ activation.regs().sp += len;
+ genObj->clearExpressionStack();
+ }
+
+ activation.regs().pc = callee->nonLazyScript()->code() + genObj->suspendedBytecodeOffset();
+
+ // If we are resuming a JSOP_YIELD, always push on a value, even if we are
+ // raising an exception. In the exception case, the stack needs to have
+ // something on it so that exception handling doesn't skip the catch
+ // blocks. See TryNoteIter::settle.
+ if (!genObj->isNewborn()) {
+ activation.regs().sp++;
+ MOZ_ASSERT(activation.regs().spForStackDepth(activation.regs().stackDepth()));
+ activation.regs().sp[-1] = arg;
+ }
+
+ switch (resumeKind) {
+ case NEXT:
+ genObj->setRunning();
+ return true;
+
+ case THROW:
+ cx->setPendingException(arg);
+ if (genObj->isNewborn())
+ genObj->setClosed();
+ else
+ genObj->setRunning();
+ return false;
+
+ case CLOSE:
+ MOZ_ASSERT(genObj->is<LegacyGeneratorObject>());
+ cx->setPendingException(MagicValue(JS_GENERATOR_CLOSING));
+ genObj->setClosing();
+ return false;
+
+ default:
+ MOZ_CRASH("bad resumeKind");
+ }
+}
+
+bool
+LegacyGeneratorObject::close(JSContext *cx, HandleObject obj)
+{
+ Rooted<LegacyGeneratorObject*> genObj(cx, &obj->as<LegacyGeneratorObject>());
+
+ // Avoid calling back into JS unless it is necessary.
+ if (genObj->isClosed())
+ return true;
+
+ if (genObj->isNewborn()) {
+ genObj->setClosed();
+ return true;
+ }
+
+ RootedValue rval(cx);
+
+ RootedValue closeValue(cx);
+ if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().LegacyGeneratorCloseInternal,
+ &closeValue))
+ {
+ return false;
+ }
+ MOZ_ASSERT(closeValue.isObject());
+ MOZ_ASSERT(closeValue.toObject().is<JSFunction>());
+
+ InvokeArgs args(cx);
+ if (!args.init(0))
+ return false;
+
+ args.setCallee(closeValue);
+ args.setThis(ObjectValue(*genObj));
+
+ return Invoke(cx, args);
+}
+
+static JSObject *
+iterator_iteratorObject(JSContext *cx, HandleObject obj, bool keysonly)
+{
+ return obj;
+}
+
+const Class LegacyGeneratorObject::class_ = {
+ "Generator",
+ JSCLASS_HAS_RESERVED_SLOTS(GeneratorObject::RESERVED_SLOTS),
+ JS_PropertyStub, /* addProperty */
+ JS_DeletePropertyStub, /* delProperty */
+ JS_PropertyStub, /* getProperty */
+ JS_StrictPropertyStub, /* setProperty */
+ JS_EnumerateStub,
+ JS_ResolveStub,
+ JS_ConvertStub,
+ nullptr, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ nullptr, /* trace */
+ JS_NULL_CLASS_SPEC,
+ {
+ nullptr, /* outerObject */
+ nullptr, /* innerObject */
+ iterator_iteratorObject,
+ }
+};
+
+const Class StarGeneratorObject::class_ = {
+ "Generator",
+ JSCLASS_HAS_RESERVED_SLOTS(GeneratorObject::RESERVED_SLOTS),
+ JS_PropertyStub, /* addProperty */
+ JS_DeletePropertyStub, /* delProperty */
+ JS_PropertyStub, /* getProperty */
+ JS_StrictPropertyStub, /* setProperty */
+ JS_EnumerateStub,
+ JS_ResolveStub,
+ JS_ConvertStub,
+ nullptr, /* finalize */
+ nullptr, /* call */
+ nullptr, /* hasInstance */
+ nullptr, /* construct */
+ nullptr, /* trace */
+};
+
+static const JSFunctionSpec star_generator_methods[] = {
+ JS_SELF_HOSTED_FN("@@iterator", "IteratorIdentity", 0, 0),
+ JS_SELF_HOSTED_FN("next", "StarGeneratorNext", 1, 0),
+ JS_SELF_HOSTED_FN("throw", "StarGeneratorThrow", 1, 0),
+ JS_FS_END
+};
+
+#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT)
+
+static const JSFunctionSpec legacy_generator_methods[] = {
+ JS_SELF_HOSTED_FN("@@iterator", "LegacyGeneratorIteratorShim", 0, 0),
+ // "send" is an alias for "next".
+ JS_SELF_HOSTED_FN("next", "LegacyGeneratorNext", 1, JSPROP_ROPERM),
+ JS_SELF_HOSTED_FN("send", "LegacyGeneratorNext", 1, JSPROP_ROPERM),
+ JS_SELF_HOSTED_FN("throw", "LegacyGeneratorThrow", 1, JSPROP_ROPERM),
+ JS_SELF_HOSTED_FN("close", "LegacyGeneratorClose", 0, JSPROP_ROPERM),
+ JS_FS_END
+};
+
+#undef JSPROP_ROPERM
+
+static JSObject*
+NewSingletonObjectWithObjectPrototype(JSContext *cx, Handle<GlobalObject *> global)
+{
+ JSObject *proto = global->getOrCreateObjectPrototype(cx);
+ if (!proto)
+ return nullptr;
+ return NewObjectWithGivenProto(cx, &JSObject::class_, proto, global, SingletonObject);
+}
+
+static JSObject*
+NewSingletonObjectWithFunctionPrototype(JSContext *cx, Handle<GlobalObject *> global)
+{
+ JSObject *proto = global->getOrCreateFunctionPrototype(cx);
+ if (!proto)
+ return nullptr;
+ return NewObjectWithGivenProto(cx, &JSObject::class_, proto, global, SingletonObject);
+}
+
+/* static */ bool
+GlobalObject::initGeneratorClasses(JSContext *cx, Handle<GlobalObject *> global)
+{
+ if (global->getSlot(LEGACY_GENERATOR_OBJECT_PROTO).isUndefined()) {
+ RootedObject proto(cx, NewSingletonObjectWithObjectPrototype(cx, global));
+ if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods))
+ return false;
+ global->setReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO, ObjectValue(*proto));
+ }
+
+ if (global->getSlot(STAR_GENERATOR_OBJECT_PROTO).isUndefined()) {
+ RootedObject genObjectProto(cx, NewSingletonObjectWithObjectPrototype(cx, global));
+ if (!genObjectProto)
+ return false;
+ if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods))
+ return false;
+
+ RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
+ if (!genFunctionProto)
+ return false;
+ if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto))
+ return false;
+
+ RootedValue function(cx, global->getConstructor(JSProto_Function));
+ if (!function.toObjectOrNull())
+ return false;
+ RootedAtom name(cx, cx->names().GeneratorFunction);
+ RootedObject genFunction(cx, NewFunctionWithProto(cx, NullPtr(), Generator, 1,
+ JSFunction::NATIVE_CTOR, global, name,
+ &function.toObject()));
+ if (!genFunction)
+ return false;
+ if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
+ return false;
+
+ global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
+ global->setConstructor(JSProto_GeneratorFunction, ObjectValue(*genFunction));
+ global->setPrototype(JSProto_GeneratorFunction, ObjectValue(*genFunctionProto));
+ }
+
+ return true;
+}
--- a/js/src/vm/GeneratorObject.h
+++ b/js/src/vm/GeneratorObject.h
@@ -2,31 +2,204 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_GeneratorObject_h
#define vm_GeneratorObject_h
+#include "jscntxt.h"
#include "jsobj.h"
+#include "vm/ArgumentsObject.h"
+#include "vm/ArrayObject.h"
+#include "vm/Stack.h"
+
namespace js {
-class LegacyGeneratorObject : public NativeObject
+class GeneratorObject : public NativeObject
+{
+ static const int32_t MAX_BYTECODE_OFFSET = INT32_MAX >> 1;
+
+ public:
+ enum {
+ CALLEE_SLOT = 0,
+ THIS_SLOT,
+ SCOPE_CHAIN_SLOT,
+ ARGS_OBJ_SLOT,
+ EXPRESSION_STACK_SLOT,
+ BYTECODE_OFFSET_SLOT,
+ RESERVED_SLOTS
+ };
+
+ enum SuspendKind { INITIAL, NORMAL, FINAL };
+ enum ResumeKind { NEXT, THROW, CLOSE };
+
+ static inline ResumeKind getResumeKind(jsbytecode *pc) {
+ MOZ_ASSERT(*pc == JSOP_RESUME);
+ unsigned arg = GET_UINT16(pc);
+ MOZ_ASSERT(arg <= CLOSE);
+ return static_cast<ResumeKind>(arg);
+ }
+
+ static inline ResumeKind getResumeKind(ExclusiveContext *cx, JSAtom *atom) {
+ if (atom == cx->names().next)
+ return NEXT;
+ if (atom == cx->names().throw_)
+ return THROW;
+ MOZ_ASSERT(atom == cx->names().close);
+ return CLOSE;
+ }
+
+ static JSObject *create(JSContext *cx, const InterpreterRegs ®s);
+
+ static bool suspend(JSContext *cx, HandleObject obj, InterpreterFrame *fp, jsbytecode *pc,
+ Value *vp, unsigned nvalues, SuspendKind kind);
+
+ static bool resume(JSContext *cx, InterpreterActivation &activation,
+ HandleObject obj, HandleValue arg, ResumeKind resumeKind);
+
+ static bool initialSuspend(JSContext *cx, HandleObject obj, InterpreterFrame *fp, jsbytecode *pc) {
+ return suspend(cx, obj, fp, pc, nullptr, 0, INITIAL);
+ }
+
+ static bool normalSuspend(JSContext *cx, HandleObject obj, InterpreterFrame *fp, jsbytecode *pc,
+ Value *vp, unsigned nvalues) {
+ return suspend(cx, obj, fp, pc, vp, nvalues, NORMAL);
+ }
+
+ static bool finalSuspend(JSContext *cx, HandleObject obj);
+
+ JSFunction &callee() const {
+ return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
+ }
+ void setCallee(JSFunction &callee) {
+ setFixedSlot(CALLEE_SLOT, ObjectValue(callee));
+ }
+
+ const Value &thisValue() const {
+ return getFixedSlot(THIS_SLOT);
+ }
+ void setThisValue(Value &thisv) {
+ setFixedSlot(THIS_SLOT, thisv);
+ }
+
+ JSObject &scopeChain() const {
+ return getFixedSlot(SCOPE_CHAIN_SLOT).toObject();
+ }
+ void setScopeChain(JSObject &scopeChain) {
+ setFixedSlot(SCOPE_CHAIN_SLOT, ObjectValue(scopeChain));
+ }
+
+ bool hasArgsObj() const {
+ return getFixedSlot(ARGS_OBJ_SLOT).isObject();
+ }
+ ArgumentsObject &argsObj() const {
+ return getFixedSlot(ARGS_OBJ_SLOT).toObject().as<ArgumentsObject>();
+ }
+ void setArgsObj(ArgumentsObject &argsObj) {
+ setFixedSlot(ARGS_OBJ_SLOT, ObjectValue(argsObj));
+ }
+
+ bool hasExpressionStack() const {
+ return getFixedSlot(EXPRESSION_STACK_SLOT).isObject();
+ }
+ ArrayObject &expressionStack() const {
+ return getFixedSlot(EXPRESSION_STACK_SLOT).toObject().as<ArrayObject>();
+ }
+ void setExpressionStack(ArrayObject &expressionStack) {
+ setFixedSlot(EXPRESSION_STACK_SLOT, ObjectValue(expressionStack));
+ }
+ void clearExpressionStack() {
+ setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
+ }
+
+ // The bytecode offset slot is abused for a few purposes. It's undefined if
+ // it hasn't been set yet (before the initial yield), and null if the
+ // generator is closed. Otherwise, the lower bit is set if the generator
+ // is in the "suspendedStart" set, and cleared otherwise. The upper bits
+ // are used for the PC offset of the suspended continuation, and are zero if
+ // the generator is running. If the generator is in that bizarre "closing"
+ // state, all upper bits are set.
+
+ bool isRunning() const {
+ MOZ_ASSERT(!isClosed());
+ return getFixedSlot(BYTECODE_OFFSET_SLOT).toInt32() == 0;
+ }
+ bool isClosing() const {
+ return getFixedSlot(BYTECODE_OFFSET_SLOT).toInt32() == MAX_BYTECODE_OFFSET << 1;
+ }
+ bool isSuspended() const {
+ MOZ_ASSERT(!isClosed());
+ // Note that newborn objects also count as suspended.
+ return !isRunning() && !isClosing();
+ }
+ bool isNewborn() const {
+ MOZ_ASSERT(!isClosed());
+ return getFixedSlot(BYTECODE_OFFSET_SLOT).toInt32() & 0x1;
+ }
+ void setRunning() {
+ MOZ_ASSERT(isSuspended());
+ setFixedSlot(BYTECODE_OFFSET_SLOT, Int32Value(0));
+ }
+ void setClosing() {
+ MOZ_ASSERT(isSuspended());
+ setFixedSlot(BYTECODE_OFFSET_SLOT, Int32Value(MAX_BYTECODE_OFFSET << 1));
+ }
+ ptrdiff_t suspendedBytecodeOffset() const {
+ MOZ_ASSERT(isSuspended());
+ return getFixedSlot(BYTECODE_OFFSET_SLOT).toInt32() >> 1;
+ }
+ void setSuspendedBytecodeOffset(ptrdiff_t offset, bool newborn) {
+ MOZ_ASSERT(newborn ? getFixedSlot(BYTECODE_OFFSET_SLOT).isUndefined() : isRunning());
+ MOZ_ASSERT(offset > 0 && offset < MAX_BYTECODE_OFFSET);
+ setFixedSlot(BYTECODE_OFFSET_SLOT, Int32Value((offset << 1) | (newborn ? 0x1 : 0)));
+ MOZ_ASSERT(isSuspended());
+ }
+ bool isClosed() const {
+ return getFixedSlot(CALLEE_SLOT).isNull();
+ }
+ void setClosed() {
+ setFixedSlot(CALLEE_SLOT, NullValue());
+ setFixedSlot(THIS_SLOT, NullValue());
+ setFixedSlot(SCOPE_CHAIN_SLOT, NullValue());
+ setFixedSlot(ARGS_OBJ_SLOT, NullValue());
+ setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
+ setFixedSlot(BYTECODE_OFFSET_SLOT, NullValue());
+ }
+};
+
+class LegacyGeneratorObject : public GeneratorObject
{
public:
static const Class class_;
- JSGenerator *getGenerator() { return static_cast<JSGenerator*>(getPrivate()); }
+ static bool close(JSContext *cx, HandleObject obj);
+
+ // Unlike most other methods returning boolean, if this returns false, it
+ // doesn't mean that an error was raised -- it just means that the object
+ // wasn't newborn.
+ static bool maybeCloseNewborn(LegacyGeneratorObject *genObj) {
+ if (genObj->isNewborn()) {
+ genObj->setClosed();
+ return true;
+ }
+ return false;
+ }
};
-class StarGeneratorObject : public NativeObject
+class StarGeneratorObject : public GeneratorObject
{
public:
static const Class class_;
-
- JSGenerator *getGenerator() { return static_cast<JSGenerator*>(getPrivate()); }
};
} // namespace js
+template<>
+inline bool
+JSObject::is<js::GeneratorObject>() const
+{
+ return is<js::LegacyGeneratorObject>() || is<js::StarGeneratorObject>();
+}
+
#endif /* vm_GeneratorObject_h */
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -610,16 +610,19 @@ class GlobalObject : public NativeObject
// Infallibly test whether the given value is the eval function for this global.
bool valueIsEval(Value val);
// Implemented in jsiter.cpp.
static bool initIteratorClasses(JSContext *cx, Handle<GlobalObject*> global);
static bool initStopIterationClass(JSContext *cx, Handle<GlobalObject*> global);
+ // Implemented in vm/GeneratorObject.cpp.
+ static bool initGeneratorClasses(JSContext *cx, Handle<GlobalObject*> global);
+
// Implemented in builtin/MapObject.cpp.
static bool initMapIteratorProto(JSContext *cx, Handle<GlobalObject*> global);
static bool initSetIteratorProto(JSContext *cx, Handle<GlobalObject*> global);
// Implemented in Intl.cpp.
static bool initIntlObject(JSContext *cx, Handle<GlobalObject*> global);
static bool initCollatorProto(JSContext *cx, Handle<GlobalObject*> global);
static bool initNumberFormatProto(JSContext *cx, Handle<GlobalObject*> global);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -30,16 +30,17 @@
#include "jsscript.h"
#include "jsstr.h"
#include "builtin/Eval.h"
#include "jit/BaselineJIT.h"
#include "jit/Ion.h"
#include "jit/IonAnalysis.h"
#include "vm/Debugger.h"
+#include "vm/GeneratorObject.h"
#include "vm/Opcodes.h"
#include "vm/Shape.h"
#include "vm/TraceLogging.h"
#include "jsatominlines.h"
#include "jsboolinlines.h"
#include "jsfuninlines.h"
#include "jsinferinlines.h"
@@ -1652,20 +1653,16 @@ CASE(JSOP_UNUSED183)
CASE(JSOP_UNUSED185)
CASE(JSOP_UNUSED186)
CASE(JSOP_UNUSED187)
CASE(JSOP_UNUSED189)
CASE(JSOP_UNUSED190)
CASE(JSOP_UNUSED191)
CASE(JSOP_UNUSED192)
CASE(JSOP_UNUSED196)
-CASE(JSOP_UNUSED201)
-CASE(JSOP_UNUSED205)
-CASE(JSOP_UNUSED206)
-CASE(JSOP_UNUSED207)
CASE(JSOP_UNUSED208)
CASE(JSOP_UNUSED209)
CASE(JSOP_UNUSED210)
CASE(JSOP_UNUSED211)
CASE(JSOP_UNUSED212)
CASE(JSOP_UNUSED213)
CASE(JSOP_UNUSED219)
CASE(JSOP_UNUSED220)
@@ -1769,32 +1766,26 @@ CASE(JSOP_RETRVAL)
* When the inlined frame exits with an exception or an error, ok will be
* false after the inline_return label.
*/
CHECK_BRANCH();
successful_return_continuation:
interpReturnOK = true;
return_continuation:
- if (activation.entryFrame() != REGS.fp())
- inline_return:
- {
+ if (activation.entryFrame() != REGS.fp()) {
// Stop the engine. (No details about which engine exactly, could be
// interpreter, Baseline or IonMonkey.)
TraceLogStopEvent(logger);
// Stop the script. (Again no details about which script exactly.)
TraceLogStopEvent(logger);
interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), interpReturnOK);
- if (!REGS.fp()->isYielding())
- REGS.fp()->epilogue(cx);
- else
- probes::ExitScript(cx, script, script->functionNonDelazifying(),
- REGS.fp()->hasPushedSPSFrame());
+ REGS.fp()->epilogue(cx);
jit_return_pop_frame:
activation.popInlineFrame(REGS.fp());
SET_SCRIPT(REGS.fp()->script());
jit_return:
@@ -3375,42 +3366,90 @@ CASE(JSOP_DEBUGLEAVEBLOCK)
DebugScopes::onPopBlock(cx, REGS.fp(), REGS.pc);
}
END_CASE(JSOP_DEBUGLEAVEBLOCK)
CASE(JSOP_GENERATOR)
{
MOZ_ASSERT(!cx->isExceptionPending());
REGS.fp()->initGeneratorFrame();
- REGS.pc += JSOP_GENERATOR_LENGTH;
- JSObject *obj = js_NewGenerator(cx, REGS);
+ JSObject *obj = GeneratorObject::create(cx, REGS);
if (!obj)
goto error;
- REGS.fp()->setReturnValue(ObjectValue(*obj));
- REGS.fp()->setYielding();
- interpReturnOK = true;
- if (activation.entryFrame() != REGS.fp())
- goto inline_return;
- goto exit;
+ PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_GENERATOR)
+
+CASE(JSOP_INITIALYIELD)
+{
+ MOZ_ASSERT(!cx->isExceptionPending());
+ MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame());
+ RootedObject &obj = rootObject0;
+ obj = ®S.sp[-1].toObject();
+ POP_RETURN_VALUE();
+ MOZ_ASSERT(REGS.stackDepth() == 0);
+ if (!GeneratorObject::initialSuspend(cx, obj, REGS.fp(), REGS.pc + JSOP_INITIALYIELD_LENGTH))
+ goto error;
+ goto successful_return_continuation;
}
CASE(JSOP_YIELD)
+{
MOZ_ASSERT(!cx->isExceptionPending());
MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame());
- if (cx->innermostGenerator()->state == JSGEN_CLOSING) {
- RootedValue &val = rootValue0;
- val.setObject(REGS.fp()->callee());
- js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, js::NullPtr());
+ RootedObject &obj = rootObject0;
+ obj = ®S.sp[-1].toObject();
+ if (!GeneratorObject::normalSuspend(cx, obj, REGS.fp(), REGS.pc + JSOP_YIELD_LENGTH,
+ REGS.spForStackDepth(0), REGS.stackDepth() - 2))
+ {
goto error;
}
- REGS.fp()->setReturnValue(REGS.sp[-1]);
- REGS.fp()->setYielding();
- REGS.pc += JSOP_YIELD_LENGTH;
- interpReturnOK = true;
- goto exit;
+
+ REGS.sp--;
+ POP_RETURN_VALUE();
+
+ goto successful_return_continuation;
+}
+
+CASE(JSOP_RESUME)
+{
+ RootedObject &gen = rootObject0;
+ RootedValue &val = rootValue0;
+ val = REGS.sp[-1];
+ gen = ®S.sp[-2].toObject();
+ // popInlineFrame expects there to be an additional value on the stack to
+ // pop off, so leave "gen" on the stack.
+
+ GeneratorObject::ResumeKind resumeKind = GeneratorObject::getResumeKind(REGS.pc);
+ bool ok = GeneratorObject::resume(cx, activation, gen, val, resumeKind);
+ SET_SCRIPT(REGS.fp()->script());
+ if (!ok)
+ goto error;
+
+ ADVANCE_AND_DISPATCH(0);
+}
+
+CASE(JSOP_FINALYIELD)
+ REGS.fp()->setReturnValue(REGS.sp[-2]);
+ REGS.sp[-2] = REGS.sp[-1];
+ REGS.sp--;
+ /* FALL THROUGH */
+CASE(JSOP_FINALYIELDRVAL)
+{
+ RootedObject &gen = rootObject0;
+ gen = ®S.sp[-1].toObject();
+ REGS.sp--;
+
+ if (!GeneratorObject::finalSuspend(cx, gen)) {
+ interpReturnOK = false;
+ goto return_continuation;
+ }
+
+ goto successful_return_continuation;
+}
CASE(JSOP_ARRAYPUSH)
{
RootedObject &obj = rootObject0;
obj = ®S.sp[-1].toObject();
if (!NewbornArrayPush(cx, obj, REGS.sp[-2]))
goto error;
REGS.sp -= 2;
@@ -3458,21 +3497,17 @@ DEFAULT()
ADVANCE_AND_DISPATCH(0);
}
MOZ_CRASH("Invalid HandleError continuation");
exit:
interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), interpReturnOK);
- if (!REGS.fp()->isYielding())
- REGS.fp()->epilogue(cx);
- else
- probes::ExitScript(cx, script, script->functionNonDelazifying(),
- REGS.fp()->hasPushedSPSFrame());
+ REGS.fp()->epilogue(cx);
gc::MaybeVerifyBarriers(cx, true);
TraceLogStopEvent(logger);
TraceLogStopEvent(logger, scriptLogId);
/*
* This path is used when it's guaranteed the method can be finished
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -106,64 +106,57 @@ ExecuteKernel(JSContext *cx, HandleScrip
ExecuteType type, AbstractFramePtr evalInFrame, Value *result);
/* Execute a script with the given scopeChain as global code. */
extern bool
Execute(JSContext *cx, HandleScript script, JSObject &scopeChain, Value *rval);
class ExecuteState;
class InvokeState;
-class GeneratorState;
// RunState is passed to RunScript and RunScript then eiter passes it to the
// interpreter or to the JITs. RunState contains all information we need to
// construct an interpreter or JIT frame.
class RunState
{
protected:
- enum Kind { Execute, Invoke, Generator };
+ enum Kind { Execute, Invoke };
Kind kind_;
RootedScript script_;
explicit RunState(JSContext *cx, Kind kind, JSScript *script)
: kind_(kind),
script_(cx, script)
{ }
public:
bool isExecute() const { return kind_ == Execute; }
bool isInvoke() const { return kind_ == Invoke; }
- bool isGenerator() const { return kind_ == Generator; }
ExecuteState *asExecute() const {
MOZ_ASSERT(isExecute());
return (ExecuteState *)this;
}
InvokeState *asInvoke() const {
MOZ_ASSERT(isInvoke());
return (InvokeState *)this;
}
- GeneratorState *asGenerator() const {
- MOZ_ASSERT(isGenerator());
- return (GeneratorState *)this;
- }
JS::HandleScript script() const { return script_; }
virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx) = 0;
virtual void setReturnValue(Value v) = 0;
bool maybeCreateThisForConstructor(JSContext *cx);
private:
RunState(const RunState &other) MOZ_DELETE;
RunState(const ExecuteState &other) MOZ_DELETE;
RunState(const InvokeState &other) MOZ_DELETE;
- RunState(const GeneratorState &other) MOZ_DELETE;
void operator=(const RunState &other) MOZ_DELETE;
};
// Eval or global script.
class ExecuteState : public RunState
{
ExecuteType type_;
@@ -219,34 +212,16 @@ class InvokeState : public RunState
virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx);
virtual void setReturnValue(Value v) {
args_.rval().set(v);
}
};
-// Generator script.
-class GeneratorState : public RunState
-{
- JSContext *cx_;
- JSGenerator *gen_;
- JSGeneratorState futureState_;
- bool entered_;
-
- public:
- GeneratorState(JSContext *cx, JSGenerator *gen, JSGeneratorState futureState);
- ~GeneratorState();
-
- virtual InterpreterFrame *pushInterpreterFrame(JSContext *cx);
- virtual void setReturnValue(Value) { }
-
- JSGenerator *gen() const { return gen_; }
-};
-
extern bool
RunScript(JSContext *cx, RunState &state);
extern bool
StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal);
extern bool
LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal);
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -1546,53 +1546,83 @@ 1234567890123456789012345678901234567890
* The opcode to assist the debugger.
* Category: Statements
* Type: Debugger
* Operands:
* Stack: =>
*/ \
macro(JSOP_DEBUGLEAVEBLOCK, 200,"debugleaveblock", NULL, 1, 0, 0, JOF_BYTE) \
\
- macro(JSOP_UNUSED201, 201,"unused201", NULL, 1, 0, 0, JOF_BYTE) \
- \
+ /*
+ * Initializes generator frame, creates a generator and pushes it on the
+ * stack.
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: => generator
+ */ \
+ macro(JSOP_GENERATOR, 201,"generator", NULL, 1, 0, 1, JOF_BYTE) \
/*
- * Initializes generator frame, creates a generator, sets 'YIELDING' flag,
- * stops interpretation and returns the generator.
+ * Pops the generator from the top of the stack, suspends it and stops
+ * interpretation.
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: generator =>
+ */ \
+ macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Pops the generator and the return value 'rval1', stops interpretation and
+ * returns 'rval1'. Pushes sent value from 'send()' onto the stack.
* Category: Statements
* Type: Generator
* Operands:
- * Stack: =>
+ * Stack: rval1, gen => rval2
*/ \
- macro(JSOP_GENERATOR, 202,"generator", NULL, 1, 0, 0, JOF_BYTE) \
+ macro(JSOP_YIELD, 203,"yield", NULL, 1, 2, 1, JOF_BYTE) \
/*
- * Pops the top of stack value as 'rval1', sets 'YIELDING' flag,
- * stops interpretation and returns 'rval1', pushes sent value from
- * 'send()' onto the stack.
+ * Pops the generator and the value to yield from the stack. Then suspends
+ * and closes the generator.
* Category: Statements
* Type: Generator
* Operands:
- * Stack: rval1 => rval2
+ * Stack: gen, val =>
+ */ \
+ macro(JSOP_FINALYIELD, 204,"finalyield", NULL, 1, 2, 0, JOF_BYTE) \
+ /*
+ * Pops the generator and suspends and closes it. Yields the value in the
+ * frame's return value slot.
+ * Category: Statements
+ * Type: Generator
+ * Operands:
+ * Stack: gen =>
*/ \
- macro(JSOP_YIELD, 203,"yield", NULL, 1, 1, 1, JOF_BYTE) \
+ macro(JSOP_FINALYIELDRVAL,205,"finalyieldrval",NULL, 1, 1, 0, JOF_BYTE) \
+ /*
+ * Pops the generator and argument from the stack, pushes a new generator
+ * frame and resumes execution of it. Pushes the return value after the
+ * generator yields.
+ * Category: Statements
+ * Type: Generator
+ * Operands: resume kind (GeneratorObject::ResumeKind)
+ * Stack: gen, val => rval
+ */ \
+ macro(JSOP_RESUME, 206,"resume", NULL, 3, 2, 1, JOF_UINT8|JOF_INVOKE) \
/*
* Pops the top two values on the stack as 'obj' and 'v', pushes 'v' to
* 'obj'.
*
* This opcode is used for Array Comprehension.
* Category: Literals
* Type: Array
* Operands:
* Stack: v, obj =>
*/ \
- macro(JSOP_ARRAYPUSH, 204,"arraypush", NULL, 1, 2, 0, JOF_BYTE) \
+ macro(JSOP_ARRAYPUSH, 207,"arraypush", NULL, 1, 2, 0, JOF_BYTE) \
\
- macro(JSOP_UNUSED205, 205, "unused205", NULL, 1, 0, 0, JOF_BYTE) \
- macro(JSOP_UNUSED206, 206, "unused206", NULL, 1, 0, 0, JOF_BYTE) \
- \
- macro(JSOP_UNUSED207, 207, "unused207", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED208, 208, "unused208", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED209, 209, "unused209", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED210, 210, "unused210", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED211, 211, "unused211", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED212, 212, "unused212", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED213, 213, "unused213", NULL, 1, 0, 0, JOF_BYTE) \
/*
* Pushes the global scope onto the stack.
--- a/js/src/vm/ProxyObject.h
+++ b/js/src/vm/ProxyObject.h
@@ -86,17 +86,17 @@ class ProxyObject : public JSObject
// Since we can take classes from the outside, make sure that they
// are "sane". They have to quack enough like proxies for us to belive
// they should be treated as such.
// proxy_Trace is just a trivial wrapper around ProxyObject::trace for
// friend api exposure.
// Proxy classes are not allowed to have call or construct hooks directly. Their
- // callability is instead decided by a trap call
+ // callability is instead decided by handler()->isCallable().
return clasp->isProxy() &&
(clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS) &&
clasp->trace == proxy_Trace &&
!clasp->call && !clasp->construct &&
JSCLASS_RESERVED_SLOTS(clasp) >= PROXY_MINIMUM_SLOTS;
}
public:
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -409,29 +409,33 @@ struct JSAtomState
};
namespace js {
/*
* Storage for well-known symbols. It's a separate struct from the Runtime so
* that it can be shared across multiple runtimes. As in JSAtomState, each
* field is a smart pointer that's immutable once initialized.
- * `rt->wellKnownSymbols.iterator` is convertible to Handle<Symbol*>.
+ * `rt->wellKnownSymbols->iterator` is convertible to Handle<Symbol*>.
*
* Well-known symbols are never GC'd. The description() of each well-known
* symbol is a permanent atom.
*/
struct WellKnownSymbols
{
js::ImmutableSymbolPtr iterator;
- ImmutableSymbolPtr &get(size_t i) {
- MOZ_ASSERT(i < JS::WellKnownSymbolLimit);
+ ImmutableSymbolPtr &get(size_t u) {
+ MOZ_ASSERT(u < JS::WellKnownSymbolLimit);
ImmutableSymbolPtr *symbols = reinterpret_cast<ImmutableSymbolPtr *>(this);
- return symbols[i];
+ return symbols[u];
+ }
+
+ ImmutableSymbolPtr &get(JS::SymbolCode code) {
+ return get(size_t(code));
}
};
#define NAME_OFFSET(name) offsetof(JSAtomState, name)
inline HandlePropertyName
AtomStateOffsetToName(const JSAtomState &atomState, size_t offset)
{
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -743,32 +743,27 @@ SavedStacks::chooseSamplingProbability(J
allocationSamplingProbability = allocationTrackingDbg->allocationSamplingProbability;
}
SavedStacks::FrameState::FrameState(const FrameIter &iter)
: principals(iter.compartment()->principals),
name(iter.isNonEvalFunctionFrame() ? iter.functionDisplayAtom() : nullptr),
location()
{
- if (principals)
- JS_HoldPrincipals(principals);
}
SavedStacks::FrameState::FrameState(const FrameState &fs)
: principals(fs.principals),
name(fs.name),
location(fs.location)
{
- if (principals)
- JS_HoldPrincipals(principals);
}
-SavedStacks::FrameState::~FrameState() {
- if (principals)
- JS_DropPrincipals(TlsPerThreadData.get()->runtimeFromMainThread(), principals);
+SavedStacks::FrameState::~FrameState()
+{
}
void
SavedStacks::FrameState::trace(JSTracer *trc) {
if (name)
gc::MarkStringUnbarriered(trc, &name, "SavedStacks::FrameState::name");
location.trace(trc);
}
--- a/js/src/vm/SavedStacks.h
+++ b/js/src/vm/SavedStacks.h
@@ -228,29 +228,32 @@ class SavedStacks {
FrameState() : principals(nullptr), name(nullptr), location() { }
explicit FrameState(const FrameIter &iter);
FrameState(const FrameState &fs);
~FrameState();
void trace(JSTracer *trc);
+ // Note: we don't have to hold/drop principals, because we're
+ // only alive while the stack is being walked and during this
+ // time the principals are kept alive by the stack itself.
JSPrincipals *principals;
JSAtom *name;
LocationValue location;
};
class MOZ_STACK_CLASS AutoFrameStateVector : public JS::CustomAutoRooter {
public:
explicit AutoFrameStateVector(JSContext *cx)
: JS::CustomAutoRooter(cx),
frames(cx)
{ }
- typedef Vector<FrameState> FrameStateVector;
+ typedef Vector<FrameState, 20> FrameStateVector;
inline FrameStateVector *operator->() { return &frames; }
inline FrameState &operator[](size_t i) { return frames[i]; }
private:
FrameStateVector frames;
virtual void trace(JSTracer *trc) {
for (size_t i = 0; i < frames.length(); i++)
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -2144,33 +2144,35 @@ DebugScopes::addDebugScope(JSContext *cx
liveScopesPostWriteBarrier(cx->runtime(), &scopes->liveScopes, &debugScope.scope());
return true;
}
void
DebugScopes::onPopCall(AbstractFramePtr frame, JSContext *cx)
{
- MOZ_ASSERT(!frame.isYielding());
assertSameCompartment(cx, frame);
DebugScopes *scopes = cx->compartment()->debugScopes;
if (!scopes)
return;
Rooted<DebugScopeObject*> debugScope(cx, nullptr);
if (frame.fun()->isHeavyweight()) {
/*
* The frame may be observed before the prologue has created the
* CallObject. See ScopeIter::settle.
*/
if (!frame.hasCallObj())
return;
+ if (frame.fun()->isGenerator())
+ return;
+
CallObject &callobj = frame.scopeChain()->as<CallObject>();
scopes->liveScopes.remove(&callobj);
if (ObjectWeakMap::Ptr p = scopes->proxiedScopes.lookup(&callobj))
debugScope = &p->value()->as<DebugScopeObject>();
} else {
ScopeIter si(frame, frame.script()->main(), cx);
if (MissingScopeMap::Ptr p = scopes->missingScopes.lookup(ScopeIterKey(si))) {
debugScope = p->value();
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -18,16 +18,17 @@
#include "builtin/Intl.h"
#include "builtin/Object.h"
#include "builtin/SelfHostingDefines.h"
#include "builtin/TypedObject.h"
#include "builtin/WeakSetObject.h"
#include "gc/Marking.h"
#include "vm/Compression.h"
#include "vm/ForkJoin.h"
+#include "vm/GeneratorObject.h"
#include "vm/Interpreter.h"
#include "vm/String.h"
#include "vm/TypedArrayCommon.h"
#include "jsfuninlines.h"
#include "jsscriptinlines.h"
#include "vm/BooleanObject-inl.h"
@@ -651,16 +652,169 @@ intrinsic_IsStringIterator(JSContext *cx
MOZ_ASSERT(args.length() == 1);
MOZ_ASSERT(args[0].isObject());
args.rval().setBoolean(args[0].toObject().is<StringIteratorObject>());
return true;
}
static bool
+intrinsic_IsStarGeneratorObject(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ args.rval().setBoolean(args[0].toObject().is<StarGeneratorObject>());
+ return true;
+}
+
+static bool
+intrinsic_StarGeneratorObjectIsClosed(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ StarGeneratorObject *genObj = &args[0].toObject().as<StarGeneratorObject>();
+ args.rval().setBoolean(genObj->isClosed());
+ return true;
+}
+
+static bool
+intrinsic_IsLegacyGeneratorObject(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ args.rval().setBoolean(args[0].toObject().is<LegacyGeneratorObject>());
+ return true;
+}
+
+static bool
+intrinsic_LegacyGeneratorObjectIsClosed(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ LegacyGeneratorObject *genObj = &args[0].toObject().as<LegacyGeneratorObject>();
+ args.rval().setBoolean(genObj->isClosed());
+ return true;
+}
+
+static bool
+intrinsic_CloseNewbornLegacyGeneratorObject(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ LegacyGeneratorObject *genObj = &args[0].toObject().as<LegacyGeneratorObject>();
+ args.rval().setBoolean(LegacyGeneratorObject::maybeCloseNewborn(genObj));
+ return true;
+}
+
+static bool
+intrinsic_CloseClosingLegacyGeneratorObject(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ LegacyGeneratorObject *genObj = &args[0].toObject().as<LegacyGeneratorObject>();
+ MOZ_ASSERT(genObj->isClosing());
+ genObj->setClosed();
+ return true;
+}
+
+static bool
+intrinsic_ThrowStopIteration(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 0);
+
+ return ThrowStopIteration(cx);
+}
+
+static bool
+intrinsic_GeneratorIsRunning(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ GeneratorObject *genObj = &args[0].toObject().as<GeneratorObject>();
+ args.rval().setBoolean(genObj->isRunning() || genObj->isClosing());
+ return true;
+}
+
+static bool
+intrinsic_GeneratorSetClosed(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ GeneratorObject *genObj = &args[0].toObject().as<GeneratorObject>();
+ genObj->setClosed();
+ return true;
+}
+
+bool
+CallSelfHostedNonGenericMethod(JSContext *cx, CallArgs args)
+{
+ // This function is called when a self-hosted method is invoked on a
+ // wrapper object, like a CrossCompartmentWrapper. The last argument is
+ // the name of the self-hosted function. The other arguments are the
+ // arguments to pass to this function.
+
+ MOZ_ASSERT(args.length() > 0);
+ RootedPropertyName name(cx, args[args.length() - 1].toString()->asAtom().asPropertyName());
+
+ RootedValue selfHostedFun(cx);
+ if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun))
+ return false;
+
+ MOZ_ASSERT(selfHostedFun.toObject().is<JSFunction>());
+
+ InvokeArgs args2(cx);
+ if (!args2.init(args.length() - 1))
+ return false;
+
+ args2.setCallee(selfHostedFun);
+ args2.setThis(args.thisv());
+
+ for (size_t i = 0; i < args.length() - 1; i++)
+ args2[i].set(args[i]);
+
+ if (!Invoke(cx, args2))
+ return false;
+
+ args.rval().set(args2.rval());
+ return true;
+}
+
+template<typename T>
+MOZ_ALWAYS_INLINE bool
+IsObjectOfType(HandleValue v)
+{
+ return v.isObject() && v.toObject().is<T>();
+}
+
+template<typename T, NativeImpl Impl>
+static bool
+NativeMethod(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<IsObjectOfType<T>, Impl>(cx, args);
+}
+
+static bool
intrinsic_IsWeakSet(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
MOZ_ASSERT(args[0].isObject());
args.rval().setBoolean(args[0].toObject().is<WeakSetObject>());
return true;
@@ -897,16 +1051,33 @@ static const JSFunctionSpec intrinsic_fu
JS_FN("GetIteratorPrototype", intrinsic_GetIteratorPrototype, 0,0),
JS_FN("NewArrayIterator", intrinsic_NewArrayIterator, 0,0),
JS_FN("IsArrayIterator", intrinsic_IsArrayIterator, 1,0),
JS_FN("NewStringIterator", intrinsic_NewStringIterator, 0,0),
JS_FN("IsStringIterator", intrinsic_IsStringIterator, 1,0),
+ JS_FN("IsStarGeneratorObject", intrinsic_IsStarGeneratorObject, 1,0),
+ JS_FN("StarGeneratorObjectIsClosed", intrinsic_StarGeneratorObjectIsClosed, 1,0),
+
+ JS_FN("IsLegacyGeneratorObject", intrinsic_IsLegacyGeneratorObject, 1,0),
+ JS_FN("LegacyGeneratorObjectIsClosed", intrinsic_LegacyGeneratorObjectIsClosed, 1,0),
+ JS_FN("CloseNewbornLegacyGeneratorObject", intrinsic_CloseNewbornLegacyGeneratorObject, 1,0),
+ JS_FN("CloseClosingLegacyGeneratorObject", intrinsic_CloseClosingLegacyGeneratorObject, 1,0),
+ JS_FN("ThrowStopIteration", intrinsic_ThrowStopIteration, 0,0),
+
+ JS_FN("GeneratorIsRunning", intrinsic_GeneratorIsRunning, 1,0),
+ JS_FN("GeneratorSetClosed", intrinsic_GeneratorSetClosed, 1,0),
+
+ JS_FN("CallLegacyGeneratorMethodIfWrapped",
+ (NativeMethod<LegacyGeneratorObject, CallSelfHostedNonGenericMethod>), 2, 0),
+ JS_FN("CallStarGeneratorMethodIfWrapped",
+ (NativeMethod<StarGeneratorObject, CallSelfHostedNonGenericMethod>), 2, 0),
+
JS_FN("IsWeakSet", intrinsic_IsWeakSet, 1,0),
JS_FN("ForkJoin", intrinsic_ForkJoin, 5,0),
JS_FN("ForkJoinNumWorkers", intrinsic_ForkJoinNumWorkers, 0,0),
JS_FN("NewDenseArray", intrinsic_NewDenseArray, 1,0),
JS_FN("ShouldForceSequential", intrinsic_ShouldForceSequential, 0,0),
JS_FN("ParallelTestsShouldPass", intrinsic_ParallelTestsShouldPass, 0,0),
JS_FNINFO("ClearThreadLocalArenas",
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -10,16 +10,17 @@
#include "vm/Stack.h"
#include "mozilla/PodOperations.h"
#include "jscntxt.h"
#include "jit/BaselineFrame.h"
#include "jit/RematerializedFrame.h"
+#include "vm/GeneratorObject.h"
#include "vm/ScopeObject.h"
#include "jsobjinlines.h"
#include "jit/BaselineFrame-inl.h"
namespace js {
@@ -321,16 +322,55 @@ InterpreterStack::pushInlineFrame(JSCont
/* Initialize frame, locals, regs. */
fp->initCallFrame(cx, prev, prevpc, prevsp, *callee, script, argv, args.length(), flags);
regs.prepareToRun(*fp, script);
return true;
}
+MOZ_ALWAYS_INLINE bool
+InterpreterStack::resumeGeneratorCallFrame(JSContext *cx, InterpreterRegs ®s,
+ HandleFunction callee, HandleValue thisv,
+ HandleObject scopeChain)
+{
+ MOZ_ASSERT(callee->isGenerator());
+ RootedScript script(cx, callee->getOrCreateScript(cx));
+ InterpreterFrame *prev = regs.fp();
+ jsbytecode *prevpc = regs.pc;
+ Value *prevsp = regs.sp;
+ MOZ_ASSERT(prev);
+
+ script->ensureNonLazyCanonicalFunction(cx);
+
+ LifoAlloc::Mark mark = allocator_.mark();
+
+ // Include callee, |this|.
+ unsigned nformal = callee->nargs();
+ unsigned nvals = 2 + nformal + script->nslots();
+
+ uint8_t *buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value));
+ if (!buffer)
+ return false;
+
+ Value *argv = reinterpret_cast<Value *>(buffer) + 2;
+ argv[-2] = ObjectValue(*callee);
+ argv[-1] = thisv;
+ SetValueRangeToUndefined(argv, nformal);
+
+ InterpreterFrame *fp = reinterpret_cast<InterpreterFrame *>(argv + nformal);
+ InterpreterFrame::Flags flags = ToFrameFlags(INITIAL_NONE);
+ fp->mark_ = mark;
+ fp->initCallFrame(cx, prev, prevpc, prevsp, *callee, script, argv, 0, flags);
+ fp->resumeGeneratorFrame(scopeChain);
+
+ regs.prepareToRun(*fp, script);
+ return true;
+}
+
MOZ_ALWAYS_INLINE void
InterpreterStack::popInlineFrame(InterpreterRegs ®s)
{
InterpreterFrame *fp = regs.fp();
regs.popInlineFrame();
regs.sp[-1] = fp->returnValue();
releaseFrame(fp);
MOZ_ASSERT(regs.fp());
@@ -513,24 +553,16 @@ inline bool
AbstractFramePtr::isGeneratorFrame() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->isGeneratorFrame();
return false;
}
inline bool
-AbstractFramePtr::isYielding() const
-{
- if (isInterpreterFrame())
- return asInterpreterFrame()->isYielding();
- return false;
-}
-
-inline bool
AbstractFramePtr::isFunctionFrame() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->isFunctionFrame();
if (isBaselineFrame())
return asBaselineFrame()->isFunctionFrame();
return asRematerializedFrame()->isFunctionFrame();
}
@@ -804,43 +836,31 @@ InterpreterActivation::InterpreterActiva
: Activation(cx, Interpreter),
state_(state),
entryFrame_(entryFrame),
opMask_(0)
#ifdef DEBUG
, oldFrameCount_(cx->runtime()->interpreterStack().frameCount_)
#endif
{
- if (!state.isGenerator()) {
- regs_.prepareToRun(*entryFrame, state.script());
- MOZ_ASSERT(regs_.pc == state.script()->code());
- } else {
- regs_ = state.asGenerator()->gen()->regs;
- }
-
+ regs_.prepareToRun(*entryFrame, state.script());
+ MOZ_ASSERT(regs_.pc == state.script()->code());
MOZ_ASSERT_IF(entryFrame_->isEvalFrame(), state_.script()->isActiveEval());
}
InterpreterActivation::~InterpreterActivation()
{
// Pop all inline frames.
while (regs_.fp() != entryFrame_)
popInlineFrame(regs_.fp());
JSContext *cx = cx_->asJSContext();
MOZ_ASSERT(oldFrameCount_ == cx->runtime()->interpreterStack().frameCount_);
MOZ_ASSERT_IF(oldFrameCount_ == 0, cx->runtime()->interpreterStack().allocator_.used() == 0);
- if (state_.isGenerator()) {
- JSGenerator *gen = state_.asGenerator()->gen();
- gen->fp->unsetPushedSPSFrame();
- gen->regs = regs_;
- return;
- }
-
if (entryFrame_)
cx->runtime()->interpreterStack().releaseFrame(entryFrame_);
}
inline bool
InterpreterActivation::pushInlineFrame(const CallArgs &args, HandleScript script,
InitialFrameFlags initial)
{
@@ -856,16 +876,28 @@ InterpreterActivation::popInlineFrame(In
{
(void)frame; // Quell compiler warning.
MOZ_ASSERT(regs_.fp() == frame);
MOZ_ASSERT(regs_.fp() != entryFrame_);
cx_->asJSContext()->runtime()->interpreterStack().popInlineFrame(regs_);
}
+inline bool
+InterpreterActivation::resumeGeneratorFrame(HandleFunction callee, HandleValue thisv,
+ HandleObject scopeChain)
+{
+ InterpreterStack &stack = cx_->asJSContext()->runtime()->interpreterStack();
+ if (!stack.resumeGeneratorCallFrame(cx_->asJSContext(), regs_, callee, thisv, scopeChain))
+ return false;
+
+ MOZ_ASSERT(regs_.fp()->script()->compartment() == compartment_);
+ return true;
+}
+
inline JSContext *
AsmJSActivation::cx()
{
return cx_->asJSContext();
}
} /* namespace js */
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -87,57 +87,16 @@ InterpreterFrame::initExecuteFrame(JSCon
MOZ_ASSERT_IF(evalInFramePrev, isDebuggerFrame());
evalInFramePrev_ = evalInFramePrev;
#ifdef DEBUG
Debug_SetValueRangeToCrashOnTouch(&rval_, 1);
#endif
}
-template <InterpreterFrame::TriggerPostBarriers doPostBarrier>
-void
-InterpreterFrame::copyFrameAndValues(JSContext *cx, Value *vp, InterpreterFrame *otherfp,
- const Value *othervp, Value *othersp)
-{
- MOZ_ASSERT(othervp == otherfp->generatorArgsSnapshotBegin());
- MOZ_ASSERT(othersp >= otherfp->slots());
- MOZ_ASSERT(othersp <= otherfp->generatorSlotsSnapshotBegin() + otherfp->script()->nslots());
-
- /* Copy args, InterpreterFrame, and slots. */
- const Value *srcend = otherfp->generatorArgsSnapshotEnd();
- Value *dst = vp;
- for (const Value *src = othervp; src < srcend; src++, dst++) {
- *dst = *src;
- if (doPostBarrier)
- HeapValue::writeBarrierPost(*dst, dst);
- }
-
- *this = *otherfp;
- argv_ = vp + 2;
- unsetPushedSPSFrame();
- if (doPostBarrier)
- writeBarrierPost();
-
- srcend = othersp;
- dst = slots();
- for (const Value *src = otherfp->slots(); src < srcend; src++, dst++) {
- *dst = *src;
- if (doPostBarrier)
- HeapValue::writeBarrierPost(*dst, dst);
- }
-}
-
-/* Note: explicit instantiation for js_NewGenerator located in jsiter.cpp. */
-template
-void InterpreterFrame::copyFrameAndValues<InterpreterFrame::NoPostBarrier>(
- JSContext *, Value *, InterpreterFrame *, const Value *, Value *);
-template
-void InterpreterFrame::copyFrameAndValues<InterpreterFrame::DoPostBarrier>(
- JSContext *, Value *, InterpreterFrame *, const Value *, Value *);
-
void
InterpreterFrame::writeBarrierPost()
{
/* This needs to follow the same rules as in InterpreterFrame::mark. */
if (scopeChain_)
JSObject::writeBarrierPost(scopeChain_, &scopeChain_);
if (flags_ & HAS_ARGS_OBJ)
JSObject::writeBarrierPost(argsObj_, &argsObj_);
@@ -260,18 +219,16 @@ InterpreterFrame::prologue(JSContext *cx
}
return probes::EnterScript(cx, script, script->functionNonDelazifying(), this);
}
void
InterpreterFrame::epilogue(JSContext *cx)
{
- MOZ_ASSERT(!isYielding());
-
RootedScript script(cx, this->script());
probes::ExitScript(cx, script, script->functionNonDelazifying(), hasPushedSPSFrame());
if (isEvalFrame()) {
if (isStrictEvalFrame()) {
MOZ_ASSERT_IF(hasCallObj(), scopeChain()->as<CallObject>().isForEval());
if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
DebugScopes::onPopStrictEvalScope(this);
@@ -298,21 +255,22 @@ InterpreterFrame::epilogue(JSContext *cx
if (isGlobalFrame()) {
MOZ_ASSERT(!scopeChain()->is<ScopeObject>());
return;
}
MOZ_ASSERT(isNonEvalFunctionFrame());
- if (fun()->isHeavyweight())
- MOZ_ASSERT_IF(hasCallObj(),
+ if (fun()->isHeavyweight()) {
+ MOZ_ASSERT_IF(hasCallObj() && !fun()->isGenerator(),
scopeChain()->as<CallObject>().callee().nonLazyScript() == script);
- else
+ } else {
AssertDynamicScopeMatchesStaticScope(cx, script, scopeChain());
+ }
if (MOZ_UNLIKELY(cx->compartment()->debugMode()))
DebugScopes::onPopCall(this, cx);
if (isConstructing() && thisValue().isObject() && returnValue().isPrimitive())
setReturnValue(ObjectValue(constructorThis()));
}
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -14,17 +14,16 @@
#include "asmjs/AsmJSFrameIterator.h"
#include "jit/JitFrameIterator.h"
#ifdef CHECK_OSIPOINT_REGISTERS
#include "jit/Registers.h" // for RegisterDump
#endif
struct JSCompartment;
-struct JSGenerator;
namespace js {
class ArgumentsObject;
class AsmJSModule;
class InterpreterRegs;
class ScopeObject;
class ScriptFrameIter;
@@ -183,17 +182,16 @@ class AbstractFramePtr
inline CallObject &callObj() const;
inline bool initFunctionScopeObjects(JSContext *cx);
inline void pushOnScopeChain(ScopeObject &scope);
inline JSCompartment *compartment() const;
inline bool hasCallObj() const;
inline bool isGeneratorFrame() const;
- inline bool isYielding() const;
inline bool isFunctionFrame() const;
inline bool isGlobalFrame() const;
inline bool isEvalFrame() const;
inline bool isDebuggerFrame() const;
inline JSScript *script() const;
inline JSFunction *fun() const;
inline JSFunction *maybeFun() const;
@@ -288,27 +286,17 @@ class InterpreterFrame
* previous frame in memory. Iteration should treat
* evalInFramePrev_ as this frame's previous frame.
*/
DEBUGGER = 0x8,
GENERATOR = 0x10, /* frame is associated with a generator */
CONSTRUCTING = 0x20, /* frame is for a constructor invocation */
- /*
- * Generator frame state
- *
- * YIELDING and SUSPENDED are similar, but there are differences. After
- * a generator yields, SendToGenerator immediately clears the YIELDING
- * flag, but the frame will still have the SUSPENDED flag. Also, when the
- * generator returns but before it's GC'ed, YIELDING is not set but
- * SUSPENDED is.
- */
- YIELDING = 0x40, /* Interpret dispatched JSOP_YIELD */
- SUSPENDED = 0x80, /* Generator is not running. */
+ /* (0x40 and 0x80 are unused) */
/* Function prologue state */
HAS_CALL_OBJ = 0x100, /* CallObject created for heavyweight fun */
HAS_ARGS_OBJ = 0x200, /* ArgumentsObject created for needsArgsObj script */
/* Lazy frame initialization */
HAS_RVAL = 0x800, /* frame has rval_ set */
HAS_SCOPECHAIN = 0x1000, /* frame has scopeChain_ set */
@@ -796,39 +784,23 @@ class InterpreterFrame
}
void initGeneratorFrame() const {
MOZ_ASSERT(!isGeneratorFrame());
MOZ_ASSERT(isNonEvalFunctionFrame());
flags_ |= GENERATOR;
}
- Value *generatorArgsSnapshotBegin() const {
- MOZ_ASSERT(isGeneratorFrame());
- return argv() - 2;
- }
-
- Value *generatorArgsSnapshotEnd() const {
- MOZ_ASSERT(isGeneratorFrame());
- return argv() + js::Max(numActualArgs(), numFormalArgs());
+ void resumeGeneratorFrame(HandleObject scopeChain) {
+ MOZ_ASSERT(!isGeneratorFrame());
+ MOZ_ASSERT(isNonEvalFunctionFrame());
+ flags_ |= GENERATOR | HAS_CALL_OBJ | HAS_SCOPECHAIN;
+ scopeChain_ = scopeChain;
}
- Value *generatorSlotsSnapshotBegin() const {
- MOZ_ASSERT(isGeneratorFrame());
- return (Value *)(this + 1);
- }
-
- enum TriggerPostBarriers {
- DoPostBarrier = true,
- NoPostBarrier = false
- };
- template <TriggerPostBarriers doPostBarrier>
- void copyFrameAndValues(JSContext *cx, Value *vp, InterpreterFrame *otherfp,
- const Value *othervp, Value *othersp);
-
/*
* Other flags
*/
InitialFrameFlags initialFlags() const {
JS_STATIC_ASSERT((int)INITIAL_NONE == 0);
JS_STATIC_ASSERT((int)INITIAL_CONSTRUCT == (int)CONSTRUCTING);
uint32_t mask = CONSTRUCTING;
@@ -879,43 +851,16 @@ class InterpreterFrame
bool prevUpToDate() const {
return !!(flags_ & PREV_UP_TO_DATE);
}
void setPrevUpToDate() {
flags_ |= PREV_UP_TO_DATE;
}
- bool isYielding() {
- return !!(flags_ & YIELDING);
- }
-
- void setYielding() {
- flags_ |= YIELDING;
- }
-
- void clearYielding() {
- flags_ &= ~YIELDING;
- }
-
- bool isSuspended() const {
- MOZ_ASSERT(isGeneratorFrame());
- return flags_ & SUSPENDED;
- }
-
- void setSuspended() {
- MOZ_ASSERT(isGeneratorFrame());
- flags_ |= SUSPENDED;
- }
-
- void clearSuspended() {
- MOZ_ASSERT(isGeneratorFrame());
- flags_ &= ~SUSPENDED;
- }
-
public:
void mark(JSTracer *trc);
void markValues(JSTracer *trc, unsigned start, unsigned end);
void markValues(JSTracer *trc, Value *sp, jsbytecode *pc);
// Entered Baseline/Ion from the interpreter.
bool runningInJit() const {
return !!(flags_ & RUNNING_IN_JIT);
@@ -1047,16 +992,20 @@ class InterpreterStack
// The interpreter can push light-weight, "inline" frames without entering a
// new InterpreterActivation or recursively calling Interpret.
bool pushInlineFrame(JSContext *cx, InterpreterRegs ®s, const CallArgs &args,
HandleScript script, InitialFrameFlags initial);
void popInlineFrame(InterpreterRegs ®s);
+ bool resumeGeneratorCallFrame(JSContext *cx, InterpreterRegs ®s,
+ HandleFunction callee, HandleValue thisv,
+ HandleObject scopeChain);
+
inline void purge(JSRuntime *rt);
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
return allocator_.sizeOfExcludingThis(mallocSizeOf);
}
};
void MarkInterpreterActivations(PerThreadData *ptd, JSTracer *trc);
@@ -1231,16 +1180,19 @@ class InterpreterActivation : public Act
public:
inline InterpreterActivation(RunState &state, JSContext *cx, InterpreterFrame *entryFrame);
inline ~InterpreterActivation();
inline bool pushInlineFrame(const CallArgs &args, HandleScript script,
InitialFrameFlags initial);
inline void popInlineFrame(InterpreterFrame *frame);
+ inline bool resumeGeneratorFrame(HandleFunction callee, HandleValue thisv,
+ HandleObject scopeChain);
+
InterpreterFrame *current() const {
return regs_.fp();
}
InterpreterRegs ®s() {
return regs_;
}
InterpreterFrame *entryFrame() const {
return entryFrame_;
--- a/js/src/vm/Xdr.cpp
+++ b/js/src/vm/Xdr.cpp
@@ -24,19 +24,21 @@ XDRBuffer::freeBuffer()
#endif
}
bool
XDRBuffer::grow(size_t n)
{
MOZ_ASSERT(n > size_t(limit - cursor));
- const size_t MEM_BLOCK = 8192;
+ const size_t MIN_CAPACITY = 8192;
size_t offset = cursor - base;
- size_t newCapacity = JS_ROUNDUP(offset + n, MEM_BLOCK);
+ size_t newCapacity = mozilla::RoundUpPow2(offset + n);
+ if (newCapacity < MIN_CAPACITY)
+ newCapacity = MIN_CAPACITY;
if (isUint32Overflow(newCapacity)) {
js::gc::AutoSuppressGC suppressGC(cx());
JS_ReportErrorNumber(cx(), js_GetErrorMessage, nullptr, JSMSG_TOO_BIG_TO_ENCODE);
return false;
}
void *data = js_realloc(base, newCapacity);
if (!data) {
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -23,17 +23,17 @@ namespace js {
* versions. If deserialization fails, the data should be invalidated if
* possible.
*
* When you change this, run make_opcode_doc.py and copy the new output into
* this wiki page:
*
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
*/
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 185);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 186);
class XDRBuffer {
public:
explicit XDRBuffer(JSContext *cx)
: context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { }
JSContext *cx() const {
return context;
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -710,20 +710,21 @@ xpc::SandboxProxyHandler::set(JSContext
JS::Handle<jsid> id,
bool strict,
JS::MutableHandle<Value> vp) const
{
return BaseProxyHandler::set(cx, proxy, receiver, id, strict, vp);
}
bool
-xpc::SandboxProxyHandler::keys(JSContext *cx, JS::Handle<JSObject*> proxy,
- AutoIdVector &props) const
+xpc::SandboxProxyHandler::getOwnEnumerablePropertyKeys(JSContext *cx,
+ JS::Handle<JSObject*> proxy,
+ AutoIdVector &props) const
{
- return BaseProxyHandler::keys(cx, proxy, props);
+ return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
}
bool
xpc::SandboxProxyHandler::iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
unsigned flags, JS::MutableHandle<Value> vp) const
{
return BaseProxyHandler::iterate(cx, proxy, flags, vp);
}
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -140,16 +140,17 @@ https://bugzilla.mozilla.org/show_bug.cg
// Maintain a static list of the properties that are available on each standard
// prototype, so that we make sure to audit any new ones to make sure they're
// Xray-safe.
//
// DO NOT CHANGE WTIHOUT REVIEW FROM AN XPCONNECT PEER.
var version = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).version;
var isNightlyBuild = version.endsWith("a1");
var isReleaseBuild = !version.contains("a");
+ const jsHasSymbols = typeof Symbol === "function";
var gPrototypeProperties = {};
gPrototypeProperties['Date'] =
["getTime", "getTimezoneOffset", "getYear", "getFullYear", "getUTCFullYear",
"getMonth", "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay",
"getHours", "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds",
"getUTCSeconds", "getMilliseconds", "getUTCMilliseconds", "setTime",
"setYear", "setFullYear", "setUTCFullYear", "setMonth", "setUTCMonth",
"setDate", "setUTCDate", "setHours", "setUTCHours", "setMinutes",
@@ -192,29 +193,33 @@ https://bugzilla.mozilla.org/show_bug.cg
gPrototypeProperties['Function'] =
["constructor", "toSource", "toString", "apply", "call", "bind",
"isGenerator", "length", "name", "arguments", "caller"];
gPrototypeProperties['Function'] =
["constructor", "toSource", "toString", "apply", "call", "bind",
"isGenerator", "length", "name", "arguments", "caller"];
+ // Sort an array that may contain symbols as well as strings.
+ function sortProperties(arr) {
+ function sortKey(prop) {
+ return typeof prop + ":" + prop.toString();
+ }
+ arr.sort((a, b) => sortKey(a) < sortKey(b) ? -1 : +1);
+ }
+
// Sort all the lists so we don't need to mutate them later (or copy them
// again to sort them).
for (var c of Object.keys(gPrototypeProperties))
- gPrototypeProperties[c].sort();
+ sortProperties(gPrototypeProperties[c]);
function filterOut(array, props) {
return array.filter(p => props.indexOf(p) == -1);
}
- function appendUnique(array, vals) {
- filterOut(vals, array).forEach(v => array.push(v));
- }
-
function isTypedArrayClass(classname) {
return typedArrayClasses.indexOf(classname) >= 0;
}
function propertyIsGetter(obj, name, classname) {
return !!Object.getOwnPropertyDescriptor(obj, name).get;
}
@@ -262,29 +267,40 @@ https://bugzilla.mozilla.org/show_bug.cg
let xrayProto = Object.getPrototypeOf(xray);
let localProto = window[classname].prototype;
let desiredProtoProps = Object.getOwnPropertyNames(localProto).sort();
is(desiredProtoProps.toSource(),
gPrototypeProperties[classname].filter(id => typeof id === "string").toSource(),
"A property on the " + classname +
" prototype has changed! You need a security audit from an XPConnect peer");
+ if (jsHasSymbols) {
+ is(Object.getOwnPropertySymbols(localProto).map(uneval).sort().toSource(),
+ gPrototypeProperties[classname].filter(id => typeof id !== "string").map(uneval).sort().toSource(),
+ "A symbol-keyed property on the " + classname +
+ " prototype has been changed! You need a security audit from an XPConnect peer");
+ }
let protoProps = filterOut(desiredProtoProps, propsToSkip);
let protoCallables = protoProps.filter(name => propertyIsGetter(localProto, name, classname) ||
typeof localProto[name] == 'function' &&
name != 'constructor');
ok(protoCallables.length > 0, "Need something to test");
is(xrayProto, iwin[classname].prototype, "Xray proto is correct");
is(xrayProto, xray.__proto__, "Proto accessors agree");
var protoProto = classname == "Object" ? null : iwin.Object.prototype;
is(Object.getPrototypeOf(xrayProto), protoProto, "proto proto is correct");
testProtoCallables(protoCallables, xray, xrayProto, localProto);
is(Object.getOwnPropertyNames(xrayProto).sort().toSource(),
protoProps.toSource(), "getOwnPropertyNames works");
+ if (jsHasSymbols) {
+ is(Object.getOwnPropertySymbols(xrayProto).map(uneval).sort().toSource(),
+ gPrototypeProperties[classname].filter(id => typeof id !== "string").map(uneval).sort().toSource(),
+ protoProps.toSource(), "getOwnPropertySymbols works");
+ }
is(xrayProto.constructor, iwin[classname], "constructor property works");
xrayProto.expando = 42;
is(xray.expando, 42, "Xrayed instances see proto expandos");
is(xray2.expando, 42, "Xrayed instances see proto expandos");
}
@@ -298,57 +314,73 @@ https://bugzilla.mozilla.org/show_bug.cg
// Test the self-hosted toLocaleString.
var d = new iwin.Date();
isnot(d.toLocaleString, Cu.unwaiveXrays(d.wrappedJSObject.toLocaleString), "Different function identities");
is(Cu.getGlobalForObject(d.toLocaleString), window, "Xray global is correct");
is(Cu.getGlobalForObject(d.wrappedJSObject.toLocaleString), iwin, "Underlying global is correct");
is(d.toLocaleString('de-DE'), d.wrappedJSObject.toLocaleString('de-DE'), "Results match");
}
+ var uniqueSymbol;
+
function testObject() {
testXray('Object', Cu.unwaiveXrays(Cu.waiveXrays(iwin).Object.create(new iwin.Object())),
new iwin.Object(), []);
// Construct an object full of tricky things.
+ let symbolProps = '';