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 class IntrusiveIterationState { |
| 4939 public: |
| 4940 IntrusiveIterationState(HeapObject* obj) |
| 4941 : obj_(obj) { } |
| 4942 |
| 4943 Object* Get() { |
| 4944 return *HeapObject::RawField(obj_, HeapObject::kMapOffset); |
| 4945 } |
| 4946 |
| 4947 void Set(Object* s) { |
| 4948 *HeapObject::RawField(obj_, HeapObject::kMapOffset) = s; |
| 4949 } |
| 4950 |
| 4951 private: |
| 4952 HeapObject* obj_; |
| 4953 }; |
| 4954 |
| 4955 |
| 4956 class IntrusiveFixedArrayIterator { |
| 4957 public: |
| 4958 IntrusiveFixedArrayIterator(FixedArray* array) |
| 4959 : state_(array) { } |
| 4960 |
| 4961 bool IsIterating() { |
| 4962 return state_.Get()->IsSmi(); |
| 4963 } |
| 4964 |
| 4965 int GetIndex() { |
| 4966 return Smi::cast(state_.Get())->value(); |
| 4967 } |
| 4968 |
| 4969 void SetIndex(int index) { |
| 4970 state_.Set(Smi::FromInt(index)); |
| 4971 } |
| 4972 |
| 4973 void Stop() { |
| 4974 state_.Set(HEAP->fixed_array_map()); |
| 4975 } |
| 4976 |
| 4977 private: |
| 4978 IntrusiveIterationState state_; |
| 4979 }; |
| 4980 |
| 4981 |
| 4982 class IntrusiveMapIterator { |
| 4983 public: |
| 4984 IntrusiveMapIterator(Map* map) |
| 4985 : current_(map) { } |
| 4986 |
| 4987 void DescendInto(Map* child) { |
| 4988 Map* parent = Current(); |
| 4989 SetCurrent(child); |
| 4990 ASSERT(Parent() == HEAP->meta_map()); |
| 4991 SetParent(parent); |
| 4992 } |
| 4993 |
| 4994 Map* Ascend() { |
| 4995 // We are done with the current map. |
| 4996 // Before ascending reset iteration state. |
| 4997 StopMapTransitionsIteration(); |
| 4998 StopPrototypeTransitionsIteration(); |
| 4999 |
| 5000 Map* parent = Parent(); |
| 5001 SetParent(HEAP->meta_map()); |
| 5002 |
| 5003 Map* current = Current(); |
| 5004 SetCurrent(parent); |
| 5005 |
| 5006 return current; |
| 5007 } |
| 5008 |
| 5009 bool HasMore() { |
| 5010 return Current() != HEAP->meta_map(); |
| 5011 } |
| 5012 |
| 5013 |
| 5014 Map* NextUnvisitedChild() { |
| 5015 Map* child = NULL; |
| 5016 |
| 5017 child = NextUnvisitedMapTransition(); |
| 5018 if (child != NULL) return child; |
| 5019 |
| 5020 child = NextUnvisitedPrototypeTransition(); |
| 5021 if (child != NULL) return child; |
| 5022 |
| 5023 return NULL; |
| 5024 } |
| 5025 |
| 5026 private: |
| 5027 Map* current_; |
| 5028 |
| 5029 Map* Current() { |
| 5030 return current_; |
| 5031 } |
| 5032 |
| 5033 void SetCurrent(Map* current) { |
| 5034 current_ = current; |
| 5035 } |
| 5036 |
| 5037 Map* Parent() { |
| 5038 return reinterpret_cast<Map*>(IntrusiveIterationState(current_).Get()); |
| 5039 } |
| 5040 |
| 5041 void SetParent(Map* parent) { |
| 5042 IntrusiveIterationState(current_).Set(parent); |
| 5043 } |
| 5044 |
| 5045 FixedArray* ContentArray() { |
| 5046 DescriptorArray* d = Current()->instance_descriptors(); |
| 5047 return reinterpret_cast<FixedArray*>( |
| 5048 d->get(DescriptorArray::kContentArrayIndex)); |
| 5049 } |
| 5050 |
| 5051 bool HasContentArray() { |
| 5052 return !Current()->instance_descriptors()->IsEmpty(); |
| 5053 } |
| 5054 |
| 5055 void StopMapTransitionsIteration() { |
| 5056 if (HasContentArray()) { |
| 5057 IntrusiveFixedArrayIterator it(ContentArray()); |
| 5058 it.Stop(); |
| 5059 } |
| 5060 } |
| 5061 |
| 5062 Map* NextUnvisitedMapTransition() { |
| 5063 if (HasContentArray()) { |
| 5064 FixedArray* content = ContentArray(); |
| 5065 |
| 5066 IntrusiveFixedArrayIterator it(content); |
| 5067 for (int i = it.IsIterating() ? it.GetIndex() : 0; |
| 5068 i < content->length(); |
| 5069 i += 2) { |
| 5070 PropertyDetails details(Smi::cast(content->get(i + 1))); |
| 5071 if (details.IsTransition()) { |
| 5072 // Found a map in the transition array. We record our progress in |
| 5073 // the transition array by recording the current map in the map field |
| 5074 // of the next map and recording the index in the transition array in |
| 5075 // the map field of the array. |
| 5076 Map* child = Map::cast(content->get(i)); |
| 5077 it.SetIndex(i + 2); |
| 5078 return child; |
| 5079 } |
| 5080 } |
| 5081 } |
| 5082 return NULL; |
| 5083 } |
| 5084 |
| 5085 void StopPrototypeTransitionsIteration() { |
| 5086 FixedArray* array = Current()->unchecked_prototype_transitions(); |
| 5087 IntrusiveFixedArrayIterator it(array); |
| 5088 it.Stop(); |
| 5089 } |
| 5090 |
| 5091 Map* NextUnvisitedPrototypeTransition() { |
| 5092 FixedArray* array = Current()->unchecked_prototype_transitions(); |
| 5093 IntrusiveFixedArrayIterator it(array); |
| 5094 |
| 5095 static const int kFirstMapIndex = |
| 5096 (Map::kProtoTransitionHeaderSize + Map::kProtoTransitionMapOffset); |
| 5097 |
| 5098 int index = it.IsIterating() ? it.GetIndex() : kFirstMapIndex; |
| 5099 |
| 5100 if (index < array->length()) { |
| 5101 Object* child = array->get(index); |
| 5102 if (child->IsMap()) { |
| 5103 it.SetIndex(index + Map::kProtoTransitionElementsPerEntry); |
| 5104 return Map::cast(child); |
| 5105 } |
| 5106 } |
| 5107 |
| 5108 return NULL; |
| 5109 } |
| 5110 }; |
| 5111 |
| 5112 |
4938 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { | 5113 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { |
4939 // Traverse the transition tree without using a stack. We do this by | 5114 // Traverse the transition tree without using a stack. We do this by |
4940 // reversing the pointers in the maps and descriptor arrays. | 5115 // reversing the pointers in the maps and descriptor arrays. |
4941 Map* current = this; | 5116 IntrusiveMapIterator it(this); |
4942 Map* meta_map = GetHeap()->meta_map(); | 5117 while (it.HasMore()) { |
4943 Object** map_or_index_field = NULL; | 5118 Map* child = it.NextUnvisitedChild(); |
4944 while (current != meta_map) { | 5119 if (child != NULL) { |
4945 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( | 5120 it.DescendInto(child); |
4946 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); | |
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 { | 5121 } else { |
4972 map_or_index_field = NULL; | 5122 Map* map = it.Ascend(); |
| 5123 callback(map, data); |
4973 } | 5124 } |
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 } | 5125 } |
5008 } | 5126 } |
5009 | 5127 |
5010 | 5128 |
5011 MaybeObject* CodeCache::Update(String* name, Code* code) { | 5129 MaybeObject* CodeCache::Update(String* name, Code* code) { |
5012 // The number of monomorphic stubs for normal load/store/call IC's can grow to | 5130 // 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 | 5131 // a large number and therefore they need to go into a hash table. They are |
5014 // used to load global properties from cells. | 5132 // used to load global properties from cells. |
5015 if (code->type() == NORMAL) { | 5133 if (code->type() == NORMAL) { |
5016 // Make sure that a hash table is allocated for the normal load code cache. | 5134 // 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; | 12927 if (break_point_objects()->IsUndefined()) return 0; |
12810 // Single break point. | 12928 // Single break point. |
12811 if (!break_point_objects()->IsFixedArray()) return 1; | 12929 if (!break_point_objects()->IsFixedArray()) return 1; |
12812 // Multiple break points. | 12930 // Multiple break points. |
12813 return FixedArray::cast(break_point_objects())->length(); | 12931 return FixedArray::cast(break_point_objects())->length(); |
12814 } | 12932 } |
12815 #endif // ENABLE_DEBUGGER_SUPPORT | 12933 #endif // ENABLE_DEBUGGER_SUPPORT |
12816 | 12934 |
12817 | 12935 |
12818 } } // namespace v8::internal | 12936 } } // namespace v8::internal |
OLD | NEW |