diff options
Diffstat (limited to 'deps/v8/src/crankshaft/hydrogen-instructions.cc')
-rw-r--r-- | deps/v8/src/crankshaft/hydrogen-instructions.cc | 4051 |
1 files changed, 0 insertions, 4051 deletions
diff --git a/deps/v8/src/crankshaft/hydrogen-instructions.cc b/deps/v8/src/crankshaft/hydrogen-instructions.cc deleted file mode 100644 index c0046fa98f..0000000000 --- a/deps/v8/src/crankshaft/hydrogen-instructions.cc +++ /dev/null @@ -1,4051 +0,0 @@ -// Copyright 2012 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "src/crankshaft/hydrogen-instructions.h" - -#include "src/base/bits.h" -#include "src/base/ieee754.h" -#include "src/base/safe_math.h" -#include "src/codegen.h" -#include "src/crankshaft/hydrogen-infer-representation.h" -#include "src/double.h" -#include "src/elements.h" -#include "src/factory.h" -#include "src/objects-inl.h" - -#if V8_TARGET_ARCH_IA32 -#include "src/crankshaft/ia32/lithium-ia32.h" // NOLINT -#elif V8_TARGET_ARCH_X64 -#include "src/crankshaft/x64/lithium-x64.h" // NOLINT -#elif V8_TARGET_ARCH_ARM64 -#include "src/crankshaft/arm64/lithium-arm64.h" // NOLINT -#elif V8_TARGET_ARCH_ARM -#include "src/crankshaft/arm/lithium-arm.h" // NOLINT -#elif V8_TARGET_ARCH_PPC -#include "src/crankshaft/ppc/lithium-ppc.h" // NOLINT -#elif V8_TARGET_ARCH_MIPS -#include "src/crankshaft/mips/lithium-mips.h" // NOLINT -#elif V8_TARGET_ARCH_MIPS64 -#include "src/crankshaft/mips64/lithium-mips64.h" // NOLINT -#elif V8_TARGET_ARCH_S390 -#include "src/crankshaft/s390/lithium-s390.h" // NOLINT -#elif V8_TARGET_ARCH_X87 -#include "src/crankshaft/x87/lithium-x87.h" // NOLINT -#else -#error Unsupported target architecture. -#endif - -namespace v8 { -namespace internal { - -#define DEFINE_COMPILE(type) \ - LInstruction* H##type::CompileToLithium(LChunkBuilder* builder) { \ - return builder->Do##type(this); \ - } -HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) -#undef DEFINE_COMPILE - -Representation RepresentationFromMachineType(MachineType type) { - if (type == MachineType::Int32()) { - return Representation::Integer32(); - } - - if (type == MachineType::TaggedSigned()) { - return Representation::Smi(); - } - - if (type == MachineType::Pointer()) { - return Representation::External(); - } - - return Representation::Tagged(); -} - -Isolate* HValue::isolate() const { - DCHECK(block() != NULL); - return block()->isolate(); -} - - -void HValue::AssumeRepresentation(Representation r) { - if (CheckFlag(kFlexibleRepresentation)) { - ChangeRepresentation(r); - // The representation of the value is dictated by type feedback and - // will not be changed later. - ClearFlag(kFlexibleRepresentation); - } -} - - -void HValue::InferRepresentation(HInferRepresentationPhase* h_infer) { - DCHECK(CheckFlag(kFlexibleRepresentation)); - Representation new_rep = RepresentationFromInputs(); - UpdateRepresentation(new_rep, h_infer, "inputs"); - new_rep = RepresentationFromUses(); - UpdateRepresentation(new_rep, h_infer, "uses"); - if (representation().IsSmi() && HasNonSmiUse()) { - UpdateRepresentation( - Representation::Integer32(), h_infer, "use requirements"); - } -} - - -Representation HValue::RepresentationFromUses() { - if (HasNoUses()) return Representation::None(); - Representation result = Representation::None(); - - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - HValue* use = it.value(); - Representation rep = use->observed_input_representation(it.index()); - result = result.generalize(rep); - - if (FLAG_trace_representation) { - PrintF("#%d %s is used by #%d %s as %s%s\n", - id(), Mnemonic(), use->id(), use->Mnemonic(), rep.Mnemonic(), - (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : "")); - } - } - if (IsPhi()) { - result = result.generalize( - HPhi::cast(this)->representation_from_indirect_uses()); - } - - // External representations are dealt with separately. - return result.IsExternal() ? Representation::None() : result; -} - - -void HValue::UpdateRepresentation(Representation new_rep, - HInferRepresentationPhase* h_infer, - const char* reason) { - Representation r = representation(); - if (new_rep.is_more_general_than(r)) { - if (CheckFlag(kCannotBeTagged) && new_rep.IsTagged()) return; - if (FLAG_trace_representation) { - PrintF("Changing #%d %s representation %s -> %s based on %s\n", - id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason); - } - ChangeRepresentation(new_rep); - AddDependantsToWorklist(h_infer); - } -} - - -void HValue::AddDependantsToWorklist(HInferRepresentationPhase* h_infer) { - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - h_infer->AddToWorklist(it.value()); - } - for (int i = 0; i < OperandCount(); ++i) { - h_infer->AddToWorklist(OperandAt(i)); - } -} - - -static int32_t ConvertAndSetOverflow(Representation r, - int64_t result, - bool* overflow) { - if (r.IsSmi()) { - if (result > Smi::kMaxValue) { - *overflow = true; - return Smi::kMaxValue; - } - if (result < Smi::kMinValue) { - *overflow = true; - return Smi::kMinValue; - } - } else { - if (result > kMaxInt) { - *overflow = true; - return kMaxInt; - } - if (result < kMinInt) { - *overflow = true; - return kMinInt; - } - } - return static_cast<int32_t>(result); -} - - -static int32_t AddWithoutOverflow(Representation r, - int32_t a, - int32_t b, - bool* overflow) { - int64_t result = static_cast<int64_t>(a) + static_cast<int64_t>(b); - return ConvertAndSetOverflow(r, result, overflow); -} - - -static int32_t SubWithoutOverflow(Representation r, - int32_t a, - int32_t b, - bool* overflow) { - int64_t result = static_cast<int64_t>(a) - static_cast<int64_t>(b); - return ConvertAndSetOverflow(r, result, overflow); -} - - -static int32_t MulWithoutOverflow(const Representation& r, - int32_t a, - int32_t b, - bool* overflow) { - int64_t result = static_cast<int64_t>(a) * static_cast<int64_t>(b); - return ConvertAndSetOverflow(r, result, overflow); -} - - -int32_t Range::Mask() const { - if (lower_ == upper_) return lower_; - if (lower_ >= 0) { - int32_t res = 1; - while (res < upper_) { - res = (res << 1) | 1; - } - return res; - } - return 0xffffffff; -} - - -void Range::AddConstant(int32_t value) { - if (value == 0) return; - bool may_overflow = false; // Overflow is ignored here. - Representation r = Representation::Integer32(); - lower_ = AddWithoutOverflow(r, lower_, value, &may_overflow); - upper_ = AddWithoutOverflow(r, upper_, value, &may_overflow); -#ifdef DEBUG - Verify(); -#endif -} - - -void Range::Intersect(Range* other) { - upper_ = Min(upper_, other->upper_); - lower_ = Max(lower_, other->lower_); - bool b = CanBeMinusZero() && other->CanBeMinusZero(); - set_can_be_minus_zero(b); -} - - -void Range::Union(Range* other) { - upper_ = Max(upper_, other->upper_); - lower_ = Min(lower_, other->lower_); - bool b = CanBeMinusZero() || other->CanBeMinusZero(); - set_can_be_minus_zero(b); -} - - -void Range::CombinedMax(Range* other) { - upper_ = Max(upper_, other->upper_); - lower_ = Max(lower_, other->lower_); - set_can_be_minus_zero(CanBeMinusZero() || other->CanBeMinusZero()); -} - - -void Range::CombinedMin(Range* other) { - upper_ = Min(upper_, other->upper_); - lower_ = Min(lower_, other->lower_); - set_can_be_minus_zero(CanBeMinusZero() || other->CanBeMinusZero()); -} - - -void Range::Sar(int32_t value) { - int32_t bits = value & 0x1F; - lower_ = lower_ >> bits; - upper_ = upper_ >> bits; - set_can_be_minus_zero(false); -} - - -void Range::Shl(int32_t value) { - int32_t bits = value & 0x1F; - int old_lower = lower_; - int old_upper = upper_; - lower_ = lower_ << bits; - upper_ = upper_ << bits; - if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) { - upper_ = kMaxInt; - lower_ = kMinInt; - } - set_can_be_minus_zero(false); -} - - -bool Range::AddAndCheckOverflow(const Representation& r, Range* other) { - bool may_overflow = false; - lower_ = AddWithoutOverflow(r, lower_, other->lower(), &may_overflow); - upper_ = AddWithoutOverflow(r, upper_, other->upper(), &may_overflow); - if (may_overflow) { - Clear(); - } else { - KeepOrder(); - } -#ifdef DEBUG - Verify(); -#endif - return may_overflow; -} - - -bool Range::SubAndCheckOverflow(const Representation& r, Range* other) { - bool may_overflow = false; - lower_ = SubWithoutOverflow(r, lower_, other->upper(), &may_overflow); - upper_ = SubWithoutOverflow(r, upper_, other->lower(), &may_overflow); - if (may_overflow) { - Clear(); - } else { - KeepOrder(); - } -#ifdef DEBUG - Verify(); -#endif - return may_overflow; -} - -void Range::Clear() { - lower_ = kMinInt; - upper_ = kMaxInt; -} - -void Range::KeepOrder() { - if (lower_ > upper_) { - int32_t tmp = lower_; - lower_ = upper_; - upper_ = tmp; - } -} - - -#ifdef DEBUG -void Range::Verify() const { - DCHECK(lower_ <= upper_); -} -#endif - - -bool Range::MulAndCheckOverflow(const Representation& r, Range* other) { - bool may_overflow = false; - int v1 = MulWithoutOverflow(r, lower_, other->lower(), &may_overflow); - int v2 = MulWithoutOverflow(r, lower_, other->upper(), &may_overflow); - int v3 = MulWithoutOverflow(r, upper_, other->lower(), &may_overflow); - int v4 = MulWithoutOverflow(r, upper_, other->upper(), &may_overflow); - if (may_overflow) { - Clear(); - } else { - lower_ = Min(Min(v1, v2), Min(v3, v4)); - upper_ = Max(Max(v1, v2), Max(v3, v4)); - } -#ifdef DEBUG - Verify(); -#endif - return may_overflow; -} - - -bool HValue::IsDefinedAfter(HBasicBlock* other) const { - return block()->block_id() > other->block_id(); -} - - -HUseListNode* HUseListNode::tail() { - // Skip and remove dead items in the use list. - while (tail_ != NULL && tail_->value()->CheckFlag(HValue::kIsDead)) { - tail_ = tail_->tail_; - } - return tail_; -} - - -bool HValue::CheckUsesForFlag(Flag f) const { - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - if (it.value()->IsSimulate()) continue; - if (!it.value()->CheckFlag(f)) return false; - } - return true; -} - - -bool HValue::CheckUsesForFlag(Flag f, HValue** value) const { - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - if (it.value()->IsSimulate()) continue; - if (!it.value()->CheckFlag(f)) { - *value = it.value(); - return false; - } - } - return true; -} - - -bool HValue::HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const { - bool return_value = false; - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - if (it.value()->IsSimulate()) continue; - if (!it.value()->CheckFlag(f)) return false; - return_value = true; - } - return return_value; -} - - -HUseIterator::HUseIterator(HUseListNode* head) : next_(head) { - Advance(); -} - - -void HUseIterator::Advance() { - current_ = next_; - if (current_ != NULL) { - next_ = current_->tail(); - value_ = current_->value(); - index_ = current_->index(); - } -} - - -int HValue::UseCount() const { - int count = 0; - for (HUseIterator it(uses()); !it.Done(); it.Advance()) ++count; - return count; -} - - -HUseListNode* HValue::RemoveUse(HValue* value, int index) { - HUseListNode* previous = NULL; - HUseListNode* current = use_list_; - while (current != NULL) { - if (current->value() == value && current->index() == index) { - if (previous == NULL) { - use_list_ = current->tail(); - } else { - previous->set_tail(current->tail()); - } - break; - } - - previous = current; - current = current->tail(); - } - -#ifdef DEBUG - // Do not reuse use list nodes in debug mode, zap them. - if (current != NULL) { - HUseListNode* temp = - new(block()->zone()) - HUseListNode(current->value(), current->index(), NULL); - current->Zap(); - current = temp; - } -#endif - return current; -} - - -bool HValue::Equals(HValue* other) { - if (other->opcode() != opcode()) return false; - if (!other->representation().Equals(representation())) return false; - if (!other->type_.Equals(type_)) return false; - if (other->flags() != flags()) return false; - if (OperandCount() != other->OperandCount()) return false; - for (int i = 0; i < OperandCount(); ++i) { - if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false; - } - bool result = DataEquals(other); - DCHECK(!result || Hashcode() == other->Hashcode()); - return result; -} - - -intptr_t HValue::Hashcode() { - intptr_t result = opcode(); - int count = OperandCount(); - for (int i = 0; i < count; ++i) { - result = result * 19 + OperandAt(i)->id() + (result >> 7); - } - return result; -} - - -const char* HValue::Mnemonic() const { - switch (opcode()) { -#define MAKE_CASE(type) case k##type: return #type; - HYDROGEN_CONCRETE_INSTRUCTION_LIST(MAKE_CASE) -#undef MAKE_CASE - case kPhi: return "Phi"; - default: return ""; - } -} - - -bool HValue::CanReplaceWithDummyUses() { - return FLAG_unreachable_code_elimination && - !(block()->IsReachable() || - IsBlockEntry() || - IsControlInstruction() || - IsArgumentsObject() || - IsCapturedObject() || - IsSimulate() || - IsEnterInlined() || - IsLeaveInlined()); -} - - -bool HValue::IsInteger32Constant() { - return IsConstant() && HConstant::cast(this)->HasInteger32Value(); -} - - -int32_t HValue::GetInteger32Constant() { - return HConstant::cast(this)->Integer32Value(); -} - - -bool HValue::EqualsInteger32Constant(int32_t value) { - return IsInteger32Constant() && GetInteger32Constant() == value; -} - - -void HValue::SetOperandAt(int index, HValue* value) { - RegisterUse(index, value); - InternalSetOperandAt(index, value); -} - - -void HValue::DeleteAndReplaceWith(HValue* other) { - // We replace all uses first, so Delete can assert that there are none. - if (other != NULL) ReplaceAllUsesWith(other); - Kill(); - DeleteFromGraph(); -} - - -void HValue::ReplaceAllUsesWith(HValue* other) { - while (use_list_ != NULL) { - HUseListNode* list_node = use_list_; - HValue* value = list_node->value(); - DCHECK(!value->block()->IsStartBlock()); - value->InternalSetOperandAt(list_node->index(), other); - use_list_ = list_node->tail(); - list_node->set_tail(other->use_list_); - other->use_list_ = list_node; - } -} - - -void HValue::Kill() { - // Instead of going through the entire use list of each operand, we only - // check the first item in each use list and rely on the tail() method to - // skip dead items, removing them lazily next time we traverse the list. - SetFlag(kIsDead); - for (int i = 0; i < OperandCount(); ++i) { - HValue* operand = OperandAt(i); - if (operand == NULL) continue; - HUseListNode* first = operand->use_list_; - if (first != NULL && first->value()->CheckFlag(kIsDead)) { - operand->use_list_ = first->tail(); - } - } -} - - -void HValue::SetBlock(HBasicBlock* block) { - DCHECK(block_ == NULL || block == NULL); - block_ = block; - if (id_ == kNoNumber && block != NULL) { - id_ = block->graph()->GetNextValueID(this); - } -} - - -std::ostream& operator<<(std::ostream& os, const HValue& v) { - return v.PrintTo(os); -} - - -std::ostream& operator<<(std::ostream& os, const TypeOf& t) { - if (t.value->representation().IsTagged() && - !t.value->type().Equals(HType::Tagged())) - return os; - return os << " type:" << t.value->type(); -} - - -std::ostream& operator<<(std::ostream& os, const ChangesOf& c) { - GVNFlagSet changes_flags = c.value->ChangesFlags(); - if (changes_flags.IsEmpty()) return os; - os << " changes["; - if (changes_flags == c.value->AllSideEffectsFlagSet()) { - os << "*"; - } else { - bool add_comma = false; -#define PRINT_DO(Type) \ - if (changes_flags.Contains(k##Type)) { \ - if (add_comma) os << ","; \ - add_comma = true; \ - os << #Type; \ - } - GVN_TRACKED_FLAG_LIST(PRINT_DO); - GVN_UNTRACKED_FLAG_LIST(PRINT_DO); -#undef PRINT_DO - } - return os << "]"; -} - - -bool HValue::HasMonomorphicJSObjectType() { - return !GetMonomorphicJSObjectMap().is_null(); -} - - -bool HValue::UpdateInferredType() { - HType type = CalculateInferredType(); - bool result = (!type.Equals(type_)); - type_ = type; - return result; -} - - -void HValue::RegisterUse(int index, HValue* new_value) { - HValue* old_value = OperandAt(index); - if (old_value == new_value) return; - - HUseListNode* removed = NULL; - if (old_value != NULL) { - removed = old_value->RemoveUse(this, index); - } - - if (new_value != NULL) { - if (removed == NULL) { - new_value->use_list_ = new(new_value->block()->zone()) HUseListNode( - this, index, new_value->use_list_); - } else { - removed->set_tail(new_value->use_list_); - new_value->use_list_ = removed; - } - } -} - - -void HValue::AddNewRange(Range* r, Zone* zone) { - if (!HasRange()) ComputeInitialRange(zone); - if (!HasRange()) range_ = new(zone) Range(); - DCHECK(HasRange()); - r->StackUpon(range_); - range_ = r; -} - - -void HValue::RemoveLastAddedRange() { - DCHECK(HasRange()); - DCHECK(range_->next() != NULL); - range_ = range_->next(); -} - - -void HValue::ComputeInitialRange(Zone* zone) { - DCHECK(!HasRange()); - range_ = InferRange(zone); - DCHECK(HasRange()); -} - - -std::ostream& HInstruction::PrintTo(std::ostream& os) const { // NOLINT - os << Mnemonic() << " "; - PrintDataTo(os) << ChangesOf(this) << TypeOf(this); - if (CheckFlag(HValue::kHasNoObservableSideEffects)) os << " [noOSE]"; - if (CheckFlag(HValue::kIsDead)) os << " [dead]"; - return os; -} - - -std::ostream& HInstruction::PrintDataTo(std::ostream& os) const { // NOLINT - for (int i = 0; i < OperandCount(); ++i) { - if (i > 0) os << " "; - os << NameOf(OperandAt(i)); - } - return os; -} - - -void HInstruction::Unlink() { - DCHECK(IsLinked()); - DCHECK(!IsControlInstruction()); // Must never move control instructions. - DCHECK(!IsBlockEntry()); // Doesn't make sense to delete these. - DCHECK(previous_ != NULL); - previous_->next_ = next_; - if (next_ == NULL) { - DCHECK(block()->last() == this); - block()->set_last(previous_); - } else { - next_->previous_ = previous_; - } - clear_block(); -} - - -void HInstruction::InsertBefore(HInstruction* next) { - DCHECK(!IsLinked()); - DCHECK(!next->IsBlockEntry()); - DCHECK(!IsControlInstruction()); - DCHECK(!next->block()->IsStartBlock()); - DCHECK(next->previous_ != NULL); - HInstruction* prev = next->previous(); - prev->next_ = this; - next->previous_ = this; - next_ = next; - previous_ = prev; - SetBlock(next->block()); - if (!has_position() && next->has_position()) { - set_position(next->position()); - } -} - - -void HInstruction::InsertAfter(HInstruction* previous) { - DCHECK(!IsLinked()); - DCHECK(!previous->IsControlInstruction()); - DCHECK(!IsControlInstruction() || previous->next_ == NULL); - HBasicBlock* block = previous->block(); - // Never insert anything except constants into the start block after finishing - // it. - if (block->IsStartBlock() && block->IsFinished() && !IsConstant()) { - DCHECK(block->end()->SecondSuccessor() == NULL); - InsertAfter(block->end()->FirstSuccessor()->first()); - return; - } - - // If we're inserting after an instruction with side-effects that is - // followed by a simulate instruction, we need to insert after the - // simulate instruction instead. - HInstruction* next = previous->next_; - if (previous->HasObservableSideEffects() && next != NULL) { - DCHECK(next->IsSimulate()); - previous = next; - next = previous->next_; - } - - previous_ = previous; - next_ = next; - SetBlock(block); - previous->next_ = this; - if (next != NULL) next->previous_ = this; - if (block->last() == previous) { - block->set_last(this); - } - if (!has_position() && previous->has_position()) { - set_position(previous->position()); - } -} - - -bool HInstruction::Dominates(HInstruction* other) { - if (block() != other->block()) { - return block()->Dominates(other->block()); - } - // Both instructions are in the same basic block. This instruction - // should precede the other one in order to dominate it. - for (HInstruction* instr = next(); instr != NULL; instr = instr->next()) { - if (instr == other) { - return true; - } - } - return false; -} - - -#ifdef DEBUG -void HInstruction::Verify() { - // Verify that input operands are defined before use. - HBasicBlock* cur_block = block(); - for (int i = 0; i < OperandCount(); ++i) { - HValue* other_operand = OperandAt(i); - if (other_operand == NULL) continue; - HBasicBlock* other_block = other_operand->block(); - if (cur_block == other_block) { - if (!other_operand->IsPhi()) { - HInstruction* cur = this->previous(); - while (cur != NULL) { - if (cur == other_operand) break; - cur = cur->previous(); - } - // Must reach other operand in the same block! - DCHECK(cur == other_operand); - } - } else { - // If the following assert fires, you may have forgotten an - // AddInstruction. - DCHECK(other_block->Dominates(cur_block)); - } - } - - // Verify that instructions that may have side-effects are followed - // by a simulate instruction. - if (HasObservableSideEffects() && !IsOsrEntry()) { - DCHECK(next()->IsSimulate()); - } - - // Verify that instructions that can be eliminated by GVN have overridden - // HValue::DataEquals. The default implementation is UNREACHABLE. We - // don't actually care whether DataEquals returns true or false here. - if (CheckFlag(kUseGVN)) DataEquals(this); - - // Verify that all uses are in the graph. - for (HUseIterator use = uses(); !use.Done(); use.Advance()) { - if (use.value()->IsInstruction()) { - DCHECK(HInstruction::cast(use.value())->IsLinked()); - } - } -} -#endif - - -bool HInstruction::CanDeoptimize() { - switch (opcode()) { - case HValue::kAbnormalExit: - case HValue::kAccessArgumentsAt: - case HValue::kAllocate: - case HValue::kArgumentsElements: - case HValue::kArgumentsLength: - case HValue::kArgumentsObject: - case HValue::kBlockEntry: - case HValue::kCallNewArray: - case HValue::kCapturedObject: - case HValue::kClassOfTestAndBranch: - case HValue::kCompareGeneric: - case HValue::kCompareHoleAndBranch: - case HValue::kCompareMap: - case HValue::kCompareNumericAndBranch: - case HValue::kCompareObjectEqAndBranch: - case HValue::kConstant: - case HValue::kContext: - case HValue::kDebugBreak: - case HValue::kDeclareGlobals: - case HValue::kDummyUse: - case HValue::kEnterInlined: - case HValue::kEnvironmentMarker: - case HValue::kForceRepresentation: - case HValue::kGoto: - case HValue::kHasInstanceTypeAndBranch: - case HValue::kInnerAllocatedObject: - case HValue::kIsSmiAndBranch: - case HValue::kIsStringAndBranch: - case HValue::kIsUndetectableAndBranch: - case HValue::kLeaveInlined: - case HValue::kLoadFieldByIndex: - case HValue::kLoadNamedField: - case HValue::kLoadRoot: - case HValue::kMathMinMax: - case HValue::kParameter: - case HValue::kPhi: - case HValue::kPushArguments: - case HValue::kReturn: - case HValue::kSeqStringGetChar: - case HValue::kStoreCodeEntry: - case HValue::kStoreKeyed: - case HValue::kStoreNamedField: - case HValue::kStringCharCodeAt: - case HValue::kStringCharFromCode: - case HValue::kThisFunction: - case HValue::kTypeofIsAndBranch: - case HValue::kUnknownOSRValue: - case HValue::kUseConst: - return false; - - case HValue::kAdd: - case HValue::kApplyArguments: - case HValue::kBitwise: - case HValue::kBoundsCheck: - case HValue::kBranch: - case HValue::kCallRuntime: - case HValue::kCallWithDescriptor: - case HValue::kChange: - case HValue::kCheckArrayBufferNotNeutered: - case HValue::kCheckHeapObject: - case HValue::kCheckInstanceType: - case HValue::kCheckMapValue: - case HValue::kCheckMaps: - case HValue::kCheckSmi: - case HValue::kCheckValue: - case HValue::kClampToUint8: - case HValue::kDeoptimize: - case HValue::kDiv: - case HValue::kForInCacheArray: - case HValue::kForInPrepareMap: - case HValue::kHasInPrototypeChainAndBranch: - case HValue::kInvokeFunction: - case HValue::kLoadContextSlot: - case HValue::kLoadFunctionPrototype: - case HValue::kLoadKeyed: - case HValue::kMathFloorOfDiv: - case HValue::kMaybeGrowElements: - case HValue::kMod: - case HValue::kMul: - case HValue::kOsrEntry: - case HValue::kPower: - case HValue::kPrologue: - case HValue::kRor: - case HValue::kSar: - case HValue::kSeqStringSetChar: - case HValue::kShl: - case HValue::kShr: - case HValue::kSimulate: - case HValue::kStackCheck: - case HValue::kStoreContextSlot: - case HValue::kStringAdd: - case HValue::kStringCompareAndBranch: - case HValue::kSub: - case HValue::kTransitionElementsKind: - case HValue::kTrapAllocationMemento: - case HValue::kTypeof: - case HValue::kUnaryMathOperation: - case HValue::kWrapReceiver: - return true; - } - UNREACHABLE(); - return true; -} - - -std::ostream& operator<<(std::ostream& os, const NameOf& v) { - return os << v.value->representation().Mnemonic() << v.value->id(); -} - -std::ostream& HDummyUse::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(value()); -} - - -std::ostream& HEnvironmentMarker::PrintDataTo( - std::ostream& os) const { // NOLINT - return os << (kind() == BIND ? "bind" : "lookup") << " var[" << index() - << "]"; -} - - -std::ostream& HUnaryCall::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(value()) << " #" << argument_count(); -} - - -std::ostream& HBinaryCall::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(first()) << " " << NameOf(second()) << " #" - << argument_count(); -} - -std::ostream& HInvokeFunction::PrintTo(std::ostream& os) const { // NOLINT - if (tail_call_mode() == TailCallMode::kAllow) os << "Tail"; - return HBinaryCall::PrintTo(os); -} - -std::ostream& HInvokeFunction::PrintDataTo(std::ostream& os) const { // NOLINT - HBinaryCall::PrintDataTo(os); - if (syntactic_tail_call_mode() == TailCallMode::kAllow) { - os << ", JSTailCall"; - } - return os; -} - -std::ostream& HBoundsCheck::PrintDataTo(std::ostream& os) const { // NOLINT - os << NameOf(index()) << " " << NameOf(length()); - if (base() != NULL && (offset() != 0 || scale() != 0)) { - os << " base: (("; - if (base() != index()) { - os << NameOf(index()); - } else { - os << "index"; - } - os << " + " << offset() << ") >> " << scale() << ")"; - } - if (skip_check()) os << " [DISABLED]"; - return os; -} - - -void HBoundsCheck::InferRepresentation(HInferRepresentationPhase* h_infer) { - DCHECK(CheckFlag(kFlexibleRepresentation)); - HValue* actual_index = index()->ActualValue(); - HValue* actual_length = length()->ActualValue(); - Representation index_rep = actual_index->representation(); - Representation length_rep = actual_length->representation(); - if (index_rep.IsTagged() && actual_index->type().IsSmi()) { - index_rep = Representation::Smi(); - } - if (length_rep.IsTagged() && actual_length->type().IsSmi()) { - length_rep = Representation::Smi(); - } - Representation r = index_rep.generalize(length_rep); - if (r.is_more_general_than(Representation::Integer32())) { - r = Representation::Integer32(); - } - UpdateRepresentation(r, h_infer, "boundscheck"); -} - - -Range* HBoundsCheck::InferRange(Zone* zone) { - Representation r = representation(); - if (r.IsSmiOrInteger32() && length()->HasRange()) { - int upper = length()->range()->upper() - (allow_equality() ? 0 : 1); - int lower = 0; - - Range* result = new(zone) Range(lower, upper); - if (index()->HasRange()) { - result->Intersect(index()->range()); - } - - // In case of Smi representation, clamp result to Smi::kMaxValue. - if (r.IsSmi()) result->ClampToSmi(); - return result; - } - return HValue::InferRange(zone); -} - - -std::ostream& HCallWithDescriptor::PrintDataTo( - std::ostream& os) const { // NOLINT - for (int i = 0; i < OperandCount(); i++) { - os << NameOf(OperandAt(i)) << " "; - } - os << "#" << argument_count(); - if (syntactic_tail_call_mode() == TailCallMode::kAllow) { - os << ", JSTailCall"; - } - return os; -} - - -std::ostream& HCallNewArray::PrintDataTo(std::ostream& os) const { // NOLINT - os << ElementsKindToString(elements_kind()) << " "; - return HBinaryCall::PrintDataTo(os); -} - - -std::ostream& HCallRuntime::PrintDataTo(std::ostream& os) const { // NOLINT - os << function()->name << " "; - if (save_doubles() == kSaveFPRegs) os << "[save doubles] "; - return os << "#" << argument_count(); -} - -std::ostream& HClassOfTestAndBranch::PrintDataTo( - std::ostream& os) const { // NOLINT - return os << "class_of_test(" << NameOf(value()) << ", \"" - << class_name()->ToCString().get() << "\")"; -} - -std::ostream& HWrapReceiver::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(receiver()) << " " << NameOf(function()); -} - - -std::ostream& HAccessArgumentsAt::PrintDataTo( - std::ostream& os) const { // NOLINT - return os << NameOf(arguments()) << "[" << NameOf(index()) << "], length " - << NameOf(length()); -} - - -std::ostream& HControlInstruction::PrintDataTo( - std::ostream& os) const { // NOLINT - os << " goto ("; - bool first_block = true; - for (HSuccessorIterator it(this); !it.Done(); it.Advance()) { - if (!first_block) os << ", "; - os << *it.Current(); - first_block = false; - } - return os << ")"; -} - - -std::ostream& HUnaryControlInstruction::PrintDataTo( - std::ostream& os) const { // NOLINT - os << NameOf(value()); - return HControlInstruction::PrintDataTo(os); -} - - -std::ostream& HReturn::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(value()) << " (pop " << NameOf(parameter_count()) - << " values)"; -} - - -Representation HBranch::observed_input_representation(int index) { - if (expected_input_types_ & - (ToBooleanHint::kNull | ToBooleanHint::kReceiver | - ToBooleanHint::kString | ToBooleanHint::kSymbol)) { - return Representation::Tagged(); - } - if (expected_input_types_ & ToBooleanHint::kUndefined) { - if (expected_input_types_ & ToBooleanHint::kHeapNumber) { - return Representation::Double(); - } - return Representation::Tagged(); - } - if (expected_input_types_ & ToBooleanHint::kHeapNumber) { - return Representation::Double(); - } - if (expected_input_types_ & ToBooleanHint::kSmallInteger) { - return Representation::Smi(); - } - return Representation::None(); -} - - -bool HBranch::KnownSuccessorBlock(HBasicBlock** block) { - HValue* value = this->value(); - if (value->EmitAtUses()) { - DCHECK(value->IsConstant()); - DCHECK(!value->representation().IsDouble()); - *block = HConstant::cast(value)->BooleanValue() - ? FirstSuccessor() - : SecondSuccessor(); - return true; - } - *block = NULL; - return false; -} - - -std::ostream& HBranch::PrintDataTo(std::ostream& os) const { // NOLINT - return HUnaryControlInstruction::PrintDataTo(os) << " " - << expected_input_types(); -} - - -std::ostream& HCompareMap::PrintDataTo(std::ostream& os) const { // NOLINT - os << NameOf(value()) << " (" << *map().handle() << ")"; - HControlInstruction::PrintDataTo(os); - if (known_successor_index() == 0) { - os << " [true]"; - } else if (known_successor_index() == 1) { - os << " [false]"; - } - return os; -} - - -const char* HUnaryMathOperation::OpName() const { - switch (op()) { - case kMathFloor: - return "floor"; - case kMathFround: - return "fround"; - case kMathRound: - return "round"; - case kMathAbs: - return "abs"; - case kMathCos: - return "cos"; - case kMathLog: - return "log"; - case kMathExp: - return "exp"; - case kMathSin: - return "sin"; - case kMathSqrt: - return "sqrt"; - case kMathPowHalf: - return "pow-half"; - case kMathClz32: - return "clz32"; - default: - UNREACHABLE(); - return NULL; - } -} - - -Range* HUnaryMathOperation::InferRange(Zone* zone) { - Representation r = representation(); - if (op() == kMathClz32) return new(zone) Range(0, 32); - if (r.IsSmiOrInteger32() && value()->HasRange()) { - if (op() == kMathAbs) { - int upper = value()->range()->upper(); - int lower = value()->range()->lower(); - bool spans_zero = value()->range()->CanBeZero(); - // Math.abs(kMinInt) overflows its representation, on which the - // instruction deopts. Hence clamp it to kMaxInt. - int abs_upper = upper == kMinInt ? kMaxInt : abs(upper); - int abs_lower = lower == kMinInt ? kMaxInt : abs(lower); - Range* result = - new(zone) Range(spans_zero ? 0 : Min(abs_lower, abs_upper), - Max(abs_lower, abs_upper)); - // In case of Smi representation, clamp Math.abs(Smi::kMinValue) to - // Smi::kMaxValue. - if (r.IsSmi()) result->ClampToSmi(); - return result; - } - } - return HValue::InferRange(zone); -} - - -std::ostream& HUnaryMathOperation::PrintDataTo( - std::ostream& os) const { // NOLINT - return os << OpName() << " " << NameOf(value()); -} - - -std::ostream& HUnaryOperation::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(value()); -} - - -std::ostream& HHasInstanceTypeAndBranch::PrintDataTo( - std::ostream& os) const { // NOLINT - os << NameOf(value()); - switch (from_) { - case FIRST_JS_RECEIVER_TYPE: - if (to_ == LAST_TYPE) os << " spec_object"; - break; - case JS_REGEXP_TYPE: - if (to_ == JS_REGEXP_TYPE) os << " reg_exp"; - break; - case JS_ARRAY_TYPE: - if (to_ == JS_ARRAY_TYPE) os << " array"; - break; - case JS_FUNCTION_TYPE: - if (to_ == JS_FUNCTION_TYPE) os << " function"; - break; - default: - break; - } - return os; -} - - -std::ostream& HTypeofIsAndBranch::PrintDataTo( - std::ostream& os) const { // NOLINT - os << NameOf(value()) << " == " << type_literal()->ToCString().get(); - return HControlInstruction::PrintDataTo(os); -} - - -namespace { - -String* TypeOfString(HConstant* constant, Isolate* isolate) { - Heap* heap = isolate->heap(); - if (constant->HasNumberValue()) return heap->number_string(); - if (constant->HasStringValue()) return heap->string_string(); - switch (constant->GetInstanceType()) { - case ODDBALL_TYPE: { - Unique<Object> unique = constant->GetUnique(); - if (unique.IsKnownGlobal(heap->true_value()) || - unique.IsKnownGlobal(heap->false_value())) { - return heap->boolean_string(); - } - if (unique.IsKnownGlobal(heap->null_value())) { - return heap->object_string(); - } - DCHECK(unique.IsKnownGlobal(heap->undefined_value())); - return heap->undefined_string(); - } - case SYMBOL_TYPE: - return heap->symbol_string(); - default: - if (constant->IsUndetectable()) return heap->undefined_string(); - if (constant->IsCallable()) return heap->function_string(); - return heap->object_string(); - } -} - -} // namespace - - -bool HTypeofIsAndBranch::KnownSuccessorBlock(HBasicBlock** block) { - if (FLAG_fold_constants && value()->IsConstant()) { - HConstant* constant = HConstant::cast(value()); - String* type_string = TypeOfString(constant, isolate()); - bool same_type = type_literal_.IsKnownGlobal(type_string); - *block = same_type ? FirstSuccessor() : SecondSuccessor(); - return true; - } else if (value()->representation().IsSpecialization()) { - bool number_type = - type_literal_.IsKnownGlobal(isolate()->heap()->number_string()); - *block = number_type ? FirstSuccessor() : SecondSuccessor(); - return true; - } - *block = NULL; - return false; -} - - -std::ostream& HCheckMapValue::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(value()) << " " << NameOf(map()); -} - - -HValue* HCheckMapValue::Canonicalize() { - if (map()->IsConstant()) { - HConstant* c_map = HConstant::cast(map()); - return HCheckMaps::CreateAndInsertAfter( - block()->graph()->zone(), value(), c_map->MapValue(), - c_map->HasStableMapValue(), this); - } - return this; -} - - -std::ostream& HForInPrepareMap::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(enumerable()); -} - - -std::ostream& HForInCacheArray::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(enumerable()) << " " << NameOf(map()) << "[" << idx_ - << "]"; -} - - -std::ostream& HLoadFieldByIndex::PrintDataTo( - std::ostream& os) const { // NOLINT - return os << NameOf(object()) << " " << NameOf(index()); -} - - -static bool MatchLeftIsOnes(HValue* l, HValue* r, HValue** negated) { - if (!l->EqualsInteger32Constant(~0)) return false; - *negated = r; - return true; -} - - -static bool MatchNegationViaXor(HValue* instr, HValue** negated) { - if (!instr->IsBitwise()) return false; - HBitwise* b = HBitwise::cast(instr); - return (b->op() == Token::BIT_XOR) && - (MatchLeftIsOnes(b->left(), b->right(), negated) || - MatchLeftIsOnes(b->right(), b->left(), negated)); -} - - -static bool MatchDoubleNegation(HValue* instr, HValue** arg) { - HValue* negated; - return MatchNegationViaXor(instr, &negated) && - MatchNegationViaXor(negated, arg); -} - - -HValue* HBitwise::Canonicalize() { - if (!representation().IsSmiOrInteger32()) return this; - // If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x. - int32_t nop_constant = (op() == Token::BIT_AND) ? -1 : 0; - if (left()->EqualsInteger32Constant(nop_constant) && - !right()->CheckFlag(kUint32)) { - return right(); - } - if (right()->EqualsInteger32Constant(nop_constant) && - !left()->CheckFlag(kUint32)) { - return left(); - } - // Optimize double negation, a common pattern used for ToInt32(x). - HValue* arg; - if (MatchDoubleNegation(this, &arg) && !arg->CheckFlag(kUint32)) { - return arg; - } - return this; -} - - -// static -HInstruction* HAdd::New(Isolate* isolate, Zone* zone, HValue* context, - HValue* left, HValue* right, - ExternalAddType external_add_type) { - // For everything else, you should use the other factory method without - // ExternalAddType. - DCHECK_EQ(external_add_type, AddOfExternalAndTagged); - return new (zone) HAdd(context, left, right, external_add_type); -} - - -Representation HAdd::RepresentationFromInputs() { - Representation left_rep = left()->representation(); - if (left_rep.IsExternal()) { - return Representation::External(); - } - return HArithmeticBinaryOperation::RepresentationFromInputs(); -} - - -Representation HAdd::RequiredInputRepresentation(int index) { - if (index == 2) { - Representation left_rep = left()->representation(); - if (left_rep.IsExternal()) { - if (external_add_type_ == AddOfExternalAndTagged) { - return Representation::Tagged(); - } else { - return Representation::Integer32(); - } - } - } - return HArithmeticBinaryOperation::RequiredInputRepresentation(index); -} - - -static bool IsIdentityOperation(HValue* arg1, HValue* arg2, int32_t identity) { - return arg1->representation().IsSpecialization() && - arg2->EqualsInteger32Constant(identity); -} - - -HValue* HAdd::Canonicalize() { - // Adding 0 is an identity operation except in case of -0: -0 + 0 = +0 - if (IsIdentityOperation(left(), right(), 0) && - !left()->representation().IsDouble()) { // Left could be -0. - return left(); - } - if (IsIdentityOperation(right(), left(), 0) && - !left()->representation().IsDouble()) { // Right could be -0. - return right(); - } - return this; -} - - -HValue* HSub::Canonicalize() { - if (IsIdentityOperation(left(), right(), 0)) return left(); - return this; -} - - -HValue* HMul::Canonicalize() { - if (IsIdentityOperation(left(), right(), 1)) return left(); - if (IsIdentityOperation(right(), left(), 1)) return right(); - return this; -} - - -bool HMul::MulMinusOne() { - if (left()->EqualsInteger32Constant(-1) || - right()->EqualsInteger32Constant(-1)) { - return true; - } - - return false; -} - - -HValue* HMod::Canonicalize() { - return this; -} - - -HValue* HDiv::Canonicalize() { - if (IsIdentityOperation(left(), right(), 1)) return left(); - return this; -} - - -HValue* HChange::Canonicalize() { - return (from().Equals(to())) ? value() : this; -} - - -HValue* HWrapReceiver::Canonicalize() { - if (HasNoUses()) return NULL; - if (receiver()->type().IsJSReceiver()) { - return receiver(); - } - return this; -} - - -std::ostream& HTypeof::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(value()); -} - - -HInstruction* HForceRepresentation::New(Isolate* isolate, Zone* zone, - HValue* context, HValue* value, - Representation representation) { - if (FLAG_fold_constants && value->IsConstant()) { - HConstant* c = HConstant::cast(value); - c = c->CopyToRepresentation(representation, zone); - if (c != NULL) return c; - } - return new(zone) HForceRepresentation(value, representation); -} - - -std::ostream& HForceRepresentation::PrintDataTo( - std::ostream& os) const { // NOLINT - return os << representation().Mnemonic() << " " << NameOf(value()); -} - - -std::ostream& HChange::PrintDataTo(std::ostream& os) const { // NOLINT - HUnaryOperation::PrintDataTo(os); - os << " " << from().Mnemonic() << " to " << to().Mnemonic(); - - if (CanTruncateToSmi()) os << " truncating-smi"; - if (CanTruncateToInt32()) os << " truncating-int32"; - if (CanTruncateToNumber()) os << " truncating-number"; - if (CheckFlag(kBailoutOnMinusZero)) os << " -0?"; - return os; -} - - -HValue* HUnaryMathOperation::Canonicalize() { - if (op() == kMathRound || op() == kMathFloor) { - HValue* val = value(); - if (val->IsChange()) val = HChange::cast(val)->value(); - if (val->representation().IsSmiOrInteger32()) { - if (val->representation().Equals(representation())) return val; - return Prepend(new (block()->zone()) - HChange(val, representation(), false, false, true)); - } - } - if (op() == kMathFloor && representation().IsSmiOrInteger32() && - value()->IsDiv() && value()->HasOneUse()) { - HDiv* hdiv = HDiv::cast(value()); - - HValue* left = hdiv->left(); - if (left->representation().IsInteger32() && !left->CheckFlag(kUint32)) { - // A value with an integer representation does not need to be transformed. - } else if (left->IsChange() && HChange::cast(left)->from().IsInteger32() && - !HChange::cast(left)->value()->CheckFlag(kUint32)) { - // A change from an integer32 can be replaced by the integer32 value. - left = HChange::cast(left)->value(); - } else if (hdiv->observed_input_representation(1).IsSmiOrInteger32()) { - left = Prepend(new (block()->zone()) HChange( - left, Representation::Integer32(), false, false, true)); - } else { - return this; - } - - HValue* right = hdiv->right(); - if (right->IsInteger32Constant()) { - right = Prepend(HConstant::cast(right)->CopyToRepresentation( - Representation::Integer32(), right->block()->zone())); - } else if (right->representation().IsInteger32() && - !right->CheckFlag(kUint32)) { - // A value with an integer representation does not need to be transformed. - } else if (right->IsChange() && - HChange::cast(right)->from().IsInteger32() && - !HChange::cast(right)->value()->CheckFlag(kUint32)) { - // A change from an integer32 can be replaced by the integer32 value. - right = HChange::cast(right)->value(); - } else if (hdiv->observed_input_representation(2).IsSmiOrInteger32()) { - right = Prepend(new (block()->zone()) HChange( - right, Representation::Integer32(), false, false, true)); - } else { - return this; - } - - return Prepend(HMathFloorOfDiv::New( - block()->graph()->isolate(), block()->zone(), context(), left, right)); - } - return this; -} - - -HValue* HCheckInstanceType::Canonicalize() { - if ((check_ == IS_JS_RECEIVER && value()->type().IsJSReceiver()) || - (check_ == IS_JS_ARRAY && value()->type().IsJSArray()) || - (check_ == IS_STRING && value()->type().IsString())) { - return value(); - } - - if (check_ == IS_INTERNALIZED_STRING && value()->IsConstant()) { - if (HConstant::cast(value())->HasInternalizedStringValue()) { - return value(); - } - } - return this; -} - - -void HCheckInstanceType::GetCheckInterval(InstanceType* first, - InstanceType* last) { - DCHECK(is_interval_check()); - switch (check_) { - case IS_JS_RECEIVER: - *first = FIRST_JS_RECEIVER_TYPE; - *last = LAST_JS_RECEIVER_TYPE; - return; - case IS_JS_ARRAY: - *first = *last = JS_ARRAY_TYPE; - return; - case IS_JS_FUNCTION: - *first = *last = JS_FUNCTION_TYPE; - return; - case IS_JS_DATE: - *first = *last = JS_DATE_TYPE; - return; - default: - UNREACHABLE(); - } -} - - -void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) { - DCHECK(!is_interval_check()); - switch (check_) { - case IS_STRING: - *mask = kIsNotStringMask; - *tag = kStringTag; - return; - case IS_INTERNALIZED_STRING: - *mask = kIsNotStringMask | kIsNotInternalizedMask; - *tag = kInternalizedTag; - return; - default: - UNREACHABLE(); - } -} - - -std::ostream& HCheckMaps::PrintDataTo(std::ostream& os) const { // NOLINT - os << NameOf(value()) << " [" << *maps()->at(0).handle(); - for (int i = 1; i < maps()->size(); ++i) { - os << "," << *maps()->at(i).handle(); - } - os << "]"; - if (IsStabilityCheck()) os << "(stability-check)"; - return os; -} - - -HValue* HCheckMaps::Canonicalize() { - if (!IsStabilityCheck() && maps_are_stable() && value()->IsConstant()) { - HConstant* c_value = HConstant::cast(value()); - if (c_value->HasObjectMap()) { - for (int i = 0; i < maps()->size(); ++i) { - if (c_value->ObjectMap() == maps()->at(i)) { - if (maps()->size() > 1) { - set_maps(new(block()->graph()->zone()) UniqueSet<Map>( - maps()->at(i), block()->graph()->zone())); - } - MarkAsStabilityCheck(); - break; - } - } - } - } - return this; -} - - -std::ostream& HCheckValue::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(value()) << " " << Brief(*object().handle()); -} - - -HValue* HCheckValue::Canonicalize() { - return (value()->IsConstant() && - HConstant::cast(value())->EqualsUnique(object_)) ? NULL : this; -} - - -const char* HCheckInstanceType::GetCheckName() const { - switch (check_) { - case IS_JS_RECEIVER: return "object"; - case IS_JS_ARRAY: return "array"; - case IS_JS_FUNCTION: - return "function"; - case IS_JS_DATE: - return "date"; - case IS_STRING: return "string"; - case IS_INTERNALIZED_STRING: return "internalized_string"; - } - UNREACHABLE(); - return ""; -} - - -std::ostream& HCheckInstanceType::PrintDataTo( - std::ostream& os) const { // NOLINT - os << GetCheckName() << " "; - return HUnaryOperation::PrintDataTo(os); -} - - -std::ostream& HUnknownOSRValue::PrintDataTo(std::ostream& os) const { // NOLINT - const char* type = "expression"; - if (environment_->is_local_index(index_)) type = "local"; - if (environment_->is_special_index(index_)) type = "special"; - if (environment_->is_parameter_index(index_)) type = "parameter"; - return os << type << " @ " << index_; -} - - -Range* HValue::InferRange(Zone* zone) { - Range* result; - if (representation().IsSmi() || type().IsSmi()) { - result = new(zone) Range(Smi::kMinValue, Smi::kMaxValue); - result->set_can_be_minus_zero(false); - } else { - result = new(zone) Range(); - result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32)); - // TODO(jkummerow): The range cannot be minus zero when the upper type - // bound is Integer32. - } - return result; -} - - -Range* HChange::InferRange(Zone* zone) { - Range* input_range = value()->range(); - if (from().IsInteger32() && !value()->CheckFlag(HInstruction::kUint32) && - (to().IsSmi() || - (to().IsTagged() && - input_range != NULL && - input_range->IsInSmiRange()))) { - set_type(HType::Smi()); - ClearChangesFlag(kNewSpacePromotion); - } - if (to().IsSmiOrTagged() && - input_range != NULL && - input_range->IsInSmiRange() && - (!SmiValuesAre32Bits() || - !value()->CheckFlag(HValue::kUint32) || - input_range->upper() != kMaxInt)) { - // The Range class can't express upper bounds in the (kMaxInt, kMaxUint32] - // interval, so we treat kMaxInt as a sentinel for this entire interval. - ClearFlag(kCanOverflow); - } - Range* result = (input_range != NULL) - ? input_range->Copy(zone) - : HValue::InferRange(zone); - result->set_can_be_minus_zero(!to().IsSmiOrInteger32() || - !(CheckFlag(kAllUsesTruncatingToInt32) || - CheckFlag(kAllUsesTruncatingToSmi))); - if (to().IsSmi()) result->ClampToSmi(); - return result; -} - - -Range* HConstant::InferRange(Zone* zone) { - if (HasInteger32Value()) { - Range* result = new(zone) Range(int32_value_, int32_value_); - result->set_can_be_minus_zero(false); - return result; - } - return HValue::InferRange(zone); -} - - -SourcePosition HPhi::position() const { return block()->first()->position(); } - - -Range* HPhi::InferRange(Zone* zone) { - Representation r = representation(); - if (r.IsSmiOrInteger32()) { - if (block()->IsLoopHeader()) { - Range* range = r.IsSmi() - ? new(zone) Range(Smi::kMinValue, Smi::kMaxValue) - : new(zone) Range(kMinInt, kMaxInt); - return range; - } else { - Range* range = OperandAt(0)->range()->Copy(zone); - for (int i = 1; i < OperandCount(); ++i) { - range->Union(OperandAt(i)->range()); - } - return range; - } - } else { - return HValue::InferRange(zone); - } -} - - -Range* HAdd::InferRange(Zone* zone) { - Representation r = representation(); - if (r.IsSmiOrInteger32()) { - Range* a = left()->range(); - Range* b = right()->range(); - Range* res = a->Copy(zone); - if (!res->AddAndCheckOverflow(r, b) || - (r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) || - (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) { - ClearFlag(kCanOverflow); - } - res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) && - !CheckFlag(kAllUsesTruncatingToInt32) && - a->CanBeMinusZero() && b->CanBeMinusZero()); - return res; - } else { - return HValue::InferRange(zone); - } -} - - -Range* HSub::InferRange(Zone* zone) { - Representation r = representation(); - if (r.IsSmiOrInteger32()) { - Range* a = left()->range(); - Range* b = right()->range(); - Range* res = a->Copy(zone); - if (!res->SubAndCheckOverflow(r, b) || - (r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) || - (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) { - ClearFlag(kCanOverflow); - } - res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) && - !CheckFlag(kAllUsesTruncatingToInt32) && - a->CanBeMinusZero() && b->CanBeZero()); - return res; - } else { - return HValue::InferRange(zone); - } -} - - -Range* HMul::InferRange(Zone* zone) { - Representation r = representation(); - if (r.IsSmiOrInteger32()) { - Range* a = left()->range(); - Range* b = right()->range(); - Range* res = a->Copy(zone); - if (!res->MulAndCheckOverflow(r, b) || - (((r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) || - (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) && - MulMinusOne())) { - // Truncated int multiplication is too precise and therefore not the - // same as converting to Double and back. - // Handle truncated integer multiplication by -1 special. - ClearFlag(kCanOverflow); - } - res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) && - !CheckFlag(kAllUsesTruncatingToInt32) && - ((a->CanBeZero() && b->CanBeNegative()) || - (a->CanBeNegative() && b->CanBeZero()))); - return res; - } else { - return HValue::InferRange(zone); - } -} - - -Range* HDiv::InferRange(Zone* zone) { - if (representation().IsInteger32()) { - Range* a = left()->range(); - Range* b = right()->range(); - Range* result = new(zone) Range(); - result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) && - (a->CanBeMinusZero() || - (a->CanBeZero() && b->CanBeNegative()))); - if (!a->Includes(kMinInt) || !b->Includes(-1)) { - ClearFlag(kCanOverflow); - } - - if (!b->CanBeZero()) { - ClearFlag(kCanBeDivByZero); - } - return result; - } else { - return HValue::InferRange(zone); - } -} - - -Range* HMathFloorOfDiv::InferRange(Zone* zone) { - if (representation().IsInteger32()) { - Range* a = left()->range(); - Range* b = right()->range(); - Range* result = new(zone) Range(); - result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) && - (a->CanBeMinusZero() || - (a->CanBeZero() && b->CanBeNegative()))); - if (!a->Includes(kMinInt)) { - ClearFlag(kLeftCanBeMinInt); - } - - if (!a->CanBeNegative()) { - ClearFlag(HValue::kLeftCanBeNegative); - } - - if (!a->CanBePositive()) { - ClearFlag(HValue::kLeftCanBePositive); - } - - if (!a->Includes(kMinInt) || !b->Includes(-1)) { - ClearFlag(kCanOverflow); - } - - if (!b->CanBeZero()) { - ClearFlag(kCanBeDivByZero); - } - return result; - } else { - return HValue::InferRange(zone); - } -} - - -// Returns the absolute value of its argument minus one, avoiding undefined -// behavior at kMinInt. -static int32_t AbsMinus1(int32_t a) { return a < 0 ? -(a + 1) : (a - 1); } - - -Range* HMod::InferRange(Zone* zone) { - if (representation().IsInteger32()) { - Range* a = left()->range(); - Range* b = right()->range(); - - // The magnitude of the modulus is bounded by the right operand. - int32_t positive_bound = Max(AbsMinus1(b->lower()), AbsMinus1(b->upper())); - - // The result of the modulo operation has the sign of its left operand. - bool left_can_be_negative = a->CanBeMinusZero() || a->CanBeNegative(); - Range* result = new(zone) Range(left_can_be_negative ? -positive_bound : 0, - a->CanBePositive() ? positive_bound : 0); - - result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) && - left_can_be_negative); - - if (!a->CanBeNegative()) { - ClearFlag(HValue::kLeftCanBeNegative); - } - - if (!a->Includes(kMinInt) || !b->Includes(-1)) { - ClearFlag(HValue::kCanOverflow); - } - - if (!b->CanBeZero()) { - ClearFlag(HValue::kCanBeDivByZero); - } - return result; - } else { - return HValue::InferRange(zone); - } -} - - -Range* HMathMinMax::InferRange(Zone* zone) { - if (representation().IsSmiOrInteger32()) { - Range* a = left()->range(); - Range* b = right()->range(); - Range* res = a->Copy(zone); - if (operation_ == kMathMax) { - res->CombinedMax(b); - } else { - DCHECK(operation_ == kMathMin); - res->CombinedMin(b); - } - return res; - } else { - return HValue::InferRange(zone); - } -} - - -void HPushArguments::AddInput(HValue* value) { - inputs_.Add(NULL, value->block()->zone()); - SetOperandAt(OperandCount() - 1, value); -} - - -std::ostream& HPhi::PrintTo(std::ostream& os) const { // NOLINT - os << "["; - for (int i = 0; i < OperandCount(); ++i) { - os << " " << NameOf(OperandAt(i)) << " "; - } - return os << " uses" << UseCount() - << representation_from_indirect_uses().Mnemonic() << " " - << TypeOf(this) << "]"; -} - - -void HPhi::AddInput(HValue* value) { - inputs_.Add(NULL, value->block()->zone()); - SetOperandAt(OperandCount() - 1, value); - // Mark phis that may have 'arguments' directly or indirectly as an operand. - if (!CheckFlag(kIsArguments) && value->CheckFlag(kIsArguments)) { - SetFlag(kIsArguments); - } -} - - -bool HPhi::HasRealUses() { - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - if (!it.value()->IsPhi()) return true; - } - return false; -} - - -HValue* HPhi::GetRedundantReplacement() { - HValue* candidate = NULL; - int count = OperandCount(); - int position = 0; - while (position < count && candidate == NULL) { - HValue* current = OperandAt(position++); - if (current != this) candidate = current; - } - while (position < count) { - HValue* current = OperandAt(position++); - if (current != this && current != candidate) return NULL; - } - DCHECK(candidate != this); - return candidate; -} - - -void HPhi::DeleteFromGraph() { - DCHECK(block() != NULL); - block()->RemovePhi(this); - DCHECK(block() == NULL); -} - - -void HPhi::InitRealUses(int phi_id) { - // Initialize real uses. - phi_id_ = phi_id; - // Compute a conservative approximation of truncating uses before inferring - // representations. The proper, exact computation will be done later, when - // inserting representation changes. - SetFlag(kTruncatingToSmi); - SetFlag(kTruncatingToInt32); - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - HValue* value = it.value(); - if (!value->IsPhi()) { - Representation rep = value->observed_input_representation(it.index()); - representation_from_non_phi_uses_ = - representation_from_non_phi_uses().generalize(rep); - if (rep.IsSmi() || rep.IsInteger32() || rep.IsDouble()) { - has_type_feedback_from_uses_ = true; - } - - if (FLAG_trace_representation) { - PrintF("#%d Phi is used by real #%d %s as %s\n", - id(), value->id(), value->Mnemonic(), rep.Mnemonic()); - } - if (!value->IsSimulate()) { - if (!value->CheckFlag(kTruncatingToSmi)) { - ClearFlag(kTruncatingToSmi); - } - if (!value->CheckFlag(kTruncatingToInt32)) { - ClearFlag(kTruncatingToInt32); - } - } - } - } -} - - -void HPhi::AddNonPhiUsesFrom(HPhi* other) { - if (FLAG_trace_representation) { - PrintF( - "generalizing use representation '%s' of #%d Phi " - "with uses of #%d Phi '%s'\n", - representation_from_indirect_uses().Mnemonic(), id(), other->id(), - other->representation_from_non_phi_uses().Mnemonic()); - } - - representation_from_indirect_uses_ = - representation_from_indirect_uses().generalize( - other->representation_from_non_phi_uses()); -} - - -void HSimulate::MergeWith(ZoneList<HSimulate*>* list) { - while (!list->is_empty()) { - HSimulate* from = list->RemoveLast(); - ZoneList<HValue*>* from_values = &from->values_; - for (int i = 0; i < from_values->length(); ++i) { - if (from->HasAssignedIndexAt(i)) { - int index = from->GetAssignedIndexAt(i); - if (HasValueForIndex(index)) continue; - AddAssignedValue(index, from_values->at(i)); - } else { - if (pop_count_ > 0) { - pop_count_--; - } else { - AddPushedValue(from_values->at(i)); - } - } - } - pop_count_ += from->pop_count_; - from->DeleteAndReplaceWith(NULL); - } -} - - -std::ostream& HSimulate::PrintDataTo(std::ostream& os) const { // NOLINT - os << "id=" << ast_id().ToInt(); - if (pop_count_ > 0) os << " pop " << pop_count_; - if (values_.length() > 0) { - if (pop_count_ > 0) os << " /"; - for (int i = values_.length() - 1; i >= 0; --i) { - if (HasAssignedIndexAt(i)) { - os << " var[" << GetAssignedIndexAt(i) << "] = "; - } else { - os << " push "; - } - os << NameOf(values_[i]); - if (i > 0) os << ","; - } - } - return os; -} - - -void HSimulate::ReplayEnvironment(HEnvironment* env) { - if (is_done_with_replay()) return; - DCHECK(env != NULL); - env->set_ast_id(ast_id()); - env->Drop(pop_count()); - for (int i = values()->length() - 1; i >= 0; --i) { - HValue* value = values()->at(i); - if (HasAssignedIndexAt(i)) { - env->Bind(GetAssignedIndexAt(i), value); - } else { - env->Push(value); - } - } - set_done_with_replay(); -} - - -static void ReplayEnvironmentNested(const ZoneList<HValue*>* values, - HCapturedObject* other) { - for (int i = 0; i < values->length(); ++i) { - HValue* value = values->at(i); - if (value->IsCapturedObject()) { - if (HCapturedObject::cast(value)->capture_id() == other->capture_id()) { - values->at(i) = other; - } else { - ReplayEnvironmentNested(HCapturedObject::cast(value)->values(), other); - } - } - } -} - - -// Replay captured objects by replacing all captured objects with the -// same capture id in the current and all outer environments. -void HCapturedObject::ReplayEnvironment(HEnvironment* env) { - DCHECK(env != NULL); - while (env != NULL) { - ReplayEnvironmentNested(env->values(), this); - env = env->outer(); - } -} - - -std::ostream& HCapturedObject::PrintDataTo(std::ostream& os) const { // NOLINT - os << "#" << capture_id() << " "; - return HDematerializedObject::PrintDataTo(os); -} - - -void HEnterInlined::RegisterReturnTarget(HBasicBlock* return_target, - Zone* zone) { - DCHECK(return_target->IsInlineReturnTarget()); - return_targets_.Add(return_target, zone); -} - - -std::ostream& HEnterInlined::PrintDataTo(std::ostream& os) const { // NOLINT - os << function()->debug_name()->ToCString().get(); - if (syntactic_tail_call_mode() == TailCallMode::kAllow) { - os << ", JSTailCall"; - } - return os; -} - - -static bool IsInteger32(double value) { - if (value >= std::numeric_limits<int32_t>::min() && - value <= std::numeric_limits<int32_t>::max()) { - double roundtrip_value = static_cast<double>(static_cast<int32_t>(value)); - return bit_cast<int64_t>(roundtrip_value) == bit_cast<int64_t>(value); - } - return false; -} - - -HConstant::HConstant(Special special) - : HTemplateInstruction<0>(HType::TaggedNumber()), - object_(Handle<Object>::null()), - object_map_(Handle<Map>::null()), - bit_field_(HasDoubleValueField::encode(true) | - InstanceTypeField::encode(kUnknownInstanceType)), - int32_value_(0) { - DCHECK_EQ(kHoleNaN, special); - // Manipulating the signaling NaN used for the hole in C++, e.g. with bit_cast - // will change its value on ia32 (the x87 stack is used to return values - // and stores to the stack silently clear the signalling bit). - // Therefore we have to use memcpy for initializing |double_value_| with - // kHoleNanInt64 here. - std::memcpy(&double_value_, &kHoleNanInt64, sizeof(double_value_)); - Initialize(Representation::Double()); -} - - -HConstant::HConstant(Handle<Object> object, Representation r) - : HTemplateInstruction<0>(HType::FromValue(object)), - object_(Unique<Object>::CreateUninitialized(object)), - object_map_(Handle<Map>::null()), - bit_field_( - HasStableMapValueField::encode(false) | - HasSmiValueField::encode(false) | HasInt32ValueField::encode(false) | - HasDoubleValueField::encode(false) | - HasExternalReferenceValueField::encode(false) | - IsNotInNewSpaceField::encode(true) | - BooleanValueField::encode(object->BooleanValue()) | - IsUndetectableField::encode(false) | IsCallableField::encode(false) | - InstanceTypeField::encode(kUnknownInstanceType)) { - if (object->IsNumber()) { - double n = object->Number(); - bool has_int32_value = IsInteger32(n); - bit_field_ = HasInt32ValueField::update(bit_field_, has_int32_value); - int32_value_ = DoubleToInt32(n); - bit_field_ = HasSmiValueField::update( - bit_field_, has_int32_value && Smi::IsValid(int32_value_)); - if (std::isnan(n)) { - double_value_ = std::numeric_limits<double>::quiet_NaN(); - // Canonicalize object with NaN value. - DCHECK(object->IsHeapObject()); // NaN can't be a Smi. - Isolate* isolate = HeapObject::cast(*object)->GetIsolate(); - object = isolate->factory()->nan_value(); - object_ = Unique<Object>::CreateUninitialized(object); - } else { - double_value_ = n; - // Canonicalize object with -0.0 value. - if (bit_cast<int64_t>(n) == bit_cast<int64_t>(-0.0)) { - DCHECK(object->IsHeapObject()); // -0.0 can't be a Smi. - Isolate* isolate = HeapObject::cast(*object)->GetIsolate(); - object = isolate->factory()->minus_zero_value(); - object_ = Unique<Object>::CreateUninitialized(object); - } - } - bit_field_ = HasDoubleValueField::update(bit_field_, true); - } - if (object->IsHeapObject()) { - Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); - Isolate* isolate = heap_object->GetIsolate(); - Handle<Map> map(heap_object->map(), isolate); - bit_field_ = IsNotInNewSpaceField::update( - bit_field_, !isolate->heap()->InNewSpace(*object)); - bit_field_ = InstanceTypeField::update(bit_field_, map->instance_type()); - bit_field_ = - IsUndetectableField::update(bit_field_, map->is_undetectable()); - bit_field_ = IsCallableField::update(bit_field_, map->is_callable()); - if (map->is_stable()) object_map_ = Unique<Map>::CreateImmovable(map); - bit_field_ = HasStableMapValueField::update( - bit_field_, - HasMapValue() && Handle<Map>::cast(heap_object)->is_stable()); - } - - Initialize(r); -} - - -HConstant::HConstant(Unique<Object> object, Unique<Map> object_map, - bool has_stable_map_value, Representation r, HType type, - bool is_not_in_new_space, bool boolean_value, - bool is_undetectable, InstanceType instance_type) - : HTemplateInstruction<0>(type), - object_(object), - object_map_(object_map), - bit_field_(HasStableMapValueField::encode(has_stable_map_value) | - HasSmiValueField::encode(false) | - HasInt32ValueField::encode(false) | - HasDoubleValueField::encode(false) | - HasExternalReferenceValueField::encode(false) | - IsNotInNewSpaceField::encode(is_not_in_new_space) | - BooleanValueField::encode(boolean_value) | - IsUndetectableField::encode(is_undetectable) | - InstanceTypeField::encode(instance_type)) { - DCHECK(!object.handle().is_null()); - DCHECK(!type.IsTaggedNumber() || type.IsNone()); - Initialize(r); -} - - -HConstant::HConstant(int32_t integer_value, Representation r, - bool is_not_in_new_space, Unique<Object> object) - : object_(object), - object_map_(Handle<Map>::null()), - bit_field_(HasStableMapValueField::encode(false) | - HasSmiValueField::encode(Smi::IsValid(integer_value)) | - HasInt32ValueField::encode(true) | - HasDoubleValueField::encode(true) | - HasExternalReferenceValueField::encode(false) | - IsNotInNewSpaceField::encode(is_not_in_new_space) | - BooleanValueField::encode(integer_value != 0) | - IsUndetectableField::encode(false) | - InstanceTypeField::encode(kUnknownInstanceType)), - int32_value_(integer_value), - double_value_(FastI2D(integer_value)) { - // It's possible to create a constant with a value in Smi-range but stored - // in a (pre-existing) HeapNumber. See crbug.com/349878. - bool could_be_heapobject = r.IsTagged() && !object.handle().is_null(); - bool is_smi = HasSmiValue() && !could_be_heapobject; - set_type(is_smi ? HType::Smi() : HType::TaggedNumber()); - Initialize(r); -} - -HConstant::HConstant(double double_value, Representation r, - bool is_not_in_new_space, Unique<Object> object) - : object_(object), - object_map_(Handle<Map>::null()), - bit_field_(HasStableMapValueField::encode(false) | - HasInt32ValueField::encode(IsInteger32(double_value)) | - HasDoubleValueField::encode(true) | - HasExternalReferenceValueField::encode(false) | - IsNotInNewSpaceField::encode(is_not_in_new_space) | - BooleanValueField::encode(double_value != 0 && - !std::isnan(double_value)) | - IsUndetectableField::encode(false) | - InstanceTypeField::encode(kUnknownInstanceType)), - int32_value_(DoubleToInt32(double_value)) { - bit_field_ = HasSmiValueField::update( - bit_field_, HasInteger32Value() && Smi::IsValid(int32_value_)); - // It's possible to create a constant with a value in Smi-range but stored - // in a (pre-existing) HeapNumber. See crbug.com/349878. - bool could_be_heapobject = r.IsTagged() && !object.handle().is_null(); - bool is_smi = HasSmiValue() && !could_be_heapobject; - set_type(is_smi ? HType::Smi() : HType::TaggedNumber()); - if (std::isnan(double_value)) { - double_value_ = std::numeric_limits<double>::quiet_NaN(); - } else { - double_value_ = double_value; - } - Initialize(r); -} - - -HConstant::HConstant(ExternalReference reference) - : HTemplateInstruction<0>(HType::Any()), - object_(Unique<Object>(Handle<Object>::null())), - object_map_(Handle<Map>::null()), - bit_field_( - HasStableMapValueField::encode(false) | - HasSmiValueField::encode(false) | HasInt32ValueField::encode(false) | - HasDoubleValueField::encode(false) | - HasExternalReferenceValueField::encode(true) | - IsNotInNewSpaceField::encode(true) | BooleanValueField::encode(true) | - IsUndetectableField::encode(false) | - InstanceTypeField::encode(kUnknownInstanceType)), - external_reference_value_(reference) { - Initialize(Representation::External()); -} - - -void HConstant::Initialize(Representation r) { - if (r.IsNone()) { - if (HasSmiValue() && SmiValuesAre31Bits()) { - r = Representation::Smi(); - } else if (HasInteger32Value()) { - r = Representation::Integer32(); - } else if (HasDoubleValue()) { - r = Representation::Double(); - } else if (HasExternalReferenceValue()) { - r = Representation::External(); - } else { - Handle<Object> object = object_.handle(); - if (object->IsJSObject()) { - // Try to eagerly migrate JSObjects that have deprecated maps. - Handle<JSObject> js_object = Handle<JSObject>::cast(object); - if (js_object->map()->is_deprecated()) { - JSObject::TryMigrateInstance(js_object); - } - } - r = Representation::Tagged(); - } - } - if (r.IsSmi()) { - // If we have an existing handle, zap it, because it might be a heap - // number which we must not re-use when copying this HConstant to - // Tagged representation later, because having Smi representation now - // could cause heap object checks not to get emitted. - object_ = Unique<Object>(Handle<Object>::null()); - } - if (r.IsSmiOrInteger32() && object_.handle().is_null()) { - // If it's not a heap object, it can't be in new space. - bit_field_ = IsNotInNewSpaceField::update(bit_field_, true); - } - set_representation(r); - SetFlag(kUseGVN); -} - - -bool HConstant::ImmortalImmovable() const { - if (HasInteger32Value()) { - return false; - } - if (HasDoubleValue()) { - if (IsSpecialDouble()) { - return true; - } - return false; - } - if (HasExternalReferenceValue()) { - return false; - } - - DCHECK(!object_.handle().is_null()); - Heap* heap = isolate()->heap(); - DCHECK(!object_.IsKnownGlobal(heap->minus_zero_value())); - DCHECK(!object_.IsKnownGlobal(heap->nan_value())); - return -#define IMMORTAL_IMMOVABLE_ROOT(name) \ - object_.IsKnownGlobal(heap->root(Heap::k##name##RootIndex)) || - IMMORTAL_IMMOVABLE_ROOT_LIST(IMMORTAL_IMMOVABLE_ROOT) -#undef IMMORTAL_IMMOVABLE_ROOT -#define INTERNALIZED_STRING(name, value) \ - object_.IsKnownGlobal(heap->name()) || - INTERNALIZED_STRING_LIST(INTERNALIZED_STRING) -#undef INTERNALIZED_STRING -#define STRING_TYPE(NAME, size, name, Name) \ - object_.IsKnownGlobal(heap->name##_map()) || - STRING_TYPE_LIST(STRING_TYPE) -#undef STRING_TYPE - false; -} - - -bool HConstant::EmitAtUses() { - DCHECK(IsLinked()); - if (block()->graph()->has_osr() && - block()->graph()->IsStandardConstant(this)) { - return true; - } - if (HasNoUses()) return true; - if (IsCell()) return false; - if (representation().IsDouble()) return false; - if (representation().IsExternal()) return false; - return true; -} - - -HConstant* HConstant::CopyToRepresentation(Representation r, Zone* zone) const { - if (r.IsSmi() && !HasSmiValue()) return NULL; - if (r.IsInteger32() && !HasInteger32Value()) return NULL; - if (r.IsDouble() && !HasDoubleValue()) return NULL; - if (r.IsExternal() && !HasExternalReferenceValue()) return NULL; - if (HasInteger32Value()) { - return new (zone) HConstant(int32_value_, r, NotInNewSpace(), object_); - } - if (HasDoubleValue()) { - return new (zone) HConstant(double_value_, r, NotInNewSpace(), object_); - } - if (HasExternalReferenceValue()) { - return new(zone) HConstant(external_reference_value_); - } - DCHECK(!object_.handle().is_null()); - return new (zone) HConstant(object_, object_map_, HasStableMapValue(), r, - type_, NotInNewSpace(), BooleanValue(), - IsUndetectable(), GetInstanceType()); -} - - -Maybe<HConstant*> HConstant::CopyToTruncatedInt32(Zone* zone) { - HConstant* res = NULL; - if (HasInteger32Value()) { - res = new (zone) HConstant(int32_value_, Representation::Integer32(), - NotInNewSpace(), object_); - } else if (HasDoubleValue()) { - res = new (zone) - HConstant(DoubleToInt32(double_value_), Representation::Integer32(), - NotInNewSpace(), object_); - } - return res != NULL ? Just(res) : Nothing<HConstant*>(); -} - - -Maybe<HConstant*> HConstant::CopyToTruncatedNumber(Isolate* isolate, - Zone* zone) { - HConstant* res = NULL; - Handle<Object> handle = this->handle(isolate); - if (handle->IsBoolean()) { - res = handle->BooleanValue() ? - new(zone) HConstant(1) : new(zone) HConstant(0); - } else if (handle->IsUndefined(isolate)) { - res = new (zone) HConstant(std::numeric_limits<double>::quiet_NaN()); - } else if (handle->IsNull(isolate)) { - res = new(zone) HConstant(0); - } else if (handle->IsString()) { - res = new(zone) HConstant(String::ToNumber(Handle<String>::cast(handle))); - } - return res != NULL ? Just(res) : Nothing<HConstant*>(); -} - - -std::ostream& HConstant::PrintDataTo(std::ostream& os) const { // NOLINT - if (HasInteger32Value()) { - os << int32_value_ << " "; - } else if (HasDoubleValue()) { - os << double_value_ << " "; - } else if (HasExternalReferenceValue()) { - os << reinterpret_cast<void*>(external_reference_value_.address()) << " "; - } else { - // The handle() method is silently and lazily mutating the object. - Handle<Object> h = const_cast<HConstant*>(this)->handle(isolate()); - os << Brief(*h) << " "; - if (HasStableMapValue()) os << "[stable-map] "; - if (HasObjectMap()) os << "[map " << *ObjectMap().handle() << "] "; - } - if (!NotInNewSpace()) os << "[new space] "; - return os; -} - - -std::ostream& HBinaryOperation::PrintDataTo(std::ostream& os) const { // NOLINT - os << NameOf(left()) << " " << NameOf(right()); - if (CheckFlag(kCanOverflow)) os << " !"; - if (CheckFlag(kBailoutOnMinusZero)) os << " -0?"; - return os; -} - - -void HBinaryOperation::InferRepresentation(HInferRepresentationPhase* h_infer) { - DCHECK(CheckFlag(kFlexibleRepresentation)); - Representation new_rep = RepresentationFromInputs(); - UpdateRepresentation(new_rep, h_infer, "inputs"); - - if (representation().IsSmi() && HasNonSmiUse()) { - UpdateRepresentation( - Representation::Integer32(), h_infer, "use requirements"); - } - - if (observed_output_representation_.IsNone()) { - new_rep = RepresentationFromUses(); - UpdateRepresentation(new_rep, h_infer, "uses"); - } else { - new_rep = RepresentationFromOutput(); - UpdateRepresentation(new_rep, h_infer, "output"); - } -} - - -Representation HBinaryOperation::RepresentationFromInputs() { - // Determine the worst case of observed input representations and - // the currently assumed output representation. - Representation rep = representation(); - for (int i = 1; i <= 2; ++i) { - rep = rep.generalize(observed_input_representation(i)); - } - // If any of the actual input representation is more general than what we - // have so far but not Tagged, use that representation instead. - Representation left_rep = left()->representation(); - Representation right_rep = right()->representation(); - if (!left_rep.IsTagged()) rep = rep.generalize(left_rep); - if (!right_rep.IsTagged()) rep = rep.generalize(right_rep); - - return rep; -} - - -bool HBinaryOperation::IgnoreObservedOutputRepresentation( - Representation current_rep) { - return ((current_rep.IsInteger32() && CheckUsesForFlag(kTruncatingToInt32)) || - (current_rep.IsSmi() && CheckUsesForFlag(kTruncatingToSmi))) && - // Mul in Integer32 mode would be too precise. - (!this->IsMul() || HMul::cast(this)->MulMinusOne()); -} - - -Representation HBinaryOperation::RepresentationFromOutput() { - Representation rep = representation(); - // Consider observed output representation, but ignore it if it's Double, - // this instruction is not a division, and all its uses are truncating - // to Integer32. - if (observed_output_representation_.is_more_general_than(rep) && - !IgnoreObservedOutputRepresentation(rep)) { - return observed_output_representation_; - } - return Representation::None(); -} - - -void HBinaryOperation::AssumeRepresentation(Representation r) { - set_observed_input_representation(1, r); - set_observed_input_representation(2, r); - HValue::AssumeRepresentation(r); -} - - -void HMathMinMax::InferRepresentation(HInferRepresentationPhase* h_infer) { - DCHECK(CheckFlag(kFlexibleRepresentation)); - Representation new_rep = RepresentationFromInputs(); - UpdateRepresentation(new_rep, h_infer, "inputs"); - // Do not care about uses. -} - - -Range* HBitwise::InferRange(Zone* zone) { - if (op() == Token::BIT_XOR) { - if (left()->HasRange() && right()->HasRange()) { - // The maximum value has the high bit, and all bits below, set: - // (1 << high) - 1. - // If the range can be negative, the minimum int is a negative number with - // the high bit, and all bits below, unset: - // -(1 << high). - // If it cannot be negative, conservatively choose 0 as minimum int. - int64_t left_upper = left()->range()->upper(); - int64_t left_lower = left()->range()->lower(); - int64_t right_upper = right()->range()->upper(); - int64_t right_lower = right()->range()->lower(); - - if (left_upper < 0) left_upper = ~left_upper; - if (left_lower < 0) left_lower = ~left_lower; - if (right_upper < 0) right_upper = ~right_upper; - if (right_lower < 0) right_lower = ~right_lower; - - int high = MostSignificantBit( - static_cast<uint32_t>( - left_upper | left_lower | right_upper | right_lower)); - - int64_t limit = 1; - limit <<= high; - int32_t min = (left()->range()->CanBeNegative() || - right()->range()->CanBeNegative()) - ? static_cast<int32_t>(-limit) : 0; - return new(zone) Range(min, static_cast<int32_t>(limit - 1)); - } - Range* result = HValue::InferRange(zone); - result->set_can_be_minus_zero(false); - return result; - } - const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff); - int32_t left_mask = (left()->range() != NULL) - ? left()->range()->Mask() - : kDefaultMask; - int32_t right_mask = (right()->range() != NULL) - ? right()->range()->Mask() - : kDefaultMask; - int32_t result_mask = (op() == Token::BIT_AND) - ? left_mask & right_mask - : left_mask | right_mask; - if (result_mask >= 0) return new(zone) Range(0, result_mask); - - Range* result = HValue::InferRange(zone); - result->set_can_be_minus_zero(false); - return result; -} - - -Range* HSar::InferRange(Zone* zone) { - if (right()->IsConstant()) { - HConstant* c = HConstant::cast(right()); - if (c->HasInteger32Value()) { - Range* result = (left()->range() != NULL) - ? left()->range()->Copy(zone) - : new(zone) Range(); - result->Sar(c->Integer32Value()); - return result; - } - } - return HValue::InferRange(zone); -} - - -Range* HShr::InferRange(Zone* zone) { - if (right()->IsConstant()) { - HConstant* c = HConstant::cast(right()); - if (c->HasInteger32Value()) { - int shift_count = c->Integer32Value() & 0x1f; - if (left()->range()->CanBeNegative()) { - // Only compute bounds if the result always fits into an int32. - return (shift_count >= 1) - ? new(zone) Range(0, - static_cast<uint32_t>(0xffffffff) >> shift_count) - : new(zone) Range(); - } else { - // For positive inputs we can use the >> operator. - Range* result = (left()->range() != NULL) - ? left()->range()->Copy(zone) - : new(zone) Range(); - result->Sar(c->Integer32Value()); - return result; - } - } - } - return HValue::InferRange(zone); -} - - -Range* HShl::InferRange(Zone* zone) { - if (right()->IsConstant()) { - HConstant* c = HConstant::cast(right()); - if (c->HasInteger32Value()) { - Range* result = (left()->range() != NULL) - ? left()->range()->Copy(zone) - : new(zone) Range(); - result->Shl(c->Integer32Value()); - return result; - } - } - return HValue::InferRange(zone); -} - - -Range* HLoadNamedField::InferRange(Zone* zone) { - if (access().representation().IsInteger8()) { - return new(zone) Range(kMinInt8, kMaxInt8); - } - if (access().representation().IsUInteger8()) { - return new(zone) Range(kMinUInt8, kMaxUInt8); - } - if (access().representation().IsInteger16()) { - return new(zone) Range(kMinInt16, kMaxInt16); - } - if (access().representation().IsUInteger16()) { - return new(zone) Range(kMinUInt16, kMaxUInt16); - } - if (access().IsStringLength()) { - return new(zone) Range(0, String::kMaxLength); - } - return HValue::InferRange(zone); -} - - -Range* HLoadKeyed::InferRange(Zone* zone) { - switch (elements_kind()) { - case INT8_ELEMENTS: - return new(zone) Range(kMinInt8, kMaxInt8); - case UINT8_ELEMENTS: - case UINT8_CLAMPED_ELEMENTS: - return new(zone) Range(kMinUInt8, kMaxUInt8); - case INT16_ELEMENTS: - return new(zone) Range(kMinInt16, kMaxInt16); - case UINT16_ELEMENTS: - return new(zone) Range(kMinUInt16, kMaxUInt16); - default: - return HValue::InferRange(zone); - } -} - - -std::ostream& HCompareGeneric::PrintDataTo(std::ostream& os) const { // NOLINT - os << Token::Name(token()) << " "; - return HBinaryOperation::PrintDataTo(os); -} - - -std::ostream& HStringCompareAndBranch::PrintDataTo( - std::ostream& os) const { // NOLINT - os << Token::Name(token()) << " "; - return HControlInstruction::PrintDataTo(os); -} - - -std::ostream& HCompareNumericAndBranch::PrintDataTo( - std::ostream& os) const { // NOLINT - os << Token::Name(token()) << " " << NameOf(left()) << " " << NameOf(right()); - return HControlInstruction::PrintDataTo(os); -} - - -std::ostream& HCompareObjectEqAndBranch::PrintDataTo( - std::ostream& os) const { // NOLINT - os << NameOf(left()) << " " << NameOf(right()); - return HControlInstruction::PrintDataTo(os); -} - - -bool HCompareObjectEqAndBranch::KnownSuccessorBlock(HBasicBlock** block) { - if (known_successor_index() != kNoKnownSuccessorIndex) { - *block = SuccessorAt(known_successor_index()); - return true; - } - if (FLAG_fold_constants && left()->IsConstant() && right()->IsConstant()) { - *block = HConstant::cast(left())->DataEquals(HConstant::cast(right())) - ? FirstSuccessor() : SecondSuccessor(); - return true; - } - *block = NULL; - return false; -} - - -bool HIsStringAndBranch::KnownSuccessorBlock(HBasicBlock** block) { - if (known_successor_index() != kNoKnownSuccessorIndex) { - *block = SuccessorAt(known_successor_index()); - return true; - } - if (FLAG_fold_constants && value()->IsConstant()) { - *block = HConstant::cast(value())->HasStringValue() - ? FirstSuccessor() : SecondSuccessor(); - return true; - } - if (value()->type().IsString()) { - *block = FirstSuccessor(); - return true; - } - if (value()->type().IsSmi() || - value()->type().IsNull() || - value()->type().IsBoolean() || - value()->type().IsUndefined() || - value()->type().IsJSReceiver()) { - *block = SecondSuccessor(); - return true; - } - *block = NULL; - return false; -} - - -bool HIsUndetectableAndBranch::KnownSuccessorBlock(HBasicBlock** block) { - if (FLAG_fold_constants && value()->IsConstant()) { - *block = HConstant::cast(value())->IsUndetectable() - ? FirstSuccessor() : SecondSuccessor(); - return true; - } - if (value()->type().IsNull() || value()->type().IsUndefined()) { - *block = FirstSuccessor(); - return true; - } - if (value()->type().IsBoolean() || - value()->type().IsSmi() || - value()->type().IsString() || - value()->type().IsJSReceiver()) { - *block = SecondSuccessor(); - return true; - } - *block = NULL; - return false; -} - - -bool HHasInstanceTypeAndBranch::KnownSuccessorBlock(HBasicBlock** block) { - if (FLAG_fold_constants && value()->IsConstant()) { - InstanceType type = HConstant::cast(value())->GetInstanceType(); - *block = (from_ <= type) && (type <= to_) - ? FirstSuccessor() : SecondSuccessor(); - return true; - } - *block = NULL; - return false; -} - - -void HCompareHoleAndBranch::InferRepresentation( - HInferRepresentationPhase* h_infer) { - ChangeRepresentation(value()->representation()); -} - - -bool HCompareNumericAndBranch::KnownSuccessorBlock(HBasicBlock** block) { - if (left() == right() && - left()->representation().IsSmiOrInteger32()) { - *block = (token() == Token::EQ || - token() == Token::EQ_STRICT || - token() == Token::LTE || - token() == Token::GTE) - ? FirstSuccessor() : SecondSuccessor(); - return true; - } - *block = NULL; - return false; -} - - -std::ostream& HGoto::PrintDataTo(std::ostream& os) const { // NOLINT - return os << *SuccessorAt(0); -} - - -void HCompareNumericAndBranch::InferRepresentation( - HInferRepresentationPhase* h_infer) { - Representation left_rep = left()->representation(); - Representation right_rep = right()->representation(); - Representation observed_left = observed_input_representation(0); - Representation observed_right = observed_input_representation(1); - - Representation rep = Representation::None(); - rep = rep.generalize(observed_left); - rep = rep.generalize(observed_right); - if (rep.IsNone() || rep.IsSmiOrInteger32()) { - if (!left_rep.IsTagged()) rep = rep.generalize(left_rep); - if (!right_rep.IsTagged()) rep = rep.generalize(right_rep); - } else { - rep = Representation::Double(); - } - - if (rep.IsDouble()) { - // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, === - // and !=) have special handling of undefined, e.g. undefined == undefined - // is 'true'. Relational comparisons have a different semantic, first - // calling ToPrimitive() on their arguments. The standard Crankshaft - // tagged-to-double conversion to ensure the HCompareNumericAndBranch's - // inputs are doubles caused 'undefined' to be converted to NaN. That's - // compatible out-of-the box with ordered relational comparisons (<, >, <=, - // >=). However, for equality comparisons (and for 'in' and 'instanceof'), - // it is not consistent with the spec. For example, it would cause undefined - // == undefined (should be true) to be evaluated as NaN == NaN - // (false). Therefore, any comparisons other than ordered relational - // comparisons must cause a deopt when one of their arguments is undefined. - // See also v8:1434 - if (Token::IsOrderedRelationalCompareOp(token_)) { - SetFlag(kTruncatingToNumber); - } - } - ChangeRepresentation(rep); -} - - -std::ostream& HParameter::PrintDataTo(std::ostream& os) const { // NOLINT - return os << index(); -} - - -std::ostream& HLoadNamedField::PrintDataTo(std::ostream& os) const { // NOLINT - os << NameOf(object()) << access_; - - if (maps() != NULL) { - os << " [" << *maps()->at(0).handle(); - for (int i = 1; i < maps()->size(); ++i) { - os << "," << *maps()->at(i).handle(); - } - os << "]"; - } - - if (HasDependency()) os << " " << NameOf(dependency()); - return os; -} - - -std::ostream& HLoadKeyed::PrintDataTo(std::ostream& os) const { // NOLINT - if (!is_fixed_typed_array()) { - os << NameOf(elements()); - } else { - DCHECK(elements_kind() >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND && - elements_kind() <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); - os << NameOf(elements()) << "." << ElementsKindToString(elements_kind()); - } - - os << "[" << NameOf(key()); - if (IsDehoisted()) os << " + " << base_offset(); - os << "]"; - - if (HasDependency()) os << " " << NameOf(dependency()); - if (RequiresHoleCheck()) os << " check_hole"; - return os; -} - - -bool HLoadKeyed::TryIncreaseBaseOffset(uint32_t increase_by_value) { - // The base offset is usually simply the size of the array header, except - // with dehoisting adds an addition offset due to a array index key - // manipulation, in which case it becomes (array header size + - // constant-offset-from-key * kPointerSize) - uint32_t base_offset = BaseOffsetField::decode(bit_field_); - v8::base::internal::CheckedNumeric<uint32_t> addition_result = base_offset; - addition_result += increase_by_value; - if (!addition_result.IsValid()) return false; - base_offset = addition_result.ValueOrDie(); - if (!BaseOffsetField::is_valid(base_offset)) return false; - bit_field_ = BaseOffsetField::update(bit_field_, base_offset); - return true; -} - - -bool HLoadKeyed::UsesMustHandleHole() const { - if (IsFastPackedElementsKind(elements_kind())) { - return false; - } - - if (IsFixedTypedArrayElementsKind(elements_kind())) { - return false; - } - - if (hole_mode() == ALLOW_RETURN_HOLE) { - if (IsFastDoubleElementsKind(elements_kind())) { - return AllUsesCanTreatHoleAsNaN(); - } - return true; - } - - if (IsFastDoubleElementsKind(elements_kind())) { - return false; - } - - // Holes are only returned as tagged values. - if (!representation().IsTagged()) { - return false; - } - - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - HValue* use = it.value(); - if (!use->IsChange()) return false; - } - - return true; -} - - -bool HLoadKeyed::AllUsesCanTreatHoleAsNaN() const { - return IsFastDoubleElementsKind(elements_kind()) && - CheckUsesForFlag(HValue::kTruncatingToNumber); -} - - -bool HLoadKeyed::RequiresHoleCheck() const { - if (IsFastPackedElementsKind(elements_kind())) { - return false; - } - - if (IsFixedTypedArrayElementsKind(elements_kind())) { - return false; - } - - if (hole_mode() == CONVERT_HOLE_TO_UNDEFINED) { - return false; - } - - return !UsesMustHandleHole(); -} - -HValue* HCallWithDescriptor::Canonicalize() { - if (kind() != Code::KEYED_LOAD_IC) return this; - - // Recognize generic keyed loads that use property name generated - // by for-in statement as a key and rewrite them into fast property load - // by index. - typedef LoadWithVectorDescriptor Descriptor; - HValue* key = parameter(Descriptor::kName); - if (key->IsLoadKeyed()) { - HLoadKeyed* key_load = HLoadKeyed::cast(key); - if (key_load->elements()->IsForInCacheArray()) { - HForInCacheArray* names_cache = - HForInCacheArray::cast(key_load->elements()); - - HValue* object = parameter(Descriptor::kReceiver); - if (names_cache->enumerable() == object) { - HForInCacheArray* index_cache = - names_cache->index_cache(); - HCheckMapValue* map_check = HCheckMapValue::New( - block()->graph()->isolate(), block()->graph()->zone(), - block()->graph()->GetInvalidContext(), object, names_cache->map()); - HInstruction* index = HLoadKeyed::New( - block()->graph()->isolate(), block()->graph()->zone(), - block()->graph()->GetInvalidContext(), index_cache, key_load->key(), - key_load->key(), nullptr, key_load->elements_kind()); - map_check->InsertBefore(this); - index->InsertBefore(this); - return Prepend(new (block()->zone()) HLoadFieldByIndex(object, index)); - } - } - } - return this; -} - -std::ostream& HStoreNamedField::PrintDataTo(std::ostream& os) const { // NOLINT - os << NameOf(object()) << access_ << " = " << NameOf(value()); - if (NeedsWriteBarrier()) os << " (write-barrier)"; - if (has_transition()) os << " (transition map " << *transition_map() << ")"; - return os; -} - - -std::ostream& HStoreKeyed::PrintDataTo(std::ostream& os) const { // NOLINT - if (!is_fixed_typed_array()) { - os << NameOf(elements()); - } else { - DCHECK(elements_kind() >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND && - elements_kind() <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); - os << NameOf(elements()) << "." << ElementsKindToString(elements_kind()); - } - - os << "[" << NameOf(key()); - if (IsDehoisted()) os << " + " << base_offset(); - return os << "] = " << NameOf(value()); -} - - -std::ostream& HTransitionElementsKind::PrintDataTo( - std::ostream& os) const { // NOLINT - os << NameOf(object()); - ElementsKind from_kind = original_map().handle()->elements_kind(); - ElementsKind to_kind = transitioned_map().handle()->elements_kind(); - os << " " << *original_map().handle() << " [" - << ElementsAccessor::ForKind(from_kind)->name() << "] -> " - << *transitioned_map().handle() << " [" - << ElementsAccessor::ForKind(to_kind)->name() << "]"; - if (IsSimpleMapChangeTransition(from_kind, to_kind)) os << " (simple)"; - return os; -} - - -std::ostream& HInnerAllocatedObject::PrintDataTo( - std::ostream& os) const { // NOLINT - os << NameOf(base_object()) << " offset "; - return offset()->PrintTo(os); -} - - -std::ostream& HLoadContextSlot::PrintDataTo(std::ostream& os) const { // NOLINT - return os << NameOf(value()) << "[" << slot_index() << "]"; -} - - -std::ostream& HStoreContextSlot::PrintDataTo( - std::ostream& os) const { // NOLINT - return os << NameOf(context()) << "[" << slot_index() - << "] = " << NameOf(value()); -} - - -// Implementation of type inference and type conversions. Calculates -// the inferred type of this instruction based on the input operands. - -HType HValue::CalculateInferredType() { - return type_; -} - - -HType HPhi::CalculateInferredType() { - if (OperandCount() == 0) return HType::Tagged(); - HType result = OperandAt(0)->type(); - for (int i = 1; i < OperandCount(); ++i) { - HType current = OperandAt(i)->type(); - result = result.Combine(current); - } - return result; -} - - -HType HChange::CalculateInferredType() { - if (from().IsDouble() && to().IsTagged()) return HType::HeapNumber(); - return type(); -} - - -Representation HUnaryMathOperation::RepresentationFromInputs() { - if (SupportsFlexibleFloorAndRound() && - (op_ == kMathFloor || op_ == kMathRound)) { - // Floor and Round always take a double input. The integral result can be - // used as an integer or a double. Infer the representation from the uses. - return Representation::None(); - } - Representation rep = representation(); - // If any of the actual input representation is more general than what we - // have so far but not Tagged, use that representation instead. - Representation input_rep = value()->representation(); - if (!input_rep.IsTagged()) { - rep = rep.generalize(input_rep); - } - return rep; -} - - -bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect, - HValue* dominator) { - DCHECK(side_effect == kNewSpacePromotion); - DCHECK(!IsAllocationFolded()); - Zone* zone = block()->zone(); - Isolate* isolate = block()->isolate(); - if (!FLAG_use_allocation_folding) return false; - - // Try to fold allocations together with their dominating allocations. - if (!dominator->IsAllocate()) { - if (FLAG_trace_allocation_folding) { - PrintF("#%d (%s) cannot fold into #%d (%s)\n", - id(), Mnemonic(), dominator->id(), dominator->Mnemonic()); - } - return false; - } - - // Check whether we are folding within the same block for local folding. - if (FLAG_use_local_allocation_folding && dominator->block() != block()) { - if (FLAG_trace_allocation_folding) { - PrintF("#%d (%s) cannot fold into #%d (%s), crosses basic blocks\n", - id(), Mnemonic(), dominator->id(), dominator->Mnemonic()); - } - return false; - } - - HAllocate* dominator_allocate = HAllocate::cast(dominator); - HValue* dominator_size = dominator_allocate->size(); - HValue* current_size = size(); - - // TODO(hpayer): Add support for non-constant allocation in dominator. - if (!current_size->IsInteger32Constant() || - !dominator_size->IsInteger32Constant()) { - if (FLAG_trace_allocation_folding) { - PrintF("#%d (%s) cannot fold into #%d (%s), " - "dynamic allocation size in dominator\n", - id(), Mnemonic(), dominator->id(), dominator->Mnemonic()); - } - return false; - } - - if (IsAllocationFoldingDominator()) { - if (FLAG_trace_allocation_folding) { - PrintF("#%d (%s) cannot fold into #%d (%s), already dominator\n", id(), - Mnemonic(), dominator->id(), dominator->Mnemonic()); - } - return false; - } - - if (!IsFoldable(dominator_allocate)) { - if (FLAG_trace_allocation_folding) { - PrintF("#%d (%s) cannot fold into #%d (%s), different spaces\n", id(), - Mnemonic(), dominator->id(), dominator->Mnemonic()); - } - return false; - } - - DCHECK( - (IsNewSpaceAllocation() && dominator_allocate->IsNewSpaceAllocation()) || - (IsOldSpaceAllocation() && dominator_allocate->IsOldSpaceAllocation())); - - // First update the size of the dominator allocate instruction. - dominator_size = dominator_allocate->size(); - int32_t original_object_size = - HConstant::cast(dominator_size)->GetInteger32Constant(); - int32_t dominator_size_constant = original_object_size; - - if (MustAllocateDoubleAligned()) { - if ((dominator_size_constant & kDoubleAlignmentMask) != 0) { - dominator_size_constant += kDoubleSize / 2; - } - } - - int32_t current_size_max_value = size()->GetInteger32Constant(); - int32_t new_dominator_size = dominator_size_constant + current_size_max_value; - - // Since we clear the first word after folded memory, we cannot use the - // whole kMaxRegularHeapObjectSize memory. - if (new_dominator_size > kMaxRegularHeapObjectSize - kPointerSize) { - if (FLAG_trace_allocation_folding) { - PrintF("#%d (%s) cannot fold into #%d (%s) due to size: %d\n", - id(), Mnemonic(), dominator_allocate->id(), - dominator_allocate->Mnemonic(), new_dominator_size); - } - return false; - } - - HInstruction* new_dominator_size_value = HConstant::CreateAndInsertBefore( - isolate, zone, context(), new_dominator_size, Representation::None(), - dominator_allocate); - - dominator_allocate->UpdateSize(new_dominator_size_value); - - if (MustAllocateDoubleAligned()) { - if (!dominator_allocate->MustAllocateDoubleAligned()) { - dominator_allocate->MakeDoubleAligned(); - } - } - - if (!dominator_allocate->IsAllocationFoldingDominator()) { - HAllocate* first_alloc = - HAllocate::New(isolate, zone, dominator_allocate->context(), - dominator_size, dominator_allocate->type(), - IsNewSpaceAllocation() ? NOT_TENURED : TENURED, - JS_OBJECT_TYPE, block()->graph()->GetConstant0()); - first_alloc->InsertAfter(dominator_allocate); - dominator_allocate->ReplaceAllUsesWith(first_alloc); - dominator_allocate->MakeAllocationFoldingDominator(); - first_alloc->MakeFoldedAllocation(dominator_allocate); - if (FLAG_trace_allocation_folding) { - PrintF("#%d (%s) inserted for dominator #%d (%s)\n", first_alloc->id(), - first_alloc->Mnemonic(), dominator_allocate->id(), - dominator_allocate->Mnemonic()); - } - } - - MakeFoldedAllocation(dominator_allocate); - - if (FLAG_trace_allocation_folding) { - PrintF("#%d (%s) folded into #%d (%s), new dominator size: %d\n", id(), - Mnemonic(), dominator_allocate->id(), dominator_allocate->Mnemonic(), - new_dominator_size); - } - return true; -} - - -std::ostream& HAllocate::PrintDataTo(std::ostream& os) const { // NOLINT - os << NameOf(size()) << " ("; - if (IsNewSpaceAllocation()) os << "N"; - if (IsOldSpaceAllocation()) os << "P"; - if (MustAllocateDoubleAligned()) os << "A"; - if (MustPrefillWithFiller()) os << "F"; - if (IsAllocationFoldingDominator()) os << "d"; - if (IsAllocationFolded()) os << "f"; - return os << ")"; -} - - -bool HStoreKeyed::TryIncreaseBaseOffset(uint32_t increase_by_value) { - // The base offset is usually simply the size of the array header, except - // with dehoisting adds an addition offset due to a array index key - // manipulation, in which case it becomes (array header size + - // constant-offset-from-key * kPointerSize) - v8::base::internal::CheckedNumeric<uint32_t> addition_result = base_offset_; - addition_result += increase_by_value; - if (!addition_result.IsValid()) return false; - base_offset_ = addition_result.ValueOrDie(); - return true; -} - - -bool HStoreKeyed::NeedsCanonicalization() { - switch (value()->opcode()) { - case kLoadKeyed: { - ElementsKind load_kind = HLoadKeyed::cast(value())->elements_kind(); - return IsFixedFloatElementsKind(load_kind); - } - case kChange: { - Representation from = HChange::cast(value())->from(); - return from.IsTagged() || from.IsHeapObject(); - } - case kConstant: - // Double constants are canonicalized upon construction. - return false; - default: - return !value()->IsBinaryOperation(); - } -} - - -#define H_CONSTANT_INT(val) \ - HConstant::New(isolate, zone, context, static_cast<int32_t>(val)) -#define H_CONSTANT_DOUBLE(val) \ - HConstant::New(isolate, zone, context, static_cast<double>(val)) - -#define DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HInstr, op) \ - HInstruction* HInstr::New(Isolate* isolate, Zone* zone, HValue* context, \ - HValue* left, HValue* right) { \ - if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { \ - HConstant* c_left = HConstant::cast(left); \ - HConstant* c_right = HConstant::cast(right); \ - if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \ - double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \ - if (IsInt32Double(double_res)) { \ - return H_CONSTANT_INT(double_res); \ - } \ - return H_CONSTANT_DOUBLE(double_res); \ - } \ - } \ - return new (zone) HInstr(context, left, right); \ - } - -DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HAdd, +) -DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HMul, *) -DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HSub, -) - -#undef DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR - - -HInstruction* HStringAdd::New(Isolate* isolate, Zone* zone, HValue* context, - HValue* left, HValue* right, - PretenureFlag pretenure_flag, - StringAddFlags flags, - Handle<AllocationSite> allocation_site) { - if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { - HConstant* c_right = HConstant::cast(right); - HConstant* c_left = HConstant::cast(left); - if (c_left->HasStringValue() && c_right->HasStringValue()) { - Handle<String> left_string = c_left->StringValue(); - Handle<String> right_string = c_right->StringValue(); - // Prevent possible exception by invalid string length. - if (left_string->length() + right_string->length() < String::kMaxLength) { - MaybeHandle<String> concat = isolate->factory()->NewConsString( - c_left->StringValue(), c_right->StringValue()); - return HConstant::New(isolate, zone, context, concat.ToHandleChecked()); - } - } - } - return new (zone) - HStringAdd(context, left, right, pretenure_flag, flags, allocation_site); -} - - -std::ostream& HStringAdd::PrintDataTo(std::ostream& os) const { // NOLINT - if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { - os << "_CheckBoth"; - } else if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_LEFT) { - os << "_CheckLeft"; - } else if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_RIGHT) { - os << "_CheckRight"; - } - HBinaryOperation::PrintDataTo(os); - os << " ("; - if (pretenure_flag() == NOT_TENURED) - os << "N"; - else if (pretenure_flag() == TENURED) - os << "D"; - return os << ")"; -} - - -HInstruction* HStringCharFromCode::New(Isolate* isolate, Zone* zone, - HValue* context, HValue* char_code) { - if (FLAG_fold_constants && char_code->IsConstant()) { - HConstant* c_code = HConstant::cast(char_code); - if (c_code->HasNumberValue()) { - if (std::isfinite(c_code->DoubleValue())) { - uint32_t code = c_code->NumberValueAsInteger32() & 0xffff; - return HConstant::New( - isolate, zone, context, - isolate->factory()->LookupSingleCharacterStringFromCode(code)); - } - return HConstant::New(isolate, zone, context, - isolate->factory()->empty_string()); - } - } - return new(zone) HStringCharFromCode(context, char_code); -} - - -HInstruction* HUnaryMathOperation::New(Isolate* isolate, Zone* zone, - HValue* context, HValue* value, - BuiltinFunctionId op) { - do { - if (!FLAG_fold_constants) break; - if (!value->IsConstant()) break; - HConstant* constant = HConstant::cast(value); - if (!constant->HasNumberValue()) break; - double d = constant->DoubleValue(); - if (std::isnan(d)) { // NaN poisons everything. - return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN()); - } - if (std::isinf(d)) { // +Infinity and -Infinity. - switch (op) { - case kMathCos: - case kMathSin: - return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN()); - case kMathExp: - return H_CONSTANT_DOUBLE((d > 0.0) ? d : 0.0); - case kMathLog: - case kMathSqrt: - return H_CONSTANT_DOUBLE( - (d > 0.0) ? d : std::numeric_limits<double>::quiet_NaN()); - case kMathPowHalf: - case kMathAbs: - return H_CONSTANT_DOUBLE((d > 0.0) ? d : -d); - case kMathRound: - case kMathFround: - case kMathFloor: - return H_CONSTANT_DOUBLE(d); - case kMathClz32: - return H_CONSTANT_INT(32); - default: - UNREACHABLE(); - break; - } - } - switch (op) { - case kMathCos: - return H_CONSTANT_DOUBLE(base::ieee754::cos(d)); - case kMathExp: - return H_CONSTANT_DOUBLE(base::ieee754::exp(d)); - case kMathLog: - return H_CONSTANT_DOUBLE(base::ieee754::log(d)); - case kMathSin: - return H_CONSTANT_DOUBLE(base::ieee754::sin(d)); - case kMathSqrt: - lazily_initialize_fast_sqrt(isolate); - return H_CONSTANT_DOUBLE(fast_sqrt(d, isolate)); - case kMathPowHalf: - return H_CONSTANT_DOUBLE(power_double_double(d, 0.5)); - case kMathAbs: - return H_CONSTANT_DOUBLE((d >= 0.0) ? d + 0.0 : -d); - case kMathRound: - // -0.5 .. -0.0 round to -0.0. - if ((d >= -0.5 && Double(d).Sign() < 0)) return H_CONSTANT_DOUBLE(-0.0); - // Doubles are represented as Significant * 2 ^ Exponent. If the - // Exponent is not negative, the double value is already an integer. - if (Double(d).Exponent() >= 0) return H_CONSTANT_DOUBLE(d); - return H_CONSTANT_DOUBLE(Floor(d + 0.5)); - case kMathFround: - return H_CONSTANT_DOUBLE(static_cast<double>(static_cast<float>(d))); - case kMathFloor: - return H_CONSTANT_DOUBLE(Floor(d)); - case kMathClz32: { - uint32_t i = DoubleToUint32(d); - return H_CONSTANT_INT(base::bits::CountLeadingZeros32(i)); - } - default: - UNREACHABLE(); - break; - } - } while (false); - return new(zone) HUnaryMathOperation(context, value, op); -} - - -Representation HUnaryMathOperation::RepresentationFromUses() { - if (op_ != kMathFloor && op_ != kMathRound) { - return HValue::RepresentationFromUses(); - } - - // The instruction can have an int32 or double output. Prefer a double - // representation if there are double uses. - bool use_double = false; - - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - HValue* use = it.value(); - int use_index = it.index(); - Representation rep_observed = use->observed_input_representation(use_index); - Representation rep_required = use->RequiredInputRepresentation(use_index); - use_double |= (rep_observed.IsDouble() || rep_required.IsDouble()); - if (use_double && !FLAG_trace_representation) { - // Having seen one double is enough. - break; - } - if (FLAG_trace_representation) { - if (!rep_required.IsDouble() || rep_observed.IsDouble()) { - PrintF("#%d %s is used by #%d %s as %s%s\n", - id(), Mnemonic(), use->id(), - use->Mnemonic(), rep_observed.Mnemonic(), - (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : "")); - } else { - PrintF("#%d %s is required by #%d %s as %s%s\n", - id(), Mnemonic(), use->id(), - use->Mnemonic(), rep_required.Mnemonic(), - (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : "")); - } - } - } - return use_double ? Representation::Double() : Representation::Integer32(); -} - - -HInstruction* HPower::New(Isolate* isolate, Zone* zone, HValue* context, - HValue* left, HValue* right) { - if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { - HConstant* c_left = HConstant::cast(left); - HConstant* c_right = HConstant::cast(right); - if (c_left->HasNumberValue() && c_right->HasNumberValue()) { - double result = - power_helper(isolate, c_left->DoubleValue(), c_right->DoubleValue()); - return H_CONSTANT_DOUBLE(std::isnan(result) - ? std::numeric_limits<double>::quiet_NaN() - : result); - } - } - return new(zone) HPower(left, right); -} - - -HInstruction* HMathMinMax::New(Isolate* isolate, Zone* zone, HValue* context, - HValue* left, HValue* right, Operation op) { - if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { - HConstant* c_left = HConstant::cast(left); - HConstant* c_right = HConstant::cast(right); - if (c_left->HasNumberValue() && c_right->HasNumberValue()) { - double d_left = c_left->DoubleValue(); - double d_right = c_right->DoubleValue(); - if (op == kMathMin) { - if (d_left > d_right) return H_CONSTANT_DOUBLE(d_right); - if (d_left < d_right) return H_CONSTANT_DOUBLE(d_left); - if (d_left == d_right) { - // Handle +0 and -0. - return H_CONSTANT_DOUBLE((Double(d_left).Sign() == -1) ? d_left - : d_right); - } - } else { - if (d_left < d_right) return H_CONSTANT_DOUBLE(d_right); - if (d_left > d_right) return H_CONSTANT_DOUBLE(d_left); - if (d_left == d_right) { - // Handle +0 and -0. - return H_CONSTANT_DOUBLE((Double(d_left).Sign() == -1) ? d_right - : d_left); - } - } - // All comparisons failed, must be NaN. - return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN()); - } - } - return new(zone) HMathMinMax(context, left, right, op); -} - -HInstruction* HMod::New(Isolate* isolate, Zone* zone, HValue* context, - HValue* left, HValue* right) { - if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { - HConstant* c_left = HConstant::cast(left); - HConstant* c_right = HConstant::cast(right); - if (c_left->HasInteger32Value() && c_right->HasInteger32Value()) { - int32_t dividend = c_left->Integer32Value(); - int32_t divisor = c_right->Integer32Value(); - if (dividend == kMinInt && divisor == -1) { - return H_CONSTANT_DOUBLE(-0.0); - } - if (divisor != 0) { - int32_t res = dividend % divisor; - if ((res == 0) && (dividend < 0)) { - return H_CONSTANT_DOUBLE(-0.0); - } - return H_CONSTANT_INT(res); - } - } - } - return new (zone) HMod(context, left, right); -} - -HInstruction* HDiv::New(Isolate* isolate, Zone* zone, HValue* context, - HValue* left, HValue* right) { - // If left and right are constant values, try to return a constant value. - if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { - HConstant* c_left = HConstant::cast(left); - HConstant* c_right = HConstant::cast(right); - if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { - if (std::isnan(c_left->DoubleValue()) || - std::isnan(c_right->DoubleValue())) { - return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN()); - } else if (c_right->DoubleValue() != 0) { - double double_res = c_left->DoubleValue() / c_right->DoubleValue(); - if (IsInt32Double(double_res)) { - return H_CONSTANT_INT(double_res); - } - return H_CONSTANT_DOUBLE(double_res); - } else if (c_left->DoubleValue() != 0) { - int sign = Double(c_left->DoubleValue()).Sign() * - Double(c_right->DoubleValue()).Sign(); // Right could be -0. - return H_CONSTANT_DOUBLE(sign * V8_INFINITY); - } else { - return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN()); - } - } - } - return new (zone) HDiv(context, left, right); -} - -HInstruction* HBitwise::New(Isolate* isolate, Zone* zone, HValue* context, - Token::Value op, HValue* left, HValue* right) { - if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { - HConstant* c_left = HConstant::cast(left); - HConstant* c_right = HConstant::cast(right); - if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { - int32_t result; - int32_t v_left = c_left->NumberValueAsInteger32(); - int32_t v_right = c_right->NumberValueAsInteger32(); - switch (op) { - case Token::BIT_XOR: - result = v_left ^ v_right; - break; - case Token::BIT_AND: - result = v_left & v_right; - break; - case Token::BIT_OR: - result = v_left | v_right; - break; - default: - result = 0; // Please the compiler. - UNREACHABLE(); - } - return H_CONSTANT_INT(result); - } - } - return new (zone) HBitwise(context, op, left, right); -} - -#define DEFINE_NEW_H_BITWISE_INSTR(HInstr, result) \ - HInstruction* HInstr::New(Isolate* isolate, Zone* zone, HValue* context, \ - HValue* left, HValue* right) { \ - if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { \ - HConstant* c_left = HConstant::cast(left); \ - HConstant* c_right = HConstant::cast(right); \ - if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \ - return H_CONSTANT_INT(result); \ - } \ - } \ - return new (zone) HInstr(context, left, right); \ - } - -DEFINE_NEW_H_BITWISE_INSTR(HSar, -c_left->NumberValueAsInteger32() >> (c_right->NumberValueAsInteger32() & 0x1f)) -DEFINE_NEW_H_BITWISE_INSTR(HShl, -c_left->NumberValueAsInteger32() << (c_right->NumberValueAsInteger32() & 0x1f)) - -#undef DEFINE_NEW_H_BITWISE_INSTR - -HInstruction* HShr::New(Isolate* isolate, Zone* zone, HValue* context, - HValue* left, HValue* right) { - if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { - HConstant* c_left = HConstant::cast(left); - HConstant* c_right = HConstant::cast(right); - if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { - int32_t left_val = c_left->NumberValueAsInteger32(); - int32_t right_val = c_right->NumberValueAsInteger32() & 0x1f; - if ((right_val == 0) && (left_val < 0)) { - return H_CONSTANT_DOUBLE(static_cast<uint32_t>(left_val)); - } - return H_CONSTANT_INT(static_cast<uint32_t>(left_val) >> right_val); - } - } - return new (zone) HShr(context, left, right); -} - - -HInstruction* HSeqStringGetChar::New(Isolate* isolate, Zone* zone, - HValue* context, String::Encoding encoding, - HValue* string, HValue* index) { - if (FLAG_fold_constants && string->IsConstant() && index->IsConstant()) { - HConstant* c_string = HConstant::cast(string); - HConstant* c_index = HConstant::cast(index); - if (c_string->HasStringValue() && c_index->HasInteger32Value()) { - Handle<String> s = c_string->StringValue(); - int32_t i = c_index->Integer32Value(); - DCHECK_LE(0, i); - DCHECK_LT(i, s->length()); - return H_CONSTANT_INT(s->Get(i)); - } - } - return new(zone) HSeqStringGetChar(encoding, string, index); -} - - -#undef H_CONSTANT_INT -#undef H_CONSTANT_DOUBLE - - -std::ostream& HBitwise::PrintDataTo(std::ostream& os) const { // NOLINT - os << Token::Name(op_) << " "; - return HBitwiseBinaryOperation::PrintDataTo(os); -} - - -void HPhi::SimplifyConstantInputs() { - // Convert constant inputs to integers when all uses are truncating. - // This must happen before representation inference takes place. - if (!CheckUsesForFlag(kTruncatingToInt32)) return; - for (int i = 0; i < OperandCount(); ++i) { - if (!OperandAt(i)->IsConstant()) return; - } - HGraph* graph = block()->graph(); - for (int i = 0; i < OperandCount(); ++i) { - HConstant* operand = HConstant::cast(OperandAt(i)); - if (operand->HasInteger32Value()) { - continue; - } else if (operand->HasDoubleValue()) { - HConstant* integer_input = HConstant::New( - graph->isolate(), graph->zone(), graph->GetInvalidContext(), - DoubleToInt32(operand->DoubleValue())); - integer_input->InsertAfter(operand); - SetOperandAt(i, integer_input); - } else if (operand->HasBooleanValue()) { - SetOperandAt(i, operand->BooleanValue() ? graph->GetConstant1() - : graph->GetConstant0()); - } else if (operand->ImmortalImmovable()) { - SetOperandAt(i, graph->GetConstant0()); - } - } - // Overwrite observed input representations because they are likely Tagged. - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - HValue* use = it.value(); - if (use->IsBinaryOperation()) { - HBinaryOperation::cast(use)->set_observed_input_representation( - it.index(), Representation::Smi()); - } - } -} - - -void HPhi::InferRepresentation(HInferRepresentationPhase* h_infer) { - DCHECK(CheckFlag(kFlexibleRepresentation)); - Representation new_rep = RepresentationFromUses(); - UpdateRepresentation(new_rep, h_infer, "uses"); - new_rep = RepresentationFromInputs(); - UpdateRepresentation(new_rep, h_infer, "inputs"); - new_rep = RepresentationFromUseRequirements(); - UpdateRepresentation(new_rep, h_infer, "use requirements"); -} - - -Representation HPhi::RepresentationFromInputs() { - Representation r = representation(); - for (int i = 0; i < OperandCount(); ++i) { - // Ignore conservative Tagged assumption of parameters if we have - // reason to believe that it's too conservative. - if (has_type_feedback_from_uses() && OperandAt(i)->IsParameter()) { - continue; - } - - r = r.generalize(OperandAt(i)->KnownOptimalRepresentation()); - } - return r; -} - - -// Returns a representation if all uses agree on the same representation. -// Integer32 is also returned when some uses are Smi but others are Integer32. -Representation HValue::RepresentationFromUseRequirements() { - Representation rep = Representation::None(); - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - // Ignore the use requirement from never run code - if (it.value()->block()->IsUnreachable()) continue; - - // We check for observed_input_representation elsewhere. - Representation use_rep = - it.value()->RequiredInputRepresentation(it.index()); - if (rep.IsNone()) { - rep = use_rep; - continue; - } - if (use_rep.IsNone() || rep.Equals(use_rep)) continue; - if (rep.generalize(use_rep).IsInteger32()) { - rep = Representation::Integer32(); - continue; - } - return Representation::None(); - } - return rep; -} - - -bool HValue::HasNonSmiUse() { - for (HUseIterator it(uses()); !it.Done(); it.Advance()) { - // We check for observed_input_representation elsewhere. - Representation use_rep = - it.value()->RequiredInputRepresentation(it.index()); - if (!use_rep.IsNone() && - !use_rep.IsSmi() && - !use_rep.IsTagged()) { - return true; - } - } - return false; -} - - -// Node-specific verification code is only included in debug mode. -#ifdef DEBUG - -void HPhi::Verify() { - DCHECK(OperandCount() == block()->predecessors()->length()); - for (int i = 0; i < OperandCount(); ++i) { - HValue* value = OperandAt(i); - HBasicBlock* defining_block = value->block(); - HBasicBlock* predecessor_block = block()->predecessors()->at(i); - DCHECK(defining_block == predecessor_block || - defining_block->Dominates(predecessor_block)); - } -} - - -void HSimulate::Verify() { - HInstruction::Verify(); - DCHECK(HasAstId() || next()->IsEnterInlined()); -} - - -void HCheckHeapObject::Verify() { - HInstruction::Verify(); - DCHECK(HasNoUses()); -} - - -void HCheckValue::Verify() { - HInstruction::Verify(); - DCHECK(HasNoUses()); -} - -#endif - - -HObjectAccess HObjectAccess::ForFixedArrayHeader(int offset) { - DCHECK(offset >= 0); - DCHECK(offset < FixedArray::kHeaderSize); - if (offset == FixedArray::kLengthOffset) return ForFixedArrayLength(); - return HObjectAccess(kInobject, offset); -} - - -HObjectAccess HObjectAccess::ForMapAndOffset(Handle<Map> map, int offset, - Representation representation) { - DCHECK(offset >= 0); - Portion portion = kInobject; - - if (offset == JSObject::kElementsOffset) { - portion = kElementsPointer; - } else if (offset == JSObject::kMapOffset) { - portion = kMaps; - } - bool existing_inobject_property = true; - if (!map.is_null()) { - existing_inobject_property = (offset < - map->instance_size() - map->unused_property_fields() * kPointerSize); - } - return HObjectAccess(portion, offset, representation, Handle<String>::null(), - false, existing_inobject_property); -} - - -HObjectAccess HObjectAccess::ForAllocationSiteOffset(int offset) { - switch (offset) { - case AllocationSite::kTransitionInfoOffset: - return HObjectAccess(kInobject, offset, Representation::Tagged()); - case AllocationSite::kNestedSiteOffset: - return HObjectAccess(kInobject, offset, Representation::Tagged()); - case AllocationSite::kPretenureDataOffset: - return HObjectAccess(kInobject, offset, Representation::Smi()); - case AllocationSite::kPretenureCreateCountOffset: - return HObjectAccess(kInobject, offset, Representation::Smi()); - case AllocationSite::kDependentCodeOffset: - return HObjectAccess(kInobject, offset, Representation::Tagged()); - case AllocationSite::kWeakNextOffset: - return HObjectAccess(kInobject, offset, Representation::Tagged()); - default: - UNREACHABLE(); - } - return HObjectAccess(kInobject, offset); -} - - -HObjectAccess HObjectAccess::ForContextSlot(int index) { - DCHECK(index >= 0); - Portion portion = kInobject; - int offset = Context::kHeaderSize + index * kPointerSize; - DCHECK_EQ(offset, Context::SlotOffset(index) + kHeapObjectTag); - return HObjectAccess(portion, offset, Representation::Tagged()); -} - - -HObjectAccess HObjectAccess::ForScriptContext(int index) { - DCHECK(index >= 0); - Portion portion = kInobject; - int offset = ScriptContextTable::GetContextOffset(index); - return HObjectAccess(portion, offset, Representation::Tagged()); -} - - -HObjectAccess HObjectAccess::ForJSArrayOffset(int offset) { - DCHECK(offset >= 0); - Portion portion = kInobject; - - if (offset == JSObject::kElementsOffset) { - portion = kElementsPointer; - } else if (offset == JSArray::kLengthOffset) { - portion = kArrayLengths; - } else if (offset == JSObject::kMapOffset) { - portion = kMaps; - } - return HObjectAccess(portion, offset); -} - - -HObjectAccess HObjectAccess::ForBackingStoreOffset(int offset, - Representation representation) { - DCHECK(offset >= 0); - return HObjectAccess(kBackingStore, offset, representation, - Handle<String>::null(), false, false); -} - - -HObjectAccess HObjectAccess::ForField(Handle<Map> map, int index, - Representation representation, - Handle<Name> name) { - if (index < 0) { - // Negative property indices are in-object properties, indexed - // from the end of the fixed part of the object. - int offset = (index * kPointerSize) + map->instance_size(); - return HObjectAccess(kInobject, offset, representation, name, false, true); - } else { - // Non-negative property indices are in the properties array. - int offset = (index * kPointerSize) + FixedArray::kHeaderSize; - return HObjectAccess(kBackingStore, offset, representation, name, - false, false); - } -} - - -void HObjectAccess::SetGVNFlags(HValue *instr, PropertyAccessType access_type) { - // set the appropriate GVN flags for a given load or store instruction - if (access_type == STORE) { - // track dominating allocations in order to eliminate write barriers - instr->SetDependsOnFlag(::v8::internal::kNewSpacePromotion); - instr->SetFlag(HValue::kTrackSideEffectDominators); - } else { - // try to GVN loads, but don't hoist above map changes - instr->SetFlag(HValue::kUseGVN); - instr->SetDependsOnFlag(::v8::internal::kMaps); - } - - switch (portion()) { - case kArrayLengths: - if (access_type == STORE) { - instr->SetChangesFlag(::v8::internal::kArrayLengths); - } else { - instr->SetDependsOnFlag(::v8::internal::kArrayLengths); - } - break; - case kStringLengths: - if (access_type == STORE) { - instr->SetChangesFlag(::v8::internal::kStringLengths); - } else { - instr->SetDependsOnFlag(::v8::internal::kStringLengths); - } - break; - case kInobject: - if (access_type == STORE) { - instr->SetChangesFlag(::v8::internal::kInobjectFields); - } else { - instr->SetDependsOnFlag(::v8::internal::kInobjectFields); - } - break; - case kDouble: - if (access_type == STORE) { - instr->SetChangesFlag(::v8::internal::kDoubleFields); - } else { - instr->SetDependsOnFlag(::v8::internal::kDoubleFields); - } - break; - case kBackingStore: - if (access_type == STORE) { - instr->SetChangesFlag(::v8::internal::kBackingStoreFields); - } else { - instr->SetDependsOnFlag(::v8::internal::kBackingStoreFields); - } - break; - case kElementsPointer: - if (access_type == STORE) { - instr->SetChangesFlag(::v8::internal::kElementsPointer); - } else { - instr->SetDependsOnFlag(::v8::internal::kElementsPointer); - } - break; - case kMaps: - if (access_type == STORE) { - instr->SetChangesFlag(::v8::internal::kMaps); - } else { - instr->SetDependsOnFlag(::v8::internal::kMaps); - } - break; - case kExternalMemory: - if (access_type == STORE) { - instr->SetChangesFlag(::v8::internal::kExternalMemory); - } else { - instr->SetDependsOnFlag(::v8::internal::kExternalMemory); - } - break; - } -} - - -std::ostream& operator<<(std::ostream& os, const HObjectAccess& access) { - os << "."; - - switch (access.portion()) { - case HObjectAccess::kArrayLengths: - case HObjectAccess::kStringLengths: - os << "%length"; - break; - case HObjectAccess::kElementsPointer: - os << "%elements"; - break; - case HObjectAccess::kMaps: - os << "%map"; - break; - case HObjectAccess::kDouble: // fall through - case HObjectAccess::kInobject: - if (!access.name().is_null() && access.name()->IsString()) { - os << Handle<String>::cast(access.name())->ToCString().get(); - } - os << "[in-object]"; - break; - case HObjectAccess::kBackingStore: - if (!access.name().is_null() && access.name()->IsString()) { - os << Handle<String>::cast(access.name())->ToCString().get(); - } - os << "[backing-store]"; - break; - case HObjectAccess::kExternalMemory: - os << "[external-memory]"; - break; - } - - return os << "@" << access.offset(); -} - -} // namespace internal -} // namespace v8 |