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

Side by Side Diff: src/objects.cc

Issue 7074052: Fix traversal of the map transition tree to take the prototype (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 6 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 | « src/objects.h ('k') | 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 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 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 3876 matching lines...) Expand 10 before | Expand all | Expand 10 after
3887 3887
3888 void Map::RemoveFromCodeCache(String* name, Code* code, int index) { 3888 void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
3889 // No GC is supposed to happen between a call to IndexInCodeCache and 3889 // No GC is supposed to happen between a call to IndexInCodeCache and
3890 // RemoveFromCodeCache so the code cache must be there. 3890 // RemoveFromCodeCache so the code cache must be there.
3891 ASSERT(!code_cache()->IsFixedArray()); 3891 ASSERT(!code_cache()->IsFixedArray());
3892 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); 3892 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
3893 } 3893 }
3894 3894
3895 3895
3896 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { 3896 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
3897 // Traverse the transition tree without using a stack. We do this by
3898 // reversing the pointers in the maps and descriptor arrays.
3897 Map* current = this; 3899 Map* current = this;
3898 Map* meta_map = heap()->meta_map(); 3900 Map* meta_map = heap()->meta_map();
3901 Object** map_or_index_field = NULL;
3899 while (current != meta_map) { 3902 while (current != meta_map) {
3900 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( 3903 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
3901 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); 3904 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
3902 if (d->IsEmpty()) { 3905 if (!d->IsEmpty()) {
3903 Map* prev = current->map(); 3906 FixedArray* contents = reinterpret_cast<FixedArray*>(
3904 current->set_map(meta_map); 3907 d->get(DescriptorArray::kContentArrayIndex));
3905 callback(current, data); 3908 map_or_index_field = RawField(contents, HeapObject::kMapOffset);
3906 current = prev; 3909 Object* map_or_index = *map_or_index_field;
3907 continue; 3910 bool map_done = true; // Controls a nested continue statement.
3911 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
3912 i < contents->length();
3913 i += 2) {
3914 PropertyDetails details(Smi::cast(contents->get(i + 1)));
3915 if (details.IsTransition()) {
3916 // Found a map in the transition array. We record our progress in
3917 // the transition array by recording the current map in the map field
3918 // of the next map and recording the index in the transition array in
3919 // the map field of the array.
3920 Map* next = Map::cast(contents->get(i));
3921 next->set_map(current);
3922 *map_or_index_field = Smi::FromInt(i + 2);
3923 current = next;
3924 map_done = false;
3925 break;
3926 }
3927 }
3928 if (!map_done) continue;
3929 }
3930 // That was the regular transitions, now for the prototype transitions.
3931 FixedArray* prototype_transitions =
3932 current->unchecked_prototype_transitions();
3933 Object** proto_map_or_index_field =
3934 RawField(prototype_transitions, HeapObject::kMapOffset);
3935 Object* map_or_index = *proto_map_or_index_field;
3936 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
3937 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
3938 if (i < prototype_transitions->length()) {
3939 // Found a map in the prototype transition array. Record progress in
3940 // an analogous way to the regular transitions array above.
3941 Object* perhaps_map = prototype_transitions->get(i);
3942 if (perhaps_map->IsMap()) {
3943 Map* next = Map::cast(perhaps_map);
3944 next->set_map(current);
3945 *proto_map_or_index_field =
3946 Smi::FromInt(i + kProtoTransitionElementsPerEntry);
3947 current = next;
3948 continue;
3949 }
3950 }
3951 *proto_map_or_index_field = heap()->fixed_array_map();
3952 if (map_or_index_field != NULL) {
3953 *map_or_index_field = heap()->fixed_array_map();
3908 } 3954 }
3909 3955
3910 FixedArray* contents = reinterpret_cast<FixedArray*>( 3956 // The callback expects a map to have a real map as its map, so we save
3911 d->get(DescriptorArray::kContentArrayIndex)); 3957 // the map field, which is being used to track the traversal and put the
3912 Object** map_or_index_field = RawField(contents, HeapObject::kMapOffset); 3958 // correct map (the meta_map) in place while we do the callback.
3913 Object* map_or_index = *map_or_index_field;
3914 bool map_done = true;
3915 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
3916 i < contents->length();
3917 i += 2) {
3918 PropertyDetails details(Smi::cast(contents->get(i + 1)));
3919 if (details.IsTransition()) {
3920 Map* next = reinterpret_cast<Map*>(contents->get(i));
3921 next->set_map(current);
3922 *map_or_index_field = Smi::FromInt(i + 2);
3923 current = next;
3924 map_done = false;
3925 break;
3926 }
3927 }
3928 if (!map_done) continue;
3929 *map_or_index_field = heap()->fixed_array_map();
3930 Map* prev = current->map(); 3959 Map* prev = current->map();
3931 current->set_map(meta_map); 3960 current->set_map(meta_map);
3932 callback(current, data); 3961 callback(current, data);
3933 current = prev; 3962 current = prev;
3934 } 3963 }
3935 } 3964 }
3936 3965
3937 3966
3938 MaybeObject* CodeCache::Update(String* name, Code* code) { 3967 MaybeObject* CodeCache::Update(String* name, Code* code) {
3939 // The number of monomorphic stubs for normal load/store/call IC's can grow to 3968 // The number of monomorphic stubs for normal load/store/call IC's can grow to
(...skipping 2417 matching lines...) Expand 10 before | Expand all | Expand 10 after
6357 Builtins* builtins = heap->isolate()->builtins(); 6386 Builtins* builtins = heap->isolate()->builtins();
6358 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), 6387 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
6359 construct_stub()); 6388 construct_stub());
6360 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); 6389 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
6361 6390
6362 int slack = map->unused_property_fields(); 6391 int slack = map->unused_property_fields();
6363 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack); 6392 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6364 if (slack != 0) { 6393 if (slack != 0) {
6365 // Resize the initial map and all maps in its transition tree. 6394 // Resize the initial map and all maps in its transition tree.
6366 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack); 6395 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
6396
6367 // Give the correct expected_nof_properties to initial maps created later. 6397 // Give the correct expected_nof_properties to initial maps created later.
6368 ASSERT(expected_nof_properties() >= slack); 6398 ASSERT(expected_nof_properties() >= slack);
6369 set_expected_nof_properties(expected_nof_properties() - slack); 6399 set_expected_nof_properties(expected_nof_properties() - slack);
6370 } 6400 }
6371 } 6401 }
6372 6402
6373 6403
6374 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { 6404 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
6375 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); 6405 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
6376 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); 6406 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
(...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after
7076 } 7106 }
7077 FixedArray::cast(obj)->set(0, len); 7107 FixedArray::cast(obj)->set(0, len);
7078 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); 7108 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
7079 set_elements(FixedArray::cast(obj)); 7109 set_elements(FixedArray::cast(obj));
7080 return this; 7110 return this;
7081 } 7111 }
7082 7112
7083 7113
7084 Object* Map::GetPrototypeTransition(Object* prototype) { 7114 Object* Map::GetPrototypeTransition(Object* prototype) {
7085 FixedArray* cache = prototype_transitions(); 7115 FixedArray* cache = prototype_transitions();
7086 int capacity = cache->length(); 7116 int number_of_transitions = NumberOfProtoTransitions();
7087 if (capacity == 0) return NULL; 7117 const int proto_offset =
7088 int finger = Smi::cast(cache->get(0))->value(); 7118 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
7089 for (int i = 1; i < finger; i += 2) { 7119 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
7090 if (cache->get(i) == prototype) return cache->get(i + 1); 7120 const int step = kProtoTransitionElementsPerEntry;
7121 for (int i = 0; i < number_of_transitions; i++) {
7122 if (cache->get(proto_offset + i * step) == prototype) {
7123 Object* map = cache->get(map_offset + i * step);
7124 ASSERT(map->IsMap());
7125 return map;
7126 }
7091 } 7127 }
7092 return NULL; 7128 return NULL;
7093 } 7129 }
7094 7130
7095 7131
7096 MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { 7132 MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
7133 ASSERT(map->IsMap());
7134 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
7097 // Don't cache prototype transition if this map is shared. 7135 // Don't cache prototype transition if this map is shared.
7098 if (is_shared() || !FLAG_cache_prototype_transitions) return this; 7136 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
7099 7137
7100 FixedArray* cache = prototype_transitions(); 7138 FixedArray* cache = prototype_transitions();
7101 7139
7102 int capacity = cache->length(); 7140 const int step = kProtoTransitionElementsPerEntry;
7141 const int header = kProtoTransitionHeaderSize;
7103 7142
7104 int finger = (capacity == 0) ? 1 : Smi::cast(cache->get(0))->value(); 7143 int capacity = (cache->length() - header) / step;
7105 7144
7106 if (finger >= capacity) { 7145 int transitions = NumberOfProtoTransitions() + 1;
7146
7147 if (transitions > capacity) {
7107 if (capacity > kMaxCachedPrototypeTransitions) return this; 7148 if (capacity > kMaxCachedPrototypeTransitions) return this;
7108 7149
7109 FixedArray* new_cache; 7150 FixedArray* new_cache;
7110 { MaybeObject* maybe_cache = heap()->AllocateFixedArray(finger * 2 + 1); 7151 // Grow array by factor 2 over and above what we need.
7152 { MaybeObject* maybe_cache =
7153 heap()->AllocateFixedArray(transitions * 2 * step + header);
7111 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache; 7154 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
7112 } 7155 }
7113 7156
7114 for (int i = 1; i < capacity; i++) new_cache->set(i, cache->get(i)); 7157 for (int i = 0; i < capacity * step; i++) {
7158 new_cache->set(i + header, cache->get(i + header));
7159 }
7115 cache = new_cache; 7160 cache = new_cache;
7116 set_prototype_transitions(cache); 7161 set_prototype_transitions(cache);
7117 } 7162 }
7118 7163
7119 cache->set(finger, prototype); 7164 int last = transitions - 1;
7120 cache->set(finger + 1, map); 7165
7121 cache->set(0, Smi::FromInt(finger + 2)); 7166 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
7167 cache->set(header + last * step + kProtoTransitionMapOffset, map);
7168 SetNumberOfProtoTransitions(transitions);
7122 7169
7123 return cache; 7170 return cache;
7124 } 7171 }
7125 7172
7126 7173
7127 MaybeObject* JSReceiver::SetPrototype(Object* value, 7174 MaybeObject* JSReceiver::SetPrototype(Object* value,
7128 bool skip_hidden_prototypes) { 7175 bool skip_hidden_prototypes) {
7176 #ifdef DEBUG
7177 int size = Size();
7178 #endif
7179
7129 Heap* heap = GetHeap(); 7180 Heap* heap = GetHeap();
7130 // Silently ignore the change if value is not a JSObject or null. 7181 // Silently ignore the change if value is not a JSObject or null.
7131 // SpiderMonkey behaves this way. 7182 // SpiderMonkey behaves this way.
7132 if (!value->IsJSReceiver() && !value->IsNull()) return value; 7183 if (!value->IsJSReceiver() && !value->IsNull()) return value;
7133 7184
7134 // From 8.6.2 Object Internal Methods 7185 // From 8.6.2 Object Internal Methods
7135 // ... 7186 // ...
7136 // In addition, if [[Extensible]] is false the value of the [[Class]] and 7187 // In addition, if [[Extensible]] is false the value of the [[Class]] and
7137 // [[Prototype]] internal properties of the object may not be modified. 7188 // [[Prototype]] internal properties of the object may not be modified.
7138 // ... 7189 // ...
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
7189 map->PutPrototypeTransition(value, Map::cast(new_map)); 7240 map->PutPrototypeTransition(value, Map::cast(new_map));
7190 if (maybe_new_cache->IsFailure()) return maybe_new_cache; 7241 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7191 } 7242 }
7192 7243
7193 Map::cast(new_map)->set_prototype(value); 7244 Map::cast(new_map)->set_prototype(value);
7194 } 7245 }
7195 ASSERT(Map::cast(new_map)->prototype() == value); 7246 ASSERT(Map::cast(new_map)->prototype() == value);
7196 real_receiver->set_map(Map::cast(new_map)); 7247 real_receiver->set_map(Map::cast(new_map));
7197 7248
7198 heap->ClearInstanceofCache(); 7249 heap->ClearInstanceofCache();
7199 7250 ASSERT(size == Size());
7200 return value; 7251 return value;
7201 } 7252 }
7202 7253
7203 7254
7204 bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) { 7255 bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
7205 switch (GetElementsKind()) { 7256 switch (GetElementsKind()) {
7206 case FAST_ELEMENTS: { 7257 case FAST_ELEMENTS: {
7207 uint32_t length = IsJSArray() ? 7258 uint32_t length = IsJSArray() ?
7208 static_cast<uint32_t> 7259 static_cast<uint32_t>
7209 (Smi::cast(JSArray::cast(this)->length())->value()) : 7260 (Smi::cast(JSArray::cast(this)->length())->value()) :
(...skipping 3500 matching lines...) Expand 10 before | Expand all | Expand 10 after
10710 if (break_point_objects()->IsUndefined()) return 0; 10761 if (break_point_objects()->IsUndefined()) return 0;
10711 // Single beak point. 10762 // Single beak point.
10712 if (!break_point_objects()->IsFixedArray()) return 1; 10763 if (!break_point_objects()->IsFixedArray()) return 1;
10713 // Multiple break points. 10764 // Multiple break points.
10714 return FixedArray::cast(break_point_objects())->length(); 10765 return FixedArray::cast(break_point_objects())->length();
10715 } 10766 }
10716 #endif 10767 #endif
10717 10768
10718 10769
10719 } } // namespace v8::internal 10770 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698