Merge m-c to autoland, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 05 May 2017 17:21:18 -0700
changeset 356862 1c93dbb91910f1c7b6f07e794ac2af7a215e4522
parent 356861 90c2b464f60c75d7c5403da527ef9c12b6530ddd (current diff)
parent 356818 37a5b7f6f101df2eb292b1b6baaf1540c9920e20 (diff)
child 356863 5a4de575944b503ec8d3f5e301200c3abc69e020
push id31775
push userihsiao@mozilla.com
push dateMon, 08 May 2017 03:10:38 +0000
treeherdermozilla-central@22aaf8bad4df [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to autoland, a=merge MozReview-Commit-ID: IeccTUJ7VtU
js/src/frontend/BytecodeEmitter.cpp
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -58,16 +58,19 @@ pref("extensions.update.autoUpdateDefaul
 pref("extensions.hotfix.id", "firefox-hotfix@mozilla.org");
 pref("extensions.hotfix.cert.checkAttributes", true);
 pref("extensions.hotfix.certs.1.sha1Fingerprint", "91:53:98:0C:C1:86:DF:47:8F:35:22:9E:11:C9:A7:31:04:49:A1:AA");
 pref("extensions.hotfix.certs.2.sha1Fingerprint", "39:E7:2B:7A:5B:CF:37:78:F9:5D:4A:E0:53:2D:2F:3D:68:53:C5:60");
 
 // Check AUS for system add-on updates.
 pref("extensions.systemAddon.update.url", "https://aus5.mozilla.org/update/3/SystemAddons/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
 
+// Disable screenshots for now, Shield will enable this.
+pref("extensions.screenshots.system-disabled", true);
+
 // Disable add-ons that are not installed by the user in all scopes by default.
 // See the SCOPE constants in AddonManager.jsm for values to use here.
 pref("extensions.autoDisableScopes", 15);
 
 // This is where the profiler WebExtension API will look for breakpad symbols.
 // NOTE: deliberately http right now since https://symbols.mozilla.org is not supported.
 pref("extensions.geckoProfiler.symbols.url", "http://symbols.mozilla.org/");
 pref("extensions.geckoProfiler.acceptedExtensionIds", "geckoprofiler@mozilla.com");
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -5881,17 +5881,17 @@ BytecodeEmitter::emitComputedPropertyNam
 bool
 BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFlavor flav)
 {
     MOZ_ASSERT(pattern->isKind(PNK_OBJECT));
     MOZ_ASSERT(pattern->isArity(PN_LIST));
 
     MOZ_ASSERT(this->stackDepth > 0);                             // ... RHS
 
-    if (!emit1(JSOP_CHECKOBJCOERCIBLE))                           // ... RHS
+    if (!emitRequireObjectCoercible())                            // ... RHS
         return false;
 
     bool needsRestPropertyExcludedSet = pattern->pn_count > 1 &&
                                         pattern->last()->isKind(PNK_SPREAD);
     if (needsRestPropertyExcludedSet) {
         if (!emitDestructuringObjRestExclusionSet(pattern))       // ... RHS SET
             return false;
 
@@ -6917,16 +6917,52 @@ BytecodeEmitter::emitWith(ParseNode* pn)
 
     if (!emitTree(pn->pn_right))
         return false;
 
     return emitterScope.leave(this);
 }
 
 bool
+BytecodeEmitter::emitRequireObjectCoercible()
+{
+    // For simplicity, handle this in self-hosted code, at cost of 13 bytes of
+    // bytecode versus 1 byte for a dedicated opcode.  As more places need this
+    // behavior, we may want to reconsider this tradeoff.
+
+#ifdef DEBUG
+    auto depth = this->stackDepth;
+#endif
+    MOZ_ASSERT(depth > 0);                 // VAL
+    if (!emit1(JSOP_DUP))                  // VAL VAL
+        return false;
+
+    // Note that "intrinsic" is a misnomer: we're calling a *self-hosted*
+    // function that's not an intrinsic!  But it nonetheless works as desired.
+    if (!emitAtomOp(cx->names().RequireObjectCoercible,
+                    JSOP_GETINTRINSIC))    // VAL VAL REQUIREOBJECTCOERCIBLE
+    {
+        return false;
+    }
+    if (!emit1(JSOP_UNDEFINED))            // VAL VAL REQUIREOBJECTCOERCIBLE UNDEFINED
+        return false;
+    if (!emit2(JSOP_PICK, 2))              // VAL REQUIREOBJECTCOERCIBLE UNDEFINED VAL
+        return false;
+    if (!emitCall(JSOP_CALL_IGNORES_RV, 1))// VAL IGNORED
+        return false;
+    checkTypeSet(JSOP_CALL_IGNORES_RV);
+
+    if (!emit1(JSOP_POP))                  // VAL
+        return false;
+
+    MOZ_ASSERT(depth == this->stackDepth);
+    return true;
+}
+
+bool
 BytecodeEmitter::emitCopyDataProperties(CopyOption option)
 {
     DebugOnly<int32_t> depth = this->stackDepth;
 
     uint32_t argc;
     if (option == CopyOption::Filtered) {
         MOZ_ASSERT(depth > 2);                 // TARGET SOURCE SET
         argc = 3;
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -703,16 +703,20 @@ struct MOZ_STACK_CLASS BytecodeEmitter
     MOZ_MUST_USE bool emitDestructuringOpsObject(ParseNode* pattern, DestructuringFlavor flav);
 
     typedef bool
     (*DestructuringDeclEmitter)(BytecodeEmitter* bce, ParseNode* pn);
 
     template <typename NameEmitter>
     MOZ_MUST_USE bool emitDestructuringDeclsWithEmitter(ParseNode* pattern, NameEmitter emitName);
 
+    // Throw a TypeError if the value atop the stack isn't convertible to an
+    // object, with no overall effect on the stack.
+    MOZ_MUST_USE bool emitRequireObjectCoercible();
+
     enum class CopyOption {
         Filtered, Unfiltered
     };
 
     // Calls either the |CopyDataProperties| or the
     // |CopyDataPropertiesUnfiltered| intrinsic function, consumes three (or
     // two in the latter case) elements from the stack.
     MOZ_MUST_USE bool emitCopyDataProperties(CopyOption option);
--- a/js/src/jit-test/tests/basic/expression-autopsy.js
+++ b/js/src/jit-test/tests/basic/expression-autopsy.js
@@ -178,20 +178,32 @@ check_one("(new foo.x(...))",
 
 check_one("[...].foo",
           function() { [undefined].foo(); },
           " is not a function");
 check_one("[...].foo",
           function() { [undefined, ...[]].foo(); },
           " is not a function");
 
-check_one("[...][Symbol.iterator](...).next(...).value",
-          function () { var [{x}] = [null, {}]; }, " is null");
-check_one("[...][Symbol.iterator](...).next(...).value",
-          function () { var [{x}] = [void 0, {}]; }, " is undefined");
+// Manual testing for this case: the only way to trigger an error is *not* on
+// an attempted property access during destructuring, and the error message
+// invoking ToObject(null) is different: "can't convert {0} to object".
+try
+{
+  (function() {
+    var [{x}] = [null, {}];
+   })();
+  throw new Error("didn't throw");
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true,
+           "expected TypeError, got " + e);
+  assertEq(e.message, "can't convert null to object");
+}
 
 try {
   (function() {
     "use strict";
     var o = [];
     Object.freeze(o);
     o[0] = "foo";
   }());