| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <functional> |
| 6 |
| 7 #include "src/codegen.h" |
| 8 #include "src/compiler/js-operator.h" |
| 9 #include "src/compiler/node-properties-inl.h" |
| 10 #include "src/compiler/typer.h" |
| 11 #include "src/isolate-inl.h" |
| 12 #include "test/unittests/compiler/graph-unittest.h" |
| 13 #include "testing/gmock-support.h" |
| 14 |
| 15 using namespace v8::internal; |
| 16 using namespace v8::internal::compiler; |
| 17 |
| 18 namespace { |
| 19 |
| 20 template <class Type, class TypeHandle, class Region> |
| 21 class Types { |
| 22 public: |
| 23 Types(Region* region, Isolate* isolate) |
| 24 : region_(region), rng_(isolate->random_number_generator()) { |
| 25 #define DECLARE_TYPE(name, value) \ |
| 26 name = Type::name(region); \ |
| 27 types.push_back(name); |
| 28 PROPER_BITSET_TYPE_LIST(DECLARE_TYPE) |
| 29 #undef DECLARE_TYPE |
| 30 |
| 31 object_map = |
| 32 isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); |
| 33 array_map = isolate->factory()->NewMap(JS_ARRAY_TYPE, JSArray::kSize); |
| 34 number_map = |
| 35 isolate->factory()->NewMap(HEAP_NUMBER_TYPE, HeapNumber::kSize); |
| 36 uninitialized_map = isolate->factory()->uninitialized_map(); |
| 37 ObjectClass = Type::Class(object_map, region); |
| 38 ArrayClass = Type::Class(array_map, region); |
| 39 NumberClass = Type::Class(number_map, region); |
| 40 UninitializedClass = Type::Class(uninitialized_map, region); |
| 41 |
| 42 maps.push_back(object_map); |
| 43 maps.push_back(array_map); |
| 44 maps.push_back(uninitialized_map); |
| 45 for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) { |
| 46 types.push_back(Type::Class(*it, region)); |
| 47 } |
| 48 |
| 49 smi = handle(Smi::FromInt(666), isolate); |
| 50 signed32 = isolate->factory()->NewHeapNumber(0x40000000); |
| 51 object1 = isolate->factory()->NewJSObjectFromMap(object_map); |
| 52 object2 = isolate->factory()->NewJSObjectFromMap(object_map); |
| 53 array = isolate->factory()->NewJSArray(20); |
| 54 uninitialized = isolate->factory()->uninitialized_value(); |
| 55 SmiConstant = Type::Constant(smi, region); |
| 56 Signed32Constant = Type::Constant(signed32, region); |
| 57 ObjectConstant1 = Type::Constant(object1, region); |
| 58 ObjectConstant2 = Type::Constant(object2, region); |
| 59 ArrayConstant = Type::Constant(array, region); |
| 60 UninitializedConstant = Type::Constant(uninitialized, region); |
| 61 |
| 62 values.push_back(smi); |
| 63 values.push_back(signed32); |
| 64 values.push_back(object1); |
| 65 values.push_back(object2); |
| 66 values.push_back(array); |
| 67 values.push_back(uninitialized); |
| 68 for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) { |
| 69 types.push_back(Type::Constant(*it, region)); |
| 70 } |
| 71 |
| 72 integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY)); |
| 73 integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY)); |
| 74 integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10))); |
| 75 integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10))); |
| 76 for (int i = 0; i < 10; ++i) { |
| 77 double x = rng_->NextInt(); |
| 78 integers.push_back(isolate->factory()->NewNumber(x)); |
| 79 x *= rng_->NextInt(); |
| 80 if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x)); |
| 81 } |
| 82 |
| 83 Integer = Type::Range(isolate->factory()->NewNumber(-V8_INFINITY), |
| 84 isolate->factory()->NewNumber(+V8_INFINITY), region); |
| 85 |
| 86 NumberArray = Type::Array(Number, region); |
| 87 StringArray = Type::Array(String, region); |
| 88 AnyArray = Type::Array(Any, region); |
| 89 |
| 90 SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region); |
| 91 NumberFunction1 = Type::Function(Number, Number, region); |
| 92 NumberFunction2 = Type::Function(Number, Number, Number, region); |
| 93 MethodFunction = Type::Function(String, Object, 0, region); |
| 94 |
| 95 for (int i = 0; i < 30; ++i) { |
| 96 types.push_back(Fuzz()); |
| 97 } |
| 98 } |
| 99 |
| 100 Handle<i::Map> object_map; |
| 101 Handle<i::Map> array_map; |
| 102 Handle<i::Map> number_map; |
| 103 Handle<i::Map> uninitialized_map; |
| 104 |
| 105 Handle<i::Smi> smi; |
| 106 Handle<i::HeapNumber> signed32; |
| 107 Handle<i::JSObject> object1; |
| 108 Handle<i::JSObject> object2; |
| 109 Handle<i::JSArray> array; |
| 110 Handle<i::Oddball> uninitialized; |
| 111 |
| 112 #define DECLARE_TYPE(name, value) TypeHandle name; |
| 113 PROPER_BITSET_TYPE_LIST(DECLARE_TYPE) |
| 114 #undef DECLARE_TYPE |
| 115 |
| 116 TypeHandle ObjectClass; |
| 117 TypeHandle ArrayClass; |
| 118 TypeHandle NumberClass; |
| 119 TypeHandle UninitializedClass; |
| 120 |
| 121 TypeHandle SmiConstant; |
| 122 TypeHandle Signed32Constant; |
| 123 TypeHandle ObjectConstant1; |
| 124 TypeHandle ObjectConstant2; |
| 125 TypeHandle ArrayConstant; |
| 126 TypeHandle UninitializedConstant; |
| 127 |
| 128 TypeHandle Integer; |
| 129 |
| 130 TypeHandle NumberArray; |
| 131 TypeHandle StringArray; |
| 132 TypeHandle AnyArray; |
| 133 |
| 134 TypeHandle SignedFunction1; |
| 135 TypeHandle NumberFunction1; |
| 136 TypeHandle NumberFunction2; |
| 137 TypeHandle MethodFunction; |
| 138 |
| 139 typedef std::vector<TypeHandle> TypeVector; |
| 140 typedef std::vector<Handle<i::Map> > MapVector; |
| 141 typedef std::vector<Handle<i::Object> > ValueVector; |
| 142 |
| 143 TypeVector types; |
| 144 MapVector maps; |
| 145 ValueVector values; |
| 146 ValueVector integers; // "Integer" values used for range limits. |
| 147 |
| 148 TypeHandle Of(Handle<i::Object> value) { return Type::Of(value, region_); } |
| 149 |
| 150 TypeHandle NowOf(Handle<i::Object> value) { |
| 151 return Type::NowOf(value, region_); |
| 152 } |
| 153 |
| 154 TypeHandle Class(Handle<i::Map> map) { return Type::Class(map, region_); } |
| 155 |
| 156 TypeHandle Constant(Handle<i::Object> value) { |
| 157 return Type::Constant(value, region_); |
| 158 } |
| 159 |
| 160 TypeHandle Range(Handle<i::Object> min, Handle<i::Object> max) { |
| 161 return Type::Range(min, max, region_); |
| 162 } |
| 163 |
| 164 TypeHandle Context(TypeHandle outer) { return Type::Context(outer, region_); } |
| 165 |
| 166 TypeHandle Array1(TypeHandle element) { |
| 167 return Type::Array(element, region_); |
| 168 } |
| 169 |
| 170 TypeHandle Function0(TypeHandle result, TypeHandle receiver) { |
| 171 return Type::Function(result, receiver, 0, region_); |
| 172 } |
| 173 |
| 174 TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) { |
| 175 TypeHandle type = Type::Function(result, receiver, 1, region_); |
| 176 type->AsFunction()->InitParameter(0, arg); |
| 177 return type; |
| 178 } |
| 179 |
| 180 TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) { |
| 181 return Type::Function(result, arg1, arg2, region_); |
| 182 } |
| 183 |
| 184 TypeHandle Union(TypeHandle t1, TypeHandle t2) { |
| 185 return Type::Union(t1, t2, region_); |
| 186 } |
| 187 TypeHandle Intersect(TypeHandle t1, TypeHandle t2) { |
| 188 return Type::Intersect(t1, t2, region_); |
| 189 } |
| 190 |
| 191 template <class Type2, class TypeHandle2> |
| 192 TypeHandle Convert(TypeHandle2 t) { |
| 193 return Type::template Convert<Type2>(t, region_); |
| 194 } |
| 195 |
| 196 TypeHandle Random() { |
| 197 return types[rng_->NextInt(static_cast<int>(types.size()))]; |
| 198 } |
| 199 |
| 200 TypeHandle Fuzz(int depth = 4) { |
| 201 switch (rng_->NextInt(depth == 0 ? 3 : 20)) { |
| 202 case 0: { // bitset |
| 203 #define COUNT_BITSET_TYPES(type, value) +1 |
| 204 int n = 0 PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES); |
| 205 #undef COUNT_BITSET_TYPES |
| 206 // Pick a bunch of named bitsets and return their intersection. |
| 207 TypeHandle result = Type::Any(region_); |
| 208 for (int i = 0, m = 1 + rng_->NextInt(3); i < m; ++i) { |
| 209 int j = rng_->NextInt(n); |
| 210 #define PICK_BITSET_TYPE(type, value) \ |
| 211 if (j-- == 0) { \ |
| 212 TypeHandle tmp = Type::Intersect(result, Type::type(region_), region_); \ |
| 213 if (tmp->Is(Type::None()) && i != 0) { \ |
| 214 break; \ |
| 215 } else { \ |
| 216 result = tmp; \ |
| 217 continue; \ |
| 218 } \ |
| 219 } |
| 220 PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE) |
| 221 #undef PICK_BITSET_TYPE |
| 222 } |
| 223 return result; |
| 224 } |
| 225 case 1: { // class |
| 226 int i = rng_->NextInt(static_cast<int>(maps.size())); |
| 227 return Type::Class(maps[i], region_); |
| 228 } |
| 229 case 2: { // constant |
| 230 int i = rng_->NextInt(static_cast<int>(values.size())); |
| 231 return Type::Constant(values[i], region_); |
| 232 } |
| 233 case 3: { // range |
| 234 int i = rng_->NextInt(static_cast<int>(integers.size())); |
| 235 int j = rng_->NextInt(static_cast<int>(integers.size())); |
| 236 i::Handle<i::Object> min = integers[i]; |
| 237 i::Handle<i::Object> max = integers[j]; |
| 238 if (min->Number() > max->Number()) std::swap(min, max); |
| 239 return Type::Range(min, max, region_); |
| 240 } |
| 241 case 4: { // context |
| 242 int depth = rng_->NextInt(3); |
| 243 TypeHandle type = Type::Internal(region_); |
| 244 for (int i = 0; i < depth; ++i) type = Type::Context(type, region_); |
| 245 return type; |
| 246 } |
| 247 case 5: { // array |
| 248 TypeHandle element = Fuzz(depth / 2); |
| 249 return Type::Array(element, region_); |
| 250 } |
| 251 case 6: |
| 252 case 7: { // function |
| 253 TypeHandle result = Fuzz(depth / 2); |
| 254 TypeHandle receiver = Fuzz(depth / 2); |
| 255 int arity = rng_->NextInt(3); |
| 256 TypeHandle type = Type::Function(result, receiver, arity, region_); |
| 257 for (int i = 0; i < type->AsFunction()->Arity(); ++i) { |
| 258 TypeHandle parameter = Fuzz(depth / 2); |
| 259 type->AsFunction()->InitParameter(i, parameter); |
| 260 } |
| 261 return type; |
| 262 } |
| 263 default: { // union |
| 264 int n = rng_->NextInt(10); |
| 265 TypeHandle type = None; |
| 266 for (int i = 0; i < n; ++i) { |
| 267 TypeHandle operand = Fuzz(depth - 1); |
| 268 type = Type::Union(type, operand, region_); |
| 269 } |
| 270 return type; |
| 271 } |
| 272 } |
| 273 UNREACHABLE(); |
| 274 } |
| 275 |
| 276 Region* region() { return region_; } |
| 277 |
| 278 private: |
| 279 Region* region_; |
| 280 v8::base::RandomNumberGenerator* rng_; |
| 281 }; |
| 282 |
| 283 |
| 284 // TODO(titzer): generate a large set of deterministic inputs for these tests. |
| 285 class TyperTest : public GraphTest { |
| 286 public: |
| 287 TyperTest() |
| 288 : types_(zone(), isolate()), |
| 289 typer_(graph(), MaybeHandle<Context>()), |
| 290 javascript_(zone()) { |
| 291 Node* s = graph()->NewNode(common()->Start(3)); |
| 292 graph()->SetStart(s); |
| 293 context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start()); |
| 294 rng_ = isolate()->random_number_generator(); |
| 295 |
| 296 integers.push_back(0); |
| 297 integers.push_back(0); |
| 298 integers.push_back(-1); |
| 299 integers.push_back(+1); |
| 300 integers.push_back(-V8_INFINITY); |
| 301 integers.push_back(+V8_INFINITY); |
| 302 for (int i = 0; i < 5; ++i) { |
| 303 double x = rng_->NextInt(); |
| 304 integers.push_back(x); |
| 305 x *= rng_->NextInt(); |
| 306 if (!IsMinusZero(x)) integers.push_back(x); |
| 307 } |
| 308 |
| 309 int32s.push_back(0); |
| 310 int32s.push_back(0); |
| 311 int32s.push_back(-1); |
| 312 int32s.push_back(+1); |
| 313 int32s.push_back(kMinInt); |
| 314 int32s.push_back(kMaxInt); |
| 315 for (int i = 0; i < 10; ++i) { |
| 316 int32s.push_back(rng_->NextInt()); |
| 317 } |
| 318 } |
| 319 |
| 320 Types<Type, Type*, Zone> types_; |
| 321 Typer typer_; |
| 322 JSOperatorBuilder javascript_; |
| 323 Node* context_node_; |
| 324 v8::base::RandomNumberGenerator* rng_; |
| 325 std::vector<double> integers; |
| 326 std::vector<double> int32s; |
| 327 |
| 328 Type* TypeBinaryOp(const Operator* op, Type* lhs, Type* rhs) { |
| 329 Node* p0 = Parameter(0); |
| 330 Node* p1 = Parameter(1); |
| 331 NodeProperties::SetBounds(p0, Bounds(lhs)); |
| 332 NodeProperties::SetBounds(p1, Bounds(rhs)); |
| 333 Node* n = graph()->NewNode(op, p0, p1, context_node_, graph()->start(), |
| 334 graph()->start()); |
| 335 return NodeProperties::GetBounds(n).upper; |
| 336 } |
| 337 |
| 338 Type* RandomRange(bool int32 = false) { |
| 339 std::vector<double>& numbers = int32 ? int32s : integers; |
| 340 double i = numbers[rng_->NextInt(static_cast<int>(numbers.size()))]; |
| 341 double j = numbers[rng_->NextInt(static_cast<int>(numbers.size()))]; |
| 342 return NewRange(i, j); |
| 343 } |
| 344 |
| 345 Type* NewRange(double i, double j) { |
| 346 Factory* f = isolate()->factory(); |
| 347 i::Handle<i::Object> min = f->NewNumber(i); |
| 348 i::Handle<i::Object> max = f->NewNumber(j); |
| 349 if (min->Number() > max->Number()) std::swap(min, max); |
| 350 return Type::Range(min, max, zone()); |
| 351 } |
| 352 |
| 353 double RandomInt(double min, double max) { |
| 354 switch (rng_->NextInt(4)) { |
| 355 case 0: |
| 356 return min; |
| 357 case 1: |
| 358 return max; |
| 359 default: |
| 360 break; |
| 361 } |
| 362 if (min == +V8_INFINITY) return +V8_INFINITY; |
| 363 if (max == -V8_INFINITY) return -V8_INFINITY; |
| 364 if (min == -V8_INFINITY && max == +V8_INFINITY) { |
| 365 return rng_->NextInt() * static_cast<double>(rng_->NextInt()); |
| 366 } |
| 367 double result = nearbyint(min + (max - min) * rng_->NextDouble()); |
| 368 if (IsMinusZero(result)) return 0; |
| 369 if (std::isnan(result)) return rng_->NextInt(2) ? min : max; |
| 370 DCHECK(min <= result && result <= max); |
| 371 return result; |
| 372 } |
| 373 |
| 374 double RandomInt(Type::RangeType* range) { |
| 375 return RandomInt(range->Min()->Number(), range->Max()->Number()); |
| 376 } |
| 377 |
| 378 // Careful, this function runs O(max_width^5) trials. |
| 379 template <class BinaryFunction> |
| 380 void TestBinaryArithOpCloseToZero(const Operator* op, BinaryFunction opfun, |
| 381 int max_width) { |
| 382 const int min_min = -2 - max_width / 2; |
| 383 const int max_min = 2 + max_width / 2; |
| 384 for (int width = 0; width < max_width; width++) { |
| 385 for (int lmin = min_min; lmin <= max_min; lmin++) { |
| 386 for (int rmin = min_min; rmin <= max_min; rmin++) { |
| 387 Type* r1 = NewRange(lmin, lmin + width); |
| 388 Type* r2 = NewRange(rmin, rmin + width); |
| 389 Type* expected_type = TypeBinaryOp(op, r1, r2); |
| 390 |
| 391 for (int x1 = lmin; x1 < lmin + width; x1++) { |
| 392 for (int x2 = rmin; x2 < rmin + width; x2++) { |
| 393 double result_value = opfun(x1, x2); |
| 394 Type* result_type = Type::Constant( |
| 395 isolate()->factory()->NewNumber(result_value), zone()); |
| 396 EXPECT_TRUE(result_type->Is(expected_type)); |
| 397 } |
| 398 } |
| 399 } |
| 400 } |
| 401 } |
| 402 } |
| 403 |
| 404 template <class BinaryFunction> |
| 405 void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) { |
| 406 TestBinaryArithOpCloseToZero(op, opfun, 8); |
| 407 for (int i = 0; i < 100; ++i) { |
| 408 Type::RangeType* r1 = RandomRange()->AsRange(); |
| 409 Type::RangeType* r2 = RandomRange()->AsRange(); |
| 410 Type* expected_type = TypeBinaryOp(op, r1, r2); |
| 411 for (int i = 0; i < 10; i++) { |
| 412 double x1 = RandomInt(r1); |
| 413 double x2 = RandomInt(r2); |
| 414 double result_value = opfun(x1, x2); |
| 415 Type* result_type = Type::Constant( |
| 416 isolate()->factory()->NewNumber(result_value), zone()); |
| 417 EXPECT_TRUE(result_type->Is(expected_type)); |
| 418 } |
| 419 } |
| 420 } |
| 421 |
| 422 template <class BinaryFunction> |
| 423 void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) { |
| 424 for (int i = 0; i < 100; ++i) { |
| 425 Type::RangeType* r1 = RandomRange()->AsRange(); |
| 426 Type::RangeType* r2 = RandomRange()->AsRange(); |
| 427 Type* expected_type = TypeBinaryOp(op, r1, r2); |
| 428 for (int i = 0; i < 10; i++) { |
| 429 double x1 = RandomInt(r1); |
| 430 double x2 = RandomInt(r2); |
| 431 bool result_value = opfun(x1, x2); |
| 432 Type* result_type = |
| 433 Type::Constant(result_value ? isolate()->factory()->true_value() |
| 434 : isolate()->factory()->false_value(), |
| 435 zone()); |
| 436 EXPECT_TRUE(result_type->Is(expected_type)); |
| 437 } |
| 438 } |
| 439 } |
| 440 |
| 441 template <class BinaryFunction> |
| 442 void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) { |
| 443 for (int i = 0; i < 100; ++i) { |
| 444 Type::RangeType* r1 = RandomRange(true)->AsRange(); |
| 445 Type::RangeType* r2 = RandomRange(true)->AsRange(); |
| 446 Type* expected_type = TypeBinaryOp(op, r1, r2); |
| 447 for (int i = 0; i < 10; i++) { |
| 448 int32_t x1 = static_cast<int32_t>(RandomInt(r1)); |
| 449 int32_t x2 = static_cast<int32_t>(RandomInt(r2)); |
| 450 double result_value = opfun(x1, x2); |
| 451 Type* result_type = Type::Constant( |
| 452 isolate()->factory()->NewNumber(result_value), zone()); |
| 453 EXPECT_TRUE(result_type->Is(expected_type)); |
| 454 } |
| 455 } |
| 456 } |
| 457 |
| 458 Type* RandomSubtype(Type* type) { |
| 459 Type* subtype; |
| 460 do { |
| 461 subtype = types_.Fuzz(); |
| 462 } while (!subtype->Is(type)); |
| 463 return subtype; |
| 464 } |
| 465 |
| 466 void TestBinaryMonotonicity(const Operator* op) { |
| 467 for (int i = 0; i < 50; ++i) { |
| 468 Type* type1 = types_.Fuzz(); |
| 469 Type* type2 = types_.Fuzz(); |
| 470 Type* type = TypeBinaryOp(op, type1, type2); |
| 471 Type* subtype1 = RandomSubtype(type1); |
| 472 ; |
| 473 Type* subtype2 = RandomSubtype(type2); |
| 474 ; |
| 475 Type* subtype = TypeBinaryOp(op, subtype1, subtype2); |
| 476 EXPECT_TRUE(subtype->Is(type)); |
| 477 } |
| 478 } |
| 479 }; |
| 480 |
| 481 |
| 482 static int32_t shift_left(int32_t x, int32_t y) { return x << y; } |
| 483 static int32_t shift_right(int32_t x, int32_t y) { return x >> y; } |
| 484 static int32_t bit_or(int32_t x, int32_t y) { return x | y; } |
| 485 static int32_t bit_and(int32_t x, int32_t y) { return x & y; } |
| 486 static int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; } |
| 487 } |
| 488 |
| 489 |
| 490 //------------------------------------------------------------------------------ |
| 491 // Soundness |
| 492 // For simplicity, we currently only test soundness on expression operators |
| 493 // that have a direct equivalent in C++. Also, testing is currently limited |
| 494 // to ranges as input types. |
| 495 |
| 496 |
| 497 TEST_F(TyperTest, TypeJSAdd2) { |
| 498 TestBinaryArithOp(javascript_.Add(), std::plus<double>()); |
| 499 } |
| 500 |
| 501 |
| 502 TEST_F(TyperTest, TypeJSSubtract) { |
| 503 TestBinaryArithOp(javascript_.Subtract(), std::minus<double>()); |
| 504 } |
| 505 |
| 506 |
| 507 TEST_F(TyperTest, TypeJSMultiply) { |
| 508 TestBinaryArithOp(javascript_.Multiply(), std::multiplies<double>()); |
| 509 } |
| 510 |
| 511 |
| 512 TEST_F(TyperTest, TypeJSDivide) { |
| 513 TestBinaryArithOp(javascript_.Divide(), std::divides<double>()); |
| 514 } |
| 515 |
| 516 |
| 517 TEST_F(TyperTest, TypeJSModulus) { |
| 518 TestBinaryArithOp(javascript_.Modulus(), modulo); |
| 519 } |
| 520 |
| 521 |
| 522 TEST_F(TyperTest, TypeJSBitwiseOr) { |
| 523 TestBinaryBitOp(javascript_.BitwiseOr(), bit_or); |
| 524 } |
| 525 |
| 526 |
| 527 TEST_F(TyperTest, TypeJSBitwiseAnd) { |
| 528 TestBinaryBitOp(javascript_.BitwiseAnd(), bit_and); |
| 529 } |
| 530 |
| 531 |
| 532 TEST_F(TyperTest, TypeJSBitwiseXor) { |
| 533 TestBinaryBitOp(javascript_.BitwiseXor(), bit_xor); |
| 534 } |
| 535 |
| 536 |
| 537 TEST_F(TyperTest, TypeJSShiftLeft) { |
| 538 TestBinaryBitOp(javascript_.ShiftLeft(), shift_left); |
| 539 } |
| 540 |
| 541 |
| 542 TEST_F(TyperTest, TypeJSShiftRight) { |
| 543 TestBinaryBitOp(javascript_.ShiftRight(), shift_right); |
| 544 } |
| 545 |
| 546 |
| 547 TEST_F(TyperTest, TypeJSLessThan) { |
| 548 TestBinaryCompareOp(javascript_.LessThan(), std::less<double>()); |
| 549 } |
| 550 |
| 551 |
| 552 TEST_F(TyperTest, TypeJSLessThanOrEqual) { |
| 553 TestBinaryCompareOp(javascript_.LessThanOrEqual(), std::less_equal<double>()); |
| 554 } |
| 555 |
| 556 |
| 557 TEST_F(TyperTest, TypeJSGreaterThan) { |
| 558 TestBinaryCompareOp(javascript_.GreaterThan(), std::greater<double>()); |
| 559 } |
| 560 |
| 561 |
| 562 TEST_F(TyperTest, TypeJSGreaterThanOrEqual) { |
| 563 TestBinaryCompareOp(javascript_.GreaterThanOrEqual(), |
| 564 std::greater_equal<double>()); |
| 565 } |
| 566 |
| 567 |
| 568 TEST_F(TyperTest, TypeJSEqual) { |
| 569 TestBinaryCompareOp(javascript_.Equal(), std::equal_to<double>()); |
| 570 } |
| 571 |
| 572 |
| 573 TEST_F(TyperTest, TypeJSNotEqual) { |
| 574 TestBinaryCompareOp(javascript_.NotEqual(), std::not_equal_to<double>()); |
| 575 } |
| 576 |
| 577 |
| 578 // For numbers there's no difference between strict and non-strict equality. |
| 579 TEST_F(TyperTest, TypeJSStrictEqual) { |
| 580 TestBinaryCompareOp(javascript_.StrictEqual(), std::equal_to<double>()); |
| 581 } |
| 582 |
| 583 |
| 584 TEST_F(TyperTest, TypeJSStrictNotEqual) { |
| 585 TestBinaryCompareOp(javascript_.StrictNotEqual(), |
| 586 std::not_equal_to<double>()); |
| 587 } |
| 588 |
| 589 |
| 590 //------------------------------------------------------------------------------ |
| 591 // Monotonicity |
| 592 |
| 593 |
| 594 // List should be in sync with JS_SIMPLE_BINOP_LIS |
| 595 #define JSBINOP_LIST(V) \ |
| 596 V(Equal) \ |
| 597 V(NotEqual) \ |
| 598 V(StrictEqual) \ |
| 599 V(StrictNotEqual) \ |
| 600 V(LessThan) \ |
| 601 V(GreaterThan) \ |
| 602 V(LessThanOrEqual) \ |
| 603 V(GreaterThanOrEqual) \ |
| 604 V(BitwiseOr) \ |
| 605 V(BitwiseXor) \ |
| 606 V(BitwiseAnd) \ |
| 607 V(ShiftLeft) \ |
| 608 V(ShiftRight) \ |
| 609 V(ShiftRightLogical) \ |
| 610 V(Add) \ |
| 611 V(Subtract) \ |
| 612 V(Multiply) \ |
| 613 V(Divide) \ |
| 614 V(Modulus) |
| 615 |
| 616 |
| 617 #define TEST_FUNC(name) \ |
| 618 TEST_F(TyperTest, Monotonicity_##name) { \ |
| 619 TestBinaryMonotonicity(javascript_.name()); \ |
| 620 } |
| 621 JSBINOP_LIST(TEST_FUNC) |
| 622 #undef TEST_FUNC |
| OLD | NEW |