1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "factory.h" 31 #include "hydrogen.h" 32 33 #if V8_TARGET_ARCH_IA32 34 #include "ia32/lithium-ia32.h" 35 #elif V8_TARGET_ARCH_X64 36 #include "x64/lithium-x64.h" 37 #elif V8_TARGET_ARCH_ARM 38 #include "arm/lithium-arm.h" 39 #elif V8_TARGET_ARCH_MIPS 40 #include "mips/lithium-mips.h" 41 #else 42 #error Unsupported target architecture. 43 #endif 44 45 namespace v8 { 46 namespace internal { 47 48 #define DEFINE_COMPILE(type) \ 49 LInstruction* H##type::CompileToLithium(LChunkBuilder* builder) { \ 50 return builder->Do##type(this); \ 51 } 52 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) 53 #undef DEFINE_COMPILE 54 55 56 const char* Representation::Mnemonic() const { 57 switch (kind_) { 58 case kNone: return "v"; 59 case kTagged: return "t"; 60 case kDouble: return "d"; 61 case kInteger32: return "i"; 62 case kExternal: return "x"; 63 case kNumRepresentations: 64 UNREACHABLE(); 65 return NULL; 66 } 67 UNREACHABLE(); 68 return NULL; 69 } 70 71 72 static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) { 73 if (result > kMaxInt) { 74 *overflow = true; 75 return kMaxInt; 76 } 77 if (result < kMinInt) { 78 *overflow = true; 79 return kMinInt; 80 } 81 return static_cast<int32_t>(result); 82 } 83 84 85 static int32_t AddWithoutOverflow(int32_t a, int32_t b, bool* overflow) { 86 int64_t result = static_cast<int64_t>(a) + static_cast<int64_t>(b); 87 return ConvertAndSetOverflow(result, overflow); 88 } 89 90 91 static int32_t SubWithoutOverflow(int32_t a, int32_t b, bool* overflow) { 92 int64_t result = static_cast<int64_t>(a) - static_cast<int64_t>(b); 93 return ConvertAndSetOverflow(result, overflow); 94 } 95 96 97 static int32_t MulWithoutOverflow(int32_t a, int32_t b, bool* overflow) { 98 int64_t result = static_cast<int64_t>(a) * static_cast<int64_t>(b); 99 return ConvertAndSetOverflow(result, overflow); 100 } 101 102 103 int32_t Range::Mask() const { 104 if (lower_ == upper_) return lower_; 105 if (lower_ >= 0) { 106 int32_t res = 1; 107 while (res < upper_) { 108 res = (res << 1) | 1; 109 } 110 return res; 111 } 112 return 0xffffffff; 113 } 114 115 116 void Range::AddConstant(int32_t value) { 117 if (value == 0) return; 118 bool may_overflow = false; // Overflow is ignored here. 119 lower_ = AddWithoutOverflow(lower_, value, &may_overflow); 120 upper_ = AddWithoutOverflow(upper_, value, &may_overflow); 121 Verify(); 122 } 123 124 125 void Range::Intersect(Range* other) { 126 upper_ = Min(upper_, other->upper_); 127 lower_ = Max(lower_, other->lower_); 128 bool b = CanBeMinusZero() && other->CanBeMinusZero(); 129 set_can_be_minus_zero(b); 130 } 131 132 133 void Range::Union(Range* other) { 134 upper_ = Max(upper_, other->upper_); 135 lower_ = Min(lower_, other->lower_); 136 bool b = CanBeMinusZero() || other->CanBeMinusZero(); 137 set_can_be_minus_zero(b); 138 } 139 140 141 void Range::Sar(int32_t value) { 142 int32_t bits = value & 0x1F; 143 lower_ = lower_ >> bits; 144 upper_ = upper_ >> bits; 145 set_can_be_minus_zero(false); 146 } 147 148 149 void Range::Shl(int32_t value) { 150 int32_t bits = value & 0x1F; 151 int old_lower = lower_; 152 int old_upper = upper_; 153 lower_ = lower_ << bits; 154 upper_ = upper_ << bits; 155 if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) { 156 upper_ = kMaxInt; 157 lower_ = kMinInt; 158 } 159 set_can_be_minus_zero(false); 160 } 161 162 163 bool Range::AddAndCheckOverflow(Range* other) { 164 bool may_overflow = false; 165 lower_ = AddWithoutOverflow(lower_, other->lower(), &may_overflow); 166 upper_ = AddWithoutOverflow(upper_, other->upper(), &may_overflow); 167 KeepOrder(); 168 Verify(); 169 return may_overflow; 170 } 171 172 173 bool Range::SubAndCheckOverflow(Range* other) { 174 bool may_overflow = false; 175 lower_ = SubWithoutOverflow(lower_, other->upper(), &may_overflow); 176 upper_ = SubWithoutOverflow(upper_, other->lower(), &may_overflow); 177 KeepOrder(); 178 Verify(); 179 return may_overflow; 180 } 181 182 183 void Range::KeepOrder() { 184 if (lower_ > upper_) { 185 int32_t tmp = lower_; 186 lower_ = upper_; 187 upper_ = tmp; 188 } 189 } 190 191 192 void Range::Verify() const { 193 ASSERT(lower_ <= upper_); 194 } 195 196 197 bool Range::MulAndCheckOverflow(Range* other) { 198 bool may_overflow = false; 199 int v1 = MulWithoutOverflow(lower_, other->lower(), &may_overflow); 200 int v2 = MulWithoutOverflow(lower_, other->upper(), &may_overflow); 201 int v3 = MulWithoutOverflow(upper_, other->lower(), &may_overflow); 202 int v4 = MulWithoutOverflow(upper_, other->upper(), &may_overflow); 203 lower_ = Min(Min(v1, v2), Min(v3, v4)); 204 upper_ = Max(Max(v1, v2), Max(v3, v4)); 205 Verify(); 206 return may_overflow; 207 } 208 209 210 const char* HType::ToString() { 211 switch (type_) { 212 case kTagged: return "tagged"; 213 case kTaggedPrimitive: return "primitive"; 214 case kTaggedNumber: return "number"; 215 case kSmi: return "smi"; 216 case kHeapNumber: return "heap-number"; 217 case kString: return "string"; 218 case kBoolean: return "boolean"; 219 case kNonPrimitive: return "non-primitive"; 220 case kJSArray: return "array"; 221 case kJSObject: return "object"; 222 case kUninitialized: return "uninitialized"; 223 } 224 UNREACHABLE(); 225 return "Unreachable code"; 226 } 227 228 229 const char* HType::ToShortString() { 230 switch (type_) { 231 case kTagged: return "t"; 232 case kTaggedPrimitive: return "p"; 233 case kTaggedNumber: return "n"; 234 case kSmi: return "m"; 235 case kHeapNumber: return "h"; 236 case kString: return "s"; 237 case kBoolean: return "b"; 238 case kNonPrimitive: return "r"; 239 case kJSArray: return "a"; 240 case kJSObject: return "o"; 241 case kUninitialized: return "z"; 242 } 243 UNREACHABLE(); 244 return "Unreachable code"; 245 } 246 247 248 HType HType::TypeFromValue(Handle<Object> value) { 249 HType result = HType::Tagged(); 250 if (value->IsSmi()) { 251 result = HType::Smi(); 252 } else if (value->IsHeapNumber()) { 253 result = HType::HeapNumber(); 254 } else if (value->IsString()) { 255 result = HType::String(); 256 } else if (value->IsBoolean()) { 257 result = HType::Boolean(); 258 } else if (value->IsJSObject()) { 259 result = HType::JSObject(); 260 } else if (value->IsJSArray()) { 261 result = HType::JSArray(); 262 } 263 return result; 264 } 265 266 267 int HValue::LookupOperandIndex(int occurrence_index, HValue* op) { 268 for (int i = 0; i < OperandCount(); ++i) { 269 if (OperandAt(i) == op) { 270 if (occurrence_index == 0) return i; 271 --occurrence_index; 272 } 273 } 274 return -1; 275 } 276 277 278 bool HValue::IsDefinedAfter(HBasicBlock* other) const { 279 return block()->block_id() > other->block_id(); 280 } 281 282 283 bool HValue::UsesMultipleTimes(HValue* op) { 284 bool seen = false; 285 for (int i = 0; i < OperandCount(); ++i) { 286 if (OperandAt(i) == op) { 287 if (seen) return true; 288 seen = true; 289 } 290 } 291 return false; 292 } 293 294 295 bool HValue::Equals(HValue* other) { 296 if (other->opcode() != opcode()) return false; 297 if (!other->representation().Equals(representation())) return false; 298 if (!other->type_.Equals(type_)) return false; 299 if (other->flags() != flags()) return false; 300 if (OperandCount() != other->OperandCount()) return false; 301 for (int i = 0; i < OperandCount(); ++i) { 302 if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false; 303 } 304 bool result = DataEquals(other); 305 ASSERT(!result || Hashcode() == other->Hashcode()); 306 return result; 307 } 308 309 310 intptr_t HValue::Hashcode() { 311 intptr_t result = opcode(); 312 int count = OperandCount(); 313 for (int i = 0; i < count; ++i) { 314 result = result * 19 + OperandAt(i)->id() + (result >> 7); 315 } 316 return result; 317 } 318 319 320 void HValue::SetOperandAt(int index, HValue* value) { 321 ASSERT(value == NULL || !value->representation().IsNone()); 322 RegisterUse(index, value); 323 InternalSetOperandAt(index, value); 324 } 325 326 327 void HValue::ReplaceAndDelete(HValue* other) { 328 if (other != NULL) ReplaceValue(other); 329 Delete(); 330 } 331 332 333 void HValue::ReplaceValue(HValue* other) { 334 for (int i = 0; i < uses_.length(); ++i) { 335 HValue* use = uses_[i]; 336 ASSERT(!use->block()->IsStartBlock()); 337 InternalReplaceAtUse(use, other); 338 other->uses_.Add(use); 339 } 340 uses_.Rewind(0); 341 } 342 343 344 void HValue::ClearOperands() { 345 for (int i = 0; i < OperandCount(); ++i) { 346 SetOperandAt(i, NULL); 347 } 348 } 349 350 351 void HValue::Delete() { 352 ASSERT(HasNoUses()); 353 ClearOperands(); 354 DeleteFromGraph(); 355 } 356 357 358 void HValue::ReplaceAtUse(HValue* use, HValue* other) { 359 for (int i = 0; i < use->OperandCount(); ++i) { 360 if (use->OperandAt(i) == this) { 361 use->SetOperandAt(i, other); 362 } 363 } 364 } 365 366 367 void HValue::ReplaceFirstAtUse(HValue* use, HValue* other, Representation r) { 368 for (int i = 0; i < use->OperandCount(); ++i) { 369 if (use->RequiredInputRepresentation(i).Equals(r) && 370 use->OperandAt(i) == this) { 371 use->SetOperandAt(i, other); 372 return; 373 } 374 } 375 } 376 377 378 void HValue::InternalReplaceAtUse(HValue* use, HValue* other) { 379 for (int i = 0; i < use->OperandCount(); ++i) { 380 if (use->OperandAt(i) == this) { 381 // Call internal method that does not update use lists. The caller is 382 // responsible for doing so. 383 use->InternalSetOperandAt(i, other); 384 } 385 } 386 } 387 388 389 void HValue::SetBlock(HBasicBlock* block) { 390 ASSERT(block_ == NULL || block == NULL); 391 block_ = block; 392 if (id_ == kNoNumber && block != NULL) { 393 id_ = block->graph()->GetNextValueID(this); 394 } 395 } 396 397 398 void HValue::PrintTypeTo(HType type, StringStream* stream) { 399 stream->Add(type.ToShortString()); 400 } 401 402 403 void HValue::PrintNameTo(StringStream* stream) { 404 stream->Add("%s%d", representation_.Mnemonic(), id()); 405 } 406 407 408 bool HValue::UpdateInferredType() { 409 HType type = CalculateInferredType(); 410 bool result = (!type.Equals(type_)); 411 type_ = type; 412 return result; 413 } 414 415 416 void HValue::RegisterUse(int index, HValue* new_value) { 417 HValue* old_value = OperandAt(index); 418 if (old_value == new_value) return; 419 if (old_value != NULL) old_value->uses_.RemoveElement(this); 420 if (new_value != NULL) { 421 new_value->uses_.Add(this); 422 } 423 } 424 425 426 void HValue::AddNewRange(Range* r) { 427 if (!HasRange()) ComputeInitialRange(); 428 if (!HasRange()) range_ = new Range(); 429 ASSERT(HasRange()); 430 r->StackUpon(range_); 431 range_ = r; 432 } 433 434 435 void HValue::RemoveLastAddedRange() { 436 ASSERT(HasRange()); 437 ASSERT(range_->next() != NULL); 438 range_ = range_->next(); 439 } 440 441 442 void HValue::ComputeInitialRange() { 443 ASSERT(!HasRange()); 444 range_ = InferRange(); 445 ASSERT(HasRange()); 446 } 447 448 449 void HInstruction::PrintTo(StringStream* stream) { 450 stream->Add("%s", Mnemonic()); 451 if (HasSideEffects()) stream->Add("*"); 452 stream->Add(" "); 453 PrintDataTo(stream); 454 455 if (range() != NULL && 456 !range()->IsMostGeneric() && 457 !range()->CanBeMinusZero()) { 458 stream->Add(" range[%d,%d,m0=%d]", 459 range()->lower(), 460 range()->upper(), 461 static_cast<int>(range()->CanBeMinusZero())); 462 } 463 464 int changes_flags = (flags() & HValue::ChangesFlagsMask()); 465 if (changes_flags != 0) { 466 stream->Add(" changes[0x%x]", changes_flags); 467 } 468 469 if (representation().IsTagged() && !type().Equals(HType::Tagged())) { 470 stream->Add(" type[%s]", type().ToString()); 471 } 472 } 473 474 475 void HInstruction::Unlink() { 476 ASSERT(IsLinked()); 477 ASSERT(!IsControlInstruction()); // Must never move control instructions. 478 ASSERT(!IsBlockEntry()); // Doesn't make sense to delete these. 479 ASSERT(previous_ != NULL); 480 previous_->next_ = next_; 481 if (next_ == NULL) { 482 ASSERT(block()->last() == this); 483 block()->set_last(previous_); 484 } else { 485 next_->previous_ = previous_; 486 } 487 clear_block(); 488 } 489 490 491 void HInstruction::InsertBefore(HInstruction* next) { 492 ASSERT(!IsLinked()); 493 ASSERT(!next->IsBlockEntry()); 494 ASSERT(!IsControlInstruction()); 495 ASSERT(!next->block()->IsStartBlock()); 496 ASSERT(next->previous_ != NULL); 497 HInstruction* prev = next->previous(); 498 prev->next_ = this; 499 next->previous_ = this; 500 next_ = next; 501 previous_ = prev; 502 SetBlock(next->block()); 503 } 504 505 506 void HInstruction::InsertAfter(HInstruction* previous) { 507 ASSERT(!IsLinked()); 508 ASSERT(!previous->IsControlInstruction()); 509 ASSERT(!IsControlInstruction() || previous->next_ == NULL); 510 HBasicBlock* block = previous->block(); 511 // Never insert anything except constants into the start block after finishing 512 // it. 513 if (block->IsStartBlock() && block->IsFinished() && !IsConstant()) { 514 ASSERT(block->end()->SecondSuccessor() == NULL); 515 InsertAfter(block->end()->FirstSuccessor()->first()); 516 return; 517 } 518 519 // If we're inserting after an instruction with side-effects that is 520 // followed by a simulate instruction, we need to insert after the 521 // simulate instruction instead. 522 HInstruction* next = previous->next_; 523 if (previous->HasSideEffects() && next != NULL) { 524 ASSERT(next->IsSimulate()); 525 previous = next; 526 next = previous->next_; 527 } 528 529 previous_ = previous; 530 next_ = next; 531 SetBlock(block); 532 previous->next_ = this; 533 if (next != NULL) next->previous_ = this; 534 } 535 536 537 #ifdef DEBUG 538 void HInstruction::Verify() { 539 // Verify that input operands are defined before use. 540 HBasicBlock* cur_block = block(); 541 for (int i = 0; i < OperandCount(); ++i) { 542 HValue* other_operand = OperandAt(i); 543 HBasicBlock* other_block = other_operand->block(); 544 if (cur_block == other_block) { 545 if (!other_operand->IsPhi()) { 546 HInstruction* cur = cur_block->first(); 547 while (cur != NULL) { 548 ASSERT(cur != this); // We should reach other_operand before! 549 if (cur == other_operand) break; 550 cur = cur->next(); 551 } 552 // Must reach other operand in the same block! 553 ASSERT(cur == other_operand); 554 } 555 } else { 556 ASSERT(other_block->Dominates(cur_block)); 557 } 558 } 559 560 // Verify that instructions that may have side-effects are followed 561 // by a simulate instruction. 562 if (HasSideEffects() && !IsOsrEntry()) { 563 ASSERT(next()->IsSimulate()); 564 } 565 566 // Verify that instructions that can be eliminated by GVN have overridden 567 // HValue::DataEquals. The default implementation is UNREACHABLE. We 568 // don't actually care whether DataEquals returns true or false here. 569 if (CheckFlag(kUseGVN)) DataEquals(this); 570 } 571 #endif 572 573 574 void HUnaryCall::PrintDataTo(StringStream* stream) { 575 value()->PrintNameTo(stream); 576 stream->Add(" "); 577 stream->Add("#%d", argument_count()); 578 } 579 580 581 void HBinaryCall::PrintDataTo(StringStream* stream) { 582 first()->PrintNameTo(stream); 583 stream->Add(" "); 584 second()->PrintNameTo(stream); 585 stream->Add(" "); 586 stream->Add("#%d", argument_count()); 587 } 588 589 590 void HCallConstantFunction::PrintDataTo(StringStream* stream) { 591 if (IsApplyFunction()) { 592 stream->Add("optimized apply "); 593 } else { 594 stream->Add("%o ", function()->shared()->DebugName()); 595 } 596 stream->Add("#%d", argument_count()); 597 } 598 599 600 void HCallNamed::PrintDataTo(StringStream* stream) { 601 stream->Add("%o ", *name()); 602 HUnaryCall::PrintDataTo(stream); 603 } 604 605 606 void HCallGlobal::PrintDataTo(StringStream* stream) { 607 stream->Add("%o ", *name()); 608 HUnaryCall::PrintDataTo(stream); 609 } 610 611 612 void HCallKnownGlobal::PrintDataTo(StringStream* stream) { 613 stream->Add("o ", target()->shared()->DebugName()); 614 stream->Add("#%d", argument_count()); 615 } 616 617 618 void HCallRuntime::PrintDataTo(StringStream* stream) { 619 stream->Add("%o ", *name()); 620 stream->Add("#%d", argument_count()); 621 } 622 623 624 void HClassOfTest::PrintDataTo(StringStream* stream) { 625 stream->Add("class_of_test("); 626 value()->PrintNameTo(stream); 627 stream->Add(", \"%o\")", *class_name()); 628 } 629 630 631 void HAccessArgumentsAt::PrintDataTo(StringStream* stream) { 632 arguments()->PrintNameTo(stream); 633 stream->Add("["); 634 index()->PrintNameTo(stream); 635 stream->Add("], length "); 636 length()->PrintNameTo(stream); 637 } 638 639 640 void HControlInstruction::PrintDataTo(StringStream* stream) { 641 if (FirstSuccessor() != NULL) { 642 int first_id = FirstSuccessor()->block_id(); 643 if (SecondSuccessor() == NULL) { 644 stream->Add(" B%d", first_id); 645 } else { 646 int second_id = SecondSuccessor()->block_id(); 647 stream->Add(" goto (B%d, B%d)", first_id, second_id); 648 } 649 } 650 } 651 652 653 void HUnaryControlInstruction::PrintDataTo(StringStream* stream) { 654 value()->PrintNameTo(stream); 655 HControlInstruction::PrintDataTo(stream); 656 } 657 658 659 void HCompareMap::PrintDataTo(StringStream* stream) { 660 value()->PrintNameTo(stream); 661 stream->Add(" (%p)", *map()); 662 HControlInstruction::PrintDataTo(stream); 663 } 664 665 666 const char* HUnaryMathOperation::OpName() const { 667 switch (op()) { 668 case kMathFloor: return "floor"; 669 case kMathRound: return "round"; 670 case kMathCeil: return "ceil"; 671 case kMathAbs: return "abs"; 672 case kMathLog: return "log"; 673 case kMathSin: return "sin"; 674 case kMathCos: return "cos"; 675 case kMathTan: return "tan"; 676 case kMathASin: return "asin"; 677 case kMathACos: return "acos"; 678 case kMathATan: return "atan"; 679 case kMathExp: return "exp"; 680 case kMathSqrt: return "sqrt"; 681 default: break; 682 } 683 return "(unknown operation)"; 684 } 685 686 687 void HUnaryMathOperation::PrintDataTo(StringStream* stream) { 688 const char* name = OpName(); 689 stream->Add("%s ", name); 690 value()->PrintNameTo(stream); 691 } 692 693 694 void HUnaryOperation::PrintDataTo(StringStream* stream) { 695 value()->PrintNameTo(stream); 696 } 697 698 699 void HHasInstanceType::PrintDataTo(StringStream* stream) { 700 value()->PrintNameTo(stream); 701 switch (from_) { 702 case FIRST_JS_OBJECT_TYPE: 703 if (to_ == LAST_TYPE) stream->Add(" spec_object"); 704 break; 705 case JS_REGEXP_TYPE: 706 if (to_ == JS_REGEXP_TYPE) stream->Add(" reg_exp"); 707 break; 708 case JS_ARRAY_TYPE: 709 if (to_ == JS_ARRAY_TYPE) stream->Add(" array"); 710 break; 711 case JS_FUNCTION_TYPE: 712 if (to_ == JS_FUNCTION_TYPE) stream->Add(" function"); 713 break; 714 default: 715 break; 716 } 717 } 718 719 720 void HTypeofIs::PrintDataTo(StringStream* stream) { 721 value()->PrintNameTo(stream); 722 stream->Add(" == "); 723 stream->Add(type_literal_->ToAsciiVector()); 724 } 725 726 727 void HChange::PrintDataTo(StringStream* stream) { 728 HUnaryOperation::PrintDataTo(stream); 729 stream->Add(" %s to %s", from_.Mnemonic(), to().Mnemonic()); 730 731 if (CanTruncateToInt32()) stream->Add(" truncating-int32"); 732 if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?"); 733 } 734 735 736 HCheckInstanceType* HCheckInstanceType::NewIsJSObjectOrJSFunction( 737 HValue* value) { 738 STATIC_ASSERT((LAST_JS_OBJECT_TYPE + 1) == JS_FUNCTION_TYPE); 739 return new HCheckInstanceType(value, FIRST_JS_OBJECT_TYPE, JS_FUNCTION_TYPE); 740 } 741 742 743 void HCheckMap::PrintDataTo(StringStream* stream) { 744 value()->PrintNameTo(stream); 745 stream->Add(" %p", *map()); 746 } 747 748 749 void HCheckFunction::PrintDataTo(StringStream* stream) { 750 value()->PrintNameTo(stream); 751 stream->Add(" %p", *target()); 752 } 753 754 755 void HCallStub::PrintDataTo(StringStream* stream) { 756 stream->Add("%s ", 757 CodeStub::MajorName(major_key_, false)); 758 HUnaryCall::PrintDataTo(stream); 759 } 760 761 762 void HInstanceOf::PrintDataTo(StringStream* stream) { 763 left()->PrintNameTo(stream); 764 stream->Add(" "); 765 right()->PrintNameTo(stream); 766 stream->Add(" "); 767 context()->PrintNameTo(stream); 768 } 769 770 771 Range* HValue::InferRange() { 772 if (representation().IsTagged()) { 773 // Tagged values are always in int32 range when converted to integer, 774 // but they can contain -0. 775 Range* result = new Range(); 776 result->set_can_be_minus_zero(true); 777 return result; 778 } else if (representation().IsNone()) { 779 return NULL; 780 } else { 781 // Untagged integer32 cannot be -0 and we don't compute ranges for 782 // untagged doubles. 783 return new Range(); 784 } 785 } 786 787 788 Range* HConstant::InferRange() { 789 if (has_int32_value_) { 790 Range* result = new Range(int32_value_, int32_value_); 791 result->set_can_be_minus_zero(false); 792 return result; 793 } 794 return HValue::InferRange(); 795 } 796 797 798 Range* HPhi::InferRange() { 799 if (representation().IsInteger32()) { 800 if (block()->IsLoopHeader()) { 801 Range* range = new Range(kMinInt, kMaxInt); 802 return range; 803 } else { 804 Range* range = OperandAt(0)->range()->Copy(); 805 for (int i = 1; i < OperandCount(); ++i) { 806 range->Union(OperandAt(i)->range()); 807 } 808 return range; 809 } 810 } else { 811 return HValue::InferRange(); 812 } 813 } 814 815 816 Range* HAdd::InferRange() { 817 if (representation().IsInteger32()) { 818 Range* a = left()->range(); 819 Range* b = right()->range(); 820 Range* res = a->Copy(); 821 if (!res->AddAndCheckOverflow(b)) { 822 ClearFlag(kCanOverflow); 823 } 824 bool m0 = a->CanBeMinusZero() && b->CanBeMinusZero(); 825 res->set_can_be_minus_zero(m0); 826 return res; 827 } else { 828 return HValue::InferRange(); 829 } 830 } 831 832 833 Range* HSub::InferRange() { 834 if (representation().IsInteger32()) { 835 Range* a = left()->range(); 836 Range* b = right()->range(); 837 Range* res = a->Copy(); 838 if (!res->SubAndCheckOverflow(b)) { 839 ClearFlag(kCanOverflow); 840 } 841 res->set_can_be_minus_zero(a->CanBeMinusZero() && b->CanBeZero()); 842 return res; 843 } else { 844 return HValue::InferRange(); 845 } 846 } 847 848 849 Range* HMul::InferRange() { 850 if (representation().IsInteger32()) { 851 Range* a = left()->range(); 852 Range* b = right()->range(); 853 Range* res = a->Copy(); 854 if (!res->MulAndCheckOverflow(b)) { 855 ClearFlag(kCanOverflow); 856 } 857 bool m0 = (a->CanBeZero() && b->CanBeNegative()) || 858 (a->CanBeNegative() && b->CanBeZero()); 859 res->set_can_be_minus_zero(m0); 860 return res; 861 } else { 862 return HValue::InferRange(); 863 } 864 } 865 866 867 Range* HDiv::InferRange() { 868 if (representation().IsInteger32()) { 869 Range* result = new Range(); 870 if (left()->range()->CanBeMinusZero()) { 871 result->set_can_be_minus_zero(true); 872 } 873 874 if (left()->range()->CanBeZero() && right()->range()->CanBeNegative()) { 875 result->set_can_be_minus_zero(true); 876 } 877 878 if (right()->range()->Includes(-1) && left()->range()->Includes(kMinInt)) { 879 SetFlag(HValue::kCanOverflow); 880 } 881 882 if (!right()->range()->CanBeZero()) { 883 ClearFlag(HValue::kCanBeDivByZero); 884 } 885 return result; 886 } else { 887 return HValue::InferRange(); 888 } 889 } 890 891 892 Range* HMod::InferRange() { 893 if (representation().IsInteger32()) { 894 Range* a = left()->range(); 895 Range* result = new Range(); 896 if (a->CanBeMinusZero() || a->CanBeNegative()) { 897 result->set_can_be_minus_zero(true); 898 } 899 if (!right()->range()->CanBeZero()) { 900 ClearFlag(HValue::kCanBeDivByZero); 901 } 902 return result; 903 } else { 904 return HValue::InferRange(); 905 } 906 } 907 908 909 void HPhi::PrintTo(StringStream* stream) { 910 stream->Add("["); 911 for (int i = 0; i < OperandCount(); ++i) { 912 HValue* value = OperandAt(i); 913 stream->Add(" "); 914 value->PrintNameTo(stream); 915 stream->Add(" "); 916 } 917 stream->Add(" uses%d_%di_%dd_%dt]", 918 uses()->length(), 919 int32_non_phi_uses() + int32_indirect_uses(), 920 double_non_phi_uses() + double_indirect_uses(), 921 tagged_non_phi_uses() + tagged_indirect_uses()); 922 } 923 924 925 void HPhi::AddInput(HValue* value) { 926 inputs_.Add(NULL); 927 SetOperandAt(OperandCount() - 1, value); 928 // Mark phis that may have 'arguments' directly or indirectly as an operand. 929 if (!CheckFlag(kIsArguments) && value->CheckFlag(kIsArguments)) { 930 SetFlag(kIsArguments); 931 } 932 } 933 934 935 bool HPhi::HasRealUses() { 936 for (int i = 0; i < uses()->length(); i++) { 937 if (!uses()->at(i)->IsPhi()) return true; 938 } 939 return false; 940 } 941 942 943 HValue* HPhi::GetRedundantReplacement() { 944 HValue* candidate = NULL; 945 int count = OperandCount(); 946 int position = 0; 947 while (position < count && candidate == NULL) { 948 HValue* current = OperandAt(position++); 949 if (current != this) candidate = current; 950 } 951 while (position < count) { 952 HValue* current = OperandAt(position++); 953 if (current != this && current != candidate) return NULL; 954 } 955 ASSERT(candidate != this); 956 return candidate; 957 } 958 959 960 void HPhi::DeleteFromGraph() { 961 ASSERT(block() != NULL); 962 block()->RemovePhi(this); 963 ASSERT(block() == NULL); 964 } 965 966 967 void HPhi::InitRealUses(int phi_id) { 968 // Initialize real uses. 969 phi_id_ = phi_id; 970 for (int j = 0; j < uses()->length(); j++) { 971 HValue* use = uses()->at(j); 972 if (!use->IsPhi()) { 973 int index = use->LookupOperandIndex(0, this); 974 Representation req_rep = use->RequiredInputRepresentation(index); 975 non_phi_uses_[req_rep.kind()]++; 976 } 977 } 978 } 979 980 981 void HPhi::AddNonPhiUsesFrom(HPhi* other) { 982 for (int i = 0; i < Representation::kNumRepresentations; i++) { 983 indirect_uses_[i] += other->non_phi_uses_[i]; 984 } 985 } 986 987 988 void HPhi::AddIndirectUsesTo(int* dest) { 989 for (int i = 0; i < Representation::kNumRepresentations; i++) { 990 dest[i] += indirect_uses_[i]; 991 } 992 } 993 994 995 void HSimulate::PrintDataTo(StringStream* stream) { 996 stream->Add("id=%d ", ast_id()); 997 if (pop_count_ > 0) stream->Add("pop %d", pop_count_); 998 if (values_.length() > 0) { 999 if (pop_count_ > 0) stream->Add(" /"); 1000 for (int i = 0; i < values_.length(); ++i) { 1001 if (!HasAssignedIndexAt(i)) { 1002 stream->Add(" push "); 1003 } else { 1004 stream->Add(" var[%d] = ", GetAssignedIndexAt(i)); 1005 } 1006 values_[i]->PrintNameTo(stream); 1007 } 1008 } 1009 } 1010 1011 1012 void HEnterInlined::PrintDataTo(StringStream* stream) { 1013 SmartPointer<char> name = function()->debug_name()->ToCString(); 1014 stream->Add("%s, id=%d", *name, function()->id()); 1015 } 1016 1017 1018 HConstant::HConstant(Handle<Object> handle, Representation r) 1019 : handle_(handle), 1020 constant_type_(HType::TypeFromValue(handle)), 1021 has_int32_value_(false), 1022 int32_value_(0), 1023 has_double_value_(false), 1024 double_value_(0) { 1025 set_representation(r); 1026 SetFlag(kUseGVN); 1027 if (handle_->IsNumber()) { 1028 double n = handle_->Number(); 1029 double roundtrip_value = static_cast<double>(static_cast<int32_t>(n)); 1030 has_int32_value_ = BitCast<int64_t>(roundtrip_value) == BitCast<int64_t>(n); 1031 if (has_int32_value_) int32_value_ = static_cast<int32_t>(n); 1032 double_value_ = n; 1033 has_double_value_ = true; 1034 } 1035 } 1036 1037 1038 HConstant* HConstant::CopyToRepresentation(Representation r) const { 1039 if (r.IsInteger32() && !has_int32_value_) return NULL; 1040 if (r.IsDouble() && !has_double_value_) return NULL; 1041 return new HConstant(handle_, r); 1042 } 1043 1044 1045 HConstant* HConstant::CopyToTruncatedInt32() const { 1046 if (!has_double_value_) return NULL; 1047 int32_t truncated = NumberToInt32(*handle_); 1048 return new HConstant(FACTORY->NewNumberFromInt(truncated), 1049 Representation::Integer32()); 1050 } 1051 1052 1053 bool HConstant::ToBoolean() const { 1054 // Converts the constant's boolean value according to 1055 // ECMAScript section 9.2 ToBoolean conversion. 1056 if (HasInteger32Value()) return Integer32Value() != 0; 1057 if (HasDoubleValue()) { 1058 double v = DoubleValue(); 1059 return v != 0 && !isnan(v); 1060 } 1061 if (handle()->IsTrue()) return true; 1062 if (handle()->IsFalse()) return false; 1063 if (handle()->IsUndefined()) return false; 1064 if (handle()->IsNull()) return false; 1065 if (handle()->IsString() && 1066 String::cast(*handle())->length() == 0) return false; 1067 return true; 1068 } 1069 1070 void HConstant::PrintDataTo(StringStream* stream) { 1071 handle()->ShortPrint(stream); 1072 } 1073 1074 1075 bool HArrayLiteral::IsCopyOnWrite() const { 1076 return constant_elements()->map() == HEAP->fixed_cow_array_map(); 1077 } 1078 1079 1080 void HBinaryOperation::PrintDataTo(StringStream* stream) { 1081 left()->PrintNameTo(stream); 1082 stream->Add(" "); 1083 right()->PrintNameTo(stream); 1084 if (CheckFlag(kCanOverflow)) stream->Add(" !"); 1085 if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?"); 1086 } 1087 1088 1089 Range* HBitAnd::InferRange() { 1090 int32_t left_mask = (left()->range() != NULL) 1091 ? left()->range()->Mask() 1092 : 0xffffffff; 1093 int32_t right_mask = (right()->range() != NULL) 1094 ? right()->range()->Mask() 1095 : 0xffffffff; 1096 int32_t result_mask = left_mask & right_mask; 1097 return (result_mask >= 0) 1098 ? new Range(0, result_mask) 1099 : HValue::InferRange(); 1100 } 1101 1102 1103 Range* HBitOr::InferRange() { 1104 int32_t left_mask = (left()->range() != NULL) 1105 ? left()->range()->Mask() 1106 : 0xffffffff; 1107 int32_t right_mask = (right()->range() != NULL) 1108 ? right()->range()->Mask() 1109 : 0xffffffff; 1110 int32_t result_mask = left_mask | right_mask; 1111 return (result_mask >= 0) 1112 ? new Range(0, result_mask) 1113 : HValue::InferRange(); 1114 } 1115 1116 1117 Range* HSar::InferRange() { 1118 if (right()->IsConstant()) { 1119 HConstant* c = HConstant::cast(right()); 1120 if (c->HasInteger32Value()) { 1121 Range* result = (left()->range() != NULL) 1122 ? left()->range()->Copy() 1123 : new Range(); 1124 result->Sar(c->Integer32Value()); 1125 return result; 1126 } 1127 } 1128 return HValue::InferRange(); 1129 } 1130 1131 1132 Range* HShl::InferRange() { 1133 if (right()->IsConstant()) { 1134 HConstant* c = HConstant::cast(right()); 1135 if (c->HasInteger32Value()) { 1136 Range* result = (left()->range() != NULL) 1137 ? left()->range()->Copy() 1138 : new Range(); 1139 result->Shl(c->Integer32Value()); 1140 return result; 1141 } 1142 } 1143 return HValue::InferRange(); 1144 } 1145 1146 1147 1148 void HCompare::PrintDataTo(StringStream* stream) { 1149 stream->Add(Token::Name(token())); 1150 stream->Add(" "); 1151 HBinaryOperation::PrintDataTo(stream); 1152 } 1153 1154 1155 void HCompare::SetInputRepresentation(Representation r) { 1156 input_representation_ = r; 1157 if (r.IsTagged()) { 1158 SetAllSideEffects(); 1159 ClearFlag(kUseGVN); 1160 } else if (r.IsDouble()) { 1161 SetFlag(kDeoptimizeOnUndefined); 1162 ClearAllSideEffects(); 1163 SetFlag(kUseGVN); 1164 } else { 1165 ClearAllSideEffects(); 1166 SetFlag(kUseGVN); 1167 } 1168 } 1169 1170 1171 void HParameter::PrintDataTo(StringStream* stream) { 1172 stream->Add("%u", index()); 1173 } 1174 1175 1176 void HLoadNamedField::PrintDataTo(StringStream* stream) { 1177 object()->PrintNameTo(stream); 1178 stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : ""); 1179 } 1180 1181 1182 HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* object, 1183 ZoneMapList* types, 1184 Handle<String> name) 1185 : HUnaryOperation(object), 1186 types_(Min(types->length(), kMaxLoadPolymorphism)), 1187 name_(name), 1188 need_generic_(false) { 1189 set_representation(Representation::Tagged()); 1190 SetFlag(kDependsOnMaps); 1191 for (int i = 0; 1192 i < types->length() && types_.length() < kMaxLoadPolymorphism; 1193 ++i) { 1194 Handle<Map> map = types->at(i); 1195 LookupResult lookup; 1196 map->LookupInDescriptors(NULL, *name, &lookup); 1197 if (lookup.IsProperty() && lookup.type() == FIELD) { 1198 types_.Add(types->at(i)); 1199 int index = lookup.GetLocalFieldIndexFromMap(*map); 1200 if (index < 0) { 1201 SetFlag(kDependsOnInobjectFields); 1202 } else { 1203 SetFlag(kDependsOnBackingStoreFields); 1204 } 1205 } 1206 } 1207 1208 if (types_.length() == types->length() && FLAG_deoptimize_uncommon_cases) { 1209 SetFlag(kUseGVN); 1210 } else { 1211 SetAllSideEffects(); 1212 need_generic_ = true; 1213 } 1214 } 1215 1216 1217 bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) { 1218 HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value); 1219 if (types_.length() != other->types()->length()) return false; 1220 if (!name_.is_identical_to(other->name())) return false; 1221 if (need_generic_ != other->need_generic_) return false; 1222 for (int i = 0; i < types_.length(); i++) { 1223 bool found = false; 1224 for (int j = 0; j < types_.length(); j++) { 1225 if (types_.at(j).is_identical_to(other->types()->at(i))) { 1226 found = true; 1227 break; 1228 } 1229 } 1230 if (!found) return false; 1231 } 1232 return true; 1233 } 1234 1235 1236 void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) { 1237 object()->PrintNameTo(stream); 1238 stream->Add("["); 1239 key()->PrintNameTo(stream); 1240 stream->Add("]"); 1241 } 1242 1243 1244 void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) { 1245 object()->PrintNameTo(stream); 1246 stream->Add("["); 1247 key()->PrintNameTo(stream); 1248 stream->Add("]"); 1249 } 1250 1251 1252 void HLoadKeyedSpecializedArrayElement::PrintDataTo( 1253 StringStream* stream) { 1254 external_pointer()->PrintNameTo(stream); 1255 stream->Add("."); 1256 switch (array_type()) { 1257 case kExternalByteArray: 1258 stream->Add("byte"); 1259 break; 1260 case kExternalUnsignedByteArray: 1261 stream->Add("u_byte"); 1262 break; 1263 case kExternalShortArray: 1264 stream->Add("short"); 1265 break; 1266 case kExternalUnsignedShortArray: 1267 stream->Add("u_short"); 1268 break; 1269 case kExternalIntArray: 1270 stream->Add("int"); 1271 break; 1272 case kExternalUnsignedIntArray: 1273 stream->Add("u_int"); 1274 break; 1275 case kExternalFloatArray: 1276 stream->Add("float"); 1277 break; 1278 case kExternalPixelArray: 1279 stream->Add("pixel"); 1280 break; 1281 } 1282 stream->Add("["); 1283 key()->PrintNameTo(stream); 1284 stream->Add("]"); 1285 } 1286 1287 1288 void HStoreNamedGeneric::PrintDataTo(StringStream* stream) { 1289 object()->PrintNameTo(stream); 1290 stream->Add("."); 1291 ASSERT(name()->IsString()); 1292 stream->Add(*String::cast(*name())->ToCString()); 1293 stream->Add(" = "); 1294 value()->PrintNameTo(stream); 1295 } 1296 1297 1298 void HStoreNamedField::PrintDataTo(StringStream* stream) { 1299 object()->PrintNameTo(stream); 1300 stream->Add("."); 1301 ASSERT(name()->IsString()); 1302 stream->Add(*String::cast(*name())->ToCString()); 1303 stream->Add(" = "); 1304 value()->PrintNameTo(stream); 1305 if (!transition().is_null()) { 1306 stream->Add(" (transition map %p)", *transition()); 1307 } 1308 } 1309 1310 1311 void HStoreKeyedFastElement::PrintDataTo(StringStream* stream) { 1312 object()->PrintNameTo(stream); 1313 stream->Add("["); 1314 key()->PrintNameTo(stream); 1315 stream->Add("] = "); 1316 value()->PrintNameTo(stream); 1317 } 1318 1319 1320 void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) { 1321 object()->PrintNameTo(stream); 1322 stream->Add("["); 1323 key()->PrintNameTo(stream); 1324 stream->Add("] = "); 1325 value()->PrintNameTo(stream); 1326 } 1327 1328 1329 void HStoreKeyedSpecializedArrayElement::PrintDataTo( 1330 StringStream* stream) { 1331 external_pointer()->PrintNameTo(stream); 1332 stream->Add("."); 1333 switch (array_type()) { 1334 case kExternalByteArray: 1335 stream->Add("byte"); 1336 break; 1337 case kExternalUnsignedByteArray: 1338 stream->Add("u_byte"); 1339 break; 1340 case kExternalShortArray: 1341 stream->Add("short"); 1342 break; 1343 case kExternalUnsignedShortArray: 1344 stream->Add("u_short"); 1345 break; 1346 case kExternalIntArray: 1347 stream->Add("int"); 1348 break; 1349 case kExternalUnsignedIntArray: 1350 stream->Add("u_int"); 1351 break; 1352 case kExternalFloatArray: 1353 stream->Add("float"); 1354 break; 1355 case kExternalPixelArray: 1356 stream->Add("pixel"); 1357 break; 1358 } 1359 stream->Add("["); 1360 key()->PrintNameTo(stream); 1361 stream->Add("] = "); 1362 value()->PrintNameTo(stream); 1363 } 1364 1365 1366 void HLoadGlobalCell::PrintDataTo(StringStream* stream) { 1367 stream->Add("[%p]", *cell()); 1368 if (check_hole_value()) stream->Add(" (deleteable/read-only)"); 1369 } 1370 1371 1372 void HLoadGlobalGeneric::PrintDataTo(StringStream* stream) { 1373 stream->Add("%o ", *name()); 1374 } 1375 1376 1377 void HStoreGlobalCell::PrintDataTo(StringStream* stream) { 1378 stream->Add("[%p] = ", *cell()); 1379 value()->PrintNameTo(stream); 1380 } 1381 1382 1383 void HStoreGlobalGeneric::PrintDataTo(StringStream* stream) { 1384 stream->Add("%o = ", *name()); 1385 value()->PrintNameTo(stream); 1386 } 1387 1388 1389 void HLoadContextSlot::PrintDataTo(StringStream* stream) { 1390 value()->PrintNameTo(stream); 1391 stream->Add("[%d]", slot_index()); 1392 } 1393 1394 1395 void HStoreContextSlot::PrintDataTo(StringStream* stream) { 1396 context()->PrintNameTo(stream); 1397 stream->Add("[%d] = ", slot_index()); 1398 value()->PrintNameTo(stream); 1399 } 1400 1401 1402 // Implementation of type inference and type conversions. Calculates 1403 // the inferred type of this instruction based on the input operands. 1404 1405 HType HValue::CalculateInferredType() { 1406 return type_; 1407 } 1408 1409 1410 HType HCheckMap::CalculateInferredType() { 1411 return value()->type(); 1412 } 1413 1414 1415 HType HCheckFunction::CalculateInferredType() { 1416 return value()->type(); 1417 } 1418 1419 1420 HType HCheckNonSmi::CalculateInferredType() { 1421 // TODO(kasperl): Is there any way to signal that this isn't a smi? 1422 return HType::Tagged(); 1423 } 1424 1425 1426 HType HCheckSmi::CalculateInferredType() { 1427 return HType::Smi(); 1428 } 1429 1430 1431 HType HPhi::CalculateInferredType() { 1432 HType result = HType::Uninitialized(); 1433 for (int i = 0; i < OperandCount(); ++i) { 1434 HType current = OperandAt(i)->type(); 1435 result = result.Combine(current); 1436 } 1437 return result; 1438 } 1439 1440 1441 HType HConstant::CalculateInferredType() { 1442 return constant_type_; 1443 } 1444 1445 1446 HType HCompare::CalculateInferredType() { 1447 return HType::Boolean(); 1448 } 1449 1450 1451 HType HCompareJSObjectEq::CalculateInferredType() { 1452 return HType::Boolean(); 1453 } 1454 1455 1456 HType HUnaryPredicate::CalculateInferredType() { 1457 return HType::Boolean(); 1458 } 1459 1460 1461 HType HBitwiseBinaryOperation::CalculateInferredType() { 1462 return HType::TaggedNumber(); 1463 } 1464 1465 1466 HType HArithmeticBinaryOperation::CalculateInferredType() { 1467 return HType::TaggedNumber(); 1468 } 1469 1470 1471 HType HAdd::CalculateInferredType() { 1472 return HType::Tagged(); 1473 } 1474 1475 1476 HType HBitAnd::CalculateInferredType() { 1477 return HType::TaggedNumber(); 1478 } 1479 1480 1481 HType HBitXor::CalculateInferredType() { 1482 return HType::TaggedNumber(); 1483 } 1484 1485 1486 HType HBitOr::CalculateInferredType() { 1487 return HType::TaggedNumber(); 1488 } 1489 1490 1491 HType HBitNot::CalculateInferredType() { 1492 return HType::TaggedNumber(); 1493 } 1494 1495 1496 HType HUnaryMathOperation::CalculateInferredType() { 1497 return HType::TaggedNumber(); 1498 } 1499 1500 1501 HType HShl::CalculateInferredType() { 1502 return HType::TaggedNumber(); 1503 } 1504 1505 1506 HType HShr::CalculateInferredType() { 1507 return HType::TaggedNumber(); 1508 } 1509 1510 1511 HType HSar::CalculateInferredType() { 1512 return HType::TaggedNumber(); 1513 } 1514 1515 1516 HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero( 1517 BitVector* visited) { 1518 visited->Add(id()); 1519 if (representation().IsInteger32() && 1520 !value()->representation().IsInteger32()) { 1521 if (value()->range() == NULL || value()->range()->CanBeMinusZero()) { 1522 SetFlag(kBailoutOnMinusZero); 1523 } 1524 } 1525 if (RequiredInputRepresentation(0).IsInteger32() && 1526 representation().IsInteger32()) { 1527 return value(); 1528 } 1529 return NULL; 1530 } 1531 1532 1533 1534 HValue* HChange::EnsureAndPropagateNotMinusZero(BitVector* visited) { 1535 visited->Add(id()); 1536 if (from().IsInteger32()) return NULL; 1537 if (CanTruncateToInt32()) return NULL; 1538 if (value()->range() == NULL || value()->range()->CanBeMinusZero()) { 1539 SetFlag(kBailoutOnMinusZero); 1540 } 1541 ASSERT(!from().IsInteger32() || !to().IsInteger32()); 1542 return NULL; 1543 } 1544 1545 1546 HValue* HMod::EnsureAndPropagateNotMinusZero(BitVector* visited) { 1547 visited->Add(id()); 1548 if (range() == NULL || range()->CanBeMinusZero()) { 1549 SetFlag(kBailoutOnMinusZero); 1550 return left(); 1551 } 1552 return NULL; 1553 } 1554 1555 1556 HValue* HDiv::EnsureAndPropagateNotMinusZero(BitVector* visited) { 1557 visited->Add(id()); 1558 if (range() == NULL || range()->CanBeMinusZero()) { 1559 SetFlag(kBailoutOnMinusZero); 1560 } 1561 return NULL; 1562 } 1563 1564 1565 HValue* HMul::EnsureAndPropagateNotMinusZero(BitVector* visited) { 1566 visited->Add(id()); 1567 if (range() == NULL || range()->CanBeMinusZero()) { 1568 SetFlag(kBailoutOnMinusZero); 1569 } 1570 return NULL; 1571 } 1572 1573 1574 HValue* HSub::EnsureAndPropagateNotMinusZero(BitVector* visited) { 1575 visited->Add(id()); 1576 // Propagate to the left argument. If the left argument cannot be -0, then 1577 // the result of the add operation cannot be either. 1578 if (range() == NULL || range()->CanBeMinusZero()) { 1579 return left(); 1580 } 1581 return NULL; 1582 } 1583 1584 1585 HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) { 1586 visited->Add(id()); 1587 // Propagate to the left argument. If the left argument cannot be -0, then 1588 // the result of the sub operation cannot be either. 1589 if (range() == NULL || range()->CanBeMinusZero()) { 1590 return left(); 1591 } 1592 return NULL; 1593 } 1594 1595 1596 // Node-specific verification code is only included in debug mode. 1597 #ifdef DEBUG 1598 1599 void HPhi::Verify() { 1600 ASSERT(OperandCount() == block()->predecessors()->length()); 1601 for (int i = 0; i < OperandCount(); ++i) { 1602 HValue* value = OperandAt(i); 1603 HBasicBlock* defining_block = value->block(); 1604 HBasicBlock* predecessor_block = block()->predecessors()->at(i); 1605 ASSERT(defining_block == predecessor_block || 1606 defining_block->Dominates(predecessor_block)); 1607 } 1608 } 1609 1610 1611 void HSimulate::Verify() { 1612 HInstruction::Verify(); 1613 ASSERT(HasAstId()); 1614 } 1615 1616 1617 void HBoundsCheck::Verify() { 1618 HInstruction::Verify(); 1619 } 1620 1621 1622 void HCheckSmi::Verify() { 1623 HInstruction::Verify(); 1624 ASSERT(HasNoUses()); 1625 } 1626 1627 1628 void HCheckNonSmi::Verify() { 1629 HInstruction::Verify(); 1630 ASSERT(HasNoUses()); 1631 } 1632 1633 1634 void HCheckInstanceType::Verify() { 1635 HInstruction::Verify(); 1636 ASSERT(HasNoUses()); 1637 } 1638 1639 1640 void HCheckMap::Verify() { 1641 HInstruction::Verify(); 1642 ASSERT(HasNoUses()); 1643 } 1644 1645 1646 void HCheckFunction::Verify() { 1647 HInstruction::Verify(); 1648 ASSERT(HasNoUses()); 1649 } 1650 1651 1652 void HCheckPrototypeMaps::Verify() { 1653 HInstruction::Verify(); 1654 ASSERT(HasNoUses()); 1655 } 1656 1657 #endif 1658 1659 } } // namespace v8::internal 1660