Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vm: improve performance of vm.runIn*() #10816

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions benchmark/vm/run-in-context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';

const common = require('../common.js');

const bench = common.createBenchmark(main, {
n: [1],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a single iteration?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I had to bump up n considerably to get the benchmarks to run long enough for me to be comfortable with the results, but then again I find myself having to do that a lot with many of the other existing benchmarks ...

breakOnSigint: [0, 1],
withSigintListener: [0, 1]
});

const vm = require('vm');

function main(conf) {
const n = +conf.n;
const options = conf.breakOnSigint ? {breakOnSigint: true} : {};
const withSigintListener = !!conf.withSigintListener;

process.removeAllListeners('SIGINT');
if (withSigintListener)
process.on('SIGINT', () => {});

var i = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, is there a reason you define i here and not in the for block where it's used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used crypto/get-ciphers.js as a template and that is what is done there. I have no strong opinions on it so I left it outside the block.


const contextifiedSandbox = vm.createContext();

common.v8ForceOptimization(vm.runInContext,
'0', contextifiedSandbox, options);
bench.start();
for (; i < n; i++)
vm.runInContext('0', contextifiedSandbox, options);
bench.end(n);
}
29 changes: 29 additions & 0 deletions benchmark/vm/run-in-this-context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

const common = require('../common.js');

const bench = common.createBenchmark(main, {
n: [1],
breakOnSigint: [0, 1],
withSigintListener: [0, 1]
});

const vm = require('vm');

function main(conf) {
const n = +conf.n;
const options = conf.breakOnSigint ? {breakOnSigint: true} : {};
const withSigintListener = !!conf.withSigintListener;

process.removeAllListeners('SIGINT');
if (withSigintListener)
process.on('SIGINT', () => {});

var i = 0;

common.v8ForceOptimization(vm.runInThisContext, '0', options);
bench.start();
for (; i < n; i++)
vm.runInThisContext('0', options);
bench.end(n);
}
26 changes: 11 additions & 15 deletions lib/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,17 @@ const realRunInThisContext = Script.prototype.runInThisContext;
const realRunInContext = Script.prototype.runInContext;

Script.prototype.runInThisContext = function(options) {
if (options && options.breakOnSigint) {
const realRunInThisContextScript = () => {
return realRunInThisContext.call(this, options);
};
return sigintHandlersWrap(realRunInThisContextScript);
if (options && options.breakOnSigint && process._events.SIGINT) {
return sigintHandlersWrap(realRunInThisContext, this, [options]);
} else {
return realRunInThisContext.call(this, options);
}
};

Script.prototype.runInContext = function(contextifiedSandbox, options) {
if (options && options.breakOnSigint) {
const realRunInContextScript = () => {
return realRunInContext.call(this, contextifiedSandbox, options);
};
return sigintHandlersWrap(realRunInContextScript);
if (options && options.breakOnSigint && process._events.SIGINT) {
return sigintHandlersWrap(realRunInContext, this,
[contextifiedSandbox, options]);
} else {
return realRunInContext.call(this, contextifiedSandbox, options);
}
Expand Down Expand Up @@ -83,19 +78,20 @@ exports.isContext = binding.isContext;

// Remove all SIGINT listeners and re-attach them after the wrapped function
// has executed, so that caught SIGINT are handled by the listeners again.
function sigintHandlersWrap(fn) {
function sigintHandlersWrap(fn, thisArg, argsArray) {
// Using the internal list here to make sure `.once()` wrappers are used,
// not the original ones.
let sigintListeners = process._events.SIGINT;
if (!Array.isArray(sigintListeners))
sigintListeners = sigintListeners ? [sigintListeners] : [];
else

if (Array.isArray(sigintListeners))
sigintListeners = sigintListeners.slice();
else
sigintListeners = [sigintListeners];

process.removeAllListeners('SIGINT');

try {
return fn();
return fn.apply(thisArg, argsArray);
} finally {
// Add using the public methods so that the `newListener` handler of
// process can re-attach the listeners.
Expand Down