Merge inbound to mozilla-central. a=merge
authorOana Pop Rus <opoprus@mozilla.com>
Thu, 09 May 2019 00:50:52 +0300
changeset 531871 fd9b8188501938a9306105a01db5beeefeab1a19
parent 531861 72f13244bf42d994d1a559457c6081b938f8ccb2 (current diff)
parent 531870 220720dbc492807edbcc203d1dab95b632ec4a00 (diff)
child 531948 9b6e243f261203cbc078d25a9725c0e5ac44003f
child 531977 7244f626713e301a1e3a338c57ad027864c57fe5
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone68.0a1
first release with
nightly linux32
fd9b81885019 / 68.0a1 / 20190508215144 / files
nightly linux64
fd9b81885019 / 68.0a1 / 20190508215144 / files
nightly mac
fd9b81885019 / 68.0a1 / 20190508215144 / files
nightly win32
fd9b81885019 / 68.0a1 / 20190508215144 / files
nightly win64
fd9b81885019 / 68.0a1 / 20190508215144 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
--- a/devtools/client/webconsole/components/message-types/EvaluationResult.js
+++ b/devtools/client/webconsole/components/message-types/EvaluationResult.js
@@ -15,35 +15,42 @@ const GripMessageBody = require("devtool
 EvaluationResult.displayName = "EvaluationResult";
 
 EvaluationResult.propTypes = {
   dispatch: PropTypes.func.isRequired,
   message: PropTypes.object.isRequired,
   timestampsVisible: PropTypes.bool.isRequired,
   serviceContainer: PropTypes.object,
   maybeScrollToBottom: PropTypes.func,
+  open: PropTypes.bool,
+};
+
+EvaluationResult.defaultProps = {
+  open: false,
 };
 
 function EvaluationResult(props) {
   const {
     dispatch,
     message,
     serviceContainer,
     timestampsVisible,
     maybeScrollToBottom,
+    open,
   } = props;
 
   const {
     source,
     type,
     helperType,
     level,
     id: messageId,
     indent,
     exceptionDocURL,
+    stacktrace,
     frame,
     timeStamp,
     parameters,
     notes,
   } = message;
 
   let messageBody;
   if (typeof message.messageText !== "undefined" && message.messageText !== null) {
@@ -67,25 +74,29 @@ function EvaluationResult(props) {
       helperType,
       maybeScrollToBottom,
     });
   }
 
   const topLevelClasses = ["cm-s-mozilla"];
 
   return Message({
+    dispatch,
     source,
     type,
     level,
     indent,
     topLevelClasses,
     messageBody,
     messageId,
     serviceContainer,
     exceptionDocURL,
+    stacktrace,
+    collapsible: Array.isArray(stacktrace),
+    open,
     frame,
     timeStamp,
     parameters,
     notes,
     timestampsVisible,
     maybeScrollToBottom,
   });
 }
--- a/devtools/client/webconsole/test/fixtures/stub-generators/head.js
+++ b/devtools/client/webconsole/test/fixtures/stub-generators/head.js
@@ -198,16 +198,30 @@ function getCleanedPacket(key, packet) {
           if (frame && existingFrame && frame.sourceId) {
             frame.sourceId = existingFrame.sourceId;
           }
           return frame;
         });
       }
     }
 
+    if (Array.isArray(res.exceptionStack)) {
+      res.exceptionStack = res.exceptionStack.map((frame, i) => {
+        const existingFrame = existingPacket.exceptionStack[i];
+        if (frame && existingFrame && frame.sourceId) {
+          frame.sourceId = existingFrame.sourceId;
+        }
+        return frame;
+      });
+    }
+
+    if (res.frame && existingPacket.frame) {
+      res.frame.sourceId = existingPacket.frame.sourceId;
+    }
+
     if (res.packet) {
       const override = {};
       const keys = ["totalTime", "from", "contentSize", "transferredSize"];
       keys.forEach(x => {
         if (res.packet[x] !== undefined) {
           override[x] = existingPacket.packet[key];
         }
       });
--- a/devtools/client/webconsole/test/fixtures/stubs/evaluationResult.js
+++ b/devtools/client/webconsole/test/fixtures/stubs/evaluationResult.js
@@ -32,18 +32,17 @@ stubPreparedMessages.set(`new Date(0)`, 
       "frozen": false,
       "sealed": false,
       "ownPropertyLength": 0,
       "preview": {
         "timestamp": 0
       }
     }
   ],
-  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"log\",\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj30\",\"class\":\"Date\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"timestamp\":0}}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":null}",
-  "stacktrace": null,
+  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"log\",\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj30\",\"class\":\"Date\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":0,\"preview\":{\"timestamp\":0}}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
   "frame": null,
   "groupId": null,
   "cssSelectors": "",
   "userProvidedStyles": null,
   "notes": null,
   "indent": 0,
   "prefix": "",
   "chromeContext": false
@@ -60,18 +59,26 @@ stubPreparedMessages.set(`asdf()`, new C
   "level": "error",
   "category": null,
   "messageText": "ReferenceError: asdf is not defined",
   "parameters": [
     {
       "type": "undefined"
     }
   ],
-  "repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":null}",
-  "stacktrace": null,
+  "repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"ReferenceError: asdf is not defined\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":[{\"filename\":\"debugger eval code\",\"sourceId\":\"server1.conn0.child1/source23\",\"lineNumber\":1,\"columnNumber\":1,\"functionName\":null}]}",
+  "stacktrace": [
+    {
+      "filename": "debugger eval code",
+      "sourceId": "server1.conn0.child1/source23",
+      "lineNumber": 1,
+      "columnNumber": 1,
+      "functionName": null
+    }
+  ],
   "frame": {
     "source": "debugger eval code",
     "line": 1,
     "column": 1
   },
   "groupId": null,
   "errorMessageName": "JSMSG_NOT_DEFINED",
   "exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default",
@@ -94,18 +101,61 @@ stubPreparedMessages.set(`1 + @`, new Co
   "level": "error",
   "category": null,
   "messageText": "SyntaxError: illegal character",
   "parameters": [
     {
       "type": "undefined"
     }
   ],
-  "repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":4},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"SyntaxError: illegal character\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":null}",
-  "stacktrace": null,
+  "repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"line\":1,\"column\":4},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"SyntaxError: illegal character\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":[{\"filename\":\"resource://devtools/server/actors/webconsole/eval-with-debugger.js\",\"sourceId\":null,\"lineNumber\":134,\"columnNumber\":28,\"functionName\":\"getEvalResult\"},{\"filename\":\"resource://devtools/server/actors/webconsole/eval-with-debugger.js\",\"sourceId\":null,\"lineNumber\":105,\"columnNumber\":18,\"functionName\":\"exports.evalWithDebugger\"},{\"filename\":\"resource://devtools/server/actors/webconsole.js\",\"sourceId\":null,\"lineNumber\":1005,\"columnNumber\":22,\"functionName\":\"evaluateJS\"},{\"filename\":\"self-hosted\",\"sourceId\":null,\"lineNumber\":1005,\"columnNumber\":17,\"functionName\":\"evaluateJS\"},{\"filename\":\"resource://devtools/server/main.js\",\"sourceId\":null,\"lineNumber\":1291,\"columnNumber\":58,\"functionName\":\"onPacket\"},{\"filename\":\"resource://devtools/shared/transport/child-transport.js\",\"sourceId\":null,\"lineNumber\":66,\"columnNumber\":16,\"functionName\":\"receiveMessage\"}]}",
+  "stacktrace": [
+    {
+      "filename": "resource://devtools/server/actors/webconsole/eval-with-debugger.js",
+      "sourceId": null,
+      "lineNumber": 134,
+      "columnNumber": 28,
+      "functionName": "getEvalResult"
+    },
+    {
+      "filename": "resource://devtools/server/actors/webconsole/eval-with-debugger.js",
+      "sourceId": null,
+      "lineNumber": 105,
+      "columnNumber": 18,
+      "functionName": "exports.evalWithDebugger"
+    },
+    {
+      "filename": "resource://devtools/server/actors/webconsole.js",
+      "sourceId": null,
+      "lineNumber": 1005,
+      "columnNumber": 22,
+      "functionName": "evaluateJS"
+    },
+    {
+      "filename": "self-hosted",
+      "sourceId": null,
+      "lineNumber": 1005,
+      "columnNumber": 17,
+      "functionName": "evaluateJS"
+    },
+    {
+      "filename": "resource://devtools/server/main.js",
+      "sourceId": null,
+      "lineNumber": 1291,
+      "columnNumber": 58,
+      "functionName": "onPacket"
+    },
+    {
+      "filename": "resource://devtools/shared/transport/child-transport.js",
+      "sourceId": null,
+      "lineNumber": 66,
+      "columnNumber": 16,
+      "functionName": "receiveMessage"
+    }
+  ],
   "frame": {
     "source": "debugger eval code",
     "line": 1,
     "column": 4
   },
   "groupId": null,
   "errorMessageName": "JSMSG_ILLEGAL_CHARACTER",
   "exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Illegal_character?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default",
@@ -148,18 +198,17 @@ stubPreparedMessages.set(`inspect({a: 1}
         },
         "ownSymbols": [],
         "ownPropertiesLength": 1,
         "ownSymbolsLength": 0,
         "safeGetterValues": {}
       }
     }
   ],
-  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"log\",\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj35\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"a\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":1}},\"ownSymbols\":[],\"ownPropertiesLength\":1,\"ownSymbolsLength\":0,\"safeGetterValues\":{}}}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":null}",
-  "stacktrace": null,
+  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"log\",\"parameters\":[{\"type\":\"object\",\"actor\":\"server1.conn0.child1/obj35\",\"class\":\"Object\",\"extensible\":true,\"frozen\":false,\"sealed\":false,\"ownPropertyLength\":1,\"preview\":{\"kind\":\"Object\",\"ownProperties\":{\"a\":{\"configurable\":true,\"enumerable\":true,\"writable\":true,\"value\":1}},\"ownSymbols\":[],\"ownPropertiesLength\":1,\"ownSymbolsLength\":0,\"safeGetterValues\":{}}}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
   "frame": null,
   "groupId": null,
   "cssSelectors": "",
   "userProvidedStyles": null,
   "notes": null,
   "indent": 0,
   "prefix": "",
   "chromeContext": false
@@ -176,18 +225,17 @@ stubPreparedMessages.set(`cd(document)`,
   "level": "error",
   "category": null,
   "messageText": "Cannot cd() to the given window. Invalid argument.",
   "parameters": [
     {
       "type": "undefined"
     }
   ],
-  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"Cannot cd() to the given window. Invalid argument.\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":null}",
-  "stacktrace": null,
+  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"Cannot cd() to the given window. Invalid argument.\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
   "frame": null,
   "groupId": null,
   "cssSelectors": "",
   "userProvidedStyles": null,
   "notes": null,
   "indent": 0,
   "prefix": "",
   "chromeContext": false
@@ -203,18 +251,17 @@ stubPreparedMessages.set(`undefined`, ne
   "helperType": null,
   "level": "log",
   "category": null,
   "parameters": [
     {
       "type": "undefined"
     }
   ],
-  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"log\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":null}",
-  "stacktrace": null,
+  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"log\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null}",
   "frame": null,
   "groupId": null,
   "cssSelectors": "",
   "userProvidedStyles": null,
   "notes": null,
   "indent": 0,
   "prefix": "",
   "chromeContext": false
@@ -236,19 +283,32 @@ stubPreparedMessages.set(`longString mes
     "length": 110007,
     "actor": "server1.conn0.child1/longString37"
   },
   "parameters": [
     {
       "type": "undefined"
     }
   ],
-  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":{\"type\":\"longString\",\"initial\":\"Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon\",\"length\":110007,\"actor\":\"server1.conn0.child1/longString37\"},\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":null}",
-  "stacktrace": null,
-  "frame": null,
+  "repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"sourceId\":\"server1.conn0.child1/source30\",\"line\":1,\"column\":7},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":{\"type\":\"longString\",\"initial\":\"Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon\",\"length\":110007,\"actor\":\"server1.conn0.child1/longString37\"},\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":[{\"filename\":\"debugger eval code\",\"sourceId\":\"server1.conn0.child1/source30\",\"lineNumber\":1,\"columnNumber\":7,\"functionName\":null}]}",
+  "stacktrace": [
+    {
+      "filename": "debugger eval code",
+      "sourceId": "server1.conn0.child1/source30",
+      "lineNumber": 1,
+      "columnNumber": 7,
+      "functionName": null
+    }
+  ],
+  "frame": {
+    "source": "debugger eval code",
+    "sourceId": "server1.conn0.child1/source30",
+    "line": 1,
+    "column": 7
+  },
   "groupId": null,
   "cssSelectors": "",
   "userProvidedStyles": null,
   "notes": null,
   "indent": 0,
   "prefix": "",
   "chromeContext": false
 }));
@@ -264,19 +324,32 @@ stubPreparedMessages.set(`eval throw ""`
   "level": "error",
   "category": null,
   "messageText": "Error",
   "parameters": [
     {
       "type": "undefined"
     }
   ],
-  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"Error\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":null}",
-  "stacktrace": null,
-  "frame": null,
+  "repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"sourceId\":\"server1.conn0.child1/source23\",\"line\":1,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"Error\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":[{\"filename\":\"debugger eval code\",\"sourceId\":\"server1.conn0.child1/source23\",\"lineNumber\":1,\"columnNumber\":1,\"functionName\":null}]}",
+  "stacktrace": [
+    {
+      "filename": "debugger eval code",
+      "sourceId": "server1.conn0.child1/source23",
+      "lineNumber": 1,
+      "columnNumber": 1,
+      "functionName": null
+    }
+  ],
+  "frame": {
+    "source": "debugger eval code",
+    "sourceId": "server1.conn0.child1/source23",
+    "line": 1,
+    "column": 1
+  },
   "groupId": null,
   "cssSelectors": "",
   "userProvidedStyles": null,
   "notes": null,
   "indent": 0,
   "prefix": "",
   "chromeContext": false
 }));
@@ -292,19 +365,32 @@ stubPreparedMessages.set(`eval throw "to
   "level": "error",
   "category": null,
   "messageText": "Error: tomato",
   "parameters": [
     {
       "type": "undefined"
     }
   ],
-  "repeatId": "{\"frame\":null,\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"Error: tomato\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":null}",
-  "stacktrace": null,
-  "frame": null,
+  "repeatId": "{\"frame\":{\"source\":\"debugger eval code\",\"sourceId\":\"server1.conn0.child1/source23\",\"line\":1,\"column\":1},\"groupId\":null,\"indent\":0,\"level\":\"error\",\"messageText\":\"Error: tomato\",\"parameters\":[{\"type\":\"undefined\"}],\"source\":\"javascript\",\"type\":\"result\",\"userProvidedStyles\":null,\"stacktrace\":[{\"filename\":\"debugger eval code\",\"sourceId\":\"server1.conn0.child1/source23\",\"lineNumber\":1,\"columnNumber\":1,\"functionName\":null}]}",
+  "stacktrace": [
+    {
+      "filename": "debugger eval code",
+      "sourceId": "server1.conn0.child1/source23",
+      "lineNumber": 1,
+      "columnNumber": 1,
+      "functionName": null
+    }
+  ],
+  "frame": {
+    "source": "debugger eval code",
+    "sourceId": "server1.conn0.child1/source23",
+    "line": 1,
+    "column": 1
+  },
   "groupId": null,
   "cssSelectors": "",
   "userProvidedStyles": null,
   "notes": null,
   "indent": 0,
   "prefix": "",
   "chromeContext": false
 }));
@@ -353,16 +439,25 @@ stubPackets.set(`asdf()`, {
       "stack": "@debugger eval code:1:1\n",
       "fileName": "debugger eval code",
       "lineNumber": 1,
       "columnNumber": 1
     }
   },
   "exceptionMessage": "ReferenceError: asdf is not defined",
   "exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default",
+  "exceptionStack": [
+    {
+      "filename": "debugger eval code",
+      "sourceId": "server1.conn0.child1/source23",
+      "lineNumber": 1,
+      "columnNumber": 1,
+      "functionName": null
+    }
+  ],
   "errorMessageName": "JSMSG_NOT_DEFINED",
   "frame": {
     "source": "debugger eval code",
     "line": 1,
     "column": 1
   },
   "helperResult": null,
   "notes": null
@@ -390,16 +485,60 @@ stubPackets.set(`1 + @`, {
       "stack": "",
       "fileName": "debugger eval code",
       "lineNumber": 1,
       "columnNumber": 4
     }
   },
   "exceptionMessage": "SyntaxError: illegal character",
   "exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Illegal_character?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default",
+  "exceptionStack": [
+    {
+      "filename": "resource://devtools/server/actors/webconsole/eval-with-debugger.js",
+      "sourceId": null,
+      "lineNumber": 134,
+      "columnNumber": 28,
+      "functionName": "getEvalResult"
+    },
+    {
+      "filename": "resource://devtools/server/actors/webconsole/eval-with-debugger.js",
+      "sourceId": null,
+      "lineNumber": 105,
+      "columnNumber": 18,
+      "functionName": "exports.evalWithDebugger"
+    },
+    {
+      "filename": "resource://devtools/server/actors/webconsole.js",
+      "sourceId": null,
+      "lineNumber": 1005,
+      "columnNumber": 22,
+      "functionName": "evaluateJS"
+    },
+    {
+      "filename": "self-hosted",
+      "sourceId": null,
+      "lineNumber": 1005,
+      "columnNumber": 17,
+      "functionName": "evaluateJS"
+    },
+    {
+      "filename": "resource://devtools/server/main.js",
+      "sourceId": null,
+      "lineNumber": 1291,
+      "columnNumber": 58,
+      "functionName": "onPacket"
+    },
+    {
+      "filename": "resource://devtools/shared/transport/child-transport.js",
+      "sourceId": null,
+      "lineNumber": 66,
+      "columnNumber": 16,
+      "functionName": "receiveMessage"
+    }
+  ],
   "errorMessageName": "JSMSG_ILLEGAL_CHARACTER",
   "frame": {
     "source": "debugger eval code",
     "line": 1,
     "column": 4
   },
   "helperResult": null,
   "notes": null
@@ -505,45 +644,87 @@ stubPackets.set(`longString message Erro
     }
   },
   "exceptionMessage": {
     "type": "longString",
     "initial": "Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon",
     "length": 110007,
     "actor": "server1.conn0.child1/longString37"
   },
-  "frame": null,
+  "exceptionStack": [
+    {
+      "filename": "debugger eval code",
+      "sourceId": "server1.conn0.child1/source30",
+      "lineNumber": 1,
+      "columnNumber": 7,
+      "functionName": null
+    }
+  ],
+  "frame": {
+    "source": "debugger eval code",
+    "sourceId": "server1.conn0.child1/source30",
+    "line": 1,
+    "column": 7
+  },
   "helperResult": null,
   "notes": null
 });
 
 stubPackets.set(`eval throw ""`, {
   "from": "server1.conn0.child1/consoleActor2",
   "input": "throw \"\"",
   "result": {
     "type": "undefined"
   },
   "timestamp": 1517990289517,
   "exception": "",
   "exceptionMessage": "",
-  "frame": null,
+  "exceptionStack": [
+    {
+      "filename": "debugger eval code",
+      "sourceId": "server1.conn0.child1/source23",
+      "lineNumber": 1,
+      "columnNumber": 1,
+      "functionName": null
+    }
+  ],
+  "frame": {
+    "source": "debugger eval code",
+    "sourceId": "server1.conn0.child1/source23",
+    "line": 1,
+    "column": 1
+  },
   "helperResult": null,
   "notes": null
 });
 
 stubPackets.set(`eval throw "tomato"`, {
   "from": "server1.conn0.child1/consoleActor2",
   "input": "throw \"tomato\"",
   "result": {
     "type": "undefined"
   },
   "timestamp": 1517990289520,
   "exception": "tomato",
   "exceptionMessage": "tomato",
-  "frame": null,
+  "exceptionStack": [
+    {
+      "filename": "debugger eval code",
+      "sourceId": "server1.conn0.child1/source23",
+      "lineNumber": 1,
+      "columnNumber": 1,
+      "functionName": null
+    }
+  ],
+  "frame": {
+    "source": "debugger eval code",
+    "sourceId": "server1.conn0.child1/source23",
+    "line": 1,
+    "column": 1
+  },
   "helperResult": null,
   "notes": null
 });
 
 module.exports = {
   stubPreparedMessages,
   stubPackets,
 };
--- a/devtools/client/webconsole/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/test/mochitest/browser.ini
@@ -43,16 +43,17 @@ support-files =
   test-data.json^headers^
   test-duplicate-error.html
   test-dynamic-import.html
   test-dynamic-import.js
   test-error.html
   test-error-worker.html
   test-error-worker.js
   test-error-worker2.js
+  test-eval-error.html
   test-eval-in-stackframe.html
   test-eval-sources.html
   test-evaluate-worker.html
   test-evaluate-worker.js
   test-external-script-errors.html
   test-external-script-errors.js
   test-iframe-insecure-form-action.html
   test-iframe1.html
@@ -291,16 +292,17 @@ tags = clipboard
 [browser_webconsole_csp_violation.js]
 [browser_webconsole_cspro.js]
 [browser_webconsole_document_focus.js]
 [browser_webconsole_duplicate_errors.js]
 [browser_webconsole_error_with_grouped_stack.js]
 [browser_webconsole_error_with_longstring_stack.js]
 [browser_webconsole_error_with_unicode.js]
 [browser_webconsole_errors_after_page_reload.js]
+[browser_webconsole_eval_error.js]
 [browser_webconsole_eval_in_debugger_stackframe.js]
 [browser_webconsole_eval_in_debugger_stackframe2.js]
 [browser_webconsole_eval_sources.js]
 [browser_webconsole_execution_scope.js]
 [browser_webconsole_external_script_errors.js]
 [browser_webconsole_file_uri.js]
 skip-if = true #	Bug 1404382
 [browser_webconsole_filter_by_input.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_eval_error.js
@@ -0,0 +1,22 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that throwing uncaught errors while doing console evaluations shows a
+// stack in the console.
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
+                 "test/mochitest/test-eval-error.html";
+
+add_task(async function() {
+  const hud = await openNewTabAndConsole(TEST_URI);
+
+  hud.jsterm.execute("throwErrorObject()");
+  await checkMessageStack(hud, "ThrowErrorObject", [6, 1]);
+
+  hud.jsterm.execute("throwValue(40 + 2)");
+  await checkMessageStack(hud, "42", [14, 10, 1]);
+});
--- a/devtools/client/webconsole/test/mochitest/head.js
+++ b/devtools/client/webconsole/test/mochitest/head.js
@@ -1329,17 +1329,17 @@ function checkConsoleOutputForWarningGro
  *        message substring to look for
  * @param {Array<number>} frameLines
  *        line numbers of the frames expected in the stack
  */
 async function checkMessageStack(hud, text, frameLines) {
   const msgNode = await waitFor(() => findMessage(hud, text));
   ok(!msgNode.classList.contains("open"), `Error logged not expanded`);
 
-  const button = msgNode.querySelector(".collapse-button");
+  const button = await waitFor(() => msgNode.querySelector(".collapse-button"));
   button.click();
 
   const framesNode = await waitFor(() => msgNode.querySelector(".frames"));
   const frameNodes = framesNode.querySelectorAll(".frame");
   ok(frameNodes.length == frameLines.length, `Found ${frameLines.length} frames`);
   for (let i = 0; i < frameLines.length; i++) {
     ok(frameNodes[i].querySelector(".line").textContent == "" + frameLines[i],
        `Found line ${frameLines[i]} for frame #${i}`);
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/test/mochitest/test-eval-error.html
@@ -0,0 +1,16 @@
+<script>
+/* eslint-disable no-unused-vars */
+"use strict";
+
+function throwErrorObject(value) {
+  throw new Error("ThrowErrorObject");
+}
+
+function throwValue(value) {
+  otherFunction(value);
+}
+
+function otherFunction(value) {
+  throw value;
+}
+</script>
--- a/devtools/client/webconsole/utils/messages.js
+++ b/devtools/client/webconsole/utils/messages.js
@@ -288,16 +288,17 @@ function transformNetworkEventPacket(pac
 }
 
 function transformEvaluationResultPacket(packet) {
   let {
     exceptionMessage,
     errorMessageName,
     exceptionDocURL,
     exception,
+    exceptionStack,
     frame,
     result,
     helperResult,
     timestamp: timeStamp,
     notes,
   } = packet;
 
   const parameter = helperResult && helperResult.object
@@ -323,16 +324,17 @@ function transformEvaluationResultPacket
     source: MESSAGE_SOURCE.JAVASCRIPT,
     type: MESSAGE_TYPE.RESULT,
     helperType: helperResult ? helperResult.type : null,
     level,
     messageText: exceptionMessage,
     parameters: [parameter],
     errorMessageName,
     exceptionDocURL,
+    stacktrace: exceptionStack,
     frame,
     timeStamp,
     notes,
     private: packet.private,
   });
 }
 
 // Helpers
--- a/devtools/server/actors/webconsole.js
+++ b/devtools/server/actors/webconsole.js
@@ -1005,17 +1005,17 @@ WebConsoleActor.prototype =
     const evalInfo = evalWithDebugger(input, evalOptions, this);
 
     this.parentActor.threadActor.insideClientEvaluation = false;
 
     const evalResult = evalInfo.result;
     const helperResult = evalInfo.helperResult;
 
     let result, errorDocURL, errorMessage, errorNotes = null, errorGrip = null,
-      frame = null, awaitResult, errorMessageName;
+      frame = null, awaitResult, errorMessageName, exceptionStack;
     if (evalResult) {
       if ("return" in evalResult) {
         result = evalResult.return;
         if (
           mapped &&
           mapped.await &&
           result &&
           result.class === "Promise" &&
@@ -1024,16 +1024,31 @@ WebConsoleActor.prototype =
           awaitResult = result.unsafeDereference();
         }
       } else if ("yield" in evalResult) {
         result = evalResult.yield;
       } else if ("throw" in evalResult) {
         const error = evalResult.throw;
         errorGrip = this.createValueGrip(error);
 
+        exceptionStack = this.prepareStackForRemote(evalResult.stack);
+
+        if (exceptionStack) {
+          // Set the frame based on the topmost stack frame for the exception.
+          const {
+            filename: source,
+            sourceId,
+            lineNumber: line,
+            columnNumber: column,
+          } = exceptionStack[0];
+          frame = { source, sourceId, line, column };
+
+          exceptionStack = WebConsoleUtils.removeFramesAboveDebuggerEval(exceptionStack);
+        }
+
         errorMessage = String(error);
         if (typeof error === "object" && error !== null) {
           try {
             errorMessage = DevToolsUtils.callPropertyOnObject(error, "toString");
           } catch (e) {
             // If the debuggee is not allowed to access the "toString" property
             // of the error object, calling this property from the debuggee's
             // compartment will fail. The debugger should show the error object
@@ -1127,16 +1142,17 @@ WebConsoleActor.prototype =
       from: this.actorID,
       input: input,
       result: resultGrip,
       awaitResult,
       timestamp: timestamp,
       exception: errorGrip,
       exceptionMessage: this._createStringGrip(errorMessage),
       exceptionDocURL: errorDocURL,
+      exceptionStack,
       errorMessageName,
       frame,
       helperResult: helperResult,
       notes: errorNotes,
     };
   },
 
   /**
@@ -1461,42 +1477,55 @@ WebConsoleActor.prototype =
   },
 
   getActorIdForInternalSourceId(id) {
     const actor = this.parentActor.sources.getSourceActorByInternalSourceId(id);
     return actor ? actor.actorID : null;
   },
 
   /**
+   * Prepare a SavedFrame stack to be sent to the client.
+   *
+   * @param SavedFrame errorStack
+   *        Stack for an error we need to send to the client.
+   * @return object
+   *         The object you can send to the remote client.
+   */
+  prepareStackForRemote(errorStack) {
+    // Convert stack objects to the JSON attributes expected by client code
+    // Bug 1348885: If the global from which this error came from has been
+    // nuked, stack is going to be a dead wrapper.
+    if (!errorStack || (Cu && Cu.isDeadWrapper(errorStack))) {
+      return null;
+    }
+    const stack = [];
+    let s = errorStack;
+    while (s) {
+      stack.push({
+        filename: s.source,
+        sourceId: this.getActorIdForInternalSourceId(s.sourceId),
+        lineNumber: s.line,
+        columnNumber: s.column,
+        functionName: s.functionDisplayName,
+      });
+      s = s.parent;
+    }
+    return stack;
+  },
+
+  /**
    * Prepare an nsIScriptError to be sent to the client.
    *
    * @param nsIScriptError pageError
    *        The page error we need to send to the client.
    * @return object
    *         The object you can send to the remote client.
    */
   preparePageErrorForRemote: function(pageError) {
-    let stack = null;
-    // Convert stack objects to the JSON attributes expected by client code
-    // Bug 1348885: If the global from which this error came from has been
-    // nuked, stack is going to be a dead wrapper.
-    if (pageError.stack && !Cu.isDeadWrapper(pageError.stack)) {
-      stack = [];
-      let s = pageError.stack;
-      while (s !== null) {
-        stack.push({
-          filename: s.source,
-          sourceId: this.getActorIdForInternalSourceId(s.sourceId),
-          lineNumber: s.line,
-          columnNumber: s.column,
-          functionName: s.functionDisplayName,
-        });
-        s = s.parent;
-      }
-    }
+    const stack = this.prepareStackForRemote(pageError.stack);
     let lineText = pageError.sourceLine;
     if (lineText && lineText.length > DebuggerServer.LONG_STRING_INITIAL_LENGTH) {
       lineText = lineText.substr(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH);
     }
 
     let notesArray = null;
     const notes = pageError.notes;
     if (notes && notes.length) {
--- a/devtools/server/actors/webconsole/utils.js
+++ b/devtools/server/actors/webconsole/utils.js
@@ -188,16 +188,39 @@ var WebConsoleUtils = {
       case "function":
         return objectWrapper(value);
       default:
         console.error("Failed to provide a grip for value of " + typeof value
                       + ": " + value);
         return null;
     }
   },
+
+  /**
+   * Remove any frames in a stack that are above a debugger-triggered evaluation
+   * and will correspond with devtools server code, which we never want to show
+   * to the user.
+   *
+   * @param array stack
+   *        An array of frames, with the topmost first, and each of which has a
+   *        'filename' property.
+   * @return array
+   *         An array of stack frames with any devtools server frames removed.
+   *         The original array is not modified.
+   */
+  removeFramesAboveDebuggerEval(stack) {
+    // Remove any frames for server code above the debugger eval.
+    const evalIndex = stack.findIndex(({ filename }) => {
+      return filename == "debugger eval code";
+    });
+    if (evalIndex != -1) {
+      return stack.slice(0, evalIndex + 1);
+    }
+    return stack;
+  },
 };
 
 exports.WebConsoleUtils = WebConsoleUtils;
 
 /**
  * WebConsole commands manager.
  *
  * Defines a set of functions /variables ("commands") that are available from
--- a/devtools/shared/specs/webconsole.js
+++ b/devtools/shared/specs/webconsole.js
@@ -44,16 +44,17 @@ const webconsoleSpecPrototype = {
     evaluationResult: {
       resultID: Option(0, "string"),
       type: "evaluationResult",
       awaitResult: Option(0, "nullable:boolean"),
       errorMessageName: Option(0, "nullable:string"),
       exception: Option(0, "nullable:json"),
       exceptionMessage: Option(0, "nullable:string"),
       exceptionDocURL: Option(0, "nullable:string"),
+      exceptionStack: Option(0, "nullable:json"),
       frame: Option(0, "nullable:json"),
       helperResult: Option(0, "nullable:json"),
       input: Option(0, "nullable:string"),
       notes: Option(0, "nullable:string"),
       result: Option(0, "nullable:json"),
       timestamp: Option(0, "string"),
       topLevelAwaitRejected: Option(0, "nullable:boolean"),
     },
--- a/js/src/doc/Debugger/Conventions.md
+++ b/js/src/doc/Debugger/Conventions.md
@@ -71,19 +71,20 @@ of debuggee call initiated by the debugg
 interface provides a value describing how the code completed; these are
 called *completion values*. A completion value has one of the
 following forms:
 
 <code>{ return: <i>value</i> }</code>
 :   The code completed normally, returning <i>value</i>. <i>Value</i> is a
     debuggee value.
 
-<code>{ throw: <i>value</i> }</code>
+<code>{ throw: <i>value</i>, stack: <i>stack</i> }</code>
 :   The code threw <i>value</i> as an exception. <i>Value</i> is a debuggee
-    value.
+    value.  <i>stack</i> is a `SavedFrame` representing the location from which
+    the value was thrown, and may be missing.
 
 `null`
 :   The code was terminated, as if by the "slow script" dialog box.
 
 If control reaches the end of a generator frame, the completion value is
 <code>{ throw: <i>stop</i> }</code> where <i>stop</i> is a
 `Debugger.Object` object representing the `StopIteration` object being
 thrown.
@@ -103,17 +104,21 @@ resumption value has one of the followin
 <code>{ return: <i>value</i> }</code>
 :   Force the top frame of the debuggee to return <i>value</i> immediately,
     as if by executing a `return` statement. <i>Value</i> must be a debuggee
     value. (Most handler functions support this, except those whose
     descriptions say otherwise.) See the list of special cases below.
 
 <code>{ throw: <i>value</i> }</code>
 :   Throw <i>value</i> as an exception from the current bytecode
-    instruction. <i>Value</i> must be a debuggee value.
+    instruction. <i>Value</i> must be a debuggee value. Note that unlike
+    completion values, resumption values do not specify a stack.  When
+    initiating an exceptional return from a handler, the current debuggee stack
+    will be used. If a handler wants to avoid modifying the stack of an
+    already-thrown exception, it should return `undefined`.
 
 `null`
 :   Terminate the debuggee, as if it had been cancelled by the "slow script"
     dialog box.
 
 In some places, the JS language treats `return` statements specially or
 doesn't allow them at all. So there are a few special cases.
 
index 301fd6874f682bda79f6d78a980c44f3162f184e..e37e2bc3bd4726f5f83cedd9f56fefbdfa412c45
GIT binary patch
literal 2126
zc$|Gx?QY^m6up^RmW8YcA%swbkQGIUB?zG?TBVy+N=QgHQ9`0XSKDU$W3UHs*4T7B
zgwm?d&|iI-_HFtEeSu27Gq$mlGzA&Y+>bM7&bf3i`j-Q8e|~p-eSLiQgX=I~xMFqq
zd+w}$p*CZe@!n5!&ce_Q{K^USymZ?f2r69rn$1Sps#>~~1#E^utt(eBPQ8KPu0Kf&
z+Ht(Um@)3!X`-=CWKZ1gy1s(|DLH7I1Q-&Sq?y9%G3RuZ?(4^4$hct6DYHGwnbW5;
zR{Kb~OGh4yf>eU+JdXvune^V`e#Vg2zz*ijO2XI?1<nFKqu#nI+&^3RwggRiAX$Ob
z!{!zJdG#`F-HaZXEz-cz`s^T#FS*8-SCIE|C%%+8ZQ4(RL&_&iq;j=Sg4uk5c+X8s
zjOYe|$7qJqLDuBwz}B~O2OUnU_Y%GXo4a#y?gb+>U8#fCQJ%4+d`bnq<(T4P)lRgy
z;nz$|11Axxl@%)EQ!VD307x;m`fQovn-PWk!SL>)e?Ca3`#1fwHum*L%JWpQ?ft0P
zkGZjwwYUgzypHE{Z<V9+*RXNqP0qxE`($EFT@jj*NxCzd6i|hQlp{3QBlQd~2$>;R
zC`i+I2wdOz!d78T5+5xl6C9l6|Df&e>V4WT3|Dj3;~a-9qB5NFU>RQcp`gCaZpP-6
zd0t@YfzNcY406kWdrm%qD@ILW>mf8HPsTot>*H7~tNzCN#fq3)Yo0BS`4cfcw0?ba
zc$qDxO>2~Guy(DHs_JB_<oy(^kUXuiD%fAA$13N<>@Zou89|3cAn=|y<5F}RbqUjR
zM~=%;GU`-(wv>ZOxsW6axQ!;KFi)Cu>co=zZK68%7qWXlyzBK+U;i;r-x{Sd*(eq8
zDdJ-h04V4L`sCnyxH8_C3EA2#5V#{X@~(5+-q48#g$gmwRHod8cLWM*UCcrJIRe;3
zq_52PP$6~5ZNP>_HgowZfT=h3pj_Vp$P@Te-v(7-fT}R^Rjq`Fmw;?QMS(&~17mBA
ztYUfra>xQq%`9qhYP%CJ+8vqN)XkR(MAkHdUntcG=sU#NHu7;0N*^$Uub~QPpy%Vh
zuRD69`Q%7r&p3z=k;~U%C5mwwEi(XmjQsaE@uHY;{4OGInEz9e@G5s+0E6l#W*(YP
zb5R1Kcw3X|1ALI;OW{EpL((hOAVI1Dv@#u6uXUJ3ELAO<se1OI(JUsT(#?AQ#|z5=
zv<%y)en)!m8*iT{r1lt2#DLDzBRkn6|9WN0syOU9HBr^qr>vR?TSa02%j!>w)gKY#
V=qZg;%vnVKY2*u3B^1{N{tI#y{t*BG
index 5906df8924bae15fc2979baf38563fd7db350ed6..f5e5b671c4484b3f62059cbe43cd697dc6fb9d04
GIT binary patch
literal 2120
zc$|$>ZENCK6h2-;2oj2jh!l}fia1t8N*TJ-p=)1kw`FRJy2I>t_ro>0YC17-Z?1J^
z+263A_eU=5PuO#B5)<2<VU(DA&&zY3^PJ=PP5*XC9<K*ycXwxlUtNd!!WHY2zw=j(
z8+DnujQ4(Da2AGc;8!oG=cU)yP*CC8cWge+M%B}!3}ABvYJYGA<J21p?)uX-pcC8s
z%Q@q&ojRHuN4DbLx$8R!kdlMuMSv!OPMQg<opDar>Ai6lhKvj5Tr%6EoH>0uXZ4Si
zyL9Za$Ver~{!3fHTS@K%-scQy4eemTti+5Nk>M)fbLwrP!gh~N8NXWkwnR?J9KAMS
z69QWbt^4s4vqkDS-4qYPxXVoe*@JA%o%&MaOo7xmqI}9ks#oVCm@k%y_i}2<B+i4t
zV>CnUI6LK+z}Alo2S=PnA0~W<Hg^}|+6%@wbtMnZj`GY*DwkBy2aYZ-)}1Y_G6U%(
zwtIfZ#4K<Usp>J|1VO5?+h?n^fEjUk9F7Jz{p(@6-+$@9XcJ$5ro2EE-QI7S{hXgj
zT}#Ul7wl}Y@YZ=Me+?U#-sDUyxlg9X%oU*-O-Xmg(;~{SlzM~)d#0Y@1tBv83k7Kz
zPl4+jpV>OB%Z|p&DR#K|M`#BJdY|@-qxFLIIL9@MsElSjScNx!D5!6<`-wSYo)=hp
z;4@vUg8VAro>NHRN>NhSehN*=ld(^e#w1qEYP_-jup;KxhG*Mj{#49PtUuqJ+-8Gm
z%Nl1BtOIMTqPm$V*`I<HlBYFM0Y@A6MERVU9XhMHBsd`v2<-EIQjWS&O_-iLc3h5<
zQK#y&mE26qg(O+TYqUDWMUtFX70c?kh3eR!$-(1j(Cejh{l~m~Ym_S_S1#gH!p9;2
zP}B+Z$??zd!FXRGWOt`XU_k2RUH74r(}@PfDlx8<r*aPO2o%-1l!y599$*KNPN7N~
zkk3KRB0Kp)4Zzf!hfrzk0Tc-AgYp}o{6?Xsm9cOcNDitB5ZW3TyBkzx(~FQt24HGt
zNsC>3-T2VyO4p8VzIGt8rV;!?xlTaeC&r#ph>cMG0ZsTCDT4-jA<p}*t2bL)C5=Pl
zI4&ZOUxt+^#%*-W0O&FDzu(7)Qo`}4h`eEbB_iQf>AnI6l}*e7w6=Yb10s7zliGvQ
zUg{2VDkSZ&4hc{lp#2RAW(gxzhGwdiBWSit$&#FZb>0A4hU)gPBe9Q+w=W%1cr+(U
zKzF-h_Zv2>hD)AT+f@7VhSd^LYbfgfjrmhD=8uSRy3OJeeHM{_7Wo1d38l^O{sXj6
B`;h<u
--- a/js/src/jit-test/tests/debug/Frame-live-07.js
+++ b/js/src/jit-test/tests/debug/Frame-live-07.js
@@ -29,25 +29,28 @@ function test(when, what) {
     dbg.onDebuggerStatement = frame => {
         dbg.onEnterFrame = frame => {
             frame.onPop = function() {
                 return tick(this);
             };
             return tick(frame);
         };
         let result = frame.eval("for (let _ of f(0)) {}");
+        if (result && "stack" in result) {
+          result.stack = true;
+        }
         assertDeepEq(result, what);
     };
     g.eval("debugger;");
 
     assertEq(t, when);
     assertEq(poppedFrame.live, false);
     assertErrorMessage(() => poppedFrame.older,
                        Error,
                        "Debugger.Frame is not live");
 }
 
 for (let when = 0; when < 6; when++) {
-    for (let what of [null, {throw: "fit"}]) {
+    for (let what of [null, {throw: "fit", stack: true}]) {
         test(when, what);
     }
 }
 
--- a/js/src/jit-test/tests/debug/Object-apply-01.js
+++ b/js/src/jit-test/tests/debug/Object-apply-01.js
@@ -38,21 +38,21 @@ function test(usingApply) {
     dbg.onDebuggerStatement = function (frame) {
         assertEq((usingApply ? frame.arguments[0].apply(null, ['one', 'two'])
                              : frame.arguments[0].call(null, 'one', 'two')).return,
                  2);
         hits++;
     };
     g.eval("f(function () { return arguments.length; });");
 
-    // Exceptions are reported as {throw:} completion values.
+    // Exceptions are reported as {throw,stack} completion values.
     dbg.onDebuggerStatement = function (frame) {
         var lose = frame.arguments[0];
         var cv = usingApply ? lose.apply(null, []) : lose.call(null);
-        assertEq(Object.keys(cv).join(","), "throw");
+        assertEq(Object.keys(cv).join(","), "throw,stack");
         assertEq(cv.throw, frame.callee);
         hits++;
     };
     g.eval("f(function lose() { throw f; });");
 }
 
 test(true);
 test(false);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/onExceptionUnwind-resumption-05.js
@@ -0,0 +1,32 @@
+// Make sure that stacks in completion values are not lost when an exception
+// unwind hook returns undefined.
+
+let g = newGlobal({ newCompartment: true });
+g.eval(`
+  function foo() {
+    bar();
+  }
+  function bar() {
+    throw new Error();
+  }
+`);
+
+let dbg = Debugger(g);
+let unwindHits = 0, popHits = 0;
+dbg.onExceptionUnwind = frame => {
+  unwindHits++;
+  return undefined;
+}
+dbg.onEnterFrame = frame => {
+  frame.onPop = completion => {
+    assertEq(completion.stack.functionDisplayName, "bar");
+    popHits++;
+  };
+};
+
+try {
+  g.eval("foo()");
+} catch (e) {}
+assertEq(unwindHits, 3);
+assertEq(popHits, 3);
+dbg.removeDebuggee(g);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/resumption-09.js
@@ -0,0 +1,41 @@
+// Test exception stack behavior when reusing completion values as resumption
+// values.
+
+load(libdir + "asserts.js");
+
+var g = newGlobal({newCompartment: true});
+g.eval(`
+  function foo() {
+    bar();
+  }
+  function bar() {
+    debugger;
+  }
+  function baz() {
+    throw new Error();
+  }
+`);
+
+var dbg = Debugger(g);
+dbg.onDebuggerStatement = frame => {
+  return frame.eval("baz()");
+};
+
+let popHits = 0;
+dbg.onEnterFrame = frame => {
+  frame.onPop = completion => {
+    popHits++;
+    // Resumption values ignore any 'stack' property, and the script location of
+    // the place where the hook was called will be used when throwing.
+    if (popHits <= 2) {
+      assertEq(completion.stack.functionDisplayName, "baz");
+    } else {
+      assertEq(completion.stack.functionDisplayName, "bar");
+    }
+  };
+};
+
+try {
+  g.eval("foo()");
+} catch (e) {}
+assertEq(popHits, 5);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1037,18 +1037,19 @@ bool Debugger::slowPathOnLeaveFrame(JSCo
   }
   if (frames.empty()) {
     return frameOk;
   }
 
   // Save the frame's completion value.
   ResumeMode resumeMode;
   RootedValue value(cx);
+  RootedSavedFrame exnStack(cx);
   Debugger::resultToCompletion(cx, frameOk, frame.returnValue(), &resumeMode,
-                               &value);
+                               &value, &exnStack);
 
   // Preserve the debuggee's microtask event queue while we run the hooks, so
   // the debugger's microtask checkpoints don't run from the debuggee's
   // microtasks, and vice versa.
   JS::AutoDebuggerJobQueueInterruption adjqi;
   if (!adjqi.init(cx)) {
     return false;
   }
@@ -1078,17 +1079,18 @@ bool Debugger::slowPathOnLeaveFrame(JSCo
         }
 
         // Call the onPop handler.
         ResumeMode nextResumeMode = resumeMode;
         RootedValue nextValue(cx, wrappedValue);
         bool success;
         {
           AutoSetGeneratorRunning asgr(cx, genObj);
-          success = handler->onPop(cx, frameobj, nextResumeMode, &nextValue);
+          success = handler->onPop(cx, frameobj, nextResumeMode, &nextValue,
+                                   exnStack);
         }
         nextResumeMode = dbg->processParsedHandlerResult(
             ar, frame, pc, success, nextResumeMode, &nextValue);
         adjqi.runJobs();
 
         // At this point, we are back in the debuggee compartment, and
         // any error has been wrapped up as a completion value.
         MOZ_ASSERT(cx->compartment() == debuggeeGlobal->compartment());
@@ -1106,17 +1108,23 @@ bool Debugger::slowPathOnLeaveFrame(JSCo
   // Establish (resumeMode, value) as our resumption value.
   switch (resumeMode) {
     case ResumeMode::Return:
       frame.setReturnValue(value);
       success = true;
       return true;
 
     case ResumeMode::Throw:
-      cx->setPendingExceptionAndCaptureStack(value);
+      // If we have a stack from the original throw, use it instead of
+      // associating the throw with the current execution point.
+      if (exnStack) {
+        cx->setPendingException(value, exnStack);
+      } else {
+        cx->setPendingExceptionAndCaptureStack(value);
+      }
       return false;
 
     case ResumeMode::Terminate:
       MOZ_ASSERT(!cx->isExceptionPending());
       return false;
 
     default:
       MOZ_CRASH("bad final onLeaveFrame resume mode");
@@ -1890,44 +1898,47 @@ ResumeMode Debugger::processHandlerResul
                        resumeMode, vp);
 }
 
 /*** Debuggee completion values *********************************************/
 
 /* static */
 void Debugger::resultToCompletion(JSContext* cx, bool ok, const Value& rv,
                                   ResumeMode* resumeMode,
-                                  MutableHandleValue value) {
+                                  MutableHandleValue value,
+                                  MutableHandleSavedFrame exnStack) {
   MOZ_ASSERT_IF(ok, !cx->isExceptionPending());
 
   if (ok) {
     *resumeMode = ResumeMode::Return;
     value.set(rv);
   } else if (cx->isExceptionPending()) {
     *resumeMode = ResumeMode::Throw;
     if (!cx->getPendingException(value)) {
       *resumeMode = ResumeMode::Terminate;
     }
+    exnStack.set(cx->getPendingExceptionStack());
     cx->clearPendingException();
   } else {
     *resumeMode = ResumeMode::Terminate;
     value.setUndefined();
   }
 }
 
 bool Debugger::newCompletionValue(JSContext* cx, ResumeMode resumeMode,
-                                  const Value& value_,
+                                  const Value& value_, SavedFrame* exnStack_,
                                   MutableHandleValue result) {
   // We must be in the debugger's compartment, since that's where we want
   // to construct the completion value.
   cx->check(object.get());
   cx->check(value_);
 
   RootedId key(cx);
   RootedValue value(cx, value_);
+  RootedSavedFrame exnStack(cx, exnStack_);
 
   switch (resumeMode) {
     case ResumeMode::Return:
       key = NameToId(cx->names().return_);
       break;
 
     case ResumeMode::Throw:
       key = NameToId(cx->names().throw_);
@@ -1943,30 +1954,40 @@ bool Debugger::newCompletionValue(JSCont
 
   // Common tail for ResumeMode::Return and ResumeMode::Throw.
   RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
   if (!obj ||
       !NativeDefineDataProperty(cx, obj, key, value, JSPROP_ENUMERATE)) {
     return false;
   }
 
+  if (exnStack) {
+    RootedId nkey(cx, NameToId(cx->names().stack));
+    RootedValue nvalue(cx, ObjectValue(*exnStack));
+    if (!cx->compartment()->wrap(cx, &nvalue) ||
+        !NativeDefineDataProperty(cx, obj, nkey, nvalue, JSPROP_ENUMERATE)) {
+      return false;
+    }
+  }
+
   result.setObject(*obj);
   return true;
 }
 
 bool Debugger::receiveCompletionValue(Maybe<AutoRealm>& ar, bool ok,
                                       HandleValue val, MutableHandleValue vp) {
   JSContext* cx = ar->context();
 
   ResumeMode resumeMode;
   RootedValue value(cx);
-  resultToCompletion(cx, ok, val, &resumeMode, &value);
+  RootedSavedFrame exnStack(cx);
+  resultToCompletion(cx, ok, val, &resumeMode, &value, &exnStack);
   ar.reset();
   return wrapDebuggeeValue(cx, &value) &&
-         newCompletionValue(cx, resumeMode, value, vp);
+         newCompletionValue(cx, resumeMode, value, exnStack, vp);
 }
 
 /*** Firing debugger hooks **************************************************/
 
 static bool CallMethodIfPresent(JSContext* cx, HandleObject obj,
                                 const char* name, size_t argc, Value* argv,
                                 MutableHandleValue rval) {
   rval.setUndefined();
@@ -8914,34 +8935,35 @@ void ScriptedOnPopHandler::drop() {
 }
 
 void ScriptedOnPopHandler::trace(JSTracer* tracer) {
   TraceEdge(tracer, &object_, "OnStepHandlerFunction.object");
 }
 
 bool ScriptedOnPopHandler::onPop(JSContext* cx, HandleDebuggerFrame frame,
                                  ResumeMode& resumeMode,
-                                 MutableHandleValue vp) {
+                                 MutableHandleValue vp,
+                                 HandleSavedFrame exnStack) {
   Debugger* dbg = frame->owner();
 
   // Make it possible to distinguish 'return' from 'await' completions.
   // Bug 1470558 will investigate a more robust solution.
   bool isAfterAwait = false;
   AbstractFramePtr referent = DebuggerFrame::getReferent(frame);
   if (resumeMode == ResumeMode::Return && referent &&
       referent.isFunctionFrame() && referent.callee()->isAsync() &&
       !referent.callee()->isGenerator()) {
     AutoRealm ar(cx, referent.callee());
     if (auto* genObj = GetGeneratorObjectForFrame(cx, referent)) {
       isAfterAwait = !genObj->isClosed() && genObj->isRunning();
     }
   }
 
   RootedValue completion(cx);
-  if (!dbg->newCompletionValue(cx, resumeMode, vp, &completion)) {
+  if (!dbg->newCompletionValue(cx, resumeMode, vp, exnStack, &completion)) {
     return false;
   }
 
   if (isAfterAwait) {
     RootedObject obj(cx, &completion.toObject());
     if (!DefineDataProperty(cx, obj, cx->names().await, TrueHandleValue)) {
       return false;
     }
@@ -9390,17 +9412,18 @@ static bool EvaluateInEnv(JSContext* cx,
   return ExecuteKernel(cx, script, *env, NullValue(), frame, rval.address());
 }
 
 static bool DebuggerGenericEval(JSContext* cx,
                                 const mozilla::Range<const char16_t> chars,
                                 HandleObject bindings,
                                 const EvalOptions& options,
                                 ResumeMode& resumeMode,
-                                MutableHandleValue value, Debugger* dbg,
+                                MutableHandleValue value,
+                                MutableHandleSavedFrame exnStack, Debugger* dbg,
                                 HandleObject envArg, FrameIter* iter) {
   // Either we're specifying the frame, or a global.
   MOZ_ASSERT_IF(iter, !envArg);
   MOZ_ASSERT_IF(!iter, envArg && IsGlobalLexicalEnvironment(envArg));
 
   // Gather keys and values of bindings, if any. This must be done in the
   // debugger compartment, since that is where any exceptions must be thrown.
   RootedIdVector keys(cx);
@@ -9471,40 +9494,41 @@ static bool DebuggerGenericEval(JSContex
   LeaveDebuggeeNoExecute nnx(cx);
   RootedValue rval(cx);
   AbstractFramePtr frame = iter ? iter->abstractFramePtr() : NullFramePtr();
 
   bool ok = EvaluateInEnv(
       cx, env, frame, chars,
       options.filename() ? options.filename() : "debugger eval code",
       options.lineno(), &rval);
-  Debugger::resultToCompletion(cx, ok, rval, &resumeMode, value);
+  Debugger::resultToCompletion(cx, ok, rval, &resumeMode, value, exnStack);
   ar.reset();
   return dbg->wrapDebuggeeValue(cx, value);
 }
 
 /* static */
 bool DebuggerFrame::eval(JSContext* cx, HandleDebuggerFrame frame,
                          mozilla::Range<const char16_t> chars,
                          HandleObject bindings, const EvalOptions& options,
-                         ResumeMode& resumeMode, MutableHandleValue value) {
+                         ResumeMode& resumeMode, MutableHandleValue value,
+                         MutableHandleSavedFrame exnStack) {
   MOZ_ASSERT(frame->isLive());
 
   Debugger* dbg = frame->owner();
 
   Maybe<FrameIter> maybeIter;
   if (!DebuggerFrame::getFrameIter(cx, frame, maybeIter)) {
     return false;
   }
   FrameIter& iter = *maybeIter;
 
   UpdateFrameIterPc(iter);
 
   return DebuggerGenericEval(cx, chars, bindings, options, resumeMode, value,
-                             dbg, nullptr, &iter);
+                             exnStack, dbg, nullptr, &iter);
 }
 
 /* static */
 bool DebuggerFrame::isLive() const { return !!getPrivate(); }
 
 OnStepHandler* DebuggerFrame::onStepHandler() const {
   Value value = getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER);
   return value.isUndefined() ? nullptr
@@ -10078,22 +10102,24 @@ bool DebuggerFrame::evalMethod(JSContext
 
   EvalOptions options;
   if (!ParseEvalOptions(cx, args.get(1), options)) {
     return false;
   }
 
   ResumeMode resumeMode;
   RootedValue value(cx);
+  RootedSavedFrame exnStack(cx);
   if (!DebuggerFrame::eval(cx, frame, chars, nullptr, options, resumeMode,
-                           &value)) {
-    return false;
-  }
-
-  return frame->owner()->newCompletionValue(cx, resumeMode, value, args.rval());
+                           &value, &exnStack)) {
+    return false;
+  }
+
+  return frame->owner()->newCompletionValue(cx, resumeMode, value, exnStack,
+                                            args.rval());
 }
 
 /* static */
 bool DebuggerFrame::evalWithBindingsMethod(JSContext* cx, unsigned argc,
                                            Value* vp) {
   THIS_DEBUGGER_FRAME(cx, argc, vp, "evalWithBindings", args, frame);
   if (!args.requireAtLeast(cx, "Debugger.Frame.prototype.evalWithBindings",
                            2)) {
@@ -10114,22 +10140,24 @@ bool DebuggerFrame::evalWithBindingsMeth
 
   EvalOptions options;
   if (!ParseEvalOptions(cx, args.get(2), options)) {
     return false;
   }
 
   ResumeMode resumeMode;
   RootedValue value(cx);
+  RootedSavedFrame exnStack(cx);
   if (!DebuggerFrame::eval(cx, frame, chars, bindings, options, resumeMode,
-                           &value)) {
-    return false;
-  }
-
-  return frame->owner()->newCompletionValue(cx, resumeMode, value, args.rval());
+                           &value, &exnStack)) {
+    return false;
+  }
+
+  return frame->owner()->newCompletionValue(cx, resumeMode, value, exnStack,
+                                            args.rval());
 }
 
 /* static */
 bool DebuggerFrame::construct(JSContext* cx, unsigned argc, Value* vp) {
   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
                             "Debugger.Frame");
   return false;
 }
@@ -11253,22 +11281,23 @@ bool DebuggerObject::executeInGlobalMeth
 
   EvalOptions options;
   if (!ParseEvalOptions(cx, args.get(1), options)) {
     return false;
   }
 
   ResumeMode resumeMode;
   RootedValue value(cx);
+  RootedSavedFrame exnStack(cx);
   if (!DebuggerObject::executeInGlobal(cx, object, chars, nullptr, options,
-                                       resumeMode, &value)) {
-    return false;
-  }
-
-  return object->owner()->newCompletionValue(cx, resumeMode, value,
+                                       resumeMode, &value, &exnStack)) {
+    return false;
+  }
+
+  return object->owner()->newCompletionValue(cx, resumeMode, value, exnStack,
                                              args.rval());
 }
 
 /* static */
 bool DebuggerObject::executeInGlobalWithBindingsMethod(JSContext* cx,
                                                        unsigned argc,
                                                        Value* vp) {
   THIS_DEBUGOBJECT(cx, argc, vp, "executeInGlobalWithBindings", args, object);
@@ -11296,22 +11325,23 @@ bool DebuggerObject::executeInGlobalWith
 
   EvalOptions options;
   if (!ParseEvalOptions(cx, args.get(2), options)) {
     return false;
   }
 
   ResumeMode resumeMode;
   RootedValue value(cx);
+  RootedSavedFrame exnStack(cx);
   if (!DebuggerObject::executeInGlobal(cx, object, chars, bindings, options,
-                                       resumeMode, &value)) {
-    return false;
-  }
-
-  return object->owner()->newCompletionValue(cx, resumeMode, value,
+                                       resumeMode, &value, &exnStack)) {
+    return false;
+  }
+
+  return object->owner()->newCompletionValue(cx, resumeMode, value, exnStack,
                                              args.rval());
 }
 
 /* static */
 bool DebuggerObject::makeDebuggeeValueMethod(JSContext* cx, unsigned argc,
                                              Value* vp) {
   THIS_DEBUGOBJECT(cx, argc, vp, "makeDebuggeeValue", args, object);
   if (!args.requireAtLeast(cx, "Debugger.Object.prototype.makeDebuggeeValue",
@@ -12266,25 +12296,26 @@ bool DebuggerObject::forceLexicalInitial
 }
 
 /* static */
 bool DebuggerObject::executeInGlobal(JSContext* cx, HandleDebuggerObject object,
                                      mozilla::Range<const char16_t> chars,
                                      HandleObject bindings,
                                      const EvalOptions& options,
                                      ResumeMode& resumeMode,
-                                     MutableHandleValue value) {
+                                     MutableHandleValue value,
+                                     MutableHandleSavedFrame exnStack) {
   MOZ_ASSERT(object->isGlobal());
 
   Rooted<GlobalObject*> referent(cx, &object->referent()->as<GlobalObject>());
   Debugger* dbg = object->owner();
 
   RootedObject globalLexical(cx, &referent->lexicalEnvironment());
   return DebuggerGenericEval(cx, chars, bindings, options, resumeMode, value,
-                             dbg, globalLexical, nullptr);
+                             exnStack, dbg, globalLexical, nullptr);
 }
 
 /* static */
 bool DebuggerObject::makeDebuggeeValue(JSContext* cx,
                                        HandleDebuggerObject object,
                                        HandleValue value_,
                                        MutableHandleValue result) {
   RootedObject referent(cx, object->referent());
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -1145,30 +1145,33 @@ class Debugger : private mozilla::Linked
   MOZ_MUST_USE bool getFrame(JSContext* cx, const FrameIter& iter,
                              MutableHandleDebuggerFrame result);
 
   /*
    * Set |*resumeMode| and |*value| to a (ResumeMode, Value) pair reflecting a
    * standard SpiderMonkey call state: a boolean success value |ok|, a return
    * value |rv|, and a context |cx| that may or may not have an exception set.
    * If an exception was pending on |cx|, it is cleared (and |ok| is asserted
-   * to be false).
+   * to be false). On exceptional returns, exnStack will be set to any stack
+   * associated with the original throw, if available.
    */
   static void resultToCompletion(JSContext* cx, bool ok, const Value& rv,
                                  ResumeMode* resumeMode,
-                                 MutableHandleValue value);
+                                 MutableHandleValue value,
+                                 MutableHandleSavedFrame exnStack);
 
   /*
    * Set |*result| to a JavaScript completion value corresponding to
    * |resumeMode| and |value|. |value| should be the return value or exception
-   * value, not wrapped as a debuggee value. |cx| must be in the debugger
-   * compartment.
+   * value, not wrapped as a debuggee value. When throwing an exception,
+   * |exnStack| may be set to the stack when the value was thrown. |cx| must be
+   * in the debugger compartment.
    */
   MOZ_MUST_USE bool newCompletionValue(JSContext* cx, ResumeMode resumeMode,
-                                       const Value& value,
+                                       const Value& value, SavedFrame* exnStack,
                                        MutableHandleValue result);
 
   /*
    * Precondition: we are in the debuggee realm (ar is entered) and ok is true
    * if the operation in the debuggee realm succeeded, false on error or
    * exception.
    *
    * Postcondition: we are in the debugger realm, having called `ar.reset()`
@@ -1406,27 +1409,29 @@ struct OnPopHandler : Handler {
   /*
    * If a frame is about the be popped, this method is called with the frame
    * as argument, and `resumeMode` and `vp` set to a completion value specifying
    * how this frame's execution completed. If successful, this method should
    * return true, with `resumeMode` and `vp` set to a resumption value
    * specifying how execution should continue.
    */
   virtual bool onPop(JSContext* cx, HandleDebuggerFrame frame,
-                     ResumeMode& resumeMode, MutableHandleValue vp) = 0;
+                     ResumeMode& resumeMode, MutableHandleValue vp,
+                     HandleSavedFrame exnStack) = 0;
 };
 
 class ScriptedOnPopHandler final : public OnPopHandler {
  public:
   explicit ScriptedOnPopHandler(JSObject* object);
   virtual JSObject* object() const override;
   virtual void drop() override;
   virtual void trace(JSTracer* tracer) override;
   virtual bool onPop(JSContext* cx, HandleDebuggerFrame frame,
-                     ResumeMode& resumeMode, MutableHandleValue vp) override;
+                     ResumeMode& resumeMode, MutableHandleValue vp,
+                     HandleSavedFrame exnStack) override;
 
  private:
   HeapPtr<JSObject*> object_;
 };
 
 class DebuggerFrame : public NativeObject {
   friend class DebuggerArguments;
   friend class ScriptedOnStepHandler;
@@ -1467,17 +1472,18 @@ class DebuggerFrame : public NativeObjec
                                             HandleDebuggerFrame frame,
                                             OnStepHandler* handler);
 
   static MOZ_MUST_USE bool eval(JSContext* cx, HandleDebuggerFrame frame,
                                 mozilla::Range<const char16_t> chars,
                                 HandleObject bindings,
                                 const EvalOptions& options,
                                 ResumeMode& resumeMode,
-                                MutableHandleValue value);
+                                MutableHandleValue value,
+                                MutableHandleSavedFrame exnStack);
 
   bool isLive() const;
   OnStepHandler* onStepHandler() const;
   OnPopHandler* onPopHandler() const;
   void setOnPopHandler(OnPopHandler* handler);
 
   /*
    * Called after a generator/async frame is resumed, before exposing this
@@ -1638,17 +1644,18 @@ class DebuggerObject : public NativeObje
   static MOZ_MUST_USE bool forceLexicalInitializationByName(
       JSContext* cx, HandleDebuggerObject object, HandleId id, bool& result);
   static MOZ_MUST_USE bool executeInGlobal(JSContext* cx,
                                            HandleDebuggerObject object,
                                            mozilla::Range<const char16_t> chars,
                                            HandleObject bindings,
                                            const EvalOptions& options,
                                            ResumeMode& resumeMode,
-                                           MutableHandleValue value);
+                                           MutableHandleValue value,
+                                           MutableHandleSavedFrame exnStack);
   static MOZ_MUST_USE bool makeDebuggeeValue(JSContext* cx,
                                              HandleDebuggerObject object,
                                              HandleValue value,
                                              MutableHandleValue result);
   static MOZ_MUST_USE bool unsafeDereference(JSContext* cx,
                                              HandleDebuggerObject object,
                                              MutableHandleObject result);
   static MOZ_MUST_USE bool unwrap(JSContext* cx, HandleDebuggerObject object,
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -1818,19 +1818,17 @@ nsDocumentViewer::Destroy() {
   // references.  If we do this stuff in the destructor, the
   // destructor might never be called (especially if we're being
   // used from JS.
 
 #ifdef NS_PRINTING
   if (mPrintJob) {
     RefPtr<nsPrintJob> printJob = std::move(mPrintJob);
 #  ifdef NS_PRINT_PREVIEW
-    bool doingPrintPreview;
-    printJob->GetDoingPrintPreview(&doingPrintPreview);
-    if (doingPrintPreview) {
+    if (printJob->IsDoingPrintPreview()) {
       printJob->FinishPrintPreview();
     }
 #  endif
     printJob->Destroy();
     MOZ_ASSERT(!mPrintJob,
                "mPrintJob shouldn't be recreated while destroying it");
   }
 #endif
@@ -3718,45 +3716,40 @@ nsDocumentViewer::GetGlobalPrintSettings
   return nsPrintJob::GetGlobalPrintSettings(aGlobalPrintSettings);
 }
 
 // XXX This always returns false for subdocuments
 NS_IMETHODIMP
 nsDocumentViewer::GetDoingPrint(bool* aDoingPrint) {
   NS_ENSURE_ARG_POINTER(aDoingPrint);
 
-  *aDoingPrint = false;
-  if (mPrintJob) {
-    // XXX shouldn't this be GetDoingPrint() ?
-    return mPrintJob->GetDoingPrintPreview(aDoingPrint);
-  }
+  // XXX shouldn't this be GetDoingPrint() ?
+  *aDoingPrint = mPrintJob ? mPrintJob->IsDoingPrintPreview() : false;
   return NS_OK;
 }
 
 // XXX This always returns false for subdocuments
 NS_IMETHODIMP
 nsDocumentViewer::GetDoingPrintPreview(bool* aDoingPrintPreview) {
   NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
 
-  *aDoingPrintPreview = false;
-  if (mPrintJob) {
-    return mPrintJob->GetDoingPrintPreview(aDoingPrintPreview);
-  }
+  *aDoingPrintPreview = mPrintJob ? mPrintJob->IsDoingPrintPreview() : false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::GetCurrentPrintSettings(
     nsIPrintSettings** aCurrentPrintSettings) {
   NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
 
   *aCurrentPrintSettings = nullptr;
   NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE);
 
-  return mPrintJob->GetCurrentPrintSettings(aCurrentPrintSettings);
+  *aCurrentPrintSettings = mPrintJob->GetCurrentPrintSettings().take();
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::Cancel() {
   NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE);
   return mPrintJob->Cancelled();
 }
 
@@ -3788,65 +3781,70 @@ nsDocumentViewer::EnumerateDocumentNames
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::GetIsFramesetFrameSelected(bool* aIsFramesetFrameSelected) {
 #  ifdef NS_PRINTING
   *aIsFramesetFrameSelected = false;
   NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE);
 
-  return mPrintJob->GetIsFramesetFrameSelected(aIsFramesetFrameSelected);
+  *aIsFramesetFrameSelected = mPrintJob->IsFramesetFrameSelected();
+  return NS_OK;
 #  else
   return NS_ERROR_FAILURE;
 #  endif
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::GetPrintPreviewNumPages(int32_t* aPrintPreviewNumPages) {
 #  ifdef NS_PRINTING
   NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
   NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE);
 
-  return mPrintJob->GetPrintPreviewNumPages(aPrintPreviewNumPages);
+  *aPrintPreviewNumPages = mPrintJob->GetPrintPreviewNumPages();
+  return *aPrintPreviewNumPages > 0 ? NS_OK : NS_ERROR_FAILURE;
 #  else
   return NS_ERROR_FAILURE;
 #  endif
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::GetIsFramesetDocument(bool* aIsFramesetDocument) {
 #  ifdef NS_PRINTING
   *aIsFramesetDocument = false;
   NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE);
 
-  return mPrintJob->GetIsFramesetDocument(aIsFramesetDocument);
+  *aIsFramesetDocument = mPrintJob->IsFramesetDocument();
+  return NS_OK;
 #  else
   return NS_ERROR_FAILURE;
 #  endif
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::GetIsIFrameSelected(bool* aIsIFrameSelected) {
 #  ifdef NS_PRINTING
   *aIsIFrameSelected = false;
   NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE);
 
-  return mPrintJob->GetIsIFrameSelected(aIsIFrameSelected);
+  *aIsIFrameSelected = mPrintJob->IsIFrameSelected();
+  return NS_OK;
 #  else
   return NS_ERROR_FAILURE;
 #  endif
 }
 
 NS_IMETHODIMP
 nsDocumentViewer::GetIsRangeSelection(bool* aIsRangeSelection) {
 #  ifdef NS_PRINTING
   *aIsRangeSelection = false;
   NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE);
 
-  return mPrintJob->GetIsRangeSelection(aIsRangeSelection);
+  *aIsRangeSelection = mPrintJob->IsRangeSelection();
+  return NS_OK;
 #  else
   return NS_ERROR_FAILURE;
 #  endif
 }
 
 //----------------------------------------------------------------------------------
 // Printing/Print Preview Helpers
 //----------------------------------------------------------------------------------
--- a/layout/printing/nsPrintJob.cpp
+++ b/layout/printing/nsPrintJob.cpp
@@ -982,33 +982,31 @@ nsresult nsPrintJob::DoCommonPrint(bool 
 
   // We will enable scripting later after printing has finished.
   scriptSuppressor.Disconnect();
 
   return NS_OK;
 }
 
 //---------------------------------------------------------------------------------
-NS_IMETHODIMP
-nsPrintJob::Print(nsIPrintSettings* aPrintSettings,
-                  nsIWebProgressListener* aWebProgressListener) {
+nsresult nsPrintJob::Print(nsIPrintSettings* aPrintSettings,
+                           nsIWebProgressListener* aWebProgressListener) {
   // If we have a print preview document, use that instead of the original
   // mDocument. That way animated images etc. get printed using the same state
   // as in print preview.
   Document* doc = mPrtPreview && mPrtPreview->mPrintObject
                       ? mPrtPreview->mPrintObject->mDocument
                       : mDocument;
 
   return CommonPrint(false, aPrintSettings, aWebProgressListener, doc);
 }
 
-NS_IMETHODIMP
-nsPrintJob::PrintPreview(nsIPrintSettings* aPrintSettings,
-                         mozIDOMWindowProxy* aChildDOMWin,
-                         nsIWebProgressListener* aWebProgressListener) {
+nsresult nsPrintJob::PrintPreview(
+    nsIPrintSettings* aPrintSettings, mozIDOMWindowProxy* aChildDOMWin,
+    nsIWebProgressListener* aWebProgressListener) {
   // Get the DocShell and see if it is busy
   // (We can't Print Preview this document if it is still busy)
   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mContainer));
   NS_ENSURE_STATE(docShell);
 
   auto busyFlags = docShell->GetBusyFlags();
   if (busyFlags != nsIDocShell::BUSY_FLAGS_NONE) {
     CloseProgressDialog(aWebProgressListener);
@@ -1021,87 +1019,74 @@ nsPrintJob::PrintPreview(nsIPrintSetting
   nsCOMPtr<Document> doc = window->GetDoc();
   NS_ENSURE_STATE(doc);
 
   // Document is not busy -- go ahead with the Print Preview
   return CommonPrint(true, aPrintSettings, aWebProgressListener, doc);
 }
 
 //----------------------------------------------------------------------------------
-NS_IMETHODIMP
-nsPrintJob::GetIsFramesetDocument(bool* aIsFramesetDocument) {
+bool nsPrintJob::IsFramesetDocument() const {
   nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer));
-  *aIsFramesetDocument = IsParentAFrameSet(webContainer);
-  return NS_OK;
+  return IsParentAFrameSet(webContainer);
 }
 
 //----------------------------------------------------------------------------------
-NS_IMETHODIMP
-nsPrintJob::GetIsIFrameSelected(bool* aIsIFrameSelected) {
-  *aIsIFrameSelected = false;
-
+bool nsPrintJob::IsIFrameSelected() {
   // Get the docshell for this documentviewer
   nsCOMPtr<nsIDocShell> webContainer(do_QueryReferent(mContainer));
   // Get the currently focused window
   nsCOMPtr<nsPIDOMWindowOuter> currentFocusWin = FindFocusedDOMWindow();
   if (currentFocusWin && webContainer) {
     // Get whether the doc contains a frameset
     // Also, check to see if the currently focus docshell
     // is a child of this docshell
     bool isParentFrameSet;
-    *aIsIFrameSelected = IsThereAnIFrameSelected(webContainer, currentFocusWin,
-                                                 isParentFrameSet);
+    return IsThereAnIFrameSelected(webContainer, currentFocusWin,
+                                   isParentFrameSet);
   }
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------------------
-NS_IMETHODIMP
-nsPrintJob::GetIsRangeSelection(bool* aIsRangeSelection) {
-  // Get the currently focused window
-  nsCOMPtr<nsPIDOMWindowOuter> currentFocusWin = FindFocusedDOMWindow();
-  *aIsRangeSelection = IsThereARangeSelection(currentFocusWin);
-  return NS_OK;
+  return false;
 }
 
 //----------------------------------------------------------------------------------
-NS_IMETHODIMP
-nsPrintJob::GetIsFramesetFrameSelected(bool* aIsFramesetFrameSelected) {
+bool nsPrintJob::IsRangeSelection() {
   // Get the currently focused window
   nsCOMPtr<nsPIDOMWindowOuter> currentFocusWin = FindFocusedDOMWindow();
-  *aIsFramesetFrameSelected = currentFocusWin != nullptr;
-  return NS_OK;
+  return IsThereARangeSelection(currentFocusWin);
 }
 
 //----------------------------------------------------------------------------------
-NS_IMETHODIMP
-nsPrintJob::GetPrintPreviewNumPages(int32_t* aPrintPreviewNumPages) {
-  NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
-
-  nsIFrame* seqFrame = nullptr;
-  *aPrintPreviewNumPages = 0;
-
+bool nsPrintJob::IsFramesetFrameSelected() const {
+  // Get the currently focused window
+  nsCOMPtr<nsPIDOMWindowOuter> currentFocusWin = FindFocusedDOMWindow();
+  return currentFocusWin != nullptr;
+}
+
+//----------------------------------------------------------------------------------
+int32_t nsPrintJob::GetPrintPreviewNumPages() {
   // When calling this function, the FinishPrintPreview() function might not
   // been called as there are still some
   RefPtr<nsPrintData> printData = mPrtPreview ? mPrtPreview : mPrt;
   if (NS_WARN_IF(!printData)) {
-    return NS_ERROR_FAILURE;
+    return 0;
   }
-  nsresult rv = GetSeqFrameAndCountPagesInternal(
-      printData->mPrintObject, seqFrame, *aPrintPreviewNumPages);
+  nsIFrame* seqFrame = nullptr;
+  int32_t numPages = 0;
+  nsresult rv = GetSeqFrameAndCountPagesInternal(printData->mPrintObject,
+                                                 seqFrame, numPages);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    return NS_ERROR_FAILURE;
+    return 0;
   }
-  return NS_OK;
+  return numPages;
 }
 
 //----------------------------------------------------------------------------------
 // Enumerate all the documents for their titles
-NS_IMETHODIMP
-nsPrintJob::EnumerateDocumentNames(uint32_t* aCount, char16_t*** aResult) {
+nsresult nsPrintJob::EnumerateDocumentNames(uint32_t* aCount,
+                                            char16_t*** aResult) {
   NS_ENSURE_ARG(aCount);
   NS_ENSURE_ARG_POINTER(aResult);
 
   *aCount = 0;
   *aResult = nullptr;
 
   int32_t numDocs = mPrt->mPrintDocList.Length();
   char16_t** array = (char16_t**)moz_xmalloc(numDocs * sizeof(char16_t*));
@@ -1135,47 +1120,24 @@ nsresult nsPrintJob::GetGlobalPrintSetti
       do_GetService(sPrintSettingsServiceContractID, &rv);
   if (NS_SUCCEEDED(rv)) {
     rv = printSettingsService->GetGlobalPrintSettings(aGlobalPrintSettings);
   }
   return rv;
 }
 
 //----------------------------------------------------------------------------------
-NS_IMETHODIMP
-nsPrintJob::GetDoingPrint(bool* aDoingPrint) {
-  NS_ENSURE_ARG_POINTER(aDoingPrint);
-  *aDoingPrint = mIsDoingPrinting;
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------------------
-NS_IMETHODIMP
-nsPrintJob::GetDoingPrintPreview(bool* aDoingPrintPreview) {
-  NS_ENSURE_ARG_POINTER(aDoingPrintPreview);
-  *aDoingPrintPreview = mIsDoingPrintPreview;
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------------------
-NS_IMETHODIMP
-nsPrintJob::GetCurrentPrintSettings(nsIPrintSettings** aCurrentPrintSettings) {
-  NS_ENSURE_ARG_POINTER(aCurrentPrintSettings);
-
+already_AddRefed<nsIPrintSettings> nsPrintJob::GetCurrentPrintSettings() {
   if (mPrt) {
-    *aCurrentPrintSettings = mPrt->mPrintSettings;
-
-  } else if (mPrtPreview) {
-    *aCurrentPrintSettings = mPrtPreview->mPrintSettings;
-
-  } else {
-    *aCurrentPrintSettings = nullptr;
+    return do_AddRef(mPrt->mPrintSettings);
   }
-  NS_IF_ADDREF(*aCurrentPrintSettings);
-  return NS_OK;
+  if (mPrtPreview) {
+    return do_AddRef(mPrtPreview->mPrintSettings);
+  }
+  return nullptr;
 }
 
 //-----------------------------------------------------------------
 //-- Section: Pre-Reflow Methods
 //-----------------------------------------------------------------
 
 //---------------------------------------------------------------------
 // This method checks to see if there is at least one printer defined
@@ -2849,17 +2811,17 @@ void nsPrintJob::CleanupDocTitleArray(ch
   free(aArray);
   aArray = nullptr;
   aCount = 0;
 }
 
 /** ---------------------------------------------------
  *  Get the Focused Frame for a documentviewer
  */
-already_AddRefed<nsPIDOMWindowOuter> nsPrintJob::FindFocusedDOMWindow() {
+already_AddRefed<nsPIDOMWindowOuter> nsPrintJob::FindFocusedDOMWindow() const {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, nullptr);
 
   nsPIDOMWindowOuter* window = mDocument->GetWindow();
   NS_ENSURE_TRUE(window, nullptr);
 
   nsCOMPtr<nsPIDOMWindowOuter> rootWindow = window->GetPrivateRoot();
   NS_ENSURE_TRUE(rootWindow, nullptr);
@@ -2873,17 +2835,17 @@ already_AddRefed<nsPIDOMWindowOuter> nsP
   if (IsWindowsInOurSubTree(focusedWindow)) {
     return focusedWindow.forget();
   }
 
   return nullptr;
 }
 
 //---------------------------------------------------------------------
-bool nsPrintJob::IsWindowsInOurSubTree(nsPIDOMWindowOuter* window) {
+bool nsPrintJob::IsWindowsInOurSubTree(nsPIDOMWindowOuter* window) const {
   bool found = false;
 
   // now check to make sure it is in "our" tree of docshells
   if (window) {
     nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
 
     if (docShell) {
       // get this DocViewer docshell
--- a/layout/printing/nsPrintJob.h
+++ b/layout/printing/nsPrintJob.h
@@ -54,31 +54,33 @@ class nsPrintJob final : public nsIObser
   // nsISupports interface...
   NS_DECL_ISUPPORTS
 
   // nsIObserver
   NS_DECL_NSIOBSERVER
 
   NS_DECL_NSIWEBPROGRESSLISTENER
 
-  // Old nsIWebBrowserPrint methods; not cleaned up yet
-  NS_IMETHOD Print(nsIPrintSettings* aPrintSettings,
-                   nsIWebProgressListener* aWebProgressListener);
-  NS_IMETHOD PrintPreview(nsIPrintSettings* aPrintSettings,
-                          mozIDOMWindowProxy* aChildDOMWin,
-                          nsIWebProgressListener* aWebProgressListener);
-  NS_IMETHOD GetIsFramesetDocument(bool* aIsFramesetDocument);
-  NS_IMETHOD GetIsIFrameSelected(bool* aIsIFrameSelected);
-  NS_IMETHOD GetIsRangeSelection(bool* aIsRangeSelection);
-  NS_IMETHOD GetIsFramesetFrameSelected(bool* aIsFramesetFrameSelected);
-  NS_IMETHOD GetPrintPreviewNumPages(int32_t* aPrintPreviewNumPages);
-  NS_IMETHOD EnumerateDocumentNames(uint32_t* aCount, char16_t*** aResult);
-  NS_IMETHOD GetDoingPrint(bool* aDoingPrint);
-  NS_IMETHOD GetDoingPrintPreview(bool* aDoingPrintPreview);
-  NS_IMETHOD GetCurrentPrintSettings(nsIPrintSettings** aCurrentPrintSettings);
+  // Our nsIWebBrowserPrint implementation defers to these methods.
+  nsresult Print(nsIPrintSettings* aPrintSettings,
+                 nsIWebProgressListener* aWebProgressListener);
+  nsresult PrintPreview(nsIPrintSettings* aPrintSettings,
+                        mozIDOMWindowProxy* aChildDOMWin,
+                        nsIWebProgressListener* aWebProgressListener);
+  bool IsDoingPrint() const { return mIsDoingPrinting; }
+  bool IsDoingPrintPreview() const { return mIsDoingPrintPreview; }
+  bool IsFramesetDocument() const;
+  bool IsIFrameSelected();
+  bool IsRangeSelection();
+  bool IsFramesetFrameSelected() const;
+  /// If the returned value is not greater than zero, an error occurred.
+  int32_t GetPrintPreviewNumPages();
+  /// Callers are responsible for free'ing aResult.
+  nsresult EnumerateDocumentNames(uint32_t* aCount, char16_t*** aResult);
+  already_AddRefed<nsIPrintSettings> GetCurrentPrintSettings();
 
   // This enum tells indicates what the default should be for the title
   // if the title from the document is null
   enum eDocTitleDefault { eDocTitleDefBlank, eDocTitleDefURLDoc };
 
   void Destroy();
   void DestroyPrintingData();
 
@@ -142,23 +144,23 @@ class nsPrintJob final : public nsIObser
   bool IsThereARangeSelection(nsPIDOMWindowOuter* aDOMWin);
 
   void FirePrintingErrorEvent(nsresult aPrintError);
   //---------------------------------------------------------------------
 
   // Timer Methods
   nsresult StartPagePrintTimer(const mozilla::UniquePtr<nsPrintObject>& aPO);
 
-  bool IsWindowsInOurSubTree(nsPIDOMWindowOuter* aDOMWindow);
+  bool IsWindowsInOurSubTree(nsPIDOMWindowOuter* aDOMWindow) const;
   bool IsThereAnIFrameSelected(nsIDocShell* aDocShell,
                                nsPIDOMWindowOuter* aDOMWin,
                                bool& aIsParentFrameSet);
 
   // get the currently infocus frame for the document viewer
-  already_AddRefed<nsPIDOMWindowOuter> FindFocusedDOMWindow();
+  already_AddRefed<nsPIDOMWindowOuter> FindFocusedDOMWindow() const;
 
   void GetDisplayTitleAndURL(const mozilla::UniquePtr<nsPrintObject>& aPO,
                              nsAString& aTitle, nsAString& aURLStr,
                              eDocTitleDefault aDefType);
 
   bool CheckBeforeDestroy();
   nsresult Cancelled();
 
--- a/python/mozbuild/mozbuild/backend/cpp_eclipse.py
+++ b/python/mozbuild/mozbuild/backend/cpp_eclipse.py
@@ -207,20 +207,20 @@ class CppEclipseBackend(CommonBackend):
 
     def _write_noindex(self):
         noindex_path = os.path.join(self._project_dir, '.settings/org.eclipse.cdt.core.prefs')
         with open(noindex_path, 'wb') as fh:
             fh.write(NOINDEX_TEMPLATE);
 
     def _remove_noindex(self):
         # Below we remove the config file that temporarily disabled the indexer
-        # while we were importing the project. Unfornutanely, CDT doesn't
+        # while we were importing the project. Unfortunately, CDT doesn't
         # notice indexer settings changes in config files when it restarts. To
         # work around that we remove the index database here to force it to:
-        for f in glob.glob(os.path.join(self._workspace_lang_dir, "*.pdom")):
+        for f in glob.glob(os.path.join(self._workspace_lang_dir, "Gecko.*.pdom")):
             os.remove(f)
 
         noindex_path = os.path.join(self._project_dir, '.settings/org.eclipse.cdt.core.prefs')
         # This may fail if the entire tree has been removed; that's fine.
         try:
             os.remove(noindex_path)
         except OSError as e:
             if e.errno != errno.ENOENT:
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_44_BETA1
+NSS_3_44_BETA2
--- a/security/nss/automation/abi-check/expected-report-libnss3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnss3.so.txt
@@ -1,5 +1,21 @@
 
 1 Added function:
 
   'function SECStatus CERT_GetCertificateDer(const CERTCertificate*, SECItem*)'    {CERT_GetCertificateDer@@NSS_3.44}
 
+1 function with some indirect sub-type change:
+
+  [C]'function SECStatus CERT_AddOCSPAcceptableResponses(CERTOCSPRequest*, SECOidTag, ...)' at ocsp.c:2203:1 has some indirect sub-type changes:
+    parameter 2 of type 'typedef SECOidTag' has sub-type changes:
+      underlying type 'enum __anonymous_enum__' at secoidt.h:34:1 changed:
+        type size hasn't changed
+        3 enumerator insertions:
+          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_END' value '361'
+          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL' value '362'
+          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_USER' value '363'
+
+        1 enumerator change:
+          '__anonymous_enum__::SEC_OID_TOTAL' from value '361' to '364' at secoidt.h:34:1
+
+
+
--- a/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt
@@ -0,0 +1,17 @@
+
+1 function with some indirect sub-type change:
+
+  [C]'function SECStatus NSS_GetAlgorithmPolicy(SECOidTag, PRUint32*)' at secoid.c:2234:1 has some indirect sub-type changes:
+    parameter 1 of type 'typedef SECOidTag' has sub-type changes:
+      underlying type 'enum __anonymous_enum__' at secoidt.h:34:1 changed:
+        type size hasn't changed
+        3 enumerator insertions:
+          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_END' value '361'
+          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL' value '362'
+          '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_USER' value '363'
+
+        1 enumerator change:
+          '__anonymous_enum__::SEC_OID_TOTAL' from value '361' to '364' at secoidt.h:34:1
+
+
+
--- a/security/nss/automation/abi-check/expected-report-libsmime3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libsmime3.so.txt
@@ -0,0 +1,47 @@
+
+1 function with some indirect sub-type change:
+
+  [C]'function PK11SymKey* NSS_CMSContentInfo_GetBulkKey(NSSCMSContentInfo*)' at cmscinfo.c:426:1 has some indirect sub-type changes:
+    parameter 1 of type 'NSSCMSContentInfo*' has sub-type changes:
+      in pointed to type 'typedef NSSCMSContentInfo' at cmst.h:54:1:
+        underlying type 'struct NSSCMSContentInfoStr' at cmst.h:126:1 changed:
+          type size hasn't changed
+          1 data member changes (2 filtered):
+           type of 'NSSCMSContent NSSCMSContentInfoStr::content' changed:
+             underlying type 'union NSSCMSContentUnion' at cmst.h:113:1 changed:
+               type size hasn't changed
+               1 data member changes (3 filtered):
+                type of 'NSSCMSEncryptedData* NSSCMSContentUnion::encryptedData' changed:
+                  in pointed to type 'typedef NSSCMSEncryptedData' at cmst.h:65:1:
+                    underlying type 'struct NSSCMSEncryptedDataStr' at cmst.h:463:1 changed:
+                      type size hasn't changed
+                      1 data member changes (1 filtered):
+                       type of 'NSSCMSAttribute** NSSCMSEncryptedDataStr::unprotectedAttr' changed:
+                         in pointed to type 'NSSCMSAttribute*':
+                           in pointed to type 'typedef NSSCMSAttribute' at cmst.h:69:1:
+                             underlying type 'struct NSSCMSAttributeStr' at cmst.h:482:1 changed:
+                               type size hasn't changed
+                               1 data member change:
+                                type of 'SECOidData* NSSCMSAttributeStr::typeTag' changed:
+                                  in pointed to type 'typedef SECOidData' at secoidt.h:16:1:
+                                    underlying type 'struct SECOidDataStr' at secoidt.h:518:1 changed:
+                                      type size hasn't changed
+                                      1 data member change:
+                                       type of 'SECOidTag SECOidDataStr::offset' changed:
+                                         underlying type 'enum __anonymous_enum__' at secoidt.h:34:1 changed:
+                                           type size hasn't changed
+                                           3 enumerator insertions:
+                                             '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_END' value '361'
+                                             '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL' value '362'
+                                             '__anonymous_enum__::SEC_OID_EXT_KEY_USAGE_IPSEC_USER' value '363'
+
+                                           1 enumerator change:
+                                             '__anonymous_enum__::SEC_OID_TOTAL' from value '361' to '364' at secoidt.h:34:1
+
+
+
+
+
+
+
+
--- a/security/nss/cmd/certutil/certext.c
+++ b/security/nss/cmd/certutil/certext.c
@@ -492,16 +492,23 @@ static const char *const
     extKeyUsageKeyWordArray[] = { "serverAuth",
                                   "clientAuth",
                                   "codeSigning",
                                   "emailProtection",
                                   "timeStamp",
                                   "ocspResponder",
                                   "stepUp",
                                   "msTrustListSigning",
+                                  "x509Any",
+                                  "ipsecIKE",
+                                  "ipsecIKEEnd",
+                                  "ipsecIKEIntermediate",
+                                  "ipsecEnd",
+                                  "ipsecTunnel",
+                                  "ipsecUser",
                                   NULL };
 
 static SECStatus
 AddExtKeyUsage(void *extHandle, const char *userSuppliedValue)
 {
     char buffer[5];
     int value;
     CERTOidSequence *os;
@@ -512,16 +519,20 @@ AddExtKeyUsage(void *extHandle, const ch
 
     os = CreateOidSequence();
     if ((CERTOidSequence *)NULL == os) {
         return SECFailure;
     }
 
     while (1) {
         if (!userSuppliedValue) {
+            /*
+             * none of the 'new' extended key usage options work with the prompted menu. This is so
+             * old scripts can continue to work.
+             */
             if (PrintChoicesAndGetAnswer(
                     "\t\t0 - Server Auth\n"
                     "\t\t1 - Client Auth\n"
                     "\t\t2 - Code Signing\n"
                     "\t\t3 - Email Protection\n"
                     "\t\t4 - Timestamp\n"
                     "\t\t5 - OCSP Responder\n"
                     "\t\t6 - Step-up\n"
@@ -567,16 +578,55 @@ AddExtKeyUsage(void *extHandle, const ch
                 rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER);
                 break;
             case 6:
                 rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED);
                 break;
             case 7:
                 rv = AddOidToSequence(os, SEC_OID_MS_EXT_KEY_USAGE_CTL_SIGNING);
                 break;
+            /*
+             * These new usages can only be added explicitly by the userSuppliedValues. This allows old
+             * scripts which used '>7' as an exit value to continue to work.
+             */
+            case 8:
+                if (!userSuppliedValue)
+                    goto endloop;
+                rv = AddOidToSequence(os, SEC_OID_X509_ANY_EXT_KEY_USAGE);
+                break;
+            case 9:
+                if (!userSuppliedValue)
+                    goto endloop;
+                rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_IPSEC_IKE);
+                break;
+            case 10:
+                if (!userSuppliedValue)
+                    goto endloop;
+                rv = AddOidToSequence(os, SEC_OID_IPSEC_IKE_END);
+                break;
+            case 11:
+                if (!userSuppliedValue)
+                    goto endloop;
+                rv = AddOidToSequence(os, SEC_OID_IPSEC_IKE_INTERMEDIATE);
+                break;
+            case 12:
+                if (!userSuppliedValue)
+                    goto endloop;
+                rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_IPSEC_END);
+                break;
+            case 13:
+                if (!userSuppliedValue)
+                    goto endloop;
+                rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL);
+                break;
+            case 14:
+                if (!userSuppliedValue)
+                    goto endloop;
+                rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_IPSEC_USER);
+                break;
             default:
                 goto endloop;
         }
 
         if (userSuppliedValue && !nextPos)
             break;
         if (SECSuccess != rv)
             goto loser;
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -1357,18 +1357,21 @@ luC(enum usage_level ul, const char *com
               "%-20s Create netscape cert type extension. Possible keywords:\n"
               "%-20s \"sslClient\", \"sslServer\", \"smime\", \"objectSigning\",\n"
               "%-20s \"sslCA\", \"smimeCA\", \"objectSigningCA\", \"critical\".\n",
         "   -5 | --nsCertType keyword,keyword,... ", "", "", "");
     FPS "%-20s \n"
               "%-20s Create extended key usage extension. Possible keywords:\n"
               "%-20s \"serverAuth\", \"clientAuth\",\"codeSigning\",\n"
               "%-20s \"emailProtection\", \"timeStamp\",\"ocspResponder\",\n"
-              "%-20s \"stepUp\", \"msTrustListSign\", \"critical\"\n",
-        "   -6 | --extKeyUsage keyword,keyword,...", "", "", "", "");
+              "%-20s \"stepUp\", \"msTrustListSign\", \"x509Any\",\n"
+              "%-20s \"ipsecIKE\", \"ipsecIKEEnd\", \"ipsecIKEIntermediate\",\n"
+              "%-20s \"ipsecEnd\", \"ipsecTunnel\", \"ipsecUser\",\n"
+              "%-20s \"critical\"\n",
+        "   -6 | --extKeyUsage keyword,keyword,...", "", "", "", "", "", "", "");
     FPS "%-20s Create an email subject alt name extension\n",
         "   -7 emailAddrs");
     FPS "%-20s Create an dns subject alt name extension\n",
         "   -8 dnsNames");
     FPS "%-20s The input certificate request is encoded in ASCII (RFC1113)\n",
         "   -a");
     FPS "\n");
 }
--- a/security/nss/coreconf/Linux.mk
+++ b/security/nss/coreconf/Linux.mk
@@ -130,16 +130,20 @@ OS_PTHREAD = -lpthread
 endif
 
 OS_CFLAGS		= $(DSO_CFLAGS) $(OS_REL_CFLAGS) $(ARCHFLAG) -pipe -ffunction-sections -fdata-sections -DHAVE_STRERROR
 ifeq ($(KERNEL),Linux)
 	OS_CFLAGS	+= -DLINUX -Dlinux
 endif
 OS_LIBS			= $(OS_PTHREAD) -ldl -lc
 
+ifeq ($(OS_TARGET),Android)
+	OS_LIBS		+= -llog
+endif
+
 ifdef USE_PTHREADS
 	DEFINES		+= -D_REENTRANT
 endif
 
 DSO_CFLAGS		= -fPIC
 DSO_LDOPTS		= -shared $(ARCHFLAG) -Wl,--gc-sections
 # The linker on Red Hat Linux 7.2 and RHEL 2.1 (GNU ld version 2.11.90.0.8)
 # incorrectly reports undefined references in the libraries we link with, so
--- a/security/nss/coreconf/config.gypi
+++ b/security/nss/coreconf/config.gypi
@@ -161,16 +161,21 @@
         ],
       }],
       [ 'OS=="linux"', {
         'libraries': [
           '-ldl',
           '-lc',
         ],
       }],
+      [ 'OS=="android"', {
+        'libraries': [
+          '-llog',
+        ],
+      }],
       [ 'fuzz==1', {
         'variables': {
           'debug_optimization_level%': '1',
         },
       }],
       [ 'target_arch=="ia32" or target_arch=="x64"', {
         'defines': [
           'NSS_X86_OR_X64',
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/doc/certutil.xml
+++ b/security/nss/doc/certutil.xml
@@ -657,16 +657,51 @@ of the attribute codes:
 		msTrustListSign
 	</para>
 	</listitem>
 	<listitem>
 	<para>
 		critical
 	</para>
 	</listitem>
+	<listitem>
+	<para>
+		x509Any
+	</para>
+	</listitem>
+	<listitem>
+	<para>
+		ipsecIKE
+	</para>
+	</listitem>
+	<listitem>
+	<para>
+		ipsecIKEEnd
+	</para>
+	</listitem>
+	<listitem>
+	<para>
+		ipsecIKEIntermediate
+	</para>
+	</listitem>
+	<listitem>
+	<para>
+		ipsecEnd
+	</para>
+	</listitem>
+	<listitem>
+	<para>
+		ipsecTunnel
+	</para>
+	</listitem>
+	<listitem>
+	<para>
+		ipsecUser
+	</para>
+	</listitem>
 	</itemizedlist>
 <para>X.509 certificate extensions are described in RFC 5280.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term>-7 emailAddrs</term>
         <listitem><para>Add a comma-separated list of email addresses to the subject alternative name extension of a certificate or certificate request that is being created or added to the database. Subject alternative name extensions are described in Section 4.2.1.7 of RFC 3280.</para></listitem>
       </varlistentry>
--- a/security/nss/lib/certdb/certdb.c
+++ b/security/nss/lib/certdb/certdb.c
@@ -442,105 +442,73 @@ cert_GetCertType(CERTCertificate *cert)
 
     /* Assert that it is safe to cast &cert->nsCertType to "PRInt32 *" */
     PORT_Assert(sizeof(cert->nsCertType) == sizeof(PRInt32));
     PR_ATOMIC_SET((PRInt32 *)&cert->nsCertType, nsCertType);
     return SECSuccess;
 }
 
 PRBool
-cert_EKUAllowsIPsecIKE(CERTCertificate *cert, PRBool *isCritical)
+cert_IsIPsecOID(CERTOidSequence *extKeyUsage)
 {
-    SECStatus rv;
-    SECItem encodedExtKeyUsage;
-    CERTOidSequence *extKeyUsage = NULL;
-    PRBool result = PR_FALSE;
-
-    rv = CERT_GetExtenCriticality(cert->extensions,
-                                  SEC_OID_X509_EXT_KEY_USAGE,
-                                  isCritical);
-    if (rv != SECSuccess) {
-        *isCritical = PR_FALSE;
+    if (findOIDinOIDSeqByTagNum(
+            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_IKE) == SECSuccess) {
+        return PR_TRUE;
     }
-
-    encodedExtKeyUsage.data = NULL;
-    rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE,
-                                &encodedExtKeyUsage);
-    if (rv != SECSuccess) {
-        /* EKU not present, allowed. */
-        result = PR_TRUE;
-        goto done;
+    if (findOIDinOIDSeqByTagNum(
+            extKeyUsage, SEC_OID_IPSEC_IKE_END) == SECSuccess) {
+        return PR_TRUE;
     }
-
-    extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage);
-    if (!extKeyUsage) {
-        /* failure */
-        goto done;
+    if (findOIDinOIDSeqByTagNum(
+            extKeyUsage, SEC_OID_IPSEC_IKE_INTERMEDIATE) == SECSuccess) {
+        return PR_TRUE;
     }
-
-    if (findOIDinOIDSeqByTagNum(extKeyUsage,
-                                SEC_OID_X509_ANY_EXT_KEY_USAGE) ==
-        SECSuccess) {
-        result = PR_TRUE;
-        goto done;
+    /* these are now deprecated, but may show up. Treat them the same as IKE */
+    if (findOIDinOIDSeqByTagNum(
+            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_END) == SECSuccess) {
+        return PR_TRUE;
     }
-
-    if (findOIDinOIDSeqByTagNum(extKeyUsage,
-                                SEC_OID_EXT_KEY_USAGE_IPSEC_IKE) ==
-        SECSuccess) {
-        result = PR_TRUE;
-        goto done;
+    if (findOIDinOIDSeqByTagNum(
+            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL) == SECSuccess) {
+        return PR_TRUE;
     }
-
-    if (findOIDinOIDSeqByTagNum(extKeyUsage,
-                                SEC_OID_IPSEC_IKE_END) ==
-        SECSuccess) {
-        result = PR_TRUE;
-        goto done;
+    if (findOIDinOIDSeqByTagNum(
+            extKeyUsage, SEC_OID_EXT_KEY_USAGE_IPSEC_USER) == SECSuccess) {
+        return PR_TRUE;
     }
-
-    if (findOIDinOIDSeqByTagNum(extKeyUsage,
-                                SEC_OID_IPSEC_IKE_INTERMEDIATE) ==
-        SECSuccess) {
-        result = PR_TRUE;
-        goto done;
+    /* this one should probably be in cert_ComputeCertType and set all usages? */
+    if (findOIDinOIDSeqByTagNum(
+            extKeyUsage, SEC_OID_X509_ANY_EXT_KEY_USAGE) == SECSuccess) {
+        return PR_TRUE;
     }
-
-done:
-    if (encodedExtKeyUsage.data != NULL) {
-        PORT_Free(encodedExtKeyUsage.data);
-    }
-    if (extKeyUsage != NULL) {
-        CERT_DestroyOidSequence(extKeyUsage);
-    }
-    return result;
+    return PR_FALSE;
 }
 
 PRUint32
 cert_ComputeCertType(CERTCertificate *cert)
 {
     SECStatus rv;
     SECItem tmpitem;
     SECItem encodedExtKeyUsage;
     CERTOidSequence *extKeyUsage = NULL;
-    PRBool basicConstraintPresent = PR_FALSE;
     CERTBasicConstraints basicConstraint;
     PRUint32 nsCertType = 0;
+    PRBool isCA = PR_FALSE;
 
     tmpitem.data = NULL;
     CERT_FindNSCertTypeExtension(cert, &tmpitem);
     encodedExtKeyUsage.data = NULL;
     rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE,
                                 &encodedExtKeyUsage);
     if (rv == SECSuccess) {
         extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage);
     }
     rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);
     if (rv == SECSuccess) {
-        basicConstraintPresent = PR_TRUE;
+        isCA = basicConstraint.isCA;
     }
     if (tmpitem.data != NULL || extKeyUsage != NULL) {
         if (tmpitem.data == NULL) {
             nsCertType = 0;
         } else {
             nsCertType = tmpitem.data[0];
         }
 
@@ -566,83 +534,74 @@ cert_ComputeCertType(CERTCertificate *ce
         /*
          * allow a cert with the extended key usage of EMail Protect
          * to be used for email or as an email CA, if basic constraints
          * indicates that it is a CA.
          */
         if (findOIDinOIDSeqByTagNum(extKeyUsage,
                                     SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT) ==
             SECSuccess) {
-            if (basicConstraintPresent == PR_TRUE && (basicConstraint.isCA)) {
-                nsCertType |= NS_CERT_TYPE_EMAIL_CA;
-            } else {
-                nsCertType |= NS_CERT_TYPE_EMAIL;
-            }
+            nsCertType |= isCA ? NS_CERT_TYPE_EMAIL_CA : NS_CERT_TYPE_EMAIL;
         }
         if (findOIDinOIDSeqByTagNum(
                 extKeyUsage, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH) == SECSuccess) {
-            if (basicConstraintPresent == PR_TRUE && (basicConstraint.isCA)) {
-                nsCertType |= NS_CERT_TYPE_SSL_CA;
-            } else {
-                nsCertType |= NS_CERT_TYPE_SSL_SERVER;
-            }
+            nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_SERVER;
         }
         /*
          * Treat certs with step-up OID as also having SSL server type.
          * COMODO needs this behaviour until June 2020.  See Bug 737802.
          */
         if (findOIDinOIDSeqByTagNum(extKeyUsage,
                                     SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) ==
             SECSuccess) {
-            if (basicConstraintPresent == PR_TRUE && (basicConstraint.isCA)) {
-                nsCertType |= NS_CERT_TYPE_SSL_CA;
-            } else {
-                nsCertType |= NS_CERT_TYPE_SSL_SERVER;
-            }
+            nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_SERVER;
         }
         if (findOIDinOIDSeqByTagNum(
                 extKeyUsage, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH) == SECSuccess) {
-            if (basicConstraintPresent == PR_TRUE && (basicConstraint.isCA)) {
-                nsCertType |= NS_CERT_TYPE_SSL_CA;
-            } else {
-                nsCertType |= NS_CERT_TYPE_SSL_CLIENT;
-            }
+            nsCertType |= isCA ? NS_CERT_TYPE_SSL_CA : NS_CERT_TYPE_SSL_CLIENT;
+        }
+        if (cert_IsIPsecOID(extKeyUsage)) {
+            nsCertType |= isCA ? NS_CERT_TYPE_IPSEC_CA : NS_CERT_TYPE_IPSEC;
         }
         if (findOIDinOIDSeqByTagNum(
                 extKeyUsage, SEC_OID_EXT_KEY_USAGE_CODE_SIGN) == SECSuccess) {
-            if (basicConstraintPresent == PR_TRUE && (basicConstraint.isCA)) {
-                nsCertType |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
-            } else {
-                nsCertType |= NS_CERT_TYPE_OBJECT_SIGNING;
-            }
+            nsCertType |= isCA ? NS_CERT_TYPE_OBJECT_SIGNING_CA : NS_CERT_TYPE_OBJECT_SIGNING;
         }
         if (findOIDinOIDSeqByTagNum(
                 extKeyUsage, SEC_OID_EXT_KEY_USAGE_TIME_STAMP) == SECSuccess) {
             nsCertType |= EXT_KEY_USAGE_TIME_STAMP;
         }
         if (findOIDinOIDSeqByTagNum(extKeyUsage, SEC_OID_OCSP_RESPONDER) ==
             SECSuccess) {
             nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
         }
     } else {
         /* If no NS Cert Type extension and no EKU extension, then */
         nsCertType = 0;
         if (CERT_IsCACert(cert, &nsCertType))
             nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
         /* if the basic constraint extension says the cert is a CA, then
            allow SSL CA and EMAIL CA and Status Responder */
-        if (basicConstraintPresent && basicConstraint.isCA) {
+        if (isCA) {
             nsCertType |= (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |
                            EXT_KEY_USAGE_STATUS_RESPONDER);
         }
         /* allow any ssl or email (no ca or object signing. */
         nsCertType |= NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER |
                       NS_CERT_TYPE_EMAIL;
     }
 
+    /* IPSEC is allowed to use SSL client and server certs as well as email certs */
+    if (nsCertType & (NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_EMAIL)) {
+        nsCertType |= NS_CERT_TYPE_IPSEC;
+    }
+    if (nsCertType & (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA)) {
+        nsCertType |= NS_CERT_TYPE_IPSEC_CA;
+    }
+
     if (encodedExtKeyUsage.data != NULL) {
         PORT_Free(encodedExtKeyUsage.data);
     }
     if (extKeyUsage != NULL) {
         CERT_DestroyOidSequence(extKeyUsage);
     }
     return nsCertType;
 }
@@ -1148,17 +1107,17 @@ CERT_KeyUsageAndTypeForCertUsage(SECCert
                 requiredCertType = NS_CERT_TYPE_SSL_CA;
                 break;
             case certUsageSSLServer:
                 requiredKeyUsage = KU_KEY_CERT_SIGN;
                 requiredCertType = NS_CERT_TYPE_SSL_CA;
                 break;
             case certUsageIPsec:
                 requiredKeyUsage = KU_KEY_CERT_SIGN;
-                requiredCertType = NS_CERT_TYPE_SSL_CA;
+                requiredCertType = NS_CERT_TYPE_IPSEC_CA;
                 break;
             case certUsageSSLCA:
                 requiredKeyUsage = KU_KEY_CERT_SIGN;
                 requiredCertType = NS_CERT_TYPE_SSL_CA;
                 break;
             case certUsageEmailSigner:
                 requiredKeyUsage = KU_KEY_CERT_SIGN;
                 requiredCertType = NS_CERT_TYPE_EMAIL_CA;
@@ -1195,17 +1154,17 @@ CERT_KeyUsageAndTypeForCertUsage(SECCert
                 break;
             case certUsageSSLServer:
                 requiredKeyUsage = KU_KEY_AGREEMENT_OR_ENCIPHERMENT;
                 requiredCertType = NS_CERT_TYPE_SSL_SERVER;
                 break;
             case certUsageIPsec:
                 /* RFC 4945 Section 5.1.3.2 */
                 requiredKeyUsage = KU_DIGITAL_SIGNATURE_OR_NON_REPUDIATION;
-                requiredCertType = 0;
+                requiredCertType = NS_CERT_TYPE_IPSEC;
                 break;
             case certUsageSSLServerWithStepUp:
                 requiredKeyUsage =
                     KU_KEY_AGREEMENT_OR_ENCIPHERMENT | KU_NS_GOVT_APPROVED;
                 requiredCertType = NS_CERT_TYPE_SSL_SERVER;
                 break;
             case certUsageSSLCA:
                 requiredKeyUsage = KU_KEY_CERT_SIGN;
--- a/security/nss/lib/certdb/certt.h
+++ b/security/nss/lib/certdb/certt.h
@@ -411,35 +411,49 @@ struct CERTCrlNodeStr {
  */
 struct CERTDistNamesStr {
     PLArenaPool *arena;
     int nnames;
     SECItem *names;
     void *head; /* private */
 };
 
+/*
+ * NS_CERT_TYPE defines are used in two areas:
+ * 1) The old NSS Cert Type Extension, which is a certificate extension in the
+ * actual cert. It was created before the x509 Extended Key Usage Extension,
+ * which has now taken over it's function. This field is only 8 bits wide
+ * 2) The nsCertType entry in the CERTCertificate structure. This field is
+ * 32 bits wide.
+ * Any entries in this table greater than 0x80 will not be able to be encoded
+ * in an NSS Cert Type Extension, but can still be represented internally in
+ * the nsCertType field.
+ */
+#define NS_CERT_TYPE_IPSEC_CA (0x200)         /* outside the NS Cert Type Extenstion */
+#define NS_CERT_TYPE_IPSEC (0x100)            /* outside the NS Cert Type Extenstion */
 #define NS_CERT_TYPE_SSL_CLIENT (0x80)        /* bit 0 */
 #define NS_CERT_TYPE_SSL_SERVER (0x40)        /* bit 1 */
 #define NS_CERT_TYPE_EMAIL (0x20)             /* bit 2 */
 #define NS_CERT_TYPE_OBJECT_SIGNING (0x10)    /* bit 3 */
 #define NS_CERT_TYPE_RESERVED (0x08)          /* bit 4 */
 #define NS_CERT_TYPE_SSL_CA (0x04)            /* bit 5 */
 #define NS_CERT_TYPE_EMAIL_CA (0x02)          /* bit 6 */
 #define NS_CERT_TYPE_OBJECT_SIGNING_CA (0x01) /* bit 7 */
 
 #define EXT_KEY_USAGE_TIME_STAMP (0x8000)
 #define EXT_KEY_USAGE_STATUS_RESPONDER (0x4000)
 
 #define NS_CERT_TYPE_APP                                                      \
     (NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_SSL_SERVER | NS_CERT_TYPE_EMAIL | \
-     NS_CERT_TYPE_OBJECT_SIGNING)
+     NS_CERT_TYPE_IPSEC | NS_CERT_TYPE_OBJECT_SIGNING)
 
-#define NS_CERT_TYPE_CA                            \
-    (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA | \
-     NS_CERT_TYPE_OBJECT_SIGNING_CA | EXT_KEY_USAGE_STATUS_RESPONDER)
+#define NS_CERT_TYPE_CA                                                \
+    (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |                     \
+     NS_CERT_TYPE_OBJECT_SIGNING_CA | EXT_KEY_USAGE_STATUS_RESPONDER | \
+     NS_CERT_TYPE_IPSEC_CA)
 typedef enum SECCertUsageEnum {
     certUsageSSLClient = 0,
     certUsageSSLServer = 1,
     certUsageSSLServerWithStepUp = 2,
     certUsageSSLCA = 3,
     certUsageEmailSigner = 4,
     certUsageEmailRecipient = 5,
     certUsageObjectSigner = 6,
--- a/security/nss/lib/certhigh/certvfy.c
+++ b/security/nss/lib/certhigh/certvfy.c
@@ -1396,17 +1396,16 @@ CERT_VerifyCertificate(CERTCertDBHandle 
     }
 
     /* check key usage and netscape cert type */
     cert_GetCertType(cert);
     certType = cert->nsCertType;
 
     for (i = 1; i <= certificateUsageHighest &&
                 (SECSuccess == valid || returnedUsages || log);) {
-        PRBool typeAndEKUAllowed = PR_TRUE;
         PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE;
         if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) {
             NEXT_USAGE();
         }
         if (returnedUsages) {
             *returnedUsages |= i; /* start off assuming this usage is valid */
         }
         switch (certUsage) {
@@ -1446,29 +1445,17 @@ CERT_VerifyCertificate(CERTCertDBHandle 
         }
         if (CERT_CheckKeyUsage(cert, requiredKeyUsage) != SECSuccess) {
             if (PR_TRUE == requiredUsage) {
                 PORT_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE);
             }
             LOG_ERROR(log, cert, 0, requiredKeyUsage);
             INVALID_USAGE();
         }
-        if (certUsage != certUsageIPsec) {
-            if (!(certType & requiredCertType)) {
-                typeAndEKUAllowed = PR_FALSE;
-            }
-        } else {
-            PRBool isCritical;
-            PRBool allowed = cert_EKUAllowsIPsecIKE(cert, &isCritical);
-            /* If the extension isn't critical, we allow any EKU value. */
-            if (isCritical && !allowed) {
-                typeAndEKUAllowed = PR_FALSE;
-            }
-        }
-        if (!typeAndEKUAllowed) {
+        if (!(certType & requiredCertType)) {
             if (PR_TRUE == requiredUsage) {
                 PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
             }
             LOG_ERROR(log, cert, 0, requiredCertType);
             INVALID_USAGE();
         }
 
         rv = cert_CheckLeafTrust(cert, certUsage, &flags, &trusted);
--- a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
@@ -2997,27 +2997,18 @@ PKIX_PL_Cert_VerifyCertAndKeyType(
         /* use this key usage and cert type for certUsageAnyCA and
          * certUsageVerifyCA. */
 	requiredKeyUsage = KU_KEY_CERT_SIGN;
 	requiredCertType = NS_CERT_TYPE_CA;
     }
     if (CERT_CheckKeyUsage(cert->nssCert, requiredKeyUsage) != SECSuccess) {
         PKIX_ERROR(PKIX_CERTCHECKKEYUSAGEFAILED);
     }
-    if (certUsage != certUsageIPsec) {
-        if (!(certType & requiredCertType)) {
-            PKIX_ERROR(PKIX_CERTCHECKCERTTYPEFAILED);
-        }
-    } else {
-        PRBool isCritical;
-        PRBool allowed = cert_EKUAllowsIPsecIKE(cert->nssCert, &isCritical);
-        /* If the extension isn't critical, we allow any EKU value. */
-        if (isCritical && !allowed) {
-            PKIX_ERROR(PKIX_CERTCHECKCERTTYPEFAILED);
-        }
+    if (!(certType & requiredCertType)) {
+        PKIX_ERROR(PKIX_CERTCHECKCERTTYPEFAILED);
     }
 cleanup:
     PKIX_DECREF(basicConstraints);
     PKIX_RETURN(CERT);
 }
 
 /*
  * FUNCTION: PKIX_PL_Cert_VerifyKeyUsage (see comments in pkix_pl_pki.h)
--- a/security/nss/lib/util/secoid.c
+++ b/security/nss/lib/util/secoid.c
@@ -450,16 +450,21 @@ CONST_OID pkixRegCtrlOldCertID[] = { PKI
 CONST_OID pkixRegCtrlProtEncKey[] = { PKIX_ID_REGCTRL, 6 };
 CONST_OID pkixRegInfoUTF8Pairs[] = { PKIX_ID_REGINFO, 1 };
 CONST_OID pkixRegInfoCertReq[] = { PKIX_ID_REGINFO, 2 };
 
 CONST_OID pkixExtendedKeyUsageServerAuth[] = { PKIX_KEY_USAGE, 1 };
 CONST_OID pkixExtendedKeyUsageClientAuth[] = { PKIX_KEY_USAGE, 2 };
 CONST_OID pkixExtendedKeyUsageCodeSign[] = { PKIX_KEY_USAGE, 3 };
 CONST_OID pkixExtendedKeyUsageEMailProtect[] = { PKIX_KEY_USAGE, 4 };
+/* IPsecEnd, IPsecTunnel, and IPsecUser are deprecated, but still in use
+ * (see RFC4945) */
+CONST_OID pkixExtendedKeyUsageIPsecEnd[] = { PKIX_KEY_USAGE, 5 };
+CONST_OID pkixExtendedKeyUsageIPsecTunnel[] = { PKIX_KEY_USAGE, 6 };
+CONST_OID pkixExtendedKeyUsageIPsecUser[] = { PKIX_KEY_USAGE, 7 };
 CONST_OID pkixExtendedKeyUsageTimeStamp[] = { PKIX_KEY_USAGE, 8 };
 CONST_OID pkixOCSPResponderExtendedKeyUsage[] = { PKIX_KEY_USAGE, 9 };
 /* 17 replaces 5 + 6 + 7 (declared obsolete in RFC 4945) */
 CONST_OID pkixExtendedKeyUsageIPsecIKE[] = { PKIX_KEY_USAGE, 17 };
 CONST_OID msExtendedKeyUsageTrustListSigning[] = { MS_CRYPTO_EKU, 1 };
 
 CONST_OID ipsecIKEEnd[] = { INTERNET_SECURITY_MECH, 0x08, 0x02, 0x01 };
 CONST_OID ipsecIKEIntermediate[] = { INTERNET_SECURITY_MECH, 0x08, 0x02, 0x02 };
@@ -1773,16 +1778,28 @@ const static SECOidData oids[SEC_OID_TOT
     OD(ipsecIKEEnd,
        SEC_OID_IPSEC_IKE_END,
        "IPsec IKE End",
        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
     OD(ipsecIKEIntermediate,
        SEC_OID_IPSEC_IKE_INTERMEDIATE,
        "IPsec IKE Intermediate",
        CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD(pkixExtendedKeyUsageIPsecEnd,
+       SEC_OID_EXT_KEY_USAGE_IPSEC_END,
+       "IPsec Tunnel",
+       CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD(pkixExtendedKeyUsageIPsecTunnel,
+       SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL,
+       "IPsec Tunnel",
+       CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+    OD(pkixExtendedKeyUsageIPsecUser,
+       SEC_OID_EXT_KEY_USAGE_IPSEC_USER,
+       "IPsec User",
+       CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
 };
 
 /* PRIVATE EXTENDED SECOID Table
  * This table is private. Its structure is opaque to the outside.
  * It is indexed by the same SECOidTag as the oids table above.
  * Every member of this struct must have accessor functions (set, get)
  * and those functions must operate by value, not by reference.
  * The addresses of the contents of this table must not be exposed
--- a/security/nss/lib/util/secoidt.h
+++ b/security/nss/lib/util/secoidt.h
@@ -493,16 +493,19 @@ typedef enum {
     SEC_OID_CURVE25519 = 355,
 
     SEC_OID_TLS13_KEA_ANY = 356,
 
     SEC_OID_X509_ANY_EXT_KEY_USAGE = 357,
     SEC_OID_EXT_KEY_USAGE_IPSEC_IKE = 358,
     SEC_OID_IPSEC_IKE_END = 359,
     SEC_OID_IPSEC_IKE_INTERMEDIATE = 360,
+    SEC_OID_EXT_KEY_USAGE_IPSEC_END = 361,
+    SEC_OID_EXT_KEY_USAGE_IPSEC_TUNNEL = 362,
+    SEC_OID_EXT_KEY_USAGE_IPSEC_USER = 363,
 
     SEC_OID_TOTAL
 } SECOidTag;
 
 #define SEC_OID_SECG_EC_SECP192R1 SEC_OID_ANSIX962_EC_PRIME192V1
 #define SEC_OID_SECG_EC_SECP256R1 SEC_OID_ANSIX962_EC_PRIME256V1
 #define SEC_OID_PKCS12_KEY_USAGE SEC_OID_X509_KEY_USAGE
 
--- a/security/nss/nss.gyp
+++ b/security/nss/nss.gyp
@@ -262,16 +262,20 @@
                 '<(nss_dist_obj_dir)/lib/<(dll_prefix)nssdbm3.chk',
                 '<(nss_dist_obj_dir)/lib/<(dll_prefix)softokn3.chk'
               ],
               'conditions': [
                 ['OS!="linux"', {
                   'inputs/': [['exclude', 'freeblpriv']],
                   'outputs/': [['exclude', 'freeblpriv']]
                 }],
+                ['disable_dbm==1', {
+                  'inputs/': [['exclude', 'nssdbm3']],
+                  'outputs/': [['exclude', 'nssdbm3']]
+                }],
               ],
               'action': ['<(python)', '<(DEPTH)/coreconf/shlibsign.py', '<@(_inputs)']
             }
           ],
         },
       ],
     }],
     [ 'fuzz_tls==1', {
--- a/security/nss/tests/chains/scenarios/ipsec.cfg
+++ b/security/nss/tests/chains/scenarios/ipsec.cfg
@@ -30,16 +30,68 @@ entity DigSigNonRepAndExtra
   issuer CA1
     ku digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement
 
 entity NoMatch
   type EE
   issuer CA1
     ku keyEncipherment,dataEncipherment,keyAgreement
 
+entity NonCriticalServerAuthEKU
+  type EE
+  issuer CA1
+    eku serverAuth
+
+entity NonIPSECEKU
+  type EE
+  issuer CA1
+    eku codeSigning
+
+entity CriticalServerAuthEKU
+  type EE
+  issuer CA1
+    ku digitalSignature
+    eku critical,serverAuth
+
+entity EKUIPsecIKE
+  type EE
+  issuer CA1
+    ku digitalSignature
+    eku critical,ipsecIKE
+
+entity EKUIPsecIKEEnd
+  type EE
+  issuer CA1
+    ku digitalSignature
+    eku ipsecIKEEnd
+
+entity EKUIPsecIKEIntermediate
+  type EE
+  issuer CA1
+    ku digitalSignature
+    eku codeSigning,serverAuth,ipsecIKEIntermediate
+
+entity EKUAny
+  type EE
+  issuer CA1
+    ku digitalSignature
+    eku x509Any
+
+entity EKUEmail
+  type EE
+  issuer CA1
+    ku digitalSignature
+    eku emailProtection
+
+entity EKUIPsecUser
+  type EE
+  issuer CA1
+    ku digitalSignature
+    eku ipsecUser
+
 db All
 
 import Root::C,,
 import CA1:Root:
 
 verify NoKU:CA1
   usage 12
   result pass
@@ -54,8 +106,44 @@ verify NonRep:CA1
 
 verify DigSigNonRepAndExtra:CA1
   usage 12
   result pass
 
 verify NoMatch:CA1
   usage 12
   result fail
+
+verify NonIPSECEKU:CA1
+  usage 12
+  result fail
+
+verify NonCriticalServerAuthEKU:CA1
+  usage 12
+  result pass
+
+verify CriticalServerAuthEKU:CA1
+  usage 12
+  result pass
+
+verify EKUIPsecIKE:CA1
+  usage 12
+  result pass
+
+verify EKUIPsecIKEEnd:CA1
+  usage 12
+  result pass
+
+verify EKUIPsecIKEIntermediate:CA1
+  usage 12
+  result pass
+
+verify EKUAny:CA1
+  usage 12
+  result pass
+
+verify EKUEmail:CA1
+  usage 12
+  result pass
+
+verify EKUIPsecUser:CA1
+  usage 12
+  result pass
--- a/widget/nsPrintSettingsImpl.cpp
+++ b/widget/nsPrintSettingsImpl.cpp
@@ -21,17 +21,16 @@ nsPrintSettings::nsPrintSettings()
       mPrintBGColors(false),
       mPrintBGImages(false),
       mPrintFrameTypeUsage(kUseInternalDefault),
       mPrintFrameType(kFramesAsIs),
       mHowToEnableFrameUI(kFrameEnableNone),
       mIsCancelled(false),
       mSaveOnCancel(true),
       mPrintSilent(false),
-      mPrintPreview(false),
       mShrinkToFit(true),
       mShowPrintProgress(true),
       mPrintPageDelay(50),
       mPaperData(0),
       mPaperWidth(8.5),
       mPaperHeight(11.0),
       mPaperSizeUnit(kPaperSizeInches),
       mPrintReversed(false),
--- a/widget/nsPrintSettingsImpl.h
+++ b/widget/nsPrintSettingsImpl.h
@@ -56,17 +56,16 @@ class nsPrintSettings : public nsIPrintS
   bool mPrintBGImages;  // print background images
 
   int16_t mPrintFrameTypeUsage;
   int16_t mPrintFrameType;
   int16_t mHowToEnableFrameUI;
   bool mIsCancelled;
   bool mSaveOnCancel;
   bool mPrintSilent;
-  bool mPrintPreview;
   bool mShrinkToFit;
   bool mShowPrintProgress;
   int32_t mPrintPageDelay;
 
   nsString mTitle;
   nsString mURL;
   nsString mPageNumberFormat;
   nsString mHeaderStrs[NUM_HEAD_FOOT];