v8/test/mjsunit/compiler/abstract-equal-oddball.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

306 lines
7.1 KiB
JavaScript
Raw Normal View History

Reland "[turbofan] Improve equality on NumberOrOddball" This is a reland of 6204768bab20e8a31a96292a2e347008831b863f The original issue exposed the problem that NumberEqual performs implicit conversion of oddballs to numbers, which is incorrect for abstract equality comparison (i.e. 0 == null must not be true). This reland fixes this by applying the following steps: * Introduced a new kNumberOrBoolean value for CompareOperationFeedback, CompareOperationHint, TypeCheckKind and CheckedTaggedInputMode. * In CodeStubAssembler::Equal: Further distinguish between boolean and non-boolean oddballs and set feedback accoringly. * In JSTypedLowering: Construct [Speculative]NumberEqual operator with CompareOperationHint::kNumberOrBoolean, when this feedback is present. JSOperatorBuilder and operator cache are extended accordingly. * In SimplifiedLowering: Propagate a UseInfo with new TypeCheckKind::kNumberOrBoolean. * This leads to the generation of CheckedTaggedToFloat64 in RepresentationChanger with new CheckedTaggedInputMode::kNumberOrBoolean. * In EffectControlLinearizer: Handle this new mode. Accept and convert number and boolean and deopt for rest. Original change's description: > [turbofan] Improve equality on NumberOrOddball > > This CL cleans up CompareOperationFeedback by replacing it with a > composable set of flags. The interpreter is changed to collect > more specific feedback for abstract equality, especially if oddballs > are involved. > > TurboFan is changed to construct SpeculativeNumberEqual operator > instead of the generic JSEqual in many more cases. This change has > shown a local speedup of a factor of 3-10, because the specific > operator is way faster than calling into the generic builtin, but > it also enables additional optimizations, further improving > runtime performance. > > Bug: v8:5660 > Change-Id: I856752caa707e9a4f742c6e7a9c75552fb431d28 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2162854 > Reviewed-by: Mythri Alle <mythria@chromium.org> > Reviewed-by: Georg Neis <neis@chromium.org> > Commit-Queue: Nico Hartmann <nicohartmann@chromium.org> > Cr-Commit-Position: refs/heads/master@{#67645} TBR: tebbi@chromium.org Bug: v8:5660 Change-Id: I12e733149a1d2773cafb781a1d4b10aa1eb242a7 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2193713 Commit-Queue: Georg Neis <neis@chromium.org> Reviewed-by: Mythri Alle <mythria@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#68037}
2020-05-28 08:24:20 +00:00
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --opt --no-always-opt
// smi == boolean
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(2, true));
assertTrue(foo(1, true));
assertTrue(foo(0, false));
assertFalse(foo(2, false));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(2, true));
assertTrue(foo(1, true));
assertTrue(foo(0, false));
assertFalse(foo(2, false));
assertOptimized(foo);
assertFalse(foo(0, null));
assertUnoptimized(foo);
})();
// boolean == smi
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(true, 2));
assertTrue(foo(true, 1));
assertTrue(foo(false, 0));
assertFalse(foo(false, 2));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(true, 2));
assertTrue(foo(true, 1));
assertTrue(foo(false, 0));
assertFalse(foo(false, 2));
assertOptimized(foo);
assertFalse(foo(null, 0));
assertUnoptimized(foo);
})();
// smi == undefined
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(2, undefined));
assertFalse(foo(0, undefined));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(2, undefined));
assertFalse(foo(0, undefined));
assertOptimized(foo);
})();
// undefined == smi
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(undefined, 2));
assertFalse(foo(undefined, 0));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(undefined, 2));
assertFalse(foo(undefined, 0));
assertOptimized(foo);
})();
// smi == null
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(2, null));
assertFalse(foo(0, null));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(2, null));
assertFalse(foo(0, null));
assertOptimized(foo);
})();
// null == smi
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(null, 2));
assertFalse(foo(null, 0));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(null, 2));
assertFalse(foo(null, 0));
assertOptimized(foo);
})();
// smi == oddball
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(2, null));
assertFalse(foo(0, undefined));
assertFalse(foo(0, true));
assertTrue(foo(1, true));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(2, null));
assertFalse(foo(0, undefined));
assertFalse(foo(0, true));
assertTrue(foo(1, true));
assertOptimized(foo);
})();
// oddball == smi
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(null, 2));
assertFalse(foo(undefined, 0));
assertFalse(foo(true, 0));
assertTrue(foo(true, 1));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(null, 2));
assertFalse(foo(undefined, 0));
assertFalse(foo(true, 0));
assertTrue(foo(true, 1));
assertOptimized(foo);
})();
// number == boolean
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(-2.8, true));
assertTrue(foo(1, true));
assertTrue(foo(-0.0, false));
assertFalse(foo(2, false));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(-2.8, true));
assertTrue(foo(1, true));
assertTrue(foo(-0.0, false));
assertFalse(foo(2, false));
assertOptimized(foo);
assertFalse(foo(0, null));
assertUnoptimized(foo);
})();
// boolean == number
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(true, -2.8));
assertTrue(foo(true, 1));
assertTrue(foo(false, -0.0));
assertFalse(foo(false, 2));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(true, -2.8));
assertTrue(foo(true, 1));
assertTrue(foo(false, -0.0));
assertFalse(foo(false, 2));
assertOptimized(foo);
assertFalse(foo(null, 0));
assertUnoptimized(foo);
})();
// number == undefined
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(-2.8, undefined));
assertFalse(foo(-0.0, undefined));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(-2.8, undefined));
assertFalse(foo(-0.0, undefined));
assertOptimized(foo);
})();
// undefined == number
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(undefined, -2.8));
assertFalse(foo(undefined, -0.0));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(undefined, -2.8));
assertFalse(foo(undefined, -0.0));
assertOptimized(foo);
})();
// number == null
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(-2.8, null));
assertFalse(foo(-0.0, null));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(-2.8, null));
assertFalse(foo(-0.0, null));
assertOptimized(foo);
})();
// null == number
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(null, -2.8));
assertFalse(foo(null, -0.0));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(null, -2.8));
assertFalse(foo(null, -0.0));
assertOptimized(foo);
})();
// number == oddball
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(-2.8, null));
assertFalse(foo(-0.0, undefined));
assertFalse(foo(0, true));
assertTrue(foo(1.0, true));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(-2.8, null));
assertFalse(foo(-0.0, undefined));
assertFalse(foo(0, true));
assertTrue(foo(1.0, true));
assertOptimized(foo);
})();
// oddball == number
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertFalse(foo(null, -2.8));
assertFalse(foo(undefined, -0.0));
assertFalse(foo(true, 0));
assertTrue(foo(true, 1.0));
%OptimizeFunctionOnNextCall(foo);
assertFalse(foo(null, -2.8));
assertFalse(foo(undefined, -0.0));
assertFalse(foo(true, 0));
assertTrue(foo(true, 1.0));
assertOptimized(foo);
})();
// oddball == oddball
(function() {
function foo(a, b) { return a == b; }
%PrepareFunctionForOptimization(foo);
assertTrue(foo(null, null));
assertTrue(foo(undefined, undefined));
assertTrue(foo(false, false));
assertTrue(foo(true, true));
assertTrue(foo(undefined, null));
assertFalse(foo(undefined, false));
assertFalse(foo(null, false));
assertFalse(foo(true, undefined));
assertFalse(foo(true, null));
assertFalse(foo(true, false));
%OptimizeFunctionOnNextCall(foo);
assertTrue(foo(null, null));
assertOptimized(foo);
assertTrue(foo(undefined, undefined));
assertTrue(foo(false, false));
assertTrue(foo(true, true));
assertTrue(foo(undefined, null));
assertFalse(foo(undefined, false));
assertFalse(foo(null, false));
assertFalse(foo(true, undefined));
assertFalse(foo(true, null));
assertFalse(foo(true, false));
assertOptimized(foo);
})();