1 // Copyright 2012 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 default: 64 UNREACHABLE(); 65 return NULL; 66 } 67 } 68 69 70 int HValue::LoopWeight() const { 71 const int w = FLAG_loop_weight; 72 static const int weights[] = { 1, w, w*w, w*w*w, w*w*w*w }; 73 return weights[Min(block()->LoopNestingDepth(), 74 static_cast<int>(ARRAY_SIZE(weights)-1))]; 75 } 76 77 78 void HValue::AssumeRepresentation(Representation r) { 79 if (CheckFlag(kFlexibleRepresentation)) { 80 ChangeRepresentation(r); 81 // The representation of the value is dictated by type feedback and 82 // will not be changed later. 83 ClearFlag(kFlexibleRepresentation); 84 } 85 } 86 87 88 static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) { 89 if (result > kMaxInt) { 90 *overflow = true; 91 return kMaxInt; 92 } 93 if (result < kMinInt) { 94 *overflow = true; 95 return kMinInt; 96 } 97 return static_cast<int32_t>(result); 98 } 99 100 101 static int32_t AddWithoutOverflow(int32_t a, int32_t b, bool* overflow) { 102 int64_t result = static_cast<int64_t>(a) + static_cast<int64_t>(b); 103 return ConvertAndSetOverflow(result, overflow); 104 } 105 106 107 static int32_t SubWithoutOverflow(int32_t a, int32_t b, bool* overflow) { 108 int64_t result = static_cast<int64_t>(a) - static_cast<int64_t>(b); 109 return ConvertAndSetOverflow(result, overflow); 110 } 111 112 113 static int32_t MulWithoutOverflow(int32_t a, int32_t b, bool* overflow) { 114 int64_t result = static_cast<int64_t>(a) * static_cast<int64_t>(b); 115 return ConvertAndSetOverflow(result, overflow); 116 } 117 118 119 int32_t Range::Mask() const { 120 if (lower_ == upper_) return lower_; 121 if (lower_ >= 0) { 122 int32_t res = 1; 123 while (res < upper_) { 124 res = (res << 1) | 1; 125 } 126 return res; 127 } 128 return 0xffffffff; 129 } 130 131 132 void Range::AddConstant(int32_t value) { 133 if (value == 0) return; 134 bool may_overflow = false; // Overflow is ignored here. 135 lower_ = AddWithoutOverflow(lower_, value, &may_overflow); 136 upper_ = AddWithoutOverflow(upper_, value, &may_overflow); 137 #ifdef DEBUG 138 Verify(); 139 #endif 140 } 141 142 143 void Range::Intersect(Range* other) { 144 upper_ = Min(upper_, other->upper_); 145 lower_ = Max(lower_, other->lower_); 146 bool b = CanBeMinusZero() && other->CanBeMinusZero(); 147 set_can_be_minus_zero(b); 148 } 149 150 151 void Range::Union(Range* other) { 152 upper_ = Max(upper_, other->upper_); 153 lower_ = Min(lower_, other->lower_); 154 bool b = CanBeMinusZero() || other->CanBeMinusZero(); 155 set_can_be_minus_zero(b); 156 } 157 158 159 void Range::Sar(int32_t value) { 160 int32_t bits = value & 0x1F; 161 lower_ = lower_ >> bits; 162 upper_ = upper_ >> bits; 163 set_can_be_minus_zero(false); 164 } 165 166 167 void Range::Shl(int32_t value) { 168 int32_t bits = value & 0x1F; 169 int old_lower = lower_; 170 int old_upper = upper_; 171 lower_ = lower_ << bits; 172 upper_ = upper_ << bits; 173 if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) { 174 upper_ = kMaxInt; 175 lower_ = kMinInt; 176 } 177 set_can_be_minus_zero(false); 178 } 179 180 181 bool Range::AddAndCheckOverflow(Range* other) { 182 bool may_overflow = false; 183 lower_ = AddWithoutOverflow(lower_, other->lower(), &may_overflow); 184 upper_ = AddWithoutOverflow(upper_, other->upper(), &may_overflow); 185 KeepOrder(); 186 #ifdef DEBUG 187 Verify(); 188 #endif 189 return may_overflow; 190 } 191 192 193 bool Range::SubAndCheckOverflow(Range* other) { 194 bool may_overflow = false; 195 lower_ = SubWithoutOverflow(lower_, other->upper(), &may_overflow); 196 upper_ = SubWithoutOverflow(upper_, other->lower(), &may_overflow); 197 KeepOrder(); 198 #ifdef DEBUG 199 Verify(); 200 #endif 201 return may_overflow; 202 } 203 204 205 void Range::KeepOrder() { 206 if (lower_ > upper_) { 207 int32_t tmp = lower_; 208 lower_ = upper_; 209 upper_ = tmp; 210 } 211 } 212 213 214 #ifdef DEBUG 215 void Range::Verify() const { 216 ASSERT(lower_ <= upper_); 217 } 218 #endif 219 220 221 bool Range::MulAndCheckOverflow(Range* other) { 222 bool may_overflow = false; 223 int v1 = MulWithoutOverflow(lower_, other->lower(), &may_overflow); 224 int v2 = MulWithoutOverflow(lower_, other->upper(), &may_overflow); 225 int v3 = MulWithoutOverflow(upper_, other->lower(), &may_overflow); 226 int v4 = MulWithoutOverflow(upper_, other->upper(), &may_overflow); 227 lower_ = Min(Min(v1, v2), Min(v3, v4)); 228 upper_ = Max(Max(v1, v2), Max(v3, v4)); 229 #ifdef DEBUG 230 Verify(); 231 #endif 232 return may_overflow; 233 } 234 235 236 const char* HType::ToString() { 237 switch (type_) { 238 case kTagged: return "tagged"; 239 case kTaggedPrimitive: return "primitive"; 240 case kTaggedNumber: return "number"; 241 case kSmi: return "smi"; 242 case kHeapNumber: return "heap-number"; 243 case kString: return "string"; 244 case kBoolean: return "boolean"; 245 case kNonPrimitive: return "non-primitive"; 246 case kJSArray: return "array"; 247 case kJSObject: return "object"; 248 case kUninitialized: return "uninitialized"; 249 } 250 UNREACHABLE(); 251 return "Unreachable code"; 252 } 253 254 255 HType HType::TypeFromValue(Handle<Object> value) { 256 HType result = HType::Tagged(); 257 if (value->IsSmi()) { 258 result = HType::Smi(); 259 } else if (value->IsHeapNumber()) { 260 result = HType::HeapNumber(); 261 } else if (value->IsString()) { 262 result = HType::String(); 263 } else if (value->IsBoolean()) { 264 result = HType::Boolean(); 265 } else if (value->IsJSObject()) { 266 result = HType::JSObject(); 267 } else if (value->IsJSArray()) { 268 result = HType::JSArray(); 269 } 270 return result; 271 } 272 273 274 bool HValue::IsDefinedAfter(HBasicBlock* other) const { 275 return block()->block_id() > other->block_id(); 276 } 277 278 279 HUseListNode* HUseListNode::tail() { 280 // Skip and remove dead items in the use list. 281 while (tail_ != NULL && tail_->value()->CheckFlag(HValue::kIsDead)) { 282 tail_ = tail_->tail_; 283 } 284 return tail_; 285 } 286 287 288 bool HValue::CheckUsesForFlag(Flag f) { 289 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 290 if (!it.value()->CheckFlag(f)) return false; 291 } 292 return true; 293 } 294 295 296 HUseIterator::HUseIterator(HUseListNode* head) : next_(head) { 297 Advance(); 298 } 299 300 301 void HUseIterator::Advance() { 302 current_ = next_; 303 if (current_ != NULL) { 304 next_ = current_->tail(); 305 value_ = current_->value(); 306 index_ = current_->index(); 307 } 308 } 309 310 311 int HValue::UseCount() const { 312 int count = 0; 313 for (HUseIterator it(uses()); !it.Done(); it.Advance()) ++count; 314 return count; 315 } 316 317 318 HUseListNode* HValue::RemoveUse(HValue* value, int index) { 319 HUseListNode* previous = NULL; 320 HUseListNode* current = use_list_; 321 while (current != NULL) { 322 if (current->value() == value && current->index() == index) { 323 if (previous == NULL) { 324 use_list_ = current->tail(); 325 } else { 326 previous->set_tail(current->tail()); 327 } 328 break; 329 } 330 331 previous = current; 332 current = current->tail(); 333 } 334 335 #ifdef DEBUG 336 // Do not reuse use list nodes in debug mode, zap them. 337 if (current != NULL) { 338 HUseListNode* temp = 339 new HUseListNode(current->value(), current->index(), NULL); 340 current->Zap(); 341 current = temp; 342 } 343 #endif 344 return current; 345 } 346 347 348 bool HValue::Equals(HValue* other) { 349 if (other->opcode() != opcode()) return false; 350 if (!other->representation().Equals(representation())) return false; 351 if (!other->type_.Equals(type_)) return false; 352 if (other->flags() != flags()) return false; 353 if (OperandCount() != other->OperandCount()) return false; 354 for (int i = 0; i < OperandCount(); ++i) { 355 if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false; 356 } 357 bool result = DataEquals(other); 358 ASSERT(!result || Hashcode() == other->Hashcode()); 359 return result; 360 } 361 362 363 intptr_t HValue::Hashcode() { 364 intptr_t result = opcode(); 365 int count = OperandCount(); 366 for (int i = 0; i < count; ++i) { 367 result = result * 19 + OperandAt(i)->id() + (result >> 7); 368 } 369 return result; 370 } 371 372 373 const char* HValue::Mnemonic() const { 374 switch (opcode()) { 375 #define MAKE_CASE(type) case k##type: return #type; 376 HYDROGEN_CONCRETE_INSTRUCTION_LIST(MAKE_CASE) 377 #undef MAKE_CASE 378 case kPhi: return "Phi"; 379 default: return ""; 380 } 381 } 382 383 384 void HValue::SetOperandAt(int index, HValue* value) { 385 RegisterUse(index, value); 386 InternalSetOperandAt(index, value); 387 } 388 389 390 void HValue::DeleteAndReplaceWith(HValue* other) { 391 // We replace all uses first, so Delete can assert that there are none. 392 if (other != NULL) ReplaceAllUsesWith(other); 393 ASSERT(HasNoUses()); 394 Kill(); 395 DeleteFromGraph(); 396 } 397 398 399 void HValue::ReplaceAllUsesWith(HValue* other) { 400 while (use_list_ != NULL) { 401 HUseListNode* list_node = use_list_; 402 HValue* value = list_node->value(); 403 ASSERT(!value->block()->IsStartBlock()); 404 value->InternalSetOperandAt(list_node->index(), other); 405 use_list_ = list_node->tail(); 406 list_node->set_tail(other->use_list_); 407 other->use_list_ = list_node; 408 } 409 } 410 411 412 void HValue::Kill() { 413 // Instead of going through the entire use list of each operand, we only 414 // check the first item in each use list and rely on the tail() method to 415 // skip dead items, removing them lazily next time we traverse the list. 416 SetFlag(kIsDead); 417 for (int i = 0; i < OperandCount(); ++i) { 418 HValue* operand = OperandAt(i); 419 HUseListNode* first = operand->use_list_; 420 if (first != NULL && first->value() == this && first->index() == i) { 421 operand->use_list_ = first->tail(); 422 } 423 } 424 } 425 426 427 void HValue::SetBlock(HBasicBlock* block) { 428 ASSERT(block_ == NULL || block == NULL); 429 block_ = block; 430 if (id_ == kNoNumber && block != NULL) { 431 id_ = block->graph()->GetNextValueID(this); 432 } 433 } 434 435 436 void HValue::PrintTypeTo(StringStream* stream) { 437 if (!representation().IsTagged() || type().Equals(HType::Tagged())) return; 438 stream->Add(" type[%s]", type().ToString()); 439 } 440 441 442 void HValue::PrintRangeTo(StringStream* stream) { 443 if (range() == NULL || range()->IsMostGeneric()) return; 444 stream->Add(" range[%d,%d,m0=%d]", 445 range()->lower(), 446 range()->upper(), 447 static_cast<int>(range()->CanBeMinusZero())); 448 } 449 450 451 void HValue::PrintChangesTo(StringStream* stream) { 452 GVNFlagSet changes_flags = ChangesFlags(); 453 if (changes_flags.IsEmpty()) return; 454 stream->Add(" changes["); 455 if (changes_flags == AllSideEffectsFlagSet()) { 456 stream->Add("*"); 457 } else { 458 bool add_comma = false; 459 #define PRINT_DO(type) \ 460 if (changes_flags.Contains(kChanges##type)) { \ 461 if (add_comma) stream->Add(","); \ 462 add_comma = true; \ 463 stream->Add(#type); \ 464 } 465 GVN_FLAG_LIST(PRINT_DO); 466 #undef PRINT_DO 467 } 468 stream->Add("]"); 469 } 470 471 472 void HValue::PrintNameTo(StringStream* stream) { 473 stream->Add("%s%d", representation_.Mnemonic(), id()); 474 } 475 476 477 bool HValue::UpdateInferredType() { 478 HType type = CalculateInferredType(); 479 bool result = (!type.Equals(type_)); 480 type_ = type; 481 return result; 482 } 483 484 485 void HValue::RegisterUse(int index, HValue* new_value) { 486 HValue* old_value = OperandAt(index); 487 if (old_value == new_value) return; 488 489 HUseListNode* removed = NULL; 490 if (old_value != NULL) { 491 removed = old_value->RemoveUse(this, index); 492 } 493 494 if (new_value != NULL) { 495 if (removed == NULL) { 496 new_value->use_list_ = 497 new HUseListNode(this, index, new_value->use_list_); 498 } else { 499 removed->set_tail(new_value->use_list_); 500 new_value->use_list_ = removed; 501 } 502 } 503 } 504 505 506 void HValue::AddNewRange(Range* r, Zone* zone) { 507 if (!HasRange()) ComputeInitialRange(zone); 508 if (!HasRange()) range_ = new(zone) Range(); 509 ASSERT(HasRange()); 510 r->StackUpon(range_); 511 range_ = r; 512 } 513 514 515 void HValue::RemoveLastAddedRange() { 516 ASSERT(HasRange()); 517 ASSERT(range_->next() != NULL); 518 range_ = range_->next(); 519 } 520 521 522 void HValue::ComputeInitialRange(Zone* zone) { 523 ASSERT(!HasRange()); 524 range_ = InferRange(zone); 525 ASSERT(HasRange()); 526 } 527 528 529 void HInstruction::PrintTo(StringStream* stream) { 530 PrintMnemonicTo(stream); 531 PrintDataTo(stream); 532 PrintRangeTo(stream); 533 PrintChangesTo(stream); 534 PrintTypeTo(stream); 535 } 536 537 538 void HInstruction::PrintMnemonicTo(StringStream* stream) { 539 stream->Add("%s ", Mnemonic()); 540 } 541 542 543 void HInstruction::Unlink() { 544 ASSERT(IsLinked()); 545 ASSERT(!IsControlInstruction()); // Must never move control instructions. 546 ASSERT(!IsBlockEntry()); // Doesn't make sense to delete these. 547 ASSERT(previous_ != NULL); 548 previous_->next_ = next_; 549 if (next_ == NULL) { 550 ASSERT(block()->last() == this); 551 block()->set_last(previous_); 552 } else { 553 next_->previous_ = previous_; 554 } 555 clear_block(); 556 } 557 558 559 void HInstruction::InsertBefore(HInstruction* next) { 560 ASSERT(!IsLinked()); 561 ASSERT(!next->IsBlockEntry()); 562 ASSERT(!IsControlInstruction()); 563 ASSERT(!next->block()->IsStartBlock()); 564 ASSERT(next->previous_ != NULL); 565 HInstruction* prev = next->previous(); 566 prev->next_ = this; 567 next->previous_ = this; 568 next_ = next; 569 previous_ = prev; 570 SetBlock(next->block()); 571 } 572 573 574 void HInstruction::InsertAfter(HInstruction* previous) { 575 ASSERT(!IsLinked()); 576 ASSERT(!previous->IsControlInstruction()); 577 ASSERT(!IsControlInstruction() || previous->next_ == NULL); 578 HBasicBlock* block = previous->block(); 579 // Never insert anything except constants into the start block after finishing 580 // it. 581 if (block->IsStartBlock() && block->IsFinished() && !IsConstant()) { 582 ASSERT(block->end()->SecondSuccessor() == NULL); 583 InsertAfter(block->end()->FirstSuccessor()->first()); 584 return; 585 } 586 587 // If we're inserting after an instruction with side-effects that is 588 // followed by a simulate instruction, we need to insert after the 589 // simulate instruction instead. 590 HInstruction* next = previous->next_; 591 if (previous->HasObservableSideEffects() && next != NULL) { 592 ASSERT(next->IsSimulate()); 593 previous = next; 594 next = previous->next_; 595 } 596 597 previous_ = previous; 598 next_ = next; 599 SetBlock(block); 600 previous->next_ = this; 601 if (next != NULL) next->previous_ = this; 602 } 603 604 605 #ifdef DEBUG 606 void HInstruction::Verify() { 607 // Verify that input operands are defined before use. 608 HBasicBlock* cur_block = block(); 609 for (int i = 0; i < OperandCount(); ++i) { 610 HValue* other_operand = OperandAt(i); 611 HBasicBlock* other_block = other_operand->block(); 612 if (cur_block == other_block) { 613 if (!other_operand->IsPhi()) { 614 HInstruction* cur = this->previous(); 615 while (cur != NULL) { 616 if (cur == other_operand) break; 617 cur = cur->previous(); 618 } 619 // Must reach other operand in the same block! 620 ASSERT(cur == other_operand); 621 } 622 } else { 623 // If the following assert fires, you may have forgotten an 624 // AddInstruction. 625 ASSERT(other_block->Dominates(cur_block)); 626 } 627 } 628 629 // Verify that instructions that may have side-effects are followed 630 // by a simulate instruction. 631 if (HasObservableSideEffects() && !IsOsrEntry()) { 632 ASSERT(next()->IsSimulate()); 633 } 634 635 // Verify that instructions that can be eliminated by GVN have overridden 636 // HValue::DataEquals. The default implementation is UNREACHABLE. We 637 // don't actually care whether DataEquals returns true or false here. 638 if (CheckFlag(kUseGVN)) DataEquals(this); 639 } 640 #endif 641 642 643 void HUnaryCall::PrintDataTo(StringStream* stream) { 644 value()->PrintNameTo(stream); 645 stream->Add(" "); 646 stream->Add("#%d", argument_count()); 647 } 648 649 650 void HBinaryCall::PrintDataTo(StringStream* stream) { 651 first()->PrintNameTo(stream); 652 stream->Add(" "); 653 second()->PrintNameTo(stream); 654 stream->Add(" "); 655 stream->Add("#%d", argument_count()); 656 } 657 658 659 void HBoundsCheck::PrintDataTo(StringStream* stream) { 660 index()->PrintNameTo(stream); 661 stream->Add(" "); 662 length()->PrintNameTo(stream); 663 } 664 665 666 void HCallConstantFunction::PrintDataTo(StringStream* stream) { 667 if (IsApplyFunction()) { 668 stream->Add("optimized apply "); 669 } else { 670 stream->Add("%o ", function()->shared()->DebugName()); 671 } 672 stream->Add("#%d", argument_count()); 673 } 674 675 676 void HCallNamed::PrintDataTo(StringStream* stream) { 677 stream->Add("%o ", *name()); 678 HUnaryCall::PrintDataTo(stream); 679 } 680 681 682 void HCallGlobal::PrintDataTo(StringStream* stream) { 683 stream->Add("%o ", *name()); 684 HUnaryCall::PrintDataTo(stream); 685 } 686 687 688 void HCallKnownGlobal::PrintDataTo(StringStream* stream) { 689 stream->Add("o ", target()->shared()->DebugName()); 690 stream->Add("#%d", argument_count()); 691 } 692 693 694 void HCallRuntime::PrintDataTo(StringStream* stream) { 695 stream->Add("%o ", *name()); 696 stream->Add("#%d", argument_count()); 697 } 698 699 700 void HClassOfTestAndBranch::PrintDataTo(StringStream* stream) { 701 stream->Add("class_of_test("); 702 value()->PrintNameTo(stream); 703 stream->Add(", \"%o\")", *class_name()); 704 } 705 706 707 void HAccessArgumentsAt::PrintDataTo(StringStream* stream) { 708 arguments()->PrintNameTo(stream); 709 stream->Add("["); 710 index()->PrintNameTo(stream); 711 stream->Add("], length "); 712 length()->PrintNameTo(stream); 713 } 714 715 716 void HControlInstruction::PrintDataTo(StringStream* stream) { 717 stream->Add(" goto ("); 718 bool first_block = true; 719 for (HSuccessorIterator it(this); !it.Done(); it.Advance()) { 720 stream->Add(first_block ? "B%d" : ", B%d", it.Current()->block_id()); 721 first_block = false; 722 } 723 stream->Add(")"); 724 } 725 726 727 void HUnaryControlInstruction::PrintDataTo(StringStream* stream) { 728 value()->PrintNameTo(stream); 729 HControlInstruction::PrintDataTo(stream); 730 } 731 732 733 void HIsNilAndBranch::PrintDataTo(StringStream* stream) { 734 value()->PrintNameTo(stream); 735 stream->Add(kind() == kStrictEquality ? " === " : " == "); 736 stream->Add(nil() == kNullValue ? "null" : "undefined"); 737 HControlInstruction::PrintDataTo(stream); 738 } 739 740 741 void HReturn::PrintDataTo(StringStream* stream) { 742 value()->PrintNameTo(stream); 743 } 744 745 746 void HCompareMap::PrintDataTo(StringStream* stream) { 747 value()->PrintNameTo(stream); 748 stream->Add(" (%p)", *map()); 749 HControlInstruction::PrintDataTo(stream); 750 } 751 752 753 const char* HUnaryMathOperation::OpName() const { 754 switch (op()) { 755 case kMathFloor: return "floor"; 756 case kMathRound: return "round"; 757 case kMathCeil: return "ceil"; 758 case kMathAbs: return "abs"; 759 case kMathLog: return "log"; 760 case kMathSin: return "sin"; 761 case kMathCos: return "cos"; 762 case kMathTan: return "tan"; 763 case kMathASin: return "asin"; 764 case kMathACos: return "acos"; 765 case kMathATan: return "atan"; 766 case kMathExp: return "exp"; 767 case kMathSqrt: return "sqrt"; 768 default: break; 769 } 770 return "(unknown operation)"; 771 } 772 773 774 void HUnaryMathOperation::PrintDataTo(StringStream* stream) { 775 const char* name = OpName(); 776 stream->Add("%s ", name); 777 value()->PrintNameTo(stream); 778 } 779 780 781 void HUnaryOperation::PrintDataTo(StringStream* stream) { 782 value()->PrintNameTo(stream); 783 } 784 785 786 void HHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { 787 value()->PrintNameTo(stream); 788 switch (from_) { 789 case FIRST_JS_RECEIVER_TYPE: 790 if (to_ == LAST_TYPE) stream->Add(" spec_object"); 791 break; 792 case JS_REGEXP_TYPE: 793 if (to_ == JS_REGEXP_TYPE) stream->Add(" reg_exp"); 794 break; 795 case JS_ARRAY_TYPE: 796 if (to_ == JS_ARRAY_TYPE) stream->Add(" array"); 797 break; 798 case JS_FUNCTION_TYPE: 799 if (to_ == JS_FUNCTION_TYPE) stream->Add(" function"); 800 break; 801 default: 802 break; 803 } 804 } 805 806 807 void HTypeofIsAndBranch::PrintDataTo(StringStream* stream) { 808 value()->PrintNameTo(stream); 809 stream->Add(" == %o", *type_literal_); 810 HControlInstruction::PrintDataTo(stream); 811 } 812 813 814 void HCheckMapValue::PrintDataTo(StringStream* stream) { 815 value()->PrintNameTo(stream); 816 stream->Add(" "); 817 map()->PrintNameTo(stream); 818 } 819 820 821 void HForInPrepareMap::PrintDataTo(StringStream* stream) { 822 enumerable()->PrintNameTo(stream); 823 } 824 825 826 void HForInCacheArray::PrintDataTo(StringStream* stream) { 827 enumerable()->PrintNameTo(stream); 828 stream->Add(" "); 829 map()->PrintNameTo(stream); 830 stream->Add("[%d]", idx_); 831 } 832 833 834 void HLoadFieldByIndex::PrintDataTo(StringStream* stream) { 835 object()->PrintNameTo(stream); 836 stream->Add(" "); 837 index()->PrintNameTo(stream); 838 } 839 840 841 HValue* HConstant::Canonicalize() { 842 return HasNoUses() ? NULL : this; 843 } 844 845 846 HValue* HTypeof::Canonicalize() { 847 return HasNoUses() ? NULL : this; 848 } 849 850 851 HValue* HBitwise::Canonicalize() { 852 if (!representation().IsInteger32()) return this; 853 // If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x. 854 int32_t nop_constant = (op() == Token::BIT_AND) ? -1 : 0; 855 if (left()->IsConstant() && 856 HConstant::cast(left())->HasInteger32Value() && 857 HConstant::cast(left())->Integer32Value() == nop_constant) { 858 return right(); 859 } 860 if (right()->IsConstant() && 861 HConstant::cast(right())->HasInteger32Value() && 862 HConstant::cast(right())->Integer32Value() == nop_constant) { 863 return left(); 864 } 865 return this; 866 } 867 868 869 HValue* HAdd::Canonicalize() { 870 if (!representation().IsInteger32()) return this; 871 if (CheckUsesForFlag(kTruncatingToInt32)) ClearFlag(kCanOverflow); 872 return this; 873 } 874 875 876 HValue* HSub::Canonicalize() { 877 if (!representation().IsInteger32()) return this; 878 if (CheckUsesForFlag(kTruncatingToInt32)) ClearFlag(kCanOverflow); 879 return this; 880 } 881 882 883 HValue* HChange::Canonicalize() { 884 return (from().Equals(to())) ? value() : this; 885 } 886 887 888 HValue* HWrapReceiver::Canonicalize() { 889 if (HasNoUses()) return NULL; 890 if (receiver()->type().IsJSObject()) { 891 return receiver(); 892 } 893 return this; 894 } 895 896 897 void HTypeof::PrintDataTo(StringStream* stream) { 898 value()->PrintNameTo(stream); 899 } 900 901 902 void HChange::PrintDataTo(StringStream* stream) { 903 HUnaryOperation::PrintDataTo(stream); 904 stream->Add(" %s to %s", from().Mnemonic(), to().Mnemonic()); 905 906 if (CanTruncateToInt32()) stream->Add(" truncating-int32"); 907 if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?"); 908 if (CheckFlag(kDeoptimizeOnUndefined)) stream->Add(" deopt-on-undefined"); 909 } 910 911 912 void HJSArrayLength::PrintDataTo(StringStream* stream) { 913 value()->PrintNameTo(stream); 914 stream->Add(" "); 915 typecheck()->PrintNameTo(stream); 916 } 917 918 919 HValue* HCheckInstanceType::Canonicalize() { 920 if (check_ == IS_STRING && 921 !value()->type().IsUninitialized() && 922 value()->type().IsString()) { 923 return NULL; 924 } 925 if (check_ == IS_SYMBOL && 926 value()->IsConstant() && 927 HConstant::cast(value())->handle()->IsSymbol()) { 928 return NULL; 929 } 930 return this; 931 } 932 933 934 void HCheckInstanceType::GetCheckInterval(InstanceType* first, 935 InstanceType* last) { 936 ASSERT(is_interval_check()); 937 switch (check_) { 938 case IS_SPEC_OBJECT: 939 *first = FIRST_SPEC_OBJECT_TYPE; 940 *last = LAST_SPEC_OBJECT_TYPE; 941 return; 942 case IS_JS_ARRAY: 943 *first = *last = JS_ARRAY_TYPE; 944 return; 945 default: 946 UNREACHABLE(); 947 } 948 } 949 950 951 void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) { 952 ASSERT(!is_interval_check()); 953 switch (check_) { 954 case IS_STRING: 955 *mask = kIsNotStringMask; 956 *tag = kStringTag; 957 return; 958 case IS_SYMBOL: 959 *mask = kIsSymbolMask; 960 *tag = kSymbolTag; 961 return; 962 default: 963 UNREACHABLE(); 964 } 965 } 966 967 968 void HCheckMap::PrintDataTo(StringStream* stream) { 969 value()->PrintNameTo(stream); 970 stream->Add(" %p", *map()); 971 if (mode() == REQUIRE_EXACT_MAP) { 972 stream->Add(" [EXACT]"); 973 } else if (!has_element_transitions_) { 974 stream->Add(" [EXACT*]"); 975 } else { 976 stream->Add(" [MATCH ELEMENTS]"); 977 } 978 } 979 980 981 void HCheckFunction::PrintDataTo(StringStream* stream) { 982 value()->PrintNameTo(stream); 983 stream->Add(" %p", *target()); 984 } 985 986 987 const char* HCheckInstanceType::GetCheckName() { 988 switch (check_) { 989 case IS_SPEC_OBJECT: return "object"; 990 case IS_JS_ARRAY: return "array"; 991 case IS_STRING: return "string"; 992 case IS_SYMBOL: return "symbol"; 993 } 994 UNREACHABLE(); 995 return ""; 996 } 997 998 void HCheckInstanceType::PrintDataTo(StringStream* stream) { 999 stream->Add("%s ", GetCheckName()); 1000 HUnaryOperation::PrintDataTo(stream); 1001 } 1002 1003 1004 void HCallStub::PrintDataTo(StringStream* stream) { 1005 stream->Add("%s ", 1006 CodeStub::MajorName(major_key_, false)); 1007 HUnaryCall::PrintDataTo(stream); 1008 } 1009 1010 1011 void HInstanceOf::PrintDataTo(StringStream* stream) { 1012 left()->PrintNameTo(stream); 1013 stream->Add(" "); 1014 right()->PrintNameTo(stream); 1015 stream->Add(" "); 1016 context()->PrintNameTo(stream); 1017 } 1018 1019 1020 Range* HValue::InferRange(Zone* zone) { 1021 // Untagged integer32 cannot be -0, all other representations can. 1022 Range* result = new(zone) Range(); 1023 result->set_can_be_minus_zero(!representation().IsInteger32()); 1024 return result; 1025 } 1026 1027 1028 Range* HChange::InferRange(Zone* zone) { 1029 Range* input_range = value()->range(); 1030 if (from().IsInteger32() && 1031 to().IsTagged() && 1032 input_range != NULL && input_range->IsInSmiRange()) { 1033 set_type(HType::Smi()); 1034 } 1035 Range* result = (input_range != NULL) 1036 ? input_range->Copy(zone) 1037 : HValue::InferRange(zone); 1038 if (to().IsInteger32()) result->set_can_be_minus_zero(false); 1039 return result; 1040 } 1041 1042 1043 Range* HConstant::InferRange(Zone* zone) { 1044 if (has_int32_value_) { 1045 Range* result = new(zone) Range(int32_value_, int32_value_); 1046 result->set_can_be_minus_zero(false); 1047 return result; 1048 } 1049 return HValue::InferRange(zone); 1050 } 1051 1052 1053 Range* HPhi::InferRange(Zone* zone) { 1054 if (representation().IsInteger32()) { 1055 if (block()->IsLoopHeader()) { 1056 Range* range = new(zone) Range(kMinInt, kMaxInt); 1057 return range; 1058 } else { 1059 Range* range = OperandAt(0)->range()->Copy(zone); 1060 for (int i = 1; i < OperandCount(); ++i) { 1061 range->Union(OperandAt(i)->range()); 1062 } 1063 return range; 1064 } 1065 } else { 1066 return HValue::InferRange(zone); 1067 } 1068 } 1069 1070 1071 Range* HAdd::InferRange(Zone* zone) { 1072 if (representation().IsInteger32()) { 1073 Range* a = left()->range(); 1074 Range* b = right()->range(); 1075 Range* res = a->Copy(zone); 1076 if (!res->AddAndCheckOverflow(b)) { 1077 ClearFlag(kCanOverflow); 1078 } 1079 bool m0 = a->CanBeMinusZero() && b->CanBeMinusZero(); 1080 res->set_can_be_minus_zero(m0); 1081 return res; 1082 } else { 1083 return HValue::InferRange(zone); 1084 } 1085 } 1086 1087 1088 Range* HSub::InferRange(Zone* zone) { 1089 if (representation().IsInteger32()) { 1090 Range* a = left()->range(); 1091 Range* b = right()->range(); 1092 Range* res = a->Copy(zone); 1093 if (!res->SubAndCheckOverflow(b)) { 1094 ClearFlag(kCanOverflow); 1095 } 1096 res->set_can_be_minus_zero(a->CanBeMinusZero() && b->CanBeZero()); 1097 return res; 1098 } else { 1099 return HValue::InferRange(zone); 1100 } 1101 } 1102 1103 1104 Range* HMul::InferRange(Zone* zone) { 1105 if (representation().IsInteger32()) { 1106 Range* a = left()->range(); 1107 Range* b = right()->range(); 1108 Range* res = a->Copy(zone); 1109 if (!res->MulAndCheckOverflow(b)) { 1110 ClearFlag(kCanOverflow); 1111 } 1112 bool m0 = (a->CanBeZero() && b->CanBeNegative()) || 1113 (a->CanBeNegative() && b->CanBeZero()); 1114 res->set_can_be_minus_zero(m0); 1115 return res; 1116 } else { 1117 return HValue::InferRange(zone); 1118 } 1119 } 1120 1121 1122 Range* HDiv::InferRange(Zone* zone) { 1123 if (representation().IsInteger32()) { 1124 Range* result = new(zone) Range(); 1125 if (left()->range()->CanBeMinusZero()) { 1126 result->set_can_be_minus_zero(true); 1127 } 1128 1129 if (left()->range()->CanBeZero() && right()->range()->CanBeNegative()) { 1130 result->set_can_be_minus_zero(true); 1131 } 1132 1133 if (right()->range()->Includes(-1) && left()->range()->Includes(kMinInt)) { 1134 SetFlag(HValue::kCanOverflow); 1135 } 1136 1137 if (!right()->range()->CanBeZero()) { 1138 ClearFlag(HValue::kCanBeDivByZero); 1139 } 1140 return result; 1141 } else { 1142 return HValue::InferRange(zone); 1143 } 1144 } 1145 1146 1147 Range* HMod::InferRange(Zone* zone) { 1148 if (representation().IsInteger32()) { 1149 Range* a = left()->range(); 1150 Range* result = new(zone) Range(); 1151 if (a->CanBeMinusZero() || a->CanBeNegative()) { 1152 result->set_can_be_minus_zero(true); 1153 } 1154 if (!right()->range()->CanBeZero()) { 1155 ClearFlag(HValue::kCanBeDivByZero); 1156 } 1157 return result; 1158 } else { 1159 return HValue::InferRange(zone); 1160 } 1161 } 1162 1163 1164 void HPhi::PrintTo(StringStream* stream) { 1165 stream->Add("["); 1166 for (int i = 0; i < OperandCount(); ++i) { 1167 HValue* value = OperandAt(i); 1168 stream->Add(" "); 1169 value->PrintNameTo(stream); 1170 stream->Add(" "); 1171 } 1172 stream->Add(" uses%d_%di_%dd_%dt", 1173 UseCount(), 1174 int32_non_phi_uses() + int32_indirect_uses(), 1175 double_non_phi_uses() + double_indirect_uses(), 1176 tagged_non_phi_uses() + tagged_indirect_uses()); 1177 stream->Add("%s%s]", 1178 is_live() ? "_live" : "", 1179 IsConvertibleToInteger() ? "" : "_ncti"); 1180 } 1181 1182 1183 void HPhi::AddInput(HValue* value) { 1184 inputs_.Add(NULL); 1185 SetOperandAt(OperandCount() - 1, value); 1186 // Mark phis that may have 'arguments' directly or indirectly as an operand. 1187 if (!CheckFlag(kIsArguments) && value->CheckFlag(kIsArguments)) { 1188 SetFlag(kIsArguments); 1189 } 1190 } 1191 1192 1193 bool HPhi::HasRealUses() { 1194 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 1195 if (!it.value()->IsPhi()) return true; 1196 } 1197 return false; 1198 } 1199 1200 1201 HValue* HPhi::GetRedundantReplacement() { 1202 HValue* candidate = NULL; 1203 int count = OperandCount(); 1204 int position = 0; 1205 while (position < count && candidate == NULL) { 1206 HValue* current = OperandAt(position++); 1207 if (current != this) candidate = current; 1208 } 1209 while (position < count) { 1210 HValue* current = OperandAt(position++); 1211 if (current != this && current != candidate) return NULL; 1212 } 1213 ASSERT(candidate != this); 1214 return candidate; 1215 } 1216 1217 1218 void HPhi::DeleteFromGraph() { 1219 ASSERT(block() != NULL); 1220 block()->RemovePhi(this); 1221 ASSERT(block() == NULL); 1222 } 1223 1224 1225 void HPhi::InitRealUses(int phi_id) { 1226 // Initialize real uses. 1227 phi_id_ = phi_id; 1228 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 1229 HValue* value = it.value(); 1230 if (!value->IsPhi()) { 1231 Representation rep = value->RequiredInputRepresentation(it.index()); 1232 non_phi_uses_[rep.kind()] += value->LoopWeight(); 1233 } 1234 } 1235 } 1236 1237 1238 void HPhi::AddNonPhiUsesFrom(HPhi* other) { 1239 for (int i = 0; i < Representation::kNumRepresentations; i++) { 1240 indirect_uses_[i] += other->non_phi_uses_[i]; 1241 } 1242 } 1243 1244 1245 void HPhi::AddIndirectUsesTo(int* dest) { 1246 for (int i = 0; i < Representation::kNumRepresentations; i++) { 1247 dest[i] += indirect_uses_[i]; 1248 } 1249 } 1250 1251 1252 void HSimulate::PrintDataTo(StringStream* stream) { 1253 stream->Add("id=%d", ast_id()); 1254 if (pop_count_ > 0) stream->Add(" pop %d", pop_count_); 1255 if (values_.length() > 0) { 1256 if (pop_count_ > 0) stream->Add(" /"); 1257 for (int i = 0; i < values_.length(); ++i) { 1258 if (i > 0) stream->Add(","); 1259 if (HasAssignedIndexAt(i)) { 1260 stream->Add(" var[%d] = ", GetAssignedIndexAt(i)); 1261 } else { 1262 stream->Add(" push "); 1263 } 1264 values_[i]->PrintNameTo(stream); 1265 } 1266 } 1267 } 1268 1269 1270 void HDeoptimize::PrintDataTo(StringStream* stream) { 1271 if (OperandCount() == 0) return; 1272 OperandAt(0)->PrintNameTo(stream); 1273 for (int i = 1; i < OperandCount(); ++i) { 1274 stream->Add(" "); 1275 OperandAt(i)->PrintNameTo(stream); 1276 } 1277 } 1278 1279 1280 void HEnterInlined::PrintDataTo(StringStream* stream) { 1281 SmartArrayPointer<char> name = function()->debug_name()->ToCString(); 1282 stream->Add("%s, id=%d", *name, function()->id()); 1283 } 1284 1285 1286 HConstant::HConstant(Handle<Object> handle, Representation r) 1287 : handle_(handle), 1288 has_int32_value_(false), 1289 has_double_value_(false), 1290 int32_value_(0), 1291 double_value_(0) { 1292 set_representation(r); 1293 SetFlag(kUseGVN); 1294 if (handle_->IsNumber()) { 1295 double n = handle_->Number(); 1296 double roundtrip_value = static_cast<double>(static_cast<int32_t>(n)); 1297 has_int32_value_ = BitCast<int64_t>(roundtrip_value) == BitCast<int64_t>(n); 1298 if (has_int32_value_) int32_value_ = static_cast<int32_t>(n); 1299 double_value_ = n; 1300 has_double_value_ = true; 1301 } 1302 } 1303 1304 1305 HConstant* HConstant::CopyToRepresentation(Representation r) const { 1306 if (r.IsInteger32() && !has_int32_value_) return NULL; 1307 if (r.IsDouble() && !has_double_value_) return NULL; 1308 return new HConstant(handle_, r); 1309 } 1310 1311 1312 HConstant* HConstant::CopyToTruncatedInt32() const { 1313 if (!has_double_value_) return NULL; 1314 int32_t truncated = NumberToInt32(*handle_); 1315 return new HConstant(FACTORY->NewNumberFromInt(truncated), 1316 Representation::Integer32()); 1317 } 1318 1319 1320 bool HConstant::ToBoolean() const { 1321 // Converts the constant's boolean value according to 1322 // ECMAScript section 9.2 ToBoolean conversion. 1323 if (HasInteger32Value()) return Integer32Value() != 0; 1324 if (HasDoubleValue()) { 1325 double v = DoubleValue(); 1326 return v != 0 && !isnan(v); 1327 } 1328 if (handle()->IsTrue()) return true; 1329 if (handle()->IsFalse()) return false; 1330 if (handle()->IsUndefined()) return false; 1331 if (handle()->IsNull()) return false; 1332 if (handle()->IsString() && 1333 String::cast(*handle())->length() == 0) return false; 1334 return true; 1335 } 1336 1337 void HConstant::PrintDataTo(StringStream* stream) { 1338 handle()->ShortPrint(stream); 1339 } 1340 1341 1342 bool HArrayLiteral::IsCopyOnWrite() const { 1343 if (!boilerplate_object_->IsJSObject()) return false; 1344 return Handle<JSObject>::cast(boilerplate_object_)->elements()->map() == 1345 HEAP->fixed_cow_array_map(); 1346 } 1347 1348 1349 void HBinaryOperation::PrintDataTo(StringStream* stream) { 1350 left()->PrintNameTo(stream); 1351 stream->Add(" "); 1352 right()->PrintNameTo(stream); 1353 if (CheckFlag(kCanOverflow)) stream->Add(" !"); 1354 if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?"); 1355 } 1356 1357 1358 Range* HBitwise::InferRange(Zone* zone) { 1359 if (op() == Token::BIT_XOR) return HValue::InferRange(zone); 1360 const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff); 1361 int32_t left_mask = (left()->range() != NULL) 1362 ? left()->range()->Mask() 1363 : kDefaultMask; 1364 int32_t right_mask = (right()->range() != NULL) 1365 ? right()->range()->Mask() 1366 : kDefaultMask; 1367 int32_t result_mask = (op() == Token::BIT_AND) 1368 ? left_mask & right_mask 1369 : left_mask | right_mask; 1370 return (result_mask >= 0) 1371 ? new(zone) Range(0, result_mask) 1372 : HValue::InferRange(zone); 1373 } 1374 1375 1376 Range* HSar::InferRange(Zone* zone) { 1377 if (right()->IsConstant()) { 1378 HConstant* c = HConstant::cast(right()); 1379 if (c->HasInteger32Value()) { 1380 Range* result = (left()->range() != NULL) 1381 ? left()->range()->Copy(zone) 1382 : new(zone) Range(); 1383 result->Sar(c->Integer32Value()); 1384 result->set_can_be_minus_zero(false); 1385 return result; 1386 } 1387 } 1388 return HValue::InferRange(zone); 1389 } 1390 1391 1392 Range* HShr::InferRange(Zone* zone) { 1393 if (right()->IsConstant()) { 1394 HConstant* c = HConstant::cast(right()); 1395 if (c->HasInteger32Value()) { 1396 int shift_count = c->Integer32Value() & 0x1f; 1397 if (left()->range()->CanBeNegative()) { 1398 // Only compute bounds if the result always fits into an int32. 1399 return (shift_count >= 1) 1400 ? new(zone) Range(0, 1401 static_cast<uint32_t>(0xffffffff) >> shift_count) 1402 : new(zone) Range(); 1403 } else { 1404 // For positive inputs we can use the >> operator. 1405 Range* result = (left()->range() != NULL) 1406 ? left()->range()->Copy(zone) 1407 : new(zone) Range(); 1408 result->Sar(c->Integer32Value()); 1409 result->set_can_be_minus_zero(false); 1410 return result; 1411 } 1412 } 1413 } 1414 return HValue::InferRange(zone); 1415 } 1416 1417 1418 Range* HShl::InferRange(Zone* zone) { 1419 if (right()->IsConstant()) { 1420 HConstant* c = HConstant::cast(right()); 1421 if (c->HasInteger32Value()) { 1422 Range* result = (left()->range() != NULL) 1423 ? left()->range()->Copy(zone) 1424 : new(zone) Range(); 1425 result->Shl(c->Integer32Value()); 1426 result->set_can_be_minus_zero(false); 1427 return result; 1428 } 1429 } 1430 return HValue::InferRange(zone); 1431 } 1432 1433 1434 Range* HLoadKeyedSpecializedArrayElement::InferRange(Zone* zone) { 1435 switch (elements_kind()) { 1436 case EXTERNAL_PIXEL_ELEMENTS: 1437 return new(zone) Range(0, 255); 1438 case EXTERNAL_BYTE_ELEMENTS: 1439 return new(zone) Range(-128, 127); 1440 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 1441 return new(zone) Range(0, 255); 1442 case EXTERNAL_SHORT_ELEMENTS: 1443 return new(zone) Range(-32768, 32767); 1444 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 1445 return new(zone) Range(0, 65535); 1446 default: 1447 return HValue::InferRange(zone); 1448 } 1449 } 1450 1451 1452 void HCompareGeneric::PrintDataTo(StringStream* stream) { 1453 stream->Add(Token::Name(token())); 1454 stream->Add(" "); 1455 HBinaryOperation::PrintDataTo(stream); 1456 } 1457 1458 1459 void HStringCompareAndBranch::PrintDataTo(StringStream* stream) { 1460 stream->Add(Token::Name(token())); 1461 stream->Add(" "); 1462 HControlInstruction::PrintDataTo(stream); 1463 } 1464 1465 1466 void HCompareIDAndBranch::PrintDataTo(StringStream* stream) { 1467 stream->Add(Token::Name(token())); 1468 stream->Add(" "); 1469 left()->PrintNameTo(stream); 1470 stream->Add(" "); 1471 right()->PrintNameTo(stream); 1472 HControlInstruction::PrintDataTo(stream); 1473 } 1474 1475 1476 void HCompareObjectEqAndBranch::PrintDataTo(StringStream* stream) { 1477 left()->PrintNameTo(stream); 1478 stream->Add(" "); 1479 right()->PrintNameTo(stream); 1480 HControlInstruction::PrintDataTo(stream); 1481 } 1482 1483 1484 void HGoto::PrintDataTo(StringStream* stream) { 1485 stream->Add("B%d", SuccessorAt(0)->block_id()); 1486 } 1487 1488 1489 void HCompareIDAndBranch::SetInputRepresentation(Representation r) { 1490 input_representation_ = r; 1491 if (r.IsDouble()) { 1492 // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, === 1493 // and !=) have special handling of undefined, e.g. undefined == undefined 1494 // is 'true'. Relational comparisons have a different semantic, first 1495 // calling ToPrimitive() on their arguments. The standard Crankshaft 1496 // tagged-to-double conversion to ensure the HCompareIDAndBranch's inputs 1497 // are doubles caused 'undefined' to be converted to NaN. That's compatible 1498 // out-of-the box with ordered relational comparisons (<, >, <=, 1499 // >=). However, for equality comparisons (and for 'in' and 'instanceof'), 1500 // it is not consistent with the spec. For example, it would cause undefined 1501 // == undefined (should be true) to be evaluated as NaN == NaN 1502 // (false). Therefore, any comparisons other than ordered relational 1503 // comparisons must cause a deopt when one of their arguments is undefined. 1504 // See also v8:1434 1505 if (!Token::IsOrderedRelationalCompareOp(token_)) { 1506 SetFlag(kDeoptimizeOnUndefined); 1507 } 1508 } else { 1509 ASSERT(r.IsInteger32()); 1510 } 1511 } 1512 1513 1514 void HParameter::PrintDataTo(StringStream* stream) { 1515 stream->Add("%u", index()); 1516 } 1517 1518 1519 void HLoadNamedField::PrintDataTo(StringStream* stream) { 1520 object()->PrintNameTo(stream); 1521 stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : ""); 1522 } 1523 1524 1525 HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context, 1526 HValue* object, 1527 SmallMapList* types, 1528 Handle<String> name) 1529 : types_(Min(types->length(), kMaxLoadPolymorphism)), 1530 name_(name), 1531 need_generic_(false) { 1532 SetOperandAt(0, context); 1533 SetOperandAt(1, object); 1534 set_representation(Representation::Tagged()); 1535 SetGVNFlag(kDependsOnMaps); 1536 for (int i = 0; 1537 i < types->length() && types_.length() < kMaxLoadPolymorphism; 1538 ++i) { 1539 Handle<Map> map = types->at(i); 1540 LookupResult lookup(map->GetIsolate()); 1541 map->LookupInDescriptors(NULL, *name, &lookup); 1542 if (lookup.IsFound()) { 1543 switch (lookup.type()) { 1544 case FIELD: { 1545 int index = lookup.GetLocalFieldIndexFromMap(*map); 1546 if (index < 0) { 1547 SetGVNFlag(kDependsOnInobjectFields); 1548 } else { 1549 SetGVNFlag(kDependsOnBackingStoreFields); 1550 } 1551 types_.Add(types->at(i)); 1552 break; 1553 } 1554 case CONSTANT_FUNCTION: 1555 types_.Add(types->at(i)); 1556 break; 1557 default: 1558 break; 1559 } 1560 } 1561 } 1562 1563 if (types_.length() == types->length() && FLAG_deoptimize_uncommon_cases) { 1564 SetFlag(kUseGVN); 1565 } else { 1566 SetAllSideEffects(); 1567 need_generic_ = true; 1568 } 1569 } 1570 1571 1572 bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) { 1573 HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value); 1574 if (types_.length() != other->types()->length()) return false; 1575 if (!name_.is_identical_to(other->name())) return false; 1576 if (need_generic_ != other->need_generic_) return false; 1577 for (int i = 0; i < types_.length(); i++) { 1578 bool found = false; 1579 for (int j = 0; j < types_.length(); j++) { 1580 if (types_.at(j).is_identical_to(other->types()->at(i))) { 1581 found = true; 1582 break; 1583 } 1584 } 1585 if (!found) return false; 1586 } 1587 return true; 1588 } 1589 1590 1591 void HLoadNamedFieldPolymorphic::PrintDataTo(StringStream* stream) { 1592 object()->PrintNameTo(stream); 1593 stream->Add("."); 1594 stream->Add(*String::cast(*name())->ToCString()); 1595 } 1596 1597 1598 void HLoadNamedGeneric::PrintDataTo(StringStream* stream) { 1599 object()->PrintNameTo(stream); 1600 stream->Add("."); 1601 stream->Add(*String::cast(*name())->ToCString()); 1602 } 1603 1604 1605 void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) { 1606 object()->PrintNameTo(stream); 1607 stream->Add("["); 1608 key()->PrintNameTo(stream); 1609 stream->Add("]"); 1610 } 1611 1612 1613 bool HLoadKeyedFastElement::RequiresHoleCheck() { 1614 if (hole_check_mode_ == OMIT_HOLE_CHECK) { 1615 return false; 1616 } 1617 1618 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 1619 HValue* use = it.value(); 1620 if (!use->IsChange()) return true; 1621 } 1622 1623 return false; 1624 } 1625 1626 1627 void HLoadKeyedFastDoubleElement::PrintDataTo(StringStream* stream) { 1628 elements()->PrintNameTo(stream); 1629 stream->Add("["); 1630 key()->PrintNameTo(stream); 1631 stream->Add("]"); 1632 } 1633 1634 1635 void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) { 1636 object()->PrintNameTo(stream); 1637 stream->Add("["); 1638 key()->PrintNameTo(stream); 1639 stream->Add("]"); 1640 } 1641 1642 1643 HValue* HLoadKeyedGeneric::Canonicalize() { 1644 // Recognize generic keyed loads that use property name generated 1645 // by for-in statement as a key and rewrite them into fast property load 1646 // by index. 1647 if (key()->IsLoadKeyedFastElement()) { 1648 HLoadKeyedFastElement* key_load = HLoadKeyedFastElement::cast(key()); 1649 if (key_load->object()->IsForInCacheArray()) { 1650 HForInCacheArray* names_cache = 1651 HForInCacheArray::cast(key_load->object()); 1652 1653 if (names_cache->enumerable() == object()) { 1654 HForInCacheArray* index_cache = 1655 names_cache->index_cache(); 1656 HCheckMapValue* map_check = 1657 new(block()->zone()) HCheckMapValue(object(), names_cache->map()); 1658 HInstruction* index = new(block()->zone()) HLoadKeyedFastElement( 1659 index_cache, 1660 key_load->key(), 1661 HLoadKeyedFastElement::OMIT_HOLE_CHECK); 1662 HLoadFieldByIndex* load = new(block()->zone()) HLoadFieldByIndex( 1663 object(), index); 1664 map_check->InsertBefore(this); 1665 index->InsertBefore(this); 1666 load->InsertBefore(this); 1667 return load; 1668 } 1669 } 1670 } 1671 1672 return this; 1673 } 1674 1675 1676 void HLoadKeyedSpecializedArrayElement::PrintDataTo( 1677 StringStream* stream) { 1678 external_pointer()->PrintNameTo(stream); 1679 stream->Add("."); 1680 switch (elements_kind()) { 1681 case EXTERNAL_BYTE_ELEMENTS: 1682 stream->Add("byte"); 1683 break; 1684 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 1685 stream->Add("u_byte"); 1686 break; 1687 case EXTERNAL_SHORT_ELEMENTS: 1688 stream->Add("short"); 1689 break; 1690 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 1691 stream->Add("u_short"); 1692 break; 1693 case EXTERNAL_INT_ELEMENTS: 1694 stream->Add("int"); 1695 break; 1696 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 1697 stream->Add("u_int"); 1698 break; 1699 case EXTERNAL_FLOAT_ELEMENTS: 1700 stream->Add("float"); 1701 break; 1702 case EXTERNAL_DOUBLE_ELEMENTS: 1703 stream->Add("double"); 1704 break; 1705 case EXTERNAL_PIXEL_ELEMENTS: 1706 stream->Add("pixel"); 1707 break; 1708 case FAST_ELEMENTS: 1709 case FAST_SMI_ONLY_ELEMENTS: 1710 case FAST_DOUBLE_ELEMENTS: 1711 case DICTIONARY_ELEMENTS: 1712 case NON_STRICT_ARGUMENTS_ELEMENTS: 1713 UNREACHABLE(); 1714 break; 1715 } 1716 stream->Add("["); 1717 key()->PrintNameTo(stream); 1718 stream->Add("]"); 1719 } 1720 1721 1722 void HStoreNamedGeneric::PrintDataTo(StringStream* stream) { 1723 object()->PrintNameTo(stream); 1724 stream->Add("."); 1725 ASSERT(name()->IsString()); 1726 stream->Add(*String::cast(*name())->ToCString()); 1727 stream->Add(" = "); 1728 value()->PrintNameTo(stream); 1729 } 1730 1731 1732 void HStoreNamedField::PrintDataTo(StringStream* stream) { 1733 object()->PrintNameTo(stream); 1734 stream->Add("."); 1735 stream->Add(*String::cast(*name())->ToCString()); 1736 stream->Add(" = "); 1737 value()->PrintNameTo(stream); 1738 stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : ""); 1739 if (!transition().is_null()) { 1740 stream->Add(" (transition map %p)", *transition()); 1741 } 1742 } 1743 1744 1745 void HStoreKeyedFastElement::PrintDataTo(StringStream* stream) { 1746 object()->PrintNameTo(stream); 1747 stream->Add("["); 1748 key()->PrintNameTo(stream); 1749 stream->Add("] = "); 1750 value()->PrintNameTo(stream); 1751 } 1752 1753 1754 void HStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) { 1755 elements()->PrintNameTo(stream); 1756 stream->Add("["); 1757 key()->PrintNameTo(stream); 1758 stream->Add("] = "); 1759 value()->PrintNameTo(stream); 1760 } 1761 1762 1763 void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) { 1764 object()->PrintNameTo(stream); 1765 stream->Add("["); 1766 key()->PrintNameTo(stream); 1767 stream->Add("] = "); 1768 value()->PrintNameTo(stream); 1769 } 1770 1771 1772 void HStoreKeyedSpecializedArrayElement::PrintDataTo( 1773 StringStream* stream) { 1774 external_pointer()->PrintNameTo(stream); 1775 stream->Add("."); 1776 switch (elements_kind()) { 1777 case EXTERNAL_BYTE_ELEMENTS: 1778 stream->Add("byte"); 1779 break; 1780 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 1781 stream->Add("u_byte"); 1782 break; 1783 case EXTERNAL_SHORT_ELEMENTS: 1784 stream->Add("short"); 1785 break; 1786 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 1787 stream->Add("u_short"); 1788 break; 1789 case EXTERNAL_INT_ELEMENTS: 1790 stream->Add("int"); 1791 break; 1792 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 1793 stream->Add("u_int"); 1794 break; 1795 case EXTERNAL_FLOAT_ELEMENTS: 1796 stream->Add("float"); 1797 break; 1798 case EXTERNAL_DOUBLE_ELEMENTS: 1799 stream->Add("double"); 1800 break; 1801 case EXTERNAL_PIXEL_ELEMENTS: 1802 stream->Add("pixel"); 1803 break; 1804 case FAST_SMI_ONLY_ELEMENTS: 1805 case FAST_ELEMENTS: 1806 case FAST_DOUBLE_ELEMENTS: 1807 case DICTIONARY_ELEMENTS: 1808 case NON_STRICT_ARGUMENTS_ELEMENTS: 1809 UNREACHABLE(); 1810 break; 1811 } 1812 stream->Add("["); 1813 key()->PrintNameTo(stream); 1814 stream->Add("] = "); 1815 value()->PrintNameTo(stream); 1816 } 1817 1818 1819 void HTransitionElementsKind::PrintDataTo(StringStream* stream) { 1820 object()->PrintNameTo(stream); 1821 stream->Add(" %p -> %p", *original_map(), *transitioned_map()); 1822 } 1823 1824 1825 void HLoadGlobalCell::PrintDataTo(StringStream* stream) { 1826 stream->Add("[%p]", *cell()); 1827 if (!details_.IsDontDelete()) stream->Add(" (deleteable)"); 1828 if (details_.IsReadOnly()) stream->Add(" (read-only)"); 1829 } 1830 1831 1832 bool HLoadGlobalCell::RequiresHoleCheck() { 1833 if (details_.IsDontDelete() && !details_.IsReadOnly()) return false; 1834 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 1835 HValue* use = it.value(); 1836 if (!use->IsChange()) return true; 1837 } 1838 return false; 1839 } 1840 1841 1842 void HLoadGlobalGeneric::PrintDataTo(StringStream* stream) { 1843 stream->Add("%o ", *name()); 1844 } 1845 1846 1847 void HStoreGlobalCell::PrintDataTo(StringStream* stream) { 1848 stream->Add("[%p] = ", *cell()); 1849 value()->PrintNameTo(stream); 1850 if (!details_.IsDontDelete()) stream->Add(" (deleteable)"); 1851 if (details_.IsReadOnly()) stream->Add(" (read-only)"); 1852 } 1853 1854 1855 void HStoreGlobalGeneric::PrintDataTo(StringStream* stream) { 1856 stream->Add("%o = ", *name()); 1857 value()->PrintNameTo(stream); 1858 } 1859 1860 1861 void HLoadContextSlot::PrintDataTo(StringStream* stream) { 1862 value()->PrintNameTo(stream); 1863 stream->Add("[%d]", slot_index()); 1864 } 1865 1866 1867 void HStoreContextSlot::PrintDataTo(StringStream* stream) { 1868 context()->PrintNameTo(stream); 1869 stream->Add("[%d] = ", slot_index()); 1870 value()->PrintNameTo(stream); 1871 } 1872 1873 1874 // Implementation of type inference and type conversions. Calculates 1875 // the inferred type of this instruction based on the input operands. 1876 1877 HType HValue::CalculateInferredType() { 1878 return type_; 1879 } 1880 1881 1882 HType HCheckMap::CalculateInferredType() { 1883 return value()->type(); 1884 } 1885 1886 1887 HType HCheckFunction::CalculateInferredType() { 1888 return value()->type(); 1889 } 1890 1891 1892 HType HCheckNonSmi::CalculateInferredType() { 1893 // TODO(kasperl): Is there any way to signal that this isn't a smi? 1894 return HType::Tagged(); 1895 } 1896 1897 1898 HType HCheckSmi::CalculateInferredType() { 1899 return HType::Smi(); 1900 } 1901 1902 1903 HType HPhi::CalculateInferredType() { 1904 HType result = HType::Uninitialized(); 1905 for (int i = 0; i < OperandCount(); ++i) { 1906 HType current = OperandAt(i)->type(); 1907 result = result.Combine(current); 1908 } 1909 return result; 1910 } 1911 1912 1913 HType HConstant::CalculateInferredType() { 1914 return HType::TypeFromValue(handle_); 1915 } 1916 1917 1918 HType HCompareGeneric::CalculateInferredType() { 1919 return HType::Boolean(); 1920 } 1921 1922 1923 HType HInstanceOf::CalculateInferredType() { 1924 return HType::Boolean(); 1925 } 1926 1927 1928 HType HDeleteProperty::CalculateInferredType() { 1929 return HType::Boolean(); 1930 } 1931 1932 1933 HType HInstanceOfKnownGlobal::CalculateInferredType() { 1934 return HType::Boolean(); 1935 } 1936 1937 1938 HType HChange::CalculateInferredType() { 1939 if (from().IsDouble() && to().IsTagged()) return HType::HeapNumber(); 1940 return type(); 1941 } 1942 1943 1944 HType HBitwiseBinaryOperation::CalculateInferredType() { 1945 return HType::TaggedNumber(); 1946 } 1947 1948 1949 HType HArithmeticBinaryOperation::CalculateInferredType() { 1950 return HType::TaggedNumber(); 1951 } 1952 1953 1954 HType HAdd::CalculateInferredType() { 1955 return HType::Tagged(); 1956 } 1957 1958 1959 HType HBitNot::CalculateInferredType() { 1960 return HType::TaggedNumber(); 1961 } 1962 1963 1964 HType HUnaryMathOperation::CalculateInferredType() { 1965 return HType::TaggedNumber(); 1966 } 1967 1968 1969 HType HStringCharFromCode::CalculateInferredType() { 1970 return HType::String(); 1971 } 1972 1973 1974 HType HAllocateObject::CalculateInferredType() { 1975 return HType::JSObject(); 1976 } 1977 1978 1979 HType HFastLiteral::CalculateInferredType() { 1980 // TODO(mstarzinger): Be smarter, could also be JSArray here. 1981 return HType::JSObject(); 1982 } 1983 1984 1985 HType HArrayLiteral::CalculateInferredType() { 1986 return HType::JSArray(); 1987 } 1988 1989 1990 HType HObjectLiteral::CalculateInferredType() { 1991 return HType::JSObject(); 1992 } 1993 1994 1995 HType HRegExpLiteral::CalculateInferredType() { 1996 return HType::JSObject(); 1997 } 1998 1999 2000 HType HFunctionLiteral::CalculateInferredType() { 2001 return HType::JSObject(); 2002 } 2003 2004 2005 HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero( 2006 BitVector* visited) { 2007 visited->Add(id()); 2008 if (representation().IsInteger32() && 2009 !value()->representation().IsInteger32()) { 2010 if (value()->range() == NULL || value()->range()->CanBeMinusZero()) { 2011 SetFlag(kBailoutOnMinusZero); 2012 } 2013 } 2014 if (RequiredInputRepresentation(0).IsInteger32() && 2015 representation().IsInteger32()) { 2016 return value(); 2017 } 2018 return NULL; 2019 } 2020 2021 2022 2023 HValue* HChange::EnsureAndPropagateNotMinusZero(BitVector* visited) { 2024 visited->Add(id()); 2025 if (from().IsInteger32()) return NULL; 2026 if (CanTruncateToInt32()) return NULL; 2027 if (value()->range() == NULL || value()->range()->CanBeMinusZero()) { 2028 SetFlag(kBailoutOnMinusZero); 2029 } 2030 ASSERT(!from().IsInteger32() || !to().IsInteger32()); 2031 return NULL; 2032 } 2033 2034 2035 HValue* HForceRepresentation::EnsureAndPropagateNotMinusZero( 2036 BitVector* visited) { 2037 visited->Add(id()); 2038 return value(); 2039 } 2040 2041 2042 HValue* HMod::EnsureAndPropagateNotMinusZero(BitVector* visited) { 2043 visited->Add(id()); 2044 if (range() == NULL || range()->CanBeMinusZero()) { 2045 SetFlag(kBailoutOnMinusZero); 2046 return left(); 2047 } 2048 return NULL; 2049 } 2050 2051 2052 HValue* HDiv::EnsureAndPropagateNotMinusZero(BitVector* visited) { 2053 visited->Add(id()); 2054 if (range() == NULL || range()->CanBeMinusZero()) { 2055 SetFlag(kBailoutOnMinusZero); 2056 } 2057 return NULL; 2058 } 2059 2060 2061 HValue* HMul::EnsureAndPropagateNotMinusZero(BitVector* visited) { 2062 visited->Add(id()); 2063 if (range() == NULL || range()->CanBeMinusZero()) { 2064 SetFlag(kBailoutOnMinusZero); 2065 } 2066 return NULL; 2067 } 2068 2069 2070 HValue* HSub::EnsureAndPropagateNotMinusZero(BitVector* visited) { 2071 visited->Add(id()); 2072 // Propagate to the left argument. If the left argument cannot be -0, then 2073 // the result of the add operation cannot be either. 2074 if (range() == NULL || range()->CanBeMinusZero()) { 2075 return left(); 2076 } 2077 return NULL; 2078 } 2079 2080 2081 HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) { 2082 visited->Add(id()); 2083 // Propagate to the left argument. If the left argument cannot be -0, then 2084 // the result of the sub operation cannot be either. 2085 if (range() == NULL || range()->CanBeMinusZero()) { 2086 return left(); 2087 } 2088 return NULL; 2089 } 2090 2091 2092 #define H_CONSTANT_INT32(val) \ 2093 new(zone) HConstant(FACTORY->NewNumberFromInt(val, TENURED), \ 2094 Representation::Integer32()) 2095 #define H_CONSTANT_DOUBLE(val) \ 2096 new(zone) HConstant(FACTORY->NewNumber(val, TENURED), \ 2097 Representation::Double()) 2098 2099 #define DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HInstr, op) \ 2100 HInstruction* HInstr::New##HInstr(Zone* zone, \ 2101 HValue* context, \ 2102 HValue* left, \ 2103 HValue* right) { \ 2104 if (left->IsConstant() && right->IsConstant()) { \ 2105 HConstant* c_left = HConstant::cast(left); \ 2106 HConstant* c_right = HConstant::cast(right); \ 2107 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \ 2108 double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \ 2109 if (TypeInfo::IsInt32Double(double_res)) { \ 2110 return H_CONSTANT_INT32(static_cast<int32_t>(double_res)); \ 2111 } \ 2112 return H_CONSTANT_DOUBLE(double_res); \ 2113 } \ 2114 } \ 2115 return new(zone) HInstr(context, left, right); \ 2116 } 2117 2118 2119 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HAdd, +) 2120 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HMul, *) 2121 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HSub, -) 2122 2123 #undef DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR 2124 2125 2126 HInstruction* HMod::NewHMod(Zone* zone, 2127 HValue* context, 2128 HValue* left, 2129 HValue* right) { 2130 if (left->IsConstant() && right->IsConstant()) { 2131 HConstant* c_left = HConstant::cast(left); 2132 HConstant* c_right = HConstant::cast(right); 2133 if (c_left->HasInteger32Value() && c_right->HasInteger32Value()) { 2134 int32_t dividend = c_left->Integer32Value(); 2135 int32_t divisor = c_right->Integer32Value(); 2136 if (divisor != 0) { 2137 int32_t res = dividend % divisor; 2138 if ((res == 0) && (dividend < 0)) { 2139 return H_CONSTANT_DOUBLE(-0.0); 2140 } 2141 return H_CONSTANT_INT32(res); 2142 } 2143 } 2144 } 2145 return new(zone) HMod(context, left, right); 2146 } 2147 2148 2149 HInstruction* HDiv::NewHDiv(Zone* zone, 2150 HValue* context, 2151 HValue* left, 2152 HValue* right) { 2153 // If left and right are constant values, try to return a constant value. 2154 if (left->IsConstant() && right->IsConstant()) { 2155 HConstant* c_left = HConstant::cast(left); 2156 HConstant* c_right = HConstant::cast(right); 2157 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { 2158 if (c_right->DoubleValue() != 0) { 2159 double double_res = c_left->DoubleValue() / c_right->DoubleValue(); 2160 if (TypeInfo::IsInt32Double(double_res)) { 2161 return H_CONSTANT_INT32(static_cast<int32_t>(double_res)); 2162 } 2163 return H_CONSTANT_DOUBLE(double_res); 2164 } 2165 } 2166 } 2167 return new(zone) HDiv(context, left, right); 2168 } 2169 2170 2171 HInstruction* HBitwise::NewHBitwise(Zone* zone, 2172 Token::Value op, 2173 HValue* context, 2174 HValue* left, 2175 HValue* right) { 2176 if (left->IsConstant() && right->IsConstant()) { 2177 HConstant* c_left = HConstant::cast(left); 2178 HConstant* c_right = HConstant::cast(right); 2179 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { 2180 int32_t result; 2181 int32_t v_left = c_left->NumberValueAsInteger32(); 2182 int32_t v_right = c_right->NumberValueAsInteger32(); 2183 switch (op) { 2184 case Token::BIT_XOR: 2185 result = v_left ^ v_right; 2186 break; 2187 case Token::BIT_AND: 2188 result = v_left & v_right; 2189 break; 2190 case Token::BIT_OR: 2191 result = v_left | v_right; 2192 break; 2193 default: 2194 result = 0; // Please the compiler. 2195 UNREACHABLE(); 2196 } 2197 return H_CONSTANT_INT32(result); 2198 } 2199 } 2200 return new(zone) HBitwise(op, context, left, right); 2201 } 2202 2203 2204 #define DEFINE_NEW_H_BITWISE_INSTR(HInstr, result) \ 2205 HInstruction* HInstr::New##HInstr(Zone* zone, \ 2206 HValue* context, \ 2207 HValue* left, \ 2208 HValue* right) { \ 2209 if (left->IsConstant() && right->IsConstant()) { \ 2210 HConstant* c_left = HConstant::cast(left); \ 2211 HConstant* c_right = HConstant::cast(right); \ 2212 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \ 2213 return H_CONSTANT_INT32(result); \ 2214 } \ 2215 } \ 2216 return new(zone) HInstr(context, left, right); \ 2217 } 2218 2219 2220 DEFINE_NEW_H_BITWISE_INSTR(HSar, 2221 c_left->NumberValueAsInteger32() >> (c_right->NumberValueAsInteger32() & 0x1f)) 2222 DEFINE_NEW_H_BITWISE_INSTR(HShl, 2223 c_left->NumberValueAsInteger32() << (c_right->NumberValueAsInteger32() & 0x1f)) 2224 2225 #undef DEFINE_NEW_H_BITWISE_INSTR 2226 2227 2228 HInstruction* HShr::NewHShr(Zone* zone, 2229 HValue* context, 2230 HValue* left, 2231 HValue* right) { 2232 if (left->IsConstant() && right->IsConstant()) { 2233 HConstant* c_left = HConstant::cast(left); 2234 HConstant* c_right = HConstant::cast(right); 2235 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { 2236 int32_t left_val = c_left->NumberValueAsInteger32(); 2237 int32_t right_val = c_right->NumberValueAsInteger32() & 0x1f; 2238 if ((right_val == 0) && (left_val < 0)) { 2239 return H_CONSTANT_DOUBLE( 2240 static_cast<double>(static_cast<uint32_t>(left_val))); 2241 } 2242 return H_CONSTANT_INT32(static_cast<uint32_t>(left_val) >> right_val); 2243 } 2244 } 2245 return new(zone) HShr(context, left, right); 2246 } 2247 2248 2249 #undef H_CONSTANT_INT32 2250 #undef H_CONSTANT_DOUBLE 2251 2252 2253 void HIn::PrintDataTo(StringStream* stream) { 2254 key()->PrintNameTo(stream); 2255 stream->Add(" "); 2256 object()->PrintNameTo(stream); 2257 } 2258 2259 2260 Representation HPhi::InferredRepresentation() { 2261 bool double_occurred = false; 2262 bool int32_occurred = false; 2263 for (int i = 0; i < OperandCount(); ++i) { 2264 HValue* value = OperandAt(i); 2265 if (value->IsUnknownOSRValue()) { 2266 HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value(); 2267 if (hint_value != NULL) { 2268 Representation hint = hint_value->representation(); 2269 if (hint.IsDouble()) double_occurred = true; 2270 if (hint.IsInteger32()) int32_occurred = true; 2271 } 2272 continue; 2273 } 2274 if (value->representation().IsDouble()) double_occurred = true; 2275 if (value->representation().IsInteger32()) int32_occurred = true; 2276 if (value->representation().IsTagged()) { 2277 if (value->IsConstant()) { 2278 HConstant* constant = HConstant::cast(value); 2279 if (constant->IsConvertibleToInteger()) { 2280 int32_occurred = true; 2281 } else if (constant->HasNumberValue()) { 2282 double_occurred = true; 2283 } else { 2284 return Representation::Tagged(); 2285 } 2286 } else { 2287 return Representation::Tagged(); 2288 } 2289 } 2290 } 2291 2292 if (double_occurred) return Representation::Double(); 2293 2294 if (int32_occurred) return Representation::Integer32(); 2295 2296 return Representation::None(); 2297 } 2298 2299 2300 // Node-specific verification code is only included in debug mode. 2301 #ifdef DEBUG 2302 2303 void HPhi::Verify() { 2304 ASSERT(OperandCount() == block()->predecessors()->length()); 2305 for (int i = 0; i < OperandCount(); ++i) { 2306 HValue* value = OperandAt(i); 2307 HBasicBlock* defining_block = value->block(); 2308 HBasicBlock* predecessor_block = block()->predecessors()->at(i); 2309 ASSERT(defining_block == predecessor_block || 2310 defining_block->Dominates(predecessor_block)); 2311 } 2312 } 2313 2314 2315 void HSimulate::Verify() { 2316 HInstruction::Verify(); 2317 ASSERT(HasAstId()); 2318 } 2319 2320 2321 void HCheckSmi::Verify() { 2322 HInstruction::Verify(); 2323 ASSERT(HasNoUses()); 2324 } 2325 2326 2327 void HCheckNonSmi::Verify() { 2328 HInstruction::Verify(); 2329 ASSERT(HasNoUses()); 2330 } 2331 2332 2333 void HCheckFunction::Verify() { 2334 HInstruction::Verify(); 2335 ASSERT(HasNoUses()); 2336 } 2337 2338 2339 void HCheckPrototypeMaps::Verify() { 2340 HInstruction::Verify(); 2341 ASSERT(HasNoUses()); 2342 } 2343 2344 #endif 2345 2346 } } // namespace v8::internal 2347