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 1918 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1929 MigrateFastToSlow(object, new_map, expected_additional_properties); | 1929 MigrateFastToSlow(object, new_map, expected_additional_properties); |
1930 } | 1930 } |
1931 } else { | 1931 } else { |
1932 // For slow-to-fast migrations JSObject::MigrateSlowToFast() | 1932 // For slow-to-fast migrations JSObject::MigrateSlowToFast() |
1933 // must be used instead. | 1933 // must be used instead. |
1934 CHECK(new_map->is_dictionary_map()); | 1934 CHECK(new_map->is_dictionary_map()); |
1935 | 1935 |
1936 // Slow-to-slow migration is trivial. | 1936 // Slow-to-slow migration is trivial. |
1937 object->set_map(*new_map); | 1937 object->set_map(*new_map); |
1938 } | 1938 } |
1939 if (old_map->is_prototype_map() && FLAG_track_prototype_users) { | 1939 if (old_map->is_prototype_map()) { |
1940 DCHECK(new_map->is_prototype_map()); | 1940 DCHECK(new_map->is_prototype_map()); |
1941 DCHECK(object->map() == *new_map); | 1941 DCHECK(object->map() == *new_map); |
1942 new_map->set_prototype_info(old_map->prototype_info()); | 1942 new_map->set_prototype_info(old_map->prototype_info()); |
1943 old_map->set_prototype_info(Smi::FromInt(0)); | 1943 old_map->set_prototype_info(Smi::FromInt(0)); |
1944 if (FLAG_trace_prototype_users) { | 1944 if (FLAG_trace_prototype_users) { |
1945 PrintF("Moving prototype_info %p from map %p to map %p.\n", | 1945 PrintF("Moving prototype_info %p from map %p to map %p.\n", |
1946 reinterpret_cast<void*>(new_map->prototype_info()), | 1946 reinterpret_cast<void*>(new_map->prototype_info()), |
1947 reinterpret_cast<void*>(*old_map), | 1947 reinterpret_cast<void*>(*old_map), |
1948 reinterpret_cast<void*>(*new_map)); | 1948 reinterpret_cast<void*>(*new_map)); |
1949 } | 1949 } |
1950 // If the map was registered with its prototype before, ensure that it | |
1951 // registers with its new prototype now. This preserves the invariant that | |
1952 // when a map on a prototype chain is registered with its prototype, then | |
1953 // all prototypes further up the chain are also registered with their | |
1954 // respective prototypes. | |
1955 Object* maybe_old_prototype = old_map->prototype(); | |
1956 if (maybe_old_prototype->IsJSObject()) { | |
1957 Handle<JSObject> old_prototype(JSObject::cast(maybe_old_prototype)); | |
1958 bool was_registered = | |
1959 JSObject::UnregisterPrototypeUser(old_prototype, old_map); | |
1960 if (was_registered) { | |
1961 JSObject::LazyRegisterPrototypeUser(new_map, new_map->GetIsolate()); | |
1962 } | |
1963 } | |
1964 } | 1950 } |
1965 } | 1951 } |
1966 | 1952 |
1967 | 1953 |
1968 // To migrate a fast instance to a fast map: | 1954 // To migrate a fast instance to a fast map: |
1969 // - First check whether the instance needs to be rewritten. If not, simply | 1955 // - First check whether the instance needs to be rewritten. If not, simply |
1970 // change the map. | 1956 // change the map. |
1971 // - Otherwise, allocate a fixed array large enough to hold all fields, in | 1957 // - Otherwise, allocate a fixed array large enough to hold all fields, in |
1972 // addition to unused space. | 1958 // addition to unused space. |
1973 // - Copy all existing properties in, in the following order: backing store | 1959 // - Copy all existing properties in, in the following order: backing store |
(...skipping 5119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7093 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child, | 7079 void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child, |
7094 Handle<Name> name, SimpleTransitionFlag flag) { | 7080 Handle<Name> name, SimpleTransitionFlag flag) { |
7095 parent->set_owns_descriptors(false); | 7081 parent->set_owns_descriptors(false); |
7096 if (parent->is_prototype_map()) { | 7082 if (parent->is_prototype_map()) { |
7097 DCHECK(child->is_prototype_map()); | 7083 DCHECK(child->is_prototype_map()); |
7098 #if TRACE_MAPS | 7084 #if TRACE_MAPS |
7099 Map::TraceTransition("NoTransition", *parent, *child, *name); | 7085 Map::TraceTransition("NoTransition", *parent, *child, *name); |
7100 #endif | 7086 #endif |
7101 } else { | 7087 } else { |
7102 TransitionArray::Insert(parent, name, child, flag); | 7088 TransitionArray::Insert(parent, name, child, flag); |
| 7089 if (child->prototype()->IsJSObject()) { |
| 7090 Handle<JSObject> proto(JSObject::cast(child->prototype())); |
| 7091 if (!ShouldRegisterAsPrototypeUser(child, proto)) { |
| 7092 JSObject::UnregisterPrototypeUser(proto, child); |
| 7093 } |
| 7094 } |
7103 #if TRACE_MAPS | 7095 #if TRACE_MAPS |
7104 Map::TraceTransition("Transition", *parent, *child, *name); | 7096 Map::TraceTransition("Transition", *parent, *child, *name); |
7105 #endif | 7097 #endif |
7106 } | 7098 } |
7107 } | 7099 } |
7108 | 7100 |
7109 | 7101 |
7110 Handle<Map> Map::CopyReplaceDescriptors( | 7102 Handle<Map> Map::CopyReplaceDescriptors( |
7111 Handle<Map> map, Handle<DescriptorArray> descriptors, | 7103 Handle<Map> map, Handle<DescriptorArray> descriptors, |
7112 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag, | 7104 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag, |
(...skipping 1144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8257 if (FLAG_trace_weak_arrays) { | 8249 if (FLAG_trace_weak_arrays) { |
8258 PrintF("[WeakFixedArray: storing at index %d ]\n", index); | 8250 PrintF("[WeakFixedArray: storing at index %d ]\n", index); |
8259 } | 8251 } |
8260 array->set_last_used_index(index); | 8252 array->set_last_used_index(index); |
8261 } | 8253 } |
8262 | 8254 |
8263 | 8255 |
8264 // static | 8256 // static |
8265 Handle<WeakFixedArray> WeakFixedArray::Add( | 8257 Handle<WeakFixedArray> WeakFixedArray::Add( |
8266 Handle<Object> maybe_array, Handle<HeapObject> value, | 8258 Handle<Object> maybe_array, Handle<HeapObject> value, |
8267 SearchForDuplicates search_for_duplicates, bool* was_present) { | 8259 SearchForDuplicates search_for_duplicates) { |
8268 Handle<WeakFixedArray> array = | 8260 Handle<WeakFixedArray> array = |
8269 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray()) | 8261 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray()) |
8270 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null()) | 8262 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null()) |
8271 : Handle<WeakFixedArray>::cast(maybe_array); | 8263 : Handle<WeakFixedArray>::cast(maybe_array); |
8272 if (was_present != NULL) *was_present = false; | 8264 |
8273 if (search_for_duplicates == kAddIfNotFound) { | 8265 if (search_for_duplicates == kAddIfNotFound) { |
8274 for (int i = 0; i < array->Length(); ++i) { | 8266 for (int i = 0; i < array->Length(); ++i) { |
8275 if (array->Get(i) == *value) { | 8267 if (array->Get(i) == *value) return array; |
8276 if (was_present != NULL) *was_present = true; | |
8277 return array; | |
8278 } | |
8279 } | 8268 } |
8280 #if 0 // Enable this if you want to check your search_for_duplicates flags. | 8269 #if 0 // Enable this if you want to check your search_for_duplicates flags. |
8281 } else { | 8270 } else { |
8282 for (int i = 0; i < array->Length(); ++i) { | 8271 for (int i = 0; i < array->Length(); ++i) { |
8283 DCHECK_NE(*value, array->Get(i)); | 8272 DCHECK_NE(*value, array->Get(i)); |
8284 } | 8273 } |
8285 #endif | 8274 #endif |
8286 } | 8275 } |
8287 | 8276 |
8288 // Try to store the new entry if there's room. Optimize for consecutive | 8277 // Try to store the new entry if there's room. Optimize for consecutive |
8289 // accesses. | 8278 // accesses. |
8290 int first_index = array->last_used_index(); | 8279 int first_index = array->last_used_index(); |
8291 if (array->Length() > 0) { | 8280 for (int i = first_index;;) { |
8292 for (int i = first_index;;) { | 8281 if (array->IsEmptySlot((i))) { |
8293 if (array->IsEmptySlot((i))) { | 8282 WeakFixedArray::Set(array, i, value); |
8294 WeakFixedArray::Set(array, i, value); | 8283 return array; |
8295 return array; | |
8296 } | |
8297 if (FLAG_trace_weak_arrays) { | |
8298 PrintF("[WeakFixedArray: searching for free slot]\n"); | |
8299 } | |
8300 i = (i + 1) % array->Length(); | |
8301 if (i == first_index) break; | |
8302 } | 8284 } |
| 8285 if (FLAG_trace_weak_arrays) { |
| 8286 PrintF("[WeakFixedArray: searching for free slot]\n"); |
| 8287 } |
| 8288 i = (i + 1) % array->Length(); |
| 8289 if (i == first_index) break; |
8303 } | 8290 } |
8304 | 8291 |
8305 // No usable slot found, grow the array. | 8292 // No usable slot found, grow the array. |
8306 int new_length = | 8293 int new_length = array->Length() + (array->Length() >> 1) + 4; |
8307 array->Length() == 0 ? 1 : array->Length() + (array->Length() >> 1) + 4; | |
8308 Handle<WeakFixedArray> new_array = | 8294 Handle<WeakFixedArray> new_array = |
8309 Allocate(array->GetIsolate(), new_length, array); | 8295 Allocate(array->GetIsolate(), new_length, array); |
8310 if (FLAG_trace_weak_arrays) { | 8296 if (FLAG_trace_weak_arrays) { |
8311 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length); | 8297 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length); |
8312 } | 8298 } |
8313 WeakFixedArray::Set(new_array, array->Length(), value); | 8299 WeakFixedArray::Set(new_array, array->Length(), value); |
8314 return new_array; | 8300 return new_array; |
8315 } | 8301 } |
8316 | 8302 |
8317 | 8303 |
8318 void WeakFixedArray::Compact() { | 8304 void WeakFixedArray::Compact() { |
8319 FixedArray* array = FixedArray::cast(this); | 8305 FixedArray* array = FixedArray::cast(this); |
8320 int new_length = kFirstIndex; | 8306 int new_length = kFirstIndex; |
8321 for (int i = kFirstIndex; i < array->length(); i++) { | 8307 for (int i = kFirstIndex; i < array->length(); i++) { |
8322 Object* element = array->get(i); | 8308 Object* element = array->get(i); |
8323 if (element->IsSmi()) continue; | 8309 if (element->IsSmi()) continue; |
8324 if (WeakCell::cast(element)->cleared()) continue; | 8310 if (WeakCell::cast(element)->cleared()) continue; |
8325 array->set(new_length++, element); | 8311 array->set(new_length++, element); |
8326 } | 8312 } |
8327 array->Shrink(new_length); | 8313 array->Shrink(new_length); |
8328 set_last_used_index(0); | 8314 set_last_used_index(0); |
8329 } | 8315 } |
8330 | 8316 |
8331 | 8317 |
8332 bool WeakFixedArray::Remove(Handle<HeapObject> value) { | 8318 void WeakFixedArray::Remove(Handle<HeapObject> value) { |
8333 if (Length() == 0) return false; | |
8334 // Optimize for the most recently added element to be removed again. | 8319 // Optimize for the most recently added element to be removed again. |
8335 int first_index = last_used_index(); | 8320 int first_index = last_used_index(); |
8336 for (int i = first_index;;) { | 8321 for (int i = first_index;;) { |
8337 if (Get(i) == *value) { | 8322 if (Get(i) == *value) { |
8338 clear(i); | 8323 clear(i); |
8339 // Users of WeakFixedArray should make sure that there are no duplicates, | 8324 // Users of WeakFixedArray should make sure that there are no duplicates, |
8340 // they can use Add(..., kAddIfNotFound) if necessary. | 8325 // they can use Add(..., kAddIfNotFound) if necessary. |
8341 return true; | 8326 return; |
8342 } | 8327 } |
8343 i = (i + 1) % Length(); | 8328 i = (i + 1) % Length(); |
8344 if (i == first_index) return false; | 8329 if (i == first_index) break; |
8345 } | 8330 } |
8346 UNREACHABLE(); | |
8347 } | 8331 } |
8348 | 8332 |
8349 | 8333 |
8350 // static | 8334 // static |
8351 Handle<WeakFixedArray> WeakFixedArray::Allocate( | 8335 Handle<WeakFixedArray> WeakFixedArray::Allocate( |
8352 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) { | 8336 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) { |
8353 DCHECK(0 <= size); | 8337 DCHECK(0 <= size); |
8354 Handle<FixedArray> result = | 8338 Handle<FixedArray> result = |
8355 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex); | 8339 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex); |
8356 Handle<WeakFixedArray> casted_result = Handle<WeakFixedArray>::cast(result); | 8340 Handle<WeakFixedArray> casted_result = Handle<WeakFixedArray>::cast(result); |
(...skipping 1712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10069 | 10053 |
10070 | 10054 |
10071 // static | 10055 // static |
10072 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { | 10056 void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) { |
10073 if (!object->map()->is_prototype_map()) return; | 10057 if (!object->map()->is_prototype_map()) return; |
10074 OptimizeAsPrototype(object, FAST_PROTOTYPE); | 10058 OptimizeAsPrototype(object, FAST_PROTOTYPE); |
10075 } | 10059 } |
10076 | 10060 |
10077 | 10061 |
10078 // static | 10062 // static |
10079 void JSObject::LazyRegisterPrototypeUser(Handle<Map> user, Isolate* isolate) { | 10063 void JSObject::RegisterPrototypeUser(Handle<JSObject> prototype, |
| 10064 Handle<HeapObject> user) { |
10080 DCHECK(FLAG_track_prototype_users); | 10065 DCHECK(FLAG_track_prototype_users); |
10081 // Contract: In line with InvalidatePrototypeChains()'s requirements, | 10066 Isolate* isolate = prototype->GetIsolate(); |
10082 // leaf maps don't need to register as users, only prototypes do. | 10067 if (prototype->IsJSGlobalProxy()) { |
10083 DCHECK(user->is_prototype_map()); | 10068 PrototypeIterator iter(isolate, prototype); |
10084 | 10069 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
10085 Handle<Map> current_user = user; | 10070 } |
10086 for (PrototypeIterator iter(user); !iter.IsAtEnd(); iter.Advance()) { | 10071 Handle<PrototypeInfo> proto_info; |
10087 Handle<Object> maybe_proto = PrototypeIterator::GetCurrent(iter); | 10072 Object* maybe_proto_info = prototype->map()->prototype_info(); |
10088 if (maybe_proto->IsJSGlobalProxy()) continue; | 10073 if (maybe_proto_info->IsPrototypeInfo()) { |
10089 // Proxies on the prototype chain are not supported. | 10074 proto_info = handle(PrototypeInfo::cast(maybe_proto_info), isolate); |
10090 if (maybe_proto->IsJSProxy()) return; | 10075 } else { |
10091 Handle<JSObject> proto = Handle<JSObject>::cast(maybe_proto); | 10076 proto_info = isolate->factory()->NewPrototypeInfo(); |
10092 bool just_registered = | 10077 prototype->map()->set_prototype_info(*proto_info); |
10093 RegisterPrototypeUserIfNotRegistered(proto, current_user, isolate); | 10078 } |
10094 // Walk up the prototype chain as far as links haven't been registered yet. | 10079 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate); |
10095 if (!just_registered) break; | 10080 Handle<WeakFixedArray> new_array = WeakFixedArray::Add(maybe_registry, user); |
10096 current_user = handle(proto->map(), isolate); | 10081 if (!maybe_registry.is_identical_to(new_array)) { |
| 10082 proto_info->set_prototype_users(*new_array); |
| 10083 } |
| 10084 if (FLAG_trace_prototype_users) { |
| 10085 PrintF("Registering %p as a user of prototype %p.\n", |
| 10086 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype)); |
10097 } | 10087 } |
10098 } | 10088 } |
10099 | 10089 |
10100 | 10090 |
10101 // Returns true if the user was not yet registered. | |
10102 // static | 10091 // static |
10103 bool JSObject::RegisterPrototypeUserIfNotRegistered(Handle<JSObject> prototype, | 10092 void JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype, |
10104 Handle<HeapObject> user, | |
10105 Isolate* isolate) { | |
10106 Handle<PrototypeInfo> proto_info = | |
10107 Map::GetOrCreatePrototypeInfo(prototype, isolate); | |
10108 Handle<Object> maybe_registry(proto_info->prototype_users(), isolate); | |
10109 bool was_present = false; | |
10110 Handle<WeakFixedArray> new_array = WeakFixedArray::Add( | |
10111 maybe_registry, user, WeakFixedArray::kAddIfNotFound, &was_present); | |
10112 if (!maybe_registry.is_identical_to(new_array)) { | |
10113 proto_info->set_prototype_users(*new_array); | |
10114 } | |
10115 if (FLAG_trace_prototype_users && !was_present) { | |
10116 PrintF("Registering %p as a user of prototype %p (map=%p).\n", | |
10117 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype), | |
10118 reinterpret_cast<void*>(prototype->map())); | |
10119 } | |
10120 return !was_present; | |
10121 } | |
10122 | |
10123 | |
10124 // Can be called regardless of whether |user| was actually registered with | |
10125 // |prototype|. Returns true when there was a registration. | |
10126 // static | |
10127 bool JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype, | |
10128 Handle<HeapObject> user) { | 10093 Handle<HeapObject> user) { |
10129 Isolate* isolate = prototype->GetIsolate(); | 10094 Isolate* isolate = prototype->GetIsolate(); |
10130 if (prototype->IsJSGlobalProxy()) { | 10095 if (prototype->IsJSGlobalProxy()) { |
10131 PrototypeIterator iter(isolate, prototype); | 10096 PrototypeIterator iter(isolate, prototype); |
10132 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | 10097 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
10133 } | 10098 } |
10134 DCHECK(prototype->map()->is_prototype_map()); | 10099 DCHECK(prototype->map()->is_prototype_map()); |
10135 Object* maybe_proto_info = prototype->map()->prototype_info(); | 10100 Object* maybe_proto_info = prototype->map()->prototype_info(); |
10136 if (!maybe_proto_info->IsPrototypeInfo()) return false; | 10101 if (!maybe_proto_info->IsPrototypeInfo()) return; |
10137 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), | 10102 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), |
10138 isolate); | 10103 isolate); |
10139 Object* maybe_registry = proto_info->prototype_users(); | 10104 Object* maybe_registry = proto_info->prototype_users(); |
10140 if (!maybe_registry->IsWeakFixedArray()) return false; | 10105 if (!maybe_registry->IsWeakFixedArray()) return; |
10141 bool result = WeakFixedArray::cast(maybe_registry)->Remove(user); | 10106 WeakFixedArray::cast(maybe_registry)->Remove(user); |
10142 if (FLAG_trace_prototype_users && result) { | 10107 if (FLAG_trace_prototype_users) { |
10143 PrintF("Unregistering %p as a user of prototype %p.\n", | 10108 PrintF("Unregistering %p as a user of prototype %p.\n", |
10144 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype)); | 10109 reinterpret_cast<void*>(*user), reinterpret_cast<void*>(*prototype)); |
10145 } | 10110 } |
10146 return result; | |
10147 } | 10111 } |
10148 | 10112 |
10149 | 10113 |
10150 static void InvalidatePrototypeChainsInternal(Map* map) { | 10114 static void InvalidatePrototypeChainsInternal(Map* map) { |
10151 if (!map->is_prototype_map()) return; | 10115 if (!map->is_prototype_map()) return; |
10152 if (FLAG_trace_prototype_users) { | |
10153 PrintF("Invalidating prototype map %p 's cell\n", | |
10154 reinterpret_cast<void*>(map)); | |
10155 } | |
10156 Object* maybe_proto_info = map->prototype_info(); | 10116 Object* maybe_proto_info = map->prototype_info(); |
10157 if (!maybe_proto_info->IsPrototypeInfo()) return; | 10117 if (!maybe_proto_info->IsPrototypeInfo()) return; |
10158 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info); | 10118 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info); |
10159 Object* maybe_cell = proto_info->validity_cell(); | 10119 Object* maybe_cell = proto_info->validity_cell(); |
10160 if (maybe_cell->IsCell()) { | 10120 if (maybe_cell->IsCell()) { |
10161 // Just set the value; the cell will be replaced lazily. | 10121 // Just set the value; the cell will be replaced lazily. |
10162 Cell* cell = Cell::cast(maybe_cell); | 10122 Cell* cell = Cell::cast(maybe_cell); |
10163 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid)); | 10123 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid)); |
10164 } | 10124 } |
10165 | 10125 |
(...skipping 18 matching lines...) Expand all Loading... |
10184 if (!FLAG_eliminate_prototype_chain_checks) return; | 10144 if (!FLAG_eliminate_prototype_chain_checks) return; |
10185 DisallowHeapAllocation no_gc; | 10145 DisallowHeapAllocation no_gc; |
10186 if (map->IsJSGlobalProxyMap()) { | 10146 if (map->IsJSGlobalProxyMap()) { |
10187 PrototypeIterator iter(map); | 10147 PrototypeIterator iter(map); |
10188 map = JSObject::cast(iter.GetCurrent())->map(); | 10148 map = JSObject::cast(iter.GetCurrent())->map(); |
10189 } | 10149 } |
10190 InvalidatePrototypeChainsInternal(map); | 10150 InvalidatePrototypeChainsInternal(map); |
10191 } | 10151 } |
10192 | 10152 |
10193 | 10153 |
10194 // static | |
10195 Handle<PrototypeInfo> Map::GetOrCreatePrototypeInfo(Handle<JSObject> prototype, | |
10196 Isolate* isolate) { | |
10197 Object* maybe_proto_info = prototype->map()->prototype_info(); | |
10198 if (maybe_proto_info->IsPrototypeInfo()) { | |
10199 return handle(PrototypeInfo::cast(maybe_proto_info), isolate); | |
10200 } | |
10201 Handle<PrototypeInfo> proto_info = isolate->factory()->NewPrototypeInfo(); | |
10202 prototype->map()->set_prototype_info(*proto_info); | |
10203 return proto_info; | |
10204 } | |
10205 | |
10206 | |
10207 // static | 10154 // static |
10208 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, | 10155 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, |
10209 Isolate* isolate) { | 10156 Isolate* isolate) { |
10210 Handle<Object> maybe_prototype(map->prototype(), isolate); | 10157 Handle<Object> maybe_prototype(map->prototype(), isolate); |
10211 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null(); | 10158 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null(); |
10212 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); | 10159 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); |
10213 if (prototype->IsJSGlobalProxy()) { | 10160 if (prototype->IsJSGlobalProxy()) { |
10214 PrototypeIterator iter(isolate, prototype); | 10161 PrototypeIterator iter(isolate, prototype); |
10215 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | 10162 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
10216 } | 10163 } |
10217 // Ensure the prototype is registered with its own prototypes so its cell | 10164 Handle<PrototypeInfo> proto_info( |
10218 // will be invalidated when necessary. | 10165 PrototypeInfo::cast(prototype->map()->prototype_info()), isolate); |
10219 JSObject::LazyRegisterPrototypeUser(handle(prototype->map(), isolate), | |
10220 isolate); | |
10221 Handle<PrototypeInfo> proto_info = | |
10222 GetOrCreatePrototypeInfo(prototype, isolate); | |
10223 Object* maybe_cell = proto_info->validity_cell(); | 10166 Object* maybe_cell = proto_info->validity_cell(); |
10224 // Return existing cell if it's still valid. | 10167 // Return existing cell if it's still valid. |
10225 if (maybe_cell->IsCell()) { | 10168 if (maybe_cell->IsCell()) { |
10226 Handle<Cell> cell(Cell::cast(maybe_cell), isolate); | 10169 Handle<Cell> cell(Cell::cast(maybe_cell), isolate); |
10227 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) { | 10170 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) { |
10228 return cell; | 10171 return handle(Cell::cast(maybe_cell), isolate); |
10229 } | 10172 } |
10230 } | 10173 } |
10231 // Otherwise create a new cell. | 10174 // Otherwise create a new cell. |
10232 Handle<Cell> cell = isolate->factory()->NewCell( | 10175 Handle<Cell> cell = isolate->factory()->NewCell( |
10233 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate)); | 10176 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate)); |
10234 proto_info->set_validity_cell(*cell); | 10177 proto_info->set_validity_cell(*cell); |
10235 return cell; | 10178 return cell; |
10236 } | 10179 } |
10237 | 10180 |
10238 | 10181 |
10239 // static | |
10240 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype, | 10182 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype, |
10241 PrototypeOptimizationMode proto_mode) { | 10183 PrototypeOptimizationMode proto_mode) { |
| 10184 if (map->prototype()->IsJSObject() && FLAG_track_prototype_users) { |
| 10185 Handle<JSObject> old_prototype(JSObject::cast(map->prototype())); |
| 10186 JSObject::UnregisterPrototypeUser(old_prototype, map); |
| 10187 } |
10242 if (prototype->IsJSObject()) { | 10188 if (prototype->IsJSObject()) { |
10243 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); | 10189 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); |
10244 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); | 10190 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); |
| 10191 if (ShouldRegisterAsPrototypeUser(map, prototype_jsobj)) { |
| 10192 JSObject::RegisterPrototypeUser(prototype_jsobj, map); |
| 10193 } |
10245 } | 10194 } |
10246 WriteBarrierMode wb_mode = | 10195 WriteBarrierMode wb_mode = |
10247 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; | 10196 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; |
10248 map->set_prototype(*prototype, wb_mode); | 10197 map->set_prototype(*prototype, wb_mode); |
10249 } | 10198 } |
10250 | 10199 |
10251 | 10200 |
| 10201 // static |
| 10202 bool Map::ShouldRegisterAsPrototypeUser(Handle<Map> map, |
| 10203 Handle<JSObject> prototype) { |
| 10204 if (!FLAG_track_prototype_users) return false; |
| 10205 if (map->is_prototype_map()) return true; |
| 10206 Object* back = map->GetBackPointer(); |
| 10207 if (!back->IsMap()) return true; |
| 10208 if (Map::cast(back)->prototype() != *prototype) return true; |
| 10209 return false; |
| 10210 } |
| 10211 |
| 10212 |
10252 Handle<Object> CacheInitialJSArrayMaps( | 10213 Handle<Object> CacheInitialJSArrayMaps( |
10253 Handle<Context> native_context, Handle<Map> initial_map) { | 10214 Handle<Context> native_context, Handle<Map> initial_map) { |
10254 // Replace all of the cached initial array maps in the native context with | 10215 // Replace all of the cached initial array maps in the native context with |
10255 // the appropriate transitioned elements kind maps. | 10216 // the appropriate transitioned elements kind maps. |
10256 Factory* factory = native_context->GetIsolate()->factory(); | 10217 Factory* factory = native_context->GetIsolate()->factory(); |
10257 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles( | 10218 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles( |
10258 kElementsKindCount, TENURED); | 10219 kElementsKindCount, TENURED); |
10259 | 10220 |
10260 Handle<Map> current_map = initial_map; | 10221 Handle<Map> current_map = initial_map; |
10261 ElementsKind kind = current_map->elements_kind(); | 10222 ElementsKind kind = current_map->elements_kind(); |
(...skipping 6910 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17172 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell, | 17133 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell, |
17173 Handle<Object> new_value) { | 17134 Handle<Object> new_value) { |
17174 if (cell->value() != *new_value) { | 17135 if (cell->value() != *new_value) { |
17175 cell->set_value(*new_value); | 17136 cell->set_value(*new_value); |
17176 Isolate* isolate = cell->GetIsolate(); | 17137 Isolate* isolate = cell->GetIsolate(); |
17177 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 17138 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
17178 isolate, DependentCode::kPropertyCellChangedGroup); | 17139 isolate, DependentCode::kPropertyCellChangedGroup); |
17179 } | 17140 } |
17180 } | 17141 } |
17181 } } // namespace v8::internal | 17142 } } // namespace v8::internal |
OLD | NEW |