Chromium Code Reviews| Index: src/hydrogen-instructions.h |
| diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h |
| index 7acec8bcd5ebc3e2e0757d312ee591f5e5174e72..8b97cc7e3d5885a709d489d9e5347a388256bee6 100644 |
| --- a/src/hydrogen-instructions.h |
| +++ b/src/hydrogen-instructions.h |
| @@ -234,14 +234,6 @@ class LChunkBuilder; |
| virtual Opcode opcode() const { return HValue::k##type; } |
| -#ifdef DEBUG |
| -#define ASSERT_ALLOCATION_DISABLED \ |
| - ASSERT(isolate()->optimizing_compiler_thread()->IsOptimizerThread() || \ |
| - !isolate()->heap()->IsAllocationAllowed()) |
| -#else |
| -#define ASSERT_ALLOCATION_DISABLED do {} while (0) |
| -#endif |
| - |
| class Range: public ZoneObject { |
| public: |
| Range() |
| @@ -364,6 +356,54 @@ class Representation { |
| }; |
| +class UniqueValueId { |
| + public: |
| + UniqueValueId() : raw_address_(NULL) { } |
| + |
| + explicit UniqueValueId(Object* object) { |
| + raw_address_ = reinterpret_cast<Address>(object); |
| + ASSERT(!IsUninitialized()); |
| + } |
| + |
| + explicit UniqueValueId(Handle<Object> handle) { |
| + static const Address kEmptyHandleSentinel = reinterpret_cast<Address>(1); |
| + if (handle.is_null()) { |
| + raw_address_ = kEmptyHandleSentinel; |
| + } else { |
| + raw_address_ = reinterpret_cast<Address>(*handle); |
| + ASSERT_NE(kEmptyHandleSentinel, raw_address_); |
| + } |
| + ASSERT(!IsUninitialized()); |
| + } |
| + |
| + bool IsUninitialized() const { return raw_address_ == NULL; } |
| + |
| + bool operator==(const UniqueValueId& other) const { |
| + ASSERT(!IsUninitialized() && !other.IsUninitialized()); |
| + return raw_address_ == other.raw_address_; |
| + } |
| + |
| + bool operator!=(const UniqueValueId& other) const { |
| + ASSERT(!IsUninitialized() && !other.IsUninitialized()); |
| + return raw_address_ != other.raw_address_; |
| + } |
| + |
| + intptr_t Hashcode() const { |
| + ASSERT(!IsUninitialized()); |
| + return reinterpret_cast<intptr_t>(raw_address_); |
| + } |
| + |
| + bool IsImmovableObject(Object* object) const { |
|
Sven Panne
2013/04/16 09:46:42
Slightly obscure, and we don't need this (see belo
Yang
2013/04/16 09:59:06
Done.
|
| + // The raw address does not change for immovable objects. |
| + ASSERT(!IsUninitialized()); |
| + return reinterpret_cast<Address>(object) == raw_address_; |
| + } |
| + |
| + private: |
| + Address raw_address_; |
| +}; |
| + |
| + |
| class HType { |
| public: |
| HType() : type_(kUninitialized) { } |
| @@ -1057,6 +1097,10 @@ class HValue: public ZoneObject { |
| bool Equals(HValue* other); |
| virtual intptr_t Hashcode(); |
| + // Some instructions' hash code is dependent on object addresses and are not |
|
Sven Panne
2013/04/16 09:46:42
Adapt comment: We are talking about unique IDs her
Yang
2013/04/16 09:59:06
Done.
|
| + // safe regarding GC and parallel recompilation. Compute the hash upfront. |
| + virtual void FinalizeUniqueValueId() { } |
| + |
| // Printing support. |
| virtual void PrintTo(StringStream* stream) = 0; |
| void PrintNameTo(StringStream* stream); |
| @@ -2643,7 +2687,8 @@ class HLoadExternalArrayPointer: public HUnaryOperation { |
| class HCheckMaps: public HTemplateInstruction<2> { |
| public: |
| HCheckMaps(HValue* value, Handle<Map> map, Zone* zone, |
| - HValue* typecheck = NULL) { |
| + HValue* typecheck = NULL) |
| + : map_unique_ids_(0, zone) { |
| 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. |
| @@ -2655,7 +2700,8 @@ class HCheckMaps: public HTemplateInstruction<2> { |
| SetGVNFlag(kDependsOnElementsKind); |
| map_set()->Add(map, zone); |
| } |
| - HCheckMaps(HValue* value, SmallMapList* maps, Zone* zone) { |
| + HCheckMaps(HValue* value, SmallMapList* maps, Zone* zone) |
| + : map_unique_ids_(0, zone) { |
| SetOperandAt(0, value); |
| SetOperandAt(1, value); |
| set_representation(Representation::Tagged()); |
| @@ -2702,28 +2748,36 @@ class HCheckMaps: public HTemplateInstruction<2> { |
| HValue* value() { return OperandAt(0); } |
| SmallMapList* map_set() { return &map_set_; } |
| + virtual void FinalizeUniqueValueId(); |
| + |
| DECLARE_CONCRETE_INSTRUCTION(CheckMaps) |
| protected: |
| virtual bool DataEquals(HValue* other) { |
| + ASSERT_EQ(map_set_.length(), map_unique_ids_.length()); |
| HCheckMaps* b = HCheckMaps::cast(other); |
| // Relies on the fact that map_set has been sorted before. |
| - if (map_set()->length() != b->map_set()->length()) return false; |
| - for (int i = 0; i < map_set()->length(); i++) { |
| - if (!map_set()->at(i).is_identical_to(b->map_set()->at(i))) return false; |
| + if (map_unique_ids_.length() != b->map_unique_ids_.length()) { |
| + return false; |
| + } |
| + for (int i = 0; i < map_unique_ids_.length(); i++) { |
| + if (map_unique_ids_.at(i) != b->map_unique_ids_.at(i)) { |
| + return false; |
| + } |
| } |
| return true; |
| } |
| private: |
| SmallMapList map_set_; |
| + ZoneList<UniqueValueId> map_unique_ids_; |
| }; |
| class HCheckFunction: public HUnaryOperation { |
| public: |
| HCheckFunction(HValue* value, Handle<JSFunction> function) |
| - : HUnaryOperation(value), target_(function) { |
| + : HUnaryOperation(value), target_(function), target_unique_id_() { |
| set_representation(Representation::Tagged()); |
| SetFlag(kUseGVN); |
| target_in_new_space_ = Isolate::Current()->heap()->InNewSpace(*function); |
| @@ -2739,6 +2793,10 @@ class HCheckFunction: public HUnaryOperation { |
| virtual void Verify(); |
| #endif |
| + virtual void FinalizeUniqueValueId() { |
| + target_unique_id_ = UniqueValueId(target_); |
| + } |
| + |
| Handle<JSFunction> target() const { return target_; } |
| bool target_in_new_space() const { return target_in_new_space_; } |
| @@ -2747,11 +2805,12 @@ class HCheckFunction: public HUnaryOperation { |
| protected: |
| virtual bool DataEquals(HValue* other) { |
| HCheckFunction* b = HCheckFunction::cast(other); |
| - return target_.is_identical_to(b->target()); |
| + return target_unique_id_ == b->target_unique_id_; |
| } |
| private: |
| Handle<JSFunction> target_; |
| + UniqueValueId target_unique_id_; |
| bool target_in_new_space_; |
| }; |
| @@ -2856,7 +2915,11 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> { |
| public: |
| HCheckPrototypeMaps(Handle<JSObject> prototype, |
| Handle<JSObject> holder, |
| - Zone* zone) : prototypes_(2, zone), maps_(2, zone) { |
| + Zone* zone) |
| + : prototypes_(2, zone), |
| + maps_(2, zone), |
| + first_prototype_unique_id_(), |
| + last_prototype_unique_id_() { |
| SetFlag(kUseGVN); |
| SetGVNFlag(kDependsOnMaps); |
| // Keep a list of all objects on the prototype chain up to the holder |
| @@ -2882,18 +2945,13 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> { |
| virtual void PrintDataTo(StringStream* stream); |
| virtual intptr_t Hashcode() { |
| - ASSERT_ALLOCATION_DISABLED; |
| - // Dereferencing to use the object's raw address for hashing is safe. |
| - HandleDereferenceGuard allow_handle_deref(isolate(), |
| - HandleDereferenceGuard::ALLOW); |
| - SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) || |
| - !isolate()->optimizing_compiler_thread()->IsOptimizerThread()); |
| - intptr_t hash = 0; |
| - for (int i = 0; i < prototypes_.length(); i++) { |
| - hash = 17 * hash + reinterpret_cast<intptr_t>(*prototypes_[i]); |
| - hash = 17 * hash + reinterpret_cast<intptr_t>(*maps_[i]); |
| - } |
| - return hash; |
| + return first_prototype_unique_id_.Hashcode() * 17 + |
| + last_prototype_unique_id_.Hashcode(); |
| + } |
| + |
| + virtual void FinalizeUniqueValueId() { |
| + first_prototype_unique_id_ = UniqueValueId(prototypes_.first()); |
| + last_prototype_unique_id_ = UniqueValueId(prototypes_.last()); |
| } |
| bool CanOmitPrototypeChecks() { |
| @@ -2906,22 +2964,15 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> { |
| protected: |
| virtual bool DataEquals(HValue* other) { |
| HCheckPrototypeMaps* b = HCheckPrototypeMaps::cast(other); |
| -#ifdef DEBUG |
| - if (prototypes_.length() != b->prototypes()->length()) return false; |
| - for (int i = 0; i < prototypes_.length(); i++) { |
| - if (!prototypes_[i].is_identical_to(b->prototypes()->at(i))) return false; |
| - if (!maps_[i].is_identical_to(b->maps()->at(i))) return false; |
| - } |
| - return true; |
| -#else |
| - return prototypes_.first().is_identical_to(b->prototypes()->first()) && |
| - prototypes_.last().is_identical_to(b->prototypes()->last()); |
| -#endif // DEBUG |
| + return first_prototype_unique_id_ == b->first_prototype_unique_id_ && |
| + last_prototype_unique_id_ == b->last_prototype_unique_id_; |
| } |
| private: |
| ZoneList<Handle<JSObject> > prototypes_; |
| ZoneList<Handle<Map> > maps_; |
| + UniqueValueId first_prototype_unique_id_; |
| + UniqueValueId last_prototype_unique_id_; |
| }; |
| @@ -3176,6 +3227,7 @@ class HConstant: public HTemplateInstruction<0> { |
| Representation r, |
| Handle<Object> optional_handle = Handle<Object>::null()); |
| HConstant(Handle<Object> handle, |
| + UniqueValueId unique_id, |
| Representation r, |
| HType type, |
| bool is_internalized_string, |
| @@ -3189,8 +3241,6 @@ class HConstant: public HTemplateInstruction<0> { |
| return handle_; |
| } |
| - bool InOldSpace() const { return !HEAP->InNewSpace(*handle_); } |
| - |
| bool IsSpecialDouble() const { |
| return has_double_value_ && |
| (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) || |
| @@ -3210,20 +3260,17 @@ class HConstant: public HTemplateInstruction<0> { |
| } |
| ASSERT(!handle_.is_null()); |
| + HandleDereferenceGuard allow_dereference_for_immovable_check( |
| + isolate(), HandleDereferenceGuard::ALLOW); |
| Heap* heap = isolate()->heap(); |
| - // We should have handled minus_zero_value and nan_value in the |
| - // has_double_value_ clause above. |
| - // Dereferencing is safe to compare against immovable singletons. |
| - HandleDereferenceGuard allow_handle_deref(isolate(), |
| - HandleDereferenceGuard::ALLOW); |
| - ASSERT(*handle_ != heap->minus_zero_value()); |
| - ASSERT(*handle_ != heap->nan_value()); |
| - return *handle_ == heap->undefined_value() || |
| - *handle_ == heap->null_value() || |
| - *handle_ == heap->true_value() || |
| - *handle_ == heap->false_value() || |
| - *handle_ == heap->the_hole_value() || |
| - *handle_ == heap->empty_string(); |
| + ASSERT(!unique_id_.IsImmovableObject(heap->minus_zero_value())); |
|
Sven Panne
2013/04/16 09:46:42
Just construct a UniqueValueId for the RHS and use
Yang
2013/04/16 09:59:06
Done.
|
| + ASSERT(!unique_id_.IsImmovableObject(heap->nan_value())); |
| + return unique_id_.IsImmovableObject(heap->undefined_value()) || |
| + unique_id_.IsImmovableObject(heap->null_value()) || |
| + unique_id_.IsImmovableObject(heap->true_value()) || |
| + unique_id_.IsImmovableObject(heap->false_value()) || |
| + unique_id_.IsImmovableObject(heap->the_hole_value()) || |
| + unique_id_.IsImmovableObject(heap->empty_string()); |
| } |
| virtual Representation RequiredInputRepresentation(int index) { |
| @@ -3293,24 +3340,21 @@ class HConstant: public HTemplateInstruction<0> { |
| } |
| virtual intptr_t Hashcode() { |
| - ASSERT_ALLOCATION_DISABLED; |
| - intptr_t hash; |
| - |
| if (has_int32_value_) { |
| - hash = static_cast<intptr_t>(int32_value_); |
| + return static_cast<intptr_t>(int32_value_); |
| } else if (has_double_value_) { |
| - hash = static_cast<intptr_t>(BitCast<int64_t>(double_value_)); |
| + return static_cast<intptr_t>(BitCast<int64_t>(double_value_)); |
| } else { |
| ASSERT(!handle_.is_null()); |
| - // Dereferencing to use the object's raw address for hashing is safe. |
| - HandleDereferenceGuard allow_handle_deref(isolate(), |
| - HandleDereferenceGuard::ALLOW); |
| - SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) || |
| - !isolate()->optimizing_compiler_thread()->IsOptimizerThread()); |
| - hash = reinterpret_cast<intptr_t>(*handle_); |
| + return unique_id_.Hashcode(); |
| } |
| + } |
| - return hash; |
| + virtual void FinalizeUniqueValueId() { |
| + if (!has_double_value_) { |
| + ASSERT(!handle_.is_null()); |
| + unique_id_ = UniqueValueId(handle_); |
| + } |
| } |
| #ifdef DEBUG |
| @@ -3334,7 +3378,7 @@ class HConstant: public HTemplateInstruction<0> { |
| } else { |
| ASSERT(!handle_.is_null()); |
| return !other_constant->handle_.is_null() && |
| - handle_.is_identical_to(other_constant->handle_); |
| + unique_id_ == other_constant->unique_id_; |
| } |
| } |
| @@ -3348,6 +3392,7 @@ class HConstant: public HTemplateInstruction<0> { |
| // constant is non-numeric, handle_ always points to a valid |
| // constant HeapObject. |
| Handle<Object> handle_; |
| + UniqueValueId unique_id_; |
| // We store the HConstant in the most specific form safely possible. |
| // The two flags, has_int32_value_ and has_double_value_ tell us if |
| @@ -4759,7 +4804,7 @@ class HUnknownOSRValue: public HTemplateInstruction<0> { |
| class HLoadGlobalCell: public HTemplateInstruction<0> { |
| public: |
| HLoadGlobalCell(Handle<JSGlobalPropertyCell> cell, PropertyDetails details) |
| - : cell_(cell), details_(details) { |
| + : cell_(cell), details_(details), unique_id_() { |
| set_representation(Representation::Tagged()); |
| SetFlag(kUseGVN); |
| SetGVNFlag(kDependsOnGlobalVars); |
| @@ -4771,13 +4816,11 @@ class HLoadGlobalCell: public HTemplateInstruction<0> { |
| virtual void PrintDataTo(StringStream* stream); |
| virtual intptr_t Hashcode() { |
| - ASSERT_ALLOCATION_DISABLED; |
| - // Dereferencing to use the object's raw address for hashing is safe. |
| - HandleDereferenceGuard allow_handle_deref(isolate(), |
| - HandleDereferenceGuard::ALLOW); |
| - SLOW_ASSERT(Heap::RelocationLock::IsLocked(isolate()->heap()) || |
| - !isolate()->optimizing_compiler_thread()->IsOptimizerThread()); |
| - return reinterpret_cast<intptr_t>(*cell_); |
| + return unique_id_.Hashcode(); |
| + } |
| + |
| + virtual void FinalizeUniqueValueId() { |
| + unique_id_ = UniqueValueId(cell_); |
| } |
| virtual Representation RequiredInputRepresentation(int index) { |
| @@ -4789,7 +4832,7 @@ class HLoadGlobalCell: public HTemplateInstruction<0> { |
| protected: |
| virtual bool DataEquals(HValue* other) { |
| HLoadGlobalCell* b = HLoadGlobalCell::cast(other); |
| - return cell_.is_identical_to(b->cell()); |
| + return unique_id_ == b->unique_id_; |
| } |
| private: |
| @@ -4797,6 +4840,7 @@ class HLoadGlobalCell: public HTemplateInstruction<0> { |
| Handle<JSGlobalPropertyCell> cell_; |
| PropertyDetails details_; |
| + UniqueValueId unique_id_; |
| }; |
| @@ -5256,12 +5300,16 @@ class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> { |
| static const int kMaxLoadPolymorphism = 4; |
| + virtual void FinalizeUniqueValueId(); |
| + |
| protected: |
| virtual bool DataEquals(HValue* value); |
| private: |
| SmallMapList types_; |
| Handle<String> name_; |
| + ZoneList<UniqueValueId> types_unique_ids_; |
| + UniqueValueId name_unique_id_; |
| bool need_generic_; |
| }; |
| @@ -5525,6 +5573,7 @@ class HStoreNamedField: public HTemplateInstruction<2> { |
| : name_(name), |
| is_in_object_(in_object), |
| offset_(offset), |
| + transition_unique_id_(), |
| new_space_dominator_(NULL) { |
| SetOperandAt(0, obj); |
| SetOperandAt(1, val); |
| @@ -5555,6 +5604,7 @@ class HStoreNamedField: public HTemplateInstruction<2> { |
| bool is_in_object() const { return is_in_object_; } |
| int offset() const { return offset_; } |
| Handle<Map> transition() const { return transition_; } |
| + UniqueValueId transition_unique_id() const { return transition_unique_id_; } |
| void set_transition(Handle<Map> map) { transition_ = map; } |
| HValue* new_space_dominator() const { return new_space_dominator_; } |
| @@ -5567,11 +5617,16 @@ class HStoreNamedField: public HTemplateInstruction<2> { |
| return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); |
| } |
| + virtual void FinalizeUniqueValueId() { |
| + transition_unique_id_ = UniqueValueId(transition_); |
| + } |
| + |
| private: |
| Handle<String> name_; |
| bool is_in_object_; |
| int offset_; |
| Handle<Map> transition_; |
| + UniqueValueId transition_unique_id_; |
| HValue* new_space_dominator_; |
| }; |
| @@ -5772,6 +5827,8 @@ class HTransitionElementsKind: public HTemplateInstruction<2> { |
| Handle<Map> transitioned_map) |
| : original_map_(original_map), |
| transitioned_map_(transitioned_map), |
| + original_map_unique_id_(), |
| + transitioned_map_unique_id_(), |
| from_kind_(original_map->elements_kind()), |
| to_kind_(transitioned_map->elements_kind()) { |
| SetOperandAt(0, object); |
| @@ -5802,18 +5859,25 @@ class HTransitionElementsKind: public HTemplateInstruction<2> { |
| virtual void PrintDataTo(StringStream* stream); |
| + virtual void FinalizeUniqueValueId() { |
| + original_map_unique_id_ = UniqueValueId(original_map_); |
| + transitioned_map_unique_id_ = UniqueValueId(transitioned_map_); |
| + } |
| + |
| DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind) |
| protected: |
| virtual bool DataEquals(HValue* other) { |
| HTransitionElementsKind* instr = HTransitionElementsKind::cast(other); |
| - return original_map_.is_identical_to(instr->original_map()) && |
| - transitioned_map_.is_identical_to(instr->transitioned_map()); |
| + return original_map_unique_id_ == instr->original_map_unique_id_ && |
| + transitioned_map_unique_id_ == instr->transitioned_map_unique_id_; |
| } |
| private: |
| Handle<Map> original_map_; |
| Handle<Map> transitioned_map_; |
| + UniqueValueId original_map_unique_id_; |
| + UniqueValueId transitioned_map_unique_id_; |
| ElementsKind from_kind_; |
| ElementsKind to_kind_; |
| }; |