[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#991707: unblock: nodejs/12.22.4~dfsg-1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: security@debian.org

Please unblock package nodejs

[ Reason ]
Debian security team plans to upload nodejs security updates "as-is",
at least while upstream still maintain nodejs 12.x. This is what was
done in Buster.

Latest security update is 12.22.4 (severity high).
I did not try to get nodejs > 12.21.0 into bullseye up until now
because upstream changes were essentially not concerning the debian package.

However the 12.22.4 release has many v8 fixes, and a security fix (high).


[ Impact ]
If not in Bullseye, it will require users to download nodejs a second time
just after installation, through security updates.
So it will postpone any issue post-release.


[ Tests ]
Usual thorough upstream test suite + all dependents packages tests.

[ Risks ]
Low, but when considering the regressions i saw false positives:
- node-chokidar seems to have a flaky test
- node-esquery, node-caniuse-api, node-browserslist suites fail on their own,
  for an unrelated problem
- node-websocket-driver was already broken, probably for a long time.
  I opened #991700 and will ask its removal from testing.

Also an undocumented internal api has been deprecated, and old modules trying
accessing it will now print a warning (process.binding('http_parser')).
Only node-websocket-driver is actually using it...
A code search shows node-http-signature, node-fastcgi are using it in their
test suites, but it doesn't pose any problem.
https://codesearch.debian.net/search?q=process%5C.binding%5C%28%5B%27%22%5Dhttp_parser%5B%27%22%5D%5C%29&literal=0

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]
debdiff is without deps/cares (not used), deps/openssl (not used), test/*, benchmark/*, tools/msvs/*.
Still waiting for armhf test results when writing this request.

unblock nodejs/12.22.4~dfsg-1
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/common.gypi nodejs-12.22.4~dfsg/common.gypi
--- nodejs-12.21.0~dfsg/common.gypi	2021-02-23 03:58:04.000000000 +0100
+++ nodejs-12.22.4~dfsg/common.gypi	2021-07-29 12:35:21.000000000 +0200
@@ -34,7 +34,7 @@
 
     # Reset this number to 0 on major V8 upgrades.
     # Increment by one for each non-official patch applied to deps/v8.
-    'v8_embedder_string': '-node.45',
+    'v8_embedder_string': '-node.56',
 
     ##### V8 defaults for Node.js #####
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/debian/changelog nodejs-12.22.4~dfsg/debian/changelog
--- nodejs-12.21.0~dfsg/debian/changelog	2021-07-03 20:50:29.000000000 +0200
+++ nodejs-12.22.4~dfsg/debian/changelog	2021-07-30 01:02:46.000000000 +0200
@@ -1,3 +1,12 @@
+nodejs (12.22.4~dfsg-1) unstable; urgency=medium
+
+  * New upstream version 12.22.4~dfsg
+    Fixed vulnerabilities:
+    + CVE-2021-22930: Use after free on close http2
+      on stream canceling (High)
+
+ -- Jérémy Lal <kapouer@melix.org>  Fri, 30 Jul 2021 01:02:46 +0200
+
 nodejs (12.21.0~dfsg-5) unstable; urgency=medium
 
   * Patch uvwasi.gyp to honour --shared-libuv. Closes: #990569.
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/cjs-module-lexer/lexer.js nodejs-12.22.4~dfsg/deps/cjs-module-lexer/lexer.js
--- nodejs-12.21.0~dfsg/deps/cjs-module-lexer/lexer.js	2021-02-23 03:58:04.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/cjs-module-lexer/lexer.js	2021-07-29 12:35:21.000000000 +0200
@@ -37,8 +37,6 @@
 const ExportAssign = 1;
 const ExportStar = 2;
 
-const strictReserved = new Set(['implements', 'interface', 'let', 'package', 'private', 'protected', 'public', 'static', 'yield', 'enum']);
-
 function parseCJS (source, name = '@') {
   resetState();
   try {
@@ -49,14 +47,39 @@
     e.loc = pos;
     throw e;
   }
-  const result = { exports: [..._exports].filter(expt => !unsafeGetters.has(expt)), reexports: [...reexports] };
+  const result = { exports: [..._exports].filter(expt => expt !== undefined && !unsafeGetters.has(expt)), reexports: [...reexports].filter(reexpt => reexpt !== undefined) };
   resetState();
   return result;
 }
 
-function addExport (name) {
-  if (!strictReserved.has(name))
-    _exports.add(name);
+function decode (str) {
+  if (str[0] === '"' || str[0] === '\'') {
+    try {
+      const decoded = (0, eval)(str);
+      // Filter to exclude non-matching UTF-16 surrogate strings
+      for (let i = 0; i < decoded.length; i++) {
+        const surrogatePrefix = decoded.charCodeAt(i) & 0xFC00;
+        if (surrogatePrefix < 0xD800) {
+          // Not a surrogate
+          continue;
+        }
+        else if (surrogatePrefix === 0xD800) {
+          // Validate surrogate pair
+          if ((decoded.charCodeAt(++i) & 0xFC00) !== 0xDC00)
+            return;
+        }
+        else {
+          // Out-of-range surrogate code (above 0xD800)
+          return;
+        }
+      }
+      return decoded;
+    }
+    catch {}
+  }
+  else {
+    return str;
+  }
 }
 
 function parseSource (cjsSource) {
@@ -97,7 +120,18 @@
           lastTokenPos = pos;
           continue;
         case 95/*_*/:
-          if (source.startsWith('_export', pos + 1) && (keywordStart(pos) || source.charCodeAt(pos - 1) === 46/*.*/)) {
+          if (source.startsWith('interopRequireWildcard', pos + 1) && (keywordStart(pos) || source.charCodeAt(pos - 1) === 46/*.*/)) {
+            const startPos = pos;
+            pos += 23;
+            if (source.charCodeAt(pos) === 40/*(*/) {
+              pos++;
+              openTokenPosStack[openTokenDepth++] = lastTokenPos;
+              if (tryParseRequire(Import) && keywordStart(startPos)) {
+                tryBacktrackAddStarExportBinding(startPos - 1);
+              }
+            }
+          }
+          else if (source.startsWith('_export', pos + 1) && (keywordStart(pos) || source.charCodeAt(pos - 1) === 46/*.*/)) {
             pos += 8;
             if (source.startsWith('Star', pos))
               pos += 4;
@@ -162,10 +196,8 @@
         // TODO: <!-- XML comment support
         break;
       case 39/*'*/:
-        singleQuoteString();
-        break;
       case 34/*"*/:
-        doubleQuoteString();
+        stringLiteral(ch);
         break;
       case 47/*/*/: {
         const next_ch = source.charCodeAt(pos + 1);
@@ -254,6 +286,48 @@
   }
 }
 
+// `Object.` `prototype.`? hasOwnProperty.call(`  IDENTIFIER `, ` IDENTIFIER$2 `)`
+function tryParseObjectHasOwnProperty (it_id) {
+  ch = commentWhitespace();
+  if (ch !== 79/*O*/ || !source.startsWith('bject', pos + 1)) return false;
+  pos += 6;
+  ch = commentWhitespace();
+  if (ch !== 46/*.*/) return false;
+  pos++;
+  ch = commentWhitespace();
+  if (ch === 112/*p*/) {
+    if (!source.startsWith('rototype', pos + 1)) return false;
+    pos += 9;
+    ch = commentWhitespace();
+    if (ch !== 46/*.*/) return false;
+    pos++;
+    ch = commentWhitespace();
+  }
+  if (ch !== 104/*h*/ || !source.startsWith('asOwnProperty', pos + 1)) return false;
+  pos += 14;
+  ch = commentWhitespace();
+  if (ch !== 46/*.*/) return false;
+  pos++;
+  ch = commentWhitespace();
+  if (ch !== 99/*c*/ || !source.startsWith('all', pos + 1)) return false;
+  pos += 4;
+  ch = commentWhitespace();
+  if (ch !== 40/*(*/) return false;
+  pos++;
+  ch = commentWhitespace();
+  if (!identifier()) return false;
+  ch = commentWhitespace();
+  if (ch !== 44/*,*/) return false;
+  pos++;
+  ch = commentWhitespace();
+  if (!source.startsWith(it_id, pos)) return false;
+  pos += it_id.length;
+  ch = commentWhitespace();
+  if (ch !== 41/*)*/) return false;
+  pos++;
+  return true;
+}
+
 function tryParseObjectDefineOrKeys (keys) {
   pos += 6;
   let revertPos = pos - 1;
@@ -276,11 +350,9 @@
         pos++;
         ch = commentWhitespace();
         if (ch !== 39/*'*/ && ch !== 34/*"*/) break;
-        let quot = ch;
-        const exportPos = ++pos;
-        if (!identifier() || source.charCodeAt(pos) !== quot) break;
-        expt = source.slice(exportPos, pos);
-        pos++;
+        const exportPos = pos;
+        stringLiteral(ch);
+        expt = source.slice(exportPos, ++pos);
         ch = commentWhitespace();
         if (ch !== 44/*,*/) break;
         pos++;
@@ -307,7 +379,7 @@
           pos += 5;
           ch = commentWhitespace();
           if (ch !== 58/*:*/) break;
-          addExport(expt);
+          _exports.add(decode(expt));
           pos = revertPos;
           return;
         }
@@ -350,8 +422,7 @@
           else if (ch === 91/*[*/) {
             pos++;
             ch = commentWhitespace();
-            if (ch === 39/*'*/) singleQuoteString();
-            else if (ch === 34/*"*/) doubleQuoteString();
+            if (ch === 39/*'*/ || ch === 34/*"*/) stringLiteral(ch);
             else break;
             pos++;
             ch = commentWhitespace();
@@ -366,17 +437,21 @@
           if (ch !== 125/*}*/) break;
           pos++;
           ch = commentWhitespace();
+          if (ch === 44/*,*/) {
+            pos++;
+            ch = commentWhitespace();
+          }
           if (ch !== 125/*}*/) break;
           pos++;
           ch = commentWhitespace();
           if (ch !== 41/*)*/) break;
-          addExport(expt);
+          _exports.add(decode(expt));
           return;
         }
         break;
       }
       if (expt) {
-        unsafeGetters.add(expt);
+        unsafeGetters.add(decode(expt));
       }
     }
     else if (keys && ch === 107/*k*/ && source.startsWith('eys', pos + 1)) {
@@ -469,8 +544,94 @@
           if (ch === 59/*;*/)
             pos++;
           ch = commentWhitespace();
+
+          // `if (`
+          if (ch === 105/*i*/ && source.charCodeAt(pos + 1) === 102/*f*/) {
+            let inIf = true;
+            pos += 2;
+            ch = commentWhitespace();
+            if (ch !== 40/*(*/) break;
+            pos++;
+            const ifInnerPos = pos;
+            // `Object.prototype.hasOwnProperty.call(`  IDENTIFIER `, ` IDENTIFIER$2 `)) return` `;`?
+            if (tryParseObjectHasOwnProperty(it_id)) {
+              ch = commentWhitespace();
+              if (ch !== 41/*)*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (ch !== 114/*r*/ || !source.startsWith('eturn', pos + 1)) break;
+              pos += 6;
+              ch = commentWhitespace();
+              if (ch === 59/*;*/)
+                pos++;
+              ch = commentWhitespace();
+              // match next if
+              if (ch === 105/*i*/ && source.charCodeAt(pos + 1) === 102/*f*/) {
+                pos += 2;
+                ch = commentWhitespace();
+                if (ch !== 40/*(*/) break;
+                pos++;
+              }
+              else {
+                inIf = false;
+              }
+            }
+            else {
+              pos = ifInnerPos;
+            }
+
+            // IDENTIFIER$2 `in` EXPORTS_IDENTIFIER `&&` EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] ===` IDENTIFIER$1 `[` IDENTIFIER$2 `]) return` `;`?
+            if (inIf) {
+              if (!source.startsWith(it_id, pos)) break;
+              pos += it_id.length;
+              ch = commentWhitespace();
+              if (ch !== 105/*i*/ || !source.startsWith('n ', pos + 1)) break;
+              pos += 3;
+              ch = commentWhitespace();
+              if (!readExportsOrModuleDotExports(ch)) break;
+              ch = commentWhitespace();
+              if (ch !== 38/*&*/ || source.charCodeAt(pos + 1) !== 38/*&*/) break;
+              pos += 2;
+              ch = commentWhitespace();
+              if (!readExportsOrModuleDotExports(ch)) break;
+              ch = commentWhitespace();
+              if (ch !== 91/*[*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (!source.startsWith(it_id, pos)) break;
+              pos += it_id.length;
+              ch = commentWhitespace();
+              if (ch !== 93/*]*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (ch !== 61/*=*/ || !source.startsWith('==', pos + 1)) break;
+              pos += 3;
+              ch = commentWhitespace();
+              if (!source.startsWith(id, pos)) break;
+              pos += id.length;
+              ch = commentWhitespace();
+              if (ch !== 91/*[*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (!source.startsWith(it_id, pos)) break;
+              pos += it_id.length;
+              ch = commentWhitespace();
+              if (ch !== 93/*]*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (ch !== 41/*)*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (ch !== 114/*r*/ || !source.startsWith('eturn', pos + 1)) break;
+              pos += 6;
+              ch = commentWhitespace();
+              if (ch === 59/*;*/)
+                pos++;
+              ch = commentWhitespace();
+            }
+          }
         }
-        // `if (` IDENTIFIER$2 `!==` ( `'default'` | `"default"` ) `)`
+        // `if (` IDENTIFIER$2 `!==` ( `'default'` | `"default"` ) (`&& !` IDENTIFIER `.hasOwnProperty(` IDENTIFIER$2 `)`  )? `)`
         else if (ch === 33/*!*/) {
           if (!source.startsWith('==', pos + 1)) break;
           pos += 3;
@@ -483,67 +644,40 @@
           if (ch !== quot) break;
           pos += 1;
           ch = commentWhitespace();
+          if (ch === 38/*&*/) {
+            if (source.charCodeAt(pos + 1) !== 38/*&*/) break;
+            pos += 2;
+            ch = commentWhitespace();
+            if (ch !== 33/*!*/) break;
+            pos += 1;
+            ch = commentWhitespace();
+            if (source.startsWith(id, pos)) {
+              pos += id.length;
+              ch = commentWhitespace();
+              if (ch !== 46/*.*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (ch !== 104/*h*/ || !source.startsWith('asOwnProperty', pos + 1)) break;
+              pos += 14;
+              ch = commentWhitespace();
+              if (ch !== 40/*(*/) break;
+              pos += 1;
+              ch = commentWhitespace();
+              if (!source.startsWith(it_id, pos)) break;
+              pos += it_id.length;
+              ch = commentWhitespace();
+              if (ch !== 41/*)*/) break;
+              pos += 1;
+            }
+            else if (!tryParseObjectHasOwnProperty(it_id)) break;
+            ch = commentWhitespace();
+          }
           if (ch !== 41/*)*/) break;
           pos += 1;
           ch = commentWhitespace();
         }
         else break;
 
-        // `if (` IDENTIFIER$2 `in` EXPORTS_IDENTIFIER `&&` EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] ===` IDENTIFIER$1 `[` IDENTIFIER$2 `]) return` `;`?
-        if (ch === 105/*i*/ && source.charCodeAt(pos + 1) === 102/*f*/) {
-          pos += 2;
-          ch = commentWhitespace();
-          if (ch !== 40/*(*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (!source.startsWith(it_id, pos)) break;
-          pos += it_id.length;
-          ch = commentWhitespace();
-          if (ch !== 105/*i*/ || !source.startsWith('n ', pos + 1)) break;
-          pos += 3;
-          ch = commentWhitespace();
-          if (!readExportsOrModuleDotExports(ch)) break;
-          ch = commentWhitespace();
-          if (ch !== 38/*&*/ || source.charCodeAt(pos + 1) !== 38/*&*/) break;
-          pos += 2;
-          ch = commentWhitespace();
-          if (!readExportsOrModuleDotExports(ch)) break;
-          ch = commentWhitespace();
-          if (ch !== 91/*[*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (!source.startsWith(it_id, pos)) break;
-          pos += it_id.length;
-          ch = commentWhitespace();
-          if (ch !== 93/*]*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (ch !== 61/*=*/ || !source.startsWith('==', pos + 1)) break;
-          pos += 3;
-          ch = commentWhitespace();
-          if (!source.startsWith(id, pos)) break;
-          pos += id.length;
-          ch = commentWhitespace();
-          if (ch !== 91/*[*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (!source.startsWith(it_id, pos)) break;
-          pos += it_id.length;
-          ch = commentWhitespace();
-          if (ch !== 93/*]*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (ch !== 41/*)*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (ch !== 114/*r*/ || !source.startsWith('eturn', pos + 1)) break;
-          pos += 6;
-          ch = commentWhitespace();
-          if (ch === 59/*;*/)
-            pos++;
-          ch = commentWhitespace();
-        }
-
         // EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] =` IDENTIFIER$1 `[` IDENTIFIER$2 `]`
         if (readExportsOrModuleDotExports(ch)) {
           ch = commentWhitespace();
@@ -619,12 +753,17 @@
           if (ch !== 103/*g*/ || !source.startsWith('et', pos + 1)) break;
           pos += 3;
           ch = commentWhitespace();
-          if (ch !== 58/*:*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (ch !== 102/*f*/ || !source.startsWith('unction', pos + 1)) break;
-          pos += 8;
-          ch = commentWhitespace();
+          if (ch === 58/*:*/) {
+            pos++;
+            ch = commentWhitespace();
+            if (ch !== 102/*f*/) break;
+            if (!source.startsWith('unction', pos + 1)) break;
+            pos += 8;
+            let lastPos = pos;
+            ch = commentWhitespace();
+            if (ch !== 40 && (lastPos === pos || !identifier())) break;
+            ch = commentWhitespace();
+          }
           if (ch !== 40/*(*/) break;
           pos++;
           ch = commentWhitespace();
@@ -656,6 +795,10 @@
           if (ch !== 125/*}*/) break;
           pos++;
           ch = commentWhitespace();
+          if (ch === 44/*,*/) {
+            pos++;
+            ch = commentWhitespace();
+          }
           if (ch !== 125/*}*/) break;
           pos++;
           ch = commentWhitespace();
@@ -676,7 +819,7 @@
 
         const starExportSpecifier = starExportMap[id];
         if (starExportSpecifier) {
-          reexports.add(starExportSpecifier);
+          reexports.add(decode(starExportSpecifier));
           pos = revertPos;
           return;
         }
@@ -738,7 +881,7 @@
         const endPos = pos;
         ch = commentWhitespace();
         if (ch === 61/*=*/) {
-          addExport(source.slice(startPos, endPos));
+          _exports.add(decode(source.slice(startPos, endPos)));
           return;
         }
       }
@@ -749,19 +892,15 @@
       pos++;
       ch = commentWhitespace();
       if (ch === 39/*'*/ || ch === 34/*"*/) {
-        pos++;
         const startPos = pos;
-        if (identifier() && source.charCodeAt(pos) === ch) {
-          const endPos = pos++;
-          ch = commentWhitespace();
-          if (ch !== 93/*]*/)
-            break;
-          pos++;
-          ch = commentWhitespace();
-          if (ch !== 61/*=*/)
-            break;
-          addExport(source.slice(startPos, endPos));
-        }
+        stringLiteral(ch);
+        const endPos = ++pos;
+        ch = commentWhitespace();
+        if (ch !== 93/*]*/) break;
+        pos++;
+        ch = commentWhitespace();
+        if (ch !== 61/*=*/) break;
+        _exports.add(decode(source.slice(startPos, endPos)));
       }
       break;
     }
@@ -796,39 +935,21 @@
     if (ch === 40/*(*/) {
       pos++;
       ch = commentWhitespace();
-      const reexportStart = pos + 1;
-      if (ch === 39/*'*/) {
-        singleQuoteString();
-        const reexportEnd = pos++;
-        ch = commentWhitespace();
-        if (ch === 41/*)*/) {
-          switch (requireType) {
-            case ExportAssign:
-              reexports.add(source.slice(reexportStart, reexportEnd));
-              return true;
-            case ExportStar:
-              reexports.add(source.slice(reexportStart, reexportEnd));
-              return true;
-            default:
-              lastStarExportSpecifier = source.slice(reexportStart, reexportEnd);
-              return true;
-          }
-        }
-      }
-      else if (ch === 34/*"*/) {
-        doubleQuoteString();
-        const reexportEnd = pos++;
+      const reexportStart = pos;
+      if (ch === 39/*'*/ || ch === 34/*"*/) {
+        stringLiteral(ch);
+        const reexportEnd = ++pos;
         ch = commentWhitespace();
         if (ch === 41/*)*/) {
           switch (requireType) {
             case ExportAssign:
-              reexports.add(source.slice(reexportStart, reexportEnd));
+              reexports.add(decode(source.slice(reexportStart, reexportEnd)));
               return true;
             case ExportStar:
-              reexports.add(source.slice(reexportStart, reexportEnd));
+              reexports.add(decode(source.slice(reexportStart, reexportEnd)));
               return true;
             default:
-              lastStarExportSpecifier = source.slice(reexportStart, reexportEnd);
+              lastStarExportSpecifier = decode(source.slice(reexportStart, reexportEnd));
               return true;
           }
         }
@@ -857,7 +978,7 @@
         }
         ch = source.charCodeAt(pos);
       }
-      addExport(source.slice(startPos, endPos));
+      _exports.add(decode(source.slice(startPos, endPos)));
     }
     else if (ch === 46/*.*/ && source.startsWith('..', pos + 1)) {
       pos += 3;
@@ -871,21 +992,20 @@
       ch = commentWhitespace();
     }
     else if (ch === 39/*'*/ || ch === 34/*"*/) {
-      const startPos = ++pos;
-      if (identifier() && source.charCodeAt(pos) === ch) {
-        const endPos = pos++;
+      const startPos = pos;
+      stringLiteral(ch);
+      const endPos = ++pos;
+      ch = commentWhitespace();
+      if (ch === 58/*:*/) {
+        pos++;
         ch = commentWhitespace();
-        if (ch === 58/*:*/) {
-          pos++;
-          ch = commentWhitespace();
-          // nothing more complex than identifier expressions for now
-          if (!identifier()) {
-            pos = revertPos;
-            return;
-          }
-          ch = source.charCodeAt(pos);
-          addExport(source.slice(startPos, endPos));
+        // nothing more complex than identifier expressions for now
+        if (!identifier()) {
+          pos = revertPos;
+          return;
         }
+        ch = source.charCodeAt(pos);
+        _exports.add(decode(source.slice(startPos, endPos)));
       }
     }
     else {
@@ -1039,7 +1159,6 @@
     // import.meta
     case 46/*.*/:
       throw new Error('Unexpected import.meta in CJS module.');
-      return;
 
     default:
       // no space after "import" -> not an import keyword
@@ -1124,26 +1243,10 @@
   }
 }
 
-function singleQuoteString () {
-  while (pos++ < end) {
-    let ch = source.charCodeAt(pos);
-    if (ch === 39/*'*/)
-      return;
-    if (ch === 92/*\*/) {
-      ch = source.charCodeAt(++pos);
-      if (ch === 13/*\r*/ && source.charCodeAt(pos + 1) === 10/*\n*/)
-        pos++;
-    }
-    else if (isBr(ch))
-      break;
-  }
-  throw new Error('Unterminated string.');
-}
-
-function doubleQuoteString () {
+function stringLiteral (quote) {
   while (pos++ < end) {
     let ch = source.charCodeAt(pos);
-    if (ch === 34/*"*/)
+    if (ch === quote)
       return;
     if (ch === 92/*\*/) {
       ch = source.charCodeAt(++pos);
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/BUILD.gn nodejs-12.22.4~dfsg/deps/v8/BUILD.gn
--- nodejs-12.21.0~dfsg/deps/v8/BUILD.gn	2021-02-23 03:58:05.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/BUILD.gn	2021-07-29 12:35:23.000000000 +0200
@@ -6,7 +6,6 @@
 import("//build/config/arm.gni")
 import("//build/config/dcheck_always_on.gni")
 import("//build/config/host_byteorder.gni")
-import("//build/config/jumbo.gni")
 import("//build/config/mips.gni")
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build_overrides/build.gni")
@@ -266,7 +265,8 @@
 #
 
 config("internal_config_base") {
-  visibility = [ ":*" ]  # Only targets in this file can depend on this.
+ # Only targets in this file and its subdirs can depend on this.
+  visibility = [ "./*" ]
 
   include_dirs = [
     ".",
@@ -276,7 +276,8 @@
 
 config("internal_config") {
   defines = []
-  visibility = [ ":*" ]  # Only targets in this file can depend on this.
+  # Only targets in this file and its subdirs can depend on this.
+  visibility = [ "./*" ]
 
   configs = [
     "//build/config/compiler:wexit_time_destructors",
@@ -362,7 +363,8 @@
 # Put defines here that are only used in our internal files and NEVER in
 # external headers that embedders (such as chromium and node) might include.
 config("features") {
-  visibility = [ ":*" ]  # Only targets in this file can depend on this.
+  # Only targets in this file and its subdirs can depend on this.
+  visibility = [ "./*" ]
 
   defines = []
 
@@ -479,7 +481,8 @@
 }
 
 config("toolchain") {
-  visibility = [ ":*" ]  # Only targets in this file can depend on this.
+  # Only targets in this file and its subdirs can depend on this.
+  visibility = [ "./*" ]
 
   defines = []
   cflags = []
@@ -1470,17 +1473,12 @@
       if (v8_use_multi_snapshots) {
         deps += [ ":asm_to_inline_asm_trusted" ]
         sources += [ "$target_gen_dir/embedded_trusted.cc" ]
-        jumbo_excluded_sources = [ "$target_gen_dir/embedded_trusted.cc" ]
       }
     } else if (v8_enable_embedded_builtins) {
       sources += [ "$target_gen_dir/embedded.S" ]
 
       if (v8_use_multi_snapshots) {
         sources += [ "$target_gen_dir/embedded_trusted.S" ]
-        jumbo_excluded_sources = [
-          # Duplicated symbols with embedded.S
-          "$target_gen_dir/embedded_trusted.S",
-        ]
       }
     } else {
       sources += [ "src/snapshot/embedded/embedded-empty.cc" ]
@@ -1577,17 +1575,6 @@
     "src/interpreter/interpreter-intrinsics-generator.h",
   ]
 
-  jumbo_excluded_sources = [
-    # TODO(mostynb@vewd.com): don't exclude these http://crbug.com/752428
-    "src/builtins/builtins-async-iterator-gen.cc",
-    "src/builtins/builtins-async-generator-gen.cc",
-
-    # These source files take an unusually large amount of time to
-    # compile.  Build them separately to avoid bottlenecks.
-    "src/builtins/builtins-regexp-gen.cc",
-    "src/codegen/code-stub-assembler.cc",
-  ]
-
   if (v8_current_cpu == "x86") {
     sources += [
       ### gcmole(arch:ia32) ###
@@ -2996,19 +2983,6 @@
     sources += check_header_includes_sources
   }
 
-  jumbo_excluded_sources = [
-    # TODO(mostynb@vewd.com): don't exclude these http://crbug.com/752428
-    "src/profiler/heap-snapshot-generator.cc",  # Macro clash in mman-linux.h
-
-    # These source files take an unusually large amount of time to
-    # compile.  Build them separately to avoid bottlenecks.
-    "src/api/api.cc",
-    "src/heap/heap.cc",
-    "src/objects/elements.cc",
-    "src/objects/objects.cc",
-    "src/parsing/parser.cc",
-  ]
-
   if (v8_current_cpu == "x86") {
     sources += [  ### gcmole(arch:ia32) ###
       "src/codegen/ia32/assembler-ia32-inl.h",
@@ -3162,11 +3136,6 @@
         "src/diagnostics/unwinding-info-win64.h",
       ]
     }
-    jumbo_excluded_sources += [
-      # TODO(mostynb@vewd.com): fix this code so it doesn't need
-      # to be excluded, see the comments inside.
-      "src/codegen/arm64/instructions-arm64-constants.cc",
-    ]
   } else if (v8_current_cpu == "mips" || v8_current_cpu == "mipsel") {
     sources += [  ### gcmole(arch:mipsel) ###
       "src/codegen/mips/assembler-mips-inl.h",
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/DEPS nodejs-12.22.4~dfsg/deps/v8/DEPS
--- nodejs-12.21.0~dfsg/deps/v8/DEPS	2021-02-23 03:58:05.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/DEPS	2021-07-29 12:35:23.000000000 +0200
@@ -2,7 +2,15 @@
 # directory and assume that the root of the checkout is in ./v8/, so
 # all paths in here must match this assumption.
 
+gclient_gn_args_file = 'v8/build/config/gclient_args.gni'
+gclient_gn_args = [
+  'checkout_aemu'
+]
+
 vars = {
+  # By Default, do not checkout AEMU, as it is too big, as is done in Chromium.
+  'checkout_aemu': False,
+
   # Fetches only the SDK boot images which match at least one of the whitelist
   # entries in a comma-separated list.
   #
@@ -72,15 +80,15 @@
 
 deps = {
   'v8/build':
-    Var('chromium_url') + '/chromium/src/build.git' + '@' + '693faeda4ee025796c7e473d953a5a7b6ad64c93',
+    Var('chromium_url') + '/chromium/src/build.git' + '@' + 'c854b8178a7e0a20b168ffded4f2d2cb1e136e42',
   'v8/third_party/depot_tools':
-    Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + 'f38bc1796282c61087dcf15abc61b8fd18a68402',
+    Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + 'd4e6fb6573e0955110a2c69be29557f6626d9ae6',
   'v8/third_party/icu':
     Var('chromium_url') + '/chromium/deps/icu.git' + '@' + '53f6b233a41ec982d8445996247093f7aaf41639',
   'v8/third_party/instrumented_libraries':
     Var('chromium_url') + '/chromium/src/third_party/instrumented_libraries.git' + '@' + 'b1c3ca20848c117eb935b02c25d441f03e6fbc5e',
   'v8/buildtools':
-    Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '74cfb57006f83cfe050817526db359d5c8a11628',
+    Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '6302c1175607a436e18947a5abe9df2209e845fc',
   'v8/buildtools/clang_format/script':
     Var('chromium_url') + '/chromium/llvm-project/cfe/tools/clang-format.git' + '@' + '96636aa0e9f047f17447f2d45a094d0b59ed7917',
   'v8/buildtools/linux64': {
@@ -104,11 +112,11 @@
     'condition': 'host_os == "mac"',
   },
   'v8/buildtools/third_party/libc++/trunk':
-    Var('chromium_url') + '/chromium/llvm-project/libcxx.git' + '@' + '5938e0582bac570a41edb3d6a2217c299adc1bc6',
+    Var('chromium_url') + '/chromium/llvm-project/libcxx.git' + '@' + '78d6a7767ed57b50122a161b91f59f19c9bd0d19',
   'v8/buildtools/third_party/libc++abi/trunk':
-    Var('chromium_url') + '/chromium/llvm-project/libcxxabi.git' + '@' + '0d529660e32d77d9111912d73f2c74fc5fa2a858',
+    Var('chromium_url') + '/chromium/llvm-project/libcxxabi.git' + '@' + 'ce3db128f9e4d6d19d1cdbe39bb45fcc64a5adb0',
   'v8/buildtools/third_party/libunwind/trunk':
-    Var('chromium_url') + '/external/llvm.org/libunwind.git' + '@' + '69d9b84cca8354117b9fe9705a4430d789ee599b',
+    Var('chromium_url') + '/external/llvm.org/libunwind.git' + '@' + '3e6ec2ae9afaa3683269b690612f84d907943ea2',
   'v8/buildtools/win': {
     'packages': [
       {
@@ -168,7 +176,7 @@
       'dep_type': 'cipd',
   },
   'v8/third_party/catapult': {
-    'url': Var('chromium_url') + '/catapult.git' + '@' + 'e7c719c3e85f76938bf4fef0ba37c27f89246f71',
+    'url': Var('chromium_url') + '/catapult.git' + '@' + 'f92a7636da65f28dad15bc524e6b681d1c311de0',
     'condition': 'checkout_android',
   },
   'v8/third_party/colorama/src': {
@@ -216,7 +224,7 @@
       'dep_type': 'cipd',
   },
   'v8/tools/clang':
-    Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + '2fef805e5b05b26a8c87c47865590b5f43218611',
+    Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + 'c72342ce992ebd9cc02c0d65f0af5941d29eb217',
   'v8/tools/luci-go': {
       'packages': [
         {
@@ -246,7 +254,7 @@
     'dep_type': 'cipd',
   },
   'v8/third_party/perfetto':
-    Var('android_url') + '/platform/external/perfetto.git' + '@' + '01615892494a9a8dc84414962d0a817bf97de2c2',
+    Var('android_url') + '/platform/external/perfetto.git' + '@' + '7cdc44f903d3bcfd1d0f67188bfa797a24756868',
   'v8/third_party/protobuf':
     Var('chromium_url') + '/external/github.com/google/protobuf'+ '@' + 'b68a347f56137b4b1a746e8c7438495a6ac1bd91',
 }
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/gni/proto_library.gni nodejs-12.22.4~dfsg/deps/v8/gni/proto_library.gni
--- nodejs-12.21.0~dfsg/deps/v8/gni/proto_library.gni	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/gni/proto_library.gni	2021-07-29 12:35:23.000000000 +0200
@@ -11,8 +11,6 @@
   assert(defined(invoker.sources))
   proto_sources = invoker.sources
 
-  set_sources_assignment_filter([])
-
   if (host_os == "win") {
     host_executable_suffix = ".exe"
   } else {
@@ -137,6 +135,12 @@
       ]
     }
 
+    if (defined(invoker.import_dirs)) {
+      foreach(path, invoker.import_dirs) {
+        args += [ "--import-dir=" + rebase_path(path, root_build_dir) ]
+      }
+    }
+
     if (generate_with_plugin) {
       plugin_path_rebased = rebase_path(plugin_path, root_build_dir)
       plugin_out_args = ""
@@ -187,10 +191,7 @@
                              "visibility",
                            ])
 
-    # Exclude the config.descriptor file which is an output for some reason.
-    set_sources_assignment_filter([ "*.descriptor" ])
     sources = get_target_outputs(":$action_name")
-    set_sources_assignment_filter(sources_assignment_filter)
 
     # configs -= [ "//gn/standalone:extra_warnings" ]
     if (defined(invoker.extra_configs)) {
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/gni/split_static_library.gni nodejs-12.22.4~dfsg/deps/v8/gni/split_static_library.gni
--- nodejs-12.21.0~dfsg/deps/v8/gni/split_static_library.gni	1970-01-01 01:00:00.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/gni/split_static_library.gni	2021-07-29 12:35:23.000000000 +0200
@@ -0,0 +1,78 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/compiler/compiler.gni")
+
+template("split_static_library") {
+  assert(defined(invoker.split_count),
+         "Must define split_count for split_static_library")
+
+  # In many conditions the number of inputs will be 1 (because the
+  # count will be conditional on platform or configuration) and for
+  # some build configurations it's unnecessary to split libraries
+  # since the tooling will never create files of a problematic size.
+  if (invoker.split_count == 1 || use_lld) {
+    static_library(target_name) {
+      forward_variables_from(invoker, "*")
+    }
+  } else {
+    group_name = target_name
+
+    generated_static_libraries = []
+    current_library_index = 0
+    foreach(current_sources, split_list(invoker.sources, invoker.split_count)) {
+      current_name = "${target_name}_$current_library_index"
+      assert(
+          current_sources != [],
+          "Your values for splitting a static library generate one that has no sources.")
+      generated_static_libraries += [ ":$current_name" ]
+
+      static_library(current_name) {
+        # Generated static library shard gets everything but sources (which
+        # we're redefining) and visibility (which is set to be the group
+        # below).
+        forward_variables_from(invoker,
+                               "*",
+                               [
+                                 "check_includes",
+                                 "sources",
+                                 "visibility",
+                               ])
+        sources = current_sources
+        visibility = [ ":$group_name" ]
+
+        # When splitting a target's sources up into a series of static
+        # libraries, those targets will naturally include headers from each
+        # other arbitrarily. We could theoretically generate a web of
+        # dependencies and allow_circular_includes_from between all pairs of
+        # targets, but that's very cumbersome. Typical usage in Chrome is that
+        # only official Windows builds use split static libraries due to the
+        # Visual Studio size limits, and this means we'll still get header
+        # checking coverage for the other configurations.
+        check_includes = false
+
+        # Uniquify the output name if one is specified.
+        if (defined(invoker.output_name)) {
+          output_name = "${invoker.output_name}_$current_library_index"
+        }
+      }
+
+      current_library_index = current_library_index + 1
+    }
+
+    group(group_name) {
+      public_deps = generated_static_libraries
+      forward_variables_from(invoker,
+                             [
+                               "testonly",
+                               "visibility",
+                             ])
+    }
+  }
+}
+
+set_defaults("split_static_library") {
+  configs = default_compiler_configs
+}
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/gni/v8.gni nodejs-12.22.4~dfsg/deps/v8/gni/v8.gni
--- nodejs-12.21.0~dfsg/deps/v8/gni/v8.gni	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/gni/v8.gni	2021-07-29 12:35:23.000000000 +0200
@@ -2,10 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/jumbo.gni")
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build/config/v8_target_cpu.gni")
-import("//build/split_static_library.gni")
+import("split_static_library.gni")
 
 declare_args() {
   # Set flags for tracking code coverage. Uses gcov with gcc and sanitizer
@@ -80,7 +79,7 @@
   # build configuration. This allows us to set v8_use_multi_snapshots=true on
   # all bots, and e.g. no-snapshot bots will automatically do the right thing.
   v8_use_multi_snapshots =
-      v8_use_external_startup_data && !build_with_chromium && !use_jumbo_build
+      v8_use_external_startup_data && !build_with_chromium
 }
 
 if (v8_enable_backtrace == "") {
@@ -149,9 +148,9 @@
       defined(v8_static_library) && v8_static_library && is_win) {
     link_target_type = "jumbo_split_static_library"
   } else if (defined(v8_static_library) && v8_static_library) {
-    link_target_type = "jumbo_static_library"
+    link_target_type = "static_library"
   } else {
-    link_target_type = "jumbo_source_set"
+    link_target_type = "source_set"
   }
   target(link_target_type, target_name) {
     forward_variables_from(invoker,
@@ -170,7 +169,7 @@
 }
 
 template("v8_header_set") {
-  jumbo_source_set(target_name) {
+  source_set(target_name) {
     forward_variables_from(invoker, "*", [ "configs" ])
     configs -= v8_remove_configs
     configs += v8_add_configs
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/infra/mb/mb_config.pyl nodejs-12.22.4~dfsg/deps/v8/infra/mb/mb_config.pyl
--- nodejs-12.21.0~dfsg/deps/v8/infra/mb/mb_config.pyl	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/infra/mb/mb_config.pyl	2021-07-29 12:35:23.000000000 +0200
@@ -64,11 +64,6 @@
       'V8 Linux64 - debug - header includes': 'debug_x64_header_includes',
       'V8 Linux64 - shared': 'release_x64_shared_verify_heap',
       'V8 Linux64 - verify csa': 'release_x64_verify_csa',
-      # Jumbo.
-      'V8 Linux64 Jumbo': 'release_x64_jumbo',
-      'V8 Linux64 Jumbo - debug': 'debug_x64_jumbo',
-      'V8 Linux64 Jumbo - limited': 'release_x64_jumbo_limited',
-      'V8 Linux64 Jumbo - limited - debug': 'debug_x64_jumbo_limited',
       # Windows.
       'V8 Win32 - builder': 'release_x86_minimal_symbols',
       'V8 Win32 - debug builder': 'debug_x86_minimal_symbols',
@@ -230,8 +225,6 @@
       'v8_linux64_msan_rel': 'release_simulate_arm64_msan_minimal_symbols',
       'v8_linux64_sanitizer_coverage_rel':
           'release_x64_asan_minimal_symbols_coverage',
-      'v8_linux64_jumbo_compile_rel': 'release_x64_jumbo_trybot',
-      'v8_linux64_jumbo_limited_compile_rel': 'release_x64_jumbo_limited_trybot',
       'v8_linux64_tsan_rel': 'release_x64_tsan_minimal_symbols',
       'v8_linux64_tsan_isolates_rel_ng':
           'release_x64_tsan_minimal_symbols',
@@ -448,14 +441,6 @@
       'release_bot', 'x64', 'ios_simulator'],
     'release_x64_internal': [
       'release_bot', 'x64', 'v8_snapshot_internal'],
-    'release_x64_jumbo': [
-      'release_bot', 'x64', 'jumbo'],
-    'release_x64_jumbo_trybot': [
-      'release_trybot', 'x64', 'jumbo'],
-    'release_x64_jumbo_limited': [
-      'release_bot', 'x64', 'jumbo_limited'],
-    'release_x64_jumbo_limited_trybot': [
-      'release_trybot', 'x64', 'jumbo_limited'],
     'release_x64_minimal_symbols': [
       'release_bot', 'x64', 'minimal_symbols'],
     'release_x64_pointer_compression': [
@@ -499,10 +484,6 @@
       'debug_bot', 'x64', 'gcc', 'v8_check_header_includes'],
     'debug_x64_header_includes': [
       'debug_bot', 'x64', 'v8_check_header_includes'],
-    'debug_x64_jumbo': [
-      'debug_bot', 'x64', 'jumbo'],
-    'debug_x64_jumbo_limited': [
-      'debug_bot', 'x64', 'jumbo_limited'],
     'debug_x64_minimal_symbols': [
       'debug_bot', 'x64', 'minimal_symbols'],
     'debug_x64_perfetto': [
@@ -668,14 +649,6 @@
       'gn_args': 'target_cpu="x64" target_os="ios"',
     },
 
-    'jumbo': {
-      'gn_args': 'use_jumbo_build=true',
-    },
-
-    'jumbo_limited': {
-      'gn_args': 'use_jumbo_build=true jumbo_file_merge_limit=50',
-    },
-
     'lsan': {
       'mixins': ['v8_enable_test_features'],
       'gn_args': 'is_lsan=true',
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/base/cpu.cc nodejs-12.22.4~dfsg/deps/v8/src/base/cpu.cc
--- nodejs-12.21.0~dfsg/deps/v8/src/base/cpu.cc	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/base/cpu.cc	2021-07-29 12:35:23.000000000 +0200
@@ -27,6 +27,9 @@
 #ifndef POWER_9
 #define POWER_9 0x20000
 #endif
+#ifndef POWER_10
+#define POWER_10 0x40000
+#endif
 #endif
 #if V8_OS_POSIX
 #include <unistd.h>  // sysconf()
@@ -639,7 +642,10 @@
 
   part_ = -1;
   if (auxv_cpu_type) {
-    if (strcmp(auxv_cpu_type, "power9") == 0) {
+    if (strcmp(auxv_cpu_type, "power10") == 0) {
+      part_ = PPC_POWER10;
+    }
+    else if (strcmp(auxv_cpu_type, "power9") == 0) {
       part_ = PPC_POWER9;
     } else if (strcmp(auxv_cpu_type, "power8") == 0) {
       part_ = PPC_POWER8;
@@ -660,6 +666,9 @@
 
 #elif V8_OS_AIX
   switch (_system_configuration.implementation) {
+    case POWER_10:
+      part_ = PPC_POWER10;
+      break;
     case POWER_9:
       part_ = PPC_POWER9;
       break;
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/base/cpu.h nodejs-12.22.4~dfsg/deps/v8/src/base/cpu.h
--- nodejs-12.21.0~dfsg/deps/v8/src/base/cpu.h	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/base/cpu.h	2021-07-29 12:35:23.000000000 +0200
@@ -70,6 +70,7 @@
     PPC_POWER7,
     PPC_POWER8,
     PPC_POWER9,
+    PPC_POWER10,
     PPC_G4,
     PPC_G5,
     PPC_PA6T
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/base/macros.h nodejs-12.22.4~dfsg/deps/v8/src/base/macros.h
--- nodejs-12.21.0~dfsg/deps/v8/src/base/macros.h	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/base/macros.h	2021-07-29 12:35:23.000000000 +0200
@@ -357,14 +357,14 @@
   STATIC_ASSERT(std::is_integral<T>::value);
   // m must be a power of two.
   DCHECK(m != 0 && ((m & (m - 1)) == 0));
-  return x & -m;
+  return x & static_cast<T>(-m);
 }
 template <intptr_t m, typename T>
 constexpr inline T RoundDown(T x) {
   STATIC_ASSERT(std::is_integral<T>::value);
   // m must be a power of two.
   STATIC_ASSERT(m != 0 && ((m & (m - 1)) == 0));
-  return x & -m;
+  return x & static_cast<T>(-m);
 }
 
 // Return the smallest multiple of m which is >= x.
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/codegen/ppc/assembler-ppc.cc nodejs-12.22.4~dfsg/deps/v8/src/codegen/ppc/assembler-ppc.cc
--- nodejs-12.21.0~dfsg/deps/v8/src/codegen/ppc/assembler-ppc.cc	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/codegen/ppc/assembler-ppc.cc	2021-07-29 12:35:23.000000000 +0200
@@ -67,21 +67,28 @@
 #ifndef USE_SIMULATOR
   // Probe for additional features at runtime.
   base::CPU cpu;
-  if (cpu.part() == base::CPU::PPC_POWER9) {
+  if (cpu.part() == base::CPU::PPC_POWER9 || 
+      cpu.part() == base::CPU::PPC_POWER10) {
     supported_ |= (1u << MODULO);
   }
 #if V8_TARGET_ARCH_PPC64
-  if (cpu.part() == base::CPU::PPC_POWER8) {
+  if (cpu.part() == base::CPU::PPC_POWER8 || 
+      cpu.part() == base::CPU::PPC_POWER9 || 
+      cpu.part() == base::CPU::PPC_POWER10) {
     supported_ |= (1u << FPR_GPR_MOV);
   }
 #endif
   if (cpu.part() == base::CPU::PPC_POWER6 ||
       cpu.part() == base::CPU::PPC_POWER7 ||
-      cpu.part() == base::CPU::PPC_POWER8) {
+      cpu.part() == base::CPU::PPC_POWER8 || 
+      cpu.part() == base::CPU::PPC_POWER9 || 
+      cpu.part() == base::CPU::PPC_POWER10) {
     supported_ |= (1u << LWSYNC);
   }
   if (cpu.part() == base::CPU::PPC_POWER7 ||
-      cpu.part() == base::CPU::PPC_POWER8) {
+      cpu.part() == base::CPU::PPC_POWER8 || 
+      cpu.part() == base::CPU::PPC_POWER9 || 
+      cpu.part() == base::CPU::PPC_POWER10) {
     supported_ |= (1u << ISELECT);
     supported_ |= (1u << VSX);
   }
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/objects/js-list-format.cc nodejs-12.22.4~dfsg/deps/v8/src/objects/js-list-format.cc
--- nodejs-12.21.0~dfsg/deps/v8/src/objects/js-list-format.cc	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/objects/js-list-format.cc	2021-07-29 12:35:23.000000000 +0200
@@ -24,11 +24,14 @@
 #include "unicode/fpositer.h"
 #include "unicode/listformatter.h"
 #include "unicode/ulistformatter.h"
+#include "unicode/uvernum.h"
 
 namespace v8 {
 namespace internal {
 
 namespace {
+
+#if U_ICU_VERSION_MAJOR_NUM < 67
 const char* kStandard = "standard";
 const char* kOr = "or";
 const char* kUnit = "unit";
@@ -72,6 +75,31 @@
   }
   UNREACHABLE();
 }
+#else
+UListFormatterWidth GetIcuWidth(JSListFormat::Style style) {
+  switch (style) {
+    case JSListFormat::Style::LONG:
+      return ULISTFMT_WIDTH_WIDE;
+    case JSListFormat::Style::SHORT:
+      return ULISTFMT_WIDTH_SHORT;
+    case JSListFormat::Style::NARROW:
+      return ULISTFMT_WIDTH_NARROW;
+  }
+  UNREACHABLE();
+}
+
+UListFormatterType GetIcuType(JSListFormat::Type type) {
+  switch (type) {
+    case JSListFormat::Type::CONJUNCTION:
+      return ULISTFMT_TYPE_AND;
+    case JSListFormat::Type::DISJUNCTION:
+      return ULISTFMT_TYPE_OR;
+    case JSListFormat::Type::UNIT:
+      return ULISTFMT_TYPE_UNITS;
+  }
+  UNREACHABLE();
+}
+#endif
 
 }  // namespace
 
@@ -170,7 +198,11 @@
   icu::Locale icu_locale = r.icu_locale;
   UErrorCode status = U_ZERO_ERROR;
   icu::ListFormatter* formatter = icu::ListFormatter::createInstance(
+#if U_ICU_VERSION_MAJOR_NUM < 67
       icu_locale, GetIcuStyleString(style_enum, type_enum), status);
+#else
+      icu_locale, GetIcuType(type_enum), GetIcuWidth(style_enum), status);
+#endif
   if (U_FAILURE(status)) {
     delete formatter;
     FATAL("Failed to create ICU list formatter, are ICU data files missing?");
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/profiler/profiler-listener.cc nodejs-12.22.4~dfsg/deps/v8/src/profiler/profiler-listener.cc
--- nodejs-12.21.0~dfsg/deps/v8/src/profiler/profiler-listener.cc	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/profiler/profiler-listener.cc	2021-07-29 12:35:23.000000000 +0200
@@ -120,7 +120,8 @@
     // profiler as is stored on the code object, except that we transform source
     // positions to line numbers here, because we only care about attributing
     // ticks to a given line.
-    for (SourcePositionTableIterator it(abstract_code.source_position_table());
+    for (SourcePositionTableIterator it(
+             handle(abstract_code.source_position_table(), isolate_));
          !it.done(); it.Advance()) {
       int position = it.source_position().ScriptOffset();
       int inlining_id = it.source_position().InliningId();
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/testing/gtest/BUILD.gn nodejs-12.22.4~dfsg/deps/v8/testing/gtest/BUILD.gn
--- nodejs-12.21.0~dfsg/deps/v8/testing/gtest/BUILD.gn	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/testing/gtest/BUILD.gn	2021-07-29 12:35:25.000000000 +0200
@@ -4,9 +4,9 @@
 
 import("//build_overrides/gtest.gni")
 if (is_ios) {
+  import("//build/buildflag_header.gni")
   import("//build/config/coverage/coverage.gni")
   import("//build/config/ios/ios_sdk.gni")
-  import("//build/buildflag_header.gni")
 }
 
 config("gtest_direct_config") {
@@ -40,9 +40,7 @@
     #    Android. https://codereview.chromium.org/2852613002/#ps20001
     "empty.cc",
   ]
-  public_deps = [
-    "//third_party/googletest:gtest",
-  ]
+  public_deps = [ "//third_party/googletest:gtest" ]
 
   public_configs = [ ":gtest_direct_config" ]
 
@@ -58,9 +56,6 @@
   }
 
   if ((is_mac || is_ios) && gtest_include_objc_support) {
-    if (is_ios) {
-      set_sources_assignment_filter([])
-    }
     sources += [
       "../gtest_mac.h",
       "../gtest_mac.mm",
@@ -68,7 +63,6 @@
     if (gtest_include_platform_test) {
       sources += [ "../platform_test_mac.mm" ]
     }
-    set_sources_assignment_filter(sources_assignment_filter)
   }
 
   if (is_ios && gtest_include_ios_coverage) {
@@ -76,9 +70,7 @@
       "../coverage_util_ios.h",
       "../coverage_util_ios.mm",
     ]
-    deps = [
-      ":ios_enable_coverage",
-    ]
+    deps = [ ":ios_enable_coverage" ]
   }
 }
 
@@ -87,9 +79,7 @@
 # into //third_party/googletest.
 source_set("gtest_main") {
   testonly = true
-  deps = [
-    "//third_party/googletest:gtest_main",
-  ]
+  deps = [ "//third_party/googletest:gtest_main" ]
 }
 
 if (is_ios) {
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/internal/modules/esm/get_source.js nodejs-12.22.4~dfsg/lib/internal/modules/esm/get_source.js
--- nodejs-12.21.0~dfsg/lib/internal/modules/esm/get_source.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/internal/modules/esm/get_source.js	2021-07-29 12:35:25.000000000 +0200
@@ -1,5 +1,8 @@
 'use strict';
 
+const {
+  decodeURIComponent,
+} = primordials;
 const { getOptionValue } = require('internal/options');
 const manifest = getOptionValue('--experimental-policy') ?
   require('internal/process/policy').manifest :
@@ -28,8 +31,8 @@
     if (!match) {
       throw new ERR_INVALID_URL(url);
     }
-    const [ , base64, body ] = match;
-    source = Buffer.from(body, base64 ? 'base64' : 'utf8');
+    const { 1: base64, 2: body } = match;
+    source = Buffer.from(decodeURIComponent(body), base64 ? 'base64' : 'utf8');
   } else {
     throw new ERR_INVALID_URL_SCHEME(['file', 'data']);
   }
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/internal/modules/esm/resolve.js nodejs-12.22.4~dfsg/lib/internal/modules/esm/resolve.js
--- nodejs-12.21.0~dfsg/lib/internal/modules/esm/resolve.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/internal/modules/esm/resolve.js	2021-07-29 12:35:25.000000000 +0200
@@ -30,7 +30,7 @@
   Stats,
 } = require('fs');
 const { getOptionValue } = require('internal/options');
-const { sep, relative } = require('path');
+const { sep, relative, resolve } = require('path');
 const preserveSymlinks = getOptionValue('--preserve-symlinks');
 const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
 const typeFlag = getOptionValue('--input-type');
@@ -160,16 +160,18 @@
   return packageConfig;
 }
 
-/*
+/**
  * Legacy CommonJS main resolution:
  * 1. let M = pkg_url + (json main field)
  * 2. TRY(M, M.js, M.json, M.node)
  * 3. TRY(M/index.js, M/index.json, M/index.node)
  * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
  * 5. NOT_FOUND
+ * @param {string | URL} url
+ * @returns {boolean}
  */
 function fileExists(url) {
-  return tryStatSync(fileURLToPath(url)).isFile();
+  return tryStatSync(url).isFile();
 }
 
 function legacyMainResolve(packageJSONUrl, packageConfig, base) {
@@ -236,7 +238,19 @@
   return undefined;
 }
 
-function resolveIndex(search) {
+function resolveDirectoryEntry(search) {
+  const dirPath = fileURLToPath(search);
+  const pkgJsonPath = resolve(dirPath, 'package.json');
+  if (fileExists(pkgJsonPath)) {
+    const pkgJson = packageJsonReader.read(pkgJsonPath);
+    if (pkgJson.containsKeys) {
+      const { main } = JSONParse(pkgJson.string);
+      if (main != null) {
+        const mainUrl = pathToFileURL(resolve(dirPath, main));
+        return resolveExtensionsWithTryExactName(mainUrl);
+      }
+    }
+  }
   return resolveExtensions(new URL('index', search));
 }
 
@@ -252,10 +266,10 @@
     let file = resolveExtensionsWithTryExactName(resolved);
     if (file !== undefined) return file;
     if (!StringPrototypeEndsWith(path, '/')) {
-      file = resolveIndex(new URL(`${resolved}/`));
+      file = resolveDirectoryEntry(new URL(`${resolved}/`));
       if (file !== undefined) return file;
     } else {
-      return resolveIndex(resolved) || resolved;
+      return resolveDirectoryEntry(resolved) || resolved;
     }
     throw new ERR_MODULE_NOT_FOUND(
       resolved.pathname, fileURLToPath(base), 'module');
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/internal/per_context/primordials.js nodejs-12.22.4~dfsg/lib/internal/per_context/primordials.js
--- nodejs-12.21.0~dfsg/lib/internal/per_context/primordials.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/internal/per_context/primordials.js	2021-07-29 12:35:25.000000000 +0200
@@ -106,6 +106,16 @@
   class SafePromise extends Promise {}
 );
 
+// Create copies of URI handling functions
+[
+  decodeURI,
+  decodeURIComponent,
+  encodeURI,
+  encodeURIComponent,
+].forEach((fn) => {
+  primordials[fn.name] = fn;
+});
+
 // Create copies of the namespace objects
 [
   'JSON',
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/internal/url.js nodejs-12.22.4~dfsg/lib/internal/url.js
--- nodejs-12.21.0~dfsg/lib/internal/url.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/internal/url.js	2021-07-29 12:35:25.000000000 +0200
@@ -14,6 +14,7 @@
   Symbol,
   SymbolIterator,
   SymbolToStringTag,
+  decodeURIComponent,
 } = primordials;
 
 const { inspect } = require('internal/util/inspect');
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/internal/worker.js nodejs-12.22.4~dfsg/lib/internal/worker.js
--- nodejs-12.21.0~dfsg/lib/internal/worker.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/internal/worker.js	2021-07-29 12:35:25.000000000 +0200
@@ -17,6 +17,7 @@
 const EventEmitter = require('events');
 const assert = require('internal/assert');
 const path = require('path');
+const { timeOrigin } = internalBinding('performance');
 
 const errorCodes = require('internal/errors').codes;
 const {
@@ -67,6 +68,8 @@
 const kOnCouldNotSerializeErr = Symbol('kOnCouldNotSerializeErr');
 const kOnErrorMessage = Symbol('kOnErrorMessage');
 const kParentSideStdio = Symbol('kParentSideStdio');
+const kLoopStartTime = Symbol('kLoopStartTime');
+const kIsOnline = Symbol('kIsOnline');
 
 const SHARE_ENV = SymbolFor('nodejs.worker_threads.SHARE_ENV');
 let debug = require('internal/util/debuglog').debuglog('worker', (fn) => {
@@ -214,6 +217,12 @@
         null,
       hasStdin: !!options.stdin
     }, transferList);
+    // Use this to cache the Worker's loopStart value once available.
+    this[kLoopStartTime] = -1;
+    this[kIsOnline] = false;
+    this.performance = {
+      eventLoopUtilization: eventLoopUtilization.bind(this),
+    };
     // Actually start the new thread now that everything is in place.
     this[kHandle].startThread();
   }
@@ -245,6 +254,7 @@
   [kOnMessage](message) {
     switch (message.type) {
       case messageTypes.UP_AND_RUNNING:
+        this[kIsOnline] = true;
         return this.emit('online');
       case messageTypes.COULD_NOT_SERIALIZE_ERROR:
         return this[kOnCouldNotSerializeErr]();
@@ -406,6 +416,52 @@
   };
 }
 
+function eventLoopUtilization(util1, util2) {
+  // TODO(trevnorris): Works to solve the thread-safe read/write issue of
+  // loopTime, but has the drawback that it can't be set until the event loop
+  // has had a chance to turn. So it will be impossible to read the ELU of
+  // a worker thread immediately after it's been created.
+  if (!this[kIsOnline] || !this[kHandle]) {
+    return { idle: 0, active: 0, utilization: 0 };
+  }
+
+  // Cache loopStart, since it's only written to once.
+  if (this[kLoopStartTime] === -1) {
+    this[kLoopStartTime] = this[kHandle].loopStartTime();
+    if (this[kLoopStartTime] === -1)
+      return { idle: 0, active: 0, utilization: 0 };
+  }
+
+  if (util2) {
+    const idle = util1.idle - util2.idle;
+    const active = util1.active - util2.active;
+    return { idle, active, utilization: active / (idle + active) };
+  }
+
+  const idle = this[kHandle].loopIdleTime();
+
+  // Using performance.now() here is fine since it's always the time from
+  // the beginning of the process, and is why it needs to be offset by the
+  // loopStart time (which is also calculated from the beginning of the
+  // process).
+  const active = now() - this[kLoopStartTime] - idle;
+
+  if (!util1) {
+    return { idle, active, utilization: active / (idle + active) };
+  }
+
+  const idle_delta = idle - util1.idle;
+  const active_delta = active - util1.active;
+  const utilization = active_delta / (idle_delta + active_delta);
+  return { idle: idle_delta, active: active_delta, utilization };
+}
+
+// Duplicate code from performance.now() so don't need to require perf_hooks.
+function now() {
+  const hr = process.hrtime();
+  return (hr[0] * 1000 + hr[1] / 1e6) - timeOrigin;
+}
+
 module.exports = {
   ownsProcessState,
   isMainThread,
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/querystring.js nodejs-12.22.4~dfsg/lib/querystring.js
--- nodejs-12.21.0~dfsg/lib/querystring.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/querystring.js	2021-07-29 12:35:25.000000000 +0200
@@ -29,6 +29,7 @@
   MathAbs,
   ObjectCreate,
   ObjectKeys,
+  decodeURIComponent,
 } = primordials;
 
 const { Buffer } = require('buffer');
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/url.js nodejs-12.22.4~dfsg/lib/url.js
--- nodejs-12.21.0~dfsg/lib/url.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/url.js	2021-07-29 12:35:25.000000000 +0200
@@ -25,6 +25,7 @@
   ObjectCreate,
   ObjectKeys,
   SafeSet,
+  decodeURIComponent,
 } = primordials;
 
 const { toASCII } = require('internal/idna');
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/v8.js nodejs-12.22.4~dfsg/lib/v8.js
--- nodejs-12.21.0~dfsg/lib/v8.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/v8.js	2021-07-29 12:35:25.000000000 +0200
@@ -37,6 +37,12 @@
   Serializer: _Serializer,
   Deserializer: _Deserializer
 } = internalBinding('serdes');
+
+let profiler = {};
+if (internalBinding('config').hasInspector) {
+  profiler = internalBinding('profiler');
+}
+
 const assert = require('internal/assert');
 const { copy } = internalBinding('buffer');
 const { inspect } = require('internal/util/inspect');
@@ -286,6 +292,8 @@
   DefaultSerializer,
   DefaultDeserializer,
   deserialize,
+  takeCoverage: profiler.takeCoverage,
+  stopCoverage: profiler.stopCoverage,
   serialize,
   writeHeapSnapshot,
 };
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/api/environment.cc nodejs-12.22.4~dfsg/src/api/environment.cc
--- nodejs-12.21.0~dfsg/src/api/environment.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/api/environment.cc	2021-07-29 12:35:25.000000000 +0200
@@ -712,7 +712,8 @@
 }
 
 void DefaultProcessExitHandler(Environment* env, int exit_code) {
-  Stop(env);
+  env->set_can_call_into_js(false);
+  env->stop_sub_worker_contexts();
   DisposePlatform();
   uv_library_shutdown();
   exit(exit_code);
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/cares_wrap.cc nodejs-12.22.4~dfsg/src/cares_wrap.cc
--- nodejs-12.21.0~dfsg/src/cares_wrap.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/cares_wrap.cc	2021-07-29 12:35:25.000000000 +0200
@@ -49,7 +49,11 @@
 # include <arpa/nameser.h>
 #endif
 
-#if defined(__OpenBSD__)
+// OpenBSD does not define these
+#ifndef AI_ALL
+# define AI_ALL 0
+#endif
+#ifndef AI_V4MAPPED
 # define AI_V4MAPPED 0
 #endif
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/env.cc nodejs-12.22.4~dfsg/src/env.cc
--- nodejs-12.21.0~dfsg/src/env.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/env.cc	2021-07-29 12:35:25.000000000 +0200
@@ -550,10 +550,9 @@
   }
 }
 
-void Environment::Stop() {
+void Environment::ExitEnv() {
   set_can_call_into_js(false);
   set_stopping(true);
-  stop_sub_worker_contexts();
   isolate_->TerminateExecution();
   SetImmediateThreadsafe([](Environment* env) { uv_stop(env->event_loop()); });
 }
@@ -1039,6 +1038,8 @@
 }
 
 void Environment::stop_sub_worker_contexts() {
+  DCHECK_EQ(Isolate::GetCurrent(), isolate());
+
   while (!sub_worker_contexts_.empty()) {
     Worker* w = *sub_worker_contexts_.begin();
     remove_sub_worker_context(w);
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/env.h nodejs-12.22.4~dfsg/src/env.h
--- nodejs-12.21.0~dfsg/src/env.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/env.h	2021-07-29 12:35:25.000000000 +0200
@@ -253,6 +253,7 @@
   V(fd_string, "fd")                                                           \
   V(fields_string, "fields")                                                   \
   V(file_string, "file")                                                       \
+  V(filename_string, "filename")                                               \
   V(fingerprint256_string, "fingerprint256")                                   \
   V(fingerprint_string, "fingerprint")                                         \
   V(flags_string, "flags")                                                     \
@@ -926,7 +927,7 @@
   void RegisterHandleCleanups();
   void CleanupHandles();
   void Exit(int code);
-  void Stop();
+  void ExitEnv();
 
   // Register clean-up cb to be called on environment destruction.
   inline void RegisterHandleCleanup(uv_handle_t* handle,
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/inspector_profiler.cc nodejs-12.22.4~dfsg/src/inspector_profiler.cc
--- nodejs-12.21.0~dfsg/src/inspector_profiler.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/inspector_profiler.cc	2021-07-29 12:35:25.000000000 +0200
@@ -9,6 +9,7 @@
 #include "util-inl.h"
 #include "v8-inspector.h"
 
+#include <cinttypes>
 #include <sstream>
 
 namespace node {
@@ -36,10 +37,11 @@
           false)),
       env_(env) {}
 
-size_t V8ProfilerConnection::DispatchMessage(const char* method,
-                                             const char* params) {
+uint32_t V8ProfilerConnection::DispatchMessage(const char* method,
+                                               const char* params,
+                                               bool is_profile_request) {
   std::stringstream ss;
-  size_t id = next_id();
+  uint32_t id = next_id();
   ss << R"({ "id": )" << id;
   DCHECK(method != nullptr);
   ss << R"(, "method": ")" << method << '"';
@@ -50,12 +52,15 @@
   std::string message = ss.str();
   const uint8_t* message_data =
       reinterpret_cast<const uint8_t*>(message.c_str());
+  // Save the id of the profile request to identify its response.
+  if (is_profile_request) {
+    profile_ids_.insert(id);
+  }
   Debug(env(),
         DebugCategory::INSPECTOR_PROFILER,
         "Dispatching message %s\n",
         message.c_str());
   session_->Dispatch(StringView(message_data, message.length()));
-  // TODO(joyeecheung): use this to identify the ending message.
   return id;
 }
 
@@ -77,21 +82,10 @@
   Environment* env = connection_->env();
   Isolate* isolate = env->isolate();
   HandleScope handle_scope(isolate);
-  Context::Scope context_scope(env->context());
+  Local<Context> context = env->context();
+  Context::Scope context_scope(context);
 
-  // TODO(joyeecheung): always parse the message so that we can use the id to
-  // identify ending messages as well as printing the message in the debug
-  // output when there is an error.
   const char* type = connection_->type();
-  Debug(env,
-        DebugCategory::INSPECTOR_PROFILER,
-        "Receive %s profile message, ending = %s\n",
-        type,
-        connection_->ending() ? "true" : "false");
-  if (!connection_->ending()) {
-    return;
-  }
-
   // Convert StringView to a Local<String>.
   Local<String> message_str;
   if (!String::NewFromTwoByte(isolate,
@@ -99,11 +93,62 @@
                               NewStringType::kNormal,
                               message.length())
            .ToLocal(&message_str)) {
-    fprintf(stderr, "Failed to convert %s profile message\n", type);
+    fprintf(
+        stderr, "Failed to convert %s profile message to V8 string\n", type);
+    return;
+  }
+
+  Debug(env,
+        DebugCategory::INSPECTOR_PROFILER,
+        "Receive %s profile message\n",
+        type);
+
+  Local<Value> parsed;
+  if (!v8::JSON::Parse(context, message_str).ToLocal(&parsed) ||
+      !parsed->IsObject()) {
+    fprintf(stderr, "Failed to parse %s profile result as JSON object\n", type);
+    return;
+  }
+
+  Local<Object> response = parsed.As<Object>();
+  Local<Value> id_v;
+  if (!response->Get(context, FIXED_ONE_BYTE_STRING(isolate, "id"))
+           .ToLocal(&id_v) ||
+      !id_v->IsUint32()) {
+    Utf8Value str(isolate, message_str);
+    fprintf(
+        stderr, "Cannot retrieve id from the response message:\n%s\n", *str);
     return;
   }
+  uint32_t id = id_v.As<v8::Uint32>()->Value();
 
-  connection_->WriteProfile(message_str);
+  if (!connection_->HasProfileId(id)) {
+    Utf8Value str(isolate, message_str);
+    Debug(env, DebugCategory::INSPECTOR_PROFILER, "%s\n", *str);
+    return;
+  } else {
+    Debug(env,
+          DebugCategory::INSPECTOR_PROFILER,
+          "Writing profile response (id = %" PRIu64 ")\n",
+          static_cast<uint64_t>(id));
+  }
+
+  // Get message.result from the response.
+  Local<Value> result_v;
+  if (!response->Get(context, FIXED_ONE_BYTE_STRING(isolate, "result"))
+           .ToLocal(&result_v)) {
+    fprintf(stderr, "Failed to get 'result' from %s profile response\n", type);
+    return;
+  }
+
+  if (!result_v->IsObject()) {
+    fprintf(
+        stderr, "'result' from %s profile response is not an object\n", type);
+    return;
+  }
+
+  connection_->WriteProfile(result_v.As<Object>());
+  connection_->RemoveProfileId(id);
 }
 
 static bool EnsureDirectory(const std::string& directory, const char* type) {
@@ -138,45 +183,9 @@
   return filename;
 }
 
-static MaybeLocal<Object> ParseProfile(Environment* env,
-                                       Local<String> message,
-                                       const char* type) {
-  Local<Context> context = env->context();
-  Isolate* isolate = env->isolate();
-
-  // Get message.result from the response
-  Local<Value> parsed;
-  if (!v8::JSON::Parse(context, message).ToLocal(&parsed) ||
-      !parsed->IsObject()) {
-    fprintf(stderr, "Failed to parse %s profile result as JSON object\n", type);
-    return MaybeLocal<Object>();
-  }
-
-  Local<Value> result_v;
-  if (!parsed.As<Object>()
-           ->Get(context, FIXED_ONE_BYTE_STRING(isolate, "result"))
-           .ToLocal(&result_v)) {
-    fprintf(stderr, "Failed to get 'result' from %s profile message\n", type);
-    return MaybeLocal<Object>();
-  }
-
-  if (!result_v->IsObject()) {
-    fprintf(
-        stderr, "'result' from %s profile message is not an object\n", type);
-    return MaybeLocal<Object>();
-  }
-
-  return result_v.As<Object>();
-}
-
-void V8ProfilerConnection::WriteProfile(Local<String> message) {
+void V8ProfilerConnection::WriteProfile(Local<Object> result) {
   Local<Context> context = env_->context();
 
-  // Get message.result from the response.
-  Local<Object> result;
-  if (!ParseProfile(env_, message, type()).ToLocal(&result)) {
-    return;
-  }
   // Generate the profile output from the subclass.
   Local<Object> profile;
   if (!GetProfile(result).ToLocal(&profile)) {
@@ -203,7 +212,7 @@
   WriteResult(env_, path.c_str(), result_s);
 }
 
-void V8CoverageConnection::WriteProfile(Local<String> message) {
+void V8CoverageConnection::WriteProfile(Local<Object> result) {
   Isolate* isolate = env_->isolate();
   Local<Context> context = env_->context();
   HandleScope handle_scope(isolate);
@@ -219,11 +228,6 @@
     return;
   }
 
-  // Get message.result from the response.
-  Local<Object> result;
-  if (!ParseProfile(env_, message, type()).ToLocal(&result)) {
-    return;
-  }
   // Generate the profile output from the subclass.
   Local<Object> profile;
   if (!GetProfile(result).ToLocal(&profile)) {
@@ -287,10 +291,23 @@
                   R"({ "callCount": true, "detailed": true })");
 }
 
+void V8CoverageConnection::TakeCoverage() {
+  DispatchMessage("Profiler.takePreciseCoverage", nullptr, true);
+}
+
+void V8CoverageConnection::StopCoverage() {
+  DispatchMessage("Profiler.stopPreciseCoverage");
+}
+
 void V8CoverageConnection::End() {
-  CHECK_EQ(ending_, false);
+  Debug(env_,
+      DebugCategory::INSPECTOR_PROFILER,
+      "V8CoverageConnection::End(), ending = %d\n", ending_);
+  if (ending_) {
+    return;
+  }
   ending_ = true;
-  DispatchMessage("Profiler.takePreciseCoverage");
+  TakeCoverage();
 }
 
 std::string V8CpuProfilerConnection::GetDirectory() const {
@@ -327,9 +344,14 @@
 }
 
 void V8CpuProfilerConnection::End() {
-  CHECK_EQ(ending_, false);
+  Debug(env_,
+      DebugCategory::INSPECTOR_PROFILER,
+      "V8CpuProfilerConnection::End(), ending = %d\n", ending_);
+  if (ending_) {
+    return;
+  }
   ending_ = true;
-  DispatchMessage("Profiler.stop");
+  DispatchMessage("Profiler.stop", nullptr, true);
 }
 
 std::string V8HeapProfilerConnection::GetDirectory() const {
@@ -365,31 +387,33 @@
 }
 
 void V8HeapProfilerConnection::End() {
-  CHECK_EQ(ending_, false);
+  Debug(env_,
+      DebugCategory::INSPECTOR_PROFILER,
+      "V8HeapProfilerConnection::End(), ending = %d\n", ending_);
+  if (ending_) {
+    return;
+  }
   ending_ = true;
-  DispatchMessage("HeapProfiler.stopSampling");
+  DispatchMessage("HeapProfiler.stopSampling", nullptr, true);
 }
 
 // For now, we only support coverage profiling, but we may add more
 // in the future.
 static void EndStartedProfilers(Environment* env) {
+  // TODO(joyeechueng): merge these connections and use one session per env.
   Debug(env, DebugCategory::INSPECTOR_PROFILER, "EndStartedProfilers\n");
   V8ProfilerConnection* connection = env->cpu_profiler_connection();
-  if (connection != nullptr && !connection->ending()) {
-    Debug(env, DebugCategory::INSPECTOR_PROFILER, "Ending cpu profiling\n");
+  if (connection != nullptr) {
     connection->End();
   }
 
   connection = env->heap_profiler_connection();
-  if (connection != nullptr && !connection->ending()) {
-    Debug(env, DebugCategory::INSPECTOR_PROFILER, "Ending heap profiling\n");
+  if (connection != nullptr) {
     connection->End();
   }
 
   connection = env->coverage_connection();
-  if (connection != nullptr && !connection->ending()) {
-    Debug(
-        env, DebugCategory::INSPECTOR_PROFILER, "Ending coverage collection\n");
+  if (connection != nullptr) {
     connection->End();
   }
 }
@@ -469,6 +493,37 @@
   env->set_source_map_cache_getter(args[0].As<Function>());
 }
 
+static void TakeCoverage(const FunctionCallbackInfo<Value>& args) {
+  Environment* env = Environment::GetCurrent(args);
+  V8CoverageConnection* connection = env->coverage_connection();
+
+  Debug(
+    env,
+    DebugCategory::INSPECTOR_PROFILER,
+    "TakeCoverage, connection %s nullptr\n",
+    connection == nullptr ? "==" : "!=");
+
+  if (connection != nullptr) {
+    Debug(env, DebugCategory::INSPECTOR_PROFILER, "taking coverage\n");
+    connection->TakeCoverage();
+  }
+}
+
+static void StopCoverage(const FunctionCallbackInfo<Value>& args) {
+  Environment* env = Environment::GetCurrent(args);
+  V8CoverageConnection* connection = env->coverage_connection();
+
+  Debug(env,
+        DebugCategory::INSPECTOR_PROFILER,
+        "StopCoverage, connection %s nullptr\n",
+        connection == nullptr ? "==" : "!=");
+
+  if (connection != nullptr) {
+    Debug(env, DebugCategory::INSPECTOR_PROFILER, "Stopping coverage\n");
+    connection->StopCoverage();
+  }
+}
+
 static void Initialize(Local<Object> target,
                        Local<Value> unused,
                        Local<Context> context,
@@ -476,6 +531,8 @@
   Environment* env = Environment::GetCurrent(context);
   env->SetMethod(target, "setCoverageDirectory", SetCoverageDirectory);
   env->SetMethod(target, "setSourceMapCacheGetter", SetSourceMapCacheGetter);
+  env->SetMethod(target, "takeCoverage", TakeCoverage);
+  env->SetMethod(target, "stopCoverage", StopCoverage);
 }
 
 }  // namespace profiler
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/inspector_profiler.h nodejs-12.22.4~dfsg/src/inspector_profiler.h
--- nodejs-12.21.0~dfsg/src/inspector_profiler.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/inspector_profiler.h	2021-07-29 12:35:25.000000000 +0200
@@ -7,6 +7,7 @@
 #error("This header can only be used when inspector is enabled")
 #endif
 
+#include <unordered_set>
 #include "inspector_agent.h"
 
 namespace node {
@@ -39,7 +40,9 @@
   // The optional `params` should be formatted in JSON.
   // The strings should be in one byte characters - which is enough for
   // the commands we use here.
-  size_t DispatchMessage(const char* method, const char* params = nullptr);
+  uint32_t DispatchMessage(const char* method,
+                           const char* params = nullptr,
+                           bool is_profile_request = false);
 
   // Use DispatchMessage() to dispatch necessary inspector messages
   // to start and end the profiling.
@@ -58,12 +61,19 @@
   // which will be then written as a JSON.
   virtual v8::MaybeLocal<v8::Object> GetProfile(
       v8::Local<v8::Object> result) = 0;
-  virtual void WriteProfile(v8::Local<v8::String> message);
+  virtual void WriteProfile(v8::Local<v8::Object> result);
+
+  bool HasProfileId(uint32_t id) const {
+    return profile_ids_.find(id) != profile_ids_.end();
+  }
+
+  void RemoveProfileId(uint32_t id) { profile_ids_.erase(id); }
 
  private:
-  size_t next_id() { return id_++; }
+  uint32_t next_id() { return id_++; }
   std::unique_ptr<inspector::InspectorSession> session_;
-  size_t id_ = 1;
+  uint32_t id_ = 1;
+  std::unordered_set<uint32_t> profile_ids_;
 
  protected:
   Environment* env_ = nullptr;
@@ -82,8 +92,10 @@
   std::string GetDirectory() const override;
   std::string GetFilename() const override;
   v8::MaybeLocal<v8::Object> GetProfile(v8::Local<v8::Object> result) override;
-  void WriteProfile(v8::Local<v8::String> message) override;
+  void WriteProfile(v8::Local<v8::Object> result) override;
   void WriteSourceMapCache();
+  void TakeCoverage();
+  void StopCoverage();
 
  private:
   std::unique_ptr<inspector::InspectorSession> session_;
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/js_native_api.h nodejs-12.22.4~dfsg/src/js_native_api.h
--- nodejs-12.21.0~dfsg/src/js_native_api.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/js_native_api.h	2021-07-29 12:35:25.000000000 +0200
@@ -17,7 +17,7 @@
 // functions available in a new version of N-API that is not yet ported in all
 // LTS versions, they can set NAPI_VERSION knowing that they have specifically
 // depended on that version.
-#define NAPI_VERSION 7
+#define NAPI_VERSION 8
 #endif
 #endif
 
@@ -539,7 +539,7 @@
                                                      bool* result);
 #endif  // NAPI_VERSION >= 7
 
-#ifdef NAPI_EXPERIMENTAL
+#if NAPI_VERSION >= 8
 // Type tagging
 NAPI_EXTERN napi_status napi_type_tag_object(napi_env env,
                                              napi_value value,
@@ -554,7 +554,7 @@
                                            napi_value object);
 NAPI_EXTERN napi_status napi_object_seal(napi_env env,
                                          napi_value object);
-#endif  // NAPI_EXPERIMENTAL
+#endif  // NAPI_VERSION >= 8
 
 EXTERN_C_END
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/js_native_api_types.h nodejs-12.22.4~dfsg/src/js_native_api_types.h
--- nodejs-12.21.0~dfsg/src/js_native_api_types.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/js_native_api_types.h	2021-07-29 12:35:25.000000000 +0200
@@ -31,7 +31,7 @@
   // from instance properties. Ignored by napi_define_properties.
   napi_static = 1 << 10,
 
-#ifdef NAPI_EXPERIMENTAL
+#if NAPI_VERSION >= 8
   // Default for class methods.
   napi_default_method = napi_writable | napi_configurable,
 
@@ -39,7 +39,7 @@
   napi_default_jsproperty = napi_writable |
                             napi_enumerable |
                             napi_configurable,
-#endif  // NAPI_EXPERIMENTAL
+#endif  // NAPI_VERSION >= 8
 } napi_property_attributes;
 
 typedef enum {
@@ -146,11 +146,11 @@
 } napi_key_conversion;
 #endif  // NAPI_VERSION >= 6
 
-#ifdef NAPI_EXPERIMENTAL
+#if NAPI_VERSION >= 8
 typedef struct {
   uint64_t lower;
   uint64_t upper;
 } napi_type_tag;
-#endif  // NAPI_EXPERIMENTAL
+#endif  // NAPI_VERSION >= 8
 
 #endif  // SRC_JS_NATIVE_API_TYPES_H_
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_api.cc nodejs-12.22.4~dfsg/src/node_api.cc
--- nodejs-12.21.0~dfsg/src/node_api.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_api.cc	2021-07-29 12:35:25.000000000 +0200
@@ -12,8 +12,9 @@
 #include <memory>
 
 struct node_napi_env__ : public napi_env__ {
-  explicit node_napi_env__(v8::Local<v8::Context> context):
-      napi_env__(context) {
+  explicit node_napi_env__(v8::Local<v8::Context> context,
+                           const std::string& module_filename):
+      napi_env__(context), filename(module_filename) {
     CHECK_NOT_NULL(node_env());
   }
 
@@ -43,6 +44,10 @@
       });
     });
   }
+
+  const char* GetFilename() const { return filename.c_str(); }
+
+  std::string filename;
 };
 
 typedef node_napi_env__* node_napi_env;
@@ -84,10 +89,11 @@
   };
 };
 
-static inline napi_env NewEnv(v8::Local<v8::Context> context) {
+static inline napi_env
+NewEnv(v8::Local<v8::Context> context, const std::string& module_filename) {
   node_napi_env result;
 
-  result = new node_napi_env__(context);
+  result = new node_napi_env__(context, module_filename);
   // TODO(addaleax): There was previously code that tried to delete the
   // napi_env when its v8::Context was garbage collected;
   // However, as long as N-API addons using this napi_env are in place,
@@ -454,16 +460,35 @@
                                     v8::Local<v8::Value> module,
                                     v8::Local<v8::Context> context,
                                     napi_addon_register_func init) {
+  node::Environment* node_env = node::Environment::GetCurrent(context);
+  std::string module_filename = "";
   if (init == nullptr) {
-    node::Environment* node_env = node::Environment::GetCurrent(context);
     CHECK_NOT_NULL(node_env);
     node_env->ThrowError(
         "Module has no declared entry point.");
     return;
   }
 
+  // We set `env->filename` from `module.filename` here, but we could just as
+  // easily add a private property to `exports` in `process.dlopen`, which
+  // receives the file name from JS, and retrieve *that* here. Thus, we are not
+  // endorsing commonjs here by making use of `module.filename`.
+  v8::Local<v8::Value> filename_js;
+  v8::Local<v8::Object> modobj;
+  if (module->ToObject(context).ToLocal(&modobj) &&
+      modobj->Get(context, node_env->filename_string()).ToLocal(&filename_js) &&
+      filename_js->IsString()) {
+    node::Utf8Value filename(node_env->isolate(), filename_js);  // Cast
+
+    // Turn the absolute path into a URL. Currently the absolute path is always
+    // a file system path.
+    // TODO(gabrielschulhof): Pass the `filename` through unchanged if/when we
+    // receive it as a URL already.
+    module_filename = std::string("file://") + (*filename);
+  }
+
   // Create a new napi_env for this specific module.
-  napi_env env = v8impl::NewEnv(context);
+  napi_env env = v8impl::NewEnv(context, module_filename);
 
   napi_value _exports;
   env->CallIntoModule([&](napi_env env) {
@@ -1154,3 +1179,11 @@
   CHECK_NOT_NULL(func);
   return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Ref();
 }
+
+napi_status node_api_get_module_file_name(napi_env env, const char** result) {
+  CHECK_ENV(env);
+  CHECK_ARG(env, result);
+
+  *result = static_cast<node_napi_env>(env)->GetFilename();
+  return napi_clear_last_error(env);
+}
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_api.h nodejs-12.22.4~dfsg/src/node_api.h
--- nodejs-12.21.0~dfsg/src/node_api.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_api.h	2021-07-29 12:35:25.000000000 +0200
@@ -250,7 +250,7 @@
 
 #endif  // NAPI_VERSION >= 4
 
-#ifdef NAPI_EXPERIMENTAL
+#if NAPI_VERSION >= 8
 
 NAPI_EXTERN napi_status napi_add_async_cleanup_hook(
     napi_env env,
@@ -261,6 +261,13 @@
 NAPI_EXTERN napi_status napi_remove_async_cleanup_hook(
     napi_async_cleanup_hook_handle remove_handle);
 
+#endif  // NAPI_VERSION >= 8
+
+#ifdef NAPI_EXPERIMENTAL
+
+NAPI_EXTERN napi_status
+node_api_get_module_file_name(napi_env env, const char** result);
+
 #endif  // NAPI_EXPERIMENTAL
 
 EXTERN_C_END
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_api_types.h nodejs-12.22.4~dfsg/src/node_api_types.h
--- nodejs-12.21.0~dfsg/src/node_api_types.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_api_types.h	2021-07-29 12:35:25.000000000 +0200
@@ -41,10 +41,10 @@
   const char* release;
 } napi_node_version;
 
-#ifdef NAPI_EXPERIMENTAL
+#if NAPI_VERSION >= 8
 typedef struct napi_async_cleanup_hook_handle__* napi_async_cleanup_hook_handle;
 typedef void (*napi_async_cleanup_hook)(napi_async_cleanup_hook_handle handle,
                                         void* data);
-#endif  // NAPI_EXPERIMENTAL
+#endif  // NAPI_VERSION >= 8
 
 #endif  // SRC_NODE_API_TYPES_H_
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node.cc nodejs-12.22.4~dfsg/src/node.cc
--- nodejs-12.21.0~dfsg/src/node.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node.cc	2021-07-29 12:35:25.000000000 +0200
@@ -1035,7 +1035,7 @@
 }
 
 int Stop(Environment* env) {
-  env->Stop();
+  env->ExitEnv();
   return 0;
 }
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node.h nodejs-12.22.4~dfsg/src/node.h
--- nodejs-12.21.0~dfsg/src/node.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node.h	2021-07-29 12:35:25.000000000 +0200
@@ -218,8 +218,7 @@
 NODE_EXTERN int Start(int argc, char* argv[]);
 
 // Tear down Node.js while it is running (there are active handles
-// in the loop and / or actively executing JavaScript code). This also stops
-// all Workers that may have been started earlier.
+// in the loop and / or actively executing JavaScript code).
 NODE_EXTERN int Stop(Environment* env);
 
 // TODO(addaleax): Officially deprecate this and replace it with something
@@ -469,8 +468,8 @@
 // It receives the Environment* instance and the exit code as arguments.
 // This could e.g. call Stop(env); in order to terminate execution and stop
 // the event loop.
-// The default handler calls Stop(), disposes of the global V8 platform
-// instance, if one is being used, and calls exit().
+// The default handler disposes of the global V8 platform instance, if one is
+// being used, and calls exit().
 NODE_EXTERN void SetProcessExitHandler(
     Environment* env,
     std::function<void(Environment*, int)>&& handler);
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_http2.cc nodejs-12.22.4~dfsg/src/node_http2.cc
--- nodejs-12.21.0~dfsg/src/node_http2.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_http2.cc	2021-07-29 12:35:25.000000000 +0200
@@ -2150,6 +2150,23 @@
 void Http2Stream::SubmitRstStream(const uint32_t code) {
   CHECK(!this->IsDestroyed());
   code_ = code;
+
+  // If RST_STREAM frame is received and stream is not writable
+  // because it is busy reading data, don't try force purging it.
+  // Instead add the stream to pending stream list and process
+  // the pending data when it is safe to do so. This is to avoid
+  // double free error due to unwanted behavior of nghttp2.
+  // Ref:https://github.com/nodejs/node/issues/38964
+
+  // Add stream to the pending list if it is received with scope
+  // below in the stack. The pending list may not get processed
+  // if RST_STREAM received is not in scope and added to the list
+  // causing endpoint to hang.
+  if (session_->is_in_scope() && IsReading()) {
+      session_->AddPendingRstStream(id_);
+      return;
+  }
+
   // If possible, force a purge of any currently pending data here to make sure
   // it is sent before closing the stream. If it returns non-zero then we need
   // to wait until the current write finishes and try again to avoid nghttp2
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_http2.h nodejs-12.22.4~dfsg/src/node_http2.h
--- nodejs-12.21.0~dfsg/src/node_http2.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_http2.h	2021-07-29 12:35:25.000000000 +0200
@@ -764,6 +764,22 @@
     return (flags_ & SESSION_STATE_CLOSED) || session_ == nullptr;
   }
 
+
+  // The changes are backported and exposes APIs to check the
+  // status flag of `Http2Session`
+#define IS_FLAG(name, flag)                                                    \
+  bool is_##name() const { return flags_ & flag; }
+
+  IS_FLAG(in_scope, SESSION_STATE_HAS_SCOPE)
+  IS_FLAG(write_scheduled, SESSION_STATE_WRITE_SCHEDULED)
+  IS_FLAG(closing, SESSION_STATE_CLOSING)
+  IS_FLAG(sending, SESSION_STATE_SENDING)
+  IS_FLAG(write_in_progress, SESSION_STATE_WRITE_IN_PROGRESS)
+  IS_FLAG(reading_stopped, SESSION_STATE_READING_STOPPED)
+  IS_FLAG(receive_paused, SESSION_STATE_NGHTTP2_RECV_PAUSED)
+
+#undef IS_FLAG
+
   // Schedule a write if nghttp2 indicates it wants to write to the socket.
   void MaybeScheduleWrite();
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_http_parser_impl.h nodejs-12.22.4~dfsg/src/node_http_parser_impl.h
--- nodejs-12.21.0~dfsg/src/node_http_parser_impl.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_http_parser_impl.h	2021-07-29 12:35:25.000000000 +0200
@@ -26,6 +26,9 @@
 
 #include "node.h"
 #include "node_buffer.h"
+#ifndef NODE_EXPERIMENTAL_HTTP
+#include "node_process.h"
+#endif  /* NODE_EXPERIMENTAL_HTTP */
 #include "util.h"
 
 #include "async_wrap-inl.h"
@@ -1021,6 +1024,10 @@
 #ifndef NODE_EXPERIMENTAL_HTTP
   static uv_once_t init_once = UV_ONCE_INIT;
   uv_once(&init_once, InitMaxHttpHeaderSizeOnce);
+  ProcessEmitDeprecationWarning(
+    env,
+    "The legacy HTTP parser is deprecated.",
+    "DEP0131").IsNothing();
 #endif  /* NODE_EXPERIMENTAL_HTTP */
 }
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_platform.cc nodejs-12.22.4~dfsg/src/node_platform.cc
--- nodejs-12.21.0~dfsg/src/node_platform.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_platform.cc	2021-07-29 12:35:25.000000000 +0200
@@ -359,10 +359,10 @@
   Mutex::ScopedLock lock(per_isolate_mutex_);
   auto it = per_isolate_.find(isolate);
   if (it == per_isolate_.end()) {
-    CHECK(it->second);
     cb(data);
     return;
   }
+  CHECK(it->second);
   it->second->AddShutdownCallback(cb, data);
 }
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_version.h nodejs-12.22.4~dfsg/src/node_version.h
--- nodejs-12.21.0~dfsg/src/node_version.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_version.h	2021-07-29 12:35:25.000000000 +0200
@@ -23,8 +23,8 @@
 #define SRC_NODE_VERSION_H_
 
 #define NODE_MAJOR_VERSION 12
-#define NODE_MINOR_VERSION 21
-#define NODE_PATCH_VERSION 0
+#define NODE_MINOR_VERSION 22
+#define NODE_PATCH_VERSION 4
 
 #define NODE_VERSION_IS_LTS 1
 #define NODE_VERSION_LTS_CODENAME "Erbium"
@@ -93,6 +93,6 @@
 
 // The NAPI_VERSION provided by this version of the runtime. This is the version
 // which the Node binary being built supports.
-#define NAPI_VERSION  7
+#define NAPI_VERSION  8
 
 #endif  // SRC_NODE_VERSION_H_
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_worker.cc nodejs-12.22.4~dfsg/src/node_worker.cc
--- nodejs-12.21.0~dfsg/src/node_worker.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_worker.cc	2021-07-29 12:35:25.000000000 +0200
@@ -765,6 +765,39 @@
   args.GetReturnValue().Set(scheduled ? taker->object() : Local<Object>());
 }
 
+void Worker::LoopIdleTime(const FunctionCallbackInfo<Value>& args) {
+  Worker* w;
+  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
+
+  Mutex::ScopedLock lock(w->mutex_);
+  // Using w->is_stopped() here leads to a deadlock, and checking is_stopped()
+  // before locking the mutex is a race condition. So manually do the same
+  // check.
+  if (w->stopped_ || w->env_ == nullptr)
+    return args.GetReturnValue().Set(-1);
+
+  uint64_t idle_time = uv_metrics_idle_time(w->env_->event_loop());
+  args.GetReturnValue().Set(1.0 * idle_time / 1e6);
+}
+
+void Worker::LoopStartTime(const FunctionCallbackInfo<Value>& args) {
+  Worker* w;
+  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
+
+  Mutex::ScopedLock lock(w->mutex_);
+  // Using w->is_stopped() here leads to a deadlock, and checking is_stopped()
+  // before locking the mutex is a race condition. So manually do the same
+  // check.
+  if (w->stopped_ || w->env_ == nullptr)
+    return args.GetReturnValue().Set(-1);
+
+  double loop_start_time = w->env_->performance_state()->milestones[
+      node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START];
+  CHECK_GE(loop_start_time, 0);
+  args.GetReturnValue().Set(
+      (loop_start_time - node::performance::timeOrigin) / 1e6);
+}
+
 namespace {
 
 // Return the MessagePort that is global for this Environment and communicates
@@ -798,6 +831,8 @@
     env->SetProtoMethod(w, "unref", Worker::Unref);
     env->SetProtoMethod(w, "getResourceLimits", Worker::GetResourceLimits);
     env->SetProtoMethod(w, "takeHeapSnapshot", Worker::TakeHeapSnapshot);
+    env->SetProtoMethod(w, "loopIdleTime", Worker::LoopIdleTime);
+    env->SetProtoMethod(w, "loopStartTime", Worker::LoopStartTime);
 
     Local<String> workerString =
         FIXED_ONE_BYTE_STRING(env->isolate(), "Worker");
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_worker.h nodejs-12.22.4~dfsg/src/node_worker.h
--- nodejs-12.21.0~dfsg/src/node_worker.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_worker.h	2021-07-29 12:35:25.000000000 +0200
@@ -66,6 +66,8 @@
       const v8::FunctionCallbackInfo<v8::Value>& args);
   v8::Local<v8::Float64Array> GetResourceLimits(v8::Isolate* isolate) const;
   static void TakeHeapSnapshot(const v8::FunctionCallbackInfo<v8::Value>& args);
+  static void LoopIdleTime(const v8::FunctionCallbackInfo<v8::Value>& args);
+  static void LoopStartTime(const v8::FunctionCallbackInfo<v8::Value>& args);
 
  private:
   void CreateEnvMessagePort(Environment* env);

 

Reply to: