OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 4917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4928 | 4928 |
4929 | 4929 |
4930 void Map::RemoveFromCodeCache(String* name, Code* code, int index) { | 4930 void Map::RemoveFromCodeCache(String* name, Code* code, int index) { |
4931 // No GC is supposed to happen between a call to IndexInCodeCache and | 4931 // No GC is supposed to happen between a call to IndexInCodeCache and |
4932 // RemoveFromCodeCache so the code cache must be there. | 4932 // RemoveFromCodeCache so the code cache must be there. |
4933 ASSERT(!code_cache()->IsFixedArray()); | 4933 ASSERT(!code_cache()->IsFixedArray()); |
4934 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); | 4934 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); |
4935 } | 4935 } |
4936 | 4936 |
4937 | 4937 |
4938 // An iterator over all map transitions in an descriptor array, reusing the map | |
4939 // field of the contens array while it is running. | |
4940 class IntrusiveMapTransitionIterator { | |
4941 public: | |
4942 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array) | |
4943 : descriptor_array_(descriptor_array) { } | |
4944 | |
4945 void Start() { | |
4946 ASSERT(!IsIterating()); | |
4947 if (HasContentArray()) *ContentHeader() = Smi::FromInt(0); | |
4948 } | |
4949 | |
4950 bool IsIterating() { | |
4951 return HasContentArray() && (*ContentHeader())->IsSmi(); | |
4952 } | |
4953 | |
4954 Map* Next() { | |
4955 ASSERT(IsIterating()); | |
4956 FixedArray* contents = ContentArray(); | |
4957 int index = Smi::cast(*ContentHeader())->value(); | |
4958 while (index < contents->length()) { | |
4959 int next_index = index + 2; | |
4960 PropertyDetails details(Smi::cast(contents->get(index + 1))); | |
4961 if (details.IsTransition()) { | |
4962 *ContentHeader() = Smi::FromInt(next_index); | |
4963 return static_cast<Map*>(contents->get(index)); | |
4964 } | |
4965 index = next_index; | |
4966 } | |
4967 *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map(); | |
4968 return NULL; | |
4969 } | |
4970 | |
4971 private: | |
4972 bool HasContentArray() { | |
4973 return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex; | |
4974 } | |
4975 | |
4976 FixedArray* ContentArray() { | |
4977 Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex); | |
4978 return static_cast<FixedArray*>(array); | |
4979 } | |
4980 | |
4981 Object** ContentHeader() { | |
4982 return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset); | |
4983 } | |
4984 | |
4985 DescriptorArray* descriptor_array_; | |
4986 }; | |
4987 | |
4988 | |
4989 // An iterator over all prototype transitions, reusing the map field of the | |
4990 // underlying array while it is running. | |
4991 class IntrusivePrototypeTransitionIterator { | |
4992 public: | |
4993 explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans) | |
4994 : proto_trans_(proto_trans) { } | |
4995 | |
4996 void Start() { | |
4997 ASSERT(!IsIterating()); | |
4998 if (HasTransitions()) *Header() = Smi::FromInt(0); | |
4999 } | |
5000 | |
5001 bool IsIterating() { | |
5002 return HasTransitions() && (*Header())->IsSmi(); | |
5003 } | |
5004 | |
5005 Map* Next() { | |
5006 ASSERT(IsIterating()); | |
5007 int transitionNumber = Smi::cast(*Header())->value(); | |
5008 if (transitionNumber < NumberOfTransitions()) { | |
5009 *Header() = Smi::FromInt(transitionNumber + 1); | |
5010 return GetTransition(transitionNumber); | |
5011 } | |
5012 *Header() = proto_trans_->GetHeap()->fixed_array_map(); | |
5013 return NULL; | |
5014 } | |
5015 | |
5016 private: | |
5017 bool HasTransitions() { | |
5018 return proto_trans_->length() >= Map::kProtoTransitionHeaderSize; | |
5019 } | |
5020 | |
5021 Object** Header() { | |
5022 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset); | |
5023 } | |
5024 | |
5025 int NumberOfTransitions() { | |
5026 Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset); | |
5027 return Smi::cast(num)->value(); | |
5028 } | |
5029 | |
5030 Map* GetTransition(int transitionNumber) { | |
5031 return Map::cast(proto_trans_->get(IndexFor(transitionNumber))); | |
5032 } | |
5033 | |
5034 int IndexFor(int transitionNumber) { | |
5035 return Map::kProtoTransitionHeaderSize + | |
5036 Map::kProtoTransitionMapOffset + | |
5037 transitionNumber * Map::kProtoTransitionElementsPerEntry; | |
5038 } | |
5039 | |
5040 FixedArray* proto_trans_; | |
5041 }; | |
5042 | |
5043 | |
5044 // To traverse the transition tree iteratively, we have to store two kinds of | |
5045 // information in a map: The parent map in the traversal and which children of a | |
5046 // node have already been visited. To do this without additional memory, we | |
5047 // temporarily reuse two maps with known values: | |
5048 // | |
5049 // (1) The map of the map temporarily holds the parent, and is restored to the | |
5050 // meta map afterwards. | |
5051 // | |
5052 // (2) The info which children have already been visited depends on which part | |
5053 // of the map we currently iterate: | |
5054 // | |
5055 // (a) If we currently follow normal map transitions, we temporarily store | |
5056 // the current index in the map of the FixedArray of the desciptor | |
5057 // array's contents, and restore it to the fixed array map afterwards. | |
5058 // Note that a single descriptor can have 0, 1, or 2 transitions. | |
5059 // | |
5060 // (b) If we currently follow prototype transitions, we temporarily store | |
5061 // the current index in the map of the FixedArray holding the prototype | |
5062 // transitions, and restore it to the fixed array map afterwards. | |
5063 // | |
5064 // Note that the child iterator is just a concatenation of two iterators: One | |
5065 // iterating over map transitions and one iterating over prototype transisitons. | |
5066 class TraversableMap : public Map { | |
Vyacheslav Egorov (Chromium)
2012/01/23 10:43:09
inheritance still.
| |
5067 public: | |
5068 // Record the parent in the traversal within this map. Note that this destroys | |
5069 // this map's map! | |
5070 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); } | |
5071 | |
5072 // Reset the current map's map, returning the parent previously stored in it. | |
5073 TraversableMap* GetAndResetParent() { | |
5074 TraversableMap* old_parent = static_cast<TraversableMap*>(map()); | |
5075 set_map_no_write_barrier(GetHeap()->meta_map()); | |
5076 return old_parent; | |
5077 } | |
5078 | |
5079 // Start iterating over this map's children, possibly destroying a FixedArray | |
5080 // map (see explanation above). | |
5081 void ChildIteratorStart() { | |
5082 IntrusiveMapTransitionIterator(instance_descriptors()).Start(); | |
5083 IntrusivePrototypeTransitionIterator( | |
5084 unchecked_prototype_transitions()).Start(); | |
5085 } | |
5086 | |
5087 // If we have an unvisited child map, return that one and advance. If we have | |
5088 // none, return NULL and reset any destroyed FixedArray maps. | |
5089 TraversableMap* ChildIteratorNext() { | |
5090 IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors()); | |
5091 if (descriptor_iterator.IsIterating()) { | |
5092 Map* next = descriptor_iterator.Next(); | |
5093 if (next != NULL) return static_cast<TraversableMap*>(next); | |
5094 } | |
5095 IntrusivePrototypeTransitionIterator | |
5096 proto_iterator(unchecked_prototype_transitions()); | |
5097 if (proto_iterator.IsIterating()) { | |
5098 Map* next = proto_iterator.Next(); | |
5099 if (next != NULL) return static_cast<TraversableMap*>(next); | |
5100 } | |
5101 return NULL; | |
5102 } | |
5103 }; | |
5104 | |
5105 | |
5106 // Traverse the transition tree in postorder without using the C++ stack by | |
5107 // doing pointer reversal. | |
4938 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { | 5108 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { |
4939 // Traverse the transition tree without using a stack. We do this by | 5109 TraversableMap* current = static_cast<TraversableMap*>(this); |
4940 // reversing the pointers in the maps and descriptor arrays. | 5110 current->ChildIteratorStart(); |
4941 Map* current = this; | 5111 while (true) { |
4942 Map* meta_map = GetHeap()->meta_map(); | 5112 TraversableMap* child = current->ChildIteratorNext(); |
4943 Object** map_or_index_field = NULL; | 5113 if (child != NULL) { |
4944 while (current != meta_map) { | 5114 child->ChildIteratorStart(); |
4945 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( | 5115 child->SetParent(current); |
4946 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); | 5116 current = child; |
4947 if (!d->IsEmpty()) { | |
4948 FixedArray* contents = reinterpret_cast<FixedArray*>( | |
4949 d->get(DescriptorArray::kContentArrayIndex)); | |
4950 map_or_index_field = RawField(contents, HeapObject::kMapOffset); | |
4951 Object* map_or_index = *map_or_index_field; | |
4952 bool map_done = true; // Controls a nested continue statement. | |
4953 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0; | |
4954 i < contents->length(); | |
4955 i += 2) { | |
4956 PropertyDetails details(Smi::cast(contents->get(i + 1))); | |
4957 if (details.IsTransition()) { | |
4958 // Found a map in the transition array. We record our progress in | |
4959 // the transition array by recording the current map in the map field | |
4960 // of the next map and recording the index in the transition array in | |
4961 // the map field of the array. | |
4962 Map* next = Map::cast(contents->get(i)); | |
4963 next->set_map_no_write_barrier(current); | |
4964 *map_or_index_field = Smi::FromInt(i + 2); | |
4965 current = next; | |
4966 map_done = false; | |
4967 break; | |
4968 } | |
4969 } | |
4970 if (!map_done) continue; | |
4971 } else { | 5117 } else { |
4972 map_or_index_field = NULL; | 5118 TraversableMap* parent = current->GetAndResetParent(); |
5119 callback(current, data); | |
5120 if (current == this) break; | |
5121 current = parent; | |
4973 } | 5122 } |
4974 // That was the regular transitions, now for the prototype transitions. | |
4975 FixedArray* prototype_transitions = | |
4976 current->unchecked_prototype_transitions(); | |
4977 Object** proto_map_or_index_field = | |
4978 RawField(prototype_transitions, HeapObject::kMapOffset); | |
4979 Object* map_or_index = *proto_map_or_index_field; | |
4980 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; | |
4981 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start; | |
4982 if (i < prototype_transitions->length()) { | |
4983 // Found a map in the prototype transition array. Record progress in | |
4984 // an analogous way to the regular transitions array above. | |
4985 Object* perhaps_map = prototype_transitions->get(i); | |
4986 if (perhaps_map->IsMap()) { | |
4987 Map* next = Map::cast(perhaps_map); | |
4988 next->set_map_no_write_barrier(current); | |
4989 *proto_map_or_index_field = | |
4990 Smi::FromInt(i + kProtoTransitionElementsPerEntry); | |
4991 current = next; | |
4992 continue; | |
4993 } | |
4994 } | |
4995 *proto_map_or_index_field = GetHeap()->fixed_array_map(); | |
4996 if (map_or_index_field != NULL) { | |
4997 *map_or_index_field = GetHeap()->fixed_array_map(); | |
4998 } | |
4999 | |
5000 // The callback expects a map to have a real map as its map, so we save | |
5001 // the map field, which is being used to track the traversal and put the | |
5002 // correct map (the meta_map) in place while we do the callback. | |
5003 Map* prev = current->map(); | |
5004 current->set_map_no_write_barrier(meta_map); | |
5005 callback(current, data); | |
5006 current = prev; | |
5007 } | 5123 } |
5008 } | 5124 } |
5009 | 5125 |
5010 | 5126 |
5011 MaybeObject* CodeCache::Update(String* name, Code* code) { | 5127 MaybeObject* CodeCache::Update(String* name, Code* code) { |
5012 // The number of monomorphic stubs for normal load/store/call IC's can grow to | 5128 // The number of monomorphic stubs for normal load/store/call IC's can grow to |
5013 // a large number and therefore they need to go into a hash table. They are | 5129 // a large number and therefore they need to go into a hash table. They are |
5014 // used to load global properties from cells. | 5130 // used to load global properties from cells. |
5015 if (code->type() == NORMAL) { | 5131 if (code->type() == NORMAL) { |
5016 // Make sure that a hash table is allocated for the normal load code cache. | 5132 // Make sure that a hash table is allocated for the normal load code cache. |
(...skipping 7792 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12809 if (break_point_objects()->IsUndefined()) return 0; | 12925 if (break_point_objects()->IsUndefined()) return 0; |
12810 // Single break point. | 12926 // Single break point. |
12811 if (!break_point_objects()->IsFixedArray()) return 1; | 12927 if (!break_point_objects()->IsFixedArray()) return 1; |
12812 // Multiple break points. | 12928 // Multiple break points. |
12813 return FixedArray::cast(break_point_objects())->length(); | 12929 return FixedArray::cast(break_point_objects())->length(); |
12814 } | 12930 } |
12815 #endif // ENABLE_DEBUGGER_SUPPORT | 12931 #endif // ENABLE_DEBUGGER_SUPPORT |
12816 | 12932 |
12817 | 12933 |
12818 } } // namespace v8::internal | 12934 } } // namespace v8::internal |
OLD | NEW |