1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <functional>
6 
7 #include "src/base/overflowing-math.h"
8 #include "src/compiler/js-operator.h"
9 #include "src/compiler/node-properties.h"
10 #include "src/compiler/operator-properties.h"
11 #include "src/compiler/simplified-operator.h"
12 #include "src/objects/objects-inl.h"
13 #include "test/common/types-fuzz.h"
14 #include "test/unittests/compiler/graph-unittest.h"
15 
16 namespace v8 {
17 namespace internal {
18 namespace compiler {
19 
20 // TODO(titzer): generate a large set of deterministic inputs for these tests.
21 class TyperTest : public TypedGraphTest {
22  public:
TyperTest()23   TyperTest()
24       : TypedGraphTest(3),
25         broker_(isolate(), zone()),
26         operation_typer_(&broker_, zone()),
27         types_(zone(), isolate(), random_number_generator()),
28         javascript_(zone()),
29         simplified_(zone()) {
30     context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start());
31     rng_ = random_number_generator();
32 
33     integers.push_back(0);
34     integers.push_back(0);
35     integers.push_back(-1);
36     integers.push_back(+1);
37     integers.push_back(-V8_INFINITY);
38     integers.push_back(+V8_INFINITY);
39     for (int i = 0; i < 5; ++i) {
40       double x = rng_->NextInt();
41       integers.push_back(x);
42       x *= rng_->NextInt();
43       if (!IsMinusZero(x)) integers.push_back(x);
44     }
45 
46     int32s.push_back(0);
47     int32s.push_back(0);
48     int32s.push_back(-1);
49     int32s.push_back(+1);
50     int32s.push_back(kMinInt);
51     int32s.push_back(kMaxInt);
52     for (int i = 0; i < 10; ++i) {
53       int32s.push_back(rng_->NextInt());
54     }
55   }
56 
57   const int kRepetitions = 50;
58 
59   JSHeapBroker broker_;
60   OperationTyper operation_typer_;
61   Types types_;
62   JSOperatorBuilder javascript_;
63   SimplifiedOperatorBuilder simplified_;
64   Node* context_node_;
65   v8::base::RandomNumberGenerator* rng_;
66   std::vector<double> integers;
67   std::vector<double> int32s;
68 
TypeUnaryOp(const Operator * op,Type type0)69   Type TypeUnaryOp(const Operator* op, Type type0) {
70     Node* p0 = Parameter(0);
71     NodeProperties::SetType(p0, type0);
72     std::vector<Node*> inputs;
73     inputs.push_back(p0);
74     if (OperatorProperties::HasContextInput(op)) {
75       inputs.push_back(context_node_);
76     }
77     for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op); i++) {
78       inputs.push_back(EmptyFrameState());
79     }
80     for (int i = 0; i < op->EffectInputCount(); i++) {
81       inputs.push_back(graph()->start());
82     }
83     for (int i = 0; i < op->ControlInputCount(); i++) {
84       inputs.push_back(graph()->start());
85     }
86     Node* n = graph()->NewNode(op, static_cast<int>(inputs.size()),
87                                &(inputs.front()));
88     return NodeProperties::GetType(n);
89   }
90 
UndefinedConstant()91   Node* UndefinedConstant() {
92     Handle<HeapObject> value = isolate()->factory()->undefined_value();
93     return graph()->NewNode(common()->HeapConstant(value));
94   }
95 
TypeBinaryOp(const Operator * op,Type lhs,Type rhs)96   Type TypeBinaryOp(const Operator* op, Type lhs, Type rhs) {
97     Node* p0 = Parameter(0);
98     Node* p1 = Parameter(1);
99     NodeProperties::SetType(p0, lhs);
100     NodeProperties::SetType(p1, rhs);
101     std::vector<Node*> inputs;
102     inputs.push_back(p0);
103     inputs.push_back(p1);
104     if (JSOperator::IsBinaryWithFeedback(op->opcode())) {
105       inputs.push_back(UndefinedConstant());  // Feedback vector.
106     }
107     if (OperatorProperties::HasContextInput(op)) {
108       inputs.push_back(context_node_);
109     }
110     for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op); i++) {
111       inputs.push_back(EmptyFrameState());
112     }
113     for (int i = 0; i < op->EffectInputCount(); i++) {
114       inputs.push_back(graph()->start());
115     }
116     for (int i = 0; i < op->ControlInputCount(); i++) {
117       inputs.push_back(graph()->start());
118     }
119     Node* n = graph()->NewNode(op, static_cast<int>(inputs.size()),
120                                &(inputs.front()));
121     return NodeProperties::GetType(n);
122   }
123 
RandomRange(bool int32=false)124   Type RandomRange(bool int32 = false) {
125     std::vector<double>& numbers = int32 ? int32s : integers;
126     double i = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
127     double j = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
128     return NewRange(i, j);
129   }
130 
NewRange(double i,double j)131   Type NewRange(double i, double j) {
132     if (i > j) std::swap(i, j);
133     return Type::Range(i, j, zone());
134   }
135 
RandomInt(double min,double max)136   double RandomInt(double min, double max) {
137     switch (rng_->NextInt(4)) {
138       case 0:
139         return min;
140       case 1:
141         return max;
142       default:
143         break;
144     }
145     if (min == +V8_INFINITY) return +V8_INFINITY;
146     if (max == -V8_INFINITY) return -V8_INFINITY;
147     if (min == -V8_INFINITY && max == +V8_INFINITY) {
148       return rng_->NextInt() * static_cast<double>(rng_->NextInt());
149     }
150     double result = nearbyint(min + (max - min) * rng_->NextDouble());
151     if (IsMinusZero(result)) return 0;
152     if (std::isnan(result)) return rng_->NextInt(2) ? min : max;
153     DCHECK(min <= result && result <= max);
154     return result;
155   }
156 
RandomInt(const RangeType * range)157   double RandomInt(const RangeType* range) {
158     return RandomInt(range->Min(), range->Max());
159   }
160 
RandomSubtype(Type type)161   Type RandomSubtype(Type type) {
162     Type subtype;
163     do {
164       subtype = types_.Fuzz();
165     } while (!subtype.Is(type));
166     return subtype;
167   }
168 
169   // Careful, this function runs O(max_width^5) trials.
170   template <class BinaryFunction>
TestBinaryArithOpCloseToZero(const Operator * op,BinaryFunction opfun,int max_width)171   void TestBinaryArithOpCloseToZero(const Operator* op, BinaryFunction opfun,
172                                     int max_width) {
173     const int min_min = -2 - max_width / 2;
174     const int max_min = 2 + max_width / 2;
175     for (int width = 0; width < max_width; width++) {
176       for (int lmin = min_min; lmin <= max_min; lmin++) {
177         for (int rmin = min_min; rmin <= max_min; rmin++) {
178           Type r1 = NewRange(lmin, lmin + width);
179           Type r2 = NewRange(rmin, rmin + width);
180           Type expected_type = TypeBinaryOp(op, r1, r2);
181 
182           for (int x1 = lmin; x1 < lmin + width; x1++) {
183             for (int x2 = rmin; x2 < rmin + width; x2++) {
184               double result_value = opfun(x1, x2);
185               Type result_type = Type::Constant(
186                   &broker_, isolate()->factory()->NewNumber(result_value),
187                   zone());
188               EXPECT_TRUE(result_type.Is(expected_type));
189             }
190           }
191         }
192       }
193     }
194   }
195 
196   template <class BinaryFunction>
TestBinaryArithOp(const Operator * op,BinaryFunction opfun)197   void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) {
198     TestBinaryArithOpCloseToZero(op, opfun, 8);
199     for (int i = 0; i < 100; ++i) {
200       Type r1 = RandomRange();
201       Type r2 = RandomRange();
202       Type expected_type = TypeBinaryOp(op, r1, r2);
203       for (int j = 0; j < 10; j++) {
204         double x1 = RandomInt(r1.AsRange());
205         double x2 = RandomInt(r2.AsRange());
206         double result_value = opfun(x1, x2);
207         Type result_type = Type::Constant(
208             &broker_, isolate()->factory()->NewNumber(result_value), zone());
209         EXPECT_TRUE(result_type.Is(expected_type));
210       }
211     }
212     // Test extreme cases.
213     double x1 = +1e-308;
214     double x2 = -1e-308;
215     Type r1 =
216         Type::Constant(&broker_, isolate()->factory()->NewNumber(x1), zone());
217     Type r2 =
218         Type::Constant(&broker_, isolate()->factory()->NewNumber(x2), zone());
219     Type expected_type = TypeBinaryOp(op, r1, r2);
220     double result_value = opfun(x1, x2);
221     Type result_type = Type::Constant(
222         &broker_, isolate()->factory()->NewNumber(result_value), zone());
223     EXPECT_TRUE(result_type.Is(expected_type));
224   }
225 
226   template <class BinaryFunction>
TestBinaryCompareOp(const Operator * op,BinaryFunction opfun)227   void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) {
228     for (int i = 0; i < 100; ++i) {
229       Type r1 = RandomRange();
230       Type r2 = RandomRange();
231       Type expected_type = TypeBinaryOp(op, r1, r2);
232       for (int j = 0; j < 10; j++) {
233         double x1 = RandomInt(r1.AsRange());
234         double x2 = RandomInt(r2.AsRange());
235         bool result_value = opfun(x1, x2);
236         Type result_type =
237             Type::Constant(&broker_,
238                            result_value ? isolate()->factory()->true_value()
239                                         : isolate()->factory()->false_value(),
240                            zone());
241         EXPECT_TRUE(result_type.Is(expected_type));
242       }
243     }
244   }
245 
246   template <class BinaryFunction>
TestBinaryBitOp(const Operator * op,BinaryFunction opfun)247   void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) {
248     for (int i = 0; i < 100; ++i) {
249       Type r1 = RandomRange(true);
250       Type r2 = RandomRange(true);
251       Type expected_type = TypeBinaryOp(op, r1, r2);
252       for (int j = 0; j < 10; j++) {
253         int32_t x1 = static_cast<int32_t>(RandomInt(r1.AsRange()));
254         int32_t x2 = static_cast<int32_t>(RandomInt(r2.AsRange()));
255         double result_value = opfun(x1, x2);
256         Type result_type = Type::Constant(
257             &broker_, isolate()->factory()->NewNumber(result_value), zone());
258         EXPECT_TRUE(result_type.Is(expected_type));
259       }
260     }
261   }
262 
263   using UnaryTyper = std::function<Type(Type)>;
264   using BinaryTyper = std::function<Type(Type, Type)>;
265 
TestUnaryMonotonicity(UnaryTyper typer,Type upper1=Type::Any ())266   void TestUnaryMonotonicity(UnaryTyper typer, Type upper1 = Type::Any()) {
267     Type type1 = Type::Intersect(types_.Fuzz(), upper1, zone());
268     DCHECK(type1.Is(upper1));
269     Type type = typer(type1);
270 
271     Type subtype1 = RandomSubtype(type1);
272     Type subtype = typer(subtype1);
273 
274     EXPECT_TRUE(subtype.Is(type));
275   }
276 
TestBinaryMonotonicity(BinaryTyper typer,Type upper1=Type::Any (),Type upper2=Type::Any ())277   void TestBinaryMonotonicity(BinaryTyper typer, Type upper1 = Type::Any(),
278                               Type upper2 = Type::Any()) {
279     Type type1 = Type::Intersect(types_.Fuzz(), upper1, zone());
280     DCHECK(type1.Is(upper1));
281     Type type2 = Type::Intersect(types_.Fuzz(), upper2, zone());
282     DCHECK(type2.Is(upper2));
283     Type type = typer(type1, type2);
284 
285     Type subtype1 = RandomSubtype(type1);
286     Type subtype2 = RandomSubtype(type2);
287     Type subtype = typer(subtype1, subtype2);
288 
289     EXPECT_TRUE(subtype.Is(type));
290   }
291 
TestUnaryMonotonicity(const Operator * op,Type upper1=Type::Any ())292   void TestUnaryMonotonicity(const Operator* op, Type upper1 = Type::Any()) {
293     UnaryTyper typer = [&](Type type1) { return TypeUnaryOp(op, type1); };
294     for (int i = 0; i < kRepetitions; ++i) {
295       TestUnaryMonotonicity(typer, upper1);
296     }
297   }
298 
TestBinaryMonotonicity(const Operator * op,Type upper1=Type::Any (),Type upper2=Type::Any ())299   void TestBinaryMonotonicity(const Operator* op, Type upper1 = Type::Any(),
300                               Type upper2 = Type::Any()) {
301     BinaryTyper typer = [&](Type type1, Type type2) {
302       return TypeBinaryOp(op, type1, type2);
303     };
304     for (int i = 0; i < kRepetitions; ++i) {
305       TestBinaryMonotonicity(typer, upper1, upper2);
306     }
307   }
308 };
309 
310 
311 namespace {
312 
shift_left(int32_t x,int32_t y)313 int32_t shift_left(int32_t x, int32_t y) {
314   return static_cast<uint32_t>(x) << (y & 0x1F);
315 }
shift_right(int32_t x,int32_t y)316 int32_t shift_right(int32_t x, int32_t y) { return x >> (y & 0x1F); }
bit_or(int32_t x,int32_t y)317 int32_t bit_or(int32_t x, int32_t y) { return x | y; }
bit_and(int32_t x,int32_t y)318 int32_t bit_and(int32_t x, int32_t y) { return x & y; }
bit_xor(int32_t x,int32_t y)319 int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; }
divide_double_double(double x,double y)320 double divide_double_double(double x, double y) { return base::Divide(x, y); }
modulo_double_double(double x,double y)321 double modulo_double_double(double x, double y) { return Modulo(x, y); }
322 
FeedbackSourceWithOneBinarySlot(TyperTest * R)323 FeedbackSource FeedbackSourceWithOneBinarySlot(TyperTest* R) {
324   return FeedbackSource{
325       FeedbackVector::NewWithOneBinarySlotForTesting(R->zone(), R->isolate()),
326       FeedbackSlot{0}};
327 }
328 
FeedbackSourceWithOneCompareSlot(TyperTest * R)329 FeedbackSource FeedbackSourceWithOneCompareSlot(TyperTest* R) {
330   return FeedbackSource{
331       FeedbackVector::NewWithOneCompareSlotForTesting(R->zone(), R->isolate()),
332       FeedbackSlot{0}};
333 }
334 
335 }  // namespace
336 
337 
338 //------------------------------------------------------------------------------
339 // Soundness
340 //   For simplicity, we currently only test soundness on expression operators
341 //   that have a direct equivalent in C++.  Also, testing is currently limited
342 //   to ranges as input types.
343 
TEST_F(TyperTest,TypeJSAdd)344 TEST_F(TyperTest, TypeJSAdd) {
345   TestBinaryArithOp(javascript_.Add(FeedbackSourceWithOneBinarySlot(this)),
346                     std::plus<double>());
347 }
348 
TEST_F(TyperTest,TypeJSSubtract)349 TEST_F(TyperTest, TypeJSSubtract) {
350   TestBinaryArithOp(javascript_.Subtract(FeedbackSourceWithOneBinarySlot(this)),
351                     std::minus<double>());
352 }
353 
TEST_F(TyperTest,TypeJSMultiply)354 TEST_F(TyperTest, TypeJSMultiply) {
355   TestBinaryArithOp(javascript_.Multiply(FeedbackSourceWithOneBinarySlot(this)),
356                     std::multiplies<double>());
357 }
358 
TEST_F(TyperTest,TypeJSDivide)359 TEST_F(TyperTest, TypeJSDivide) {
360   TestBinaryArithOp(javascript_.Divide(FeedbackSourceWithOneBinarySlot(this)),
361                     divide_double_double);
362 }
363 
TEST_F(TyperTest,TypeJSModulus)364 TEST_F(TyperTest, TypeJSModulus) {
365   TestBinaryArithOp(javascript_.Modulus(FeedbackSourceWithOneBinarySlot(this)),
366                     modulo_double_double);
367 }
368 
TEST_F(TyperTest,TypeJSBitwiseOr)369 TEST_F(TyperTest, TypeJSBitwiseOr) {
370   TestBinaryBitOp(javascript_.BitwiseOr(FeedbackSourceWithOneBinarySlot(this)),
371                   bit_or);
372 }
373 
TEST_F(TyperTest,TypeJSBitwiseAnd)374 TEST_F(TyperTest, TypeJSBitwiseAnd) {
375   TestBinaryBitOp(javascript_.BitwiseAnd(FeedbackSourceWithOneBinarySlot(this)),
376                   bit_and);
377 }
378 
TEST_F(TyperTest,TypeJSBitwiseXor)379 TEST_F(TyperTest, TypeJSBitwiseXor) {
380   TestBinaryBitOp(javascript_.BitwiseXor(FeedbackSourceWithOneBinarySlot(this)),
381                   bit_xor);
382 }
383 
TEST_F(TyperTest,TypeJSShiftLeft)384 TEST_F(TyperTest, TypeJSShiftLeft) {
385   TestBinaryBitOp(javascript_.ShiftLeft(FeedbackSourceWithOneBinarySlot(this)),
386                   shift_left);
387 }
388 
TEST_F(TyperTest,TypeJSShiftRight)389 TEST_F(TyperTest, TypeJSShiftRight) {
390   TestBinaryBitOp(javascript_.ShiftRight(FeedbackSourceWithOneBinarySlot(this)),
391                   shift_right);
392 }
393 
TEST_F(TyperTest,TypeJSLessThan)394 TEST_F(TyperTest, TypeJSLessThan) {
395   TestBinaryCompareOp(
396       javascript_.LessThan(FeedbackSourceWithOneCompareSlot(this)),
397       std::less<double>());
398 }
399 
TEST_F(TyperTest,TypeNumberLessThan)400 TEST_F(TyperTest, TypeNumberLessThan) {
401   TestBinaryCompareOp(simplified_.NumberLessThan(), std::less<double>());
402 }
403 
TEST_F(TyperTest,TypeSpeculativeNumberLessThan)404 TEST_F(TyperTest, TypeSpeculativeNumberLessThan) {
405   TestBinaryCompareOp(simplified_.SpeculativeNumberLessThan(
406                           NumberOperationHint::kNumberOrOddball),
407                       std::less<double>());
408 }
409 
TEST_F(TyperTest,TypeJSLessThanOrEqual)410 TEST_F(TyperTest, TypeJSLessThanOrEqual) {
411   TestBinaryCompareOp(
412       javascript_.LessThanOrEqual(FeedbackSourceWithOneCompareSlot(this)),
413       std::less_equal<double>());
414 }
415 
TEST_F(TyperTest,TypeNumberLessThanOrEqual)416 TEST_F(TyperTest, TypeNumberLessThanOrEqual) {
417   TestBinaryCompareOp(simplified_.NumberLessThanOrEqual(),
418                       std::less_equal<double>());
419 }
420 
TEST_F(TyperTest,TypeSpeculativeNumberLessThanOrEqual)421 TEST_F(TyperTest, TypeSpeculativeNumberLessThanOrEqual) {
422   TestBinaryCompareOp(simplified_.SpeculativeNumberLessThanOrEqual(
423                           NumberOperationHint::kNumberOrOddball),
424                       std::less_equal<double>());
425 }
426 
TEST_F(TyperTest,TypeJSGreaterThan)427 TEST_F(TyperTest, TypeJSGreaterThan) {
428   TestBinaryCompareOp(
429       javascript_.GreaterThan(FeedbackSourceWithOneCompareSlot(this)),
430       std::greater<double>());
431 }
432 
433 
TEST_F(TyperTest,TypeJSGreaterThanOrEqual)434 TEST_F(TyperTest, TypeJSGreaterThanOrEqual) {
435   TestBinaryCompareOp(
436       javascript_.GreaterThanOrEqual(FeedbackSourceWithOneCompareSlot(this)),
437       std::greater_equal<double>());
438 }
439 
TEST_F(TyperTest,TypeJSEqual)440 TEST_F(TyperTest, TypeJSEqual) {
441   TestBinaryCompareOp(javascript_.Equal(FeedbackSourceWithOneCompareSlot(this)),
442                       std::equal_to<double>());
443 }
444 
TEST_F(TyperTest,TypeNumberEqual)445 TEST_F(TyperTest, TypeNumberEqual) {
446   TestBinaryCompareOp(simplified_.NumberEqual(), std::equal_to<double>());
447 }
448 
TEST_F(TyperTest,TypeSpeculativeNumberEqual)449 TEST_F(TyperTest, TypeSpeculativeNumberEqual) {
450   TestBinaryCompareOp(
451       simplified_.SpeculativeNumberEqual(NumberOperationHint::kNumberOrOddball),
452       std::equal_to<double>());
453 }
454 
455 // For numbers there's no difference between strict and non-strict equality.
TEST_F(TyperTest,TypeJSStrictEqual)456 TEST_F(TyperTest, TypeJSStrictEqual) {
457   TestBinaryCompareOp(
458       javascript_.StrictEqual(FeedbackSourceWithOneCompareSlot(this)),
459       std::equal_to<double>());
460 }
461 
462 //------------------------------------------------------------------------------
463 // Typer Monotonicity
464 
465 // JS UNOPs without hint
466 #define TEST_MONOTONICITY(name)                \
467   TEST_F(TyperTest, Monotonicity_##name) {     \
468     TestUnaryMonotonicity(javascript_.name()); \
469   }
470 TEST_MONOTONICITY(ToLength)
TEST_MONOTONICITY(ToName)471 TEST_MONOTONICITY(ToName)
472 TEST_MONOTONICITY(ToNumber)
473 TEST_MONOTONICITY(ToObject)
474 TEST_MONOTONICITY(ToString)
475 #undef TEST_MONOTONICITY
476 
477 // JS compare ops.
478 #define TEST_MONOTONICITY(name)                                    \
479   TEST_F(TyperTest, Monotonicity_##name) {                         \
480     TestBinaryMonotonicity(                                        \
481         javascript_.name(FeedbackSourceWithOneCompareSlot(this))); \
482   }
483 TEST_MONOTONICITY(Equal)
484 TEST_MONOTONICITY(StrictEqual)
485 TEST_MONOTONICITY(LessThan)
486 TEST_MONOTONICITY(GreaterThan)
487 TEST_MONOTONICITY(LessThanOrEqual)
488 TEST_MONOTONICITY(GreaterThanOrEqual)
489 #undef TEST_MONOTONICITY
490 
491 // JS binary ops.
492 #define TEST_MONOTONICITY(name)                                   \
493   TEST_F(TyperTest, Monotonicity_##name) {                        \
494     TestBinaryMonotonicity(                                       \
495         javascript_.name(FeedbackSourceWithOneBinarySlot(this))); \
496   }
497 TEST_MONOTONICITY(Add)
498 TEST_MONOTONICITY(BitwiseAnd)
499 TEST_MONOTONICITY(BitwiseOr)
500 TEST_MONOTONICITY(BitwiseXor)
501 TEST_MONOTONICITY(Divide)
502 TEST_MONOTONICITY(Modulus)
503 TEST_MONOTONICITY(Multiply)
504 TEST_MONOTONICITY(ShiftLeft)
505 TEST_MONOTONICITY(ShiftRight)
506 TEST_MONOTONICITY(ShiftRightLogical)
507 TEST_MONOTONICITY(Subtract)
508 #undef TEST_MONOTONICITY
509 
510 TEST_F(TyperTest, Monotonicity_InstanceOf) {
511   TestBinaryMonotonicity(javascript_.InstanceOf(FeedbackSource()));
512 }
513 
TEST_F(TyperTest,Monotonicity_OrdinaryHasInstance)514 TEST_F(TyperTest, Monotonicity_OrdinaryHasInstance) {
515   TestBinaryMonotonicity(javascript_.OrdinaryHasInstance());
516 }
517 
518 // SIMPLIFIED UNOPs without hint
519 #define TEST_MONOTONICITY(name)                \
520   TEST_F(TyperTest, Monotonicity_##name) {     \
521     TestUnaryMonotonicity(simplified_.name()); \
522   }
523 TEST_MONOTONICITY(ObjectIsDetectableCallable)
TEST_MONOTONICITY(ObjectIsNaN)524 TEST_MONOTONICITY(ObjectIsNaN)
525 TEST_MONOTONICITY(ObjectIsNonCallable)
526 TEST_MONOTONICITY(ObjectIsNumber)
527 TEST_MONOTONICITY(ObjectIsReceiver)
528 TEST_MONOTONICITY(ObjectIsSmi)
529 TEST_MONOTONICITY(ObjectIsString)
530 TEST_MONOTONICITY(ObjectIsSymbol)
531 TEST_MONOTONICITY(ObjectIsUndetectable)
532 TEST_MONOTONICITY(TypeOf)
533 TEST_MONOTONICITY(ToBoolean)
534 #undef TEST_MONOTONICITY
535 
536 // SIMPLIFIED BINOPs without hint, with Number input restriction
537 #define TEST_MONOTONICITY(name)                                \
538   TEST_F(TyperTest, Monotonicity_##name) {                     \
539     TestBinaryMonotonicity(simplified_.name(), Type::Number(), \
540                            Type::Number());                    \
541   }
542 SIMPLIFIED_NUMBER_BINOP_LIST(TEST_MONOTONICITY)
543 #undef TEST_MONOTONICITY
544 
545 // SIMPLIFIED BINOPs without hint, without input restriction
546 #define TEST_MONOTONICITY(name)                 \
547   TEST_F(TyperTest, Monotonicity_##name) {      \
548     TestBinaryMonotonicity(simplified_.name()); \
549   }
550 TEST_MONOTONICITY(NumberLessThan)
551 TEST_MONOTONICITY(NumberLessThanOrEqual)
552 TEST_MONOTONICITY(NumberEqual)
553 TEST_MONOTONICITY(ReferenceEqual)
554 TEST_MONOTONICITY(StringEqual)
555 TEST_MONOTONICITY(StringLessThan)
556 TEST_MONOTONICITY(StringLessThanOrEqual)
557 #undef TEST_MONOTONICITY
558 
559 // SIMPLIFIED BINOPs with NumberOperationHint, without input restriction
560 #define TEST_MONOTONICITY(name)                                             \
561   TEST_F(TyperTest, Monotonicity_##name) {                                  \
562     TestBinaryMonotonicity(simplified_.name(NumberOperationHint::kNumber)); \
563   }
564 TEST_MONOTONICITY(SpeculativeNumberEqual)
565 TEST_MONOTONICITY(SpeculativeNumberLessThan)
566 TEST_MONOTONICITY(SpeculativeNumberLessThanOrEqual)
567 #undef TEST_MONOTONICITY
568 
569 // SIMPLIFIED BINOPs with NumberOperationHint, without input restriction
570 #define TEST_MONOTONICITY(name)                                             \
571   TEST_F(TyperTest, Monotonicity_##name) {                                  \
572     TestBinaryMonotonicity(simplified_.name(NumberOperationHint::kNumber)); \
573   }
574 SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(TEST_MONOTONICITY)
575 #undef TEST_MONOTONICITY
576 
577 //------------------------------------------------------------------------------
578 // OperationTyper Monotonicity
579 
580 // SIMPLIFIED UNOPs with Number input restriction
581 #define TEST_MONOTONICITY(name)                      \
582   TEST_F(TyperTest, Monotonicity_Operation_##name) { \
583     UnaryTyper typer = [&](Type type1) {             \
584       return operation_typer_.name(type1);           \
585     };                                               \
586     for (int i = 0; i < kRepetitions; ++i) {         \
587       TestUnaryMonotonicity(typer, Type::Number());  \
588     }                                                \
589   }
590 SIMPLIFIED_NUMBER_UNOP_LIST(TEST_MONOTONICITY)
591 #undef TEST_MONOTONICITY
592 
593 // SIMPLIFIED BINOPs with Number input restriction
594 #define TEST_MONOTONICITY(name)                                      \
595   TEST_F(TyperTest, Monotonicity_Operation_##name) {                 \
596     BinaryTyper typer = [&](Type type1, Type type2) {                \
597       return operation_typer_.name(type1, type2);                    \
598     };                                                               \
599     for (int i = 0; i < kRepetitions; ++i) {                         \
600       TestBinaryMonotonicity(typer, Type::Number(), Type::Number()); \
601     }                                                                \
602   }
603 SIMPLIFIED_NUMBER_BINOP_LIST(TEST_MONOTONICITY)
604 #undef TEST_MONOTONICITY
605 
606 // SIMPLIFIED BINOPs without input restriction
607 #define TEST_MONOTONICITY(name)                       \
608   TEST_F(TyperTest, Monotonicity_Operation_##name) {  \
609     BinaryTyper typer = [&](Type type1, Type type2) { \
610       return operation_typer_.name(type1, type2);     \
611     };                                                \
612     for (int i = 0; i < kRepetitions; ++i) {          \
613       TestBinaryMonotonicity(typer);                  \
614     }                                                 \
615   }
616 SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(TEST_MONOTONICITY)
617 #undef TEST_MONOTONICITY
618 
619 TEST_F(TyperTest, Manual_Operation_NumberMax) {
__anon35a172e70402(Type type1, Type type2) 620   BinaryTyper t = [&](Type type1, Type type2) {
621     return operation_typer_.NumberMax(type1, type2);
622   };
623 
624   Type zero = Type::Constant(0, zone());
625   Type zero_or_minuszero = Type::Union(zero, Type::MinusZero(), zone());
626   Type dot_five = Type::Constant(0.5, zone());
627 
628   Type a = t(Type::MinusZero(), Type::MinusZero());
629   CHECK(Type::MinusZero().Is(a));
630 
631   Type b = t(Type::MinusZero(), zero_or_minuszero);
632   CHECK(Type::MinusZero().Is(b));
633   CHECK(zero.Is(b));
634   CHECK(a.Is(b));  // Monotonicity.
635 
636   Type c = t(zero_or_minuszero, Type::MinusZero());
637   CHECK(Type::MinusZero().Is(c));
638   CHECK(zero.Is(c));
639   CHECK(a.Is(c));  // Monotonicity.
640 
641   Type d = t(zero_or_minuszero, zero_or_minuszero);
642   CHECK(Type::MinusZero().Is(d));
643   CHECK(zero.Is(d));
644   CHECK(b.Is(d));  // Monotonicity.
645   CHECK(c.Is(d));  // Monotonicity.
646 
647   Type e =
648       t(Type::MinusZero(), Type::Union(Type::MinusZero(), dot_five, zone()));
649   CHECK(Type::MinusZero().Is(e));
650   CHECK(dot_five.Is(e));
651   CHECK(a.Is(e));  // Monotonicity.
652 
653   Type f = t(Type::MinusZero(), zero);
654   CHECK(zero.Is(f));
655   CHECK(f.Is(b));  // Monotonicity.
656 
657   Type g = t(zero, Type::MinusZero());
658   CHECK(zero.Is(g));
659   CHECK(g.Is(c));  // Monotonicity.
660 
661   Type h = t(Type::Signed32(), Type::MinusZero());
662   CHECK(Type::MinusZero().Is(h));
663 
664   Type i = t(Type::Signed32(), zero_or_minuszero);
665   CHECK(h.Is(i));  // Monotonicity.
666 }
667 
TEST_F(TyperTest,Manual_Operation_NumberMin)668 TEST_F(TyperTest, Manual_Operation_NumberMin) {
669   BinaryTyper t = [&](Type type1, Type type2) {
670     return operation_typer_.NumberMin(type1, type2);
671   };
672 
673   Type zero = Type::Constant(0, zone());
674   Type zero_or_minuszero = Type::Union(zero, Type::MinusZero(), zone());
675   Type one = Type::Constant(1, zone());
676   Type minus_dot_five = Type::Constant(-0.5, zone());
677 
678   Type a = t(Type::MinusZero(), Type::MinusZero());
679   CHECK(Type::MinusZero().Is(a));
680 
681   Type b = t(Type::MinusZero(), zero_or_minuszero);
682   CHECK(Type::MinusZero().Is(b));
683   CHECK(zero.Is(b));
684   CHECK(a.Is(b));  // Monotonicity.
685 
686   Type c = t(zero_or_minuszero, Type::MinusZero());
687   CHECK(Type::MinusZero().Is(c));
688   CHECK(zero.Is(c));
689   CHECK(a.Is(c));  // Monotonicity.
690 
691   Type d = t(zero_or_minuszero, zero_or_minuszero);
692   CHECK(Type::MinusZero().Is(d));
693   CHECK(zero.Is(d));
694   CHECK(b.Is(d));  // Monotonicity.
695   CHECK(c.Is(d));  // Monotonicity.
696 
697   Type e = t(Type::MinusZero(),
698              Type::Union(Type::MinusZero(), minus_dot_five, zone()));
699   CHECK(Type::MinusZero().Is(e));
700   CHECK(minus_dot_five.Is(e));
701   CHECK(a.Is(e));  // Monotonicity.
702 
703   Type f = t(Type::MinusZero(), zero);
704   CHECK(Type::MinusZero().Is(f));
705   CHECK(f.Is(b));  // Monotonicity.
706 
707   Type g = t(zero, Type::MinusZero());
708   CHECK(Type::MinusZero().Is(g));
709   CHECK(g.Is(c));  // Monotonicity.
710 
711   Type h = t(one, Type::MinusZero());
712   CHECK(Type::MinusZero().Is(h));
713 
714   Type i = t(Type::Signed32(), Type::MinusZero());
715   CHECK(Type::MinusZero().Is(i));
716 
717   Type j = t(Type::Signed32(), zero_or_minuszero);
718   CHECK(i.Is(j));  // Monotonicity.
719 }
720 
721 }  // namespace compiler
722 }  // namespace internal
723 }  // namespace v8
724