From ae64ec46118a3cae02a25ff5f4104d09eb7143d3 Mon Sep 17 00:00:00 2001 From: Bradley Farias Date: Tue, 14 Jul 2020 16:31:29 -0500 Subject: [PATCH] repl: give repl entries unique names This is a workaround for the REPL for a problem when multiple of the entries have the same source text Fixes: https://github.com/nodejs/node/issues/1337 Refs: https://bugs.chromium.org/p/v8/issues/detail?id=10284 PR-URL: https://github.com/nodejs/node/pull/34372 Reviewed-By: Ruben Bridgewater Reviewed-By: Anto Aravinth --- lib/repl.js | 14 +++++++++---- test/parallel/test-repl-dynamic-import.js | 20 +++++++++++++++++++ .../parallel/test-repl-pretty-custom-stack.js | 12 +++++------ test/parallel/test-repl-pretty-stack.js | 14 ++++++------- 4 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 test/parallel/test-repl-dynamic-import.js diff --git a/lib/repl.js b/lib/repl.js index 26376a43c56d66..760a71d80ae93e 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -128,6 +128,12 @@ const { } = internalBinding('contextify'); const history = require('internal/repl/history'); +let nextREPLResourceNumber = 1; +// This prevents v8 code cache from getting confused and using a different +// cache from a resource of the same name +function getREPLResourceName() { + return `REPL${nextREPLResourceNumber++}`; +} // Lazy-loaded. let processTopLevelAwait; @@ -578,10 +584,10 @@ function REPLServer(prompt, if (e.name === 'SyntaxError') { // Remove stack trace. e.stack = e.stack - .replace(/^repl:\d+\r?\n/, '') + .replace(/^REPL\d+:\d+\r?\n/, '') .replace(/^\s+at\s.*\n?/gm, ''); } else if (self.replMode === module.exports.REPL_MODE_STRICT) { - e.stack = e.stack.replace(/(\s+at\s+repl:)(\d+)/, + e.stack = e.stack.replace(/(\s+at\s+REPL\d+:)(\d+)/, (_, pre, line) => pre + (line - 1)); } } @@ -791,7 +797,7 @@ function REPLServer(prompt, const evalCmd = self[kBufferedCommandSymbol] + cmd + '\n'; debug('eval %j', evalCmd); - self.eval(evalCmd, self.context, 'repl', finish); + self.eval(evalCmd, self.context, getREPLResourceName(), finish); function finish(e, ret) { debug('finish', e, ret); @@ -1277,7 +1283,7 @@ function complete(line, callback) { const memberGroups = []; const evalExpr = `try { ${expr} } catch {}`; - this.eval(evalExpr, this.context, 'repl', (e, obj) => { + this.eval(evalExpr, this.context, getREPLResourceName(), (e, obj) => { try { let p; if ((typeof obj === 'object' && obj !== null) || diff --git a/test/parallel/test-repl-dynamic-import.js b/test/parallel/test-repl-dynamic-import.js new file mode 100644 index 00000000000000..1f7a01575aa89b --- /dev/null +++ b/test/parallel/test-repl-dynamic-import.js @@ -0,0 +1,20 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const child_process = require('child_process'); +const child = child_process.spawn(process.execPath, [ + '--interactive', + '--expose-gc' +], { + stdio: 'pipe' +}); +child.stdin.write('\nimport("fs");\n_.then(gc);\n'); +// Wait for concurrent GC to finish +setTimeout(() => { + child.stdin.write('\nimport("fs");\n'); + child.stdin.write('\nprocess.exit(0);\n'); +}, common.platformTimeout(50)); +child.on('exit', (code, signal) => { + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); +}); diff --git a/test/parallel/test-repl-pretty-custom-stack.js b/test/parallel/test-repl-pretty-custom-stack.js index 8f633a4d4808c5..d04a394a2e249e 100644 --- a/test/parallel/test-repl-pretty-custom-stack.js +++ b/test/parallel/test-repl-pretty-custom-stack.js @@ -5,7 +5,7 @@ const fixtures = require('../common/fixtures'); const assert = require('assert'); const repl = require('repl'); -const stackRegExp = /repl:[0-9]+:[0-9]+/g; +const stackRegExp = /(REPL\d+):[0-9]+:[0-9]+/g; function run({ command, expected }) { let accum = ''; @@ -25,8 +25,8 @@ function run({ command, expected }) { r.write(`${command}\n`); assert.strictEqual( - accum.replace(stackRegExp, 'repl:*:*'), - expected.replace(stackRegExp, 'repl:*:*') + accum.replace(stackRegExp, '$1:*:*'), + expected.replace(stackRegExp, '$1:*:*') ); r.close(); } @@ -48,8 +48,8 @@ const tests = [ { // test .load for a file that throws command: `.load ${fixtures.path('repl-pretty-stack.js')}`, - expected: 'Uncaught Error: Whoops!--->\nrepl:*:*--->\nd (repl:*:*)' + - '--->\nc (repl:*:*)--->\nb (repl:*:*)--->\na (repl:*:*)\n' + expected: 'Uncaught Error: Whoops!--->\nREPL1:*:*--->\nd (REPL1:*:*)' + + '--->\nc (REPL1:*:*)--->\nb (REPL1:*:*)--->\na (REPL1:*:*)\n' }, { command: 'let x y;', @@ -67,7 +67,7 @@ const tests = [ // test anonymous IIFE { command: '(function() { throw new Error(\'Whoops!\'); })()', - expected: 'Uncaught Error: Whoops!--->\nrepl:*:*\n' + expected: 'Uncaught Error: Whoops!--->\nREPL5:*:*\n' } ]; diff --git a/test/parallel/test-repl-pretty-stack.js b/test/parallel/test-repl-pretty-stack.js index 456e866b7b20f9..8ab3fef2aaa033 100644 --- a/test/parallel/test-repl-pretty-stack.js +++ b/test/parallel/test-repl-pretty-stack.js @@ -5,7 +5,7 @@ const fixtures = require('../common/fixtures'); const assert = require('assert'); const repl = require('repl'); -const stackRegExp = /(at .*repl:)[0-9]+:[0-9]+/g; +const stackRegExp = /(at .*REPL\d+:)[0-9]+:[0-9]+/g; function run({ command, expected, ...extraREPLOptions }, i) { let accum = ''; @@ -37,9 +37,9 @@ const tests = [ { // Test .load for a file that throws. command: `.load ${fixtures.path('repl-pretty-stack.js')}`, - expected: 'Uncaught Error: Whoops!\n at repl:*:*\n' + - ' at d (repl:*:*)\n at c (repl:*:*)\n' + - ' at b (repl:*:*)\n at a (repl:*:*)\n' + expected: 'Uncaught Error: Whoops!\n at REPL1:*:*\n' + + ' at d (REPL1:*:*)\n at c (REPL1:*:*)\n' + + ' at b (REPL1:*:*)\n at a (REPL1:*:*)\n' }, { command: 'let x y;', @@ -53,12 +53,12 @@ const tests = [ { command: '(() => { const err = Error(\'Whoops!\'); ' + 'err.foo = \'bar\'; throw err; })()', - expected: "Uncaught Error: Whoops!\n at repl:*:* {\n foo: 'bar'\n}\n", + expected: "Uncaught Error: Whoops!\n at REPL4:*:* {\n foo: 'bar'\n}\n", }, { command: '(() => { const err = Error(\'Whoops!\'); ' + 'err.foo = \'bar\'; throw err; })()', - expected: 'Uncaught Error: Whoops!\n at repl:*:* {\n foo: ' + + expected: 'Uncaught Error: Whoops!\n at REPL5:*:* {\n foo: ' + "\u001b[32m'bar'\u001b[39m\n}\n", useColors: true }, @@ -69,7 +69,7 @@ const tests = [ // Test anonymous IIFE. { command: '(function() { throw new Error(\'Whoops!\'); })()', - expected: 'Uncaught Error: Whoops!\n at repl:*:*\n' + expected: 'Uncaught Error: Whoops!\n at REPL7:*:*\n' } ];