Chromium Code Reviews| 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 |