OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <iomanip> | 5 #include <iomanip> |
6 #include <sstream> | 6 #include <sstream> |
7 | 7 |
8 #include "src/v8.h" | 8 #include "src/v8.h" |
9 | 9 |
10 #include "src/accessors.h" | 10 #include "src/accessors.h" |
(...skipping 1893 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1904 } | 1904 } |
1905 | 1905 |
1906 | 1906 |
1907 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, | 1907 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, |
1908 int expected_additional_properties) { | 1908 int expected_additional_properties) { |
1909 if (object->map() == *new_map) return; | 1909 if (object->map() == *new_map) return; |
1910 // If this object is a prototype (the callee will check), invalidate any | 1910 // If this object is a prototype (the callee will check), invalidate any |
1911 // prototype chains involving it. | 1911 // prototype chains involving it. |
1912 InvalidatePrototypeChains(object->map()); | 1912 InvalidatePrototypeChains(object->map()); |
1913 Handle<Map> old_map(object->map()); | 1913 Handle<Map> old_map(object->map()); |
| 1914 |
| 1915 // If the map was registered with its prototype before, ensure that it |
| 1916 // registers with its new prototype now. This preserves the invariant that |
| 1917 // when a map on a prototype chain is registered with its prototype, then |
| 1918 // all prototypes further up the chain are also registered with their |
| 1919 // respective prototypes. |
| 1920 Object* maybe_old_prototype = old_map->prototype(); |
| 1921 if (maybe_old_prototype->IsJSObject()) { |
| 1922 Handle<JSObject> old_prototype(JSObject::cast(maybe_old_prototype)); |
| 1923 bool was_registered = |
| 1924 JSObject::UnregisterPrototypeUser(old_prototype, old_map); |
| 1925 if (was_registered) { |
| 1926 JSObject::LazyRegisterPrototypeUser(new_map, new_map->GetIsolate()); |
| 1927 } |
| 1928 } |
| 1929 |
1914 if (object->HasFastProperties()) { | 1930 if (object->HasFastProperties()) { |
1915 if (!new_map->is_dictionary_map()) { | 1931 if (!new_map->is_dictionary_map()) { |
1916 MigrateFastToFast(object, new_map); | 1932 MigrateFastToFast(object, new_map); |
1917 if (old_map->is_prototype_map()) { | 1933 if (old_map->is_prototype_map()) { |
1918 // Clear out the old descriptor array to avoid problems to sharing | 1934 // Clear out the old descriptor array to avoid problems to sharing |
1919 // the descriptor array without using an explicit. | 1935 // the descriptor array without using an explicit. |
1920 old_map->InitializeDescriptors( | 1936 old_map->InitializeDescriptors( |
1921 old_map->GetHeap()->empty_descriptor_array(), | 1937 old_map->GetHeap()->empty_descriptor_array(), |
1922 LayoutDescriptor::FastPointerLayout()); | 1938 LayoutDescriptor::FastPointerLayout()); |
1923 // Ensure that no transition was inserted for prototype migrations. | 1939 // Ensure that no transition was inserted for prototype migrations. |
1924 DCHECK_EQ(0, TransitionArray::NumberOfTransitions( | 1940 DCHECK_EQ(0, TransitionArray::NumberOfTransitions( |
1925 old_map->raw_transitions())); | 1941 old_map->raw_transitions())); |
1926 DCHECK(new_map->GetBackPointer()->IsUndefined()); | 1942 DCHECK(new_map->GetBackPointer()->IsUndefined()); |
1927 } | 1943 } |
1928 } else { | 1944 } else { |
1929 MigrateFastToSlow(object, new_map, expected_additional_properties); | 1945 MigrateFastToSlow(object, new_map, expected_additional_properties); |
1930 } | 1946 } |
1931 } else { | 1947 } else { |
1932 // For slow-to-fast migrations JSObject::MigrateSlowToFast() | 1948 // For slow-to-fast migrations JSObject::MigrateSlowToFast() |
1933 // must be used instead. | 1949 // must be used instead. |
1934 CHECK(new_map->is_dictionary_map()); | 1950 CHECK(new_map->is_dictionary_map()); |
1935 | 1951 |
1936 // Slow-to-slow migration is trivial. | 1952 // Slow-to-slow migration is trivial. |
1937 object->set_map(*new_map); | 1953 object->set_map(*new_map); |
1938 } | 1954 } |
1939 if (old_map->is_prototype_map()) { | 1955 |
| 1956 // Careful: Don't allocate here! |
| 1957 // For some callers of this method, |object| might be in an inconsistent |
| 1958 // state now: the new map might have a new elements_kind, but the object's |
| 1959 // elements pointer hasn't been updated yet. Callers will fix this, but in |
| 1960 // the meantime, (indirectly) calling JSObjectVerify() must be avoided. |
| 1961 DisallowHeapAllocation no_object_verification; |
| 1962 |
| 1963 if (old_map->is_prototype_map() && FLAG_track_prototype_users) { |
1940 DCHECK(new_map->is_prototype_map()); | 1964 DCHECK(new_map->is_prototype_map()); |
1941 DCHECK(object->map() == *new_map); | 1965 DCHECK(object->map() == *new_map); |
1942 new_map->set_prototype_info(old_map->prototype_info()); | 1966 new_map->set_prototype_info(old_map->prototype_info()); |
1943 old_map->set_prototype_info(Smi::FromInt(0)); | 1967 old_map->set_prototype_info(Smi::FromInt(0)); |
1944 if (FLAG_trace_prototype_users) { | 1968 if (FLAG_trace_prototype_users) { |
1945 PrintF("Moving prototype_info %p from map %p to map %p.\n", | 1969 PrintF("Moving prototype_info %p from map %p to map %p.\n", |
1946 reinterpret_cast<void*>(new_map->prototype_info()), | 1970 reinterpret_cast<void*>(new_map->prototype_info()), |
1947 reinterpret_cast<void*>(*old_map), | 1971 reinterpret_cast<void*>(*old_map), |
1948 reinterpret_cast<void*>(*new_map)); | 1972 reinterpret_cast<void*>(*new_map)); |
1949 } | 1973 } |
(...skipping 5131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7081 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child, | 7105 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child, |
7082 Handle<Name> name, SimpleTransitionFlag flag) { | 7106 Handle<Name> name, SimpleTransitionFlag flag) { |
7083 parent->set_owns_descriptors(false); | 7107 parent->set_owns_descriptors(false); |
7084 if (parent->is_prototype_map()) { | 7108 if (parent->is_prototype_map()) { |
7085 DCHECK(child->is_prototype_map()); | 7109 DCHECK(child->is_prototype_map()); |
7086 #if TRACE_MAPS | 7110 #if TRACE_MAPS |
7087 Map::TraceTransition("NoTransition", *parent, *child, *name); | 7111 Map::TraceTransition("NoTransition", *parent, *child, *name); |
7088 #endif | 7112 #endif |
7089 } else { | 7113 } else { |
7090 TransitionArray::Insert(parent, name, child, flag); | 7114 TransitionArray::Insert(parent, name, child, flag); |
7091 if (child->prototype()->IsJSObject()) { | |
7092 Handle<JSObject> proto(JSObject::cast(child->prototype())); | |
7093 if (!ShouldRegisterAsPrototypeUser(child, proto)) { | |
7094 JSObject::UnregisterPrototypeUser(proto, child); | |
7095 } | |
7096 } | |
7097 #if TRACE_MAPS | 7115 #if TRACE_MAPS |
7098 Map::TraceTransition("Transition", *parent, *child, *name); | 7116 Map::TraceTransition("Transition", *parent, *child, *name); |
7099 #endif | 7117 #endif |
7100 } | 7118 } |
7101 } | 7119 } |
7102 | 7120 |
7103 | 7121 |
7104 Handle<Map> Map::CopyReplaceDescriptors( | 7122 Handle<Map> Map::CopyReplaceDescriptors( |
7105 Handle<Map> map, Handle<DescriptorArray> descriptors, | 7123 Handle<Map> map, Handle<DescriptorArray> descriptors, |
7106 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag, | 7124 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag, |
(...skipping 1144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8251 if (FLAG_trace_weak_arrays) { | 8269 if (FLAG_trace_weak_arrays) { |
8252 PrintF("[WeakFixedArray: storing at index %d ]\n", index); | 8270 PrintF("[WeakFixedArray: storing at index %d ]\n", index); |
8253 } | 8271 } |
8254 array->set_last_used_index(index); | 8272 array->set_last_used_index(index); |
8255 } | 8273 } |
8256 | 8274 |
8257 | 8275 |
8258 // static | 8276 // static |
8259 Handle<WeakFixedArray> WeakFixedArray::Add( | 8277 Handle<WeakFixedArray> WeakFixedArray::Add( |
8260 Handle<Object> maybe_array, Handle<HeapObject> value, | 8278 Handle<Object> maybe_array, Handle<HeapObject> value, |
8261 SearchForDuplicates search_for_duplicates) { | 8279 SearchForDuplicates search_for_duplicates, bool* was_present) { |
8262 Handle<WeakFixedArray> array = | 8280 Handle<WeakFixedArray> array = |
8263 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray()) | 8281 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray()) |
8264 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null()) | 8282 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null()) |
8265 : Handle<WeakFixedArray>::cast(maybe_array); | 8283 : Handle<WeakFixedArray>::cast(maybe_array); |
8266 | 8284 if (was_present != NULL) *was_present = false; |
8267 if (search_for_duplicates == kAddIfNotFound) { | 8285 if (search_for_duplicates == kAddIfNotFound) { |
8268 for (int i = 0; i < array->Length(); ++i) { | 8286 for (int i = 0; i < array->Length(); ++i) { |
8269 if (array->Get(i) == *value) return array; | 8287 if (array->Get(i) == *value) { |
| 8288 if (was_present != NULL) *was_present = true; |
| 8289 return array; |
| 8290 } |
8270 } | 8291 } |
8271 #if 0 // Enable this if you want to check your search_for_duplicates flags. | 8292 #if 0 // Enable this if you want to check your search_for_duplicates flags. |
8272 } else { | 8293 } else { |
8273 for (int i = 0; i < array->Length(); ++i) { | 8294 for (int i = 0; i < array->Length(); ++i) { |
8274 DCHECK_NE(*value, array->Get(i)); | 8295 DCHECK_NE(*value, array->Get(i)); |
8275 } | 8296 } |
8276 #endif | 8297 #endif |
8277 } | 8298 } |
8278 | 8299 |
8279 // Try to store the new entry if there's room. Optimize for consecutive | 8300 // Try to store the new entry if there's room. Optimize for consecutive |
8280 // accesses. | 8301 // accesses. |
8281 int first_index = array->last_used_index(); | 8302 int first_index = array->last_used_index(); |
8282 for (int i = first_index;;) { | 8303 if (array->Length() > 0) { |
8283 if (array->IsEmptySlot((i))) { | 8304 for (int i = first_index;;) { |
8284 WeakFixedArray::Set(array, i, value); | 8305 if (array->IsEmptySlot((i))) { |
8285 return array; | 8306 WeakFixedArray::Set(array, i, value); |
| 8307 return array; |
| 8308 } |
| 8309 if (FLAG_trace_weak_arrays) { |
| 8310 PrintF("[WeakFixedArray: searching for free slot]\n"); |
| 8311 } |
| 8312 i = (i + 1) % array->Length(); |
| 8313 if (i == first_index) break; |
8286 } | 8314 } |
8287 if (FLAG_trace_weak_arrays) { | |
8288 PrintF("[WeakFixedArray: searching for free slot]\n"); | |
8289 } | |
8290 i = (i + 1) % array->Length(); | |
8291 if (i == first_index) break; | |
8292 } | 8315 } |
8293 | 8316 |
8294 // No usable slot found, grow the array. | 8317 // No usable slot found, grow the array. |
8295 int new_length = array->Length() + (array->Length() >> 1) + 4; | 8318 int new_length = |
| 8319 array->Length() == 0 ? 1 : array->Length() + (array->Length() >> 1) + 4; |
8296 Handle<WeakFixedArray> new_array = | 8320 Handle<WeakFixedArray> new_array = |
8297 Allocate(array->GetIsolate(), new_length, array); | 8321 Allocate(array->GetIsolate(), new_length, array); |
8298 if (FLAG_trace_weak_arrays) { | 8322 if (FLAG_trace_weak_arrays) { |
8299 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length); | 8323 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length); |
8300 } | 8324 } |
8301 WeakFixedArray::Set(new_array, array->Length(), value); | 8325 WeakFixedArray::Set(new_array, array->Length(), value); |
8302 return new_array; | 8326 return new_array; |
8303 } | 8327 } |
8304 | 8328 |
8305 | 8329 |
8306 void WeakFixedArray::Compact() { | 8330 void WeakFixedArray::Compact() { |
8307 FixedArray* array = FixedArray::cast(this); | 8331 FixedArray* array = FixedArray::cast(this); |
8308 int new_length = kFirstIndex; | 8332 int new_length = kFirstIndex; |
8309 for (int i = kFirstIndex; i < array->length(); i++) { | 8333 for (int i = kFirstIndex; i < array->length(); i++) { |
8310 Object* element = array->get(i); | 8334 Object* element = array->get(i); |
8311 if (element->IsSmi()) continue; | 8335 if (element->IsSmi()) continue; |
8312 if (WeakCell::cast(element)->cleared()) continue; | 8336 if (WeakCell::cast(element)->cleared()) continue; |
8313 array->set(new_length++, element); | 8337 array->set(new_length++, element); |
8314 } | 8338 } |
8315 array->Shrink(new_length); | 8339 array->Shrink(new_length); |
8316 set_last_used_index(0); | 8340 set_last_used_index(0); |
8317 } | 8341 } |
8318 | 8342 |
8319 | 8343 |
8320 void WeakFixedArray::Remove(Handle<HeapObject> value) { | 8344 bool WeakFixedArray::Remove(Handle<HeapObject> value) { |
| 8345 if (Length() == 0) return false; |
8321 // Optimize for the most recently added element to be removed again. | 8346 // Optimize for the most recently added element to be removed again. |
8322 int first_index = last_used_index(); | 8347 int first_index = last_used_index(); |
8323 for (int i = first_index;;) { | 8348 for (int i = first_index;;) { |
8324 if (Get(i) == *value) { | 8349 if (Get(i) == *value) { |
8325 clear(i); | 8350 clear(i); |
8326 // Users of WeakFixedArray should make sure that there are no duplicates, | 8351 // Users of WeakFixedArray should make sure that there are no duplicates, |
8327 // they can use Add(..., kAddIfNotFound) if necessary. | 8352 // they can use Add(..., kAddIfNotFound) if necessary. |
8328 return; | 8353 return true; |
8329 } | 8354 } |
8330 i = (i + 1) % Length(); | 8355 i = (i + 1) % Length(); |
8331 if (i == first_index) break; | 8356 if (i == first_index) return false; |
8332 } | 8357 } |
| 8358 UNREACHABLE(); |
8333 } | 8359 } |
8334 | 8360 |
8335 | 8361 |
8336 // static | 8362 // static |
8337 Handle<WeakFixedArray> WeakFixedArray::Allocate( | 8363 Handle<WeakFixedArray> WeakFixedArray::Allocate( |
8338 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) { | 8364 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) { |
8339 DCHECK(0 <= size); | 8365 DCHECK(0 <= size); |
8340 Handle<FixedArray> result = | 8366 Handle<FixedArray> result = |
8341 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex); | 8367 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex); |
8342 Handle<WeakFixedArray> casted_result = Handle<WeakFixedArray>::cast(result); | 8368 Handle<WeakFixedArray> casted_result = Handle<WeakFixedArray>::cast(result); |
(...skipping 1712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10055 | 10081 |
10056 | 10082 |
10057 // static | 10083 // static |
10058 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { | 10084 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { |
10059 if (!object->map()->is_prototype_map()) return; | 10085 if (!object->map()->is_prototype_map()) return; |
10060 OptimizeAsPrototype(object, FAST_PROTOTYPE); | 10086 OptimizeAsPrototype(object, FAST_PROTOTYPE); |
10061 } | 10087 } |
10062 | 10088 |
10063 | 10089 |
10064 // static | 10090 // static |
10065 void JSObject::RegisterPrototypeUser(Handle<JSObject> prototype, | 10091 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) { |
10066 Handle<HeapObject> user) { | |
10067 DCHECK(FLAG_track_prototype_users); | 10092 DCHECK(FLAG_track_prototype_users); |
10068 Isolate* isolate = prototype->GetIsolate(); | 10093 // Contract: In line with InvalidatePrototypeChains()'s requirements, |
10069 if (prototype->IsJSGlobalProxy()) { | 10094 // leaf maps don't need to register as users, only prototypes do. |
10070 PrototypeIterator iter(isolate, prototype); | 10095 DCHECK(user->is_prototype_map()); |
10071 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | 10096 |
10072 } | 10097 Handle<Map> current_user = user; |
10073 Handle<PrototypeInfo> proto_info; | 10098 for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) { |
10074 Object* maybe_proto_info = prototype->map()->prototype_info(); | 10099 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter); |
10075 if (maybe_proto_info->IsPrototypeInfo()) { | 10100 if (maybe_proto->IsJSGlobalProxy()) continue; |
10076 proto_info = handle(PrototypeInfo::cast(maybe_proto_info), isolate); | 10101 // Proxies on the prototype chain are not supported. |
10077 } else { | 10102 if (maybe_proto->IsJSProxy()) return; |
10078 proto_info = isolate->factory()->NewPrototypeInfo(); | 10103 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto); |
10079 prototype->map()->set_prototype_info(*proto_info); | 10104 bool just_registered = |
10080 } | 10105 RegisterPrototypeUserIfNotRegistered(proto, current_user, isolate); |
10081 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate); | 10106 // Walk up the prototype chain as far as links haven't been registered yet. |
10082 Handle<WeakFixedArray> new_array = WeakFixedArray::Add(maybe_registry, user); | 10107 if (!just_registered) break; |
10083 if (!maybe_registry.is_identical_to(new_array)) { | 10108 current_user = handle(proto->map(), isolate); |
10084 proto_info->set_prototype_users(*new_array); | |
10085 } | |
10086 if (FLAG_trace_prototype_users) { | |
10087 PrintF("Registering %p as a user of prototype %p.\n", | |
10088 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype)); | |
10089 } | 10109 } |
10090 } | 10110 } |
10091 | 10111 |
10092 | 10112 |
| 10113 // Returns true if the user was not yet registered. |
10093 // static | 10114 // static |
10094 void JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype, | 10115 bool JSObject::RegisterPrototypeUserIfNotRegistered(Handle<JSObject> prototype, |
| 10116 Handle<HeapObject> user, |
| 10117 Isolate* isolate) { |
| 10118 Handle<PrototypeInfo> proto_info = |
| 10119 Map::GetOrCreatePrototypeInfo(prototype, isolate); |
| 10120 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate); |
| 10121 bool was_present = false; |
| 10122 Handle<WeakFixedArray> new_array = WeakFixedArray::Add( |
| 10123 maybe_registry, user, WeakFixedArray::kAddIfNotFound, &was_present); |
| 10124 if (!maybe_registry.is_identical_to(new_array)) { |
| 10125 proto_info->set_prototype_users(*new_array); |
| 10126 } |
| 10127 if (FLAG_trace_prototype_users && !was_present) { |
| 10128 PrintF("Registering %p as a user of prototype %p (map=%p).\n", |
| 10129 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype), |
| 10130 reinterpret_cast<void*>(prototype->map())); |
| 10131 } |
| 10132 return !was_present; |
| 10133 } |
| 10134 |
| 10135 |
| 10136 // Can be called regardless of whether |user| was actually registered with |
| 10137 // |prototype|. Returns true when there was a registration. |
| 10138 // static |
| 10139 bool JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype, |
10095 Handle<HeapObject> user) { | 10140 Handle<HeapObject> user) { |
10096 Isolate* isolate = prototype->GetIsolate(); | 10141 Isolate* isolate = prototype->GetIsolate(); |
10097 if (prototype->IsJSGlobalProxy()) { | 10142 if (prototype->IsJSGlobalProxy()) { |
10098 PrototypeIterator iter(isolate, prototype); | 10143 PrototypeIterator iter(isolate, prototype); |
10099 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | 10144 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
10100 } | 10145 } |
10101 DCHECK(prototype->map()->is_prototype_map()); | 10146 DCHECK(prototype->map()->is_prototype_map()); |
10102 Object* maybe_proto_info = prototype->map()->prototype_info(); | 10147 Object* maybe_proto_info = prototype->map()->prototype_info(); |
10103 if (!maybe_proto_info->IsPrototypeInfo()) return; | 10148 if (!maybe_proto_info->IsPrototypeInfo()) return false; |
10104 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), | 10149 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), |
10105 isolate); | 10150 isolate); |
10106 Object* maybe_registry = proto_info->prototype_users(); | 10151 Object* maybe_registry = proto_info->prototype_users(); |
10107 if (!maybe_registry->IsWeakFixedArray()) return; | 10152 if (!maybe_registry->IsWeakFixedArray()) return false; |
10108 WeakFixedArray::cast(maybe_registry)->Remove(user); | 10153 bool result = WeakFixedArray::cast(maybe_registry)->Remove(user); |
10109 if (FLAG_trace_prototype_users) { | 10154 if (FLAG_trace_prototype_users && result) { |
10110 PrintF("Unregistering %p as a user of prototype %p.\n", | 10155 PrintF("Unregistering %p as a user of prototype %p.\n", |
10111 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype)); | 10156 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype)); |
10112 } | 10157 } |
| 10158 return result; |
10113 } | 10159 } |
10114 | 10160 |
10115 | 10161 |
10116 static void InvalidatePrototypeChainsInternal(Map* map) { | 10162 static void InvalidatePrototypeChainsInternal(Map* map) { |
10117 if (!map->is_prototype_map()) return; | 10163 if (!map->is_prototype_map()) return; |
| 10164 if (FLAG_trace_prototype_users) { |
| 10165 PrintF("Invalidating prototype map %p 's cell\n", |
| 10166 reinterpret_cast<void*>(map)); |
| 10167 } |
10118 Object* maybe_proto_info = map->prototype_info(); | 10168 Object* maybe_proto_info = map->prototype_info(); |
10119 if (!maybe_proto_info->IsPrototypeInfo()) return; | 10169 if (!maybe_proto_info->IsPrototypeInfo()) return; |
10120 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info); | 10170 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info); |
10121 Object* maybe_cell = proto_info->validity_cell(); | 10171 Object* maybe_cell = proto_info->validity_cell(); |
10122 if (maybe_cell->IsCell()) { | 10172 if (maybe_cell->IsCell()) { |
10123 // Just set the value; the cell will be replaced lazily. | 10173 // Just set the value; the cell will be replaced lazily. |
10124 Cell* cell = Cell::cast(maybe_cell); | 10174 Cell* cell = Cell::cast(maybe_cell); |
10125 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid)); | 10175 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid)); |
10126 } | 10176 } |
10127 | 10177 |
(...skipping 19 matching lines...) Expand all Loading... |
10147 DisallowHeapAllocation no_gc; | 10197 DisallowHeapAllocation no_gc; |
10148 if (map->IsJSGlobalProxyMap()) { | 10198 if (map->IsJSGlobalProxyMap()) { |
10149 PrototypeIterator iter(map); | 10199 PrototypeIterator iter(map); |
10150 map = JSObject::cast(iter.GetCurrent())->map(); | 10200 map = JSObject::cast(iter.GetCurrent())->map(); |
10151 } | 10201 } |
10152 InvalidatePrototypeChainsInternal(map); | 10202 InvalidatePrototypeChainsInternal(map); |
10153 } | 10203 } |
10154 | 10204 |
10155 | 10205 |
10156 // static | 10206 // static |
| 10207 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype, |
| 10208 Isolate* isolate) { |
| 10209 Object* maybe_proto_info = prototype->map()->prototype_info(); |
| 10210 if (maybe_proto_info->IsPrototypeInfo()) { |
| 10211 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); |
| 10212 } |
| 10213 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); |
| 10214 prototype->map()->set_prototype_info(*proto_info); |
| 10215 return proto_info; |
| 10216 } |
| 10217 |
| 10218 |
| 10219 // static |
10157 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, | 10220 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, |
10158 Isolate* isolate) { | 10221 Isolate* isolate) { |
10159 Handle<Object> maybe_prototype(map->prototype(), isolate); | 10222 Handle<Object> maybe_prototype(map->prototype(), isolate); |
10160 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null(); | 10223 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null(); |
10161 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); | 10224 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); |
10162 if (prototype->IsJSGlobalProxy()) { | 10225 if (prototype->IsJSGlobalProxy()) { |
10163 PrototypeIterator iter(isolate, prototype); | 10226 PrototypeIterator iter(isolate, prototype); |
10164 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | 10227 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
10165 } | 10228 } |
10166 Handle<PrototypeInfo> proto_info( | 10229 // Ensure the prototype is registered with its own prototypes so its cell |
10167 PrototypeInfo::cast(prototype->map()->prototype_info()), isolate); | 10230 // will be invalidated when necessary. |
| 10231 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate), |
| 10232 isolate); |
| 10233 Handle<PrototypeInfo> proto_info = |
| 10234 GetOrCreatePrototypeInfo(prototype, isolate); |
10168 Object* maybe_cell = proto_info->validity_cell(); | 10235 Object* maybe_cell = proto_info->validity_cell(); |
10169 // Return existing cell if it's still valid. | 10236 // Return existing cell if it's still valid. |
10170 if (maybe_cell->IsCell()) { | 10237 if (maybe_cell->IsCell()) { |
10171 Handle<Cell> cell(Cell::cast(maybe_cell), isolate); | 10238 Handle<Cell> cell(Cell::cast(maybe_cell), isolate); |
10172 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) { | 10239 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) { |
10173 return handle(Cell::cast(maybe_cell), isolate); | 10240 return cell; |
10174 } | 10241 } |
10175 } | 10242 } |
10176 // Otherwise create a new cell. | 10243 // Otherwise create a new cell. |
10177 Handle<Cell> cell = isolate->factory()->NewCell( | 10244 Handle<Cell> cell = isolate->factory()->NewCell( |
10178 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate)); | 10245 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate)); |
10179 proto_info->set_validity_cell(*cell); | 10246 proto_info->set_validity_cell(*cell); |
10180 return cell; | 10247 return cell; |
10181 } | 10248 } |
10182 | 10249 |
10183 | 10250 |
| 10251 // static |
10184 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype, | 10252 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype, |
10185 PrototypeOptimizationMode proto_mode) { | 10253 PrototypeOptimizationMode proto_mode) { |
10186 if (map->prototype()->IsJSObject() && FLAG_track_prototype_users) { | |
10187 Handle<JSObject> old_prototype(JSObject::cast(map->prototype())); | |
10188 JSObject::UnregisterPrototypeUser(old_prototype, map); | |
10189 } | |
10190 if (prototype->IsJSObject()) { | 10254 if (prototype->IsJSObject()) { |
10191 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); | 10255 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); |
10192 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); | 10256 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); |
10193 if (ShouldRegisterAsPrototypeUser(map, prototype_jsobj)) { | |
10194 JSObject::RegisterPrototypeUser(prototype_jsobj, map); | |
10195 } | |
10196 } | 10257 } |
10197 WriteBarrierMode wb_mode = | 10258 WriteBarrierMode wb_mode = |
10198 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; | 10259 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; |
10199 map->set_prototype(*prototype, wb_mode); | 10260 map->set_prototype(*prototype, wb_mode); |
10200 } | 10261 } |
10201 | 10262 |
10202 | 10263 |
10203 // static | |
10204 bool Map::ShouldRegisterAsPrototypeUser(Handle<Map> map, | |
10205 Handle<JSObject> prototype) { | |
10206 if (!FLAG_track_prototype_users) return false; | |
10207 if (map->is_prototype_map()) return true; | |
10208 Object* back = map->GetBackPointer(); | |
10209 if (!back->IsMap()) return true; | |
10210 if (Map::cast(back)->prototype() != *prototype) return true; | |
10211 return false; | |
10212 } | |
10213 | |
10214 | |
10215 Handle<Object> CacheInitialJSArrayMaps( | 10264 Handle<Object> CacheInitialJSArrayMaps( |
10216 Handle<Context> native_context, Handle<Map> initial_map) { | 10265 Handle<Context> native_context, Handle<Map> initial_map) { |
10217 // Replace all of the cached initial array maps in the native context with | 10266 // Replace all of the cached initial array maps in the native context with |
10218 // the appropriate transitioned elements kind maps. | 10267 // the appropriate transitioned elements kind maps. |
10219 Factory* factory = native_context->GetIsolate()->factory(); | 10268 Factory* factory = native_context->GetIsolate()->factory(); |
10220 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles( | 10269 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles( |
10221 kElementsKindCount, TENURED); | 10270 kElementsKindCount, TENURED); |
10222 | 10271 |
10223 Handle<Map> current_map = initial_map; | 10272 Handle<Map> current_map = initial_map; |
10224 ElementsKind kind = current_map->elements_kind(); | 10273 ElementsKind kind = current_map->elements_kind(); |
(...skipping 6898 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17123 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell, | 17172 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell, |
17124 Handle<Object> new_value) { | 17173 Handle<Object> new_value) { |
17125 if (cell->value() != *new_value) { | 17174 if (cell->value() != *new_value) { |
17126 cell->set_value(*new_value); | 17175 cell->set_value(*new_value); |
17127 Isolate* isolate = cell->GetIsolate(); | 17176 Isolate* isolate = cell->GetIsolate(); |
17128 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 17177 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
17129 isolate, DependentCode::kPropertyCellChangedGroup); | 17178 isolate, DependentCode::kPropertyCellChangedGroup); |
17130 } | 17179 } |
17131 } | 17180 } |
17132 } } // namespace v8::internal | 17181 } } // namespace v8::internal |
OLD | NEW |