| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <functional> | 5 #include <functional> |
| 6 | 6 |
| 7 #include "src/codegen.h" |
| 7 #include "src/compiler/node-properties-inl.h" | 8 #include "src/compiler/node-properties-inl.h" |
| 8 #include "src/compiler/typer.h" | 9 #include "src/compiler/typer.h" |
| 9 #include "test/cctest/cctest.h" | 10 #include "test/cctest/cctest.h" |
| 10 #include "test/cctest/compiler/graph-builder-tester.h" | 11 #include "test/cctest/compiler/graph-builder-tester.h" |
| 11 #include "test/cctest/types-fuzz.h" | 12 #include "test/cctest/types-fuzz.h" |
| 12 | 13 |
| 13 using namespace v8::internal; | 14 using namespace v8::internal; |
| 14 using namespace v8::internal::compiler; | 15 using namespace v8::internal::compiler; |
| 15 | 16 |
| 16 | 17 |
| 17 | 18 // TODO(titzer): generate a large set of deterministic inputs for these tests. |
| 18 class TyperTester : public HandleAndZoneScope, public GraphAndBuilders { | 19 class TyperTester : public HandleAndZoneScope, public GraphAndBuilders { |
| 19 public: | 20 public: |
| 20 TyperTester() | 21 TyperTester() |
| 21 : GraphAndBuilders(main_zone()), | 22 : GraphAndBuilders(main_zone()), |
| 22 types_(main_zone(), isolate()), | 23 types_(main_zone(), isolate()), |
| 23 typer_(graph(), MaybeHandle<Context>()), | 24 typer_(graph(), MaybeHandle<Context>()), |
| 24 javascript_(main_zone()) { | 25 javascript_(main_zone()) { |
| 25 Node* s = graph()->NewNode(common()->Start(3)); | 26 Node* s = graph()->NewNode(common()->Start(3)); |
| 26 graph()->SetStart(s); | 27 graph()->SetStart(s); |
| 27 context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start()); | 28 context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start()); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 Node* p1 = Parameter(1); | 73 Node* p1 = Parameter(1); |
| 73 NodeProperties::SetBounds(p0, Bounds(lhs)); | 74 NodeProperties::SetBounds(p0, Bounds(lhs)); |
| 74 NodeProperties::SetBounds(p1, Bounds(rhs)); | 75 NodeProperties::SetBounds(p1, Bounds(rhs)); |
| 75 Node* n = graph()->NewNode( | 76 Node* n = graph()->NewNode( |
| 76 op, p0, p1, context_node_, graph()->start(), graph()->start()); | 77 op, p0, p1, context_node_, graph()->start(), graph()->start()); |
| 77 return NodeProperties::GetBounds(n).upper; | 78 return NodeProperties::GetBounds(n).upper; |
| 78 } | 79 } |
| 79 | 80 |
| 80 Type* RandomRange(bool int32 = false) { | 81 Type* RandomRange(bool int32 = false) { |
| 81 std::vector<double>& numbers = int32 ? int32s : integers; | 82 std::vector<double>& numbers = int32 ? int32s : integers; |
| 83 double i = numbers[rng_->NextInt(static_cast<int>(numbers.size()))]; |
| 84 double j = numbers[rng_->NextInt(static_cast<int>(numbers.size()))]; |
| 85 return NewRange(i, j); |
| 86 } |
| 87 |
| 88 Type* NewRange(double i, double j) { |
| 82 Factory* f = isolate()->factory(); | 89 Factory* f = isolate()->factory(); |
| 83 int i = rng_->NextInt(static_cast<int>(numbers.size())); | 90 i::Handle<i::Object> min = f->NewNumber(i); |
| 84 int j = rng_->NextInt(static_cast<int>(numbers.size())); | 91 i::Handle<i::Object> max = f->NewNumber(j); |
| 85 i::Handle<i::Object> min = f->NewNumber(numbers[i]); | |
| 86 i::Handle<i::Object> max = f->NewNumber(numbers[j]); | |
| 87 if (min->Number() > max->Number()) std::swap(min, max); | 92 if (min->Number() > max->Number()) std::swap(min, max); |
| 88 return Type::Range(min, max, main_zone()); | 93 return Type::Range(min, max, main_zone()); |
| 89 } | 94 } |
| 90 | 95 |
| 91 double RandomInt(double min, double max) { | 96 double RandomInt(double min, double max) { |
| 92 switch (rng_->NextInt(4)) { | 97 switch (rng_->NextInt(4)) { |
| 93 case 0: return min; | 98 case 0: return min; |
| 94 case 1: return max; | 99 case 1: return max; |
| 95 default: break; | 100 default: break; |
| 96 } | 101 } |
| 97 if (min == +V8_INFINITY) return +V8_INFINITY; | 102 if (min == +V8_INFINITY) return +V8_INFINITY; |
| 98 if (max == -V8_INFINITY) return -V8_INFINITY; | 103 if (max == -V8_INFINITY) return -V8_INFINITY; |
| 99 if (min == -V8_INFINITY && max == +V8_INFINITY) { | 104 if (min == -V8_INFINITY && max == +V8_INFINITY) { |
| 100 return rng_->NextInt() * static_cast<double>(rng_->NextInt()); | 105 return rng_->NextInt() * static_cast<double>(rng_->NextInt()); |
| 101 } | 106 } |
| 102 double result = nearbyint(min + (max - min) * rng_->NextDouble()); | 107 double result = nearbyint(min + (max - min) * rng_->NextDouble()); |
| 103 if (IsMinusZero(result)) return 0; | 108 if (IsMinusZero(result)) return 0; |
| 104 if (std::isnan(result)) return rng_->NextInt(2) ? min : max; | 109 if (std::isnan(result)) return rng_->NextInt(2) ? min : max; |
| 105 DCHECK(min <= result && result <= max); | 110 DCHECK(min <= result && result <= max); |
| 106 return result; | 111 return result; |
| 107 } | 112 } |
| 108 | 113 |
| 109 double RandomInt(Type::RangeType* range) { | 114 double RandomInt(Type::RangeType* range) { |
| 110 return RandomInt(range->Min()->Number(), range->Max()->Number()); | 115 return RandomInt(range->Min()->Number(), range->Max()->Number()); |
| 111 } | 116 } |
| 112 | 117 |
| 118 // Careful, this function runs O(max_width^5) trials. |
| 119 template <class BinaryFunction> |
| 120 void TestBinaryArithOpCloseToZero(const Operator* op, BinaryFunction opfun, |
| 121 int max_width) { |
| 122 const int min_min = -2 - max_width / 2; |
| 123 const int max_min = 2 + max_width / 2; |
| 124 for (int width = 0; width < max_width; width++) { |
| 125 for (int lmin = min_min; lmin <= max_min; lmin++) { |
| 126 for (int rmin = min_min; rmin <= max_min; rmin++) { |
| 127 Type* r1 = NewRange(lmin, lmin + width); |
| 128 Type* r2 = NewRange(rmin, rmin + width); |
| 129 Type* expected_type = TypeBinaryOp(op, r1, r2); |
| 130 |
| 131 for (int x1 = lmin; x1 < lmin + width; x1++) { |
| 132 for (int x2 = rmin; x2 < rmin + width; x2++) { |
| 133 double result_value = opfun(x1, x2); |
| 134 Type* result_type = Type::Constant( |
| 135 isolate()->factory()->NewNumber(result_value), main_zone()); |
| 136 CHECK(result_type->Is(expected_type)); |
| 137 } |
| 138 } |
| 139 } |
| 140 } |
| 141 } |
| 142 } |
| 143 |
| 113 template <class BinaryFunction> | 144 template <class BinaryFunction> |
| 114 void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) { | 145 void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) { |
| 146 TestBinaryArithOpCloseToZero(op, opfun, 8); |
| 115 for (int i = 0; i < 100; ++i) { | 147 for (int i = 0; i < 100; ++i) { |
| 116 Type::RangeType* r1 = RandomRange()->AsRange(); | 148 Type::RangeType* r1 = RandomRange()->AsRange(); |
| 117 Type::RangeType* r2 = RandomRange()->AsRange(); | 149 Type::RangeType* r2 = RandomRange()->AsRange(); |
| 118 Type* expected_type = TypeBinaryOp(op, r1, r2); | 150 Type* expected_type = TypeBinaryOp(op, r1, r2); |
| 119 double x1 = RandomInt(r1); | 151 for (int i = 0; i < 10; i++) { |
| 120 double x2 = RandomInt(r2); | 152 double x1 = RandomInt(r1); |
| 121 double result_value = opfun(x1, x2); | 153 double x2 = RandomInt(r2); |
| 122 Type* result_type = Type::Constant( | 154 double result_value = opfun(x1, x2); |
| 123 isolate()->factory()->NewNumber(result_value), main_zone()); | 155 Type* result_type = Type::Constant( |
| 124 CHECK(result_type->Is(expected_type)); | 156 isolate()->factory()->NewNumber(result_value), main_zone()); |
| 157 CHECK(result_type->Is(expected_type)); |
| 158 } |
| 125 } | 159 } |
| 126 } | 160 } |
| 127 | 161 |
| 128 template <class BinaryFunction> | 162 template <class BinaryFunction> |
| 129 void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) { | 163 void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) { |
| 130 for (int i = 0; i < 100; ++i) { | 164 for (int i = 0; i < 100; ++i) { |
| 131 Type::RangeType* r1 = RandomRange()->AsRange(); | 165 Type::RangeType* r1 = RandomRange()->AsRange(); |
| 132 Type::RangeType* r2 = RandomRange()->AsRange(); | 166 Type::RangeType* r2 = RandomRange()->AsRange(); |
| 133 Type* expected_type = TypeBinaryOp(op, r1, r2); | 167 Type* expected_type = TypeBinaryOp(op, r1, r2); |
| 134 double x1 = RandomInt(r1); | 168 for (int i = 0; i < 10; i++) { |
| 135 double x2 = RandomInt(r2); | 169 double x1 = RandomInt(r1); |
| 136 bool result_value = opfun(x1, x2); | 170 double x2 = RandomInt(r2); |
| 137 Type* result_type = Type::Constant(result_value ? | 171 bool result_value = opfun(x1, x2); |
| 138 isolate()->factory()->true_value() : | 172 Type* result_type = |
| 139 isolate()->factory()->false_value(), main_zone()); | 173 Type::Constant(result_value ? isolate()->factory()->true_value() |
| 140 CHECK(result_type->Is(expected_type)); | 174 : isolate()->factory()->false_value(), |
| 175 main_zone()); |
| 176 CHECK(result_type->Is(expected_type)); |
| 177 } |
| 141 } | 178 } |
| 142 } | 179 } |
| 143 | 180 |
| 144 template <class BinaryFunction> | 181 template <class BinaryFunction> |
| 145 void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) { | 182 void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) { |
| 146 for (int i = 0; i < 100; ++i) { | 183 for (int i = 0; i < 100; ++i) { |
| 147 Type::RangeType* r1 = RandomRange(true)->AsRange(); | 184 Type::RangeType* r1 = RandomRange(true)->AsRange(); |
| 148 Type::RangeType* r2 = RandomRange(true)->AsRange(); | 185 Type::RangeType* r2 = RandomRange(true)->AsRange(); |
| 149 Type* expected_type = TypeBinaryOp(op, r1, r2); | 186 Type* expected_type = TypeBinaryOp(op, r1, r2); |
| 150 int32_t x1 = static_cast<int32_t>(RandomInt(r1)); | 187 for (int i = 0; i < 10; i++) { |
| 151 int32_t x2 = static_cast<int32_t>(RandomInt(r2)); | 188 int32_t x1 = static_cast<int32_t>(RandomInt(r1)); |
| 152 double result_value = opfun(x1, x2); | 189 int32_t x2 = static_cast<int32_t>(RandomInt(r2)); |
| 153 Type* result_type = Type::Constant( | 190 double result_value = opfun(x1, x2); |
| 154 isolate()->factory()->NewNumber(result_value), main_zone()); | 191 Type* result_type = Type::Constant( |
| 155 CHECK(result_type->Is(expected_type)); | 192 isolate()->factory()->NewNumber(result_value), main_zone()); |
| 193 CHECK(result_type->Is(expected_type)); |
| 194 } |
| 156 } | 195 } |
| 157 } | 196 } |
| 158 | 197 |
| 159 Type* RandomSubtype(Type* type) { | 198 Type* RandomSubtype(Type* type) { |
| 160 Type* subtype; | 199 Type* subtype; |
| 161 do { | 200 do { |
| 162 subtype = types_.Fuzz(); | 201 subtype = types_.Fuzz(); |
| 163 } while (!subtype->Is(type)); | 202 } while (!subtype->Is(type)); |
| 164 return subtype; | 203 return subtype; |
| 165 } | 204 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 t.TestBinaryArithOp(t.javascript_.Multiply(), std::multiplies<double>()); | 248 t.TestBinaryArithOp(t.javascript_.Multiply(), std::multiplies<double>()); |
| 210 } | 249 } |
| 211 | 250 |
| 212 | 251 |
| 213 TEST(TypeJSDivide) { | 252 TEST(TypeJSDivide) { |
| 214 TyperTester t; | 253 TyperTester t; |
| 215 t.TestBinaryArithOp(t.javascript_.Divide(), std::divides<double>()); | 254 t.TestBinaryArithOp(t.javascript_.Divide(), std::divides<double>()); |
| 216 } | 255 } |
| 217 | 256 |
| 218 | 257 |
| 258 TEST(TypeJSModulus) { |
| 259 TyperTester t; |
| 260 t.TestBinaryArithOp(t.javascript_.Modulus(), modulo); |
| 261 } |
| 262 |
| 263 |
| 219 TEST(TypeJSBitwiseOr) { | 264 TEST(TypeJSBitwiseOr) { |
| 220 TyperTester t; | 265 TyperTester t; |
| 221 t.TestBinaryBitOp(t.javascript_.BitwiseOr(), bit_or); | 266 t.TestBinaryBitOp(t.javascript_.BitwiseOr(), bit_or); |
| 222 } | 267 } |
| 223 | 268 |
| 224 | 269 |
| 225 TEST(TypeJSBitwiseAnd) { | 270 TEST(TypeJSBitwiseAnd) { |
| 226 TyperTester t; | 271 TyperTester t; |
| 227 t.TestBinaryBitOp(t.javascript_.BitwiseAnd(), bit_and); | 272 t.TestBinaryBitOp(t.javascript_.BitwiseAnd(), bit_and); |
| 228 } | 273 } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 V(ShiftLeft) \ | 363 V(ShiftLeft) \ |
| 319 V(ShiftRight) \ | 364 V(ShiftRight) \ |
| 320 V(ShiftRightLogical) \ | 365 V(ShiftRightLogical) \ |
| 321 V(Add) \ | 366 V(Add) \ |
| 322 V(Subtract) \ | 367 V(Subtract) \ |
| 323 V(Multiply) \ | 368 V(Multiply) \ |
| 324 V(Divide) \ | 369 V(Divide) \ |
| 325 V(Modulus) | 370 V(Modulus) |
| 326 | 371 |
| 327 | 372 |
| 328 TEST(Monotonicity) { | 373 #define TEST_FUNC(name) \ |
| 329 TyperTester t; | 374 TEST(Monotonicity_##name) { \ |
| 330 #define TEST_OP(name) \ | 375 TyperTester t; \ |
| 331 t.TestBinaryMonotonicity(t.javascript_.name()); | 376 t.TestBinaryMonotonicity(t.javascript_.name()); \ |
| 332 JSBINOP_LIST(TEST_OP) | 377 } |
| 333 #undef TEST_OP | 378 JSBINOP_LIST(TEST_FUNC) |
| 334 } | 379 #undef TEST_FUNC |
| OLD | NEW |