Index: src/hydrogen-instructions.h |
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h |
deleted file mode 100644 |
index f7acbb5292c804eb19f47f10a58d99e723e54803..0000000000000000000000000000000000000000 |
--- a/src/hydrogen-instructions.h |
+++ /dev/null |
@@ -1,7982 +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. |
- |
-#ifndef V8_HYDROGEN_INSTRUCTIONS_H_ |
-#define V8_HYDROGEN_INSTRUCTIONS_H_ |
- |
-#include <cstring> |
-#include <iosfwd> |
- |
-#include "src/allocation.h" |
-#include "src/base/bits.h" |
-#include "src/bit-vector.h" |
-#include "src/code-stubs.h" |
-#include "src/conversions.h" |
-#include "src/deoptimizer.h" |
-#include "src/hydrogen-types.h" |
-#include "src/small-pointer-list.h" |
-#include "src/unique.h" |
-#include "src/utils.h" |
-#include "src/zone.h" |
- |
-namespace v8 { |
-namespace internal { |
- |
-// Forward declarations. |
-struct ChangesOf; |
-class HBasicBlock; |
-class HDiv; |
-class HEnvironment; |
-class HInferRepresentationPhase; |
-class HInstruction; |
-class HLoopInformation; |
-class HStoreNamedField; |
-class HValue; |
-class LInstruction; |
-class LChunkBuilder; |
- |
-#define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \ |
- V(ArithmeticBinaryOperation) \ |
- V(BinaryOperation) \ |
- V(BitwiseBinaryOperation) \ |
- V(ControlInstruction) \ |
- V(Instruction) |
- |
- |
-#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \ |
- V(AbnormalExit) \ |
- V(AccessArgumentsAt) \ |
- V(Add) \ |
- V(AllocateBlockContext) \ |
- V(Allocate) \ |
- V(ApplyArguments) \ |
- V(ArgumentsElements) \ |
- V(ArgumentsLength) \ |
- V(ArgumentsObject) \ |
- V(Bitwise) \ |
- V(BlockEntry) \ |
- V(BoundsCheck) \ |
- V(BoundsCheckBaseIndexInformation) \ |
- V(Branch) \ |
- V(CallWithDescriptor) \ |
- V(CallJSFunction) \ |
- V(CallFunction) \ |
- V(CallNew) \ |
- V(CallNewArray) \ |
- V(CallRuntime) \ |
- V(CallStub) \ |
- V(CapturedObject) \ |
- V(Change) \ |
- V(CheckArrayBufferNotNeutered) \ |
- V(CheckHeapObject) \ |
- V(CheckInstanceType) \ |
- V(CheckMaps) \ |
- V(CheckMapValue) \ |
- V(CheckSmi) \ |
- V(CheckValue) \ |
- V(ClampToUint8) \ |
- V(ClassOfTestAndBranch) \ |
- V(CompareNumericAndBranch) \ |
- V(CompareHoleAndBranch) \ |
- V(CompareGeneric) \ |
- V(CompareMinusZeroAndBranch) \ |
- V(CompareObjectEqAndBranch) \ |
- V(CompareMap) \ |
- V(Constant) \ |
- V(ConstructDouble) \ |
- V(Context) \ |
- V(DateField) \ |
- V(DebugBreak) \ |
- V(DeclareGlobals) \ |
- V(Deoptimize) \ |
- V(Div) \ |
- V(DoubleBits) \ |
- V(DummyUse) \ |
- V(EnterInlined) \ |
- V(EnvironmentMarker) \ |
- V(ForceRepresentation) \ |
- V(ForInCacheArray) \ |
- V(ForInPrepareMap) \ |
- V(GetCachedArrayIndex) \ |
- V(Goto) \ |
- V(HasCachedArrayIndexAndBranch) \ |
- V(HasInstanceTypeAndBranch) \ |
- V(InnerAllocatedObject) \ |
- V(InstanceOf) \ |
- V(InvokeFunction) \ |
- V(IsConstructCallAndBranch) \ |
- V(HasInPrototypeChainAndBranch) \ |
- V(IsStringAndBranch) \ |
- V(IsSmiAndBranch) \ |
- V(IsUndetectableAndBranch) \ |
- V(LeaveInlined) \ |
- V(LoadContextSlot) \ |
- V(LoadFieldByIndex) \ |
- V(LoadFunctionPrototype) \ |
- V(LoadGlobalGeneric) \ |
- V(LoadGlobalViaContext) \ |
- V(LoadKeyed) \ |
- V(LoadKeyedGeneric) \ |
- V(LoadNamedField) \ |
- V(LoadNamedGeneric) \ |
- V(LoadRoot) \ |
- V(MapEnumLength) \ |
- V(MathFloorOfDiv) \ |
- V(MathMinMax) \ |
- V(MaybeGrowElements) \ |
- V(Mod) \ |
- V(Mul) \ |
- V(OsrEntry) \ |
- V(Parameter) \ |
- V(Power) \ |
- V(Prologue) \ |
- V(PushArguments) \ |
- V(RegExpLiteral) \ |
- V(Return) \ |
- V(Ror) \ |
- V(Sar) \ |
- V(SeqStringGetChar) \ |
- V(SeqStringSetChar) \ |
- V(Shl) \ |
- V(Shr) \ |
- V(Simulate) \ |
- V(StackCheck) \ |
- V(StoreCodeEntry) \ |
- V(StoreContextSlot) \ |
- V(StoreFrameContext) \ |
- V(StoreGlobalViaContext) \ |
- V(StoreKeyed) \ |
- V(StoreKeyedGeneric) \ |
- V(StoreNamedField) \ |
- V(StoreNamedGeneric) \ |
- V(StringAdd) \ |
- V(StringCharCodeAt) \ |
- V(StringCharFromCode) \ |
- V(StringCompareAndBranch) \ |
- V(Sub) \ |
- V(ThisFunction) \ |
- V(ToFastProperties) \ |
- V(TransitionElementsKind) \ |
- V(TrapAllocationMemento) \ |
- V(Typeof) \ |
- V(TypeofIsAndBranch) \ |
- V(UnaryMathOperation) \ |
- V(UnknownOSRValue) \ |
- V(UseConst) \ |
- V(WrapReceiver) |
- |
-#define GVN_TRACKED_FLAG_LIST(V) \ |
- V(NewSpacePromotion) |
- |
-#define GVN_UNTRACKED_FLAG_LIST(V) \ |
- V(ArrayElements) \ |
- V(ArrayLengths) \ |
- V(StringLengths) \ |
- V(BackingStoreFields) \ |
- V(Calls) \ |
- V(ContextSlots) \ |
- V(DoubleArrayElements) \ |
- V(DoubleFields) \ |
- V(ElementsKind) \ |
- V(ElementsPointer) \ |
- V(GlobalVars) \ |
- V(InobjectFields) \ |
- V(Maps) \ |
- V(OsrEntries) \ |
- V(ExternalMemory) \ |
- V(StringChars) \ |
- V(TypedArrayElements) |
- |
- |
-#define DECLARE_ABSTRACT_INSTRUCTION(type) \ |
- bool Is##type() const final { return true; } \ |
- static H##type* cast(HValue* value) { \ |
- DCHECK(value->Is##type()); \ |
- return reinterpret_cast<H##type*>(value); \ |
- } |
- |
- |
-#define DECLARE_CONCRETE_INSTRUCTION(type) \ |
- LInstruction* CompileToLithium(LChunkBuilder* builder) final; \ |
- static H##type* cast(HValue* value) { \ |
- DCHECK(value->Is##type()); \ |
- return reinterpret_cast<H##type*>(value); \ |
- } \ |
- Opcode opcode() const final { return HValue::k##type; } |
- |
- |
-enum PropertyAccessType { LOAD, STORE }; |
- |
- |
-class Range final : public ZoneObject { |
- public: |
- Range() |
- : lower_(kMinInt), |
- upper_(kMaxInt), |
- next_(NULL), |
- can_be_minus_zero_(false) { } |
- |
- Range(int32_t lower, int32_t upper) |
- : lower_(lower), |
- upper_(upper), |
- next_(NULL), |
- can_be_minus_zero_(false) { } |
- |
- int32_t upper() const { return upper_; } |
- int32_t lower() const { return lower_; } |
- Range* next() const { return next_; } |
- Range* CopyClearLower(Zone* zone) const { |
- return new(zone) Range(kMinInt, upper_); |
- } |
- Range* CopyClearUpper(Zone* zone) const { |
- return new(zone) Range(lower_, kMaxInt); |
- } |
- Range* Copy(Zone* zone) const { |
- Range* result = new(zone) Range(lower_, upper_); |
- result->set_can_be_minus_zero(CanBeMinusZero()); |
- return result; |
- } |
- int32_t Mask() const; |
- void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; } |
- bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; } |
- bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; } |
- bool CanBeNegative() const { return lower_ < 0; } |
- bool CanBePositive() const { return upper_ > 0; } |
- bool Includes(int value) const { return lower_ <= value && upper_ >= value; } |
- bool IsMostGeneric() const { |
- return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero(); |
- } |
- bool IsInSmiRange() const { |
- return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue; |
- } |
- void ClampToSmi() { |
- lower_ = Max(lower_, Smi::kMinValue); |
- upper_ = Min(upper_, Smi::kMaxValue); |
- } |
- void KeepOrder(); |
-#ifdef DEBUG |
- void Verify() const; |
-#endif |
- |
- void StackUpon(Range* other) { |
- Intersect(other); |
- next_ = other; |
- } |
- |
- void Intersect(Range* other); |
- void Union(Range* other); |
- void CombinedMax(Range* other); |
- void CombinedMin(Range* other); |
- |
- void AddConstant(int32_t value); |
- void Sar(int32_t value); |
- void Shl(int32_t value); |
- bool AddAndCheckOverflow(const Representation& r, Range* other); |
- bool SubAndCheckOverflow(const Representation& r, Range* other); |
- bool MulAndCheckOverflow(const Representation& r, Range* other); |
- |
- private: |
- int32_t lower_; |
- int32_t upper_; |
- Range* next_; |
- bool can_be_minus_zero_; |
-}; |
- |
- |
-class HUseListNode: public ZoneObject { |
- public: |
- HUseListNode(HValue* value, int index, HUseListNode* tail) |
- : tail_(tail), value_(value), index_(index) { |
- } |
- |
- HUseListNode* tail(); |
- HValue* value() const { return value_; } |
- int index() const { return index_; } |
- |
- void set_tail(HUseListNode* list) { tail_ = list; } |
- |
-#ifdef DEBUG |
- void Zap() { |
- tail_ = reinterpret_cast<HUseListNode*>(1); |
- value_ = NULL; |
- index_ = -1; |
- } |
-#endif |
- |
- private: |
- HUseListNode* tail_; |
- HValue* value_; |
- int index_; |
-}; |
- |
- |
-// We reuse use list nodes behind the scenes as uses are added and deleted. |
-// This class is the safe way to iterate uses while deleting them. |
-class HUseIterator final BASE_EMBEDDED { |
- public: |
- bool Done() { return current_ == NULL; } |
- void Advance(); |
- |
- HValue* value() { |
- DCHECK(!Done()); |
- return value_; |
- } |
- |
- int index() { |
- DCHECK(!Done()); |
- return index_; |
- } |
- |
- private: |
- explicit HUseIterator(HUseListNode* head); |
- |
- HUseListNode* current_; |
- HUseListNode* next_; |
- HValue* value_; |
- int index_; |
- |
- friend class HValue; |
-}; |
- |
- |
-// All tracked flags should appear before untracked ones. |
-enum GVNFlag { |
- // Declare global value numbering flags. |
-#define DECLARE_FLAG(Type) k##Type, |
- GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) |
- GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) |
-#undef DECLARE_FLAG |
-#define COUNT_FLAG(Type) + 1 |
- kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG), |
- kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG), |
-#undef COUNT_FLAG |
- kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects |
-}; |
- |
- |
-static inline GVNFlag GVNFlagFromInt(int i) { |
- DCHECK(i >= 0); |
- DCHECK(i < kNumberOfFlags); |
- return static_cast<GVNFlag>(i); |
-} |
- |
- |
-class DecompositionResult final BASE_EMBEDDED { |
- public: |
- DecompositionResult() : base_(NULL), offset_(0), scale_(0) {} |
- |
- HValue* base() { return base_; } |
- int offset() { return offset_; } |
- int scale() { return scale_; } |
- |
- bool Apply(HValue* other_base, int other_offset, int other_scale = 0) { |
- if (base_ == NULL) { |
- base_ = other_base; |
- offset_ = other_offset; |
- scale_ = other_scale; |
- return true; |
- } else { |
- if (scale_ == 0) { |
- base_ = other_base; |
- offset_ += other_offset; |
- scale_ = other_scale; |
- return true; |
- } else { |
- return false; |
- } |
- } |
- } |
- |
- void SwapValues(HValue** other_base, int* other_offset, int* other_scale) { |
- swap(&base_, other_base); |
- swap(&offset_, other_offset); |
- swap(&scale_, other_scale); |
- } |
- |
- private: |
- template <class T> void swap(T* a, T* b) { |
- T c(*a); |
- *a = *b; |
- *b = c; |
- } |
- |
- HValue* base_; |
- int offset_; |
- int scale_; |
-}; |
- |
- |
-typedef EnumSet<GVNFlag, int32_t> GVNFlagSet; |
- |
- |
-class HValue : public ZoneObject { |
- public: |
- static const int kNoNumber = -1; |
- |
- enum Flag { |
- kFlexibleRepresentation, |
- kCannotBeTagged, |
- // Participate in Global Value Numbering, i.e. elimination of |
- // unnecessary recomputations. If an instruction sets this flag, it must |
- // implement DataEquals(), which will be used to determine if other |
- // occurrences of the instruction are indeed the same. |
- kUseGVN, |
- // Track instructions that are dominating side effects. If an instruction |
- // sets this flag, it must implement HandleSideEffectDominator() and should |
- // indicate which side effects to track by setting GVN flags. |
- kTrackSideEffectDominators, |
- kCanOverflow, |
- kBailoutOnMinusZero, |
- kCanBeDivByZero, |
- kLeftCanBeMinInt, |
- kLeftCanBeNegative, |
- kLeftCanBePositive, |
- kAllowUndefinedAsNaN, |
- kIsArguments, |
- kTruncatingToInt32, |
- kAllUsesTruncatingToInt32, |
- kTruncatingToSmi, |
- kAllUsesTruncatingToSmi, |
- // Set after an instruction is killed. |
- kIsDead, |
- // Instructions that are allowed to produce full range unsigned integer |
- // values are marked with kUint32 flag. If arithmetic shift or a load from |
- // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag |
- // it will deoptimize if result does not fit into signed integer range. |
- // HGraph::ComputeSafeUint32Operations is responsible for setting this |
- // flag. |
- kUint32, |
- kHasNoObservableSideEffects, |
- // Indicates an instruction shouldn't be replaced by optimization, this flag |
- // is useful to set in cases where recomputing a value is cheaper than |
- // extending the value's live range and spilling it. |
- kCantBeReplaced, |
- // Indicates the instruction is live during dead code elimination. |
- kIsLive, |
- |
- // HEnvironmentMarkers are deleted before dead code |
- // elimination takes place, so they can repurpose the kIsLive flag: |
- kEndsLiveRange = kIsLive, |
- |
- // TODO(everyone): Don't forget to update this! |
- kLastFlag = kIsLive |
- }; |
- |
- STATIC_ASSERT(kLastFlag < kBitsPerInt); |
- |
- static HValue* cast(HValue* value) { return value; } |
- |
- enum Opcode { |
- // Declare a unique enum value for each hydrogen instruction. |
- #define DECLARE_OPCODE(type) k##type, |
- HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE) |
- kPhi |
- #undef DECLARE_OPCODE |
- }; |
- virtual Opcode opcode() const = 0; |
- |
- // Declare a non-virtual predicates for each concrete HInstruction or HValue. |
- #define DECLARE_PREDICATE(type) \ |
- bool Is##type() const { return opcode() == k##type; } |
- HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE) |
- #undef DECLARE_PREDICATE |
- bool IsPhi() const { return opcode() == kPhi; } |
- |
- // Declare virtual predicates for abstract HInstruction or HValue |
- #define DECLARE_PREDICATE(type) \ |
- virtual bool Is##type() const { return false; } |
- HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE) |
- #undef DECLARE_PREDICATE |
- |
- bool IsBitwiseBinaryShift() { |
- return IsShl() || IsShr() || IsSar(); |
- } |
- |
- explicit HValue(HType type = HType::Tagged()) |
- : block_(NULL), |
- id_(kNoNumber), |
- type_(type), |
- use_list_(NULL), |
- range_(NULL), |
-#ifdef DEBUG |
- range_poisoned_(false), |
-#endif |
- flags_(0) {} |
- virtual ~HValue() {} |
- |
- virtual SourcePosition position() const { return SourcePosition::Unknown(); } |
- virtual SourcePosition operand_position(int index) const { |
- return position(); |
- } |
- |
- HBasicBlock* block() const { return block_; } |
- void SetBlock(HBasicBlock* block); |
- |
- // Note: Never call this method for an unlinked value. |
- Isolate* isolate() const; |
- |
- int id() const { return id_; } |
- void set_id(int id) { id_ = id; } |
- |
- HUseIterator uses() const { return HUseIterator(use_list_); } |
- |
- virtual bool EmitAtUses() { return false; } |
- |
- Representation representation() const { return representation_; } |
- void ChangeRepresentation(Representation r) { |
- DCHECK(CheckFlag(kFlexibleRepresentation)); |
- DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged()); |
- RepresentationChanged(r); |
- representation_ = r; |
- if (r.IsTagged()) { |
- // Tagged is the bottom of the lattice, don't go any further. |
- ClearFlag(kFlexibleRepresentation); |
- } |
- } |
- virtual void AssumeRepresentation(Representation r); |
- |
- virtual Representation KnownOptimalRepresentation() { |
- Representation r = representation(); |
- if (r.IsTagged()) { |
- HType t = type(); |
- if (t.IsSmi()) return Representation::Smi(); |
- if (t.IsHeapNumber()) return Representation::Double(); |
- if (t.IsHeapObject()) return r; |
- return Representation::None(); |
- } |
- return r; |
- } |
- |
- HType type() const { return type_; } |
- void set_type(HType new_type) { |
- DCHECK(new_type.IsSubtypeOf(type_)); |
- type_ = new_type; |
- } |
- |
- // There are HInstructions that do not really change a value, they |
- // only add pieces of information to it (like bounds checks, map checks, |
- // smi checks...). |
- // We call these instructions "informative definitions", or "iDef". |
- // One of the iDef operands is special because it is the value that is |
- // "transferred" to the output, we call it the "redefined operand". |
- // If an HValue is an iDef it must override RedefinedOperandIndex() so that |
- // it does not return kNoRedefinedOperand; |
- static const int kNoRedefinedOperand = -1; |
- virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; } |
- bool IsInformativeDefinition() { |
- return RedefinedOperandIndex() != kNoRedefinedOperand; |
- } |
- HValue* RedefinedOperand() { |
- int index = RedefinedOperandIndex(); |
- return index == kNoRedefinedOperand ? NULL : OperandAt(index); |
- } |
- |
- bool CanReplaceWithDummyUses(); |
- |
- virtual int argument_delta() const { return 0; } |
- |
- // A purely informative definition is an idef that will not emit code and |
- // should therefore be removed from the graph in the RestoreActualValues |
- // phase (so that live ranges will be shorter). |
- virtual bool IsPurelyInformativeDefinition() { return false; } |
- |
- // This method must always return the original HValue SSA definition, |
- // regardless of any chain of iDefs of this value. |
- HValue* ActualValue() { |
- HValue* value = this; |
- int index; |
- while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) { |
- value = value->OperandAt(index); |
- } |
- return value; |
- } |
- |
- bool IsInteger32Constant(); |
- int32_t GetInteger32Constant(); |
- bool EqualsInteger32Constant(int32_t value); |
- |
- bool IsDefinedAfter(HBasicBlock* other) const; |
- |
- // Operands. |
- virtual int OperandCount() const = 0; |
- virtual HValue* OperandAt(int index) const = 0; |
- void SetOperandAt(int index, HValue* value); |
- |
- void DeleteAndReplaceWith(HValue* other); |
- void ReplaceAllUsesWith(HValue* other); |
- bool HasNoUses() const { return use_list_ == NULL; } |
- bool HasOneUse() const { |
- return use_list_ != NULL && use_list_->tail() == NULL; |
- } |
- bool HasMultipleUses() const { |
- return use_list_ != NULL && use_list_->tail() != NULL; |
- } |
- int UseCount() const; |
- |
- // Mark this HValue as dead and to be removed from other HValues' use lists. |
- void Kill(); |
- |
- int flags() const { return flags_; } |
- void SetFlag(Flag f) { flags_ |= (1 << f); } |
- void ClearFlag(Flag f) { flags_ &= ~(1 << f); } |
- bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; } |
- void CopyFlag(Flag f, HValue* other) { |
- if (other->CheckFlag(f)) SetFlag(f); |
- } |
- |
- // Returns true if the flag specified is set for all uses, false otherwise. |
- bool CheckUsesForFlag(Flag f) const; |
- // Same as before and the first one without the flag is returned in value. |
- bool CheckUsesForFlag(Flag f, HValue** value) const; |
- // Returns true if the flag specified is set for all uses, and this set |
- // of uses is non-empty. |
- bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const; |
- |
- GVNFlagSet ChangesFlags() const { return changes_flags_; } |
- GVNFlagSet DependsOnFlags() const { return depends_on_flags_; } |
- void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); } |
- void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); } |
- void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); } |
- void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); } |
- bool CheckChangesFlag(GVNFlag f) const { |
- return changes_flags_.Contains(f); |
- } |
- bool CheckDependsOnFlag(GVNFlag f) const { |
- return depends_on_flags_.Contains(f); |
- } |
- void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); } |
- void ClearAllSideEffects() { |
- changes_flags_.Remove(AllSideEffectsFlagSet()); |
- } |
- bool HasSideEffects() const { |
- return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet()); |
- } |
- bool HasObservableSideEffects() const { |
- return !CheckFlag(kHasNoObservableSideEffects) && |
- changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet()); |
- } |
- |
- GVNFlagSet SideEffectFlags() const { |
- GVNFlagSet result = ChangesFlags(); |
- result.Intersect(AllSideEffectsFlagSet()); |
- return result; |
- } |
- |
- GVNFlagSet ObservableChangesFlags() const { |
- GVNFlagSet result = ChangesFlags(); |
- result.Intersect(AllObservableSideEffectsFlagSet()); |
- return result; |
- } |
- |
- Range* range() const { |
- DCHECK(!range_poisoned_); |
- return range_; |
- } |
- bool HasRange() const { |
- DCHECK(!range_poisoned_); |
- return range_ != NULL; |
- } |
-#ifdef DEBUG |
- void PoisonRange() { range_poisoned_ = true; } |
-#endif |
- void AddNewRange(Range* r, Zone* zone); |
- void RemoveLastAddedRange(); |
- void ComputeInitialRange(Zone* zone); |
- |
- // Escape analysis helpers. |
- virtual bool HasEscapingOperandAt(int index) { return true; } |
- virtual bool HasOutOfBoundsAccess(int size) { return false; } |
- |
- // Representation helpers. |
- virtual Representation observed_input_representation(int index) { |
- return Representation::None(); |
- } |
- virtual Representation RequiredInputRepresentation(int index) = 0; |
- virtual void InferRepresentation(HInferRepresentationPhase* h_infer); |
- |
- // This gives the instruction an opportunity to replace itself with an |
- // instruction that does the same in some better way. To replace an |
- // instruction with a new one, first add the new instruction to the graph, |
- // then return it. Return NULL to have the instruction deleted. |
- virtual HValue* Canonicalize() { return this; } |
- |
- bool Equals(HValue* other); |
- virtual intptr_t Hashcode(); |
- |
- // Compute unique ids upfront that is safe wrt GC and concurrent compilation. |
- virtual void FinalizeUniqueness() { } |
- |
- // Printing support. |
- virtual std::ostream& PrintTo(std::ostream& os) const = 0; // NOLINT |
- |
- const char* Mnemonic() const; |
- |
- // Type information helpers. |
- bool HasMonomorphicJSObjectType(); |
- |
- // TODO(mstarzinger): For now instructions can override this function to |
- // specify statically known types, once HType can convey more information |
- // it should be based on the HType. |
- virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); } |
- |
- // Updated the inferred type of this instruction and returns true if |
- // it has changed. |
- bool UpdateInferredType(); |
- |
- virtual HType CalculateInferredType(); |
- |
- // This function must be overridden for instructions which have the |
- // kTrackSideEffectDominators flag set, to track instructions that are |
- // dominating side effects. |
- // It returns true if it removed an instruction which had side effects. |
- virtual bool HandleSideEffectDominator(GVNFlag side_effect, |
- HValue* dominator) { |
- UNREACHABLE(); |
- return false; |
- } |
- |
- // Check if this instruction has some reason that prevents elimination. |
- bool CannotBeEliminated() const { |
- return HasObservableSideEffects() || !IsDeletable(); |
- } |
- |
-#ifdef DEBUG |
- virtual void Verify() = 0; |
-#endif |
- |
- virtual bool TryDecompose(DecompositionResult* decomposition) { |
- if (RedefinedOperand() != NULL) { |
- return RedefinedOperand()->TryDecompose(decomposition); |
- } else { |
- return false; |
- } |
- } |
- |
- // Returns true conservatively if the program might be able to observe a |
- // ToString() operation on this value. |
- bool ToStringCanBeObserved() const { |
- return ToStringOrToNumberCanBeObserved(); |
- } |
- |
- // Returns true conservatively if the program might be able to observe a |
- // ToNumber() operation on this value. |
- bool ToNumberCanBeObserved() const { |
- return ToStringOrToNumberCanBeObserved(); |
- } |
- |
- MinusZeroMode GetMinusZeroMode() { |
- return CheckFlag(kBailoutOnMinusZero) |
- ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO; |
- } |
- |
- protected: |
- // This function must be overridden for instructions with flag kUseGVN, to |
- // compare the non-Operand parts of the instruction. |
- virtual bool DataEquals(HValue* other) { |
- UNREACHABLE(); |
- return false; |
- } |
- |
- bool ToStringOrToNumberCanBeObserved() const { |
- if (type().IsTaggedPrimitive()) return false; |
- if (type().IsJSObject()) return true; |
- return !representation().IsSmiOrInteger32() && !representation().IsDouble(); |
- } |
- |
- virtual Representation RepresentationFromInputs() { |
- return representation(); |
- } |
- virtual Representation RepresentationFromUses(); |
- Representation RepresentationFromUseRequirements(); |
- bool HasNonSmiUse(); |
- virtual void UpdateRepresentation(Representation new_rep, |
- HInferRepresentationPhase* h_infer, |
- const char* reason); |
- void AddDependantsToWorklist(HInferRepresentationPhase* h_infer); |
- |
- virtual void RepresentationChanged(Representation to) { } |
- |
- virtual Range* InferRange(Zone* zone); |
- virtual void DeleteFromGraph() = 0; |
- virtual void InternalSetOperandAt(int index, HValue* value) = 0; |
- void clear_block() { |
- DCHECK(block_ != NULL); |
- block_ = NULL; |
- } |
- |
- void set_representation(Representation r) { |
- DCHECK(representation_.IsNone() && !r.IsNone()); |
- representation_ = r; |
- } |
- |
- static GVNFlagSet AllFlagSet() { |
- GVNFlagSet result; |
-#define ADD_FLAG(Type) result.Add(k##Type); |
- GVN_TRACKED_FLAG_LIST(ADD_FLAG) |
- GVN_UNTRACKED_FLAG_LIST(ADD_FLAG) |
-#undef ADD_FLAG |
- return result; |
- } |
- |
- // A flag mask to mark an instruction as having arbitrary side effects. |
- static GVNFlagSet AllSideEffectsFlagSet() { |
- GVNFlagSet result = AllFlagSet(); |
- result.Remove(kOsrEntries); |
- return result; |
- } |
- friend std::ostream& operator<<(std::ostream& os, const ChangesOf& v); |
- |
- // A flag mask of all side effects that can make observable changes in |
- // an executing program (i.e. are not safe to repeat, move or remove); |
- static GVNFlagSet AllObservableSideEffectsFlagSet() { |
- GVNFlagSet result = AllFlagSet(); |
- result.Remove(kNewSpacePromotion); |
- result.Remove(kElementsKind); |
- result.Remove(kElementsPointer); |
- result.Remove(kMaps); |
- return result; |
- } |
- |
- // Remove the matching use from the use list if present. Returns the |
- // removed list node or NULL. |
- HUseListNode* RemoveUse(HValue* value, int index); |
- |
- void RegisterUse(int index, HValue* new_value); |
- |
- HBasicBlock* block_; |
- |
- // The id of this instruction in the hydrogen graph, assigned when first |
- // added to the graph. Reflects creation order. |
- int id_; |
- |
- Representation representation_; |
- HType type_; |
- HUseListNode* use_list_; |
- Range* range_; |
-#ifdef DEBUG |
- bool range_poisoned_; |
-#endif |
- int flags_; |
- GVNFlagSet changes_flags_; |
- GVNFlagSet depends_on_flags_; |
- |
- private: |
- virtual bool IsDeletable() const { return false; } |
- |
- DISALLOW_COPY_AND_ASSIGN(HValue); |
-}; |
- |
-// Support for printing various aspects of an HValue. |
-struct NameOf { |
- explicit NameOf(const HValue* const v) : value(v) {} |
- const HValue* value; |
-}; |
- |
- |
-struct TypeOf { |
- explicit TypeOf(const HValue* const v) : value(v) {} |
- const HValue* value; |
-}; |
- |
- |
-struct ChangesOf { |
- explicit ChangesOf(const HValue* const v) : value(v) {} |
- const HValue* value; |
-}; |
- |
- |
-std::ostream& operator<<(std::ostream& os, const HValue& v); |
-std::ostream& operator<<(std::ostream& os, const NameOf& v); |
-std::ostream& operator<<(std::ostream& os, const TypeOf& v); |
-std::ostream& operator<<(std::ostream& os, const ChangesOf& v); |
- |
- |
-#define DECLARE_INSTRUCTION_FACTORY_P0(I) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context) { \ |
- return new (zone) I(); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \ |
- return new (zone) I(p1); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \ |
- return new (zone) I(p1, p2); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ |
- P3 p3) { \ |
- return new (zone) I(p1, p2, p3); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ |
- P3 p3, P4 p4) { \ |
- return new (zone) I(p1, p2, p3, p4); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ |
- P3 p3, P4 p4, P5 p5) { \ |
- return new (zone) I(p1, p2, p3, p4, p5); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ |
- P3 p3, P4 p4, P5 p5, P6 p6) { \ |
- return new (zone) I(p1, p2, p3, p4, p5, p6); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context) { \ |
- return new (zone) I(context); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \ |
- return new (zone) I(context, p1); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \ |
- return new (zone) I(context, p1, p2); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ |
- P3 p3) { \ |
- return new (zone) I(context, p1, p2, p3); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ |
- P3 p3, P4 p4) { \ |
- return new (zone) I(context, p1, p2, p3, p4); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ |
- P3 p3, P4 p4, P5 p5) { \ |
- return new (zone) I(context, p1, p2, p3, p4, p5); \ |
- } |
- |
-#define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \ |
- static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ |
- P3 p3, P4 p4, P5 p5, P6 p6) { \ |
- return new (zone) I(context, p1, p2, p3, p4, p5, p6); \ |
- } |
- |
- |
-// A helper class to represent per-operand position information attached to |
-// the HInstruction in the compact form. Uses tagging to distinguish between |
-// case when only instruction's position is available and case when operands' |
-// positions are also available. |
-// In the first case it contains intruction's position as a tagged value. |
-// In the second case it points to an array which contains instruction's |
-// position and operands' positions. |
-class HPositionInfo { |
- public: |
- explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { } |
- |
- SourcePosition position() const { |
- if (has_operand_positions()) { |
- return operand_positions()[kInstructionPosIndex]; |
- } |
- return SourcePosition::FromRaw(static_cast<int>(UntagPosition(data_))); |
- } |
- |
- void set_position(SourcePosition pos) { |
- if (has_operand_positions()) { |
- operand_positions()[kInstructionPosIndex] = pos; |
- } else { |
- data_ = TagPosition(pos.raw()); |
- } |
- } |
- |
- void ensure_storage_for_operand_positions(Zone* zone, int operand_count) { |
- if (has_operand_positions()) { |
- return; |
- } |
- |
- const int length = kFirstOperandPosIndex + operand_count; |
- SourcePosition* positions = zone->NewArray<SourcePosition>(length); |
- for (int i = 0; i < length; i++) { |
- positions[i] = SourcePosition::Unknown(); |
- } |
- |
- const SourcePosition pos = position(); |
- data_ = reinterpret_cast<intptr_t>(positions); |
- set_position(pos); |
- |
- DCHECK(has_operand_positions()); |
- } |
- |
- SourcePosition operand_position(int idx) const { |
- if (!has_operand_positions()) { |
- return position(); |
- } |
- return *operand_position_slot(idx); |
- } |
- |
- void set_operand_position(int idx, SourcePosition pos) { |
- *operand_position_slot(idx) = pos; |
- } |
- |
- private: |
- static const intptr_t kInstructionPosIndex = 0; |
- static const intptr_t kFirstOperandPosIndex = 1; |
- |
- SourcePosition* operand_position_slot(int idx) const { |
- DCHECK(has_operand_positions()); |
- return &(operand_positions()[kFirstOperandPosIndex + idx]); |
- } |
- |
- bool has_operand_positions() const { |
- return !IsTaggedPosition(data_); |
- } |
- |
- SourcePosition* operand_positions() const { |
- DCHECK(has_operand_positions()); |
- return reinterpret_cast<SourcePosition*>(data_); |
- } |
- |
- static const intptr_t kPositionTag = 1; |
- static const intptr_t kPositionShift = 1; |
- static bool IsTaggedPosition(intptr_t val) { |
- return (val & kPositionTag) != 0; |
- } |
- static intptr_t UntagPosition(intptr_t val) { |
- DCHECK(IsTaggedPosition(val)); |
- return val >> kPositionShift; |
- } |
- static intptr_t TagPosition(intptr_t val) { |
- const intptr_t result = (val << kPositionShift) | kPositionTag; |
- DCHECK(UntagPosition(result) == val); |
- return result; |
- } |
- |
- intptr_t data_; |
-}; |
- |
- |
-class HInstruction : public HValue { |
- public: |
- HInstruction* next() const { return next_; } |
- HInstruction* previous() const { return previous_; } |
- |
- std::ostream& PrintTo(std::ostream& os) const override; // NOLINT |
- virtual std::ostream& PrintDataTo(std::ostream& os) const; // NOLINT |
- |
- bool IsLinked() const { return block() != NULL; } |
- void Unlink(); |
- |
- void InsertBefore(HInstruction* next); |
- |
- template<class T> T* Prepend(T* instr) { |
- instr->InsertBefore(this); |
- return instr; |
- } |
- |
- void InsertAfter(HInstruction* previous); |
- |
- template<class T> T* Append(T* instr) { |
- instr->InsertAfter(this); |
- return instr; |
- } |
- |
- // The position is a write-once variable. |
- SourcePosition position() const override { |
- return SourcePosition(position_.position()); |
- } |
- bool has_position() const { |
- return !position().IsUnknown(); |
- } |
- void set_position(SourcePosition position) { |
- DCHECK(!has_position()); |
- DCHECK(!position.IsUnknown()); |
- position_.set_position(position); |
- } |
- |
- SourcePosition operand_position(int index) const override { |
- const SourcePosition pos = position_.operand_position(index); |
- return pos.IsUnknown() ? position() : pos; |
- } |
- void set_operand_position(Zone* zone, int index, SourcePosition pos) { |
- DCHECK(0 <= index && index < OperandCount()); |
- position_.ensure_storage_for_operand_positions(zone, OperandCount()); |
- position_.set_operand_position(index, pos); |
- } |
- |
- bool Dominates(HInstruction* other); |
- bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); } |
- bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); } |
- |
- virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0; |
- |
-#ifdef DEBUG |
- void Verify() override; |
-#endif |
- |
- bool CanDeoptimize(); |
- |
- virtual bool HasStackCheck() { return false; } |
- |
- DECLARE_ABSTRACT_INSTRUCTION(Instruction) |
- |
- protected: |
- explicit HInstruction(HType type = HType::Tagged()) |
- : HValue(type), |
- next_(NULL), |
- previous_(NULL), |
- position_(RelocInfo::kNoPosition) { |
- SetDependsOnFlag(kOsrEntries); |
- } |
- |
- void DeleteFromGraph() override { Unlink(); } |
- |
- private: |
- void InitializeAsFirst(HBasicBlock* block) { |
- DCHECK(!IsLinked()); |
- SetBlock(block); |
- } |
- |
- HInstruction* next_; |
- HInstruction* previous_; |
- HPositionInfo position_; |
- |
- friend class HBasicBlock; |
-}; |
- |
- |
-template<int V> |
-class HTemplateInstruction : public HInstruction { |
- public: |
- int OperandCount() const final { return V; } |
- HValue* OperandAt(int i) const final { return inputs_[i]; } |
- |
- protected: |
- explicit HTemplateInstruction(HType type = HType::Tagged()) |
- : HInstruction(type) {} |
- |
- void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; } |
- |
- private: |
- EmbeddedContainer<HValue*, V> inputs_; |
-}; |
- |
- |
-class HControlInstruction : public HInstruction { |
- public: |
- virtual HBasicBlock* SuccessorAt(int i) const = 0; |
- virtual int SuccessorCount() const = 0; |
- virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0; |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- virtual bool KnownSuccessorBlock(HBasicBlock** block) { |
- *block = NULL; |
- return false; |
- } |
- |
- HBasicBlock* FirstSuccessor() { |
- return SuccessorCount() > 0 ? SuccessorAt(0) : NULL; |
- } |
- HBasicBlock* SecondSuccessor() { |
- return SuccessorCount() > 1 ? SuccessorAt(1) : NULL; |
- } |
- |
- void Not() { |
- HBasicBlock* swap = SuccessorAt(0); |
- SetSuccessorAt(0, SuccessorAt(1)); |
- SetSuccessorAt(1, swap); |
- } |
- |
- DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction) |
-}; |
- |
- |
-class HSuccessorIterator final BASE_EMBEDDED { |
- public: |
- explicit HSuccessorIterator(const HControlInstruction* instr) |
- : instr_(instr), current_(0) {} |
- |
- bool Done() { return current_ >= instr_->SuccessorCount(); } |
- HBasicBlock* Current() { return instr_->SuccessorAt(current_); } |
- void Advance() { current_++; } |
- |
- private: |
- const HControlInstruction* instr_; |
- int current_; |
-}; |
- |
- |
-template<int S, int V> |
-class HTemplateControlInstruction : public HControlInstruction { |
- public: |
- int SuccessorCount() const override { return S; } |
- HBasicBlock* SuccessorAt(int i) const override { return successors_[i]; } |
- void SetSuccessorAt(int i, HBasicBlock* block) override { |
- successors_[i] = block; |
- } |
- |
- int OperandCount() const override { return V; } |
- HValue* OperandAt(int i) const override { return inputs_[i]; } |
- |
- |
- protected: |
- void InternalSetOperandAt(int i, HValue* value) override { |
- inputs_[i] = value; |
- } |
- |
- private: |
- EmbeddedContainer<HBasicBlock*, S> successors_; |
- EmbeddedContainer<HValue*, V> inputs_; |
-}; |
- |
- |
-class HBlockEntry final : public HTemplateInstruction<0> { |
- public: |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(BlockEntry) |
-}; |
- |
- |
-class HDummyUse final : public HTemplateInstruction<1> { |
- public: |
- explicit HDummyUse(HValue* value) |
- : HTemplateInstruction<1>(HType::Smi()) { |
- SetOperandAt(0, value); |
- // Pretend to be a Smi so that the HChange instructions inserted |
- // before any use generate as little code as possible. |
- set_representation(Representation::Tagged()); |
- } |
- |
- HValue* value() const { return OperandAt(0); } |
- |
- bool HasEscapingOperandAt(int index) override { return false; } |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(DummyUse); |
-}; |
- |
- |
-// Inserts an int3/stop break instruction for debugging purposes. |
-class HDebugBreak final : public HTemplateInstruction<0> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(DebugBreak) |
-}; |
- |
- |
-class HPrologue final : public HTemplateInstruction<0> { |
- public: |
- static HPrologue* New(Zone* zone) { return new (zone) HPrologue(); } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Prologue) |
-}; |
- |
- |
-class HGoto final : public HTemplateControlInstruction<1, 0> { |
- public: |
- explicit HGoto(HBasicBlock* target) { |
- SetSuccessorAt(0, target); |
- } |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override { |
- *block = FirstSuccessor(); |
- return true; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(Goto) |
-}; |
- |
- |
-class HDeoptimize final : public HTemplateControlInstruction<1, 0> { |
- public: |
- static HDeoptimize* New(Isolate* isolate, Zone* zone, HValue* context, |
- Deoptimizer::DeoptReason reason, |
- Deoptimizer::BailoutType type, |
- HBasicBlock* unreachable_continuation) { |
- return new(zone) HDeoptimize(reason, type, unreachable_continuation); |
- } |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override { |
- *block = NULL; |
- return true; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- Deoptimizer::DeoptReason reason() const { return reason_; } |
- Deoptimizer::BailoutType type() { return type_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Deoptimize) |
- |
- private: |
- explicit HDeoptimize(Deoptimizer::DeoptReason reason, |
- Deoptimizer::BailoutType type, |
- HBasicBlock* unreachable_continuation) |
- : reason_(reason), type_(type) { |
- SetSuccessorAt(0, unreachable_continuation); |
- } |
- |
- Deoptimizer::DeoptReason reason_; |
- Deoptimizer::BailoutType type_; |
-}; |
- |
- |
-class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> { |
- public: |
- HUnaryControlInstruction(HValue* value, |
- HBasicBlock* true_target, |
- HBasicBlock* false_target) { |
- SetOperandAt(0, value); |
- SetSuccessorAt(0, true_target); |
- SetSuccessorAt(1, false_target); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HValue* value() const { return OperandAt(0); } |
-}; |
- |
- |
-class HBranch final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*); |
- DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*, |
- ToBooleanStub::Types); |
- DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*, |
- ToBooleanStub::Types, |
- HBasicBlock*, HBasicBlock*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- Representation observed_input_representation(int index) override; |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override; |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- ToBooleanStub::Types expected_input_types() const { |
- return expected_input_types_; |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Branch) |
- |
- private: |
- HBranch(HValue* value, |
- ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(), |
- HBasicBlock* true_target = NULL, |
- HBasicBlock* false_target = NULL) |
- : HUnaryControlInstruction(value, true_target, false_target), |
- expected_input_types_(expected_input_types) { |
- SetFlag(kAllowUndefinedAsNaN); |
- } |
- |
- ToBooleanStub::Types expected_input_types_; |
-}; |
- |
- |
-class HCompareMap final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>); |
- DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>, |
- HBasicBlock*, HBasicBlock*); |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override { |
- if (known_successor_index() != kNoKnownSuccessorIndex) { |
- *block = SuccessorAt(known_successor_index()); |
- return true; |
- } |
- *block = NULL; |
- return false; |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- static const int kNoKnownSuccessorIndex = -1; |
- int known_successor_index() const { |
- return KnownSuccessorIndexField::decode(bit_field_) - |
- kInternalKnownSuccessorOffset; |
- } |
- void set_known_successor_index(int index) { |
- DCHECK(index >= 0 - kInternalKnownSuccessorOffset); |
- bit_field_ = KnownSuccessorIndexField::update( |
- bit_field_, index + kInternalKnownSuccessorOffset); |
- } |
- |
- Unique<Map> map() const { return map_; } |
- bool map_is_stable() const { return MapIsStableField::decode(bit_field_); } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CompareMap) |
- |
- protected: |
- int RedefinedOperandIndex() override { return 0; } |
- |
- private: |
- HCompareMap(HValue* value, Handle<Map> map, HBasicBlock* true_target = NULL, |
- HBasicBlock* false_target = NULL) |
- : HUnaryControlInstruction(value, true_target, false_target), |
- bit_field_(KnownSuccessorIndexField::encode( |
- kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset) | |
- MapIsStableField::encode(map->is_stable())), |
- map_(Unique<Map>::CreateImmovable(map)) { |
- set_representation(Representation::Tagged()); |
- } |
- |
- // BitFields can only store unsigned values, so use an offset. |
- // Adding kInternalKnownSuccessorOffset must yield an unsigned value. |
- static const int kInternalKnownSuccessorOffset = 1; |
- STATIC_ASSERT(kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset >= 0); |
- |
- class KnownSuccessorIndexField : public BitField<int, 0, 31> {}; |
- class MapIsStableField : public BitField<bool, 31, 1> {}; |
- |
- uint32_t bit_field_; |
- Unique<Map> map_; |
-}; |
- |
- |
-class HContext final : public HTemplateInstruction<0> { |
- public: |
- static HContext* New(Zone* zone) { |
- return new(zone) HContext(); |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Context) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- HContext() { |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- } |
- |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HReturn final : public HTemplateControlInstruction<0, 3> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*); |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- // TODO(titzer): require an Int32 input for faster returns. |
- if (index == 2) return Representation::Smi(); |
- return Representation::Tagged(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HValue* value() const { return OperandAt(0); } |
- HValue* context() const { return OperandAt(1); } |
- HValue* parameter_count() const { return OperandAt(2); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Return) |
- |
- private: |
- HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) { |
- SetOperandAt(0, value); |
- SetOperandAt(1, context); |
- SetOperandAt(2, parameter_count); |
- } |
-}; |
- |
- |
-class HAbnormalExit final : public HTemplateControlInstruction<0, 0> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(AbnormalExit) |
- private: |
- HAbnormalExit() {} |
-}; |
- |
- |
-class HUnaryOperation : public HTemplateInstruction<1> { |
- public: |
- explicit HUnaryOperation(HValue* value, HType type = HType::Tagged()) |
- : HTemplateInstruction<1>(type) { |
- SetOperandAt(0, value); |
- } |
- |
- static HUnaryOperation* cast(HValue* value) { |
- return reinterpret_cast<HUnaryOperation*>(value); |
- } |
- |
- HValue* value() const { return OperandAt(0); } |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
-}; |
- |
- |
-class HUseConst final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(UseConst) |
- |
- private: |
- explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { } |
-}; |
- |
- |
-class HForceRepresentation final : public HTemplateInstruction<1> { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* value, |
- Representation required_representation); |
- |
- HValue* value() const { return OperandAt(0); } |
- |
- Representation observed_input_representation(int index) override { |
- // We haven't actually *observed* this, but it's closer to the truth |
- // than 'None'. |
- return representation(); // Same as the output representation. |
- } |
- Representation RequiredInputRepresentation(int index) override { |
- return representation(); // Same as the output representation. |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation) |
- |
- private: |
- HForceRepresentation(HValue* value, Representation required_representation) { |
- SetOperandAt(0, value); |
- set_representation(required_representation); |
- } |
-}; |
- |
- |
-class HChange final : public HUnaryOperation { |
- public: |
- HChange(HValue* value, |
- Representation to, |
- bool is_truncating_to_smi, |
- bool is_truncating_to_int32) |
- : HUnaryOperation(value) { |
- DCHECK(!value->representation().IsNone()); |
- DCHECK(!to.IsNone()); |
- DCHECK(!value->representation().Equals(to)); |
- set_representation(to); |
- SetFlag(kUseGVN); |
- SetFlag(kCanOverflow); |
- if (is_truncating_to_smi && to.IsSmi()) { |
- SetFlag(kTruncatingToSmi); |
- SetFlag(kTruncatingToInt32); |
- } |
- if (is_truncating_to_int32) SetFlag(kTruncatingToInt32); |
- if (value->representation().IsSmi() || value->type().IsSmi()) { |
- set_type(HType::Smi()); |
- } else { |
- set_type(HType::TaggedNumber()); |
- if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion); |
- } |
- } |
- |
- bool can_convert_undefined_to_nan() { |
- return CheckUsesForFlag(kAllowUndefinedAsNaN); |
- } |
- |
- HType CalculateInferredType() override; |
- HValue* Canonicalize() override; |
- |
- Representation from() const { return value()->representation(); } |
- Representation to() const { return representation(); } |
- bool deoptimize_on_minus_zero() const { |
- return CheckFlag(kBailoutOnMinusZero); |
- } |
- Representation RequiredInputRepresentation(int index) override { |
- return from(); |
- } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(Change) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- bool IsDeletable() const override { |
- return !from().IsTagged() || value()->type().IsSmi(); |
- } |
-}; |
- |
- |
-class HClampToUint8 final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(ClampToUint8) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- explicit HClampToUint8(HValue* value) |
- : HUnaryOperation(value) { |
- set_representation(Representation::Integer32()); |
- SetFlag(kAllowUndefinedAsNaN); |
- SetFlag(kUseGVN); |
- } |
- |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HDoubleBits final : public HUnaryOperation { |
- public: |
- enum Bits { HIGH, LOW }; |
- DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Double(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(DoubleBits) |
- |
- Bits bits() { return bits_; } |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits(); |
- } |
- |
- private: |
- HDoubleBits(HValue* value, Bits bits) |
- : HUnaryOperation(value), bits_(bits) { |
- set_representation(Representation::Integer32()); |
- SetFlag(kUseGVN); |
- } |
- |
- bool IsDeletable() const override { return true; } |
- |
- Bits bits_; |
-}; |
- |
- |
-class HConstructDouble final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Integer32(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(ConstructDouble) |
- |
- HValue* hi() { return OperandAt(0); } |
- HValue* lo() { return OperandAt(1); } |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- explicit HConstructDouble(HValue* hi, HValue* lo) { |
- set_representation(Representation::Double()); |
- SetFlag(kUseGVN); |
- SetOperandAt(0, hi); |
- SetOperandAt(1, lo); |
- } |
- |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-enum RemovableSimulate { |
- REMOVABLE_SIMULATE, |
- FIXED_SIMULATE |
-}; |
- |
- |
-class HSimulate final : public HInstruction { |
- public: |
- HSimulate(BailoutId ast_id, int pop_count, Zone* zone, |
- RemovableSimulate removable) |
- : ast_id_(ast_id), |
- pop_count_(pop_count), |
- values_(2, zone), |
- assigned_indexes_(2, zone), |
- zone_(zone), |
- bit_field_(RemovableField::encode(removable) | |
- DoneWithReplayField::encode(false)) {} |
- ~HSimulate() {} |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- bool HasAstId() const { return !ast_id_.IsNone(); } |
- BailoutId ast_id() const { return ast_id_; } |
- void set_ast_id(BailoutId id) { |
- DCHECK(!HasAstId()); |
- ast_id_ = id; |
- } |
- |
- int pop_count() const { return pop_count_; } |
- const ZoneList<HValue*>* values() const { return &values_; } |
- int GetAssignedIndexAt(int index) const { |
- DCHECK(HasAssignedIndexAt(index)); |
- return assigned_indexes_[index]; |
- } |
- bool HasAssignedIndexAt(int index) const { |
- return assigned_indexes_[index] != kNoIndex; |
- } |
- void AddAssignedValue(int index, HValue* value) { |
- AddValue(index, value); |
- } |
- void AddPushedValue(HValue* value) { |
- AddValue(kNoIndex, value); |
- } |
- int ToOperandIndex(int environment_index) { |
- for (int i = 0; i < assigned_indexes_.length(); ++i) { |
- if (assigned_indexes_[i] == environment_index) return i; |
- } |
- return -1; |
- } |
- int OperandCount() const override { return values_.length(); } |
- HValue* OperandAt(int index) const override { return values_[index]; } |
- |
- bool HasEscapingOperandAt(int index) override { return false; } |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- void MergeWith(ZoneList<HSimulate*>* list); |
- bool is_candidate_for_removal() { |
- return RemovableField::decode(bit_field_) == REMOVABLE_SIMULATE; |
- } |
- |
- // Replay effects of this instruction on the given environment. |
- void ReplayEnvironment(HEnvironment* env); |
- |
- DECLARE_CONCRETE_INSTRUCTION(Simulate) |
- |
-#ifdef DEBUG |
- void Verify() override; |
- void set_closure(Handle<JSFunction> closure) { closure_ = closure; } |
- Handle<JSFunction> closure() const { return closure_; } |
-#endif |
- |
- protected: |
- void InternalSetOperandAt(int index, HValue* value) override { |
- values_[index] = value; |
- } |
- |
- private: |
- static const int kNoIndex = -1; |
- void AddValue(int index, HValue* value) { |
- assigned_indexes_.Add(index, zone_); |
- // Resize the list of pushed values. |
- values_.Add(NULL, zone_); |
- // Set the operand through the base method in HValue to make sure that the |
- // use lists are correctly updated. |
- SetOperandAt(values_.length() - 1, value); |
- } |
- bool HasValueForIndex(int index) { |
- for (int i = 0; i < assigned_indexes_.length(); ++i) { |
- if (assigned_indexes_[i] == index) return true; |
- } |
- return false; |
- } |
- bool is_done_with_replay() const { |
- return DoneWithReplayField::decode(bit_field_); |
- } |
- void set_done_with_replay() { |
- bit_field_ = DoneWithReplayField::update(bit_field_, true); |
- } |
- |
- class RemovableField : public BitField<RemovableSimulate, 0, 1> {}; |
- class DoneWithReplayField : public BitField<bool, 1, 1> {}; |
- |
- BailoutId ast_id_; |
- int pop_count_; |
- ZoneList<HValue*> values_; |
- ZoneList<int> assigned_indexes_; |
- Zone* zone_; |
- uint32_t bit_field_; |
- |
-#ifdef DEBUG |
- Handle<JSFunction> closure_; |
-#endif |
-}; |
- |
- |
-class HEnvironmentMarker final : public HTemplateInstruction<1> { |
- public: |
- enum Kind { BIND, LOOKUP }; |
- |
- DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int); |
- |
- Kind kind() const { return kind_; } |
- int index() const { return index_; } |
- HSimulate* next_simulate() { return next_simulate_; } |
- void set_next_simulate(HSimulate* simulate) { |
- next_simulate_ = simulate; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
-#ifdef DEBUG |
- void set_closure(Handle<JSFunction> closure) { |
- DCHECK(closure_.is_null()); |
- DCHECK(!closure.is_null()); |
- closure_ = closure; |
- } |
- Handle<JSFunction> closure() const { return closure_; } |
-#endif |
- |
- DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker); |
- |
- private: |
- HEnvironmentMarker(Kind kind, int index) |
- : kind_(kind), index_(index), next_simulate_(NULL) { } |
- |
- Kind kind_; |
- int index_; |
- HSimulate* next_simulate_; |
- |
-#ifdef DEBUG |
- Handle<JSFunction> closure_; |
-#endif |
-}; |
- |
- |
-class HStackCheck final : public HTemplateInstruction<1> { |
- public: |
- enum Type { |
- kFunctionEntry, |
- kBackwardsBranch |
- }; |
- |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type); |
- |
- HValue* context() { return OperandAt(0); } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- void Eliminate() { |
- // The stack check eliminator might try to eliminate the same stack |
- // check instruction multiple times. |
- if (IsLinked()) { |
- DeleteAndReplaceWith(NULL); |
- } |
- } |
- |
- bool is_function_entry() { return type_ == kFunctionEntry; } |
- bool is_backwards_branch() { return type_ == kBackwardsBranch; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(StackCheck) |
- |
- private: |
- HStackCheck(HValue* context, Type type) : type_(type) { |
- SetOperandAt(0, context); |
- SetChangesFlag(kNewSpacePromotion); |
- } |
- |
- Type type_; |
-}; |
- |
- |
-enum InliningKind { |
- NORMAL_RETURN, // Drop the function from the environment on return. |
- CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value. |
- GETTER_CALL_RETURN, // Returning from a getter, need to restore context. |
- SETTER_CALL_RETURN // Use the RHS of the assignment as the return value. |
-}; |
- |
- |
-class HArgumentsObject; |
-class HConstant; |
- |
- |
-class HEnterInlined final : public HTemplateInstruction<0> { |
- public: |
- static HEnterInlined* New(Isolate* isolate, Zone* zone, HValue* context, |
- BailoutId return_id, Handle<JSFunction> closure, |
- HConstant* closure_context, int arguments_count, |
- FunctionLiteral* function, |
- InliningKind inlining_kind, Variable* arguments_var, |
- HArgumentsObject* arguments_object) { |
- return new (zone) HEnterInlined(return_id, closure, closure_context, |
- arguments_count, function, inlining_kind, |
- arguments_var, arguments_object, zone); |
- } |
- |
- void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone); |
- ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Handle<SharedFunctionInfo> shared() const { return shared_; } |
- Handle<JSFunction> closure() const { return closure_; } |
- HConstant* closure_context() const { return closure_context_; } |
- int arguments_count() const { return arguments_count_; } |
- bool arguments_pushed() const { return arguments_pushed_; } |
- void set_arguments_pushed() { arguments_pushed_ = true; } |
- FunctionLiteral* function() const { return function_; } |
- InliningKind inlining_kind() const { return inlining_kind_; } |
- BailoutId ReturnId() const { return return_id_; } |
- int inlining_id() const { return inlining_id_; } |
- void set_inlining_id(int inlining_id) { inlining_id_ = inlining_id; } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- Variable* arguments_var() { return arguments_var_; } |
- HArgumentsObject* arguments_object() { return arguments_object_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(EnterInlined) |
- |
- private: |
- HEnterInlined(BailoutId return_id, Handle<JSFunction> closure, |
- HConstant* closure_context, int arguments_count, |
- FunctionLiteral* function, InliningKind inlining_kind, |
- Variable* arguments_var, HArgumentsObject* arguments_object, |
- Zone* zone) |
- : return_id_(return_id), |
- shared_(handle(closure->shared())), |
- closure_(closure), |
- closure_context_(closure_context), |
- arguments_count_(arguments_count), |
- arguments_pushed_(false), |
- function_(function), |
- inlining_kind_(inlining_kind), |
- inlining_id_(0), |
- arguments_var_(arguments_var), |
- arguments_object_(arguments_object), |
- return_targets_(2, zone) {} |
- |
- BailoutId return_id_; |
- Handle<SharedFunctionInfo> shared_; |
- Handle<JSFunction> closure_; |
- HConstant* closure_context_; |
- int arguments_count_; |
- bool arguments_pushed_; |
- FunctionLiteral* function_; |
- InliningKind inlining_kind_; |
- int inlining_id_; |
- Variable* arguments_var_; |
- HArgumentsObject* arguments_object_; |
- ZoneList<HBasicBlock*> return_targets_; |
-}; |
- |
- |
-class HLeaveInlined final : public HTemplateInstruction<0> { |
- public: |
- HLeaveInlined(HEnterInlined* entry, |
- int drop_count) |
- : entry_(entry), |
- drop_count_(drop_count) { } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- int argument_delta() const override { |
- return entry_->arguments_pushed() ? -drop_count_ : 0; |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(LeaveInlined) |
- |
- private: |
- HEnterInlined* entry_; |
- int drop_count_; |
-}; |
- |
- |
-class HPushArguments final : public HInstruction { |
- public: |
- static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context) { |
- return new(zone) HPushArguments(zone); |
- } |
- static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* arg1) { |
- HPushArguments* instr = new(zone) HPushArguments(zone); |
- instr->AddInput(arg1); |
- return instr; |
- } |
- static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* arg1, HValue* arg2) { |
- HPushArguments* instr = new(zone) HPushArguments(zone); |
- instr->AddInput(arg1); |
- instr->AddInput(arg2); |
- return instr; |
- } |
- static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* arg1, HValue* arg2, HValue* arg3) { |
- HPushArguments* instr = new(zone) HPushArguments(zone); |
- instr->AddInput(arg1); |
- instr->AddInput(arg2); |
- instr->AddInput(arg3); |
- return instr; |
- } |
- static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* arg1, HValue* arg2, HValue* arg3, |
- HValue* arg4) { |
- HPushArguments* instr = new(zone) HPushArguments(zone); |
- instr->AddInput(arg1); |
- instr->AddInput(arg2); |
- instr->AddInput(arg3); |
- instr->AddInput(arg4); |
- return instr; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- int argument_delta() const override { return inputs_.length(); } |
- HValue* argument(int i) { return OperandAt(i); } |
- |
- int OperandCount() const final { return inputs_.length(); } |
- HValue* OperandAt(int i) const final { return inputs_[i]; } |
- |
- void AddInput(HValue* value); |
- |
- DECLARE_CONCRETE_INSTRUCTION(PushArguments) |
- |
- protected: |
- void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; } |
- |
- private: |
- explicit HPushArguments(Zone* zone) |
- : HInstruction(HType::Tagged()), inputs_(4, zone) { |
- set_representation(Representation::Tagged()); |
- } |
- |
- ZoneList<HValue*> inputs_; |
-}; |
- |
- |
-class HThisFunction final : public HTemplateInstruction<0> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(ThisFunction) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- HThisFunction() { |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- } |
- |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HDeclareGlobals final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals, |
- Handle<FixedArray>, |
- int); |
- |
- HValue* context() { return OperandAt(0); } |
- Handle<FixedArray> pairs() const { return pairs_; } |
- int flags() const { return flags_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals) |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- private: |
- HDeclareGlobals(HValue* context, |
- Handle<FixedArray> pairs, |
- int flags) |
- : HUnaryOperation(context), |
- pairs_(pairs), |
- flags_(flags) { |
- set_representation(Representation::Tagged()); |
- SetAllSideEffects(); |
- } |
- |
- Handle<FixedArray> pairs_; |
- int flags_; |
-}; |
- |
- |
-template <int V> |
-class HCall : public HTemplateInstruction<V> { |
- public: |
- // The argument count includes the receiver. |
- explicit HCall<V>(int argument_count) : argument_count_(argument_count) { |
- this->set_representation(Representation::Tagged()); |
- this->SetAllSideEffects(); |
- } |
- |
- HType CalculateInferredType() final { return HType::Tagged(); } |
- |
- virtual int argument_count() const { |
- return argument_count_; |
- } |
- |
- int argument_delta() const override { return -argument_count(); } |
- |
- private: |
- int argument_count_; |
-}; |
- |
- |
-class HUnaryCall : public HCall<1> { |
- public: |
- HUnaryCall(HValue* value, int argument_count) |
- : HCall<1>(argument_count) { |
- SetOperandAt(0, value); |
- } |
- |
- Representation RequiredInputRepresentation(int index) final { |
- return Representation::Tagged(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HValue* value() const { return OperandAt(0); } |
-}; |
- |
- |
-class HBinaryCall : public HCall<2> { |
- public: |
- HBinaryCall(HValue* first, HValue* second, int argument_count) |
- : HCall<2>(argument_count) { |
- SetOperandAt(0, first); |
- SetOperandAt(1, second); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) final { |
- return Representation::Tagged(); |
- } |
- |
- HValue* first() const { return OperandAt(0); } |
- HValue* second() const { return OperandAt(1); } |
-}; |
- |
- |
-class HCallJSFunction final : public HCall<1> { |
- public: |
- static HCallJSFunction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* function, int argument_count); |
- |
- HValue* function() const { return OperandAt(0); } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) final { |
- DCHECK(index == 0); |
- return Representation::Tagged(); |
- } |
- |
- bool HasStackCheck() final { return has_stack_check_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CallJSFunction) |
- |
- private: |
- // The argument count includes the receiver. |
- HCallJSFunction(HValue* function, |
- int argument_count, |
- bool has_stack_check) |
- : HCall<1>(argument_count), |
- has_stack_check_(has_stack_check) { |
- SetOperandAt(0, function); |
- } |
- |
- bool has_stack_check_; |
-}; |
- |
- |
-enum CallMode { NORMAL_CALL, TAIL_CALL }; |
- |
- |
-class HCallWithDescriptor final : public HInstruction { |
- public: |
- static HCallWithDescriptor* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* target, int argument_count, |
- CallInterfaceDescriptor descriptor, |
- const Vector<HValue*>& operands, |
- CallMode call_mode = NORMAL_CALL) { |
- HCallWithDescriptor* res = new (zone) HCallWithDescriptor( |
- target, argument_count, descriptor, operands, call_mode, zone); |
- DCHECK(operands.length() == res->GetParameterCount()); |
- return res; |
- } |
- |
- int OperandCount() const final { return values_.length(); } |
- HValue* OperandAt(int index) const final { return values_[index]; } |
- |
- Representation RequiredInputRepresentation(int index) final { |
- if (index == 0 || index == 1) { |
- // Target + context |
- return Representation::Tagged(); |
- } else { |
- int par_index = index - 2; |
- DCHECK(par_index < GetParameterCount()); |
- return RepresentationFromType(descriptor_.GetParameterType(par_index)); |
- } |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor) |
- |
- HType CalculateInferredType() final { return HType::Tagged(); } |
- |
- bool IsTailCall() const { return call_mode_ == TAIL_CALL; } |
- |
- virtual int argument_count() const { |
- return argument_count_; |
- } |
- |
- int argument_delta() const override { return -argument_count_; } |
- |
- CallInterfaceDescriptor descriptor() const { return descriptor_; } |
- |
- HValue* target() { |
- return OperandAt(0); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- private: |
- // The argument count includes the receiver. |
- HCallWithDescriptor(HValue* target, int argument_count, |
- CallInterfaceDescriptor descriptor, |
- const Vector<HValue*>& operands, CallMode call_mode, |
- Zone* zone) |
- : descriptor_(descriptor), |
- values_(GetParameterCount() + 1, zone), |
- argument_count_(argument_count), |
- call_mode_(call_mode) { |
- // We can only tail call without any stack arguments. |
- DCHECK(call_mode != TAIL_CALL || argument_count == 0); |
- AddOperand(target, zone); |
- for (int i = 0; i < operands.length(); i++) { |
- AddOperand(operands[i], zone); |
- } |
- this->set_representation(Representation::Tagged()); |
- this->SetAllSideEffects(); |
- } |
- |
- void AddOperand(HValue* v, Zone* zone) { |
- values_.Add(NULL, zone); |
- SetOperandAt(values_.length() - 1, v); |
- } |
- |
- int GetParameterCount() const { |
- return descriptor_.GetRegisterParameterCount() + 1; |
- } |
- |
- void InternalSetOperandAt(int index, HValue* value) final { |
- values_[index] = value; |
- } |
- |
- CallInterfaceDescriptor descriptor_; |
- ZoneList<HValue*> values_; |
- int argument_count_; |
- CallMode call_mode_; |
-}; |
- |
- |
-class HInvokeFunction final : public HBinaryCall { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int); |
- |
- HInvokeFunction(HValue* context, |
- HValue* function, |
- Handle<JSFunction> known_function, |
- int argument_count) |
- : HBinaryCall(context, function, argument_count), |
- known_function_(known_function) { |
- formal_parameter_count_ = |
- known_function.is_null() |
- ? 0 |
- : known_function->shared()->internal_formal_parameter_count(); |
- has_stack_check_ = !known_function.is_null() && |
- (known_function->code()->kind() == Code::FUNCTION || |
- known_function->code()->kind() == Code::OPTIMIZED_FUNCTION); |
- } |
- |
- static HInvokeFunction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* function, |
- Handle<JSFunction> known_function, |
- int argument_count) { |
- return new(zone) HInvokeFunction(context, function, |
- known_function, argument_count); |
- } |
- |
- HValue* context() { return first(); } |
- HValue* function() { return second(); } |
- Handle<JSFunction> known_function() { return known_function_; } |
- int formal_parameter_count() const { return formal_parameter_count_; } |
- |
- bool HasStackCheck() final { return has_stack_check_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(InvokeFunction) |
- |
- private: |
- HInvokeFunction(HValue* context, HValue* function, int argument_count) |
- : HBinaryCall(context, function, argument_count), |
- has_stack_check_(false) { |
- } |
- |
- Handle<JSFunction> known_function_; |
- int formal_parameter_count_; |
- bool has_stack_check_; |
-}; |
- |
- |
-class HCallFunction final : public HBinaryCall { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int); |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3( |
- HCallFunction, HValue*, int, CallFunctionFlags); |
- |
- HValue* context() const { return first(); } |
- HValue* function() const { return second(); } |
- CallFunctionFlags function_flags() const { return function_flags_; } |
- |
- FeedbackVectorSlot slot() const { return slot_; } |
- Handle<TypeFeedbackVector> feedback_vector() const { |
- return feedback_vector_; |
- } |
- bool HasVectorAndSlot() const { return !feedback_vector_.is_null(); } |
- void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, |
- FeedbackVectorSlot slot) { |
- feedback_vector_ = vector; |
- slot_ = slot; |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CallFunction) |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- int argument_delta() const override { return -argument_count(); } |
- |
- private: |
- HCallFunction(HValue* context, HValue* function, int argument_count, |
- CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS) |
- : HBinaryCall(context, function, argument_count), |
- function_flags_(flags) {} |
- CallFunctionFlags function_flags_; |
- Handle<TypeFeedbackVector> feedback_vector_; |
- FeedbackVectorSlot slot_; |
-}; |
- |
- |
-class HCallNew final : public HBinaryCall { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int); |
- |
- HValue* context() { return first(); } |
- HValue* constructor() { return second(); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CallNew) |
- |
- private: |
- HCallNew(HValue* context, HValue* constructor, int argument_count) |
- : HBinaryCall(context, constructor, argument_count) {} |
-}; |
- |
- |
-class HCallNewArray final : public HBinaryCall { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int, |
- ElementsKind, |
- Handle<AllocationSite>); |
- |
- HValue* context() { return first(); } |
- HValue* constructor() { return second(); } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- ElementsKind elements_kind() const { return elements_kind_; } |
- Handle<AllocationSite> site() const { return site_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CallNewArray) |
- |
- private: |
- HCallNewArray(HValue* context, HValue* constructor, int argument_count, |
- ElementsKind elements_kind, Handle<AllocationSite> site) |
- : HBinaryCall(context, constructor, argument_count), |
- elements_kind_(elements_kind), |
- site_(site) {} |
- |
- ElementsKind elements_kind_; |
- Handle<AllocationSite> site_; |
-}; |
- |
- |
-class HCallRuntime final : public HCall<1> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallRuntime, |
- const Runtime::Function*, int); |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HValue* context() { return OperandAt(0); } |
- const Runtime::Function* function() const { return c_function_; } |
- SaveFPRegsMode save_doubles() const { return save_doubles_; } |
- void set_save_doubles(SaveFPRegsMode save_doubles) { |
- save_doubles_ = save_doubles; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CallRuntime) |
- |
- private: |
- HCallRuntime(HValue* context, const Runtime::Function* c_function, |
- int argument_count) |
- : HCall<1>(argument_count), |
- c_function_(c_function), |
- save_doubles_(kDontSaveFPRegs) { |
- SetOperandAt(0, context); |
- } |
- |
- const Runtime::Function* c_function_; |
- SaveFPRegsMode save_doubles_; |
-}; |
- |
- |
-class HMapEnumLength final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(MapEnumLength) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- explicit HMapEnumLength(HValue* value) |
- : HUnaryOperation(value, HType::Smi()) { |
- set_representation(Representation::Smi()); |
- SetFlag(kUseGVN); |
- SetDependsOnFlag(kMaps); |
- } |
- |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HUnaryMathOperation final : public HTemplateInstruction<2> { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* value, BuiltinFunctionId op); |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* value() const { return OperandAt(1); } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- if (index == 0) { |
- return Representation::Tagged(); |
- } else { |
- switch (op_) { |
- case kMathFloor: |
- case kMathRound: |
- case kMathFround: |
- case kMathSqrt: |
- case kMathPowHalf: |
- case kMathLog: |
- case kMathExp: |
- return Representation::Double(); |
- case kMathAbs: |
- return representation(); |
- case kMathClz32: |
- return Representation::Integer32(); |
- default: |
- UNREACHABLE(); |
- return Representation::None(); |
- } |
- } |
- } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- HValue* Canonicalize() override; |
- Representation RepresentationFromUses() override; |
- Representation RepresentationFromInputs() override; |
- |
- BuiltinFunctionId op() const { return op_; } |
- const char* OpName() const; |
- |
- DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- HUnaryMathOperation* b = HUnaryMathOperation::cast(other); |
- return op_ == b->op(); |
- } |
- |
- private: |
- // Indicates if we support a double (and int32) output for Math.floor and |
- // Math.round. |
- bool SupportsFlexibleFloorAndRound() const { |
-#ifdef V8_TARGET_ARCH_ARM64 |
- // TODO(rmcilroy): Re-enable this for Arm64 once http://crbug.com/476477 is |
- // fixed. |
- return false; |
-#else |
- return false; |
-#endif |
- } |
- HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op) |
- : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, value); |
- switch (op) { |
- case kMathFloor: |
- case kMathRound: |
- if (SupportsFlexibleFloorAndRound()) { |
- SetFlag(kFlexibleRepresentation); |
- } else { |
- set_representation(Representation::Integer32()); |
- } |
- break; |
- case kMathClz32: |
- set_representation(Representation::Integer32()); |
- break; |
- case kMathAbs: |
- // Not setting representation here: it is None intentionally. |
- SetFlag(kFlexibleRepresentation); |
- // TODO(svenpanne) This flag is actually only needed if representation() |
- // is tagged, and not when it is an unboxed double or unboxed integer. |
- SetChangesFlag(kNewSpacePromotion); |
- break; |
- case kMathFround: |
- case kMathLog: |
- case kMathExp: |
- case kMathSqrt: |
- case kMathPowHalf: |
- set_representation(Representation::Double()); |
- break; |
- default: |
- UNREACHABLE(); |
- } |
- SetFlag(kUseGVN); |
- SetFlag(kAllowUndefinedAsNaN); |
- } |
- |
- bool IsDeletable() const override { |
- // TODO(crankshaft): This should be true, however the semantics of this |
- // instruction also include the ToNumber conversion that is mentioned in the |
- // spec, which is of course observable. |
- return false; |
- } |
- |
- HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv); |
- HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv); |
- |
- BuiltinFunctionId op_; |
-}; |
- |
- |
-class HLoadRoot final : public HTemplateInstruction<0> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex); |
- DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- Heap::RootListIndex index() const { return index_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(LoadRoot) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- HLoadRoot* b = HLoadRoot::cast(other); |
- return index_ == b->index_; |
- } |
- |
- private: |
- explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged()) |
- : HTemplateInstruction<0>(type), index_(index) { |
- SetFlag(kUseGVN); |
- // TODO(bmeurer): We'll need kDependsOnRoots once we add the |
- // corresponding HStoreRoot instruction. |
- SetDependsOnFlag(kCalls); |
- set_representation(Representation::Tagged()); |
- } |
- |
- bool IsDeletable() const override { return true; } |
- |
- const Heap::RootListIndex index_; |
-}; |
- |
- |
-class HCheckMaps final : public HTemplateInstruction<2> { |
- public: |
- static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* value, Handle<Map> map, |
- HValue* typecheck = NULL) { |
- return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>( |
- Unique<Map>::CreateImmovable(map), zone), typecheck); |
- } |
- static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* value, SmallMapList* map_list, |
- HValue* typecheck = NULL) { |
- UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone); |
- for (int i = 0; i < map_list->length(); ++i) { |
- maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone); |
- } |
- return new(zone) HCheckMaps(value, maps, typecheck); |
- } |
- |
- bool IsStabilityCheck() const { |
- return IsStabilityCheckField::decode(bit_field_); |
- } |
- void MarkAsStabilityCheck() { |
- bit_field_ = MapsAreStableField::encode(true) | |
- HasMigrationTargetField::encode(false) | |
- IsStabilityCheckField::encode(true); |
- ClearChangesFlag(kNewSpacePromotion); |
- ClearDependsOnFlag(kElementsKind); |
- ClearDependsOnFlag(kMaps); |
- } |
- |
- bool HasEscapingOperandAt(int index) override { return false; } |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HType CalculateInferredType() override { |
- if (value()->type().IsHeapObject()) return value()->type(); |
- return HType::HeapObject(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HValue* value() const { return OperandAt(0); } |
- HValue* typecheck() const { return OperandAt(1); } |
- |
- const UniqueSet<Map>* maps() const { return maps_; } |
- void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; } |
- |
- bool maps_are_stable() const { |
- return MapsAreStableField::decode(bit_field_); |
- } |
- |
- bool HasMigrationTarget() const { |
- return HasMigrationTargetField::decode(bit_field_); |
- } |
- |
- HValue* Canonicalize() override; |
- |
- static HCheckMaps* CreateAndInsertAfter(Zone* zone, |
- HValue* value, |
- Unique<Map> map, |
- bool map_is_stable, |
- HInstruction* instr) { |
- return instr->Append(new(zone) HCheckMaps( |
- value, new(zone) UniqueSet<Map>(map, zone), map_is_stable)); |
- } |
- |
- static HCheckMaps* CreateAndInsertBefore(Zone* zone, |
- HValue* value, |
- const UniqueSet<Map>* maps, |
- bool maps_are_stable, |
- HInstruction* instr) { |
- return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable)); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CheckMaps) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- return this->maps()->Equals(HCheckMaps::cast(other)->maps()); |
- } |
- |
- int RedefinedOperandIndex() override { return 0; } |
- |
- private: |
- HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable) |
- : HTemplateInstruction<2>(HType::HeapObject()), |
- maps_(maps), |
- bit_field_(HasMigrationTargetField::encode(false) | |
- IsStabilityCheckField::encode(false) | |
- MapsAreStableField::encode(maps_are_stable)) { |
- DCHECK_NE(0, maps->size()); |
- SetOperandAt(0, value); |
- // Use the object value for the dependency. |
- SetOperandAt(1, value); |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- SetDependsOnFlag(kMaps); |
- SetDependsOnFlag(kElementsKind); |
- } |
- |
- HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck) |
- : HTemplateInstruction<2>(HType::HeapObject()), |
- maps_(maps), |
- bit_field_(HasMigrationTargetField::encode(false) | |
- IsStabilityCheckField::encode(false) | |
- MapsAreStableField::encode(true)) { |
- DCHECK_NE(0, maps->size()); |
- SetOperandAt(0, value); |
- // Use the object value for the dependency if NULL is passed. |
- SetOperandAt(1, typecheck ? typecheck : value); |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- SetDependsOnFlag(kMaps); |
- SetDependsOnFlag(kElementsKind); |
- for (int i = 0; i < maps->size(); ++i) { |
- Handle<Map> map = maps->at(i).handle(); |
- if (map->is_migration_target()) { |
- bit_field_ = HasMigrationTargetField::update(bit_field_, true); |
- } |
- if (!map->is_stable()) { |
- bit_field_ = MapsAreStableField::update(bit_field_, false); |
- } |
- } |
- if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion); |
- } |
- |
- class HasMigrationTargetField : public BitField<bool, 0, 1> {}; |
- class IsStabilityCheckField : public BitField<bool, 1, 1> {}; |
- class MapsAreStableField : public BitField<bool, 2, 1> {}; |
- |
- const UniqueSet<Map>* maps_; |
- uint32_t bit_field_; |
-}; |
- |
- |
-class HCheckValue final : public HUnaryOperation { |
- public: |
- static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* value, Handle<JSFunction> func) { |
- bool in_new_space = isolate->heap()->InNewSpace(*func); |
- // NOTE: We create an uninitialized Unique and initialize it later. |
- // This is because a JSFunction can move due to GC during graph creation. |
- // TODO(titzer): This is a migration crutch. Replace with some kind of |
- // Uniqueness scope later. |
- Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func); |
- HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space); |
- return check; |
- } |
- static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* value, Unique<HeapObject> target, |
- bool object_in_new_space) { |
- return new(zone) HCheckValue(value, target, object_in_new_space); |
- } |
- |
- void FinalizeUniqueness() override { |
- object_ = Unique<HeapObject>(object_.handle()); |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HValue* Canonicalize() override; |
- |
-#ifdef DEBUG |
- void Verify() override; |
-#endif |
- |
- Unique<HeapObject> object() const { return object_; } |
- bool object_in_new_space() const { return object_in_new_space_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CheckValue) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- HCheckValue* b = HCheckValue::cast(other); |
- return object_ == b->object_; |
- } |
- |
- private: |
- HCheckValue(HValue* value, Unique<HeapObject> object, |
- bool object_in_new_space) |
- : HUnaryOperation(value, value->type()), |
- object_(object), |
- object_in_new_space_(object_in_new_space) { |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- } |
- |
- Unique<HeapObject> object_; |
- bool object_in_new_space_; |
-}; |
- |
- |
-class HCheckInstanceType final : public HUnaryOperation { |
- public: |
- enum Check { |
- IS_SPEC_OBJECT, |
- IS_JS_ARRAY, |
- IS_JS_DATE, |
- IS_STRING, |
- IS_INTERNALIZED_STRING, |
- LAST_INTERVAL_CHECK = IS_JS_DATE |
- }; |
- |
- DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check); |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HType CalculateInferredType() override { |
- switch (check_) { |
- case IS_SPEC_OBJECT: return HType::JSObject(); |
- case IS_JS_ARRAY: return HType::JSArray(); |
- case IS_JS_DATE: |
- return HType::JSObject(); |
- case IS_STRING: return HType::String(); |
- case IS_INTERNALIZED_STRING: return HType::String(); |
- } |
- UNREACHABLE(); |
- return HType::Tagged(); |
- } |
- |
- HValue* Canonicalize() override; |
- |
- bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; } |
- void GetCheckInterval(InstanceType* first, InstanceType* last); |
- void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag); |
- |
- Check check() const { return check_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType) |
- |
- protected: |
- // TODO(ager): It could be nice to allow the ommision of instance |
- // type checks if we have already performed an instance type check |
- // with a larger range. |
- bool DataEquals(HValue* other) override { |
- HCheckInstanceType* b = HCheckInstanceType::cast(other); |
- return check_ == b->check_; |
- } |
- |
- int RedefinedOperandIndex() override { return 0; } |
- |
- private: |
- const char* GetCheckName() const; |
- |
- HCheckInstanceType(HValue* value, Check check) |
- : HUnaryOperation(value, HType::HeapObject()), check_(check) { |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- } |
- |
- const Check check_; |
-}; |
- |
- |
-class HCheckSmi final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HValue* Canonicalize() override { |
- HType value_type = value()->type(); |
- if (value_type.IsSmi()) { |
- return NULL; |
- } |
- return this; |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CheckSmi) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) { |
- set_representation(Representation::Smi()); |
- SetFlag(kUseGVN); |
- } |
-}; |
- |
- |
-class HCheckArrayBufferNotNeutered final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HCheckArrayBufferNotNeutered, HValue*); |
- |
- bool HasEscapingOperandAt(int index) override { return false; } |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HType CalculateInferredType() override { |
- if (value()->type().IsHeapObject()) return value()->type(); |
- return HType::HeapObject(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- int RedefinedOperandIndex() override { return 0; } |
- |
- private: |
- explicit HCheckArrayBufferNotNeutered(HValue* value) |
- : HUnaryOperation(value) { |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- SetDependsOnFlag(kCalls); |
- } |
-}; |
- |
- |
-class HCheckHeapObject final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*); |
- |
- bool HasEscapingOperandAt(int index) override { return false; } |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HType CalculateInferredType() override { |
- if (value()->type().IsHeapObject()) return value()->type(); |
- return HType::HeapObject(); |
- } |
- |
-#ifdef DEBUG |
- void Verify() override; |
-#endif |
- |
- HValue* Canonicalize() override { |
- return value()->type().IsHeapObject() ? NULL : this; |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) { |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- } |
-}; |
- |
- |
-class InductionVariableData; |
- |
- |
-struct InductionVariableLimitUpdate { |
- InductionVariableData* updated_variable; |
- HValue* limit; |
- bool limit_is_upper; |
- bool limit_is_included; |
- |
- InductionVariableLimitUpdate() |
- : updated_variable(NULL), limit(NULL), |
- limit_is_upper(false), limit_is_included(false) {} |
-}; |
- |
- |
-class HBoundsCheck; |
-class HPhi; |
-class HBitwise; |
- |
- |
-class InductionVariableData final : public ZoneObject { |
- public: |
- class InductionVariableCheck : public ZoneObject { |
- public: |
- HBoundsCheck* check() { return check_; } |
- InductionVariableCheck* next() { return next_; } |
- bool HasUpperLimit() { return upper_limit_ >= 0; } |
- int32_t upper_limit() { |
- DCHECK(HasUpperLimit()); |
- return upper_limit_; |
- } |
- void set_upper_limit(int32_t upper_limit) { |
- upper_limit_ = upper_limit; |
- } |
- |
- bool processed() { return processed_; } |
- void set_processed() { processed_ = true; } |
- |
- InductionVariableCheck(HBoundsCheck* check, |
- InductionVariableCheck* next, |
- int32_t upper_limit = kNoLimit) |
- : check_(check), next_(next), upper_limit_(upper_limit), |
- processed_(false) {} |
- |
- private: |
- HBoundsCheck* check_; |
- InductionVariableCheck* next_; |
- int32_t upper_limit_; |
- bool processed_; |
- }; |
- |
- class ChecksRelatedToLength : public ZoneObject { |
- public: |
- HValue* length() { return length_; } |
- ChecksRelatedToLength* next() { return next_; } |
- InductionVariableCheck* checks() { return checks_; } |
- |
- void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); |
- void CloseCurrentBlock(); |
- |
- ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next) |
- : length_(length), next_(next), checks_(NULL), |
- first_check_in_block_(NULL), |
- added_index_(NULL), |
- added_constant_(NULL), |
- current_and_mask_in_block_(0), |
- current_or_mask_in_block_(0) {} |
- |
- private: |
- void UseNewIndexInCurrentBlock(Token::Value token, |
- int32_t mask, |
- HValue* index_base, |
- HValue* context); |
- |
- HBoundsCheck* first_check_in_block() { return first_check_in_block_; } |
- HBitwise* added_index() { return added_index_; } |
- void set_added_index(HBitwise* index) { added_index_ = index; } |
- HConstant* added_constant() { return added_constant_; } |
- void set_added_constant(HConstant* constant) { added_constant_ = constant; } |
- int32_t current_and_mask_in_block() { return current_and_mask_in_block_; } |
- int32_t current_or_mask_in_block() { return current_or_mask_in_block_; } |
- int32_t current_upper_limit() { return current_upper_limit_; } |
- |
- HValue* length_; |
- ChecksRelatedToLength* next_; |
- InductionVariableCheck* checks_; |
- |
- HBoundsCheck* first_check_in_block_; |
- HBitwise* added_index_; |
- HConstant* added_constant_; |
- int32_t current_and_mask_in_block_; |
- int32_t current_or_mask_in_block_; |
- int32_t current_upper_limit_; |
- }; |
- |
- struct LimitFromPredecessorBlock { |
- InductionVariableData* variable; |
- Token::Value token; |
- HValue* limit; |
- HBasicBlock* other_target; |
- |
- bool LimitIsValid() { return token != Token::ILLEGAL; } |
- |
- bool LimitIsIncluded() { |
- return Token::IsEqualityOp(token) || |
- token == Token::GTE || token == Token::LTE; |
- } |
- bool LimitIsUpper() { |
- return token == Token::LTE || token == Token::LT || token == Token::NE; |
- } |
- |
- LimitFromPredecessorBlock() |
- : variable(NULL), |
- token(Token::ILLEGAL), |
- limit(NULL), |
- other_target(NULL) {} |
- }; |
- |
- static const int32_t kNoLimit = -1; |
- |
- static InductionVariableData* ExaminePhi(HPhi* phi); |
- static void ComputeLimitFromPredecessorBlock( |
- HBasicBlock* block, |
- LimitFromPredecessorBlock* result); |
- static bool ComputeInductionVariableLimit( |
- HBasicBlock* block, |
- InductionVariableLimitUpdate* additional_limit); |
- |
- struct BitwiseDecompositionResult { |
- HValue* base; |
- int32_t and_mask; |
- int32_t or_mask; |
- HValue* context; |
- |
- BitwiseDecompositionResult() |
- : base(NULL), and_mask(0), or_mask(0), context(NULL) {} |
- }; |
- static void DecomposeBitwise(HValue* value, |
- BitwiseDecompositionResult* result); |
- |
- void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); |
- |
- bool CheckIfBranchIsLoopGuard(Token::Value token, |
- HBasicBlock* current_branch, |
- HBasicBlock* other_branch); |
- |
- void UpdateAdditionalLimit(InductionVariableLimitUpdate* update); |
- |
- HPhi* phi() { return phi_; } |
- HValue* base() { return base_; } |
- int32_t increment() { return increment_; } |
- HValue* limit() { return limit_; } |
- bool limit_included() { return limit_included_; } |
- HBasicBlock* limit_validity() { return limit_validity_; } |
- HBasicBlock* induction_exit_block() { return induction_exit_block_; } |
- HBasicBlock* induction_exit_target() { return induction_exit_target_; } |
- ChecksRelatedToLength* checks() { return checks_; } |
- HValue* additional_upper_limit() { return additional_upper_limit_; } |
- bool additional_upper_limit_is_included() { |
- return additional_upper_limit_is_included_; |
- } |
- HValue* additional_lower_limit() { return additional_lower_limit_; } |
- bool additional_lower_limit_is_included() { |
- return additional_lower_limit_is_included_; |
- } |
- |
- bool LowerLimitIsNonNegativeConstant() { |
- if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) { |
- return true; |
- } |
- if (additional_lower_limit() != NULL && |
- additional_lower_limit()->IsInteger32Constant() && |
- additional_lower_limit()->GetInteger32Constant() >= 0) { |
- // Ignoring the corner case of !additional_lower_limit_is_included() |
- // is safe, handling it adds unneeded complexity. |
- return true; |
- } |
- return false; |
- } |
- |
- int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask); |
- |
- private: |
- template <class T> void swap(T* a, T* b) { |
- T c(*a); |
- *a = *b; |
- *b = c; |
- } |
- |
- InductionVariableData(HPhi* phi, HValue* base, int32_t increment) |
- : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment), |
- limit_(NULL), limit_included_(false), limit_validity_(NULL), |
- induction_exit_block_(NULL), induction_exit_target_(NULL), |
- checks_(NULL), |
- additional_upper_limit_(NULL), |
- additional_upper_limit_is_included_(false), |
- additional_lower_limit_(NULL), |
- additional_lower_limit_is_included_(false) {} |
- |
- static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand); |
- |
- static HValue* IgnoreOsrValue(HValue* v); |
- static InductionVariableData* GetInductionVariableData(HValue* v); |
- |
- HPhi* phi_; |
- HValue* base_; |
- int32_t increment_; |
- HValue* limit_; |
- bool limit_included_; |
- HBasicBlock* limit_validity_; |
- HBasicBlock* induction_exit_block_; |
- HBasicBlock* induction_exit_target_; |
- ChecksRelatedToLength* checks_; |
- HValue* additional_upper_limit_; |
- bool additional_upper_limit_is_included_; |
- HValue* additional_lower_limit_; |
- bool additional_lower_limit_is_included_; |
-}; |
- |
- |
-class HPhi final : public HValue { |
- public: |
- HPhi(int merged_index, Zone* zone) |
- : inputs_(2, zone), merged_index_(merged_index) { |
- DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex); |
- SetFlag(kFlexibleRepresentation); |
- SetFlag(kAllowUndefinedAsNaN); |
- } |
- |
- Representation RepresentationFromInputs() override; |
- |
- Range* InferRange(Zone* zone) override; |
- virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; |
- Representation RequiredInputRepresentation(int index) override { |
- return representation(); |
- } |
- Representation KnownOptimalRepresentation() override { |
- return representation(); |
- } |
- HType CalculateInferredType() override; |
- int OperandCount() const override { return inputs_.length(); } |
- HValue* OperandAt(int index) const override { return inputs_[index]; } |
- HValue* GetRedundantReplacement(); |
- void AddInput(HValue* value); |
- bool HasRealUses(); |
- |
- bool IsReceiver() const { return merged_index_ == 0; } |
- bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; } |
- |
- SourcePosition position() const override; |
- |
- int merged_index() const { return merged_index_; } |
- |
- InductionVariableData* induction_variable_data() { |
- return induction_variable_data_; |
- } |
- bool IsInductionVariable() { |
- return induction_variable_data_ != NULL; |
- } |
- bool IsLimitedInductionVariable() { |
- return IsInductionVariable() && |
- induction_variable_data_->limit() != NULL; |
- } |
- void DetectInductionVariable() { |
- DCHECK(induction_variable_data_ == NULL); |
- induction_variable_data_ = InductionVariableData::ExaminePhi(this); |
- } |
- |
- std::ostream& PrintTo(std::ostream& os) const override; // NOLINT |
- |
-#ifdef DEBUG |
- void Verify() override; |
-#endif |
- |
- void InitRealUses(int id); |
- void AddNonPhiUsesFrom(HPhi* other); |
- |
- Representation representation_from_indirect_uses() const { |
- return representation_from_indirect_uses_; |
- } |
- |
- bool has_type_feedback_from_uses() const { |
- return has_type_feedback_from_uses_; |
- } |
- |
- int phi_id() { return phi_id_; } |
- |
- static HPhi* cast(HValue* value) { |
- DCHECK(value->IsPhi()); |
- return reinterpret_cast<HPhi*>(value); |
- } |
- Opcode opcode() const override { return HValue::kPhi; } |
- |
- void SimplifyConstantInputs(); |
- |
- // Marker value representing an invalid merge index. |
- static const int kInvalidMergedIndex = -1; |
- |
- protected: |
- void DeleteFromGraph() override; |
- void InternalSetOperandAt(int index, HValue* value) override { |
- inputs_[index] = value; |
- } |
- |
- private: |
- Representation representation_from_non_phi_uses() const { |
- return representation_from_non_phi_uses_; |
- } |
- |
- ZoneList<HValue*> inputs_; |
- int merged_index_ = 0; |
- |
- int phi_id_ = -1; |
- InductionVariableData* induction_variable_data_ = nullptr; |
- |
- Representation representation_from_indirect_uses_ = Representation::None(); |
- Representation representation_from_non_phi_uses_ = Representation::None(); |
- bool has_type_feedback_from_uses_ = false; |
- |
- // TODO(titzer): we can't eliminate the receiver for generating backtraces |
- bool IsDeletable() const override { return !IsReceiver(); } |
-}; |
- |
- |
-// Common base class for HArgumentsObject and HCapturedObject. |
-class HDematerializedObject : public HInstruction { |
- public: |
- HDematerializedObject(int count, Zone* zone) : values_(count, zone) {} |
- |
- int OperandCount() const final { return values_.length(); } |
- HValue* OperandAt(int index) const final { return values_[index]; } |
- |
- bool HasEscapingOperandAt(int index) final { return false; } |
- Representation RequiredInputRepresentation(int index) final { |
- return Representation::None(); |
- } |
- |
- protected: |
- void InternalSetOperandAt(int index, HValue* value) final { |
- values_[index] = value; |
- } |
- |
- // List of values tracked by this marker. |
- ZoneList<HValue*> values_; |
-}; |
- |
- |
-class HArgumentsObject final : public HDematerializedObject { |
- public: |
- static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context, |
- int count) { |
- return new(zone) HArgumentsObject(count, zone); |
- } |
- |
- // The values contain a list of all elements in the arguments object |
- // including the receiver object, which is skipped when materializing. |
- const ZoneList<HValue*>* arguments_values() const { return &values_; } |
- int arguments_count() const { return values_.length(); } |
- |
- void AddArgument(HValue* argument, Zone* zone) { |
- values_.Add(NULL, zone); // Resize list. |
- SetOperandAt(values_.length() - 1, argument); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject) |
- |
- private: |
- HArgumentsObject(int count, Zone* zone) |
- : HDematerializedObject(count, zone) { |
- set_representation(Representation::Tagged()); |
- SetFlag(kIsArguments); |
- } |
-}; |
- |
- |
-class HCapturedObject final : public HDematerializedObject { |
- public: |
- HCapturedObject(int length, int id, Zone* zone) |
- : HDematerializedObject(length, zone), capture_id_(id) { |
- set_representation(Representation::Tagged()); |
- values_.AddBlock(NULL, length, zone); // Resize list. |
- } |
- |
- // The values contain a list of all in-object properties inside the |
- // captured object and is index by field index. Properties in the |
- // properties or elements backing store are not tracked here. |
- const ZoneList<HValue*>* values() const { return &values_; } |
- int length() const { return values_.length(); } |
- int capture_id() const { return capture_id_; } |
- |
- // Shortcut for the map value of this captured object. |
- HValue* map_value() const { return values()->first(); } |
- |
- void ReuseSideEffectsFromStore(HInstruction* store) { |
- DCHECK(store->HasObservableSideEffects()); |
- DCHECK(store->IsStoreNamedField()); |
- changes_flags_.Add(store->ChangesFlags()); |
- } |
- |
- // Replay effects of this instruction on the given environment. |
- void ReplayEnvironment(HEnvironment* env); |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(CapturedObject) |
- |
- private: |
- int capture_id_; |
- |
- // Note that we cannot DCE captured objects as they are used to replay |
- // the environment. This method is here as an explicit reminder. |
- // TODO(mstarzinger): Turn HSimulates into full snapshots maybe? |
- bool IsDeletable() const final { return false; } |
-}; |
- |
- |
-class HConstant final : public HTemplateInstruction<0> { |
- public: |
- enum Special { kHoleNaN }; |
- |
- DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special); |
- DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t); |
- DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation); |
- DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double); |
- DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>); |
- DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference); |
- |
- static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone, |
- HValue* context, int32_t value, |
- Representation representation, |
- HInstruction* instruction) { |
- return instruction->Append( |
- HConstant::New(isolate, zone, context, value, representation)); |
- } |
- |
- Handle<Map> GetMonomorphicJSObjectMap() override { |
- Handle<Object> object = object_.handle(); |
- if (!object.is_null() && object->IsHeapObject()) { |
- return v8::internal::handle(HeapObject::cast(*object)->map()); |
- } |
- return Handle<Map>(); |
- } |
- |
- static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone, |
- HValue* context, int32_t value, |
- Representation representation, |
- HInstruction* instruction) { |
- return instruction->Prepend( |
- HConstant::New(isolate, zone, context, value, representation)); |
- } |
- |
- static HConstant* CreateAndInsertBefore(Zone* zone, |
- Unique<Map> map, |
- bool map_is_stable, |
- HInstruction* instruction) { |
- return instruction->Prepend(new(zone) HConstant( |
- map, Unique<Map>(Handle<Map>::null()), map_is_stable, |
- Representation::Tagged(), HType::HeapObject(), true, |
- false, false, MAP_TYPE)); |
- } |
- |
- static HConstant* CreateAndInsertAfter(Zone* zone, |
- Unique<Map> map, |
- bool map_is_stable, |
- HInstruction* instruction) { |
- return instruction->Append(new(zone) HConstant( |
- map, Unique<Map>(Handle<Map>::null()), map_is_stable, |
- Representation::Tagged(), HType::HeapObject(), true, |
- false, false, MAP_TYPE)); |
- } |
- |
- Handle<Object> handle(Isolate* isolate) { |
- if (object_.handle().is_null()) { |
- // Default arguments to is_not_in_new_space depend on this heap number |
- // to be tenured so that it's guaranteed not to be located in new space. |
- object_ = Unique<Object>::CreateUninitialized( |
- isolate->factory()->NewNumber(double_value_, TENURED)); |
- } |
- AllowDeferredHandleDereference smi_check; |
- DCHECK(HasInteger32Value() || !object_.handle()->IsSmi()); |
- return object_.handle(); |
- } |
- |
- bool IsSpecialDouble() const { |
- return HasDoubleValue() && |
- (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) || |
- std::isnan(double_value_)); |
- } |
- |
- bool NotInNewSpace() const { |
- return IsNotInNewSpaceField::decode(bit_field_); |
- } |
- |
- bool ImmortalImmovable() const; |
- |
- bool IsCell() const { |
- InstanceType instance_type = GetInstanceType(); |
- return instance_type == CELL_TYPE; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- Representation KnownOptimalRepresentation() override { |
- if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi(); |
- if (HasInteger32Value()) return Representation::Integer32(); |
- if (HasNumberValue()) return Representation::Double(); |
- if (HasExternalReferenceValue()) return Representation::External(); |
- return Representation::Tagged(); |
- } |
- |
- bool EmitAtUses() override; |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- HConstant* CopyToRepresentation(Representation r, Zone* zone) const; |
- Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone); |
- Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone); |
- bool HasInteger32Value() const { |
- return HasInt32ValueField::decode(bit_field_); |
- } |
- int32_t Integer32Value() const { |
- DCHECK(HasInteger32Value()); |
- return int32_value_; |
- } |
- bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); } |
- bool HasDoubleValue() const { |
- return HasDoubleValueField::decode(bit_field_); |
- } |
- double DoubleValue() const { |
- DCHECK(HasDoubleValue()); |
- return double_value_; |
- } |
- uint64_t DoubleValueAsBits() const { |
- uint64_t bits; |
- DCHECK(HasDoubleValue()); |
- STATIC_ASSERT(sizeof(bits) == sizeof(double_value_)); |
- std::memcpy(&bits, &double_value_, sizeof(bits)); |
- return bits; |
- } |
- bool IsTheHole() const { |
- if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) { |
- return true; |
- } |
- return object_.IsInitialized() && |
- object_.IsKnownGlobal(isolate()->heap()->the_hole_value()); |
- } |
- bool HasNumberValue() const { return HasDoubleValue(); } |
- int32_t NumberValueAsInteger32() const { |
- DCHECK(HasNumberValue()); |
- // Irrespective of whether a numeric HConstant can be safely |
- // represented as an int32, we store the (in some cases lossy) |
- // representation of the number in int32_value_. |
- return int32_value_; |
- } |
- bool HasStringValue() const { |
- if (HasNumberValue()) return false; |
- DCHECK(!object_.handle().is_null()); |
- return GetInstanceType() < FIRST_NONSTRING_TYPE; |
- } |
- Handle<String> StringValue() const { |
- DCHECK(HasStringValue()); |
- return Handle<String>::cast(object_.handle()); |
- } |
- bool HasInternalizedStringValue() const { |
- return HasStringValue() && StringShape(GetInstanceType()).IsInternalized(); |
- } |
- |
- bool HasExternalReferenceValue() const { |
- return HasExternalReferenceValueField::decode(bit_field_); |
- } |
- ExternalReference ExternalReferenceValue() const { |
- return external_reference_value_; |
- } |
- |
- bool HasBooleanValue() const { return type_.IsBoolean(); } |
- bool BooleanValue() const { return BooleanValueField::decode(bit_field_); } |
- bool IsCallable() const { return IsCallableField::decode(bit_field_); } |
- bool IsUndetectable() const { |
- return IsUndetectableField::decode(bit_field_); |
- } |
- InstanceType GetInstanceType() const { |
- return InstanceTypeField::decode(bit_field_); |
- } |
- |
- bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; } |
- Unique<Map> MapValue() const { |
- DCHECK(HasMapValue()); |
- return Unique<Map>::cast(GetUnique()); |
- } |
- bool HasStableMapValue() const { |
- DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_)); |
- return HasStableMapValueField::decode(bit_field_); |
- } |
- |
- bool HasObjectMap() const { return !object_map_.IsNull(); } |
- Unique<Map> ObjectMap() const { |
- DCHECK(HasObjectMap()); |
- return object_map_; |
- } |
- |
- intptr_t Hashcode() override { |
- if (HasInteger32Value()) { |
- return static_cast<intptr_t>(int32_value_); |
- } else if (HasDoubleValue()) { |
- uint64_t bits = DoubleValueAsBits(); |
- if (sizeof(bits) > sizeof(intptr_t)) { |
- bits ^= (bits >> 32); |
- } |
- return static_cast<intptr_t>(bits); |
- } else if (HasExternalReferenceValue()) { |
- return reinterpret_cast<intptr_t>(external_reference_value_.address()); |
- } else { |
- DCHECK(!object_.handle().is_null()); |
- return object_.Hashcode(); |
- } |
- } |
- |
- void FinalizeUniqueness() override { |
- if (!HasDoubleValue() && !HasExternalReferenceValue()) { |
- DCHECK(!object_.handle().is_null()); |
- object_ = Unique<Object>(object_.handle()); |
- } |
- } |
- |
- Unique<Object> GetUnique() const { |
- return object_; |
- } |
- |
- bool EqualsUnique(Unique<Object> other) const { |
- return object_.IsInitialized() && object_ == other; |
- } |
- |
- bool DataEquals(HValue* other) override { |
- HConstant* other_constant = HConstant::cast(other); |
- if (HasInteger32Value()) { |
- return other_constant->HasInteger32Value() && |
- int32_value_ == other_constant->int32_value_; |
- } else if (HasDoubleValue()) { |
- return other_constant->HasDoubleValue() && |
- std::memcmp(&double_value_, &other_constant->double_value_, |
- sizeof(double_value_)) == 0; |
- } else if (HasExternalReferenceValue()) { |
- return other_constant->HasExternalReferenceValue() && |
- external_reference_value_ == |
- other_constant->external_reference_value_; |
- } else { |
- if (other_constant->HasInteger32Value() || |
- other_constant->HasDoubleValue() || |
- other_constant->HasExternalReferenceValue()) { |
- return false; |
- } |
- DCHECK(!object_.handle().is_null()); |
- return other_constant->object_ == object_; |
- } |
- } |
- |
-#ifdef DEBUG |
- void Verify() override {} |
-#endif |
- |
- DECLARE_CONCRETE_INSTRUCTION(Constant) |
- |
- protected: |
- Range* InferRange(Zone* zone) override; |
- |
- private: |
- friend class HGraph; |
- explicit HConstant(Special special); |
- explicit HConstant(Handle<Object> handle, |
- Representation r = Representation::None()); |
- HConstant(int32_t value, |
- Representation r = Representation::None(), |
- bool is_not_in_new_space = true, |
- Unique<Object> optional = Unique<Object>(Handle<Object>::null())); |
- HConstant(double value, |
- Representation r = Representation::None(), |
- bool is_not_in_new_space = true, |
- Unique<Object> optional = Unique<Object>(Handle<Object>::null())); |
- 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); |
- |
- explicit HConstant(ExternalReference reference); |
- |
- void Initialize(Representation r); |
- |
- bool IsDeletable() const override { return true; } |
- |
- // If object_ is a map, this indicates whether the map is stable. |
- class HasStableMapValueField : public BitField<bool, 0, 1> {}; |
- |
- // We store the HConstant in the most specific form safely possible. |
- // These flags tell us if the respective member fields hold valid, safe |
- // representations of the constant. More specific flags imply more general |
- // flags, but not the converse (i.e. smi => int32 => double). |
- class HasSmiValueField : public BitField<bool, 1, 1> {}; |
- class HasInt32ValueField : public BitField<bool, 2, 1> {}; |
- class HasDoubleValueField : public BitField<bool, 3, 1> {}; |
- |
- class HasExternalReferenceValueField : public BitField<bool, 4, 1> {}; |
- class IsNotInNewSpaceField : public BitField<bool, 5, 1> {}; |
- class BooleanValueField : public BitField<bool, 6, 1> {}; |
- class IsUndetectableField : public BitField<bool, 7, 1> {}; |
- class IsCallableField : public BitField<bool, 8, 1> {}; |
- |
- static const InstanceType kUnknownInstanceType = FILLER_TYPE; |
- class InstanceTypeField : public BitField<InstanceType, 16, 8> {}; |
- |
- // If this is a numerical constant, object_ either points to the |
- // HeapObject the constant originated from or is null. If the |
- // constant is non-numeric, object_ always points to a valid |
- // constant HeapObject. |
- Unique<Object> object_; |
- |
- // If object_ is a heap object, this points to the stable map of the object. |
- Unique<Map> object_map_; |
- |
- uint32_t bit_field_; |
- |
- int32_t int32_value_; |
- double double_value_; |
- ExternalReference external_reference_value_; |
-}; |
- |
- |
-class HBinaryOperation : public HTemplateInstruction<3> { |
- public: |
- HBinaryOperation(HValue* context, HValue* left, HValue* right, |
- Strength strength, HType type = HType::Tagged()) |
- : HTemplateInstruction<3>(type), |
- strength_(strength), |
- observed_output_representation_(Representation::None()) { |
- DCHECK(left != NULL && right != NULL); |
- SetOperandAt(0, context); |
- SetOperandAt(1, left); |
- SetOperandAt(2, right); |
- observed_input_representation_[0] = Representation::None(); |
- observed_input_representation_[1] = Representation::None(); |
- } |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* left() const { return OperandAt(1); } |
- HValue* right() const { return OperandAt(2); } |
- Strength strength() const { return strength_; } |
- |
- // True if switching left and right operands likely generates better code. |
- bool AreOperandsBetterSwitched() { |
- if (!IsCommutative()) return false; |
- |
- // Constant operands are better off on the right, they can be inlined in |
- // many situations on most platforms. |
- if (left()->IsConstant()) return true; |
- if (right()->IsConstant()) return false; |
- |
- // Otherwise, if there is only one use of the right operand, it would be |
- // better off on the left for platforms that only have 2-arg arithmetic |
- // ops (e.g ia32, x64) that clobber the left operand. |
- return right()->HasOneUse(); |
- } |
- |
- HValue* BetterLeftOperand() { |
- return AreOperandsBetterSwitched() ? right() : left(); |
- } |
- |
- HValue* BetterRightOperand() { |
- return AreOperandsBetterSwitched() ? left() : right(); |
- } |
- |
- void set_observed_input_representation(int index, Representation rep) { |
- DCHECK(index >= 1 && index <= 2); |
- observed_input_representation_[index - 1] = rep; |
- } |
- |
- virtual void initialize_output_representation(Representation observed) { |
- observed_output_representation_ = observed; |
- } |
- |
- Representation observed_input_representation(int index) override { |
- if (index == 0) return Representation::Tagged(); |
- return observed_input_representation_[index - 1]; |
- } |
- |
- virtual void UpdateRepresentation(Representation new_rep, |
- HInferRepresentationPhase* h_infer, |
- const char* reason) override { |
- Representation rep = !FLAG_smi_binop && new_rep.IsSmi() |
- ? Representation::Integer32() : new_rep; |
- HValue::UpdateRepresentation(rep, h_infer, reason); |
- } |
- |
- virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; |
- Representation RepresentationFromInputs() override; |
- Representation RepresentationFromOutput(); |
- void AssumeRepresentation(Representation r) override; |
- |
- virtual bool IsCommutative() const { return false; } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- if (index == 0) return Representation::Tagged(); |
- return representation(); |
- } |
- |
- void SetOperandPositions(Zone* zone, SourcePosition left_pos, |
- SourcePosition right_pos) { |
- set_operand_position(zone, 1, left_pos); |
- set_operand_position(zone, 2, right_pos); |
- } |
- |
- bool RightIsPowerOf2() { |
- if (!right()->IsInteger32Constant()) return false; |
- int32_t value = right()->GetInteger32Constant(); |
- if (value < 0) { |
- return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value)); |
- } |
- return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value)); |
- } |
- |
- Strength strength() { return strength_; } |
- |
- DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation) |
- |
- private: |
- bool IgnoreObservedOutputRepresentation(Representation current_rep); |
- Strength strength_; |
- |
- Representation observed_input_representation_[2]; |
- Representation observed_output_representation_; |
-}; |
- |
- |
-class HWrapReceiver final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*); |
- |
- bool DataEquals(HValue* other) override { return true; } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HValue* receiver() const { return OperandAt(0); } |
- HValue* function() const { return OperandAt(1); } |
- |
- HValue* Canonicalize() override; |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- bool known_function() const { return known_function_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(WrapReceiver) |
- |
- private: |
- HWrapReceiver(HValue* receiver, HValue* function) { |
- known_function_ = function->IsConstant() && |
- HConstant::cast(function)->handle(function->isolate())->IsJSFunction(); |
- set_representation(Representation::Tagged()); |
- SetOperandAt(0, receiver); |
- SetOperandAt(1, function); |
- SetFlag(kUseGVN); |
- } |
- |
- bool known_function_; |
-}; |
- |
- |
-class HApplyArguments final : public HTemplateInstruction<4> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*, |
- HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- // The length is untagged, all other inputs are tagged. |
- return (index == 2) |
- ? Representation::Integer32() |
- : Representation::Tagged(); |
- } |
- |
- HValue* function() { return OperandAt(0); } |
- HValue* receiver() { return OperandAt(1); } |
- HValue* length() { return OperandAt(2); } |
- HValue* elements() { return OperandAt(3); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(ApplyArguments) |
- |
- private: |
- HApplyArguments(HValue* function, |
- HValue* receiver, |
- HValue* length, |
- HValue* elements) { |
- set_representation(Representation::Tagged()); |
- SetOperandAt(0, function); |
- SetOperandAt(1, receiver); |
- SetOperandAt(2, length); |
- SetOperandAt(3, elements); |
- SetAllSideEffects(); |
- } |
-}; |
- |
- |
-class HArgumentsElements final : public HTemplateInstruction<0> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool); |
- |
- DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements) |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- bool from_inlined() const { return from_inlined_; } |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) { |
- // The value produced by this instruction is a pointer into the stack |
- // that looks as if it was a smi because of alignment. |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- } |
- |
- bool IsDeletable() const override { return true; } |
- |
- bool from_inlined_; |
-}; |
- |
- |
-class HArgumentsLength final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) { |
- set_representation(Representation::Integer32()); |
- SetFlag(kUseGVN); |
- } |
- |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HAccessArgumentsAt final : public HTemplateInstruction<3> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*); |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- // The arguments elements is considered tagged. |
- return index == 0 |
- ? Representation::Tagged() |
- : Representation::Integer32(); |
- } |
- |
- HValue* arguments() const { return OperandAt(0); } |
- HValue* length() const { return OperandAt(1); } |
- HValue* index() const { return OperandAt(2); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt) |
- |
- private: |
- HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) { |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- SetOperandAt(0, arguments); |
- SetOperandAt(1, length); |
- SetOperandAt(2, index); |
- } |
- |
- bool DataEquals(HValue* other) override { return true; } |
-}; |
- |
- |
-class HBoundsCheckBaseIndexInformation; |
- |
- |
-class HBoundsCheck final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*); |
- |
- bool skip_check() const { return skip_check_; } |
- void set_skip_check() { skip_check_ = true; } |
- |
- HValue* base() const { return base_; } |
- int offset() const { return offset_; } |
- int scale() const { return scale_; } |
- |
- void ApplyIndexChange(); |
- bool DetectCompoundIndex() { |
- DCHECK(base() == NULL); |
- |
- DecompositionResult decomposition; |
- if (index()->TryDecompose(&decomposition)) { |
- base_ = decomposition.base(); |
- offset_ = decomposition.offset(); |
- scale_ = decomposition.scale(); |
- return true; |
- } else { |
- base_ = index(); |
- offset_ = 0; |
- scale_ = 0; |
- return false; |
- } |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return representation(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; |
- |
- HValue* index() const { return OperandAt(0); } |
- HValue* length() const { return OperandAt(1); } |
- bool allow_equality() const { return allow_equality_; } |
- void set_allow_equality(bool v) { allow_equality_ = v; } |
- |
- int RedefinedOperandIndex() override { return 0; } |
- bool IsPurelyInformativeDefinition() override { return skip_check(); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(BoundsCheck) |
- |
- protected: |
- friend class HBoundsCheckBaseIndexInformation; |
- |
- Range* InferRange(Zone* zone) override; |
- |
- bool DataEquals(HValue* other) override { return true; } |
- bool skip_check_; |
- HValue* base_; |
- int offset_; |
- int scale_; |
- bool allow_equality_; |
- |
- private: |
- // Normally HBoundsCheck should be created using the |
- // HGraphBuilder::AddBoundsCheck() helper. |
- // However when building stubs, where we know that the arguments are Int32, |
- // it makes sense to invoke this constructor directly. |
- HBoundsCheck(HValue* index, HValue* length) |
- : skip_check_(false), |
- base_(NULL), offset_(0), scale_(0), |
- allow_equality_(false) { |
- SetOperandAt(0, index); |
- SetOperandAt(1, length); |
- SetFlag(kFlexibleRepresentation); |
- SetFlag(kUseGVN); |
- } |
- |
- bool IsDeletable() const override { return skip_check() && !FLAG_debug_code; } |
-}; |
- |
- |
-class HBoundsCheckBaseIndexInformation final : public HTemplateInstruction<2> { |
- public: |
- explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) { |
- DecompositionResult decomposition; |
- if (check->index()->TryDecompose(&decomposition)) { |
- SetOperandAt(0, decomposition.base()); |
- SetOperandAt(1, check); |
- } else { |
- UNREACHABLE(); |
- } |
- } |
- |
- HValue* base_index() const { return OperandAt(0); } |
- HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation) |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return representation(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- int RedefinedOperandIndex() override { return 0; } |
- bool IsPurelyInformativeDefinition() override { return true; } |
-}; |
- |
- |
-class HBitwiseBinaryOperation : public HBinaryOperation { |
- public: |
- HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right, |
- Strength strength, HType type = HType::TaggedNumber()) |
- : HBinaryOperation(context, left, right, strength, type) { |
- SetFlag(kFlexibleRepresentation); |
- SetFlag(kTruncatingToInt32); |
- if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN); |
- SetAllSideEffects(); |
- } |
- |
- void RepresentationChanged(Representation to) override { |
- if (to.IsTagged() && |
- (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) { |
- SetAllSideEffects(); |
- ClearFlag(kUseGVN); |
- } else { |
- ClearAllSideEffects(); |
- SetFlag(kUseGVN); |
- } |
- if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion); |
- } |
- |
- virtual void UpdateRepresentation(Representation new_rep, |
- HInferRepresentationPhase* h_infer, |
- const char* reason) override { |
- // We only generate either int32 or generic tagged bitwise operations. |
- if (new_rep.IsDouble()) new_rep = Representation::Integer32(); |
- HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); |
- } |
- |
- Representation observed_input_representation(int index) override { |
- Representation r = HBinaryOperation::observed_input_representation(index); |
- if (r.IsDouble()) return Representation::Integer32(); |
- return r; |
- } |
- |
- virtual void initialize_output_representation( |
- Representation observed) override { |
- if (observed.IsDouble()) observed = Representation::Integer32(); |
- HBinaryOperation::initialize_output_representation(observed); |
- } |
- |
- DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation) |
- |
- private: |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HMathFloorOfDiv final : public HBinaryOperation { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv, |
- HValue*, |
- HValue*); |
- |
- DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- HMathFloorOfDiv(HValue* context, HValue* left, HValue* right) |
- : HBinaryOperation(context, left, right, Strength::WEAK) { |
- set_representation(Representation::Integer32()); |
- SetFlag(kUseGVN); |
- SetFlag(kCanOverflow); |
- SetFlag(kCanBeDivByZero); |
- SetFlag(kLeftCanBeMinInt); |
- SetFlag(kLeftCanBeNegative); |
- SetFlag(kLeftCanBePositive); |
- SetFlag(kAllowUndefinedAsNaN); |
- } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HArithmeticBinaryOperation : public HBinaryOperation { |
- public: |
- HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right, |
- Strength strength) |
- : HBinaryOperation(context, left, right, strength, |
- HType::TaggedNumber()) { |
- SetAllSideEffects(); |
- SetFlag(kFlexibleRepresentation); |
- if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN); |
- } |
- |
- void RepresentationChanged(Representation to) override { |
- if (to.IsTagged() && |
- (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) { |
- SetAllSideEffects(); |
- ClearFlag(kUseGVN); |
- } else { |
- ClearAllSideEffects(); |
- SetFlag(kUseGVN); |
- } |
- if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion); |
- } |
- |
- DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation) |
- |
- private: |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HCompareGeneric final : public HBinaryOperation { |
- public: |
- static HCompareGeneric* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, Token::Value token, |
- Strength strength = Strength::WEAK) { |
- return new (zone) HCompareGeneric(context, left, right, token, strength); |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return index == 0 |
- ? Representation::Tagged() |
- : representation(); |
- } |
- |
- Token::Value token() const { return token_; } |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(CompareGeneric) |
- |
- private: |
- HCompareGeneric(HValue* context, HValue* left, HValue* right, |
- Token::Value token, Strength strength) |
- : HBinaryOperation(context, left, right, strength, HType::Boolean()), |
- token_(token) { |
- DCHECK(Token::IsCompareOp(token)); |
- set_representation(Representation::Tagged()); |
- SetAllSideEffects(); |
- } |
- |
- Token::Value token_; |
-}; |
- |
- |
-class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> { |
- public: |
- static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone, |
- HValue* context, HValue* left, |
- HValue* right, Token::Value token, |
- HBasicBlock* true_target = NULL, |
- HBasicBlock* false_target = NULL, |
- Strength strength = Strength::WEAK) { |
- return new (zone) HCompareNumericAndBranch(left, right, token, true_target, |
- false_target, strength); |
- } |
- static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone, |
- HValue* context, HValue* left, |
- HValue* right, Token::Value token, |
- Strength strength) { |
- return new (zone) |
- HCompareNumericAndBranch(left, right, token, NULL, NULL, strength); |
- } |
- |
- HValue* left() const { return OperandAt(0); } |
- HValue* right() const { return OperandAt(1); } |
- Token::Value token() const { return token_; } |
- |
- void set_observed_input_representation(Representation left, |
- Representation right) { |
- observed_input_representation_[0] = left; |
- observed_input_representation_[1] = right; |
- } |
- |
- virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return representation(); |
- } |
- Representation observed_input_representation(int index) override { |
- return observed_input_representation_[index]; |
- } |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override; |
- |
- Strength strength() const { return strength_; } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- void SetOperandPositions(Zone* zone, SourcePosition left_pos, |
- SourcePosition right_pos) { |
- set_operand_position(zone, 0, left_pos); |
- set_operand_position(zone, 1, right_pos); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch) |
- |
- private: |
- HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token, |
- HBasicBlock* true_target, HBasicBlock* false_target, |
- Strength strength) |
- : token_(token), strength_(strength) { |
- SetFlag(kFlexibleRepresentation); |
- DCHECK(Token::IsCompareOp(token)); |
- SetOperandAt(0, left); |
- SetOperandAt(1, right); |
- SetSuccessorAt(0, true_target); |
- SetSuccessorAt(1, false_target); |
- } |
- |
- Representation observed_input_representation_[2]; |
- Token::Value token_; |
- Strength strength_; |
-}; |
- |
- |
-class HCompareHoleAndBranch final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*); |
- DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*, |
- HBasicBlock*, HBasicBlock*); |
- |
- virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return representation(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch) |
- |
- private: |
- HCompareHoleAndBranch(HValue* value, |
- HBasicBlock* true_target = NULL, |
- HBasicBlock* false_target = NULL) |
- : HUnaryControlInstruction(value, true_target, false_target) { |
- SetFlag(kFlexibleRepresentation); |
- SetFlag(kAllowUndefinedAsNaN); |
- } |
-}; |
- |
- |
-class HCompareMinusZeroAndBranch final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*); |
- |
- virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return representation(); |
- } |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override; |
- |
- DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch) |
- |
- private: |
- explicit HCompareMinusZeroAndBranch(HValue* value) |
- : HUnaryControlInstruction(value, NULL, NULL) { |
- } |
-}; |
- |
- |
-class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*); |
- DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*, |
- HBasicBlock*, HBasicBlock*); |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override; |
- |
- static const int kNoKnownSuccessorIndex = -1; |
- int known_successor_index() const { return known_successor_index_; } |
- void set_known_successor_index(int known_successor_index) { |
- known_successor_index_ = known_successor_index; |
- } |
- |
- HValue* left() const { return OperandAt(0); } |
- HValue* right() const { return OperandAt(1); } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- Representation observed_input_representation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch) |
- |
- private: |
- HCompareObjectEqAndBranch(HValue* left, |
- HValue* right, |
- HBasicBlock* true_target = NULL, |
- HBasicBlock* false_target = NULL) |
- : known_successor_index_(kNoKnownSuccessorIndex) { |
- SetOperandAt(0, left); |
- SetOperandAt(1, right); |
- SetSuccessorAt(0, true_target); |
- SetSuccessorAt(1, false_target); |
- } |
- |
- int known_successor_index_; |
-}; |
- |
- |
-class HIsStringAndBranch final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*); |
- DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*, |
- HBasicBlock*, HBasicBlock*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override; |
- |
- static const int kNoKnownSuccessorIndex = -1; |
- int known_successor_index() const { return known_successor_index_; } |
- void set_known_successor_index(int known_successor_index) { |
- known_successor_index_ = known_successor_index; |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch) |
- |
- protected: |
- int RedefinedOperandIndex() override { return 0; } |
- |
- private: |
- HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL, |
- HBasicBlock* false_target = NULL) |
- : HUnaryControlInstruction(value, true_target, false_target), |
- known_successor_index_(kNoKnownSuccessorIndex) { |
- set_representation(Representation::Tagged()); |
- } |
- |
- int known_successor_index_; |
-}; |
- |
- |
-class HIsSmiAndBranch final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*); |
- DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*, |
- HBasicBlock*, HBasicBlock*); |
- |
- DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch) |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- int RedefinedOperandIndex() override { return 0; } |
- |
- private: |
- HIsSmiAndBranch(HValue* value, |
- HBasicBlock* true_target = NULL, |
- HBasicBlock* false_target = NULL) |
- : HUnaryControlInstruction(value, true_target, false_target) { |
- set_representation(Representation::Tagged()); |
- } |
-}; |
- |
- |
-class HIsUndetectableAndBranch final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*); |
- DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*, |
- HBasicBlock*, HBasicBlock*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override; |
- |
- DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch) |
- |
- private: |
- HIsUndetectableAndBranch(HValue* value, |
- HBasicBlock* true_target = NULL, |
- HBasicBlock* false_target = NULL) |
- : HUnaryControlInstruction(value, true_target, false_target) {} |
-}; |
- |
- |
-class HStringCompareAndBranch final : public HTemplateControlInstruction<2, 3> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch, |
- HValue*, |
- HValue*, |
- Token::Value); |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* left() const { return OperandAt(1); } |
- HValue* right() const { return OperandAt(2); } |
- Token::Value token() const { return token_; } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const final; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) final { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch) |
- |
- private: |
- HStringCompareAndBranch(HValue* context, HValue* left, HValue* right, |
- Token::Value token) |
- : token_(token) { |
- DCHECK(Token::IsCompareOp(token)); |
- SetOperandAt(0, context); |
- SetOperandAt(1, left); |
- SetOperandAt(2, right); |
- set_representation(Representation::Tagged()); |
- SetChangesFlag(kNewSpacePromotion); |
- SetDependsOnFlag(kStringChars); |
- SetDependsOnFlag(kStringLengths); |
- } |
- |
- Token::Value const token_; |
-}; |
- |
- |
-class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch) |
- private: |
- HIsConstructCallAndBranch() {} |
-}; |
- |
- |
-class HHasInstanceTypeAndBranch final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2( |
- HHasInstanceTypeAndBranch, HValue*, InstanceType); |
- DECLARE_INSTRUCTION_FACTORY_P3( |
- HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType); |
- |
- InstanceType from() { return from_; } |
- InstanceType to() { return to_; } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override; |
- |
- DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch) |
- |
- private: |
- HHasInstanceTypeAndBranch(HValue* value, InstanceType type) |
- : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { } |
- HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to) |
- : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) { |
- DCHECK(to == LAST_TYPE); // Others not implemented yet in backend. |
- } |
- |
- InstanceType from_; |
- InstanceType to_; // Inclusive range, not all combinations work. |
-}; |
- |
- |
-class HHasCachedArrayIndexAndBranch final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch) |
- private: |
- explicit HHasCachedArrayIndexAndBranch(HValue* value) |
- : HUnaryControlInstruction(value, NULL, NULL) { } |
-}; |
- |
- |
-class HGetCachedArrayIndex final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) { |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- } |
- |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HClassOfTestAndBranch final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*, |
- Handle<String>); |
- |
- DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch) |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Handle<String> class_name() const { return class_name_; } |
- |
- private: |
- HClassOfTestAndBranch(HValue* value, Handle<String> class_name) |
- : HUnaryControlInstruction(value, NULL, NULL), |
- class_name_(class_name) { } |
- |
- Handle<String> class_name_; |
-}; |
- |
- |
-class HTypeofIsAndBranch final : public HUnaryControlInstruction { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>); |
- |
- Handle<String> type_literal() const { return type_literal_.handle(); } |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch) |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- bool KnownSuccessorBlock(HBasicBlock** block) override; |
- |
- void FinalizeUniqueness() override { |
- type_literal_ = Unique<String>(type_literal_.handle()); |
- } |
- |
- private: |
- HTypeofIsAndBranch(HValue* value, Handle<String> type_literal) |
- : HUnaryControlInstruction(value, NULL, NULL), |
- type_literal_(Unique<String>::CreateUninitialized(type_literal)) { } |
- |
- Unique<String> type_literal_; |
-}; |
- |
- |
-class HInstanceOf final : public HBinaryOperation { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(InstanceOf) |
- |
- private: |
- HInstanceOf(HValue* context, HValue* left, HValue* right) |
- : HBinaryOperation(context, left, right, Strength::WEAK, |
- HType::Boolean()) { |
- set_representation(Representation::Tagged()); |
- SetAllSideEffects(); |
- } |
-}; |
- |
- |
-class HHasInPrototypeChainAndBranch final |
- : public HTemplateControlInstruction<2, 2> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HHasInPrototypeChainAndBranch, HValue*, |
- HValue*); |
- |
- HValue* object() const { return OperandAt(0); } |
- HValue* prototype() const { return OperandAt(1); } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- bool ObjectNeedsSmiCheck() const { |
- return !object()->type().IsHeapObject() && |
- !object()->representation().IsHeapObject(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(HasInPrototypeChainAndBranch) |
- |
- private: |
- HHasInPrototypeChainAndBranch(HValue* object, HValue* prototype) { |
- SetOperandAt(0, object); |
- SetOperandAt(1, prototype); |
- SetDependsOnFlag(kCalls); |
- } |
-}; |
- |
- |
-class HPower final : public HTemplateInstruction<2> { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right); |
- |
- HValue* left() { return OperandAt(0); } |
- HValue* right() const { return OperandAt(1); } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return index == 0 |
- ? Representation::Double() |
- : Representation::None(); |
- } |
- Representation observed_input_representation(int index) override { |
- return RequiredInputRepresentation(index); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Power) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- HPower(HValue* left, HValue* right) { |
- SetOperandAt(0, left); |
- SetOperandAt(1, right); |
- set_representation(Representation::Double()); |
- SetFlag(kUseGVN); |
- SetChangesFlag(kNewSpacePromotion); |
- } |
- |
- bool IsDeletable() const override { |
- return !right()->representation().IsTagged(); |
- } |
-}; |
- |
- |
-enum ExternalAddType { |
- AddOfExternalAndTagged, |
- AddOfExternalAndInt32, |
- NoExternalAdd |
-}; |
- |
- |
-class HAdd final : public HArithmeticBinaryOperation { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, |
- Strength strength = Strength::WEAK); |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, Strength strength, |
- ExternalAddType external_add_type); |
- |
- // Add is only commutative if two integer values are added and not if two |
- // tagged values are added (because it might be a String concatenation). |
- // We also do not commute (pointer + offset). |
- bool IsCommutative() const override { |
- return !representation().IsTagged() && !representation().IsExternal(); |
- } |
- |
- HValue* Canonicalize() override; |
- |
- bool TryDecompose(DecompositionResult* decomposition) override { |
- if (left()->IsInteger32Constant()) { |
- decomposition->Apply(right(), left()->GetInteger32Constant()); |
- return true; |
- } else if (right()->IsInteger32Constant()) { |
- decomposition->Apply(left(), right()->GetInteger32Constant()); |
- return true; |
- } else { |
- return false; |
- } |
- } |
- |
- void RepresentationChanged(Representation to) override { |
- if (to.IsTagged() && |
- (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() || |
- left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) { |
- SetAllSideEffects(); |
- ClearFlag(kUseGVN); |
- } else { |
- ClearAllSideEffects(); |
- SetFlag(kUseGVN); |
- } |
- if (to.IsTagged()) { |
- SetChangesFlag(kNewSpacePromotion); |
- ClearFlag(kAllowUndefinedAsNaN); |
- } |
- } |
- |
- Representation RepresentationFromInputs() override; |
- |
- Representation RequiredInputRepresentation(int index) override; |
- |
- bool IsConsistentExternalRepresentation() { |
- return left()->representation().IsExternal() && |
- ((external_add_type_ == AddOfExternalAndInt32 && |
- right()->representation().IsInteger32()) || |
- (external_add_type_ == AddOfExternalAndTagged && |
- right()->representation().IsTagged())); |
- } |
- |
- ExternalAddType external_add_type() const { return external_add_type_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Add) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- private: |
- HAdd(HValue* context, HValue* left, HValue* right, Strength strength, |
- ExternalAddType external_add_type = NoExternalAdd) |
- : HArithmeticBinaryOperation(context, left, right, strength), |
- external_add_type_(external_add_type) { |
- SetFlag(kCanOverflow); |
- switch (external_add_type_) { |
- case AddOfExternalAndTagged: |
- DCHECK(left->representation().IsExternal()); |
- DCHECK(right->representation().IsTagged()); |
- SetDependsOnFlag(kNewSpacePromotion); |
- ClearFlag(HValue::kCanOverflow); |
- SetFlag(kHasNoObservableSideEffects); |
- break; |
- |
- case NoExternalAdd: |
- // This is a bit of a hack: The call to this constructor is generated |
- // by a macro that also supports sub and mul, so it doesn't pass in |
- // a value for external_add_type but uses the default. |
- if (left->representation().IsExternal()) { |
- external_add_type_ = AddOfExternalAndInt32; |
- } |
- break; |
- |
- case AddOfExternalAndInt32: |
- // See comment above. |
- UNREACHABLE(); |
- break; |
- } |
- } |
- |
- ExternalAddType external_add_type_; |
-}; |
- |
- |
-class HSub final : public HArithmeticBinaryOperation { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, |
- Strength strength = Strength::WEAK); |
- |
- HValue* Canonicalize() override; |
- |
- bool TryDecompose(DecompositionResult* decomposition) override { |
- if (right()->IsInteger32Constant()) { |
- decomposition->Apply(left(), -right()->GetInteger32Constant()); |
- return true; |
- } else { |
- return false; |
- } |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Sub) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- private: |
- HSub(HValue* context, HValue* left, HValue* right, Strength strength) |
- : HArithmeticBinaryOperation(context, left, right, strength) { |
- SetFlag(kCanOverflow); |
- } |
-}; |
- |
- |
-class HMul final : public HArithmeticBinaryOperation { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, |
- Strength strength = Strength::WEAK); |
- |
- static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, |
- Strength strength = Strength::WEAK) { |
- HInstruction* instr = |
- HMul::New(isolate, zone, context, left, right, strength); |
- if (!instr->IsMul()) return instr; |
- HMul* mul = HMul::cast(instr); |
- // TODO(mstarzinger): Prevent bailout on minus zero for imul. |
- mul->AssumeRepresentation(Representation::Integer32()); |
- mul->ClearFlag(HValue::kCanOverflow); |
- return mul; |
- } |
- |
- HValue* Canonicalize() override; |
- |
- // Only commutative if it is certain that not two objects are multiplicated. |
- bool IsCommutative() const override { return !representation().IsTagged(); } |
- |
- virtual void UpdateRepresentation(Representation new_rep, |
- HInferRepresentationPhase* h_infer, |
- const char* reason) override { |
- HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); |
- } |
- |
- bool MulMinusOne(); |
- |
- DECLARE_CONCRETE_INSTRUCTION(Mul) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- private: |
- HMul(HValue* context, HValue* left, HValue* right, Strength strength) |
- : HArithmeticBinaryOperation(context, left, right, strength) { |
- SetFlag(kCanOverflow); |
- } |
-}; |
- |
- |
-class HMod final : public HArithmeticBinaryOperation { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, |
- Strength strength = Strength::WEAK); |
- |
- HValue* Canonicalize() override; |
- |
- virtual void UpdateRepresentation(Representation new_rep, |
- HInferRepresentationPhase* h_infer, |
- const char* reason) override { |
- if (new_rep.IsSmi()) new_rep = Representation::Integer32(); |
- HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Mod) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- private: |
- HMod(HValue* context, HValue* left, HValue* right, Strength strength) |
- : HArithmeticBinaryOperation(context, left, right, strength) { |
- SetFlag(kCanBeDivByZero); |
- SetFlag(kCanOverflow); |
- SetFlag(kLeftCanBeNegative); |
- } |
-}; |
- |
- |
-class HDiv final : public HArithmeticBinaryOperation { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, |
- Strength strength = Strength::WEAK); |
- |
- HValue* Canonicalize() override; |
- |
- virtual void UpdateRepresentation(Representation new_rep, |
- HInferRepresentationPhase* h_infer, |
- const char* reason) override { |
- if (new_rep.IsSmi()) new_rep = Representation::Integer32(); |
- HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Div) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- private: |
- HDiv(HValue* context, HValue* left, HValue* right, Strength strength) |
- : HArithmeticBinaryOperation(context, left, right, strength) { |
- SetFlag(kCanBeDivByZero); |
- SetFlag(kCanOverflow); |
- } |
-}; |
- |
- |
-class HMathMinMax final : public HArithmeticBinaryOperation { |
- public: |
- enum Operation { kMathMin, kMathMax }; |
- |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, Operation op); |
- |
- Representation observed_input_representation(int index) override { |
- return RequiredInputRepresentation(index); |
- } |
- |
- virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; |
- |
- Representation RepresentationFromInputs() override { |
- Representation left_rep = left()->representation(); |
- Representation right_rep = right()->representation(); |
- Representation result = Representation::Smi(); |
- result = result.generalize(left_rep); |
- result = result.generalize(right_rep); |
- if (result.IsTagged()) return Representation::Double(); |
- return result; |
- } |
- |
- bool IsCommutative() const override { return true; } |
- |
- Operation operation() { return operation_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(MathMinMax) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- return other->IsMathMinMax() && |
- HMathMinMax::cast(other)->operation_ == operation_; |
- } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- private: |
- HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op) |
- : HArithmeticBinaryOperation(context, left, right, Strength::WEAK), |
- operation_(op) {} |
- |
- Operation operation_; |
-}; |
- |
- |
-class HBitwise final : public HBitwiseBinaryOperation { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- Token::Value op, HValue* left, HValue* right, |
- Strength strength = Strength::WEAK); |
- |
- Token::Value op() const { return op_; } |
- |
- bool IsCommutative() const override { return true; } |
- |
- HValue* Canonicalize() override; |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(Bitwise) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- return op() == HBitwise::cast(other)->op(); |
- } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- private: |
- HBitwise(HValue* context, Token::Value op, HValue* left, HValue* right, |
- Strength strength) |
- : HBitwiseBinaryOperation(context, left, right, strength), op_(op) { |
- DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR); |
- // BIT_AND with a smi-range positive value will always unset the |
- // entire sign-extension of the smi-sign. |
- if (op == Token::BIT_AND && |
- ((left->IsConstant() && |
- left->representation().IsSmi() && |
- HConstant::cast(left)->Integer32Value() >= 0) || |
- (right->IsConstant() && |
- right->representation().IsSmi() && |
- HConstant::cast(right)->Integer32Value() >= 0))) { |
- SetFlag(kTruncatingToSmi); |
- SetFlag(kTruncatingToInt32); |
- // BIT_OR with a smi-range negative value will always set the entire |
- // sign-extension of the smi-sign. |
- } else if (op == Token::BIT_OR && |
- ((left->IsConstant() && |
- left->representation().IsSmi() && |
- HConstant::cast(left)->Integer32Value() < 0) || |
- (right->IsConstant() && |
- right->representation().IsSmi() && |
- HConstant::cast(right)->Integer32Value() < 0))) { |
- SetFlag(kTruncatingToSmi); |
- SetFlag(kTruncatingToInt32); |
- } |
- } |
- |
- Token::Value op_; |
-}; |
- |
- |
-class HShl final : public HBitwiseBinaryOperation { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, |
- Strength strength = Strength::WEAK); |
- |
- Range* InferRange(Zone* zone) override; |
- |
- virtual void UpdateRepresentation(Representation new_rep, |
- HInferRepresentationPhase* h_infer, |
- const char* reason) override { |
- if (new_rep.IsSmi() && |
- !(right()->IsInteger32Constant() && |
- right()->GetInteger32Constant() >= 0)) { |
- new_rep = Representation::Integer32(); |
- } |
- HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Shl) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- HShl(HValue* context, HValue* left, HValue* right, Strength strength) |
- : HBitwiseBinaryOperation(context, left, right, strength) {} |
-}; |
- |
- |
-class HShr final : public HBitwiseBinaryOperation { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, |
- Strength strength = Strength::WEAK); |
- |
- bool TryDecompose(DecompositionResult* decomposition) override { |
- if (right()->IsInteger32Constant()) { |
- if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) { |
- // This is intended to look for HAdd and HSub, to handle compounds |
- // like ((base + offset) >> scale) with one single decomposition. |
- left()->TryDecompose(decomposition); |
- return true; |
- } |
- } |
- return false; |
- } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- virtual void UpdateRepresentation(Representation new_rep, |
- HInferRepresentationPhase* h_infer, |
- const char* reason) override { |
- if (new_rep.IsSmi()) new_rep = Representation::Integer32(); |
- HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Shr) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- HShr(HValue* context, HValue* left, HValue* right, Strength strength) |
- : HBitwiseBinaryOperation(context, left, right, strength) {} |
-}; |
- |
- |
-class HSar final : public HBitwiseBinaryOperation { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, |
- Strength strength = Strength::WEAK); |
- |
- bool TryDecompose(DecompositionResult* decomposition) override { |
- if (right()->IsInteger32Constant()) { |
- if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) { |
- // This is intended to look for HAdd and HSub, to handle compounds |
- // like ((base + offset) >> scale) with one single decomposition. |
- left()->TryDecompose(decomposition); |
- return true; |
- } |
- } |
- return false; |
- } |
- |
- Range* InferRange(Zone* zone) override; |
- |
- virtual void UpdateRepresentation(Representation new_rep, |
- HInferRepresentationPhase* h_infer, |
- const char* reason) override { |
- if (new_rep.IsSmi()) new_rep = Representation::Integer32(); |
- HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Sar) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- HSar(HValue* context, HValue* left, HValue* right, Strength strength) |
- : HBitwiseBinaryOperation(context, left, right, strength) {} |
-}; |
- |
- |
-class HRor final : public HBitwiseBinaryOperation { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* left, HValue* right, |
- Strength strength = Strength::WEAK) { |
- return new (zone) HRor(context, left, right, strength); |
- } |
- |
- virtual void UpdateRepresentation(Representation new_rep, |
- HInferRepresentationPhase* h_infer, |
- const char* reason) override { |
- if (new_rep.IsSmi()) new_rep = Representation::Integer32(); |
- HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Ror) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- HRor(HValue* context, HValue* left, HValue* right, Strength strength) |
- : HBitwiseBinaryOperation(context, left, right, strength) { |
- ChangeRepresentation(Representation::Integer32()); |
- } |
-}; |
- |
- |
-class HOsrEntry final : public HTemplateInstruction<0> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId); |
- |
- BailoutId ast_id() const { return ast_id_; } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(OsrEntry) |
- |
- private: |
- explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) { |
- SetChangesFlag(kOsrEntries); |
- SetChangesFlag(kNewSpacePromotion); |
- } |
- |
- BailoutId ast_id_; |
-}; |
- |
- |
-class HParameter final : public HTemplateInstruction<0> { |
- public: |
- enum ParameterKind { |
- STACK_PARAMETER, |
- REGISTER_PARAMETER |
- }; |
- |
- DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned); |
- DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind); |
- DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind, |
- Representation); |
- |
- unsigned index() const { return index_; } |
- ParameterKind kind() const { return kind_; } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- Representation KnownOptimalRepresentation() override { |
- // If a parameter is an input to a phi, that phi should not |
- // choose any more optimistic representation than Tagged. |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Parameter) |
- |
- private: |
- explicit HParameter(unsigned index, |
- ParameterKind kind = STACK_PARAMETER) |
- : index_(index), |
- kind_(kind) { |
- set_representation(Representation::Tagged()); |
- } |
- |
- explicit HParameter(unsigned index, |
- ParameterKind kind, |
- Representation r) |
- : index_(index), |
- kind_(kind) { |
- set_representation(r); |
- } |
- |
- unsigned index_; |
- ParameterKind kind_; |
-}; |
- |
- |
-class HCallStub final : public HUnaryCall { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int); |
- CodeStub::Major major_key() { return major_key_; } |
- |
- HValue* context() { return value(); } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(CallStub) |
- |
- private: |
- HCallStub(HValue* context, CodeStub::Major major_key, int argument_count) |
- : HUnaryCall(context, argument_count), |
- major_key_(major_key) { |
- } |
- |
- CodeStub::Major major_key_; |
-}; |
- |
- |
-class HUnknownOSRValue final : public HTemplateInstruction<0> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int); |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::None(); |
- } |
- |
- void set_incoming_value(HPhi* value) { incoming_value_ = value; } |
- HPhi* incoming_value() { return incoming_value_; } |
- HEnvironment *environment() { return environment_; } |
- int index() { return index_; } |
- |
- Representation KnownOptimalRepresentation() override { |
- if (incoming_value_ == NULL) return Representation::None(); |
- return incoming_value_->KnownOptimalRepresentation(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue) |
- |
- private: |
- HUnknownOSRValue(HEnvironment* environment, int index) |
- : environment_(environment), |
- index_(index), |
- incoming_value_(NULL) { |
- set_representation(Representation::Tagged()); |
- } |
- |
- HEnvironment* environment_; |
- int index_; |
- HPhi* incoming_value_; |
-}; |
- |
- |
-class HLoadGlobalGeneric final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*, |
- Handle<String>, TypeofMode); |
- |
- HValue* context() { return OperandAt(0); } |
- HValue* global_object() { return OperandAt(1); } |
- Handle<String> name() const { return name_; } |
- TypeofMode typeof_mode() const { return typeof_mode_; } |
- FeedbackVectorSlot slot() const { return slot_; } |
- Handle<TypeFeedbackVector> feedback_vector() const { |
- return feedback_vector_; |
- } |
- bool HasVectorAndSlot() const { return true; } |
- void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, |
- FeedbackVectorSlot slot) { |
- feedback_vector_ = vector; |
- slot_ = slot; |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric) |
- |
- private: |
- HLoadGlobalGeneric(HValue* context, HValue* global_object, |
- Handle<String> name, TypeofMode typeof_mode) |
- : name_(name), typeof_mode_(typeof_mode) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, global_object); |
- set_representation(Representation::Tagged()); |
- SetAllSideEffects(); |
- } |
- |
- Handle<String> name_; |
- TypeofMode typeof_mode_; |
- Handle<TypeFeedbackVector> feedback_vector_; |
- FeedbackVectorSlot slot_; |
-}; |
- |
- |
-class HLoadGlobalViaContext final : public HTemplateInstruction<1> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadGlobalViaContext, int, int); |
- |
- HValue* context() { return OperandAt(0); } |
- int depth() const { return depth_; } |
- int slot_index() const { return slot_index_; } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(LoadGlobalViaContext) |
- |
- private: |
- HLoadGlobalViaContext(HValue* context, int depth, int slot_index) |
- : depth_(depth), slot_index_(slot_index) { |
- SetOperandAt(0, context); |
- set_representation(Representation::Tagged()); |
- SetAllSideEffects(); |
- } |
- |
- int const depth_; |
- int const slot_index_; |
-}; |
- |
- |
-class HAllocate final : public HTemplateInstruction<2> { |
- public: |
- static bool CompatibleInstanceTypes(InstanceType type1, |
- InstanceType type2) { |
- return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) && |
- ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2); |
- } |
- |
- static HAllocate* New( |
- Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type, |
- PretenureFlag pretenure_flag, InstanceType instance_type, |
- Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) { |
- return new(zone) HAllocate(context, size, type, pretenure_flag, |
- instance_type, allocation_site); |
- } |
- |
- // Maximum instance size for which allocations will be inlined. |
- static const int kMaxInlineSize = 64 * kPointerSize; |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* size() const { return OperandAt(1); } |
- |
- bool has_size_upper_bound() { return size_upper_bound_ != NULL; } |
- HConstant* size_upper_bound() { return size_upper_bound_; } |
- void set_size_upper_bound(HConstant* value) { |
- DCHECK(size_upper_bound_ == NULL); |
- size_upper_bound_ = value; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- if (index == 0) { |
- return Representation::Tagged(); |
- } else { |
- return Representation::Integer32(); |
- } |
- } |
- |
- Handle<Map> GetMonomorphicJSObjectMap() override { |
- return known_initial_map_; |
- } |
- |
- void set_known_initial_map(Handle<Map> known_initial_map) { |
- known_initial_map_ = known_initial_map; |
- } |
- |
- bool IsNewSpaceAllocation() const { |
- return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0; |
- } |
- |
- bool IsOldSpaceAllocation() const { |
- return (flags_ & ALLOCATE_IN_OLD_SPACE) != 0; |
- } |
- |
- bool MustAllocateDoubleAligned() const { |
- return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0; |
- } |
- |
- bool MustPrefillWithFiller() const { |
- return (flags_ & PREFILL_WITH_FILLER) != 0; |
- } |
- |
- void MakePrefillWithFiller() { |
- flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER); |
- } |
- |
- bool MustClearNextMapWord() const { |
- return (flags_ & CLEAR_NEXT_MAP_WORD) != 0; |
- } |
- |
- void MakeDoubleAligned() { |
- flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED); |
- } |
- |
- virtual bool HandleSideEffectDominator(GVNFlag side_effect, |
- HValue* dominator) override; |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(Allocate) |
- |
- private: |
- enum Flags { |
- ALLOCATE_IN_NEW_SPACE = 1 << 0, |
- ALLOCATE_IN_OLD_SPACE = 1 << 2, |
- ALLOCATE_DOUBLE_ALIGNED = 1 << 3, |
- PREFILL_WITH_FILLER = 1 << 4, |
- CLEAR_NEXT_MAP_WORD = 1 << 5 |
- }; |
- |
- HAllocate(HValue* context, |
- HValue* size, |
- HType type, |
- PretenureFlag pretenure_flag, |
- InstanceType instance_type, |
- Handle<AllocationSite> allocation_site = |
- Handle<AllocationSite>::null()) |
- : HTemplateInstruction<2>(type), |
- flags_(ComputeFlags(pretenure_flag, instance_type)), |
- dominating_allocate_(NULL), |
- filler_free_space_size_(NULL), |
- size_upper_bound_(NULL) { |
- SetOperandAt(0, context); |
- UpdateSize(size); |
- set_representation(Representation::Tagged()); |
- SetFlag(kTrackSideEffectDominators); |
- SetChangesFlag(kNewSpacePromotion); |
- SetDependsOnFlag(kNewSpacePromotion); |
- |
- if (FLAG_trace_pretenuring) { |
- PrintF("HAllocate with AllocationSite %p %s\n", |
- allocation_site.is_null() |
- ? static_cast<void*>(NULL) |
- : static_cast<void*>(*allocation_site), |
- pretenure_flag == TENURED ? "tenured" : "not tenured"); |
- } |
- } |
- |
- static Flags ComputeFlags(PretenureFlag pretenure_flag, |
- InstanceType instance_type) { |
- Flags flags = pretenure_flag == TENURED ? ALLOCATE_IN_OLD_SPACE |
- : ALLOCATE_IN_NEW_SPACE; |
- if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) { |
- flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED); |
- } |
- // We have to fill the allocated object with one word fillers if we do |
- // not use allocation folding since some allocations may depend on each |
- // other, i.e., have a pointer to each other. A GC in between these |
- // allocations may leave such objects behind in a not completely initialized |
- // state. |
- if (!FLAG_use_gvn || !FLAG_use_allocation_folding) { |
- flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER); |
- } |
- if (pretenure_flag == NOT_TENURED && |
- AllocationSite::CanTrack(instance_type)) { |
- flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD); |
- } |
- return flags; |
- } |
- |
- void UpdateClearNextMapWord(bool clear_next_map_word) { |
- flags_ = static_cast<Flags>(clear_next_map_word |
- ? flags_ | CLEAR_NEXT_MAP_WORD |
- : flags_ & ~CLEAR_NEXT_MAP_WORD); |
- } |
- |
- void UpdateSize(HValue* size) { |
- SetOperandAt(1, size); |
- if (size->IsInteger32Constant()) { |
- size_upper_bound_ = HConstant::cast(size); |
- } else { |
- size_upper_bound_ = NULL; |
- } |
- } |
- |
- HAllocate* GetFoldableDominator(HAllocate* dominator); |
- |
- void UpdateFreeSpaceFiller(int32_t filler_size); |
- |
- void CreateFreeSpaceFiller(int32_t filler_size); |
- |
- bool IsFoldable(HAllocate* allocate) { |
- return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) || |
- (IsOldSpaceAllocation() && allocate->IsOldSpaceAllocation()); |
- } |
- |
- void ClearNextMapWord(int offset); |
- |
- Flags flags_; |
- Handle<Map> known_initial_map_; |
- HAllocate* dominating_allocate_; |
- HStoreNamedField* filler_free_space_size_; |
- HConstant* size_upper_bound_; |
-}; |
- |
- |
-class HStoreCodeEntry final : public HTemplateInstruction<2> { |
- public: |
- static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* function, HValue* code) { |
- return new(zone) HStoreCodeEntry(function, code); |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HValue* function() { return OperandAt(0); } |
- HValue* code_object() { return OperandAt(1); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry) |
- |
- private: |
- HStoreCodeEntry(HValue* function, HValue* code) { |
- SetOperandAt(0, function); |
- SetOperandAt(1, code); |
- } |
-}; |
- |
- |
-class HInnerAllocatedObject final : public HTemplateInstruction<2> { |
- public: |
- static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone, |
- HValue* context, HValue* value, |
- HValue* offset, HType type) { |
- return new(zone) HInnerAllocatedObject(value, offset, type); |
- } |
- |
- HValue* base_object() const { return OperandAt(0); } |
- HValue* offset() const { return OperandAt(1); } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return index == 0 ? Representation::Tagged() : Representation::Integer32(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject) |
- |
- private: |
- HInnerAllocatedObject(HValue* value, |
- HValue* offset, |
- HType type) : HTemplateInstruction<2>(type) { |
- DCHECK(value->IsAllocate()); |
- DCHECK(type.IsHeapObject()); |
- SetOperandAt(0, value); |
- SetOperandAt(1, offset); |
- set_representation(Representation::Tagged()); |
- } |
-}; |
- |
- |
-inline bool StoringValueNeedsWriteBarrier(HValue* value) { |
- return !value->type().IsSmi() |
- && !value->type().IsNull() |
- && !value->type().IsBoolean() |
- && !value->type().IsUndefined() |
- && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable()); |
-} |
- |
- |
-inline bool ReceiverObjectNeedsWriteBarrier(HValue* object, |
- HValue* value, |
- HValue* dominator) { |
- while (object->IsInnerAllocatedObject()) { |
- object = HInnerAllocatedObject::cast(object)->base_object(); |
- } |
- if (object->IsConstant() && |
- HConstant::cast(object)->HasExternalReferenceValue()) { |
- // Stores to external references require no write barriers |
- return false; |
- } |
- // We definitely need a write barrier unless the object is the allocation |
- // dominator. |
- if (object == dominator && object->IsAllocate()) { |
- // Stores to new space allocations require no write barriers. |
- if (HAllocate::cast(object)->IsNewSpaceAllocation()) { |
- return false; |
- } |
- // Stores to old space allocations require no write barriers if the value is |
- // a constant provably not in new space. |
- if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) { |
- return false; |
- } |
- // Stores to old space allocations require no write barriers if the value is |
- // an old space allocation. |
- while (value->IsInnerAllocatedObject()) { |
- value = HInnerAllocatedObject::cast(value)->base_object(); |
- } |
- if (value->IsAllocate() && |
- !HAllocate::cast(value)->IsNewSpaceAllocation()) { |
- return false; |
- } |
- } |
- return true; |
-} |
- |
- |
-inline PointersToHereCheck PointersToHereCheckForObject(HValue* object, |
- HValue* dominator) { |
- while (object->IsInnerAllocatedObject()) { |
- object = HInnerAllocatedObject::cast(object)->base_object(); |
- } |
- if (object == dominator && |
- object->IsAllocate() && |
- HAllocate::cast(object)->IsNewSpaceAllocation()) { |
- return kPointersToHereAreAlwaysInteresting; |
- } |
- return kPointersToHereMaybeInteresting; |
-} |
- |
- |
-class HLoadContextSlot final : public HUnaryOperation { |
- public: |
- enum Mode { |
- // Perform a normal load of the context slot without checking its value. |
- kNoCheck, |
- // Load and check the value of the context slot. Deoptimize if it's the |
- // hole value. This is used for checking for loading of uninitialized |
- // harmony bindings where we deoptimize into full-codegen generated code |
- // which will subsequently throw a reference error. |
- kCheckDeoptimize, |
- // Load and check the value of the context slot. Return undefined if it's |
- // the hole value. This is used for non-harmony const assignments |
- kCheckReturnUndefined |
- }; |
- |
- HLoadContextSlot(HValue* context, int slot_index, Mode mode) |
- : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) { |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- SetDependsOnFlag(kContextSlots); |
- } |
- |
- int slot_index() const { return slot_index_; } |
- Mode mode() const { return mode_; } |
- |
- bool DeoptimizesOnHole() { |
- return mode_ == kCheckDeoptimize; |
- } |
- |
- bool RequiresHoleCheck() const { |
- return mode_ != kNoCheck; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- HLoadContextSlot* b = HLoadContextSlot::cast(other); |
- return (slot_index() == b->slot_index()); |
- } |
- |
- private: |
- bool IsDeletable() const override { return !RequiresHoleCheck(); } |
- |
- int slot_index_; |
- Mode mode_; |
-}; |
- |
- |
-class HStoreContextSlot final : public HTemplateInstruction<2> { |
- public: |
- enum Mode { |
- // Perform a normal store to the context slot without checking its previous |
- // value. |
- kNoCheck, |
- // Check the previous value of the context slot and deoptimize if it's the |
- // hole value. This is used for checking for assignments to uninitialized |
- // harmony bindings where we deoptimize into full-codegen generated code |
- // which will subsequently throw a reference error. |
- kCheckDeoptimize, |
- // Check the previous value and ignore assignment if it isn't a hole value |
- kCheckIgnoreAssignment |
- }; |
- |
- DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int, |
- Mode, HValue*); |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* value() const { return OperandAt(1); } |
- int slot_index() const { return slot_index_; } |
- Mode mode() const { return mode_; } |
- |
- bool NeedsWriteBarrier() { |
- return StoringValueNeedsWriteBarrier(value()); |
- } |
- |
- bool DeoptimizesOnHole() { |
- return mode_ == kCheckDeoptimize; |
- } |
- |
- bool RequiresHoleCheck() { |
- return mode_ != kNoCheck; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot) |
- |
- private: |
- HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value) |
- : slot_index_(slot_index), mode_(mode) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, value); |
- SetChangesFlag(kContextSlots); |
- } |
- |
- int slot_index_; |
- Mode mode_; |
-}; |
- |
- |
-// Represents an access to a portion of an object, such as the map pointer, |
-// array elements pointer, etc, but not accesses to array elements themselves. |
-class HObjectAccess final { |
- public: |
- inline bool IsInobject() const { |
- return portion() != kBackingStore && portion() != kExternalMemory; |
- } |
- |
- inline bool IsExternalMemory() const { |
- return portion() == kExternalMemory; |
- } |
- |
- inline bool IsStringLength() const { |
- return portion() == kStringLengths; |
- } |
- |
- inline bool IsMap() const { |
- return portion() == kMaps; |
- } |
- |
- inline int offset() const { |
- return OffsetField::decode(value_); |
- } |
- |
- inline Representation representation() const { |
- return Representation::FromKind(RepresentationField::decode(value_)); |
- } |
- |
- inline Handle<Name> name() const { return name_; } |
- |
- inline bool immutable() const { |
- return ImmutableField::decode(value_); |
- } |
- |
- // Returns true if access is being made to an in-object property that |
- // was already added to the object. |
- inline bool existing_inobject_property() const { |
- return ExistingInobjectPropertyField::decode(value_); |
- } |
- |
- inline HObjectAccess WithRepresentation(Representation representation) { |
- return HObjectAccess(portion(), offset(), representation, name(), |
- immutable(), existing_inobject_property()); |
- } |
- |
- static HObjectAccess ForHeapNumberValue() { |
- return HObjectAccess( |
- kDouble, HeapNumber::kValueOffset, Representation::Double()); |
- } |
- |
- static HObjectAccess ForHeapNumberValueLowestBits() { |
- return HObjectAccess(kDouble, |
- HeapNumber::kValueOffset, |
- Representation::Integer32()); |
- } |
- |
- static HObjectAccess ForHeapNumberValueHighestBits() { |
- return HObjectAccess(kDouble, |
- HeapNumber::kValueOffset + kIntSize, |
- Representation::Integer32()); |
- } |
- |
- static HObjectAccess ForOddballToNumber( |
- Representation representation = Representation::Tagged()) { |
- return HObjectAccess(kInobject, Oddball::kToNumberOffset, representation); |
- } |
- |
- static HObjectAccess ForOddballTypeOf() { |
- return HObjectAccess(kInobject, Oddball::kTypeOfOffset, |
- Representation::HeapObject()); |
- } |
- |
- static HObjectAccess ForElementsPointer() { |
- return HObjectAccess(kElementsPointer, JSObject::kElementsOffset); |
- } |
- |
- static HObjectAccess ForLiteralsPointer() { |
- return HObjectAccess(kInobject, JSFunction::kLiteralsOffset); |
- } |
- |
- static HObjectAccess ForNextFunctionLinkPointer() { |
- return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset); |
- } |
- |
- static HObjectAccess ForArrayLength(ElementsKind elements_kind) { |
- return HObjectAccess( |
- kArrayLengths, |
- JSArray::kLengthOffset, |
- IsFastElementsKind(elements_kind) |
- ? Representation::Smi() : Representation::Tagged()); |
- } |
- |
- static HObjectAccess ForAllocationSiteOffset(int offset); |
- |
- static HObjectAccess ForAllocationSiteList() { |
- return HObjectAccess(kExternalMemory, 0, Representation::Tagged(), |
- Handle<Name>::null(), false, false); |
- } |
- |
- static HObjectAccess ForFixedArrayLength() { |
- return HObjectAccess( |
- kArrayLengths, |
- FixedArray::kLengthOffset, |
- Representation::Smi()); |
- } |
- |
- static HObjectAccess ForFixedTypedArrayBaseBasePointer() { |
- return HObjectAccess(kInobject, FixedTypedArrayBase::kBasePointerOffset, |
- Representation::Tagged()); |
- } |
- |
- static HObjectAccess ForFixedTypedArrayBaseExternalPointer() { |
- return HObjectAccess::ForObservableJSObjectOffset( |
- FixedTypedArrayBase::kExternalPointerOffset, |
- Representation::External()); |
- } |
- |
- static HObjectAccess ForStringHashField() { |
- return HObjectAccess(kInobject, |
- String::kHashFieldOffset, |
- Representation::Integer32()); |
- } |
- |
- static HObjectAccess ForStringLength() { |
- STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); |
- return HObjectAccess( |
- kStringLengths, |
- String::kLengthOffset, |
- Representation::Smi()); |
- } |
- |
- static HObjectAccess ForConsStringFirst() { |
- return HObjectAccess(kInobject, ConsString::kFirstOffset); |
- } |
- |
- static HObjectAccess ForConsStringSecond() { |
- return HObjectAccess(kInobject, ConsString::kSecondOffset); |
- } |
- |
- static HObjectAccess ForPropertiesPointer() { |
- return HObjectAccess(kInobject, JSObject::kPropertiesOffset); |
- } |
- |
- static HObjectAccess ForPrototypeOrInitialMap() { |
- return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset); |
- } |
- |
- static HObjectAccess ForSharedFunctionInfoPointer() { |
- return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset); |
- } |
- |
- static HObjectAccess ForCodeEntryPointer() { |
- return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset); |
- } |
- |
- static HObjectAccess ForCodeOffset() { |
- return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset); |
- } |
- |
- static HObjectAccess ForOptimizedCodeMap() { |
- return HObjectAccess(kInobject, |
- SharedFunctionInfo::kOptimizedCodeMapOffset); |
- } |
- |
- static HObjectAccess ForOptimizedCodeMapSharedCode() { |
- return HObjectAccess(kInobject, FixedArray::OffsetOfElementAt( |
- SharedFunctionInfo::kSharedCodeIndex)); |
- } |
- |
- static HObjectAccess ForFunctionContextPointer() { |
- return HObjectAccess(kInobject, JSFunction::kContextOffset); |
- } |
- |
- static HObjectAccess ForMap() { |
- return HObjectAccess(kMaps, JSObject::kMapOffset); |
- } |
- |
- static HObjectAccess ForPrototype() { |
- return HObjectAccess(kMaps, Map::kPrototypeOffset); |
- } |
- |
- static HObjectAccess ForMapAsInteger32() { |
- return HObjectAccess(kMaps, JSObject::kMapOffset, |
- Representation::Integer32()); |
- } |
- |
- static HObjectAccess ForMapInObjectPropertiesOrConstructorFunctionIndex() { |
- return HObjectAccess( |
- kInobject, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset, |
- Representation::UInteger8()); |
- } |
- |
- static HObjectAccess ForMapInstanceType() { |
- return HObjectAccess(kInobject, |
- Map::kInstanceTypeOffset, |
- Representation::UInteger8()); |
- } |
- |
- static HObjectAccess ForMapInstanceSize() { |
- return HObjectAccess(kInobject, |
- Map::kInstanceSizeOffset, |
- Representation::UInteger8()); |
- } |
- |
- static HObjectAccess ForMapBitField() { |
- return HObjectAccess(kInobject, |
- Map::kBitFieldOffset, |
- Representation::UInteger8()); |
- } |
- |
- static HObjectAccess ForMapBitField2() { |
- return HObjectAccess(kInobject, |
- Map::kBitField2Offset, |
- Representation::UInteger8()); |
- } |
- |
- static HObjectAccess ForNameHashField() { |
- return HObjectAccess(kInobject, |
- Name::kHashFieldOffset, |
- Representation::Integer32()); |
- } |
- |
- static HObjectAccess ForMapInstanceTypeAndBitField() { |
- STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0); |
- // Ensure the two fields share one 16-bit word, endian-independent. |
- STATIC_ASSERT((Map::kBitFieldOffset & ~1) == |
- (Map::kInstanceTypeOffset & ~1)); |
- return HObjectAccess(kInobject, |
- Map::kInstanceTypeAndBitFieldOffset, |
- Representation::UInteger16()); |
- } |
- |
- static HObjectAccess ForPropertyCellValue() { |
- return HObjectAccess(kInobject, PropertyCell::kValueOffset); |
- } |
- |
- static HObjectAccess ForPropertyCellDetails() { |
- return HObjectAccess(kInobject, PropertyCell::kDetailsOffset, |
- Representation::Smi()); |
- } |
- |
- static HObjectAccess ForCellValue() { |
- return HObjectAccess(kInobject, Cell::kValueOffset); |
- } |
- |
- static HObjectAccess ForWeakCellValue() { |
- return HObjectAccess(kInobject, WeakCell::kValueOffset); |
- } |
- |
- static HObjectAccess ForWeakCellNext() { |
- return HObjectAccess(kInobject, WeakCell::kNextOffset); |
- } |
- |
- static HObjectAccess ForAllocationMementoSite() { |
- return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset); |
- } |
- |
- static HObjectAccess ForCounter() { |
- return HObjectAccess(kExternalMemory, 0, Representation::Integer32(), |
- Handle<Name>::null(), false, false); |
- } |
- |
- static HObjectAccess ForExternalUInteger8() { |
- return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(), |
- Handle<Name>::null(), false, false); |
- } |
- |
- // Create an access to an offset in a fixed array header. |
- static HObjectAccess ForFixedArrayHeader(int offset); |
- |
- // Create an access to an in-object property in a JSObject. |
- // This kind of access must be used when the object |map| is known and |
- // in-object properties are being accessed. Accesses of the in-object |
- // properties can have different semantics depending on whether corresponding |
- // property was added to the map or not. |
- static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset, |
- Representation representation = Representation::Tagged()); |
- |
- // Create an access to an in-object property in a JSObject. |
- // This kind of access can be used for accessing object header fields or |
- // in-object properties if the map of the object is not known. |
- static HObjectAccess ForObservableJSObjectOffset(int offset, |
- Representation representation = Representation::Tagged()) { |
- return ForMapAndOffset(Handle<Map>::null(), offset, representation); |
- } |
- |
- // Create an access to an in-object property in a JSArray. |
- static HObjectAccess ForJSArrayOffset(int offset); |
- |
- static HObjectAccess ForContextSlot(int index); |
- |
- static HObjectAccess ForScriptContext(int index); |
- |
- // Create an access to the backing store of an object. |
- static HObjectAccess ForBackingStoreOffset(int offset, |
- Representation representation = Representation::Tagged()); |
- |
- // Create an access to a resolved field (in-object or backing store). |
- static HObjectAccess ForField(Handle<Map> map, int index, |
- Representation representation, |
- Handle<Name> name); |
- |
- static HObjectAccess ForJSTypedArrayLength() { |
- return HObjectAccess::ForObservableJSObjectOffset( |
- JSTypedArray::kLengthOffset); |
- } |
- |
- static HObjectAccess ForJSArrayBufferBackingStore() { |
- return HObjectAccess::ForObservableJSObjectOffset( |
- JSArrayBuffer::kBackingStoreOffset, Representation::External()); |
- } |
- |
- static HObjectAccess ForJSArrayBufferByteLength() { |
- return HObjectAccess::ForObservableJSObjectOffset( |
- JSArrayBuffer::kByteLengthOffset, Representation::Tagged()); |
- } |
- |
- static HObjectAccess ForJSArrayBufferBitField() { |
- return HObjectAccess::ForObservableJSObjectOffset( |
- JSArrayBuffer::kBitFieldOffset, Representation::Integer32()); |
- } |
- |
- static HObjectAccess ForJSArrayBufferBitFieldSlot() { |
- return HObjectAccess::ForObservableJSObjectOffset( |
- JSArrayBuffer::kBitFieldSlot, Representation::Smi()); |
- } |
- |
- static HObjectAccess ForJSArrayBufferViewBuffer() { |
- return HObjectAccess::ForObservableJSObjectOffset( |
- JSArrayBufferView::kBufferOffset); |
- } |
- |
- static HObjectAccess ForJSArrayBufferViewByteOffset() { |
- return HObjectAccess::ForObservableJSObjectOffset( |
- JSArrayBufferView::kByteOffsetOffset); |
- } |
- |
- static HObjectAccess ForJSArrayBufferViewByteLength() { |
- return HObjectAccess::ForObservableJSObjectOffset( |
- JSArrayBufferView::kByteLengthOffset); |
- } |
- |
- static HObjectAccess ForGlobalObjectNativeContext() { |
- return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset); |
- } |
- |
- static HObjectAccess ForJSCollectionTable() { |
- return HObjectAccess::ForObservableJSObjectOffset( |
- JSCollection::kTableOffset); |
- } |
- |
- template <typename CollectionType> |
- static HObjectAccess ForOrderedHashTableNumberOfBuckets() { |
- return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset, |
- Representation::Smi()); |
- } |
- |
- template <typename CollectionType> |
- static HObjectAccess ForOrderedHashTableNumberOfElements() { |
- return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset, |
- Representation::Smi()); |
- } |
- |
- template <typename CollectionType> |
- static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() { |
- return HObjectAccess(kInobject, |
- CollectionType::kNumberOfDeletedElementsOffset, |
- Representation::Smi()); |
- } |
- |
- template <typename CollectionType> |
- static HObjectAccess ForOrderedHashTableNextTable() { |
- return HObjectAccess(kInobject, CollectionType::kNextTableOffset); |
- } |
- |
- template <typename CollectionType> |
- static HObjectAccess ForOrderedHashTableBucket(int bucket) { |
- return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset + |
- (bucket * kPointerSize), |
- Representation::Smi()); |
- } |
- |
- // Access into the data table of an OrderedHashTable with a |
- // known-at-compile-time bucket count. |
- template <typename CollectionType, int kBucketCount> |
- static HObjectAccess ForOrderedHashTableDataTableIndex(int index) { |
- return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset + |
- (kBucketCount * kPointerSize) + |
- (index * kPointerSize)); |
- } |
- |
- inline bool Equals(HObjectAccess that) const { |
- return value_ == that.value_; // portion and offset must match |
- } |
- |
- protected: |
- void SetGVNFlags(HValue *instr, PropertyAccessType access_type); |
- |
- private: |
- // internal use only; different parts of an object or array |
- enum Portion { |
- kMaps, // map of an object |
- kArrayLengths, // the length of an array |
- kStringLengths, // the length of a string |
- kElementsPointer, // elements pointer |
- kBackingStore, // some field in the backing store |
- kDouble, // some double field |
- kInobject, // some other in-object field |
- kExternalMemory // some field in external memory |
- }; |
- |
- HObjectAccess() : value_(0) {} |
- |
- HObjectAccess(Portion portion, int offset, |
- Representation representation = Representation::Tagged(), |
- Handle<Name> name = Handle<Name>::null(), |
- bool immutable = false, bool existing_inobject_property = true) |
- : value_(PortionField::encode(portion) | |
- RepresentationField::encode(representation.kind()) | |
- ImmutableField::encode(immutable ? 1 : 0) | |
- ExistingInobjectPropertyField::encode( |
- existing_inobject_property ? 1 : 0) | |
- OffsetField::encode(offset)), |
- name_(name) { |
- // assert that the fields decode correctly |
- DCHECK(this->offset() == offset); |
- DCHECK(this->portion() == portion); |
- DCHECK(this->immutable() == immutable); |
- DCHECK(this->existing_inobject_property() == existing_inobject_property); |
- DCHECK(RepresentationField::decode(value_) == representation.kind()); |
- DCHECK(!this->existing_inobject_property() || IsInobject()); |
- } |
- |
- class PortionField : public BitField<Portion, 0, 3> {}; |
- class RepresentationField : public BitField<Representation::Kind, 3, 4> {}; |
- class ImmutableField : public BitField<bool, 7, 1> {}; |
- class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {}; |
- class OffsetField : public BitField<int, 9, 23> {}; |
- |
- uint32_t value_; // encodes portion, representation, immutable, and offset |
- Handle<Name> name_; |
- |
- friend class HLoadNamedField; |
- friend class HStoreNamedField; |
- friend class SideEffectsTracker; |
- friend std::ostream& operator<<(std::ostream& os, |
- const HObjectAccess& access); |
- |
- inline Portion portion() const { |
- return PortionField::decode(value_); |
- } |
-}; |
- |
- |
-std::ostream& operator<<(std::ostream& os, const HObjectAccess& access); |
- |
- |
-class HLoadNamedField final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*, |
- HValue*, HObjectAccess); |
- DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*, |
- HObjectAccess, const UniqueSet<Map>*, HType); |
- |
- HValue* object() const { return OperandAt(0); } |
- HValue* dependency() const { |
- DCHECK(HasDependency()); |
- return OperandAt(1); |
- } |
- bool HasDependency() const { return OperandAt(0) != OperandAt(1); } |
- HObjectAccess access() const { return access_; } |
- Representation field_representation() const { |
- return access_.representation(); |
- } |
- |
- const UniqueSet<Map>* maps() const { return maps_; } |
- |
- bool HasEscapingOperandAt(int index) override { return false; } |
- bool HasOutOfBoundsAccess(int size) override { |
- return !access().IsInobject() || access().offset() >= size; |
- } |
- Representation RequiredInputRepresentation(int index) override { |
- if (index == 0) { |
- // object must be external in case of external memory access |
- return access().IsExternalMemory() ? Representation::External() |
- : Representation::Tagged(); |
- } |
- DCHECK(index == 1); |
- return Representation::None(); |
- } |
- Range* InferRange(Zone* zone) override; |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- bool CanBeReplacedWith(HValue* other) const { |
- if (!CheckFlag(HValue::kCantBeReplaced)) return false; |
- if (!type().Equals(other->type())) return false; |
- if (!representation().Equals(other->representation())) return false; |
- if (!other->IsLoadNamedField()) return true; |
- HLoadNamedField* that = HLoadNamedField::cast(other); |
- if (this->maps_ == that->maps_) return true; |
- if (this->maps_ == NULL || that->maps_ == NULL) return false; |
- return this->maps_->IsSubset(that->maps_); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(LoadNamedField) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- HLoadNamedField* that = HLoadNamedField::cast(other); |
- if (!this->access_.Equals(that->access_)) return false; |
- if (this->maps_ == that->maps_) return true; |
- return (this->maps_ != NULL && |
- that->maps_ != NULL && |
- this->maps_->Equals(that->maps_)); |
- } |
- |
- private: |
- HLoadNamedField(HValue* object, |
- HValue* dependency, |
- HObjectAccess access) |
- : access_(access), maps_(NULL) { |
- DCHECK_NOT_NULL(object); |
- SetOperandAt(0, object); |
- SetOperandAt(1, dependency ? dependency : object); |
- |
- Representation representation = access.representation(); |
- if (representation.IsInteger8() || |
- representation.IsUInteger8() || |
- representation.IsInteger16() || |
- representation.IsUInteger16()) { |
- set_representation(Representation::Integer32()); |
- } else if (representation.IsSmi()) { |
- set_type(HType::Smi()); |
- if (SmiValuesAre32Bits()) { |
- set_representation(Representation::Integer32()); |
- } else { |
- set_representation(representation); |
- } |
- } else if (representation.IsDouble() || |
- representation.IsExternal() || |
- representation.IsInteger32()) { |
- set_representation(representation); |
- } else if (representation.IsHeapObject()) { |
- set_type(HType::HeapObject()); |
- set_representation(Representation::Tagged()); |
- } else { |
- set_representation(Representation::Tagged()); |
- } |
- access.SetGVNFlags(this, LOAD); |
- } |
- |
- HLoadNamedField(HValue* object, |
- HValue* dependency, |
- HObjectAccess access, |
- const UniqueSet<Map>* maps, |
- HType type) |
- : HTemplateInstruction<2>(type), access_(access), maps_(maps) { |
- DCHECK_NOT_NULL(maps); |
- DCHECK_NE(0, maps->size()); |
- |
- DCHECK_NOT_NULL(object); |
- SetOperandAt(0, object); |
- SetOperandAt(1, dependency ? dependency : object); |
- |
- DCHECK(access.representation().IsHeapObject()); |
- DCHECK(type.IsHeapObject()); |
- set_representation(Representation::Tagged()); |
- |
- access.SetGVNFlags(this, LOAD); |
- } |
- |
- bool IsDeletable() const override { return true; } |
- |
- HObjectAccess access_; |
- const UniqueSet<Map>* maps_; |
-}; |
- |
- |
-class HLoadNamedGeneric final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadNamedGeneric, HValue*, |
- Handle<Name>, LanguageMode, |
- InlineCacheState); |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* object() const { return OperandAt(1); } |
- Handle<Name> name() const { return name_; } |
- |
- InlineCacheState initialization_state() const { |
- return initialization_state_; |
- } |
- FeedbackVectorSlot slot() const { return slot_; } |
- Handle<TypeFeedbackVector> feedback_vector() const { |
- return feedback_vector_; |
- } |
- bool HasVectorAndSlot() const { return true; } |
- void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, |
- FeedbackVectorSlot slot) { |
- feedback_vector_ = vector; |
- slot_ = slot; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric) |
- |
- LanguageMode language_mode() const { return language_mode_; } |
- |
- private: |
- HLoadNamedGeneric(HValue* context, HValue* object, Handle<Name> name, |
- LanguageMode language_mode, |
- InlineCacheState initialization_state) |
- : name_(name), |
- language_mode_(language_mode), |
- initialization_state_(initialization_state) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, object); |
- set_representation(Representation::Tagged()); |
- SetAllSideEffects(); |
- } |
- |
- Handle<Name> name_; |
- Handle<TypeFeedbackVector> feedback_vector_; |
- FeedbackVectorSlot slot_; |
- LanguageMode language_mode_; |
- InlineCacheState initialization_state_; |
-}; |
- |
- |
-class HLoadFunctionPrototype final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*); |
- |
- HValue* function() { return OperandAt(0); } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- explicit HLoadFunctionPrototype(HValue* function) |
- : HUnaryOperation(function) { |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- SetDependsOnFlag(kCalls); |
- } |
-}; |
- |
-class ArrayInstructionInterface { |
- public: |
- virtual HValue* GetKey() = 0; |
- virtual void SetKey(HValue* key) = 0; |
- virtual ElementsKind elements_kind() const = 0; |
- // TryIncreaseBaseOffset returns false if overflow would result. |
- virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0; |
- virtual bool IsDehoisted() const = 0; |
- virtual void SetDehoisted(bool is_dehoisted) = 0; |
- virtual ~ArrayInstructionInterface() { } |
- |
- static Representation KeyedAccessIndexRequirement(Representation r) { |
- return r.IsInteger32() || SmiValuesAre32Bits() |
- ? Representation::Integer32() : Representation::Smi(); |
- } |
-}; |
- |
- |
-static const int kDefaultKeyedHeaderOffsetSentinel = -1; |
- |
-enum LoadKeyedHoleMode { |
- NEVER_RETURN_HOLE, |
- ALLOW_RETURN_HOLE, |
- CONVERT_HOLE_TO_UNDEFINED |
-}; |
- |
- |
-class HLoadKeyed final : public HTemplateInstruction<3>, |
- public ArrayInstructionInterface { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*, |
- ElementsKind); |
- DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*, |
- ElementsKind, LoadKeyedHoleMode); |
- DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*, |
- ElementsKind, LoadKeyedHoleMode, int); |
- |
- bool is_fixed_typed_array() const { |
- return IsFixedTypedArrayElementsKind(elements_kind()); |
- } |
- HValue* elements() const { return OperandAt(0); } |
- HValue* key() const { return OperandAt(1); } |
- HValue* dependency() const { |
- DCHECK(HasDependency()); |
- return OperandAt(2); |
- } |
- bool HasDependency() const { return OperandAt(0) != OperandAt(2); } |
- uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); } |
- bool TryIncreaseBaseOffset(uint32_t increase_by_value) override; |
- HValue* GetKey() override { return key(); } |
- void SetKey(HValue* key) override { SetOperandAt(1, key); } |
- bool IsDehoisted() const override { |
- return IsDehoistedField::decode(bit_field_); |
- } |
- void SetDehoisted(bool is_dehoisted) override { |
- bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted); |
- } |
- ElementsKind elements_kind() const override { |
- return ElementsKindField::decode(bit_field_); |
- } |
- LoadKeyedHoleMode hole_mode() const { |
- return HoleModeField::decode(bit_field_); |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- // kind_fast: tagged[int32] (none) |
- // kind_double: tagged[int32] (none) |
- // kind_fixed_typed_array: external[int32] (none) |
- // kind_external: external[int32] (none) |
- if (index == 0) { |
- return is_fixed_typed_array() ? Representation::External() |
- : Representation::Tagged(); |
- } |
- if (index == 1) { |
- return ArrayInstructionInterface::KeyedAccessIndexRequirement( |
- OperandAt(1)->representation()); |
- } |
- return Representation::None(); |
- } |
- |
- Representation observed_input_representation(int index) override { |
- return RequiredInputRepresentation(index); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- bool UsesMustHandleHole() const; |
- bool AllUsesCanTreatHoleAsNaN() const; |
- bool RequiresHoleCheck() const; |
- |
- Range* InferRange(Zone* zone) override; |
- |
- DECLARE_CONCRETE_INSTRUCTION(LoadKeyed) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- if (!other->IsLoadKeyed()) return false; |
- HLoadKeyed* other_load = HLoadKeyed::cast(other); |
- |
- if (base_offset() != other_load->base_offset()) return false; |
- return elements_kind() == other_load->elements_kind(); |
- } |
- |
- private: |
- HLoadKeyed(HValue* obj, HValue* key, HValue* dependency, |
- ElementsKind elements_kind, |
- LoadKeyedHoleMode mode = NEVER_RETURN_HOLE, |
- int offset = kDefaultKeyedHeaderOffsetSentinel) |
- : bit_field_(0) { |
- offset = offset == kDefaultKeyedHeaderOffsetSentinel |
- ? GetDefaultHeaderSizeForElementsKind(elements_kind) |
- : offset; |
- bit_field_ = ElementsKindField::encode(elements_kind) | |
- HoleModeField::encode(mode) | |
- BaseOffsetField::encode(offset); |
- |
- SetOperandAt(0, obj); |
- SetOperandAt(1, key); |
- SetOperandAt(2, dependency != NULL ? dependency : obj); |
- |
- if (!is_fixed_typed_array()) { |
- // I can detect the case between storing double (holey and fast) and |
- // smi/object by looking at elements_kind_. |
- DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || |
- IsFastDoubleElementsKind(elements_kind)); |
- |
- if (IsFastSmiOrObjectElementsKind(elements_kind)) { |
- if (IsFastSmiElementsKind(elements_kind) && |
- (!IsHoleyElementsKind(elements_kind) || |
- mode == NEVER_RETURN_HOLE)) { |
- set_type(HType::Smi()); |
- if (SmiValuesAre32Bits() && !RequiresHoleCheck()) { |
- set_representation(Representation::Integer32()); |
- } else { |
- set_representation(Representation::Smi()); |
- } |
- } else { |
- set_representation(Representation::Tagged()); |
- } |
- |
- SetDependsOnFlag(kArrayElements); |
- } else { |
- set_representation(Representation::Double()); |
- SetDependsOnFlag(kDoubleArrayElements); |
- } |
- } else { |
- if (elements_kind == FLOAT32_ELEMENTS || |
- elements_kind == FLOAT64_ELEMENTS) { |
- set_representation(Representation::Double()); |
- } else { |
- set_representation(Representation::Integer32()); |
- } |
- |
- if (is_fixed_typed_array()) { |
- SetDependsOnFlag(kExternalMemory); |
- SetDependsOnFlag(kTypedArrayElements); |
- } else { |
- UNREACHABLE(); |
- } |
- // Native code could change the specialized array. |
- SetDependsOnFlag(kCalls); |
- } |
- |
- SetFlag(kUseGVN); |
- } |
- |
- bool IsDeletable() const override { return !RequiresHoleCheck(); } |
- |
- // Establish some checks around our packed fields |
- enum LoadKeyedBits { |
- kBitsForElementsKind = 5, |
- kBitsForHoleMode = 2, |
- kBitsForBaseOffset = 24, |
- kBitsForIsDehoisted = 1, |
- |
- kStartElementsKind = 0, |
- kStartHoleMode = kStartElementsKind + kBitsForElementsKind, |
- kStartBaseOffset = kStartHoleMode + kBitsForHoleMode, |
- kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset |
- }; |
- |
- STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset + |
- kBitsForIsDehoisted) <= sizeof(uint32_t) * 8); |
- STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind)); |
- class ElementsKindField: |
- public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind> |
- {}; // NOLINT |
- class HoleModeField: |
- public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode> |
- {}; // NOLINT |
- class BaseOffsetField: |
- public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset> |
- {}; // NOLINT |
- class IsDehoistedField: |
- public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted> |
- {}; // NOLINT |
- uint32_t bit_field_; |
-}; |
- |
- |
-class HLoadKeyedGeneric final : public HTemplateInstruction<3> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadKeyedGeneric, HValue*, |
- HValue*, LanguageMode, |
- InlineCacheState); |
- HValue* object() const { return OperandAt(0); } |
- HValue* key() const { return OperandAt(1); } |
- HValue* context() const { return OperandAt(2); } |
- InlineCacheState initialization_state() const { |
- return initialization_state_; |
- } |
- FeedbackVectorSlot slot() const { return slot_; } |
- Handle<TypeFeedbackVector> feedback_vector() const { |
- return feedback_vector_; |
- } |
- bool HasVectorAndSlot() const { |
- DCHECK(initialization_state_ == MEGAMORPHIC || !feedback_vector_.is_null()); |
- return !feedback_vector_.is_null(); |
- } |
- void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, |
- FeedbackVectorSlot slot) { |
- feedback_vector_ = vector; |
- slot_ = slot; |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- // tagged[tagged] |
- return Representation::Tagged(); |
- } |
- |
- HValue* Canonicalize() override; |
- |
- DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric) |
- |
- LanguageMode language_mode() const { return language_mode_; } |
- |
- private: |
- HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key, |
- LanguageMode language_mode, |
- InlineCacheState initialization_state) |
- : initialization_state_(initialization_state), |
- language_mode_(language_mode) { |
- set_representation(Representation::Tagged()); |
- SetOperandAt(0, obj); |
- SetOperandAt(1, key); |
- SetOperandAt(2, context); |
- SetAllSideEffects(); |
- } |
- |
- Handle<TypeFeedbackVector> feedback_vector_; |
- FeedbackVectorSlot slot_; |
- InlineCacheState initialization_state_; |
- LanguageMode language_mode_; |
-}; |
- |
- |
-// Indicates whether the store is a store to an entry that was previously |
-// initialized or not. |
-enum StoreFieldOrKeyedMode { |
- // The entry could be either previously initialized or not. |
- INITIALIZING_STORE, |
- // At the time of this store it is guaranteed that the entry is already |
- // initialized. |
- STORE_TO_INITIALIZED_ENTRY |
-}; |
- |
- |
-class HStoreNamedField final : public HTemplateInstruction<3> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*, |
- HObjectAccess, HValue*); |
- DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*, |
- HObjectAccess, HValue*, StoreFieldOrKeyedMode); |
- |
- DECLARE_CONCRETE_INSTRUCTION(StoreNamedField) |
- |
- bool HasEscapingOperandAt(int index) override { return index == 1; } |
- bool HasOutOfBoundsAccess(int size) override { |
- return !access().IsInobject() || access().offset() >= size; |
- } |
- Representation RequiredInputRepresentation(int index) override { |
- if (index == 0 && access().IsExternalMemory()) { |
- // object must be external in case of external memory access |
- return Representation::External(); |
- } else if (index == 1) { |
- if (field_representation().IsInteger8() || |
- field_representation().IsUInteger8() || |
- field_representation().IsInteger16() || |
- field_representation().IsUInteger16() || |
- field_representation().IsInteger32()) { |
- return Representation::Integer32(); |
- } else if (field_representation().IsDouble()) { |
- return field_representation(); |
- } else if (field_representation().IsSmi()) { |
- if (SmiValuesAre32Bits() && |
- store_mode() == STORE_TO_INITIALIZED_ENTRY) { |
- return Representation::Integer32(); |
- } |
- return field_representation(); |
- } else if (field_representation().IsExternal()) { |
- return Representation::External(); |
- } |
- } |
- return Representation::Tagged(); |
- } |
- virtual bool HandleSideEffectDominator(GVNFlag side_effect, |
- HValue* dominator) override { |
- DCHECK(side_effect == kNewSpacePromotion); |
- if (!FLAG_use_write_barrier_elimination) return false; |
- dominator_ = dominator; |
- return false; |
- } |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HValue* object() const { return OperandAt(0); } |
- HValue* value() const { return OperandAt(1); } |
- HValue* transition() const { return OperandAt(2); } |
- |
- HObjectAccess access() const { return access_; } |
- HValue* dominator() const { return dominator_; } |
- bool has_transition() const { return HasTransitionField::decode(bit_field_); } |
- StoreFieldOrKeyedMode store_mode() const { |
- return StoreModeField::decode(bit_field_); |
- } |
- |
- Handle<Map> transition_map() const { |
- if (has_transition()) { |
- return Handle<Map>::cast( |
- HConstant::cast(transition())->handle(isolate())); |
- } else { |
- return Handle<Map>(); |
- } |
- } |
- |
- void SetTransition(HConstant* transition) { |
- DCHECK(!has_transition()); // Only set once. |
- SetOperandAt(2, transition); |
- bit_field_ = HasTransitionField::update(bit_field_, true); |
- SetChangesFlag(kMaps); |
- } |
- |
- bool NeedsWriteBarrier() const { |
- DCHECK(!field_representation().IsDouble() || |
- (FLAG_unbox_double_fields && access_.IsInobject()) || |
- !has_transition()); |
- if (field_representation().IsDouble()) return false; |
- if (field_representation().IsSmi()) return false; |
- if (field_representation().IsInteger32()) return false; |
- if (field_representation().IsExternal()) return false; |
- return StoringValueNeedsWriteBarrier(value()) && |
- ReceiverObjectNeedsWriteBarrier(object(), value(), dominator()); |
- } |
- |
- bool NeedsWriteBarrierForMap() { |
- return ReceiverObjectNeedsWriteBarrier(object(), transition(), |
- dominator()); |
- } |
- |
- SmiCheck SmiCheckForWriteBarrier() const { |
- if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK; |
- if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK; |
- return INLINE_SMI_CHECK; |
- } |
- |
- PointersToHereCheck PointersToHereCheckForValue() const { |
- return PointersToHereCheckForObject(value(), dominator()); |
- } |
- |
- Representation field_representation() const { |
- return access_.representation(); |
- } |
- |
- void UpdateValue(HValue* value) { |
- SetOperandAt(1, value); |
- } |
- |
- bool CanBeReplacedWith(HStoreNamedField* that) const { |
- if (!this->access().Equals(that->access())) return false; |
- if (SmiValuesAre32Bits() && |
- this->field_representation().IsSmi() && |
- this->store_mode() == INITIALIZING_STORE && |
- that->store_mode() == STORE_TO_INITIALIZED_ENTRY) { |
- // We cannot replace an initializing store to a smi field with a store to |
- // an initialized entry on 64-bit architectures (with 32-bit smis). |
- return false; |
- } |
- return true; |
- } |
- |
- private: |
- HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val, |
- StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE) |
- : access_(access), |
- dominator_(NULL), |
- bit_field_(HasTransitionField::encode(false) | |
- StoreModeField::encode(store_mode)) { |
- // Stores to a non existing in-object property are allowed only to the |
- // newly allocated objects (via HAllocate or HInnerAllocatedObject). |
- DCHECK(!access.IsInobject() || access.existing_inobject_property() || |
- obj->IsAllocate() || obj->IsInnerAllocatedObject()); |
- SetOperandAt(0, obj); |
- SetOperandAt(1, val); |
- SetOperandAt(2, obj); |
- access.SetGVNFlags(this, STORE); |
- } |
- |
- class HasTransitionField : public BitField<bool, 0, 1> {}; |
- class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {}; |
- |
- HObjectAccess access_; |
- HValue* dominator_; |
- uint32_t bit_field_; |
-}; |
- |
- |
-class HStoreNamedGeneric final : public HTemplateInstruction<3> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreNamedGeneric, HValue*, |
- Handle<Name>, HValue*, |
- LanguageMode, InlineCacheState); |
- HValue* object() const { return OperandAt(0); } |
- HValue* value() const { return OperandAt(1); } |
- HValue* context() const { return OperandAt(2); } |
- Handle<Name> name() const { return name_; } |
- LanguageMode language_mode() const { return language_mode_; } |
- InlineCacheState initialization_state() const { |
- return initialization_state_; |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- FeedbackVectorSlot slot() const { return slot_; } |
- Handle<TypeFeedbackVector> feedback_vector() const { |
- return feedback_vector_; |
- } |
- bool HasVectorAndSlot() const { return FLAG_vector_stores; } |
- void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, |
- FeedbackVectorSlot slot) { |
- feedback_vector_ = vector; |
- slot_ = slot; |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric) |
- |
- private: |
- HStoreNamedGeneric(HValue* context, HValue* object, Handle<Name> name, |
- HValue* value, LanguageMode language_mode, |
- InlineCacheState initialization_state) |
- : name_(name), |
- language_mode_(language_mode), |
- initialization_state_(initialization_state) { |
- SetOperandAt(0, object); |
- SetOperandAt(1, value); |
- SetOperandAt(2, context); |
- SetAllSideEffects(); |
- } |
- |
- Handle<Name> name_; |
- Handle<TypeFeedbackVector> feedback_vector_; |
- FeedbackVectorSlot slot_; |
- LanguageMode language_mode_; |
- InlineCacheState initialization_state_; |
-}; |
- |
- |
-class HStoreGlobalViaContext final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreGlobalViaContext, HValue*, |
- int, int, LanguageMode); |
- HValue* context() const { return OperandAt(0); } |
- HValue* value() const { return OperandAt(1); } |
- int depth() const { return depth_; } |
- int slot_index() const { return slot_index_; } |
- LanguageMode language_mode() const { return language_mode_; } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(StoreGlobalViaContext) |
- |
- private: |
- HStoreGlobalViaContext(HValue* context, HValue* value, int depth, |
- int slot_index, LanguageMode language_mode) |
- : depth_(depth), slot_index_(slot_index), language_mode_(language_mode) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, value); |
- SetAllSideEffects(); |
- } |
- |
- int const depth_; |
- int const slot_index_; |
- LanguageMode const language_mode_; |
-}; |
- |
- |
-class HStoreKeyed final : public HTemplateInstruction<3>, |
- public ArrayInstructionInterface { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*, |
- ElementsKind); |
- DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*, |
- ElementsKind, StoreFieldOrKeyedMode); |
- DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*, |
- ElementsKind, StoreFieldOrKeyedMode, int); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- // kind_fast: tagged[int32] = tagged |
- // kind_double: tagged[int32] = double |
- // kind_smi : tagged[int32] = smi |
- // kind_fixed_typed_array: tagged[int32] = (double | int32) |
- // kind_external: external[int32] = (double | int32) |
- if (index == 0) { |
- return is_fixed_typed_array() ? Representation::External() |
- : Representation::Tagged(); |
- } else if (index == 1) { |
- return ArrayInstructionInterface::KeyedAccessIndexRequirement( |
- OperandAt(1)->representation()); |
- } |
- |
- DCHECK_EQ(index, 2); |
- return RequiredValueRepresentation(elements_kind(), store_mode()); |
- } |
- |
- static Representation RequiredValueRepresentation( |
- ElementsKind kind, StoreFieldOrKeyedMode mode) { |
- if (IsDoubleOrFloatElementsKind(kind)) { |
- return Representation::Double(); |
- } |
- |
- if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() && |
- mode == STORE_TO_INITIALIZED_ENTRY) { |
- return Representation::Integer32(); |
- } |
- |
- if (IsFastSmiElementsKind(kind)) { |
- return Representation::Smi(); |
- } |
- |
- if (IsFixedTypedArrayElementsKind(kind)) { |
- return Representation::Integer32(); |
- } |
- return Representation::Tagged(); |
- } |
- |
- bool is_fixed_typed_array() const { |
- return IsFixedTypedArrayElementsKind(elements_kind()); |
- } |
- |
- Representation observed_input_representation(int index) override { |
- if (index < 2) return RequiredInputRepresentation(index); |
- if (IsUninitialized()) { |
- return Representation::None(); |
- } |
- Representation r = |
- RequiredValueRepresentation(elements_kind(), store_mode()); |
- // For fast object elements kinds, don't assume anything. |
- if (r.IsTagged()) return Representation::None(); |
- return r; |
- } |
- |
- HValue* elements() const { return OperandAt(0); } |
- HValue* key() const { return OperandAt(1); } |
- HValue* value() const { return OperandAt(2); } |
- bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); } |
- StoreFieldOrKeyedMode store_mode() const { |
- return StoreModeField::decode(bit_field_); |
- } |
- ElementsKind elements_kind() const override { |
- return ElementsKindField::decode(bit_field_); |
- } |
- uint32_t base_offset() const { return base_offset_; } |
- bool TryIncreaseBaseOffset(uint32_t increase_by_value) override; |
- HValue* GetKey() override { return key(); } |
- void SetKey(HValue* key) override { SetOperandAt(1, key); } |
- bool IsDehoisted() const override { |
- return IsDehoistedField::decode(bit_field_); |
- } |
- void SetDehoisted(bool is_dehoisted) override { |
- bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted); |
- } |
- bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); } |
- void SetUninitialized(bool is_uninitialized) { |
- bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized); |
- } |
- |
- bool IsConstantHoleStore() { |
- return value()->IsConstant() && HConstant::cast(value())->IsTheHole(); |
- } |
- |
- virtual bool HandleSideEffectDominator(GVNFlag side_effect, |
- HValue* dominator) override { |
- DCHECK(side_effect == kNewSpacePromotion); |
- dominator_ = dominator; |
- return false; |
- } |
- |
- HValue* dominator() const { return dominator_; } |
- |
- bool NeedsWriteBarrier() { |
- if (value_is_smi()) { |
- return false; |
- } else { |
- return StoringValueNeedsWriteBarrier(value()) && |
- ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator()); |
- } |
- } |
- |
- PointersToHereCheck PointersToHereCheckForValue() const { |
- return PointersToHereCheckForObject(value(), dominator()); |
- } |
- |
- bool NeedsCanonicalization(); |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(StoreKeyed) |
- |
- private: |
- HStoreKeyed(HValue* obj, HValue* key, HValue* val, ElementsKind elements_kind, |
- StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE, |
- int offset = kDefaultKeyedHeaderOffsetSentinel) |
- : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel |
- ? GetDefaultHeaderSizeForElementsKind(elements_kind) |
- : offset), |
- bit_field_(IsDehoistedField::encode(false) | |
- IsUninitializedField::encode(false) | |
- StoreModeField::encode(store_mode) | |
- ElementsKindField::encode(elements_kind)), |
- dominator_(NULL) { |
- SetOperandAt(0, obj); |
- SetOperandAt(1, key); |
- SetOperandAt(2, val); |
- |
- if (IsFastObjectElementsKind(elements_kind)) { |
- SetFlag(kTrackSideEffectDominators); |
- SetDependsOnFlag(kNewSpacePromotion); |
- } |
- if (IsFastDoubleElementsKind(elements_kind)) { |
- SetChangesFlag(kDoubleArrayElements); |
- } else if (IsFastSmiElementsKind(elements_kind)) { |
- SetChangesFlag(kArrayElements); |
- } else if (is_fixed_typed_array()) { |
- SetChangesFlag(kTypedArrayElements); |
- SetChangesFlag(kExternalMemory); |
- SetFlag(kAllowUndefinedAsNaN); |
- } else { |
- SetChangesFlag(kArrayElements); |
- } |
- |
- // {UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating. |
- if (elements_kind >= UINT8_ELEMENTS && elements_kind <= INT32_ELEMENTS) { |
- SetFlag(kTruncatingToInt32); |
- } |
- } |
- |
- class IsDehoistedField : public BitField<bool, 0, 1> {}; |
- class IsUninitializedField : public BitField<bool, 1, 1> {}; |
- class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {}; |
- class ElementsKindField : public BitField<ElementsKind, 3, 5> {}; |
- |
- uint32_t base_offset_; |
- uint32_t bit_field_; |
- HValue* dominator_; |
-}; |
- |
- |
-class HStoreKeyedGeneric final : public HTemplateInstruction<4> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreKeyedGeneric, HValue*, |
- HValue*, HValue*, LanguageMode, |
- InlineCacheState); |
- |
- HValue* object() const { return OperandAt(0); } |
- HValue* key() const { return OperandAt(1); } |
- HValue* value() const { return OperandAt(2); } |
- HValue* context() const { return OperandAt(3); } |
- LanguageMode language_mode() const { return language_mode_; } |
- InlineCacheState initialization_state() const { |
- return initialization_state_; |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- // tagged[tagged] = tagged |
- return Representation::Tagged(); |
- } |
- |
- FeedbackVectorSlot slot() const { return slot_; } |
- Handle<TypeFeedbackVector> feedback_vector() const { |
- return feedback_vector_; |
- } |
- bool HasVectorAndSlot() const { |
- DCHECK(!(FLAG_vector_stores && initialization_state_ != MEGAMORPHIC) || |
- !feedback_vector_.is_null()); |
- return !feedback_vector_.is_null(); |
- } |
- void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, |
- FeedbackVectorSlot slot) { |
- feedback_vector_ = vector; |
- slot_ = slot; |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric) |
- |
- private: |
- HStoreKeyedGeneric(HValue* context, HValue* object, HValue* key, |
- HValue* value, LanguageMode language_mode, |
- InlineCacheState initialization_state) |
- : language_mode_(language_mode), |
- initialization_state_(initialization_state) { |
- SetOperandAt(0, object); |
- SetOperandAt(1, key); |
- SetOperandAt(2, value); |
- SetOperandAt(3, context); |
- SetAllSideEffects(); |
- } |
- |
- Handle<TypeFeedbackVector> feedback_vector_; |
- FeedbackVectorSlot slot_; |
- LanguageMode language_mode_; |
- InlineCacheState initialization_state_; |
-}; |
- |
- |
-class HTransitionElementsKind final : public HTemplateInstruction<2> { |
- public: |
- inline static HTransitionElementsKind* New(Isolate* isolate, Zone* zone, |
- HValue* context, HValue* object, |
- Handle<Map> original_map, |
- Handle<Map> transitioned_map) { |
- return new(zone) HTransitionElementsKind(context, object, |
- original_map, transitioned_map); |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HValue* object() const { return OperandAt(0); } |
- HValue* context() const { return OperandAt(1); } |
- Unique<Map> original_map() const { return original_map_; } |
- Unique<Map> transitioned_map() const { return transitioned_map_; } |
- ElementsKind from_kind() const { |
- return FromElementsKindField::decode(bit_field_); |
- } |
- ElementsKind to_kind() const { |
- return ToElementsKindField::decode(bit_field_); |
- } |
- bool map_is_stable() const { return MapIsStableField::decode(bit_field_); } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- HTransitionElementsKind* instr = HTransitionElementsKind::cast(other); |
- return original_map_ == instr->original_map_ && |
- transitioned_map_ == instr->transitioned_map_; |
- } |
- |
- int RedefinedOperandIndex() override { return 0; } |
- |
- private: |
- HTransitionElementsKind(HValue* context, HValue* object, |
- Handle<Map> original_map, |
- Handle<Map> transitioned_map) |
- : original_map_(Unique<Map>(original_map)), |
- transitioned_map_(Unique<Map>(transitioned_map)), |
- bit_field_( |
- FromElementsKindField::encode(original_map->elements_kind()) | |
- ToElementsKindField::encode(transitioned_map->elements_kind()) | |
- MapIsStableField::encode(transitioned_map->is_stable())) { |
- SetOperandAt(0, object); |
- SetOperandAt(1, context); |
- SetFlag(kUseGVN); |
- SetChangesFlag(kElementsKind); |
- if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) { |
- SetChangesFlag(kElementsPointer); |
- SetChangesFlag(kNewSpacePromotion); |
- } |
- set_representation(Representation::Tagged()); |
- } |
- |
- class FromElementsKindField : public BitField<ElementsKind, 0, 5> {}; |
- class ToElementsKindField : public BitField<ElementsKind, 5, 5> {}; |
- class MapIsStableField : public BitField<bool, 10, 1> {}; |
- |
- Unique<Map> original_map_; |
- Unique<Map> transitioned_map_; |
- uint32_t bit_field_; |
-}; |
- |
- |
-class HStringAdd final : public HBinaryOperation { |
- public: |
- static HInstruction* New( |
- Isolate* isolate, Zone* zone, HValue* context, HValue* left, |
- HValue* right, PretenureFlag pretenure_flag = NOT_TENURED, |
- StringAddFlags flags = STRING_ADD_CHECK_BOTH, |
- Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()); |
- |
- StringAddFlags flags() const { return flags_; } |
- PretenureFlag pretenure_flag() const { return pretenure_flag_; } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(StringAdd) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- return flags_ == HStringAdd::cast(other)->flags_ && |
- pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_; |
- } |
- |
- private: |
- HStringAdd(HValue* context, HValue* left, HValue* right, |
- PretenureFlag pretenure_flag, StringAddFlags flags, |
- Handle<AllocationSite> allocation_site) |
- : HBinaryOperation(context, left, right, Strength::WEAK, HType::String()), |
- flags_(flags), |
- pretenure_flag_(pretenure_flag) { |
- set_representation(Representation::Tagged()); |
- if ((flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT) { |
- SetAllSideEffects(); |
- ClearFlag(kUseGVN); |
- } else { |
- SetChangesFlag(kNewSpacePromotion); |
- SetFlag(kUseGVN); |
- } |
- SetDependsOnFlag(kMaps); |
- if (FLAG_trace_pretenuring) { |
- PrintF("HStringAdd with AllocationSite %p %s\n", |
- allocation_site.is_null() |
- ? static_cast<void*>(NULL) |
- : static_cast<void*>(*allocation_site), |
- pretenure_flag == TENURED ? "tenured" : "not tenured"); |
- } |
- } |
- |
- bool IsDeletable() const final { |
- return (flags_ & STRING_ADD_CONVERT) != STRING_ADD_CONVERT; |
- } |
- |
- const StringAddFlags flags_; |
- const PretenureFlag pretenure_flag_; |
-}; |
- |
- |
-class HStringCharCodeAt final : public HTemplateInstruction<3> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt, |
- HValue*, |
- HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- // The index is supposed to be Integer32. |
- return index == 2 |
- ? Representation::Integer32() |
- : Representation::Tagged(); |
- } |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* string() const { return OperandAt(1); } |
- HValue* index() const { return OperandAt(2); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- Range* InferRange(Zone* zone) override { |
- return new(zone) Range(0, String::kMaxUtf16CodeUnit); |
- } |
- |
- private: |
- HStringCharCodeAt(HValue* context, HValue* string, HValue* index) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, string); |
- SetOperandAt(2, index); |
- set_representation(Representation::Integer32()); |
- SetFlag(kUseGVN); |
- SetDependsOnFlag(kMaps); |
- SetDependsOnFlag(kStringChars); |
- SetChangesFlag(kNewSpacePromotion); |
- } |
- |
- // No side effects: runtime function assumes string + number inputs. |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HStringCharFromCode final : public HTemplateInstruction<2> { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- HValue* char_code); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return index == 0 |
- ? Representation::Tagged() |
- : Representation::Integer32(); |
- } |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* value() const { return OperandAt(1); } |
- |
- bool DataEquals(HValue* other) override { return true; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode) |
- |
- private: |
- HStringCharFromCode(HValue* context, HValue* char_code) |
- : HTemplateInstruction<2>(HType::String()) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, char_code); |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- SetChangesFlag(kNewSpacePromotion); |
- } |
- |
- bool IsDeletable() const override { |
- return !value()->ToNumberCanBeObserved(); |
- } |
-}; |
- |
- |
-template <int V> |
-class HMaterializedLiteral : public HTemplateInstruction<V> { |
- public: |
- HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode) |
- : literal_index_(index), depth_(depth), allocation_site_mode_(mode) { |
- this->set_representation(Representation::Tagged()); |
- } |
- |
- HMaterializedLiteral<V>(int index, int depth) |
- : literal_index_(index), depth_(depth), |
- allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) { |
- this->set_representation(Representation::Tagged()); |
- } |
- |
- int literal_index() const { return literal_index_; } |
- int depth() const { return depth_; } |
- AllocationSiteMode allocation_site_mode() const { |
- return allocation_site_mode_; |
- } |
- |
- private: |
- bool IsDeletable() const final { return true; } |
- |
- int literal_index_; |
- int depth_; |
- AllocationSiteMode allocation_site_mode_; |
-}; |
- |
- |
-class HRegExpLiteral final : public HMaterializedLiteral<1> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral, |
- Handle<FixedArray>, |
- Handle<String>, |
- Handle<String>, |
- int); |
- |
- HValue* context() { return OperandAt(0); } |
- Handle<FixedArray> literals() { return literals_; } |
- Handle<String> pattern() { return pattern_; } |
- Handle<String> flags() { return flags_; } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral) |
- |
- private: |
- HRegExpLiteral(HValue* context, |
- Handle<FixedArray> literals, |
- Handle<String> pattern, |
- Handle<String> flags, |
- int literal_index) |
- : HMaterializedLiteral<1>(literal_index, 0), |
- literals_(literals), |
- pattern_(pattern), |
- flags_(flags) { |
- SetOperandAt(0, context); |
- SetAllSideEffects(); |
- set_type(HType::JSObject()); |
- } |
- |
- Handle<FixedArray> literals_; |
- Handle<String> pattern_; |
- Handle<String> flags_; |
-}; |
- |
- |
-class HTypeof final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*); |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* value() const { return OperandAt(1); } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(Typeof) |
- |
- private: |
- explicit HTypeof(HValue* context, HValue* value) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, value); |
- set_representation(Representation::Tagged()); |
- } |
- |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HTrapAllocationMemento final : public HTemplateInstruction<1> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HValue* object() { return OperandAt(0); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento) |
- |
- private: |
- explicit HTrapAllocationMemento(HValue* obj) { |
- SetOperandAt(0, obj); |
- } |
-}; |
- |
- |
-class HMaybeGrowElements final : public HTemplateInstruction<5> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(HMaybeGrowElements, HValue*, |
- HValue*, HValue*, HValue*, bool, |
- ElementsKind); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- if (index < 3) { |
- return Representation::Tagged(); |
- } |
- DCHECK(index == 3 || index == 4); |
- return Representation::Integer32(); |
- } |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* object() const { return OperandAt(1); } |
- HValue* elements() const { return OperandAt(2); } |
- HValue* key() const { return OperandAt(3); } |
- HValue* current_capacity() const { return OperandAt(4); } |
- |
- bool is_js_array() const { return is_js_array_; } |
- ElementsKind kind() const { return kind_; } |
- |
- DECLARE_CONCRETE_INSTRUCTION(MaybeGrowElements) |
- |
- protected: |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- explicit HMaybeGrowElements(HValue* context, HValue* object, HValue* elements, |
- HValue* key, HValue* current_capacity, |
- bool is_js_array, ElementsKind kind) { |
- is_js_array_ = is_js_array; |
- kind_ = kind; |
- |
- SetOperandAt(0, context); |
- SetOperandAt(1, object); |
- SetOperandAt(2, elements); |
- SetOperandAt(3, key); |
- SetOperandAt(4, current_capacity); |
- |
- SetFlag(kUseGVN); |
- SetChangesFlag(kElementsPointer); |
- SetChangesFlag(kNewSpacePromotion); |
- set_representation(Representation::Tagged()); |
- } |
- |
- bool is_js_array_; |
- ElementsKind kind_; |
-}; |
- |
- |
-class HToFastProperties final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(ToFastProperties) |
- |
- private: |
- explicit HToFastProperties(HValue* value) : HUnaryOperation(value) { |
- set_representation(Representation::Tagged()); |
- SetChangesFlag(kNewSpacePromotion); |
- |
- // This instruction is not marked as kChangesMaps, but does |
- // change the map of the input operand. Use it only when creating |
- // object literals via a runtime call. |
- DCHECK(value->IsCallRuntime()); |
-#ifdef DEBUG |
- const Runtime::Function* function = HCallRuntime::cast(value)->function(); |
- DCHECK(function->function_id == Runtime::kCreateObjectLiteral); |
-#endif |
- } |
- |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HDateField final : public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*); |
- |
- Smi* index() const { return index_; } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(DateField) |
- |
- private: |
- HDateField(HValue* date, Smi* index) |
- : HUnaryOperation(date), index_(index) { |
- set_representation(Representation::Tagged()); |
- } |
- |
- Smi* index_; |
-}; |
- |
- |
-class HSeqStringGetChar final : public HTemplateInstruction<2> { |
- public: |
- static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, |
- String::Encoding encoding, HValue* string, |
- HValue* index); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return (index == 0) ? Representation::Tagged() |
- : Representation::Integer32(); |
- } |
- |
- String::Encoding encoding() const { return encoding_; } |
- HValue* string() const { return OperandAt(0); } |
- HValue* index() const { return OperandAt(1); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar) |
- |
- protected: |
- bool DataEquals(HValue* other) override { |
- return encoding() == HSeqStringGetChar::cast(other)->encoding(); |
- } |
- |
- Range* InferRange(Zone* zone) override { |
- if (encoding() == String::ONE_BYTE_ENCODING) { |
- return new(zone) Range(0, String::kMaxOneByteCharCode); |
- } else { |
- DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding()); |
- return new(zone) Range(0, String::kMaxUtf16CodeUnit); |
- } |
- } |
- |
- private: |
- HSeqStringGetChar(String::Encoding encoding, |
- HValue* string, |
- HValue* index) : encoding_(encoding) { |
- SetOperandAt(0, string); |
- SetOperandAt(1, index); |
- set_representation(Representation::Integer32()); |
- SetFlag(kUseGVN); |
- SetDependsOnFlag(kStringChars); |
- } |
- |
- bool IsDeletable() const override { return true; } |
- |
- String::Encoding encoding_; |
-}; |
- |
- |
-class HSeqStringSetChar final : public HTemplateInstruction<4> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4( |
- HSeqStringSetChar, String::Encoding, |
- HValue*, HValue*, HValue*); |
- |
- String::Encoding encoding() { return encoding_; } |
- HValue* context() { return OperandAt(0); } |
- HValue* string() { return OperandAt(1); } |
- HValue* index() { return OperandAt(2); } |
- HValue* value() { return OperandAt(3); } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return (index <= 1) ? Representation::Tagged() |
- : Representation::Integer32(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar) |
- |
- private: |
- HSeqStringSetChar(HValue* context, |
- String::Encoding encoding, |
- HValue* string, |
- HValue* index, |
- HValue* value) : encoding_(encoding) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, string); |
- SetOperandAt(2, index); |
- SetOperandAt(3, value); |
- set_representation(Representation::Tagged()); |
- SetChangesFlag(kStringChars); |
- } |
- |
- String::Encoding encoding_; |
-}; |
- |
- |
-class HCheckMapValue final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HType CalculateInferredType() override { |
- if (value()->type().IsHeapObject()) return value()->type(); |
- return HType::HeapObject(); |
- } |
- |
- HValue* value() const { return OperandAt(0); } |
- HValue* map() const { return OperandAt(1); } |
- |
- HValue* Canonicalize() override; |
- |
- DECLARE_CONCRETE_INSTRUCTION(CheckMapValue) |
- |
- protected: |
- int RedefinedOperandIndex() override { return 0; } |
- |
- bool DataEquals(HValue* other) override { return true; } |
- |
- private: |
- HCheckMapValue(HValue* value, HValue* map) |
- : HTemplateInstruction<2>(HType::HeapObject()) { |
- SetOperandAt(0, value); |
- SetOperandAt(1, map); |
- set_representation(Representation::Tagged()); |
- SetFlag(kUseGVN); |
- SetDependsOnFlag(kMaps); |
- SetDependsOnFlag(kElementsKind); |
- } |
-}; |
- |
- |
-class HForInPrepareMap final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HValue* context() const { return OperandAt(0); } |
- HValue* enumerable() const { return OperandAt(1); } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HType CalculateInferredType() override { return HType::Tagged(); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap); |
- |
- private: |
- HForInPrepareMap(HValue* context, |
- HValue* object) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, object); |
- set_representation(Representation::Tagged()); |
- SetAllSideEffects(); |
- } |
-}; |
- |
- |
-class HForInCacheArray final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int); |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- HValue* enumerable() const { return OperandAt(0); } |
- HValue* map() const { return OperandAt(1); } |
- int idx() const { return idx_; } |
- |
- HForInCacheArray* index_cache() { |
- return index_cache_; |
- } |
- |
- void set_index_cache(HForInCacheArray* index_cache) { |
- index_cache_ = index_cache; |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HType CalculateInferredType() override { return HType::Tagged(); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray); |
- |
- private: |
- HForInCacheArray(HValue* enumerable, |
- HValue* keys, |
- int idx) : idx_(idx) { |
- SetOperandAt(0, enumerable); |
- SetOperandAt(1, keys); |
- set_representation(Representation::Tagged()); |
- } |
- |
- int idx_; |
- HForInCacheArray* index_cache_; |
-}; |
- |
- |
-class HLoadFieldByIndex final : public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*); |
- |
- HLoadFieldByIndex(HValue* object, |
- HValue* index) { |
- SetOperandAt(0, object); |
- SetOperandAt(1, index); |
- SetChangesFlag(kNewSpacePromotion); |
- set_representation(Representation::Tagged()); |
- } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- if (index == 1) { |
- return Representation::Smi(); |
- } else { |
- return Representation::Tagged(); |
- } |
- } |
- |
- HValue* object() const { return OperandAt(0); } |
- HValue* index() const { return OperandAt(1); } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- HType CalculateInferredType() override { return HType::Tagged(); } |
- |
- DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex); |
- |
- private: |
- bool IsDeletable() const override { return true; } |
-}; |
- |
- |
-class HStoreFrameContext: public HUnaryOperation { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*); |
- |
- HValue* context() { return OperandAt(0); } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext) |
- private: |
- explicit HStoreFrameContext(HValue* context) |
- : HUnaryOperation(context) { |
- set_representation(Representation::Tagged()); |
- SetChangesFlag(kContextSlots); |
- } |
-}; |
- |
- |
-class HAllocateBlockContext: public HTemplateInstruction<2> { |
- public: |
- DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*, |
- HValue*, Handle<ScopeInfo>); |
- HValue* context() const { return OperandAt(0); } |
- HValue* function() const { return OperandAt(1); } |
- Handle<ScopeInfo> scope_info() const { return scope_info_; } |
- |
- Representation RequiredInputRepresentation(int index) override { |
- return Representation::Tagged(); |
- } |
- |
- std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT |
- |
- DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext) |
- |
- private: |
- HAllocateBlockContext(HValue* context, |
- HValue* function, |
- Handle<ScopeInfo> scope_info) |
- : scope_info_(scope_info) { |
- SetOperandAt(0, context); |
- SetOperandAt(1, function); |
- set_representation(Representation::Tagged()); |
- } |
- |
- Handle<ScopeInfo> scope_info_; |
-}; |
- |
- |
- |
-#undef DECLARE_INSTRUCTION |
-#undef DECLARE_CONCRETE_INSTRUCTION |
- |
-} // namespace internal |
-} // namespace v8 |
- |
-#endif // V8_HYDROGEN_INSTRUCTIONS_H_ |