I'm writing a constant-time string comparison function (for node.js) and would like to disable V8's optimizing compiler for this single function; using command-line flags are out of the question.
I know that using a with{}
(or try/catch) block will disable the optimizing compiler now, but I'm afraid this "feature" (bug) will be fixed in future versions.
Is there an immutable (and documented) way disabling V8's optimizing compiler?
Example function:
function constantTimeStringCompare( a, b ) {
// By adding a `with` block here, we disable v8's optimizing compiler.
// Using Object.create(null) ensures we don't have any object prototype properties getting in our way.our way.
with ( Object.create( null ) ){
var valid = true,
length = Math.max( a.length, b.length );
while ( length-- ) {
valid &= a.charCodeAt( length ) === b.charCodeAt( length );
}
// returns true if valid == 1, false if valid == 0
return !!valid;
}
}
And a perf test just for fun.
I'm writing a constant-time string comparison function (for node.js) and would like to disable V8's optimizing compiler for this single function; using command-line flags are out of the question.
I know that using a with{}
(or try/catch) block will disable the optimizing compiler now, but I'm afraid this "feature" (bug) will be fixed in future versions.
Is there an immutable (and documented) way disabling V8's optimizing compiler?
Example function:
function constantTimeStringCompare( a, b ) {
// By adding a `with` block here, we disable v8's optimizing compiler.
// Using Object.create(null) ensures we don't have any object prototype properties getting in our way.our way.
with ( Object.create( null ) ){
var valid = true,
length = Math.max( a.length, b.length );
while ( length-- ) {
valid &= a.charCodeAt( length ) === b.charCodeAt( length );
}
// returns true if valid == 1, false if valid == 0
return !!valid;
}
}
And a perf test just for fun.
Share Improve this question edited Aug 27, 2013 at 22:39 David Murdoch asked Aug 27, 2013 at 22:17 David MurdochDavid Murdoch 89.3k39 gold badges152 silver badges192 bronze badges 24 | Show 19 more comments2 Answers
Reset to default 14If you want solid way to do it, you need to run node with --allow-natives-syntax
flag and call this:
%NeverOptimizeFunction(constantTimeStringCompare);
Note that you should call this before you have called constantTimeStringCompare
, if the function is already optimized then this violates an assertion.
Otherwise with
statement is your best bet as making it optimizable would be absolute lunacy whereas supporting try/catch
would be reasonable. You don't need it to affect your code though, this will be sufficient:
function constantTimeStringCompare( a, b ) {
with({});
var valid = true,
length = Math.max( a.length, b.length );
while ( length-- ) {
valid &= a.charCodeAt( length ) === b.charCodeAt( length );
}
// returns true if valid == 1, false if valid == 0
return !!valid;
}
Merely mentioning with
statement corrupts the entire containing function - the optimizations are done at function-level granularity, not per statement.
To actually check is function optimized by particular Node.js version you can refer to Optimization Killers wiki of bluebird.
I've checked 3 solutions on Node 7.2:
with({})
- Function is optimized by TurboFantry {} catch(e) {}
- Function is optimized by TurboFaneval('');
- Function is not optimized
So to guarantee disable V8 optimization you should add eval('')
to function body.
n
. In your case, this operation would be the character comparison. Since this would be the length of the longer string, it doesn't matter thata
is constant, since for all stringsb
longer thana
the value of this function would beb.length
. (Since there is an infinite amount of strings longer thana
, and a finite number of strings shorter thana
, we can ignore the shorter ones in our analysis.) – millimoose Commented Aug 28, 2013 at 17:00.length
andmax()
– millimoose Commented Aug 28, 2013 at 17:09a
is a prefix ofb
. (To make this a constant-time comparison, you'd in fact have to implement the "optimisations" I've mentioned.) Also counting all operations into counter makes no sense. You usually count the instances of one or sometimes several "representative" operations, separately. Reads or writes to input elements (in your case characters) are common, as are comparisons between input elements. You can safely ignore constant overhead. – millimoose Commented Aug 28, 2013 at 20:58