| Index: src/hydrogen-instructions.h
|
| diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
|
| index 763b6369e3583a0a1c9b1a41bd3af7e93e8fe34e..c36388ee6abd359898fe1f57134b8e9f19311d81 100644
|
| --- a/src/hydrogen-instructions.h
|
| +++ b/src/hydrogen-instructions.h
|
| @@ -33,6 +33,7 @@
|
| #include "allocation.h"
|
| #include "code-stubs.h"
|
| #include "data-flow.h"
|
| +#include "deoptimizer.h"
|
| #include "small-pointer-list.h"
|
| #include "string-stream.h"
|
| #include "v8conversions.h"
|
| @@ -91,17 +92,18 @@ class LChunkBuilder;
|
| V(CheckHeapObject) \
|
| V(CheckInstanceType) \
|
| V(CheckMaps) \
|
| - V(CheckSmi) \
|
| + V(CheckMapValue) \
|
| V(CheckPrototypeMaps) \
|
| + V(CheckSmi) \
|
| V(ClampToUint8) \
|
| V(ClassOfTestAndBranch) \
|
| V(CompareNumericAndBranch) \
|
| V(CompareGeneric) \
|
| V(CompareObjectEqAndBranch) \
|
| V(CompareMap) \
|
| - V(CompareConstantEqAndBranch) \
|
| V(Constant) \
|
| V(Context) \
|
| + V(DateField) \
|
| V(DebugBreak) \
|
| V(DeclareGlobals) \
|
| V(Deoptimize) \
|
| @@ -111,6 +113,8 @@ class LChunkBuilder;
|
| V(EnterInlined) \
|
| V(EnvironmentMarker) \
|
| V(ForceRepresentation) \
|
| + V(ForInCacheArray) \
|
| + V(ForInPrepareMap) \
|
| V(FunctionLiteral) \
|
| V(GetCachedArrayIndex) \
|
| V(GlobalObject) \
|
| @@ -134,6 +138,7 @@ class LChunkBuilder;
|
| V(LinkObjectInList) \
|
| V(LoadContextSlot) \
|
| V(LoadExternalArrayPointer) \
|
| + V(LoadFieldByIndex) \
|
| V(LoadFunctionPrototype) \
|
| V(LoadGlobalCell) \
|
| V(LoadGlobalGeneric) \
|
| @@ -162,7 +167,6 @@ class LChunkBuilder;
|
| V(Shl) \
|
| V(Shr) \
|
| V(Simulate) \
|
| - V(SoftDeoptimize) \
|
| V(StackCheck) \
|
| V(StoreContextSlot) \
|
| V(StoreGlobalCell) \
|
| @@ -188,11 +192,6 @@ class LChunkBuilder;
|
| V(UnknownOSRValue) \
|
| V(UseConst) \
|
| V(ValueOf) \
|
| - V(ForInPrepareMap) \
|
| - V(ForInCacheArray) \
|
| - V(CheckMapValue) \
|
| - V(LoadFieldByIndex) \
|
| - V(DateField) \
|
| V(WrapReceiver)
|
|
|
| #define GVN_TRACKED_FLAG_LIST(V) \
|
| @@ -200,19 +199,20 @@ class LChunkBuilder;
|
| V(NewSpacePromotion)
|
|
|
| #define GVN_UNTRACKED_FLAG_LIST(V) \
|
| - V(Calls) \
|
| - V(InobjectFields) \
|
| + V(ArrayElements) \
|
| + V(ArrayLengths) \
|
| V(BackingStoreFields) \
|
| + V(Calls) \
|
| + V(ContextSlots) \
|
| + V(DoubleArrayElements) \
|
| V(DoubleFields) \
|
| V(ElementsKind) \
|
| V(ElementsPointer) \
|
| - V(ArrayElements) \
|
| - V(DoubleArrayElements) \
|
| - V(SpecializedArrayElements) \
|
| V(GlobalVars) \
|
| - V(ArrayLengths) \
|
| - V(ContextSlots) \
|
| - V(OsrEntries)
|
| + V(InobjectFields) \
|
| + V(OsrEntries) \
|
| + V(SpecializedArrayElements)
|
| +
|
|
|
| #define DECLARE_ABSTRACT_INSTRUCTION(type) \
|
| virtual bool Is##type() const { return true; } \
|
| @@ -294,9 +294,9 @@ class Range: public ZoneObject {
|
| void AddConstant(int32_t value);
|
| void Sar(int32_t value);
|
| void Shl(int32_t value);
|
| - bool AddAndCheckOverflow(Range* other);
|
| - bool SubAndCheckOverflow(Range* other);
|
| - bool MulAndCheckOverflow(Range* other);
|
| + 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_;
|
| @@ -407,6 +407,11 @@ class HType {
|
| return ((type_ & kString) == kString);
|
| }
|
|
|
| + bool IsNonString() const {
|
| + return IsTaggedPrimitive() || IsSmi() || IsHeapNumber() ||
|
| + IsBoolean() || IsJSArray();
|
| + }
|
| +
|
| bool IsBoolean() const {
|
| ASSERT(type_ != kUninitialized);
|
| return ((type_ & kBoolean) == kBoolean);
|
| @@ -800,6 +805,8 @@ class HValue: public ZoneObject {
|
| kIsArguments,
|
| kTruncatingToInt32,
|
| kAllUsesTruncatingToInt32,
|
| + kTruncatingToSmi,
|
| + kAllUsesTruncatingToSmi,
|
| // Set after an instruction is killed.
|
| kIsDead,
|
| // Instructions that are allowed to produce full range unsigned integer
|
| @@ -886,6 +893,7 @@ class HValue: public ZoneObject {
|
| HUseIterator uses() const { return HUseIterator(use_list_); }
|
|
|
| virtual bool EmitAtUses() { return false; }
|
| +
|
| Representation representation() const { return representation_; }
|
| void ChangeRepresentation(Representation r) {
|
| ASSERT(CheckFlag(kFlexibleRepresentation));
|
| @@ -1161,6 +1169,7 @@ class HValue: public ZoneObject {
|
| }
|
| Representation RepresentationFromUses();
|
| Representation RepresentationFromUseRequirements();
|
| + bool HasNonSmiUse();
|
| virtual void UpdateRepresentation(Representation new_rep,
|
| HInferRepresentationPhase* h_infer,
|
| const char* reason);
|
| @@ -1493,16 +1502,20 @@ class HNumericConstraint : public HTemplateInstruction<2> {
|
| };
|
|
|
|
|
| -// We insert soft-deoptimize when we hit code with unknown typefeedback,
|
| -// so that we get a chance of re-optimizing with useful typefeedback.
|
| -// HSoftDeoptimize does not end a basic block as opposed to HDeoptimize.
|
| -class HSoftDeoptimize: public HTemplateInstruction<0> {
|
| +class HDeoptimize: public HTemplateInstruction<0> {
|
| public:
|
| + explicit HDeoptimize(Deoptimizer::BailoutType type) : type_(type) {}
|
| +
|
| virtual Representation RequiredInputRepresentation(int index) {
|
| return Representation::None();
|
| }
|
|
|
| - DECLARE_CONCRETE_INSTRUCTION(SoftDeoptimize)
|
| + Deoptimizer::BailoutType type() { return type_; }
|
| +
|
| + DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
|
| +
|
| + private:
|
| + Deoptimizer::BailoutType type_;
|
| };
|
|
|
|
|
| @@ -1517,59 +1530,6 @@ class HDebugBreak: public HTemplateInstruction<0> {
|
| };
|
|
|
|
|
| -class HDeoptimize: public HControlInstruction {
|
| - public:
|
| - HDeoptimize(int environment_length,
|
| - int first_local_index,
|
| - int first_expression_index,
|
| - Zone* zone)
|
| - : values_(environment_length, zone),
|
| - first_local_index_(first_local_index),
|
| - first_expression_index_(first_expression_index) { }
|
| -
|
| - virtual Representation RequiredInputRepresentation(int index) {
|
| - return Representation::None();
|
| - }
|
| -
|
| - virtual int OperandCount() { return values_.length(); }
|
| - virtual HValue* OperandAt(int index) const { return values_[index]; }
|
| - virtual void PrintDataTo(StringStream* stream);
|
| -
|
| - virtual int SuccessorCount() { return 0; }
|
| - virtual HBasicBlock* SuccessorAt(int i) {
|
| - UNREACHABLE();
|
| - return NULL;
|
| - }
|
| - virtual void SetSuccessorAt(int i, HBasicBlock* block) {
|
| - UNREACHABLE();
|
| - }
|
| -
|
| - void AddEnvironmentValue(HValue* value, Zone* zone) {
|
| - values_.Add(NULL, zone);
|
| - SetOperandAt(values_.length() - 1, value);
|
| - }
|
| - int first_local_index() { return first_local_index_; }
|
| - int first_expression_index() { return first_expression_index_; }
|
| -
|
| - DECLARE_CONCRETE_INSTRUCTION(Deoptimize)
|
| -
|
| - enum UseEnvironment {
|
| - kNoUses,
|
| - kUseAll
|
| - };
|
| -
|
| - protected:
|
| - virtual void InternalSetOperandAt(int index, HValue* value) {
|
| - values_[index] = value;
|
| - }
|
| -
|
| - private:
|
| - ZoneList<HValue*> values_;
|
| - int first_local_index_;
|
| - int first_expression_index_;
|
| -};
|
| -
|
| -
|
| class HGoto: public HTemplateControlInstruction<1, 0> {
|
| public:
|
| explicit HGoto(HBasicBlock* target) {
|
| @@ -1758,7 +1718,8 @@ class HChange: public HUnaryOperation {
|
| public:
|
| HChange(HValue* value,
|
| Representation to,
|
| - bool is_truncating,
|
| + bool is_truncating_to_smi,
|
| + bool is_truncating_to_int32,
|
| bool allow_undefined_as_nan)
|
| : HUnaryOperation(value) {
|
| ASSERT(!value->representation().IsNone());
|
| @@ -1767,7 +1728,8 @@ class HChange: public HUnaryOperation {
|
| set_representation(to);
|
| SetFlag(kUseGVN);
|
| if (allow_undefined_as_nan) SetFlag(kAllowUndefinedAsNaN);
|
| - if (is_truncating) SetFlag(kTruncatingToInt32);
|
| + if (is_truncating_to_smi) SetFlag(kTruncatingToSmi);
|
| + if (is_truncating_to_int32) SetFlag(kTruncatingToInt32);
|
| if (value->representation().IsSmi() || value->type().IsSmi()) {
|
| set_type(HType::Smi());
|
| } else {
|
| @@ -2668,6 +2630,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
|
| switch (op) {
|
| case kMathFloor:
|
| case kMathRound:
|
| + // TODO(verwaest): Set representation to flexible int starting as smi.
|
| set_representation(Representation::Integer32());
|
| break;
|
| case kMathAbs:
|
| @@ -2732,12 +2695,7 @@ class HLoadExternalArrayPointer: public HUnaryOperation {
|
| class HCheckMaps: public HTemplateInstruction<2> {
|
| public:
|
| static HCheckMaps* New(HValue* value, Handle<Map> map, Zone* zone,
|
| - HValue *typecheck = NULL) {
|
| - HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck);
|
| - check_map->map_set_.Add(map, zone);
|
| - return check_map;
|
| - }
|
| -
|
| + CompilationInfo* info, HValue *typecheck = NULL);
|
| static HCheckMaps* New(HValue* value, SmallMapList* maps, Zone* zone,
|
| HValue *typecheck = NULL) {
|
| HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck);
|
| @@ -2749,27 +2707,9 @@ class HCheckMaps: public HTemplateInstruction<2> {
|
| }
|
|
|
| static HCheckMaps* NewWithTransitions(HValue* value, Handle<Map> map,
|
| - Zone* zone) {
|
| - HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, value);
|
| - check_map->map_set_.Add(map, zone);
|
| -
|
| - // Since transitioned elements maps of the initial map don't fail the map
|
| - // check, the CheckMaps instruction doesn't need to depend on ElementsKinds.
|
| - check_map->ClearGVNFlag(kDependsOnElementsKind);
|
| -
|
| - ElementsKind kind = map->elements_kind();
|
| - bool packed = IsFastPackedElementsKind(kind);
|
| - while (CanTransitionToMoreGeneralFastElementsKind(kind, packed)) {
|
| - kind = GetNextMoreGeneralFastElementsKind(kind, packed);
|
| - Map* transitioned_map =
|
| - map->LookupElementsTransitionMap(kind);
|
| - if (transitioned_map) {
|
| - check_map->map_set_.Add(Handle<Map>(transitioned_map), zone);
|
| - }
|
| - };
|
| - check_map->map_set_.Sort();
|
| - return check_map;
|
| - }
|
| + Zone* zone, CompilationInfo* info);
|
| +
|
| + bool CanOmitMapChecks() { return omit_; }
|
|
|
| virtual bool HasEscapingOperandAt(int index) { return false; }
|
| virtual Representation RequiredInputRepresentation(int index) {
|
| @@ -2806,7 +2746,7 @@ class HCheckMaps: public HTemplateInstruction<2> {
|
| private:
|
| // Clients should use one of the static New* methods above.
|
| HCheckMaps(HValue* value, Zone *zone, HValue* typecheck)
|
| - : map_unique_ids_(0, zone) {
|
| + : omit_(false), map_unique_ids_(0, zone) {
|
| SetOperandAt(0, value);
|
| // Use the object value for the dependency if NULL is passed.
|
| // TODO(titzer): do GVN flags already express this dependency?
|
| @@ -2818,6 +2758,16 @@ class HCheckMaps: public HTemplateInstruction<2> {
|
| SetGVNFlag(kDependsOnElementsKind);
|
| }
|
|
|
| + void omit(CompilationInfo* info) {
|
| + omit_ = true;
|
| + for (int i = 0; i < map_set_.length(); i++) {
|
| + Handle<Map> map = map_set_.at(i);
|
| + map->AddDependentCompilationInfo(DependentCode::kPrototypeCheckGroup,
|
| + info);
|
| + }
|
| + }
|
| +
|
| + bool omit_;
|
| SmallMapList map_set_;
|
| ZoneList<UniqueValueId> map_unique_ids_;
|
| };
|
| @@ -3074,12 +3024,234 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
|
| };
|
|
|
|
|
| +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 HConstant;
|
| +class HBitwise;
|
| +
|
| +
|
| +class InductionVariableData : 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() {
|
| + ASSERT(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: public HValue {
|
| public:
|
| HPhi(int merged_index, Zone* zone)
|
| : inputs_(2, zone),
|
| merged_index_(merged_index),
|
| - phi_id_(-1) {
|
| + phi_id_(-1),
|
| + induction_variable_data_(NULL) {
|
| for (int i = 0; i < Representation::kNumRepresentations; i++) {
|
| non_phi_uses_[i] = 0;
|
| indirect_uses_[i] = 0;
|
| @@ -3110,6 +3282,21 @@ class HPhi: public HValue {
|
|
|
| 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() {
|
| + ASSERT(induction_variable_data_ == NULL);
|
| + induction_variable_data_ = InductionVariableData::ExaminePhi(this);
|
| + }
|
| +
|
| virtual void AddInformativeDefinitions();
|
|
|
| virtual void PrintTo(StringStream* stream);
|
| @@ -3177,6 +3364,7 @@ class HPhi: public HValue {
|
| int non_phi_uses_[Representation::kNumRepresentations];
|
| int indirect_uses_[Representation::kNumRepresentations];
|
| int phi_id_;
|
| + InductionVariableData* induction_variable_data_;
|
| };
|
|
|
|
|
| @@ -3296,6 +3484,11 @@ class HConstant: public HTemplateInstruction<0> {
|
| return handle_;
|
| }
|
|
|
| + bool InstanceOf(Handle<Map> map) {
|
| + return handle_->IsJSObject() &&
|
| + Handle<JSObject>::cast(handle_)->map() == *map;
|
| + }
|
| +
|
| bool IsSpecialDouble() const {
|
| return has_double_value_ &&
|
| (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) ||
|
| @@ -3339,7 +3532,7 @@ class HConstant: public HTemplateInstruction<0> {
|
| }
|
|
|
| virtual Representation KnownOptimalRepresentation() {
|
| - if (HasSmiValue()) return Representation::Smi();
|
| + if (HasSmiValue() && kSmiValueSize == 31) return Representation::Smi();
|
| if (HasInteger32Value()) return Representation::Integer32();
|
| if (HasNumberValue()) return Representation::Double();
|
| return Representation::Tagged();
|
| @@ -3350,7 +3543,8 @@ class HConstant: public HTemplateInstruction<0> {
|
| virtual HType CalculateInferredType();
|
| bool IsInteger() { return handle()->IsSmi(); }
|
| HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
|
| - HConstant* CopyToTruncatedInt32(Zone* zone) const;
|
| + Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
|
| + Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone);
|
| bool HasInteger32Value() const { return has_int32_value_; }
|
| int32_t Integer32Value() const {
|
| ASSERT(HasInteger32Value());
|
| @@ -3500,7 +3694,7 @@ class HBinaryOperation: public HTemplateInstruction<3> {
|
| // 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()->UseCount() == 1);
|
| + return right()->UseCount() == 1;
|
| }
|
|
|
| HValue* BetterLeftOperand() {
|
| @@ -3525,24 +3719,28 @@ class HBinaryOperation: public HTemplateInstruction<3> {
|
| return observed_input_representation_[index - 1];
|
| }
|
|
|
| - virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
|
| - virtual Representation RepresentationFromInputs();
|
| - virtual void AssumeRepresentation(Representation r);
|
| -
|
| virtual void UpdateRepresentation(Representation new_rep,
|
| HInferRepresentationPhase* h_infer,
|
| const char* reason) {
|
| - // By default, binary operations don't handle Smis.
|
| - if (new_rep.IsSmi()) {
|
| - new_rep = Representation::Integer32();
|
| - }
|
| - HValue::UpdateRepresentation(new_rep, h_infer, reason);
|
| + Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
|
| + ? Representation::Integer32() : new_rep;
|
| + HValue::UpdateRepresentation(rep, h_infer, reason);
|
| }
|
|
|
| + virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
|
| + virtual Representation RepresentationFromInputs();
|
| + Representation RepresentationFromOutput();
|
| + virtual void AssumeRepresentation(Representation r);
|
| +
|
| virtual bool IsCommutative() const { return false; }
|
|
|
| virtual void PrintDataTo(StringStream* stream);
|
|
|
| + virtual Representation RequiredInputRepresentation(int index) {
|
| + if (index == 0) return Representation::Tagged();
|
| + return representation();
|
| + }
|
| +
|
| DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
|
|
|
| private:
|
| @@ -3695,15 +3893,16 @@ class HBoundsCheck: public HTemplateInstruction<2> {
|
| HBoundsCheck(HValue* index, HValue* length)
|
| : skip_check_(false),
|
| base_(NULL), offset_(0), scale_(0),
|
| - responsibility_direction_(DIRECTION_NONE) {
|
| + responsibility_direction_(DIRECTION_NONE),
|
| + allow_equality_(false) {
|
| SetOperandAt(0, index);
|
| SetOperandAt(1, length);
|
| SetFlag(kFlexibleRepresentation);
|
| SetFlag(kUseGVN);
|
| }
|
|
|
| - bool skip_check() { return skip_check_; }
|
| - void set_skip_check(bool skip_check) { skip_check_ = skip_check; }
|
| + bool skip_check() const { return skip_check_; }
|
| + void set_skip_check() { skip_check_ = true; }
|
| HValue* base() { return base_; }
|
| int offset() { return offset_; }
|
| int scale() { return scale_; }
|
| @@ -3735,6 +3934,9 @@ class HBoundsCheck: public HTemplateInstruction<2> {
|
| virtual Representation RequiredInputRepresentation(int arg_index) {
|
| return representation();
|
| }
|
| + virtual bool IsDeletable() const {
|
| + return skip_check() && !FLAG_debug_code;
|
| + }
|
|
|
| virtual bool IsRelationTrueInternal(NumericRelation relation,
|
| HValue* related_value,
|
| @@ -3746,6 +3948,8 @@ class HBoundsCheck: public HTemplateInstruction<2> {
|
|
|
| HValue* index() { return OperandAt(0); }
|
| HValue* length() { return OperandAt(1); }
|
| + bool allow_equality() { return allow_equality_; }
|
| + void set_allow_equality(bool v) { allow_equality_ = v; }
|
|
|
| virtual int RedefinedOperandIndex() { return 0; }
|
| virtual bool IsPurelyInformativeDefinition() { return skip_check(); }
|
| @@ -3768,6 +3972,7 @@ class HBoundsCheck: public HTemplateInstruction<2> {
|
| int offset_;
|
| int scale_;
|
| RangeGuaranteeDirection responsibility_direction_;
|
| + bool allow_equality_;
|
| };
|
|
|
|
|
| @@ -3821,15 +4026,9 @@ class HBitwiseBinaryOperation: public HBinaryOperation {
|
| SetAllSideEffects();
|
| }
|
|
|
| - virtual Representation RequiredInputRepresentation(int index) {
|
| - return index == 0
|
| - ? Representation::Tagged()
|
| - : representation();
|
| - }
|
| -
|
| virtual void RepresentationChanged(Representation to) {
|
| if (!to.IsTagged()) {
|
| - ASSERT(to.IsInteger32());
|
| + ASSERT(to.IsSmiOrInteger32());
|
| ClearAllSideEffects();
|
| SetFlag(kUseGVN);
|
| } else {
|
| @@ -3842,10 +4041,14 @@ class HBitwiseBinaryOperation: public HBinaryOperation {
|
| HInferRepresentationPhase* h_infer,
|
| const char* reason) {
|
| // We only generate either int32 or generic tagged bitwise operations.
|
| - if (new_rep.IsSmi() || new_rep.IsDouble()) {
|
| - new_rep = Representation::Integer32();
|
| - }
|
| - HValue::UpdateRepresentation(new_rep, h_infer, reason);
|
| + if (new_rep.IsDouble()) new_rep = Representation::Integer32();
|
| + HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
|
| + }
|
| +
|
| + virtual Representation observed_input_representation(int index) {
|
| + Representation r = HBinaryOperation::observed_input_representation(index);
|
| + if (r.IsDouble()) return Representation::Integer32();
|
| + return r;
|
| }
|
|
|
| virtual void initialize_output_representation(Representation observed) {
|
| @@ -3911,11 +4114,6 @@ class HArithmeticBinaryOperation: public HBinaryOperation {
|
| }
|
|
|
| virtual HType CalculateInferredType();
|
| - virtual Representation RequiredInputRepresentation(int index) {
|
| - return index == 0
|
| - ? Representation::Tagged()
|
| - : representation();
|
| - }
|
|
|
| DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
|
|
|
| @@ -4018,29 +4216,6 @@ class HCompareObjectEqAndBranch: public HTemplateControlInstruction<2, 2> {
|
| };
|
|
|
|
|
| -class HCompareConstantEqAndBranch: public HUnaryControlInstruction {
|
| - public:
|
| - HCompareConstantEqAndBranch(HValue* left, int right, Token::Value op)
|
| - : HUnaryControlInstruction(left, NULL, NULL), op_(op), right_(right) {
|
| - ASSERT(op == Token::EQ_STRICT);
|
| - }
|
| -
|
| - Token::Value op() const { return op_; }
|
| - HValue* left() { return value(); }
|
| - int right() const { return right_; }
|
| -
|
| - virtual Representation RequiredInputRepresentation(int index) {
|
| - return Representation::Integer32();
|
| - }
|
| -
|
| - DECLARE_CONCRETE_INSTRUCTION(CompareConstantEqAndBranch);
|
| -
|
| - private:
|
| - const Token::Value op_;
|
| - const int right_;
|
| -};
|
| -
|
| -
|
| class HIsObjectAndBranch: public HUnaryControlInstruction {
|
| public:
|
| explicit HIsObjectAndBranch(HValue* value)
|
| @@ -4475,6 +4650,13 @@ class HMul: public HArithmeticBinaryOperation {
|
| return !representation().IsTagged();
|
| }
|
|
|
| + virtual void UpdateRepresentation(Representation new_rep,
|
| + HInferRepresentationPhase* h_infer,
|
| + const char* reason) {
|
| + if (new_rep.IsSmi()) new_rep = Representation::Integer32();
|
| + HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
|
| + }
|
| +
|
| DECLARE_CONCRETE_INSTRUCTION(Mul)
|
|
|
| protected:
|
| @@ -4514,6 +4696,13 @@ class HMod: public HArithmeticBinaryOperation {
|
|
|
| virtual HValue* Canonicalize();
|
|
|
| + virtual void UpdateRepresentation(Representation new_rep,
|
| + HInferRepresentationPhase* h_infer,
|
| + const char* reason) {
|
| + if (new_rep.IsSmi()) new_rep = Representation::Integer32();
|
| + HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
|
| + }
|
| +
|
| DECLARE_CONCRETE_INSTRUCTION(Mod)
|
|
|
| protected:
|
| @@ -4556,6 +4745,13 @@ class HDiv: public HArithmeticBinaryOperation {
|
|
|
| virtual HValue* Canonicalize();
|
|
|
| + virtual void UpdateRepresentation(Representation new_rep,
|
| + HInferRepresentationPhase* h_infer,
|
| + const char* reason) {
|
| + if (new_rep.IsSmi()) new_rep = Representation::Integer32();
|
| + HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
|
| + }
|
| +
|
| DECLARE_CONCRETE_INSTRUCTION(Div)
|
|
|
| protected:
|
| @@ -4596,11 +4792,11 @@ class HMathMinMax: public HArithmeticBinaryOperation {
|
| virtual Representation RepresentationFromInputs() {
|
| Representation left_rep = left()->representation();
|
| Representation right_rep = right()->representation();
|
| - if ((left_rep.IsNone() || left_rep.IsInteger32()) &&
|
| - (right_rep.IsNone() || right_rep.IsInteger32())) {
|
| - return Representation::Integer32();
|
| - }
|
| - return Representation::Double();
|
| + Representation result = Representation::Smi();
|
| + result = result.generalize(left_rep);
|
| + result = result.generalize(right_rep);
|
| + if (result.IsTagged()) return Representation::Double();
|
| + return result;
|
| }
|
|
|
| virtual bool IsCommutative() const { return true; }
|
| @@ -4655,6 +4851,27 @@ class HBitwise: public HBitwiseBinaryOperation {
|
| HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right)
|
| : HBitwiseBinaryOperation(context, left, right), op_(op) {
|
| ASSERT(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);
|
| + // 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);
|
| + }
|
| }
|
|
|
| Token::Value op_;
|
| @@ -4670,6 +4887,17 @@ class HShl: public HBitwiseBinaryOperation {
|
|
|
| virtual Range* InferRange(Zone* zone);
|
|
|
| + virtual void UpdateRepresentation(Representation new_rep,
|
| + HInferRepresentationPhase* h_infer,
|
| + const char* reason) {
|
| + 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:
|
| @@ -4702,6 +4930,13 @@ class HShr: public HBitwiseBinaryOperation {
|
|
|
| virtual Range* InferRange(Zone* zone);
|
|
|
| + virtual void UpdateRepresentation(Representation new_rep,
|
| + HInferRepresentationPhase* h_infer,
|
| + const char* reason) {
|
| + if (new_rep.IsSmi()) new_rep = Representation::Integer32();
|
| + HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
|
| + }
|
| +
|
| DECLARE_CONCRETE_INSTRUCTION(Shr)
|
|
|
| protected:
|
| @@ -4734,6 +4969,13 @@ class HSar: public HBitwiseBinaryOperation {
|
|
|
| virtual Range* InferRange(Zone* zone);
|
|
|
| + virtual void UpdateRepresentation(Representation new_rep,
|
| + HInferRepresentationPhase* h_infer,
|
| + const char* reason) {
|
| + if (new_rep.IsSmi()) new_rep = Representation::Integer32();
|
| + HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
|
| + }
|
| +
|
| DECLARE_CONCRETE_INSTRUCTION(Sar)
|
|
|
| protected:
|
| @@ -4752,6 +4994,13 @@ class HRor: public HBitwiseBinaryOperation {
|
| ChangeRepresentation(Representation::Integer32());
|
| }
|
|
|
| + virtual void UpdateRepresentation(Representation new_rep,
|
| + HInferRepresentationPhase* h_infer,
|
| + const char* reason) {
|
| + if (new_rep.IsSmi()) new_rep = Representation::Integer32();
|
| + HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
|
| + }
|
| +
|
| DECLARE_CONCRETE_INSTRUCTION(Ror)
|
|
|
| protected:
|
| @@ -4969,10 +5218,10 @@ class HAllocate: public HTemplateInstruction<2> {
|
| };
|
|
|
| HAllocate(HValue* context, HValue* size, HType type, Flags flags)
|
| - : type_(type),
|
| - flags_(flags) {
|
| + : flags_(flags) {
|
| SetOperandAt(0, context);
|
| SetOperandAt(1, size);
|
| + set_type(type);
|
| set_representation(Representation::Tagged());
|
| SetFlag(kTrackSideEffectDominators);
|
| SetGVNFlag(kChangesNewSpacePromotion);
|
| @@ -4997,7 +5246,6 @@ class HAllocate: public HTemplateInstruction<2> {
|
|
|
| HValue* context() { return OperandAt(0); }
|
| HValue* size() { return OperandAt(1); }
|
| - HType type() { return type_; }
|
|
|
| virtual Representation RequiredInputRepresentation(int index) {
|
| if (index == 0) {
|
| @@ -5015,8 +5263,6 @@ class HAllocate: public HTemplateInstruction<2> {
|
| known_initial_map_ = known_initial_map;
|
| }
|
|
|
| - virtual HType CalculateInferredType();
|
| -
|
| bool CanAllocateInNewSpace() const {
|
| return (flags_ & CAN_ALLOCATE_IN_NEW_SPACE) != 0;
|
| }
|
| @@ -5062,7 +5308,6 @@ class HAllocate: public HTemplateInstruction<2> {
|
| DECLARE_CONCRETE_INSTRUCTION(Allocate)
|
|
|
| private:
|
| - HType type_;
|
| Flags flags_;
|
| Handle<Map> known_initial_map_;
|
| };
|
| @@ -5071,10 +5316,10 @@ class HAllocate: public HTemplateInstruction<2> {
|
| class HInnerAllocatedObject: public HTemplateInstruction<1> {
|
| public:
|
| HInnerAllocatedObject(HValue* value, int offset, HType type = HType::Tagged())
|
| - : offset_(offset),
|
| - type_(type) {
|
| + : offset_(offset) {
|
| ASSERT(value->IsAllocate());
|
| SetOperandAt(0, value);
|
| + set_type(type);
|
| set_representation(Representation::Tagged());
|
| }
|
|
|
| @@ -5085,15 +5330,12 @@ class HInnerAllocatedObject: public HTemplateInstruction<1> {
|
| return Representation::Tagged();
|
| }
|
|
|
| - virtual HType CalculateInferredType() { return type_; }
|
| -
|
| virtual void PrintDataTo(StringStream* stream);
|
|
|
| DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
|
|
|
| private:
|
| int offset_;
|
| - HType type_;
|
| };
|
|
|
|
|
| @@ -5322,20 +5564,32 @@ class HObjectAccess {
|
| return OffsetField::decode(value_);
|
| }
|
|
|
| + inline Representation representation() const {
|
| + return Representation::FromKind(RepresentationField::decode(value_));
|
| + }
|
| +
|
| inline Handle<String> name() const {
|
| return name_;
|
| }
|
|
|
| + inline HObjectAccess WithRepresentation(Representation representation) {
|
| + return HObjectAccess(portion(), offset(), representation, name());
|
| + }
|
| +
|
| static HObjectAccess ForHeapNumberValue() {
|
| - return HObjectAccess(kDouble, HeapNumber::kValueOffset);
|
| + return HObjectAccess(
|
| + kDouble, HeapNumber::kValueOffset, Representation::Double());
|
| }
|
|
|
| static HObjectAccess ForElementsPointer() {
|
| return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
|
| }
|
|
|
| - static HObjectAccess ForArrayLength() {
|
| - return HObjectAccess(kArrayLengths, JSArray::kLengthOffset);
|
| + static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
|
| + return HObjectAccess(
|
| + kArrayLengths, JSArray::kLengthOffset,
|
| + IsFastElementsKind(elements_kind) && FLAG_track_fields ?
|
| + Representation::Smi() : Representation::Tagged());
|
| }
|
|
|
| static HObjectAccess ForAllocationSiteTransitionInfo() {
|
| @@ -5347,7 +5601,10 @@ class HObjectAccess {
|
| }
|
|
|
| static HObjectAccess ForFixedArrayLength() {
|
| - return HObjectAccess(kArrayLengths, FixedArray::kLengthOffset);
|
| + return HObjectAccess(
|
| + kArrayLengths, FixedArray::kLengthOffset,
|
| + FLAG_track_fields ?
|
| + Representation::Smi() : Representation::Tagged());
|
| }
|
|
|
| static HObjectAccess ForPropertiesPointer() {
|
| @@ -5378,13 +5635,15 @@ class HObjectAccess {
|
| static HObjectAccess ForFixedArrayHeader(int offset);
|
|
|
| // Create an access to an in-object property in a JSObject.
|
| - static HObjectAccess ForJSObjectOffset(int offset);
|
| + static HObjectAccess ForJSObjectOffset(int offset,
|
| + Representation representation = Representation::Tagged());
|
|
|
| // Create an access to an in-object property in a JSArray.
|
| static HObjectAccess ForJSArrayOffset(int offset);
|
|
|
| // Create an access to the backing store of an object.
|
| - static HObjectAccess ForBackingStoreOffset(int offset);
|
| + 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,
|
| @@ -5414,17 +5673,23 @@ class HObjectAccess {
|
| };
|
|
|
| HObjectAccess(Portion portion, int offset,
|
| - Handle<String> name = Handle<String>::null())
|
| - : value_(PortionField::encode(portion) | OffsetField::encode(offset)),
|
| + Representation representation = Representation::Tagged(),
|
| + Handle<String> name = Handle<String>::null())
|
| + : value_(PortionField::encode(portion) |
|
| + RepresentationField::encode(representation.kind()) |
|
| + OffsetField::encode(offset)),
|
| name_(name) {
|
| - ASSERT(this->offset() == offset); // offset should decode correctly
|
| - ASSERT(this->portion() == portion); // portion should decode correctly
|
| + // assert that the fields decode correctly
|
| + ASSERT(this->offset() == offset);
|
| + ASSERT(this->portion() == portion);
|
| + ASSERT(RepresentationField::decode(value_) == representation.kind());
|
| }
|
|
|
| class PortionField : public BitField<Portion, 0, 3> {};
|
| - class OffsetField : public BitField<int, 3, 29> {};
|
| + class RepresentationField : public BitField<Representation::Kind, 3, 3> {};
|
| + class OffsetField : public BitField<int, 6, 26> {};
|
|
|
| - uint32_t value_; // encodes both portion and offset
|
| + uint32_t value_; // encodes portion, representation, and offset
|
| Handle<String> name_;
|
|
|
| friend class HLoadNamedField;
|
| @@ -5472,22 +5737,20 @@ class HLoadNamedField: public HTemplateInstruction<2> {
|
| public:
|
| HLoadNamedField(HValue* object,
|
| HObjectAccess access,
|
| - HValue* typecheck = NULL,
|
| - Representation field_representation
|
| - = Representation::Tagged())
|
| - : access_(access),
|
| - field_representation_(field_representation) {
|
| + HValue* typecheck = NULL)
|
| + : access_(access) {
|
| ASSERT(object != NULL);
|
| SetOperandAt(0, object);
|
| SetOperandAt(1, typecheck != NULL ? typecheck : object);
|
|
|
| - if (FLAG_track_fields && field_representation.IsSmi()) {
|
| + Representation representation = access.representation();
|
| + if (representation.IsSmi()) {
|
| set_type(HType::Smi());
|
| - set_representation(field_representation);
|
| - } else if (FLAG_track_double_fields && field_representation.IsDouble()) {
|
| - set_representation(field_representation);
|
| + set_representation(representation);
|
| + } else if (representation.IsDouble()) {
|
| + set_representation(representation);
|
| } else if (FLAG_track_heap_object_fields &&
|
| - field_representation.IsHeapObject()) {
|
| + representation.IsHeapObject()) {
|
| set_type(HType::NonPrimitive());
|
| set_representation(Representation::Tagged());
|
| } else {
|
| @@ -5504,7 +5767,9 @@ class HLoadNamedField: public HTemplateInstruction<2> {
|
|
|
| bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); }
|
| HObjectAccess access() const { return access_; }
|
| - Representation field_representation() const { return representation_; }
|
| + Representation field_representation() const {
|
| + return access_.representation();
|
| + }
|
|
|
| virtual bool HasEscapingOperandAt(int index) { return false; }
|
| virtual Representation RequiredInputRepresentation(int index) {
|
| @@ -5524,7 +5789,6 @@ class HLoadNamedField: public HTemplateInstruction<2> {
|
| virtual bool IsDeletable() const { return true; }
|
|
|
| HObjectAccess access_;
|
| - Representation field_representation_;
|
| };
|
|
|
|
|
| @@ -5625,8 +5889,8 @@ class ArrayInstructionInterface {
|
| virtual ~ArrayInstructionInterface() { };
|
|
|
| static Representation KeyedAccessIndexRequirement(Representation r) {
|
| - return r.IsInteger32() ? Representation::Integer32()
|
| - : Representation::Smi();
|
| + return r.IsInteger32() || kSmiValueSize != 31
|
| + ? Representation::Integer32() : Representation::Smi();
|
| }
|
| };
|
|
|
| @@ -5824,11 +6088,8 @@ class HStoreNamedField: public HTemplateInstruction<2> {
|
| public:
|
| HStoreNamedField(HValue* obj,
|
| HObjectAccess access,
|
| - HValue* val,
|
| - Representation field_representation
|
| - = Representation::Tagged())
|
| + HValue* val)
|
| : access_(access),
|
| - field_representation_(field_representation),
|
| transition_(),
|
| transition_unique_id_(),
|
| new_space_dominator_(NULL),
|
| @@ -5842,12 +6103,10 @@ class HStoreNamedField: public HTemplateInstruction<2> {
|
|
|
| virtual bool HasEscapingOperandAt(int index) { return index == 1; }
|
| virtual Representation RequiredInputRepresentation(int index) {
|
| - if (FLAG_track_double_fields &&
|
| - index == 1 && field_representation_.IsDouble()) {
|
| - return field_representation_;
|
| - } else if (FLAG_track_fields &&
|
| - index == 1 && field_representation_.IsSmi()) {
|
| - return field_representation_;
|
| + if (index == 1 && field_representation().IsDouble()) {
|
| + return field_representation();
|
| + } else if (index == 1 && field_representation().IsSmi()) {
|
| + return field_representation();
|
| }
|
| return Representation::Tagged();
|
| }
|
| @@ -5879,13 +6138,12 @@ class HStoreNamedField: public HTemplateInstruction<2> {
|
| HValue* new_space_dominator() const { return new_space_dominator_; }
|
|
|
| bool NeedsWriteBarrier() {
|
| - ASSERT(!(FLAG_track_double_fields && field_representation_.IsDouble()) ||
|
| + ASSERT(!(FLAG_track_double_fields && field_representation().IsDouble()) ||
|
| transition_.is_null());
|
| if (IsSkipWriteBarrier()) return false;
|
| - return (!FLAG_track_fields || !field_representation_.IsSmi()) &&
|
| - // If there is a transition, a new storage object needs to be allocated.
|
| - !(FLAG_track_double_fields && field_representation_.IsDouble()) &&
|
| - StoringValueNeedsWriteBarrier(value()) &&
|
| + if (field_representation().IsDouble()) return false;
|
| + if (field_representation().IsSmi()) return false;
|
| + return StoringValueNeedsWriteBarrier(value()) &&
|
| ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator());
|
| }
|
|
|
| @@ -5899,12 +6157,11 @@ class HStoreNamedField: public HTemplateInstruction<2> {
|
| }
|
|
|
| Representation field_representation() const {
|
| - return field_representation_;
|
| + return access_.representation();
|
| }
|
|
|
| private:
|
| HObjectAccess access_;
|
| - Representation field_representation_;
|
| Handle<Map> transition_;
|
| UniqueValueId transition_unique_id_;
|
| HValue* new_space_dominator_;
|
|
|