Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(676)

Side by Side Diff: src/objects.cc

Issue 9252007: Refactored iterative map traversal. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Removed inheritance for descriptor/proto iterators plus some renaming Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698