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 1887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1898 void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) { | 1898 void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) { |
1899 Isolate* isolate = parent->GetIsolate(); | 1899 Isolate* isolate = parent->GetIsolate(); |
1900 Handle<Name> name = isolate->factory()->elements_transition_symbol(); | 1900 Handle<Name> name = isolate->factory()->elements_transition_symbol(); |
1901 ConnectTransition(parent, child, name, SPECIAL_TRANSITION); | 1901 ConnectTransition(parent, child, name, SPECIAL_TRANSITION); |
1902 } | 1902 } |
1903 | 1903 |
1904 | 1904 |
1905 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, | 1905 void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, |
1906 int expected_additional_properties) { | 1906 int expected_additional_properties) { |
1907 if (object->map() == *new_map) return; | 1907 if (object->map() == *new_map) return; |
| 1908 // If this object is a prototype (the callee will check), invalidate any |
| 1909 // prototype chains involving it. |
| 1910 InvalidatePrototypeChains(object->map()); |
1908 Handle<Map> old_map(object->map()); | 1911 Handle<Map> old_map(object->map()); |
1909 if (object->HasFastProperties()) { | 1912 if (object->HasFastProperties()) { |
1910 if (!new_map->is_dictionary_map()) { | 1913 if (!new_map->is_dictionary_map()) { |
1911 MigrateFastToFast(object, new_map); | 1914 MigrateFastToFast(object, new_map); |
1912 if (old_map->is_prototype_map()) { | 1915 if (old_map->is_prototype_map()) { |
1913 // Clear out the old descriptor array to avoid problems to sharing | 1916 // Clear out the old descriptor array to avoid problems to sharing |
1914 // the descriptor array without using an explicit. | 1917 // the descriptor array without using an explicit. |
1915 old_map->InitializeDescriptors( | 1918 old_map->InitializeDescriptors( |
1916 old_map->GetHeap()->empty_descriptor_array(), | 1919 old_map->GetHeap()->empty_descriptor_array(), |
1917 LayoutDescriptor::FastPointerLayout()); | 1920 LayoutDescriptor::FastPointerLayout()); |
1918 // Ensure that no transition was inserted for prototype migrations. | 1921 // Ensure that no transition was inserted for prototype migrations. |
1919 DCHECK_EQ(0, TransitionArray::NumberOfTransitions( | 1922 DCHECK_EQ(0, TransitionArray::NumberOfTransitions( |
1920 old_map->raw_transitions())); | 1923 old_map->raw_transitions())); |
1921 DCHECK(new_map->GetBackPointer()->IsUndefined()); | 1924 DCHECK(new_map->GetBackPointer()->IsUndefined()); |
1922 } | 1925 } |
1923 } else { | 1926 } else { |
1924 MigrateFastToSlow(object, new_map, expected_additional_properties); | 1927 MigrateFastToSlow(object, new_map, expected_additional_properties); |
1925 } | 1928 } |
1926 } else { | 1929 } else { |
1927 // For slow-to-fast migrations JSObject::MigrateSlowToFast() | 1930 // For slow-to-fast migrations JSObject::MigrateSlowToFast() |
1928 // must be used instead. | 1931 // must be used instead. |
1929 CHECK(new_map->is_dictionary_map()); | 1932 CHECK(new_map->is_dictionary_map()); |
1930 | 1933 |
1931 // Slow-to-slow migration is trivial. | 1934 // Slow-to-slow migration is trivial. |
1932 object->set_map(*new_map); | 1935 object->set_map(*new_map); |
1933 } | 1936 } |
1934 if (old_map->is_prototype_map()) { | 1937 if (old_map->is_prototype_map()) { |
| 1938 DCHECK(new_map->is_prototype_map()); |
| 1939 DCHECK(object->map() == *new_map); |
1935 new_map->set_prototype_info(old_map->prototype_info()); | 1940 new_map->set_prototype_info(old_map->prototype_info()); |
1936 old_map->set_prototype_info(Smi::FromInt(0)); | 1941 old_map->set_prototype_info(Smi::FromInt(0)); |
1937 } | 1942 } |
1938 } | 1943 } |
1939 | 1944 |
1940 | 1945 |
1941 // To migrate a fast instance to a fast map: | 1946 // To migrate a fast instance to a fast map: |
1942 // - First check whether the instance needs to be rewritten. If not, simply | 1947 // - First check whether the instance needs to be rewritten. If not, simply |
1943 // change the map. | 1948 // change the map. |
1944 // - Otherwise, allocate a fixed array large enough to hold all fields, in | 1949 // - Otherwise, allocate a fixed array large enough to hold all fields, in |
(...skipping 2758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4703 number_of_fields += 1; | 4708 number_of_fields += 1; |
4704 } | 4709 } |
4705 } | 4710 } |
4706 | 4711 |
4707 int inobject_props = object->map()->inobject_properties(); | 4712 int inobject_props = object->map()->inobject_properties(); |
4708 | 4713 |
4709 // Allocate new map. | 4714 // Allocate new map. |
4710 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map())); | 4715 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map())); |
4711 new_map->set_dictionary_map(false); | 4716 new_map->set_dictionary_map(false); |
4712 | 4717 |
| 4718 if (object->map()->is_prototype_map()) { |
| 4719 DCHECK(new_map->is_prototype_map()); |
| 4720 new_map->set_prototype_info(object->map()->prototype_info()); |
| 4721 object->map()->set_prototype_info(Smi::FromInt(0)); |
| 4722 } |
| 4723 |
4713 #if TRACE_MAPS | 4724 #if TRACE_MAPS |
4714 if (FLAG_trace_maps) { | 4725 if (FLAG_trace_maps) { |
4715 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n", | 4726 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n", |
4716 reinterpret_cast<void*>(object->map()), | 4727 reinterpret_cast<void*>(object->map()), |
4717 reinterpret_cast<void*>(*new_map), reason); | 4728 reinterpret_cast<void*>(*new_map), reason); |
4718 } | 4729 } |
4719 #endif | 4730 #endif |
4720 | 4731 |
4721 if (instance_descriptor_length == 0) { | 4732 if (instance_descriptor_length == 0) { |
4722 DisallowHeapAllocation no_gc; | 4733 DisallowHeapAllocation no_gc; |
(...skipping 2165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6888 #ifdef VERIFY_HEAP | 6899 #ifdef VERIFY_HEAP |
6889 if (FLAG_verify_heap) new_map->DictionaryMapVerify(); | 6900 if (FLAG_verify_heap) new_map->DictionaryMapVerify(); |
6890 #endif | 6901 #endif |
6891 #ifdef ENABLE_SLOW_DCHECKS | 6902 #ifdef ENABLE_SLOW_DCHECKS |
6892 if (FLAG_enable_slow_asserts) { | 6903 if (FLAG_enable_slow_asserts) { |
6893 // The cached map should match newly created normalized map bit-by-bit, | 6904 // The cached map should match newly created normalized map bit-by-bit, |
6894 // except for the code cache, which can contain some ics which can be | 6905 // except for the code cache, which can contain some ics which can be |
6895 // applied to the shared map, dependent code and weak cell cache. | 6906 // applied to the shared map, dependent code and weak cell cache. |
6896 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode); | 6907 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode); |
6897 | 6908 |
6898 DCHECK(memcmp(fresh->address(), | 6909 if (new_map->is_prototype_map()) { |
6899 new_map->address(), | 6910 // For prototype maps, the PrototypeInfo is not copied. |
6900 Map::kCodeCacheOffset) == 0); | 6911 DCHECK(memcmp(fresh->address(), new_map->address(), |
| 6912 kTransitionsOrPrototypeInfoOffset) == 0); |
| 6913 DCHECK(fresh->raw_transitions() == Smi::FromInt(0)); |
| 6914 STATIC_ASSERT(kDescriptorsOffset == |
| 6915 kTransitionsOrPrototypeInfoOffset + kPointerSize); |
| 6916 DCHECK(memcmp(HeapObject::RawField(*fresh, kDescriptorsOffset), |
| 6917 HeapObject::RawField(*new_map, kDescriptorsOffset), |
| 6918 kCodeCacheOffset - kDescriptorsOffset) == 0); |
| 6919 } else { |
| 6920 DCHECK(memcmp(fresh->address(), new_map->address(), |
| 6921 Map::kCodeCacheOffset) == 0); |
| 6922 } |
6901 STATIC_ASSERT(Map::kDependentCodeOffset == | 6923 STATIC_ASSERT(Map::kDependentCodeOffset == |
6902 Map::kCodeCacheOffset + kPointerSize); | 6924 Map::kCodeCacheOffset + kPointerSize); |
6903 STATIC_ASSERT(Map::kWeakCellCacheOffset == | 6925 STATIC_ASSERT(Map::kWeakCellCacheOffset == |
6904 Map::kDependentCodeOffset + kPointerSize); | 6926 Map::kDependentCodeOffset + kPointerSize); |
6905 int offset = Map::kWeakCellCacheOffset + kPointerSize; | 6927 int offset = Map::kWeakCellCacheOffset + kPointerSize; |
6906 DCHECK(memcmp(fresh->address() + offset, | 6928 DCHECK(memcmp(fresh->address() + offset, |
6907 new_map->address() + offset, | 6929 new_map->address() + offset, |
6908 Map::kSize - offset) == 0); | 6930 Map::kSize - offset) == 0); |
6909 } | 6931 } |
6910 #endif | 6932 #endif |
(...skipping 1310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8221 SearchForDuplicates search_for_duplicates) { | 8243 SearchForDuplicates search_for_duplicates) { |
8222 Handle<WeakFixedArray> array = | 8244 Handle<WeakFixedArray> array = |
8223 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray()) | 8245 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray()) |
8224 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null()) | 8246 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null()) |
8225 : Handle<WeakFixedArray>::cast(maybe_array); | 8247 : Handle<WeakFixedArray>::cast(maybe_array); |
8226 | 8248 |
8227 if (search_for_duplicates == kAddIfNotFound) { | 8249 if (search_for_duplicates == kAddIfNotFound) { |
8228 for (int i = 0; i < array->Length(); ++i) { | 8250 for (int i = 0; i < array->Length(); ++i) { |
8229 if (array->Get(i) == *value) return array; | 8251 if (array->Get(i) == *value) return array; |
8230 } | 8252 } |
| 8253 #if 0 // Enable this if you want to check your search_for_duplicates flags. |
8231 } else { | 8254 } else { |
8232 #ifdef DEBUG | |
8233 for (int i = 0; i < array->Length(); ++i) { | 8255 for (int i = 0; i < array->Length(); ++i) { |
8234 DCHECK_NE(*value, array->Get(i)); | 8256 DCHECK_NE(*value, array->Get(i)); |
8235 } | 8257 } |
8236 #endif | 8258 #endif |
8237 } | 8259 } |
8238 | 8260 |
8239 // Try to store the new entry if there's room. Optimize for consecutive | 8261 // Try to store the new entry if there's room. Optimize for consecutive |
8240 // accesses. | 8262 // accesses. |
8241 int first_index = array->last_used_index(); | 8263 int first_index = array->last_used_index(); |
8242 for (int i = first_index;;) { | 8264 for (int i = first_index;;) { |
(...skipping 1799 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10042 Object* maybe_proto_info = prototype->map()->prototype_info(); | 10064 Object* maybe_proto_info = prototype->map()->prototype_info(); |
10043 if (!maybe_proto_info->IsPrototypeInfo()) return; | 10065 if (!maybe_proto_info->IsPrototypeInfo()) return; |
10044 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), | 10066 Handle<PrototypeInfo> proto_info(PrototypeInfo::cast(maybe_proto_info), |
10045 isolate); | 10067 isolate); |
10046 Object* maybe_registry = proto_info->prototype_users(); | 10068 Object* maybe_registry = proto_info->prototype_users(); |
10047 if (!maybe_registry->IsWeakFixedArray()) return; | 10069 if (!maybe_registry->IsWeakFixedArray()) return; |
10048 WeakFixedArray::cast(maybe_registry)->Remove(user); | 10070 WeakFixedArray::cast(maybe_registry)->Remove(user); |
10049 } | 10071 } |
10050 | 10072 |
10051 | 10073 |
| 10074 static void InvalidatePrototypeChainsInternal(Map* map) { |
| 10075 if (!map->is_prototype_map()) return; |
| 10076 Object* maybe_proto_info = map->prototype_info(); |
| 10077 if (!maybe_proto_info->IsPrototypeInfo()) return; |
| 10078 PrototypeInfo* proto_info = PrototypeInfo::cast(maybe_proto_info); |
| 10079 Object* maybe_cell = proto_info->validity_cell(); |
| 10080 if (maybe_cell->IsCell()) { |
| 10081 // Just set the value; the cell will be replaced lazily. |
| 10082 Cell* cell = Cell::cast(maybe_cell); |
| 10083 cell->set_value(Smi::FromInt(Map::kPrototypeChainInvalid)); |
| 10084 } |
| 10085 |
| 10086 Object* maybe_array = proto_info->prototype_users(); |
| 10087 if (!maybe_array->IsWeakFixedArray()) return; |
| 10088 |
| 10089 WeakFixedArray* users = WeakFixedArray::cast(maybe_array); |
| 10090 for (int i = 0; i < users->Length(); ++i) { |
| 10091 Object* maybe_user = users->Get(i); |
| 10092 if (maybe_user->IsSmi()) continue; |
| 10093 |
| 10094 // For now, only maps register themselves as users. |
| 10095 Map* user = Map::cast(maybe_user); |
| 10096 // Walk the prototype chain (backwards, towards leaf objects) if necessary. |
| 10097 InvalidatePrototypeChainsInternal(user); |
| 10098 } |
| 10099 } |
| 10100 |
| 10101 |
10052 // static | 10102 // static |
| 10103 void JSObject::InvalidatePrototypeChains(Map* map) { |
| 10104 if (!FLAG_eliminate_prototype_chain_checks) return; |
| 10105 DisallowHeapAllocation no_gc; |
| 10106 if (map->IsJSGlobalProxyMap()) { |
| 10107 PrototypeIterator iter(map); |
| 10108 map = JSObject::cast(iter.GetCurrent())->map(); |
| 10109 } |
| 10110 InvalidatePrototypeChainsInternal(map); |
| 10111 } |
| 10112 |
| 10113 |
| 10114 // static |
| 10115 Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map, |
| 10116 Isolate* isolate) { |
| 10117 Handle<Object> maybe_prototype(map->prototype(), isolate); |
| 10118 if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null(); |
| 10119 Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype); |
| 10120 if (prototype->IsJSGlobalProxy()) { |
| 10121 PrototypeIterator iter(isolate, prototype); |
| 10122 prototype = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); |
| 10123 } |
| 10124 PrototypeInfo* proto_info = |
| 10125 PrototypeInfo::cast(prototype->map()->prototype_info()); |
| 10126 Object* maybe_cell = proto_info->validity_cell(); |
| 10127 // Return existing cell if it's still valid. |
| 10128 if (maybe_cell->IsCell()) { |
| 10129 Handle<Cell> cell(Cell::cast(maybe_cell), isolate); |
| 10130 if (cell->value() == Smi::FromInt(Map::kPrototypeChainValid)) { |
| 10131 return handle(Cell::cast(maybe_cell), isolate); |
| 10132 } |
| 10133 } |
| 10134 // Otherwise create a new cell. |
| 10135 Handle<Cell> cell = isolate->factory()->NewCell( |
| 10136 handle(Smi::FromInt(Map::kPrototypeChainValid), isolate)); |
| 10137 proto_info->set_validity_cell(*cell); |
| 10138 return cell; |
| 10139 } |
| 10140 |
| 10141 |
10053 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype, | 10142 void Map::SetPrototype(Handle<Map> map, Handle<Object> prototype, |
10054 PrototypeOptimizationMode proto_mode) { | 10143 PrototypeOptimizationMode proto_mode) { |
10055 if (map->prototype()->IsJSObject() && FLAG_track_prototype_users) { | 10144 if (map->prototype()->IsJSObject() && FLAG_track_prototype_users) { |
10056 Handle<JSObject> old_prototype(JSObject::cast(map->prototype())); | 10145 Handle<JSObject> old_prototype(JSObject::cast(map->prototype())); |
10057 JSObject::UnregisterPrototypeUser(old_prototype, map); | 10146 JSObject::UnregisterPrototypeUser(old_prototype, map); |
10058 } | 10147 } |
10059 if (prototype->IsJSObject()) { | 10148 if (prototype->IsJSObject()) { |
10060 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); | 10149 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype); |
| 10150 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); |
10061 if (ShouldRegisterAsPrototypeUser(map, prototype_jsobj)) { | 10151 if (ShouldRegisterAsPrototypeUser(map, prototype_jsobj)) { |
10062 JSObject::RegisterPrototypeUser(prototype_jsobj, map); | 10152 JSObject::RegisterPrototypeUser(prototype_jsobj, map); |
10063 } | 10153 } |
10064 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode); | |
10065 } | 10154 } |
10066 WriteBarrierMode wb_mode = | 10155 WriteBarrierMode wb_mode = |
10067 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; | 10156 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; |
10068 map->set_prototype(*prototype, wb_mode); | 10157 map->set_prototype(*prototype, wb_mode); |
10069 } | 10158 } |
10070 | 10159 |
10071 | 10160 |
10072 // static | 10161 // static |
10073 bool Map::ShouldRegisterAsPrototypeUser(Handle<Map> map, | 10162 bool Map::ShouldRegisterAsPrototypeUser(Handle<Map> map, |
10074 Handle<JSObject> prototype) { | 10163 Handle<JSObject> prototype) { |
(...skipping 6983 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17058 CompilationInfo* info) { | 17147 CompilationInfo* info) { |
17059 Handle<DependentCode> codes = DependentCode::InsertCompilationInfo( | 17148 Handle<DependentCode> codes = DependentCode::InsertCompilationInfo( |
17060 handle(cell->dependent_code(), info->isolate()), | 17149 handle(cell->dependent_code(), info->isolate()), |
17061 DependentCode::kPropertyCellChangedGroup, info->object_wrapper()); | 17150 DependentCode::kPropertyCellChangedGroup, info->object_wrapper()); |
17062 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes); | 17151 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes); |
17063 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add( | 17152 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add( |
17064 cell, info->zone()); | 17153 cell, info->zone()); |
17065 } | 17154 } |
17066 | 17155 |
17067 } } // namespace v8::internal | 17156 } } // namespace v8::internal |
OLD | NEW |