| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <sstream> | 5 #include <sstream> |
| 6 | 6 |
| 7 #include "src/v8.h" | 7 #include "src/v8.h" |
| 8 | 8 |
| 9 #include "src/accessors.h" | 9 #include "src/accessors.h" |
| 10 #include "src/allocation-site-scopes.h" | 10 #include "src/allocation-site-scopes.h" |
| (...skipping 7659 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7670 | 7670 |
| 7671 | 7671 |
| 7672 void Map::RemoveFromCodeCache(Name* name, Code* code, int index) { | 7672 void Map::RemoveFromCodeCache(Name* name, Code* code, int index) { |
| 7673 // No GC is supposed to happen between a call to IndexInCodeCache and | 7673 // No GC is supposed to happen between a call to IndexInCodeCache and |
| 7674 // RemoveFromCodeCache so the code cache must be there. | 7674 // RemoveFromCodeCache so the code cache must be there. |
| 7675 DCHECK(!code_cache()->IsFixedArray()); | 7675 DCHECK(!code_cache()->IsFixedArray()); |
| 7676 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); | 7676 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); |
| 7677 } | 7677 } |
| 7678 | 7678 |
| 7679 | 7679 |
| 7680 // An iterator over all map transitions in an descriptor array, reusing the | 7680 static void TraverseTransitionTreeInternal(Map* map, |
| 7681 // constructor field of the map while it is running. Negative values in | 7681 Map::TraverseCallback callback, |
| 7682 // the constructor field indicate an active map transition iteration. The | 7682 void* data) { |
| 7683 // original constructor is restored after iterating over all entries. | 7683 if (map->HasTransitionArray()) { |
| 7684 class IntrusiveMapTransitionIterator { | 7684 TransitionArray* transitions = map->transitions(); |
| 7685 public: | 7685 if (transitions->HasPrototypeTransitions()) { |
| 7686 IntrusiveMapTransitionIterator( | 7686 FixedArray* proto_trans = transitions->GetPrototypeTransitions(); |
| 7687 Map* map, TransitionArray* transition_array, Object* constructor) | 7687 Object* num_obj = |
| 7688 : map_(map), | 7688 proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset); |
| 7689 transition_array_(transition_array), | 7689 int num = Smi::cast(num_obj)->value(); |
| 7690 constructor_(constructor) { } | 7690 for (int i = 0; i < num; ++i) { |
| 7691 | 7691 int index = Map::kProtoTransitionHeaderSize + i; |
| 7692 void StartIfNotStarted() { | 7692 TraverseTransitionTreeInternal(Map::cast(proto_trans->get(index)), |
| 7693 DCHECK(!(*IteratorField())->IsSmi() || IsIterating()); | 7693 callback, data); |
| 7694 if (!(*IteratorField())->IsSmi()) { | 7694 } |
| 7695 DCHECK(*IteratorField() == constructor_); | 7695 } |
| 7696 *IteratorField() = Smi::FromInt(-1); | 7696 for (int i = 0; i < transitions->number_of_transitions(); ++i) { |
| 7697 TraverseTransitionTreeInternal(transitions->GetTarget(i), callback, data); |
| 7697 } | 7698 } |
| 7698 } | 7699 } |
| 7699 | 7700 callback(map, data); |
| 7700 bool IsIterating() { | 7701 } |
| 7701 return (*IteratorField())->IsSmi() && | |
| 7702 Smi::cast(*IteratorField())->value() < 0; | |
| 7703 } | |
| 7704 | |
| 7705 Map* Next() { | |
| 7706 DCHECK(IsIterating()); | |
| 7707 int value = Smi::cast(*IteratorField())->value(); | |
| 7708 int index = -value - 1; | |
| 7709 int number_of_transitions = transition_array_->number_of_transitions(); | |
| 7710 if (index < number_of_transitions) { | |
| 7711 *IteratorField() = Smi::FromInt(value - 1); | |
| 7712 return transition_array_->GetTarget(index); | |
| 7713 } | |
| 7714 | |
| 7715 *IteratorField() = constructor_; | |
| 7716 return NULL; | |
| 7717 } | |
| 7718 | |
| 7719 private: | |
| 7720 Object** IteratorField() { | |
| 7721 return HeapObject::RawField(map_, Map::kConstructorOffset); | |
| 7722 } | |
| 7723 | |
| 7724 Map* map_; | |
| 7725 TransitionArray* transition_array_; | |
| 7726 Object* constructor_; | |
| 7727 }; | |
| 7728 | 7702 |
| 7729 | 7703 |
| 7730 // An iterator over all prototype transitions, reusing the constructor field | 7704 // Traverse the transition tree in postorder. |
| 7731 // of the map while it is running. Positive values in the constructor field | |
| 7732 // indicate an active prototype transition iteration. The original constructor | |
| 7733 // is restored after iterating over all entries. | |
| 7734 class IntrusivePrototypeTransitionIterator { | |
| 7735 public: | |
| 7736 IntrusivePrototypeTransitionIterator( | |
| 7737 Map* map, HeapObject* proto_trans, Object* constructor) | |
| 7738 : map_(map), proto_trans_(proto_trans), constructor_(constructor) { } | |
| 7739 | |
| 7740 void StartIfNotStarted() { | |
| 7741 if (!(*IteratorField())->IsSmi()) { | |
| 7742 DCHECK(*IteratorField() == constructor_); | |
| 7743 *IteratorField() = Smi::FromInt(0); | |
| 7744 } | |
| 7745 } | |
| 7746 | |
| 7747 bool IsIterating() { | |
| 7748 return (*IteratorField())->IsSmi() && | |
| 7749 Smi::cast(*IteratorField())->value() >= 0; | |
| 7750 } | |
| 7751 | |
| 7752 Map* Next() { | |
| 7753 DCHECK(IsIterating()); | |
| 7754 int transitionNumber = Smi::cast(*IteratorField())->value(); | |
| 7755 if (transitionNumber < NumberOfTransitions()) { | |
| 7756 *IteratorField() = Smi::FromInt(transitionNumber + 1); | |
| 7757 return GetTransition(transitionNumber); | |
| 7758 } | |
| 7759 *IteratorField() = constructor_; | |
| 7760 return NULL; | |
| 7761 } | |
| 7762 | |
| 7763 private: | |
| 7764 Object** IteratorField() { | |
| 7765 return HeapObject::RawField(map_, Map::kConstructorOffset); | |
| 7766 } | |
| 7767 | |
| 7768 int NumberOfTransitions() { | |
| 7769 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_); | |
| 7770 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset); | |
| 7771 return Smi::cast(num)->value(); | |
| 7772 } | |
| 7773 | |
| 7774 Map* GetTransition(int transitionNumber) { | |
| 7775 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_); | |
| 7776 int index = Map::kProtoTransitionHeaderSize + transitionNumber; | |
| 7777 return Map::cast(proto_trans->get(index)); | |
| 7778 } | |
| 7779 | |
| 7780 Map* map_; | |
| 7781 HeapObject* proto_trans_; | |
| 7782 Object* constructor_; | |
| 7783 }; | |
| 7784 | |
| 7785 | |
| 7786 // To traverse the transition tree iteratively, we have to store two kinds of | |
| 7787 // information in a map: The parent map in the traversal and which children of a | |
| 7788 // node have already been visited. To do this without additional memory, we | |
| 7789 // temporarily reuse two fields with known values: | |
| 7790 // | |
| 7791 // (1) The map of the map temporarily holds the parent, and is restored to the | |
| 7792 // meta map afterwards. | |
| 7793 // | |
| 7794 // (2) The info which children have already been visited depends on which part | |
| 7795 // of the map we currently iterate. We use the constructor field of the | |
| 7796 // map to store the current index. We can do that because the constructor | |
| 7797 // is the same for all involved maps. | |
| 7798 // | |
| 7799 // (a) If we currently follow normal map transitions, we temporarily store | |
| 7800 // the current index in the constructor field, and restore it to the | |
| 7801 // original constructor afterwards. Note that a single descriptor can | |
| 7802 // have 0, 1, or 2 transitions. | |
| 7803 // | |
| 7804 // (b) If we currently follow prototype transitions, we temporarily store | |
| 7805 // the current index in the constructor field, and restore it to the | |
| 7806 // original constructor afterwards. | |
| 7807 // | |
| 7808 // Note that the child iterator is just a concatenation of two iterators: One | |
| 7809 // iterating over map transitions and one iterating over prototype transisitons. | |
| 7810 class TraversableMap : public Map { | |
| 7811 public: | |
| 7812 // Record the parent in the traversal within this map. Note that this destroys | |
| 7813 // this map's map! | |
| 7814 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); } | |
| 7815 | |
| 7816 // Reset the current map's map, returning the parent previously stored in it. | |
| 7817 TraversableMap* GetAndResetParent() { | |
| 7818 TraversableMap* old_parent = static_cast<TraversableMap*>(map()); | |
| 7819 set_map_no_write_barrier(GetHeap()->meta_map()); | |
| 7820 return old_parent; | |
| 7821 } | |
| 7822 | |
| 7823 // If we have an unvisited child map, return that one and advance. If we have | |
| 7824 // none, return NULL and restore the overwritten constructor field. | |
| 7825 TraversableMap* ChildIteratorNext(Object* constructor) { | |
| 7826 if (!HasTransitionArray()) return NULL; | |
| 7827 | |
| 7828 TransitionArray* transition_array = transitions(); | |
| 7829 if (transition_array->HasPrototypeTransitions()) { | |
| 7830 HeapObject* proto_transitions = | |
| 7831 transition_array->GetPrototypeTransitions(); | |
| 7832 IntrusivePrototypeTransitionIterator proto_iterator(this, | |
| 7833 proto_transitions, | |
| 7834 constructor); | |
| 7835 proto_iterator.StartIfNotStarted(); | |
| 7836 if (proto_iterator.IsIterating()) { | |
| 7837 Map* next = proto_iterator.Next(); | |
| 7838 if (next != NULL) return static_cast<TraversableMap*>(next); | |
| 7839 } | |
| 7840 } | |
| 7841 | |
| 7842 IntrusiveMapTransitionIterator transition_iterator(this, | |
| 7843 transition_array, | |
| 7844 constructor); | |
| 7845 transition_iterator.StartIfNotStarted(); | |
| 7846 if (transition_iterator.IsIterating()) { | |
| 7847 Map* next = transition_iterator.Next(); | |
| 7848 if (next != NULL) return static_cast<TraversableMap*>(next); | |
| 7849 } | |
| 7850 | |
| 7851 return NULL; | |
| 7852 } | |
| 7853 }; | |
| 7854 | |
| 7855 | |
| 7856 // Traverse the transition tree in postorder without using the C++ stack by | |
| 7857 // doing pointer reversal. | |
| 7858 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { | 7705 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { |
| 7859 // Make sure that we do not allocate in the callback. | 7706 // Make sure that we do not allocate in the callback. |
| 7860 DisallowHeapAllocation no_allocation; | 7707 DisallowHeapAllocation no_allocation; |
| 7861 | 7708 TraverseTransitionTreeInternal(this, callback, data); |
| 7862 TraversableMap* current = static_cast<TraversableMap*>(this); | |
| 7863 // Get the root constructor here to restore it later when finished iterating | |
| 7864 // over maps. | |
| 7865 Object* root_constructor = constructor(); | |
| 7866 while (true) { | |
| 7867 TraversableMap* child = current->ChildIteratorNext(root_constructor); | |
| 7868 if (child != NULL) { | |
| 7869 child->SetParent(current); | |
| 7870 current = child; | |
| 7871 } else { | |
| 7872 TraversableMap* parent = current->GetAndResetParent(); | |
| 7873 callback(current, data); | |
| 7874 if (current == this) break; | |
| 7875 current = parent; | |
| 7876 } | |
| 7877 } | |
| 7878 } | 7709 } |
| 7879 | 7710 |
| 7880 | 7711 |
| 7881 void CodeCache::Update( | 7712 void CodeCache::Update( |
| 7882 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) { | 7713 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) { |
| 7883 // The number of monomorphic stubs for normal load/store/call IC's can grow to | 7714 // The number of monomorphic stubs for normal load/store/call IC's can grow to |
| 7884 // a large number and therefore they need to go into a hash table. They are | 7715 // a large number and therefore they need to go into a hash table. They are |
| 7885 // used to load global properties from cells. | 7716 // used to load global properties from cells. |
| 7886 if (code->type() == Code::NORMAL) { | 7717 if (code->type() == Code::NORMAL) { |
| 7887 // Make sure that a hash table is allocated for the normal load code cache. | 7718 // Make sure that a hash table is allocated for the normal load code cache. |
| (...skipping 9441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 17329 CompilationInfo* info) { | 17160 CompilationInfo* info) { |
| 17330 Handle<DependentCode> codes = DependentCode::InsertCompilationInfo( | 17161 Handle<DependentCode> codes = DependentCode::InsertCompilationInfo( |
| 17331 handle(cell->dependent_code(), info->isolate()), | 17162 handle(cell->dependent_code(), info->isolate()), |
| 17332 DependentCode::kPropertyCellChangedGroup, info->object_wrapper()); | 17163 DependentCode::kPropertyCellChangedGroup, info->object_wrapper()); |
| 17333 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes); | 17164 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes); |
| 17334 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add( | 17165 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add( |
| 17335 cell, info->zone()); | 17166 cell, info->zone()); |
| 17336 } | 17167 } |
| 17337 | 17168 |
| 17338 } } // namespace v8::internal | 17169 } } // namespace v8::internal |
| OLD | NEW |