diff options
Diffstat (limited to 'src/3rdparty/v8/src/hydrogen-instructions.h')
-rw-r--r-- | src/3rdparty/v8/src/hydrogen-instructions.h | 994 |
1 files changed, 620 insertions, 374 deletions
diff --git a/src/3rdparty/v8/src/hydrogen-instructions.h b/src/3rdparty/v8/src/hydrogen-instructions.h index c2c51ca..7136657 100644 --- a/src/3rdparty/v8/src/hydrogen-instructions.h +++ b/src/3rdparty/v8/src/hydrogen-instructions.h @@ -53,6 +53,7 @@ class LChunkBuilder; #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \ + V(BinaryOperation) \ V(BitwiseBinaryOperation) \ V(ControlInstruction) \ V(Instruction) \ @@ -124,7 +125,6 @@ class LChunkBuilder; V(IsStringAndBranch) \ V(IsSmiAndBranch) \ V(IsUndetectableAndBranch) \ - V(StringCompareAndBranch) \ V(JSArrayLength) \ V(LeaveInlined) \ V(LoadContextSlot) \ @@ -133,14 +133,14 @@ class LChunkBuilder; V(LoadFunctionPrototype) \ V(LoadGlobalCell) \ V(LoadGlobalGeneric) \ - V(LoadKeyedFastDoubleElement) \ - V(LoadKeyedFastElement) \ + V(LoadKeyed) \ V(LoadKeyedGeneric) \ - V(LoadKeyedSpecializedArrayElement) \ V(LoadNamedField) \ V(LoadNamedFieldPolymorphic) \ V(LoadNamedGeneric) \ + V(MapEnumLength) \ V(MathFloorOfDiv) \ + V(MathMinMax) \ V(Mod) \ V(Mul) \ V(ObjectLiteral) \ @@ -152,6 +152,7 @@ class LChunkBuilder; V(Random) \ V(RegExpLiteral) \ V(Return) \ + V(Ror) \ V(Sar) \ V(Shl) \ V(Shr) \ @@ -161,15 +162,14 @@ class LChunkBuilder; V(StoreContextSlot) \ V(StoreGlobalCell) \ V(StoreGlobalGeneric) \ - V(StoreKeyedFastDoubleElement) \ - V(StoreKeyedFastElement) \ + V(StoreKeyed) \ V(StoreKeyedGeneric) \ - V(StoreKeyedSpecializedArrayElement) \ V(StoreNamedField) \ V(StoreNamedGeneric) \ V(StringAdd) \ V(StringCharCodeAt) \ V(StringCharFromCode) \ + V(StringCompareAndBranch) \ V(StringLength) \ V(Sub) \ V(ThisFunction) \ @@ -224,6 +224,16 @@ class LChunkBuilder; virtual Opcode opcode() const { return HValue::k##type; } +#ifdef DEBUG +#define ASSERT_ALLOCATION_DISABLED do { \ + OptimizingCompilerThread* thread = \ + ISOLATE->optimizing_compiler_thread(); \ + ASSERT(thread->IsOptimizerThread() || !HEAP->IsAllocationAllowed()); \ + } while (0) +#else +#define ASSERT_ALLOCATION_DISABLED do {} while (0) +#endif + class Range: public ZoneObject { public: Range() @@ -276,6 +286,8 @@ class Range: public ZoneObject { 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); @@ -549,7 +561,14 @@ class HValue: public ZoneObject { kIsArguments, kTruncatingToInt32, kIsDead, - kLastFlag = 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_UNSIGNED_INT_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, + kLastFlag = kUint32 }; STATIC_ASSERT(kLastFlag < kBitsPerInt); @@ -645,7 +664,7 @@ class HValue: public ZoneObject { // Operands. virtual int OperandCount() = 0; - virtual HValue* OperandAt(int index) = 0; + virtual HValue* OperandAt(int index) const = 0; void SetOperandAt(int index, HValue* value); void DeleteAndReplaceWith(HValue* other); @@ -720,6 +739,11 @@ class HValue: public ZoneObject { return representation(); } + // Type feedback access. + virtual Representation ObservedInputRepresentation(int index) { + return RequiredInputRepresentation(index); + } + // 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, @@ -751,6 +775,10 @@ class HValue: public ZoneObject { UNREACHABLE(); } + bool IsDead() const { + return HasNoUses() && !HasObservableSideEffects() && IsDeletable(); + } + #ifdef DEBUG virtual void Verify() = 0; #endif @@ -835,6 +863,8 @@ class HValue: public ZoneObject { GVNFlagSet gvn_flags_; private: + virtual bool IsDeletable() const { return false; } + DISALLOW_COPY_AND_ASSIGN(HValue); }; @@ -852,9 +882,14 @@ class HInstruction: public HValue { void InsertBefore(HInstruction* next); void InsertAfter(HInstruction* previous); + // The position is a write-once variable. int position() const { return position_; } bool has_position() const { return position_ != RelocInfo::kNoPosition; } - void set_position(int position) { position_ = position; } + void set_position(int position) { + ASSERT(!has_position()); + ASSERT(position != RelocInfo::kNoPosition); + position_ = position; + } bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); } @@ -898,7 +933,7 @@ template<int V> class HTemplateInstruction : public HInstruction { public: int OperandCount() { return V; } - HValue* OperandAt(int i) { return inputs_[i]; } + HValue* OperandAt(int i) const { return inputs_[i]; } protected: void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; } @@ -950,7 +985,7 @@ class HTemplateControlInstruction: public HControlInstruction { void SetSuccessorAt(int i, HBasicBlock* block) { successors_[i] = block; } int OperandCount() { return V; } - HValue* OperandAt(int i) { return inputs_[i]; } + HValue* OperandAt(int i) const { return inputs_[i]; } protected: @@ -987,14 +1022,15 @@ class HSoftDeoptimize: public HTemplateInstruction<0> { class HDeoptimize: public HControlInstruction { public: - explicit HDeoptimize(int environment_length) : values_(environment_length) { } + HDeoptimize(int environment_length, Zone* zone) + : values_(environment_length, zone) { } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); } virtual int OperandCount() { return values_.length(); } - virtual HValue* OperandAt(int index) { return values_[index]; } + virtual HValue* OperandAt(int index) const { return values_[index]; } virtual void PrintDataTo(StringStream* stream); virtual int SuccessorCount() { return 0; } @@ -1006,8 +1042,8 @@ class HDeoptimize: public HControlInstruction { UNREACHABLE(); } - void AddEnvironmentValue(HValue* value) { - values_.Add(NULL); + void AddEnvironmentValue(HValue* value, Zone* zone) { + values_.Add(NULL, zone); SetOperandAt(values_.length() - 1, value); } @@ -1155,7 +1191,7 @@ class HUnaryOperation: public HTemplateInstruction<1> { return reinterpret_cast<HUnaryOperation*>(value); } - HValue* value() { return OperandAt(0); } + HValue* value() const { return OperandAt(0); } virtual void PrintDataTo(StringStream* stream); }; @@ -1231,8 +1267,8 @@ class HChange: public HUnaryOperation { virtual HType CalculateInferredType(); virtual HValue* Canonicalize(); - Representation from() { return value()->representation(); } - Representation to() { return representation(); } + Representation from() const { return value()->representation(); } + Representation to() const { return representation(); } bool deoptimize_on_undefined() const { return CheckFlag(kDeoptimizeOnUndefined); } @@ -1251,6 +1287,11 @@ class HChange: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { + return !from().IsTagged() || value()->type().IsSmi(); + } }; @@ -1270,23 +1311,27 @@ class HClampToUint8: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; class HSimulate: public HInstruction { public: - HSimulate(int ast_id, int pop_count) + HSimulate(BailoutId ast_id, int pop_count, Zone* zone) : ast_id_(ast_id), pop_count_(pop_count), - values_(2), - assigned_indexes_(2) {} + values_(2, zone), + assigned_indexes_(2, zone), + zone_(zone) {} virtual ~HSimulate() {} virtual void PrintDataTo(StringStream* stream); - bool HasAstId() const { return ast_id_ != AstNode::kNoNumber; } - int ast_id() const { return ast_id_; } - void set_ast_id(int id) { + bool HasAstId() const { return !ast_id_.IsNone(); } + BailoutId ast_id() const { return ast_id_; } + void set_ast_id(BailoutId id) { ASSERT(!HasAstId()); ast_id_ = id; } @@ -1307,7 +1352,7 @@ class HSimulate: public HInstruction { AddValue(kNoIndex, value); } virtual int OperandCount() { return values_.length(); } - virtual HValue* OperandAt(int index) { return values_[index]; } + virtual HValue* OperandAt(int index) const { return values_[index]; } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); @@ -1327,17 +1372,18 @@ class HSimulate: public HInstruction { private: static const int kNoIndex = -1; void AddValue(int index, HValue* value) { - assigned_indexes_.Add(index); + assigned_indexes_.Add(index, zone_); // Resize the list of pushed values. - values_.Add(NULL); + 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); } - int ast_id_; + BailoutId ast_id_; int pop_count_; ZoneList<HValue*> values_; ZoneList<int> assigned_indexes_; + Zone* zone_; }; @@ -1377,20 +1423,30 @@ class HStackCheck: public HTemplateInstruction<1> { }; +enum InliningKind { + NORMAL_RETURN, // Normal function/method call and return. + DROP_EXTRA_ON_RETURN, // Drop an extra value 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 HEnterInlined: public HTemplateInstruction<0> { public: HEnterInlined(Handle<JSFunction> closure, int arguments_count, FunctionLiteral* function, CallKind call_kind, - bool is_construct, + InliningKind inlining_kind, Variable* arguments_var, ZoneList<HValue*>* arguments_values) : closure_(closure), arguments_count_(arguments_count), + arguments_pushed_(false), function_(function), call_kind_(call_kind), - is_construct_(is_construct), + inlining_kind_(inlining_kind), arguments_var_(arguments_var), arguments_values_(arguments_values) { } @@ -1399,9 +1455,11 @@ class HEnterInlined: public HTemplateInstruction<0> { Handle<JSFunction> closure() const { return closure_; } 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_; } CallKind call_kind() const { return call_kind_; } - bool is_construct() const { return is_construct_; } + InliningKind inlining_kind() const { return inlining_kind_; } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); @@ -1415,9 +1473,10 @@ class HEnterInlined: public HTemplateInstruction<0> { private: Handle<JSFunction> closure_; int arguments_count_; + bool arguments_pushed_; FunctionLiteral* function_; CallKind call_kind_; - bool is_construct_; + InliningKind inlining_kind_; Variable* arguments_var_; ZoneList<HValue*>* arguments_values_; }; @@ -1425,21 +1484,13 @@ class HEnterInlined: public HTemplateInstruction<0> { class HLeaveInlined: public HTemplateInstruction<0> { public: - explicit HLeaveInlined(bool arguments_pushed) - : arguments_pushed_(arguments_pushed) { } + HLeaveInlined() { } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); } - bool arguments_pushed() { - return arguments_pushed_; - } - DECLARE_CONCRETE_INSTRUCTION(LeaveInlined) - - private: - bool arguments_pushed_; }; @@ -1461,7 +1512,7 @@ class HPushArgument: public HUnaryOperation { class HThisFunction: public HTemplateInstruction<0> { public: - explicit HThisFunction(Handle<JSFunction> closure) : closure_(closure) { + HThisFunction() { set_representation(Representation::Tagged()); SetFlag(kUseGVN); } @@ -1470,18 +1521,13 @@ class HThisFunction: public HTemplateInstruction<0> { return Representation::None(); } - Handle<JSFunction> closure() const { return closure_; } - DECLARE_CONCRETE_INSTRUCTION(ThisFunction) protected: - virtual bool DataEquals(HValue* other) { - HThisFunction* b = HThisFunction::cast(other); - return *closure() == *b->closure(); - } + virtual bool DataEquals(HValue* other) { return true; } private: - Handle<JSFunction> closure_; + virtual bool IsDeletable() const { return true; } }; @@ -1500,6 +1546,9 @@ class HContext: public HTemplateInstruction<0> { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1518,6 +1567,9 @@ class HOuterContext: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1573,6 +1625,7 @@ class HGlobalObject: public HUnaryOperation { } private: + virtual bool IsDeletable() const { return true; } bool qml_global_; }; @@ -1593,6 +1646,9 @@ class HGlobalReceiver: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1855,7 +1911,9 @@ class HCallRuntime: public HCall<1> { class HJSArrayLength: public HTemplateInstruction<2> { public: - HJSArrayLength(HValue* value, HValue* typecheck) { + HJSArrayLength(HValue* value, HValue* typecheck, + HType type = HType::Tagged()) { + set_type(type); // The length of an array is stored as a tagged value in the array // object. It is guaranteed to be 32 bit integer, but it can be // represented as either a smi or heap number. @@ -1879,13 +1937,17 @@ class HJSArrayLength: public HTemplateInstruction<2> { DECLARE_CONCRETE_INSTRUCTION(JSArrayLength) protected: - virtual bool DataEquals(HValue* other) { return true; } + virtual bool DataEquals(HValue* other_raw) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; class HFixedArrayBaseLength: public HUnaryOperation { public: explicit HFixedArrayBaseLength(HValue* value) : HUnaryOperation(value) { + set_type(HType::Smi()); set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetGVNFlag(kDependsOnArrayLengths); @@ -1899,6 +1961,32 @@ class HFixedArrayBaseLength: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } +}; + + +class HMapEnumLength: public HUnaryOperation { + public: + explicit HMapEnumLength(HValue* value) : HUnaryOperation(value) { + set_type(HType::Smi()); + set_representation(Representation::Tagged()); + SetFlag(kUseGVN); + SetGVNFlag(kDependsOnMaps); + } + + virtual Representation RequiredInputRepresentation(int index) { + return Representation::Tagged(); + } + + DECLARE_CONCRETE_INSTRUCTION(MapEnumLength) + + protected: + virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1918,6 +2006,9 @@ class HElementsKind: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -1940,6 +2031,9 @@ class HBitNot: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -2022,18 +2116,27 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { } private: + virtual bool IsDeletable() const { return true; } + BuiltinFunctionId op_; }; -class HLoadElements: public HUnaryOperation { +class HLoadElements: public HTemplateInstruction<2> { public: - explicit HLoadElements(HValue* value) : HUnaryOperation(value) { + HLoadElements(HValue* value, HValue* typecheck) { + SetOperandAt(0, value); + SetOperandAt(1, typecheck); set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetGVNFlag(kDependsOnElementsPointer); } + HValue* value() { return OperandAt(0); } + HValue* typecheck() { return OperandAt(1); } + + virtual void PrintDataTo(StringStream* stream); + virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); } @@ -2042,6 +2145,9 @@ class HLoadElements: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -2065,12 +2171,16 @@ class HLoadExternalArrayPointer: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; class HCheckMaps: public HTemplateInstruction<2> { public: - HCheckMaps(HValue* value, Handle<Map> map, HValue* typecheck = NULL) { + HCheckMaps(HValue* value, Handle<Map> map, Zone* zone, + HValue* typecheck = NULL) { SetOperandAt(0, value); // If callers don't depend on a typecheck, they can pass in NULL. In that // case we use a copy of the |value| argument as a dummy value. @@ -2079,9 +2189,9 @@ class HCheckMaps: public HTemplateInstruction<2> { SetFlag(kUseGVN); SetGVNFlag(kDependsOnMaps); SetGVNFlag(kDependsOnElementsKind); - map_set()->Add(map); + map_set()->Add(map, zone); } - HCheckMaps(HValue* value, SmallMapList* maps) { + HCheckMaps(HValue* value, SmallMapList* maps, Zone* zone) { SetOperandAt(0, value); SetOperandAt(1, value); set_representation(Representation::Tagged()); @@ -2089,37 +2199,31 @@ class HCheckMaps: public HTemplateInstruction<2> { SetGVNFlag(kDependsOnMaps); SetGVNFlag(kDependsOnElementsKind); for (int i = 0; i < maps->length(); i++) { - map_set()->Add(maps->at(i)); + map_set()->Add(maps->at(i), zone); } map_set()->Sort(); } - static HCheckMaps* NewWithTransitions(HValue* object, Handle<Map> map) { - HCheckMaps* check_map = new HCheckMaps(object, map); + static HCheckMaps* NewWithTransitions(HValue* object, Handle<Map> map, + Zone* zone) { + HCheckMaps* check_map = new(zone) HCheckMaps(object, map, zone); SmallMapList* map_set = check_map->map_set(); - // If the map to check has the untransitioned elements, it can be hoisted - // above TransitionElements instructions. - if (map->has_fast_smi_only_elements()) { - check_map->ClearGVNFlag(kDependsOnElementsKind); - } - - Map* transitioned_fast_element_map = - map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL); - ASSERT(transitioned_fast_element_map == NULL || - map->elements_kind() != FAST_ELEMENTS); - if (transitioned_fast_element_map != NULL) { - map_set->Add(Handle<Map>(transitioned_fast_element_map)); - } - Map* transitioned_double_map = - map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL); - ASSERT(transitioned_double_map == NULL || - map->elements_kind() == FAST_SMI_ONLY_ELEMENTS); - if (transitioned_double_map != NULL) { - map_set->Add(Handle<Map>(transitioned_double_map)); - } + // 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) { + map_set->Add(Handle<Map>(transitioned_map), zone); + } + }; map_set->Sort(); - return check_map; } @@ -2185,17 +2289,17 @@ class HCheckFunction: public HUnaryOperation { class HCheckInstanceType: public HUnaryOperation { public: - static HCheckInstanceType* NewIsSpecObject(HValue* value) { - return new HCheckInstanceType(value, IS_SPEC_OBJECT); + static HCheckInstanceType* NewIsSpecObject(HValue* value, Zone* zone) { + return new(zone) HCheckInstanceType(value, IS_SPEC_OBJECT); } - static HCheckInstanceType* NewIsJSArray(HValue* value) { - return new HCheckInstanceType(value, IS_JS_ARRAY); + static HCheckInstanceType* NewIsJSArray(HValue* value, Zone* zone) { + return new(zone) HCheckInstanceType(value, IS_JS_ARRAY); } - static HCheckInstanceType* NewIsString(HValue* value) { - return new HCheckInstanceType(value, IS_STRING); + static HCheckInstanceType* NewIsString(HValue* value, Zone* zone) { + return new(zone) HCheckInstanceType(value, IS_STRING); } - static HCheckInstanceType* NewIsSymbol(HValue* value) { - return new HCheckInstanceType(value, IS_SYMBOL); + static HCheckInstanceType* NewIsSymbol(HValue* value, Zone* zone) { + return new(zone) HCheckInstanceType(value, IS_SYMBOL); } virtual void PrintDataTo(StringStream* stream); @@ -2286,10 +2390,6 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> { SetGVNFlag(kDependsOnMaps); } -#ifdef DEBUG - virtual void Verify(); -#endif - Handle<JSObject> prototype() const { return prototype_; } Handle<JSObject> holder() const { return holder_; } @@ -2299,8 +2399,10 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> { return Representation::None(); } + virtual void PrintDataTo(StringStream* stream); + virtual intptr_t Hashcode() { - ASSERT(!HEAP->IsAllocationAllowed()); + ASSERT_ALLOCATION_DISABLED; intptr_t hash = reinterpret_cast<intptr_t>(*prototype()); hash = 17 * hash + reinterpret_cast<intptr_t>(*holder()); return hash; @@ -2344,8 +2446,8 @@ class HCheckSmi: public HUnaryOperation { class HPhi: public HValue { public: - explicit HPhi(int merged_index) - : inputs_(2), + HPhi(int merged_index, Zone* zone) + : inputs_(2, zone), merged_index_(merged_index), phi_id_(-1), is_live_(false), @@ -2367,7 +2469,7 @@ class HPhi: public HValue { } virtual HType CalculateInferredType(); virtual int OperandCount() { return inputs_.length(); } - virtual HValue* OperandAt(int index) { return inputs_[index]; } + virtual HValue* OperandAt(int index) const { return inputs_[index]; } HValue* GetRedundantReplacement(); void AddInput(HValue* value); bool HasRealUses(); @@ -2424,11 +2526,15 @@ class HPhi: public HValue { bool AllOperandsConvertibleToInteger() { for (int i = 0; i < OperandCount(); ++i) { - if (!OperandAt(i)->IsConvertibleToInteger()) return false; + if (!OperandAt(i)->IsConvertibleToInteger()) { + return false; + } } return true; } + void ResetInteger32Uses(); + protected: virtual void DeleteFromGraph(); virtual void InternalSetOperandAt(int index, HValue* value) { @@ -2459,26 +2565,51 @@ class HArgumentsObject: public HTemplateInstruction<0> { } DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject) + + private: + virtual bool IsDeletable() const { return true; } }; class HConstant: public HTemplateInstruction<0> { public: HConstant(Handle<Object> handle, Representation r); + HConstant(int32_t value, Representation r); + HConstant(double value, Representation r); - Handle<Object> handle() const { return handle_; } + Handle<Object> handle() { + if (handle_.is_null()) { + handle_ = FACTORY->NewNumber(double_value_, TENURED); + } + ASSERT(has_int32_value_ || !handle_->IsSmi()); + return handle_; + } bool InOldSpace() const { return !HEAP->InNewSpace(*handle_); } bool ImmortalImmovable() const { + if (has_int32_value_) { + return false; + } + if (has_double_value_) { + if (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) || + isnan(double_value_)) { + return true; + } + return false; + } + + ASSERT(!handle_.is_null()); Heap* heap = HEAP; + // We should have handled minus_zero_value and nan_value in the + // has_double_value_ clause above. + ASSERT(*handle_ != heap->minus_zero_value()); + ASSERT(*handle_ != heap->nan_value()); if (*handle_ == heap->undefined_value()) return true; if (*handle_ == heap->null_value()) return true; if (*handle_ == heap->true_value()) return true; if (*handle_ == heap->false_value()) return true; if (*handle_ == heap->the_hole_value()) return true; - if (*handle_ == heap->minus_zero_value()) return true; - if (*handle_ == heap->nan_value()) return true; if (*handle_ == heap->empty_string()) return true; return false; } @@ -2488,20 +2619,15 @@ class HConstant: public HTemplateInstruction<0> { } virtual bool IsConvertibleToInteger() const { - if (handle_->IsSmi()) return true; - if (handle_->IsHeapNumber() && - (HeapNumber::cast(*handle_)->value() == - static_cast<double>(NumberToInt32(*handle_)))) return true; - return false; + return has_int32_value_; } virtual bool EmitAtUses() { return !representation().IsDouble(); } - virtual HValue* Canonicalize(); virtual void PrintDataTo(StringStream* stream); virtual HType CalculateInferredType(); - bool IsInteger() const { return handle_->IsSmi(); } - HConstant* CopyToRepresentation(Representation r) const; - HConstant* CopyToTruncatedInt32() const; + bool IsInteger() { return handle()->IsSmi(); } + HConstant* CopyToRepresentation(Representation r, Zone* zone) const; + HConstant* CopyToTruncatedInt32(Zone* zone) const; bool HasInteger32Value() const { return has_int32_value_; } int32_t Integer32Value() const { ASSERT(HasInteger32Value()); @@ -2512,24 +2638,35 @@ class HConstant: public HTemplateInstruction<0> { ASSERT(HasDoubleValue()); return double_value_; } - bool HasNumberValue() const { return has_int32_value_ || has_double_value_; } + bool HasNumberValue() const { return has_double_value_; } int32_t NumberValueAsInteger32() const { ASSERT(HasNumberValue()); - if (has_int32_value_) return int32_value_; - return DoubleToInt32(double_value_); + // 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 { return handle_->IsString(); } - bool ToBoolean() const; + bool ToBoolean(); + + bool IsUint32() { + return HasInteger32Value() && (Integer32Value() >= 0); + } virtual intptr_t Hashcode() { - ASSERT(!HEAP->allow_allocation(false)); - intptr_t hash = reinterpret_cast<intptr_t>(*handle()); - // Prevent smis from having fewer hash values when truncated to - // the least significant bits. - const int kShiftSize = kSmiShiftSize + kSmiTagSize; - STATIC_ASSERT(kShiftSize != 0); - return hash ^ (hash >> kShiftSize); + ASSERT_ALLOCATION_DISABLED; + intptr_t hash; + + if (has_int32_value_) { + hash = static_cast<intptr_t>(int32_value_); + } else if (has_double_value_) { + hash = static_cast<intptr_t>(BitCast<int64_t>(double_value_)); + } else { + ASSERT(!handle_.is_null()); + hash = reinterpret_cast<intptr_t>(*handle_); + } + + return hash; } #ifdef DEBUG @@ -2543,15 +2680,34 @@ class HConstant: public HTemplateInstruction<0> { virtual bool DataEquals(HValue* other) { HConstant* other_constant = HConstant::cast(other); - return handle().is_identical_to(other_constant->handle()); + if (has_int32_value_) { + return other_constant->has_int32_value_ && + int32_value_ == other_constant->int32_value_; + } else if (has_double_value_) { + return other_constant->has_double_value_ && + BitCast<int64_t>(double_value_) == + BitCast<int64_t>(other_constant->double_value_); + } else { + ASSERT(!handle_.is_null()); + return !other_constant->handle_.is_null() && + *handle_ == *other_constant->handle_; + } } private: + virtual bool IsDeletable() const { return true; } + + // If this is a numerical constant, handle_ either points to to the + // HeapObject the constant originated from or is null. If the + // constant is non-numeric, handle_ always points to a valid + // constant HeapObject. Handle<Object> handle_; - // The following two values represent the int32 and the double value of the - // given constant if there is a lossless conversion between the constant - // and the specific representation. + // We store the HConstant in the most specific form safely possible. + // The two flags, has_int32_value_ and has_double_value_ tell us if + // int32_value_ and double_value_ hold valid, safe representations + // of the constant. has_int32_value_ implies has_double_value_ but + // not the converse. bool has_int32_value_ : 1; bool has_double_value_ : 1; int32_t int32_value_; @@ -2578,6 +2734,7 @@ class HBinaryOperation: public HTemplateInstruction<3> { if (IsCommutative() && left()->IsConstant()) return right(); return left(); } + HValue* MostConstantOperand() { if (IsCommutative() && left()->IsConstant()) return left(); return right(); @@ -2586,6 +2743,8 @@ class HBinaryOperation: public HTemplateInstruction<3> { virtual bool IsCommutative() const { return false; } virtual void PrintDataTo(StringStream* stream); + + DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation) }; @@ -2660,6 +2819,9 @@ class HArgumentsElements: public HTemplateInstruction<0> { protected: virtual bool DataEquals(HValue* other) { return true; } + private: + virtual bool IsDeletable() const { return true; } + bool from_inlined_; }; @@ -2679,6 +2841,9 @@ class HArgumentsLength: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -2711,16 +2876,42 @@ class HAccessArgumentsAt: public HTemplateInstruction<3> { }; +enum BoundsCheckKeyMode { + DONT_ALLOW_SMI_KEY, + ALLOW_SMI_KEY +}; + + class HBoundsCheck: public HTemplateInstruction<2> { public: - HBoundsCheck(HValue* index, HValue* length) { + HBoundsCheck(HValue* index, HValue* length, + BoundsCheckKeyMode key_mode = DONT_ALLOW_SMI_KEY) + : key_mode_(key_mode) { SetOperandAt(0, index); SetOperandAt(1, length); set_representation(Representation::Integer32()); SetFlag(kUseGVN); } - virtual Representation RequiredInputRepresentation(int index) { + virtual Representation RequiredInputRepresentation(int arg_index) { + if (key_mode_ == DONT_ALLOW_SMI_KEY || + !length()->representation().IsTagged()) { + return Representation::Integer32(); + } + // If the index is tagged and isn't constant, then allow the length + // to be tagged, since it is usually already tagged from loading it out of + // the length field of a JSArray. This allows for direct comparison without + // untagging. + if (index()->representation().IsTagged() && !index()->IsConstant()) { + return Representation::Tagged(); + } + // Also allow the length to be tagged if the index is constant, because + // it can be tagged to allow direct comparison. + if (index()->IsConstant() && + index()->representation().IsInteger32() && + arg_index == 1) { + return Representation::Tagged(); + } return Representation::Integer32(); } @@ -2733,6 +2924,7 @@ class HBoundsCheck: public HTemplateInstruction<2> { protected: virtual bool DataEquals(HValue* other) { return true; } + BoundsCheckKeyMode key_mode_; }; @@ -2743,6 +2935,9 @@ class HBitwiseBinaryOperation: public HBinaryOperation { set_representation(Representation::Tagged()); SetFlag(kFlexibleRepresentation); SetAllSideEffects(); + observed_input_representation_[0] = Representation::Tagged(); + observed_input_representation_[1] = Representation::None(); + observed_input_representation_[2] = Representation::None(); } virtual Representation RequiredInputRepresentation(int index) { @@ -2762,7 +2957,21 @@ class HBitwiseBinaryOperation: public HBinaryOperation { virtual HType CalculateInferredType(); + virtual Representation ObservedInputRepresentation(int index) { + return observed_input_representation_[index]; + } + + void InitializeObservedInputRepresentation(Representation r) { + observed_input_representation_[1] = r; + observed_input_representation_[2] = r; + } + DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation) + + private: + virtual bool IsDeletable() const { return true; } + + Representation observed_input_representation_[3]; }; @@ -2772,8 +2981,11 @@ class HMathFloorOfDiv: public HBinaryOperation { : HBinaryOperation(context, left, right) { set_representation(Representation::Integer32()); SetFlag(kUseGVN); + SetFlag(kCanOverflow); } + virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); + virtual Representation RequiredInputRepresentation(int index) { return Representation::Integer32(); } @@ -2782,6 +2994,9 @@ class HMathFloorOfDiv: public HBinaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -2814,6 +3029,9 @@ class HArithmeticBinaryOperation: public HBinaryOperation { } return HValue::InferredRepresentation(); } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -3099,6 +3317,9 @@ class HGetCachedArrayIndex: public HUnaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -3203,7 +3424,7 @@ class HPower: public HTemplateInstruction<2> { } HValue* left() { return OperandAt(0); } - HValue* right() { return OperandAt(1); } + HValue* right() const { return OperandAt(1); } virtual Representation RequiredInputRepresentation(int index) { return index == 0 @@ -3215,6 +3436,11 @@ class HPower: public HTemplateInstruction<2> { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + virtual bool IsDeletable() const { + return !right()->representation().IsTagged(); + } }; @@ -3232,6 +3458,9 @@ class HRandom: public HTemplateInstruction<1> { } DECLARE_CONCRETE_INSTRUCTION(Random) + + private: + virtual bool IsDeletable() const { return true; } }; @@ -3378,6 +3607,47 @@ class HDiv: public HArithmeticBinaryOperation { }; +class HMathMinMax: public HArithmeticBinaryOperation { + public: + enum Operation { kMathMin, kMathMax }; + + HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op) + : HArithmeticBinaryOperation(context, left, right), + operation_(op) { } + + virtual Representation RequiredInputRepresentation(int index) { + return index == 0 + ? Representation::Tagged() + : representation(); + } + + virtual Representation InferredRepresentation() { + if (left()->representation().IsInteger32() && + right()->representation().IsInteger32()) { + return Representation::Integer32(); + } + return Representation::Double(); + } + + virtual bool IsCommutative() const { return true; } + + Operation operation() { return operation_; } + + DECLARE_CONCRETE_INSTRUCTION(MathMinMax) + + protected: + virtual bool DataEquals(HValue* other) { + return other->IsMathMinMax() && + HMathMinMax::cast(other)->operation_ == operation_; + } + + virtual Range* InferRange(Zone* zone); + + private: + Operation operation_; +}; + + class HBitwise: public HBitwiseBinaryOperation { public: HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right) @@ -3472,13 +3742,32 @@ class HSar: public HBitwiseBinaryOperation { }; +class HRor: public HBitwiseBinaryOperation { + public: + HRor(HValue* context, HValue* left, HValue* right) + : HBitwiseBinaryOperation(context, left, right) { + ChangeRepresentation(Representation::Integer32()); + } + + static HInstruction* NewHRor(Zone* zone, + HValue* context, + HValue* left, + HValue* right); + + DECLARE_CONCRETE_INSTRUCTION(Ror) + + protected: + virtual bool DataEquals(HValue* other) { return true; } +}; + + class HOsrEntry: public HTemplateInstruction<0> { public: - explicit HOsrEntry(int ast_id) : ast_id_(ast_id) { + explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) { SetGVNFlag(kChangesOsrEntries); } - int ast_id() const { return ast_id_; } + BailoutId ast_id() const { return ast_id_; } virtual Representation RequiredInputRepresentation(int index) { return Representation::None(); @@ -3487,7 +3776,7 @@ class HOsrEntry: public HTemplateInstruction<0> { DECLARE_CONCRETE_INSTRUCTION(OsrEntry) private: - int ast_id_; + BailoutId ast_id_; }; @@ -3581,12 +3870,12 @@ class HLoadGlobalCell: public HTemplateInstruction<0> { } Handle<JSGlobalPropertyCell> cell() const { return cell_; } - bool RequiresHoleCheck(); + bool RequiresHoleCheck() const; virtual void PrintDataTo(StringStream* stream); virtual intptr_t Hashcode() { - ASSERT(!HEAP->allow_allocation(false)); + ASSERT_ALLOCATION_DISABLED; return reinterpret_cast<intptr_t>(*cell_); } @@ -3603,6 +3892,8 @@ class HLoadGlobalCell: public HTemplateInstruction<0> { } private: + virtual bool IsDeletable() const { return !RequiresHoleCheck(); } + Handle<JSGlobalPropertyCell> cell_; PropertyDetails details_; }; @@ -3650,7 +3941,8 @@ inline bool StoringValueNeedsWriteBarrier(HValue* value) { inline bool ReceiverObjectNeedsWriteBarrier(HValue* object, HValue* new_space_dominator) { - return !object->IsAllocateObject() || (object != new_space_dominator); + return (!object->IsAllocateObject() && !object->IsFastLiteral()) || + (object != new_space_dominator); } @@ -3763,7 +4055,7 @@ class HLoadContextSlot: public HUnaryOperation { return mode_ == kCheckDeoptimize; } - bool RequiresHoleCheck() { + bool RequiresHoleCheck() const { return mode_ != kNoCheck; } @@ -3782,6 +4074,8 @@ class HLoadContextSlot: public HUnaryOperation { } private: + virtual bool IsDeletable() const { return !RequiresHoleCheck(); } + int slot_index_; Mode mode_; }; @@ -3874,6 +4168,8 @@ class HLoadNamedField: public HUnaryOperation { } private: + virtual bool IsDeletable() const { return true; } + bool is_in_object_; int offset_; }; @@ -3884,7 +4180,8 @@ class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> { HLoadNamedFieldPolymorphic(HValue* context, HValue* object, SmallMapList* types, - Handle<String> name); + Handle<String> name, + Zone* zone); HValue* context() { return OperandAt(0); } HValue* object() { return OperandAt(1); } @@ -3971,162 +4268,134 @@ class ArrayInstructionInterface { virtual ~ArrayInstructionInterface() { }; }; -class HLoadKeyedFastElement - : public HTemplateInstruction<2>, public ArrayInstructionInterface { + +class HLoadKeyed + : public HTemplateInstruction<3>, public ArrayInstructionInterface { public: - enum HoleCheckMode { PERFORM_HOLE_CHECK, OMIT_HOLE_CHECK }; + HLoadKeyed(HValue* obj, + HValue* key, + HValue* dependency, + ElementsKind elements_kind) + : bit_field_(0) { + bit_field_ = ElementsKindField::encode(elements_kind); - HLoadKeyedFastElement(HValue* obj, - HValue* key, - HoleCheckMode hole_check_mode = PERFORM_HOLE_CHECK) - : hole_check_mode_(hole_check_mode), - index_offset_(0), - is_dehoisted_(false) { SetOperandAt(0, obj); SetOperandAt(1, key); - set_representation(Representation::Tagged()); - SetGVNFlag(kDependsOnArrayElements); - SetFlag(kUseGVN); - } + SetOperandAt(2, dependency); - HValue* object() { return OperandAt(0); } - HValue* key() { return OperandAt(1); } - uint32_t index_offset() { return index_offset_; } - void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } - HValue* GetKey() { return key(); } - void SetKey(HValue* key) { SetOperandAt(1, key); } - bool IsDehoisted() { return is_dehoisted_; } - void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } - - virtual Representation RequiredInputRepresentation(int index) { - // The key is supposed to be Integer32. - return index == 0 - ? Representation::Tagged() - : Representation::Integer32(); - } + if (!is_external()) { + // I can detect the case between storing double (holey and fast) and + // smi/object by looking at elements_kind_. + ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) || + IsFastDoubleElementsKind(elements_kind)); - virtual void PrintDataTo(StringStream* stream); + if (IsFastSmiOrObjectElementsKind(elements_kind)) { + if (IsFastSmiElementsKind(elements_kind) && + IsFastPackedElementsKind(elements_kind)) { + set_type(HType::Smi()); + } - bool RequiresHoleCheck(); - - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement) - - protected: - virtual bool DataEquals(HValue* other) { - if (!other->IsLoadKeyedFastElement()) return false; - HLoadKeyedFastElement* other_load = HLoadKeyedFastElement::cast(other); - if (is_dehoisted_ && index_offset_ != other_load->index_offset_) - return false; - return hole_check_mode_ == other_load->hole_check_mode_; - } - - private: - HoleCheckMode hole_check_mode_; - uint32_t index_offset_; - bool is_dehoisted_; -}; + set_representation(Representation::Tagged()); + SetGVNFlag(kDependsOnArrayElements); + } else { + set_representation(Representation::Double()); + SetGVNFlag(kDependsOnDoubleArrayElements); + } + } else { + if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || + elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { + set_representation(Representation::Double()); + } else { + set_representation(Representation::Integer32()); + } + SetGVNFlag(kDependsOnSpecializedArrayElements); + // Native code could change the specialized array. + SetGVNFlag(kDependsOnCalls); + } -class HLoadKeyedFastDoubleElement - : public HTemplateInstruction<2>, public ArrayInstructionInterface { - public: - HLoadKeyedFastDoubleElement(HValue* elements, HValue* key) - : index_offset_(0), is_dehoisted_(false) { - SetOperandAt(0, elements); - SetOperandAt(1, key); - set_representation(Representation::Double()); - SetGVNFlag(kDependsOnDoubleArrayElements); SetFlag(kUseGVN); } + bool is_external() const { + return IsExternalArrayElementsKind(elements_kind()); + } HValue* elements() { return OperandAt(0); } HValue* key() { return OperandAt(1); } - uint32_t index_offset() { return index_offset_; } - void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } + HValue* dependency() { return OperandAt(2); } + uint32_t index_offset() { return IndexOffsetField::decode(bit_field_); } + void SetIndexOffset(uint32_t index_offset) { + bit_field_ = IndexOffsetField::update(bit_field_, index_offset); + } HValue* GetKey() { return key(); } void SetKey(HValue* key) { SetOperandAt(1, key); } - bool IsDehoisted() { return is_dehoisted_; } - void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } - - virtual Representation RequiredInputRepresentation(int index) { - // The key is supposed to be Integer32. - return index == 0 - ? Representation::Tagged() - : Representation::Integer32(); + bool IsDehoisted() { return IsDehoistedField::decode(bit_field_); } + void SetDehoisted(bool is_dehoisted) { + bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted); + } + ElementsKind elements_kind() const { + return ElementsKindField::decode(bit_field_); } - virtual void PrintDataTo(StringStream* stream); - - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement) - - protected: - virtual bool DataEquals(HValue* other) { return true; } - - private: - uint32_t index_offset_; - bool is_dehoisted_; -}; - - -class HLoadKeyedSpecializedArrayElement - : public HTemplateInstruction<2>, public ArrayInstructionInterface { - public: - HLoadKeyedSpecializedArrayElement(HValue* external_elements, - HValue* key, - ElementsKind elements_kind) - : elements_kind_(elements_kind), - index_offset_(0), - is_dehoisted_(false) { - SetOperandAt(0, external_elements); - SetOperandAt(1, key); - if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || - elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { - set_representation(Representation::Double()); - } else { - set_representation(Representation::Integer32()); + virtual Representation RequiredInputRepresentation(int index) { + // kind_fast: tagged[int32] (none) + // kind_double: tagged[int32] (none) + // kind_external: external[int32] (none) + if (index == 0) { + return is_external() ? Representation::External() + : Representation::Tagged(); } - SetGVNFlag(kDependsOnSpecializedArrayElements); - // Native code could change the specialized array. - SetGVNFlag(kDependsOnCalls); - SetFlag(kUseGVN); + if (index == 1) return Representation::Integer32(); + return Representation::None(); } virtual void PrintDataTo(StringStream* stream); - virtual Representation RequiredInputRepresentation(int index) { - // The key is supposed to be Integer32, but the base pointer - // for the element load is a naked pointer. - return index == 0 - ? Representation::External() - : Representation::Integer32(); - } - - HValue* external_pointer() { return OperandAt(0); } - HValue* key() { return OperandAt(1); } - ElementsKind elements_kind() const { return elements_kind_; } - uint32_t index_offset() { return index_offset_; } - void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } - HValue* GetKey() { return key(); } - void SetKey(HValue* key) { SetOperandAt(1, key); } - bool IsDehoisted() { return is_dehoisted_; } - void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } + bool RequiresHoleCheck() const; virtual Range* InferRange(Zone* zone); - DECLARE_CONCRETE_INSTRUCTION(LoadKeyedSpecializedArrayElement) + DECLARE_CONCRETE_INSTRUCTION(LoadKeyed) protected: virtual bool DataEquals(HValue* other) { - if (!other->IsLoadKeyedSpecializedArrayElement()) return false; - HLoadKeyedSpecializedArrayElement* cast_other = - HLoadKeyedSpecializedArrayElement::cast(other); - return elements_kind_ == cast_other->elements_kind(); + if (!other->IsLoadKeyed()) return false; + HLoadKeyed* other_load = HLoadKeyed::cast(other); + + if (IsDehoisted() && index_offset() != other_load->index_offset()) + return false; + return elements_kind() == other_load->elements_kind(); } private: - ElementsKind elements_kind_; - uint32_t index_offset_; - bool is_dehoisted_; + virtual bool IsDeletable() const { + return !RequiresHoleCheck(); + } + + // Establish some checks around our packed fields + enum LoadKeyedBits { + kBitsForElementsKind = 5, + kBitsForIndexOffset = 26, + kBitsForIsDehoisted = 1, + + kStartElementsKind = 0, + kStartIndexOffset = kStartElementsKind + kBitsForElementsKind, + kStartIsDehoisted = kStartIndexOffset + kBitsForIndexOffset + }; + + STATIC_ASSERT((kBitsForElementsKind + kBitsForIndexOffset + + kBitsForIsDehoisted) <= sizeof(uint32_t)*8); + STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind)); + class ElementsKindField: + public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind> + {}; // NOLINT + class IndexOffsetField: + public BitField<uint32_t, kStartIndexOffset, kBitsForIndexOffset> + {}; // NOLINT + class IsDehoistedField: + public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted> + {}; // NOLINT + uint32_t bit_field_; }; @@ -4147,6 +4416,7 @@ class HLoadKeyedGeneric: public HTemplateInstruction<3> { virtual void PrintDataTo(StringStream* stream); virtual Representation RequiredInputRepresentation(int index) { + // tagged[tagged] return Representation::Tagged(); } @@ -4204,6 +4474,10 @@ class HStoreNamedField: public HTemplateInstruction<2> { ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); } + bool NeedsWriteBarrierForMap() { + return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); + } + private: Handle<String> name_; bool is_in_object_; @@ -4248,83 +4522,56 @@ class HStoreNamedGeneric: public HTemplateInstruction<3> { }; -class HStoreKeyedFastElement +class HStoreKeyed : public HTemplateInstruction<3>, public ArrayInstructionInterface { public: - HStoreKeyedFastElement(HValue* obj, HValue* key, HValue* val, - ElementsKind elements_kind = FAST_ELEMENTS) + HStoreKeyed(HValue* obj, HValue* key, HValue* val, + ElementsKind elements_kind) : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) { SetOperandAt(0, obj); SetOperandAt(1, key); SetOperandAt(2, val); - SetGVNFlag(kChangesArrayElements); - } - - virtual Representation RequiredInputRepresentation(int index) { - // The key is supposed to be Integer32. - return index == 1 - ? Representation::Integer32() - : Representation::Tagged(); - } - - HValue* object() { return OperandAt(0); } - HValue* key() { return OperandAt(1); } - HValue* value() { return OperandAt(2); } - bool value_is_smi() { - return elements_kind_ == FAST_SMI_ONLY_ELEMENTS; - } - uint32_t index_offset() { return index_offset_; } - void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } - HValue* GetKey() { return key(); } - void SetKey(HValue* key) { SetOperandAt(1, key); } - bool IsDehoisted() { return is_dehoisted_; } - void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } - bool NeedsWriteBarrier() { - if (value_is_smi()) { - return false; + if (is_external()) { + SetGVNFlag(kChangesSpecializedArrayElements); + } else if (IsFastDoubleElementsKind(elements_kind)) { + SetGVNFlag(kChangesDoubleArrayElements); + SetFlag(kDeoptimizeOnUndefined); } else { - return StoringValueNeedsWriteBarrier(value()); + SetGVNFlag(kChangesArrayElements); } } - virtual void PrintDataTo(StringStream* stream); - - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastElement) - - private: - ElementsKind elements_kind_; - uint32_t index_offset_; - bool is_dehoisted_; -}; - - -class HStoreKeyedFastDoubleElement - : public HTemplateInstruction<3>, public ArrayInstructionInterface { - public: - HStoreKeyedFastDoubleElement(HValue* elements, - HValue* key, - HValue* val) - : index_offset_(0), is_dehoisted_(false) { - SetOperandAt(0, elements); - SetOperandAt(1, key); - SetOperandAt(2, val); - SetGVNFlag(kChangesDoubleArrayElements); - } - virtual Representation RequiredInputRepresentation(int index) { - if (index == 1) { + // kind_fast: tagged[int32] = tagged + // kind_double: tagged[int32] = double + // kind_external: external[int32] = (double | int32) + if (index == 0) { + return is_external() ? Representation::External() + : Representation::Tagged(); + } else if (index == 1) { return Representation::Integer32(); - } else if (index == 2) { + } + + ASSERT_EQ(index, 2); + if (IsDoubleOrFloatElementsKind(elements_kind())) { return Representation::Double(); - } else { - return Representation::Tagged(); } + + return is_external() ? Representation::Integer32() + : Representation::Tagged(); } + bool is_external() const { + return IsExternalArrayElementsKind(elements_kind()); + } HValue* elements() { return OperandAt(0); } HValue* key() { return OperandAt(1); } HValue* value() { return OperandAt(2); } + bool value_is_smi() const { + return IsFastSmiElementsKind(elements_kind_); + } + ElementsKind elements_kind() const { return elements_kind_; } uint32_t index_offset() { return index_offset_; } void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } HValue* GetKey() { return key(); } @@ -4333,64 +4580,18 @@ class HStoreKeyedFastDoubleElement void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } bool NeedsWriteBarrier() { - return StoringValueNeedsWriteBarrier(value()); + if (value_is_smi()) { + return false; + } else { + return StoringValueNeedsWriteBarrier(value()); + } } bool NeedsCanonicalization(); virtual void PrintDataTo(StringStream* stream); - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement) - - private: - uint32_t index_offset_; - bool is_dehoisted_; -}; - - -class HStoreKeyedSpecializedArrayElement - : public HTemplateInstruction<3>, public ArrayInstructionInterface { - public: - HStoreKeyedSpecializedArrayElement(HValue* external_elements, - HValue* key, - HValue* val, - ElementsKind elements_kind) - : elements_kind_(elements_kind), index_offset_(0), is_dehoisted_(false) { - SetGVNFlag(kChangesSpecializedArrayElements); - SetOperandAt(0, external_elements); - SetOperandAt(1, key); - SetOperandAt(2, val); - } - - virtual void PrintDataTo(StringStream* stream); - - virtual Representation RequiredInputRepresentation(int index) { - if (index == 0) { - return Representation::External(); - } else { - bool float_or_double_elements = - elements_kind() == EXTERNAL_FLOAT_ELEMENTS || - elements_kind() == EXTERNAL_DOUBLE_ELEMENTS; - if (index == 2 && float_or_double_elements) { - return Representation::Double(); - } else { - return Representation::Integer32(); - } - } - } - - HValue* external_pointer() { return OperandAt(0); } - HValue* key() { return OperandAt(1); } - HValue* value() { return OperandAt(2); } - ElementsKind elements_kind() const { return elements_kind_; } - uint32_t index_offset() { return index_offset_; } - void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } - HValue* GetKey() { return key(); } - void SetKey(HValue* key) { SetOperandAt(1, key); } - bool IsDehoisted() { return is_dehoisted_; } - void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } - - DECLARE_CONCRETE_INSTRUCTION(StoreKeyedSpecializedArrayElement) + DECLARE_CONCRETE_INSTRUCTION(StoreKeyed) private: ElementsKind elements_kind_; @@ -4421,6 +4622,7 @@ class HStoreKeyedGeneric: public HTemplateInstruction<4> { StrictModeFlag strict_mode_flag() { return strict_mode_flag_; } virtual Representation RequiredInputRepresentation(int index) { + // tagged[tagged] = tagged return Representation::Tagged(); } @@ -4443,8 +4645,14 @@ class HTransitionElementsKind: public HTemplateInstruction<1> { SetOperandAt(0, object); SetFlag(kUseGVN); SetGVNFlag(kChangesElementsKind); - SetGVNFlag(kChangesElementsPointer); - SetGVNFlag(kChangesNewSpacePromotion); + if (original_map->has_fast_double_elements()) { + SetGVNFlag(kChangesElementsPointer); + SetGVNFlag(kChangesNewSpacePromotion); + } + if (transitioned_map->has_fast_double_elements()) { + SetGVNFlag(kChangesElementsPointer); + SetGVNFlag(kChangesNewSpacePromotion); + } set_representation(Representation::Tagged()); } @@ -4480,6 +4688,7 @@ class HStringAdd: public HBinaryOperation { set_representation(Representation::Tagged()); SetFlag(kUseGVN); SetGVNFlag(kDependsOnMaps); + SetGVNFlag(kChangesNewSpacePromotion); } virtual Representation RequiredInputRepresentation(int index) { @@ -4494,6 +4703,10 @@ class HStringAdd: public HBinaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + // TODO(svenpanne) Might be safe, but leave it out until we know for sure. + // private: + // virtual bool IsDeletable() const { return true; } }; @@ -4528,6 +4741,10 @@ class HStringCharCodeAt: public HTemplateInstruction<3> { virtual Range* InferRange(Zone* zone) { return new(zone) Range(0, String::kMaxUtf16CodeUnit); } + + // TODO(svenpanne) Might be safe, but leave it out until we know for sure. + // private: + // virtual bool IsDeletable() const { return true; } }; @@ -4554,6 +4771,10 @@ class HStringCharFromCode: public HTemplateInstruction<2> { virtual bool DataEquals(HValue* other) { return true; } DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode) + + // TODO(svenpanne) Might be safe, but leave it out until we know for sure. + // private: + // virtual bool IsDeletable() const { return true; } }; @@ -4582,6 +4803,9 @@ class HStringLength: public HUnaryOperation { virtual Range* InferRange(Zone* zone) { return new(zone) Range(0, String::kMaxLength); } + + private: + virtual bool IsDeletable() const { return true; } }; @@ -4608,6 +4832,9 @@ class HAllocateObject: public HTemplateInstruction<1> { DECLARE_CONCRETE_INSTRUCTION(AllocateObject) private: + // TODO(svenpanne) Might be safe, but leave it out until we know for sure. + // virtual bool IsDeletable() const { return true; } + Handle<JSFunction> constructor_; }; @@ -4624,6 +4851,8 @@ class HMaterializedLiteral: public HTemplateInstruction<V> { int depth() const { return depth_; } private: + virtual bool IsDeletable() const { return true; } + int literal_index_; int depth_; }; @@ -4682,7 +4911,7 @@ class HArrayLiteral: public HMaterializedLiteral<1> { HValue* context() { return OperandAt(0); } ElementsKind boilerplate_elements_kind() const { if (!boilerplate_object_->IsJSObject()) { - return FAST_ELEMENTS; + return TERMINAL_FAST_ELEMENTS_KIND; } return Handle<JSObject>::cast(boilerplate_object_)->GetElementsKind(); } @@ -4744,10 +4973,12 @@ class HObjectLiteral: public HMaterializedLiteral<1> { class HRegExpLiteral: public HMaterializedLiteral<1> { public: 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); @@ -4755,6 +4986,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> { } HValue* context() { return OperandAt(0); } + Handle<FixedArray> literals() { return literals_; } Handle<String> pattern() { return pattern_; } Handle<String> flags() { return flags_; } @@ -4766,6 +4998,7 @@ class HRegExpLiteral: public HMaterializedLiteral<1> { DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral) private: + Handle<FixedArray> literals_; Handle<String> pattern_; Handle<String> flags_; }; @@ -4795,6 +5028,8 @@ class HFunctionLiteral: public HTemplateInstruction<1> { bool pretenure() const { return pretenure_; } private: + virtual bool IsDeletable() const { return true; } + Handle<SharedFunctionInfo> shared_info_; bool pretenure_; }; @@ -4811,7 +5046,6 @@ class HTypeof: public HTemplateInstruction<2> { HValue* context() { return OperandAt(0); } HValue* value() { return OperandAt(1); } - virtual HValue* Canonicalize(); virtual void PrintDataTo(StringStream* stream); virtual Representation RequiredInputRepresentation(int index) { @@ -4819,6 +5053,9 @@ class HTypeof: public HTemplateInstruction<2> { } DECLARE_CONCRETE_INSTRUCTION(Typeof) + + private: + virtual bool IsDeletable() const { return true; } }; @@ -4837,6 +5074,9 @@ class HToFastProperties: public HUnaryOperation { } DECLARE_CONCRETE_INSTRUCTION(ToFastProperties) + + private: + virtual bool IsDeletable() const { return true; } }; @@ -4851,6 +5091,9 @@ class HValueOf: public HUnaryOperation { } DECLARE_CONCRETE_INSTRUCTION(ValueOf) + + private: + virtual bool IsDeletable() const { return true; } }; @@ -5047,6 +5290,9 @@ class HLoadFieldByIndex : public HTemplateInstruction<2> { } DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex); + + private: + virtual bool IsDeletable() const { return true; } }; |