| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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 "src/compiler/operation-typer.h" | 5 #include "src/compiler/operation-typer.h" |
| 6 | 6 |
| 7 #include "src/factory.h" | 7 #include "src/factory.h" |
| 8 #include "src/isolate.h" | 8 #include "src/isolate.h" |
| 9 #include "src/type-cache.h" | 9 #include "src/type-cache.h" |
| 10 #include "src/types.h" | 10 #include "src/types.h" |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 if (type->Is(singleton_false_)) return cache_.kSingletonZero; | 278 if (type->Is(singleton_false_)) return cache_.kSingletonZero; |
| 279 if (type->Is(singleton_true_)) return cache_.kSingletonOne; | 279 if (type->Is(singleton_true_)) return cache_.kSingletonOne; |
| 280 if (type->Is(Type::Boolean())) return cache_.kZeroOrOne; | 280 if (type->Is(Type::Boolean())) return cache_.kZeroOrOne; |
| 281 if (type->Is(Type::BooleanOrNumber())) { | 281 if (type->Is(Type::BooleanOrNumber())) { |
| 282 return Type::Union(Type::Intersect(type, Type::Number(), zone()), | 282 return Type::Union(Type::Intersect(type, Type::Number(), zone()), |
| 283 cache_.kZeroOrOne, zone()); | 283 cache_.kZeroOrOne, zone()); |
| 284 } | 284 } |
| 285 return Type::Number(); | 285 return Type::Number(); |
| 286 } | 286 } |
| 287 | 287 |
| 288 Type* OperationTyper::NumericAdd(Type* lhs, Type* rhs) { | 288 Type* OperationTyper::NumberAdd(Type* lhs, Type* rhs) { |
| 289 DCHECK(lhs->Is(Type::Number())); | 289 DCHECK(lhs->Is(Type::Number())); |
| 290 DCHECK(rhs->Is(Type::Number())); | 290 DCHECK(rhs->Is(Type::Number())); |
| 291 | 291 |
| 292 if (!lhs->IsInhabited() || !rhs->IsInhabited()) { | 292 if (!lhs->IsInhabited() || !rhs->IsInhabited()) { |
| 293 return Type::None(); | 293 return Type::None(); |
| 294 } | 294 } |
| 295 | 295 |
| 296 // We can give more precise types for integers. | 296 // We can give more precise types for integers. |
| 297 if (!lhs->Is(cache_.kIntegerOrMinusZeroOrNaN) || | 297 if (!lhs->Is(cache_.kIntegerOrMinusZeroOrNaN) || |
| 298 !rhs->Is(cache_.kIntegerOrMinusZeroOrNaN)) { | 298 !rhs->Is(cache_.kIntegerOrMinusZeroOrNaN)) { |
| 299 return Type::Number(); | 299 return Type::Number(); |
| 300 } | 300 } |
| 301 Type* int_lhs = Type::Intersect(lhs, cache_.kInteger, zone()); | 301 Type* int_lhs = Type::Intersect(lhs, cache_.kInteger, zone()); |
| 302 Type* int_rhs = Type::Intersect(rhs, cache_.kInteger, zone()); | 302 Type* int_rhs = Type::Intersect(rhs, cache_.kInteger, zone()); |
| 303 Type* result = | 303 Type* result = |
| 304 AddRanger(int_lhs->Min(), int_lhs->Max(), int_rhs->Min(), int_rhs->Max()); | 304 AddRanger(int_lhs->Min(), int_lhs->Max(), int_rhs->Min(), int_rhs->Max()); |
| 305 if (lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN())) { | 305 if (lhs->Maybe(Type::NaN()) || rhs->Maybe(Type::NaN())) { |
| 306 result = Type::Union(result, Type::NaN(), zone()); | 306 result = Type::Union(result, Type::NaN(), zone()); |
| 307 } | 307 } |
| 308 if (lhs->Maybe(Type::MinusZero()) && rhs->Maybe(Type::MinusZero())) { | 308 if (lhs->Maybe(Type::MinusZero()) && rhs->Maybe(Type::MinusZero())) { |
| 309 result = Type::Union(result, Type::MinusZero(), zone()); | 309 result = Type::Union(result, Type::MinusZero(), zone()); |
| 310 } | 310 } |
| 311 return result; | 311 return result; |
| 312 } | 312 } |
| 313 | 313 |
| 314 Type* OperationTyper::NumericSubtract(Type* lhs, Type* rhs) { | 314 Type* OperationTyper::NumberSubtract(Type* lhs, Type* rhs) { |
| 315 DCHECK(lhs->Is(Type::Number())); | 315 DCHECK(lhs->Is(Type::Number())); |
| 316 DCHECK(rhs->Is(Type::Number())); | 316 DCHECK(rhs->Is(Type::Number())); |
| 317 | 317 |
| 318 if (!lhs->IsInhabited() || !rhs->IsInhabited()) { | 318 if (!lhs->IsInhabited() || !rhs->IsInhabited()) { |
| 319 return Type::None(); | 319 return Type::None(); |
| 320 } | 320 } |
| 321 | 321 |
| 322 lhs = Rangify(lhs); | 322 lhs = Rangify(lhs); |
| 323 rhs = Rangify(rhs); | 323 rhs = Rangify(rhs); |
| 324 if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); | 324 if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); |
| 325 if (lhs->IsRange() && rhs->IsRange()) { | 325 if (lhs->IsRange() && rhs->IsRange()) { |
| 326 return SubtractRanger(lhs->AsRange(), rhs->AsRange()); | 326 return SubtractRanger(lhs->AsRange(), rhs->AsRange()); |
| 327 } | 327 } |
| 328 // TODO(neis): Deal with numeric bitsets here and elsewhere. | 328 // TODO(neis): Deal with numeric bitsets here and elsewhere. |
| 329 return Type::Number(); | 329 return Type::Number(); |
| 330 } | 330 } |
| 331 | 331 |
| 332 Type* OperationTyper::NumericMultiply(Type* lhs, Type* rhs) { | 332 Type* OperationTyper::NumberMultiply(Type* lhs, Type* rhs) { |
| 333 DCHECK(lhs->Is(Type::Number())); | 333 DCHECK(lhs->Is(Type::Number())); |
| 334 DCHECK(rhs->Is(Type::Number())); | 334 DCHECK(rhs->Is(Type::Number())); |
| 335 | 335 |
| 336 if (!lhs->IsInhabited() || !rhs->IsInhabited()) { | 336 if (!lhs->IsInhabited() || !rhs->IsInhabited()) { |
| 337 return Type::None(); | 337 return Type::None(); |
| 338 } | 338 } |
| 339 | 339 |
| 340 lhs = Rangify(lhs); | 340 lhs = Rangify(lhs); |
| 341 rhs = Rangify(rhs); | 341 rhs = Rangify(rhs); |
| 342 if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); | 342 if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); |
| 343 if (lhs->IsRange() && rhs->IsRange()) { | 343 if (lhs->IsRange() && rhs->IsRange()) { |
| 344 return MultiplyRanger(lhs, rhs); | 344 return MultiplyRanger(lhs, rhs); |
| 345 } | 345 } |
| 346 return Type::Number(); | 346 return Type::Number(); |
| 347 } | 347 } |
| 348 | 348 |
| 349 Type* OperationTyper::NumericDivide(Type* lhs, Type* rhs) { | 349 Type* OperationTyper::NumberDivide(Type* lhs, Type* rhs) { |
| 350 DCHECK(lhs->Is(Type::Number())); | 350 DCHECK(lhs->Is(Type::Number())); |
| 351 DCHECK(rhs->Is(Type::Number())); | 351 DCHECK(rhs->Is(Type::Number())); |
| 352 | 352 |
| 353 if (!lhs->IsInhabited() || !rhs->IsInhabited()) { | 353 if (!lhs->IsInhabited() || !rhs->IsInhabited()) { |
| 354 return Type::None(); | 354 return Type::None(); |
| 355 } | 355 } |
| 356 | 356 |
| 357 if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); | 357 if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); |
| 358 // Division is tricky, so all we do is try ruling out nan. | 358 // Division is tricky, so all we do is try ruling out nan. |
| 359 bool maybe_nan = | 359 bool maybe_nan = |
| 360 lhs->Maybe(Type::NaN()) || rhs->Maybe(cache_.kZeroish) || | 360 lhs->Maybe(Type::NaN()) || rhs->Maybe(cache_.kZeroish) || |
| 361 ((lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) && | 361 ((lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) && |
| 362 (rhs->Min() == -V8_INFINITY || rhs->Max() == +V8_INFINITY)); | 362 (rhs->Min() == -V8_INFINITY || rhs->Max() == +V8_INFINITY)); |
| 363 return maybe_nan ? Type::Number() : Type::OrderedNumber(); | 363 return maybe_nan ? Type::Number() : Type::OrderedNumber(); |
| 364 } | 364 } |
| 365 | 365 |
| 366 Type* OperationTyper::NumericModulus(Type* lhs, Type* rhs) { | 366 Type* OperationTyper::NumberModulus(Type* lhs, Type* rhs) { |
| 367 DCHECK(lhs->Is(Type::Number())); | 367 DCHECK(lhs->Is(Type::Number())); |
| 368 DCHECK(rhs->Is(Type::Number())); | 368 DCHECK(rhs->Is(Type::Number())); |
| 369 | 369 |
| 370 if (!lhs->IsInhabited() || !rhs->IsInhabited()) { | 370 if (!lhs->IsInhabited() || !rhs->IsInhabited()) { |
| 371 return Type::None(); | 371 return Type::None(); |
| 372 } | 372 } |
| 373 | 373 |
| 374 if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); | 374 if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN(); |
| 375 | 375 |
| 376 if (lhs->Maybe(Type::NaN()) || rhs->Maybe(cache_.kZeroish) || | 376 if (lhs->Maybe(Type::NaN()) || rhs->Maybe(cache_.kZeroish) || |
| 377 lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) { | 377 lhs->Min() == -V8_INFINITY || lhs->Max() == +V8_INFINITY) { |
| 378 // Result maybe NaN. | 378 // Result maybe NaN. |
| 379 return Type::Number(); | 379 return Type::Number(); |
| 380 } | 380 } |
| 381 | 381 |
| 382 lhs = Rangify(lhs); | 382 lhs = Rangify(lhs); |
| 383 rhs = Rangify(rhs); | 383 rhs = Rangify(rhs); |
| 384 if (lhs->IsRange() && rhs->IsRange()) { | 384 if (lhs->IsRange() && rhs->IsRange()) { |
| 385 return ModulusRanger(lhs->AsRange(), rhs->AsRange()); | 385 return ModulusRanger(lhs->AsRange(), rhs->AsRange()); |
| 386 } | 386 } |
| 387 return Type::OrderedNumber(); | 387 return Type::OrderedNumber(); |
| 388 } | 388 } |
| 389 | 389 |
| 390 Type* OperationTyper::NumberAbs(Type* type) { |
| 391 DCHECK(type->Is(Type::Number())); |
| 392 |
| 393 if (!type->IsInhabited()) { |
| 394 return Type::None(); |
| 395 } |
| 396 |
| 397 bool const maybe_nan = type->Maybe(Type::NaN()); |
| 398 bool const maybe_minuszero = type->Maybe(Type::MinusZero()); |
| 399 type = Type::Intersect(type, Type::PlainNumber(), zone()); |
| 400 double const max = type->Max(); |
| 401 double const min = type->Min(); |
| 402 if (min < 0) { |
| 403 if (type->Is(cache_.kInteger)) { |
| 404 type = Type::Range(0.0, std::max(std::fabs(min), std::fabs(max)), zone()); |
| 405 } else { |
| 406 type = Type::PlainNumber(); |
| 407 } |
| 408 } |
| 409 if (maybe_minuszero) { |
| 410 type = Type::Union(type, cache_.kSingletonZero, zone()); |
| 411 } |
| 412 if (maybe_nan) { |
| 413 type = Type::Union(type, Type::NaN(), zone()); |
| 414 } |
| 415 return type; |
| 416 } |
| 417 |
| 390 Type* OperationTyper::ToPrimitive(Type* type) { | 418 Type* OperationTyper::ToPrimitive(Type* type) { |
| 391 if (type->Is(Type::Primitive()) && !type->Maybe(Type::Receiver())) { | 419 if (type->Is(Type::Primitive()) && !type->Maybe(Type::Receiver())) { |
| 392 return type; | 420 return type; |
| 393 } | 421 } |
| 394 return Type::Primitive(); | 422 return Type::Primitive(); |
| 395 } | 423 } |
| 396 | 424 |
| 397 Type* OperationTyper::Invert(Type* type) { | 425 Type* OperationTyper::Invert(Type* type) { |
| 398 DCHECK(type->Is(Type::Boolean())); | 426 DCHECK(type->Is(Type::Boolean())); |
| 399 DCHECK(type->IsInhabited()); | 427 DCHECK(type->IsInhabited()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 | 460 |
| 433 if (lhs->Maybe(Type::String()) || rhs->Maybe(Type::String())) { | 461 if (lhs->Maybe(Type::String()) || rhs->Maybe(Type::String())) { |
| 434 if (lhs->Is(Type::String()) || rhs->Is(Type::String())) { | 462 if (lhs->Is(Type::String()) || rhs->Is(Type::String())) { |
| 435 return Type::String(); | 463 return Type::String(); |
| 436 } else { | 464 } else { |
| 437 return Type::NumberOrString(); | 465 return Type::NumberOrString(); |
| 438 } | 466 } |
| 439 } | 467 } |
| 440 lhs = ToNumber(lhs); | 468 lhs = ToNumber(lhs); |
| 441 rhs = ToNumber(rhs); | 469 rhs = ToNumber(rhs); |
| 442 return NumericAdd(lhs, rhs); | 470 return NumberAdd(lhs, rhs); |
| 443 } | 471 } |
| 444 | 472 |
| 445 Type* OperationTyper::TypeJSSubtract(Type* lhs, Type* rhs) { | 473 Type* OperationTyper::TypeJSSubtract(Type* lhs, Type* rhs) { |
| 446 return NumericSubtract(ToNumber(lhs), ToNumber(rhs)); | 474 return NumberSubtract(ToNumber(lhs), ToNumber(rhs)); |
| 447 } | 475 } |
| 448 | 476 |
| 449 } // namespace compiler | 477 } // namespace compiler |
| 450 } // namespace internal | 478 } // namespace internal |
| 451 } // namespace v8 | 479 } // namespace v8 |
| OLD | NEW |